@angular/core 16.2.2 → 16.2.4

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 (40) hide show
  1. package/esm2022/src/di/injection_token.mjs +12 -7
  2. package/esm2022/src/hydration/annotate.mjs +53 -25
  3. package/esm2022/src/linker/view_container_ref.mjs +35 -1
  4. package/esm2022/src/render3/after_render_hooks.mjs +6 -3
  5. package/esm2022/src/render3/collect_native_nodes.mjs +30 -23
  6. package/esm2022/src/render3/component.mjs +4 -3
  7. package/esm2022/src/render3/di.mjs +1 -1
  8. package/esm2022/src/render3/instructions/change_detection.mjs +4 -4
  9. package/esm2022/src/render3/instructions/shared.mjs +20 -14
  10. package/esm2022/src/render3/interfaces/injector.mjs +1 -1
  11. package/esm2022/src/render3/interfaces/styling.mjs +4 -7
  12. package/esm2022/src/render3/node_manipulation.mjs +4 -3
  13. package/esm2022/src/render3/reactive_lview_consumer.mjs +25 -45
  14. package/esm2022/src/render3/reactivity/effect.mjs +8 -8
  15. package/esm2022/src/render3/util/injector_utils.mjs +1 -1
  16. package/esm2022/src/signals/index.mjs +4 -4
  17. package/esm2022/src/signals/src/api.mjs +2 -11
  18. package/esm2022/src/signals/src/computed.mjs +43 -93
  19. package/esm2022/src/signals/src/graph.mjs +238 -162
  20. package/esm2022/src/signals/src/signal.mjs +59 -79
  21. package/esm2022/src/signals/src/watch.mjs +38 -52
  22. package/esm2022/src/signals/src/weak_ref.mjs +2 -29
  23. package/esm2022/src/util/dom.mjs +2 -2
  24. package/esm2022/src/util/security/trusted_type_defs.mjs +1 -1
  25. package/esm2022/src/util/security/trusted_types.mjs +1 -1
  26. package/esm2022/src/version.mjs +1 -1
  27. package/esm2022/src/zone/ng_zone.mjs +16 -1
  28. package/esm2022/testing/src/logger.mjs +3 -3
  29. package/fesm2022/core.mjs +14963 -14928
  30. package/fesm2022/core.mjs.map +1 -1
  31. package/fesm2022/rxjs-interop.mjs +373 -413
  32. package/fesm2022/rxjs-interop.mjs.map +1 -1
  33. package/fesm2022/testing.mjs +1162 -644
  34. package/fesm2022/testing.mjs.map +1 -1
  35. package/index.d.ts +123 -108
  36. package/package.json +1 -1
  37. package/rxjs-interop/index.d.ts +1 -1
  38. package/schematics/ng-generate/standalone-migration/bundle.js +9 -9
  39. package/schematics/ng-generate/standalone-migration/bundle.js.map +1 -1
  40. package/testing/index.d.ts +1 -1
@@ -1,12 +1,13 @@
1
1
  /**
2
- * @license Angular v16.2.2
2
+ * @license Angular v16.2.4
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
6
6
 
7
- import { getDebugNode, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, provideZoneChangeDetection, Compiler, COMPILER_OPTIONS, Injector as Injector$1, ɵisEnvironmentProviders, ɵNgModuleFactory, ModuleWithComponentFactories, ɵconvertToBitFlags, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, EnvironmentInjector as EnvironmentInjector$1, NgZone, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
7
+ import { getDebugNode, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, provideZoneChangeDetection, Compiler, COMPILER_OPTIONS, Injector as Injector$1, ɵisEnvironmentProviders, ɵNgModuleFactory, ModuleWithComponentFactories, ɵconvertToBitFlags, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, EnvironmentInjector as EnvironmentInjector$1, NgZone as NgZone$1, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
8
8
  import { ResourceLoader } from '@angular/compiler';
9
- import { Subject, Subscription } from 'rxjs';
9
+ import { Subject, Subscription, Observable, merge as merge$1 } from 'rxjs';
10
+ import { share } from 'rxjs/operators';
10
11
 
11
12
  /**
12
13
  * Wraps a test function in an asynchronous test zone. The test will automatically
@@ -3564,15 +3565,6 @@ const SIGNAL = Symbol('SIGNAL');
3564
3565
  function isSignal(value) {
3565
3566
  return typeof value === 'function' && value[SIGNAL] !== undefined;
3566
3567
  }
3567
- /**
3568
- * Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`), and
3569
- * potentially add some set of extra properties (passed as an object record `extraApi`).
3570
- */
3571
- function createSignalFromFunction(node, fn, extraApi = {}) {
3572
- fn[SIGNAL] = node;
3573
- // Copy properties from `extraApi` to `fn` to complete the desired API of the `Signal`.
3574
- return Object.assign(fn, extraApi);
3575
- }
3576
3568
  /**
3577
3569
  * The default equality function used for `signal` and `computed`, which treats objects and arrays
3578
3570
  * as never equal, and all other primitive values using identity semantics.
@@ -3593,216 +3585,265 @@ function defaultEquals(a, b) {
3593
3585
 
3594
3586
  // Required as the signals library is in a separate package, so we need to explicitly ensure the
3595
3587
  /**
3596
- * A `WeakRef`-compatible reference that fakes the API with a strong reference
3597
- * internally.
3588
+ * The currently active consumer `ReactiveNode`, if running code in a reactive context.
3589
+ *
3590
+ * Change this via `setActiveConsumer`.
3598
3591
  */
3599
- class LeakyRef {
3600
- constructor(ref) {
3601
- this.ref = ref;
3592
+ let activeConsumer = null;
3593
+ let inNotificationPhase = false;
3594
+ function setActiveConsumer(consumer) {
3595
+ const prev = activeConsumer;
3596
+ activeConsumer = consumer;
3597
+ return prev;
3598
+ }
3599
+ const REACTIVE_NODE = {
3600
+ version: 0,
3601
+ dirty: false,
3602
+ producerNode: undefined,
3603
+ producerLastReadVersion: undefined,
3604
+ producerIndexOfThis: undefined,
3605
+ nextProducerIndex: 0,
3606
+ liveConsumerNode: undefined,
3607
+ liveConsumerIndexOfThis: undefined,
3608
+ consumerAllowSignalWrites: false,
3609
+ consumerIsAlwaysLive: false,
3610
+ producerMustRecompute: () => false,
3611
+ producerRecomputeValue: () => { },
3612
+ consumerMarkedDirty: () => { },
3613
+ };
3614
+ /**
3615
+ * Called by implementations when a producer's signal is read.
3616
+ */
3617
+ function producerAccessed(node) {
3618
+ if (inNotificationPhase) {
3619
+ throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ?
3620
+ `Assertion error: signal read during notification phase` :
3621
+ '');
3602
3622
  }
3603
- deref() {
3604
- return this.ref;
3623
+ if (activeConsumer === null) {
3624
+ // Accessed outside of a reactive context, so nothing to record.
3625
+ return;
3605
3626
  }
3606
- }
3607
- // `WeakRef` is not always defined in every TS environment where Angular is compiled. Instead,
3608
- // read it off of the global context if available.
3609
- // tslint:disable-next-line: no-toplevel-property-access
3610
- let WeakRefImpl = _global['WeakRef'] ?? LeakyRef;
3611
- function newWeakRef(value) {
3612
- if (typeof ngDevMode !== 'undefined' && ngDevMode && WeakRefImpl === undefined) {
3613
- throw new Error(`Angular requires a browser which supports the 'WeakRef' API`);
3627
+ // This producer is the `idx`th dependency of `activeConsumer`.
3628
+ const idx = activeConsumer.nextProducerIndex++;
3629
+ assertConsumerNode(activeConsumer);
3630
+ if (idx < activeConsumer.producerNode.length && activeConsumer.producerNode[idx] !== node) {
3631
+ // There's been a change in producers since the last execution of `activeConsumer`.
3632
+ // `activeConsumer.producerNode[idx]` holds a stale dependency which will be be removed and
3633
+ // replaced with `this`.
3634
+ //
3635
+ // If `activeConsumer` isn't live, then this is a no-op, since we can replace the producer in
3636
+ // `activeConsumer.producerNode` directly. However, if `activeConsumer` is live, then we need
3637
+ // to remove it from the stale producer's `liveConsumer`s.
3638
+ if (consumerIsLive(activeConsumer)) {
3639
+ const staleProducer = activeConsumer.producerNode[idx];
3640
+ producerRemoveLiveConsumerAtIndex(staleProducer, activeConsumer.producerIndexOfThis[idx]);
3641
+ // At this point, the only record of `staleProducer` is the reference at
3642
+ // `activeConsumer.producerNode[idx]` which will be overwritten below.
3643
+ }
3614
3644
  }
3615
- return new WeakRefImpl(value);
3616
- }
3617
- function setAlternateWeakRefImpl(impl) {
3618
- // no-op since the alternate impl is included by default by the framework. Remove once internal
3619
- // migration is complete.
3645
+ if (activeConsumer.producerNode[idx] !== node) {
3646
+ // We're a new dependency of the consumer (at `idx`).
3647
+ activeConsumer.producerNode[idx] = node;
3648
+ // If the active consumer is live, then add it as a live consumer. If not, then use 0 as a
3649
+ // placeholder value.
3650
+ activeConsumer.producerIndexOfThis[idx] =
3651
+ consumerIsLive(activeConsumer) ? producerAddLiveConsumer(node, activeConsumer, idx) : 0;
3652
+ }
3653
+ activeConsumer.producerLastReadVersion[idx] = node.version;
3620
3654
  }
3621
-
3622
- // Required as the signals library is in a separate package, so we need to explicitly ensure the
3623
3655
  /**
3624
- * Counter tracking the next `ProducerId` or `ConsumerId`.
3656
+ * Ensure this producer's `version` is up-to-date.
3625
3657
  */
3626
- let _nextReactiveId = 0;
3658
+ function producerUpdateValueVersion(node) {
3659
+ if (consumerIsLive(node) && !node.dirty) {
3660
+ // A live consumer will be marked dirty by producers, so a clean state means that its version
3661
+ // is guaranteed to be up-to-date.
3662
+ return;
3663
+ }
3664
+ if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) {
3665
+ // None of our producers report a change since the last time they were read, so no
3666
+ // recomputation of our value is necessary, and we can consider ourselves clean.
3667
+ node.dirty = false;
3668
+ return;
3669
+ }
3670
+ node.producerRecomputeValue(node);
3671
+ // After recomputing the value, we're no longer dirty.
3672
+ node.dirty = false;
3673
+ }
3627
3674
  /**
3628
- * Tracks the currently active reactive consumer (or `null` if there is no active
3629
- * consumer).
3675
+ * Propagate a dirty notification to live consumers of this producer.
3630
3676
  */
3631
- let activeConsumer = null;
3677
+ function producerNotifyConsumers(node) {
3678
+ if (node.liveConsumerNode === undefined) {
3679
+ return;
3680
+ }
3681
+ // Prevent signal reads when we're updating the graph
3682
+ const prev = inNotificationPhase;
3683
+ inNotificationPhase = true;
3684
+ try {
3685
+ for (const consumer of node.liveConsumerNode) {
3686
+ if (!consumer.dirty) {
3687
+ consumerMarkDirty(consumer);
3688
+ }
3689
+ }
3690
+ }
3691
+ finally {
3692
+ inNotificationPhase = prev;
3693
+ }
3694
+ }
3632
3695
  /**
3633
- * Whether the graph is currently propagating change notifications.
3696
+ * Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates,
3697
+ * based on the current consumer context.
3634
3698
  */
3635
- let inNotificationPhase = false;
3636
- function setActiveConsumer(consumer) {
3637
- const prev = activeConsumer;
3638
- activeConsumer = consumer;
3639
- return prev;
3699
+ function producerUpdatesAllowed() {
3700
+ return activeConsumer?.consumerAllowSignalWrites !== false;
3701
+ }
3702
+ function consumerMarkDirty(node) {
3703
+ node.dirty = true;
3704
+ producerNotifyConsumers(node);
3705
+ node.consumerMarkedDirty?.(node);
3640
3706
  }
3641
3707
  /**
3642
- * A node in the reactive graph.
3643
- *
3644
- * Nodes can be producers of reactive values, consumers of other reactive values, or both.
3645
- *
3646
- * Producers are nodes that produce values, and can be depended upon by consumer nodes.
3647
- *
3648
- * Producers expose a monotonic `valueVersion` counter, and are responsible for incrementing this
3649
- * version when their value semantically changes. Some producers may produce their values lazily and
3650
- * thus at times need to be polled for potential updates to their value (and by extension their
3651
- * `valueVersion`). This is accomplished via the `onProducerUpdateValueVersion` method for
3652
- * implemented by producers, which should perform whatever calculations are necessary to ensure
3653
- * `valueVersion` is up to date.
3708
+ * Prepare this consumer to run a computation in its reactive context.
3654
3709
  *
3655
- * Consumers are nodes that depend on the values of producers and are notified when those values
3656
- * might have changed.
3657
- *
3658
- * Consumers do not wrap the reads they consume themselves, but rather can be set as the active
3659
- * reader via `setActiveConsumer`. Reads of producers that happen while a consumer is active will
3660
- * result in those producers being added as dependencies of that consumer node.
3661
- *
3662
- * The set of dependencies of a consumer is dynamic. Implementers expose a monotonically increasing
3663
- * `trackingVersion` counter, which increments whenever the consumer is about to re-run any reactive
3664
- * reads it needs and establish a new set of dependencies as a result.
3710
+ * Must be called by subclasses which represent reactive computations, before those computations
3711
+ * begin.
3712
+ */
3713
+ function consumerBeforeComputation(node) {
3714
+ node && (node.nextProducerIndex = 0);
3715
+ return setActiveConsumer(node);
3716
+ }
3717
+ /**
3718
+ * Finalize this consumer's state after a reactive computation has run.
3665
3719
  *
3666
- * Producers store the last `trackingVersion` they've seen from `Consumer`s which have read them.
3667
- * This allows a producer to identify whether its record of the dependency is current or stale, by
3668
- * comparing the consumer's `trackingVersion` to the version at which the dependency was
3669
- * last observed.
3720
+ * Must be called by subclasses which represent reactive computations, after those computations
3721
+ * have finished.
3670
3722
  */
3671
- class ReactiveNode {
3672
- constructor() {
3673
- this.id = _nextReactiveId++;
3674
- /**
3675
- * A cached weak reference to this node, which will be used in `ReactiveEdge`s.
3676
- */
3677
- this.ref = newWeakRef(this);
3678
- /**
3679
- * Edges to producers on which this node depends (in its consumer capacity).
3680
- */
3681
- this.producers = new Map();
3682
- /**
3683
- * Edges to consumers on which this node depends (in its producer capacity).
3684
- */
3685
- this.consumers = new Map();
3686
- /**
3687
- * Monotonically increasing counter representing a version of this `Consumer`'s
3688
- * dependencies.
3689
- */
3690
- this.trackingVersion = 0;
3691
- /**
3692
- * Monotonically increasing counter which increases when the value of this `Producer`
3693
- * semantically changes.
3694
- */
3695
- this.valueVersion = 0;
3723
+ function consumerAfterComputation(node, prevConsumer) {
3724
+ setActiveConsumer(prevConsumer);
3725
+ if (!node || node.producerNode === undefined || node.producerIndexOfThis === undefined ||
3726
+ node.producerLastReadVersion === undefined) {
3727
+ return;
3696
3728
  }
3697
- /**
3698
- * Polls dependencies of a consumer to determine if they have actually changed.
3699
- *
3700
- * If this returns `false`, then even though the consumer may have previously been notified of a
3701
- * change, the values of its dependencies have not actually changed and the consumer should not
3702
- * rerun any reactions.
3703
- */
3704
- consumerPollProducersForChange() {
3705
- for (const [producerId, edge] of this.producers) {
3706
- const producer = edge.producerNode.deref();
3707
- // On Safari < 16.1 deref can return null, we need to check for null also.
3708
- // See https://github.com/WebKit/WebKit/commit/44c15ba58912faab38b534fef909dd9e13e095e0
3709
- if (producer == null || edge.atTrackingVersion !== this.trackingVersion) {
3710
- // This dependency edge is stale, so remove it.
3711
- this.producers.delete(producerId);
3712
- producer?.consumers.delete(this.id);
3713
- continue;
3714
- }
3715
- if (producer.producerPollStatus(edge.seenValueVersion)) {
3716
- // One of the dependencies reports a real value change.
3717
- return true;
3718
- }
3729
+ if (consumerIsLive(node)) {
3730
+ // For live consumers, we need to remove the producer -> consumer edge for any stale producers
3731
+ // which weren't dependencies after the recomputation.
3732
+ for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
3733
+ producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
3719
3734
  }
3720
- // No dependency reported a real value change, so the `Consumer` has also not been
3721
- // impacted.
3722
- return false;
3723
3735
  }
3724
- /**
3725
- * Notify all consumers of this producer that its value may have changed.
3726
- */
3727
- producerMayHaveChanged() {
3728
- // Prevent signal reads when we're updating the graph
3729
- const prev = inNotificationPhase;
3730
- inNotificationPhase = true;
3731
- try {
3732
- for (const [consumerId, edge] of this.consumers) {
3733
- const consumer = edge.consumerNode.deref();
3734
- // On Safari < 16.1 deref can return null, we need to check for null also.
3735
- // See https://github.com/WebKit/WebKit/commit/44c15ba58912faab38b534fef909dd9e13e095e0
3736
- if (consumer == null || consumer.trackingVersion !== edge.atTrackingVersion) {
3737
- this.consumers.delete(consumerId);
3738
- consumer?.producers.delete(this.id);
3739
- continue;
3740
- }
3741
- consumer.onConsumerDependencyMayHaveChanged();
3742
- }
3743
- }
3744
- finally {
3745
- inNotificationPhase = prev;
3746
- }
3736
+ // Truncate the producer tracking arrays.
3737
+ for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
3738
+ node.producerNode.pop();
3739
+ node.producerLastReadVersion.pop();
3740
+ node.producerIndexOfThis.pop();
3747
3741
  }
3748
- /**
3749
- * Mark that this producer node has been accessed in the current reactive context.
3750
- */
3751
- producerAccessed() {
3752
- if (inNotificationPhase) {
3753
- throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ?
3754
- `Assertion error: signal read during notification phase` :
3755
- '');
3756
- }
3757
- if (activeConsumer === null) {
3758
- return;
3742
+ }
3743
+ /**
3744
+ * Determine whether this consumer has any dependencies which have changed since the last time
3745
+ * they were read.
3746
+ */
3747
+ function consumerPollProducersForChange(node) {
3748
+ assertConsumerNode(node);
3749
+ // Poll producers for change.
3750
+ for (let i = 0; i < node.producerNode.length; i++) {
3751
+ const producer = node.producerNode[i];
3752
+ const seenVersion = node.producerLastReadVersion[i];
3753
+ // First check the versions. A mismatch means that the producer's value is known to have
3754
+ // changed since the last time we read it.
3755
+ if (seenVersion !== producer.version) {
3756
+ return true;
3759
3757
  }
3760
- // Either create or update the dependency `Edge` in both directions.
3761
- let edge = activeConsumer.producers.get(this.id);
3762
- if (edge === undefined) {
3763
- edge = {
3764
- consumerNode: activeConsumer.ref,
3765
- producerNode: this.ref,
3766
- seenValueVersion: this.valueVersion,
3767
- atTrackingVersion: activeConsumer.trackingVersion,
3768
- };
3769
- activeConsumer.producers.set(this.id, edge);
3770
- this.consumers.set(activeConsumer.id, edge);
3758
+ // The producer's version is the same as the last time we read it, but it might itself be
3759
+ // stale. Force the producer to recompute its version (calculating a new value if necessary).
3760
+ producerUpdateValueVersion(producer);
3761
+ // Now when we do this check, `producer.version` is guaranteed to be up to date, so if the
3762
+ // versions still match then it has not changed since the last time we read it.
3763
+ if (seenVersion !== producer.version) {
3764
+ return true;
3771
3765
  }
3772
- else {
3773
- edge.seenValueVersion = this.valueVersion;
3774
- edge.atTrackingVersion = activeConsumer.trackingVersion;
3766
+ }
3767
+ return false;
3768
+ }
3769
+ /**
3770
+ * Disconnect this consumer from the graph.
3771
+ */
3772
+ function consumerDestroy(node) {
3773
+ assertConsumerNode(node);
3774
+ if (consumerIsLive(node)) {
3775
+ // Drop all connections from the graph to this node.
3776
+ for (let i = 0; i < node.producerNode.length; i++) {
3777
+ producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
3775
3778
  }
3776
3779
  }
3777
- /**
3778
- * Whether this consumer currently has any producers registered.
3779
- */
3780
- get hasProducers() {
3781
- return this.producers.size > 0;
3780
+ // Truncate all the arrays to drop all connection from this node to the graph.
3781
+ node.producerNode.length = node.producerLastReadVersion.length = node.producerIndexOfThis.length =
3782
+ 0;
3783
+ if (node.liveConsumerNode) {
3784
+ node.liveConsumerNode.length = node.liveConsumerIndexOfThis.length = 0;
3782
3785
  }
3783
- /**
3784
- * Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates,
3785
- * based on the current consumer context.
3786
- */
3787
- get producerUpdatesAllowed() {
3788
- return activeConsumer?.consumerAllowSignalWrites !== false;
3786
+ }
3787
+ /**
3788
+ * Add `consumer` as a live consumer of this node.
3789
+ *
3790
+ * Note that this operation is potentially transitive. If this node becomes live, then it becomes
3791
+ * a live consumer of all of its current producers.
3792
+ */
3793
+ function producerAddLiveConsumer(node, consumer, indexOfThis) {
3794
+ assertProducerNode(node);
3795
+ assertConsumerNode(node);
3796
+ if (node.liveConsumerNode.length === 0) {
3797
+ // When going from 0 to 1 live consumers, we become a live consumer to our producers.
3798
+ for (let i = 0; i < node.producerNode.length; i++) {
3799
+ node.producerIndexOfThis[i] = producerAddLiveConsumer(node.producerNode[i], node, i);
3800
+ }
3789
3801
  }
3790
- /**
3791
- * Checks if a `Producer` has a current value which is different than the value
3792
- * last seen at a specific version by a `Consumer` which recorded a dependency on
3793
- * this `Producer`.
3794
- */
3795
- producerPollStatus(lastSeenValueVersion) {
3796
- // `producer.valueVersion` may be stale, but a mismatch still means that the value
3797
- // last seen by the `Consumer` is also stale.
3798
- if (this.valueVersion !== lastSeenValueVersion) {
3799
- return true;
3802
+ node.liveConsumerIndexOfThis.push(indexOfThis);
3803
+ return node.liveConsumerNode.push(consumer) - 1;
3804
+ }
3805
+ /**
3806
+ * Remove the live consumer at `idx`.
3807
+ */
3808
+ function producerRemoveLiveConsumerAtIndex(node, idx) {
3809
+ assertProducerNode(node);
3810
+ assertConsumerNode(node);
3811
+ if (node.liveConsumerNode.length === 1) {
3812
+ // When removing the last live consumer, we will no longer be live. We need to remove
3813
+ // ourselves from our producers' tracking (which may cause consumer-producers to lose
3814
+ // liveness as well).
3815
+ for (let i = 0; i < node.producerNode.length; i++) {
3816
+ producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
3800
3817
  }
3801
- // Trigger the `Producer` to update its `valueVersion` if necessary.
3802
- this.onProducerUpdateValueVersion();
3803
- // At this point, we can trust `producer.valueVersion`.
3804
- return this.valueVersion !== lastSeenValueVersion;
3805
3818
  }
3819
+ // Move the last value of `liveConsumers` into `idx`. Note that if there's only a single
3820
+ // live consumer, this is a no-op.
3821
+ const lastIdx = node.liveConsumerNode.length - 1;
3822
+ node.liveConsumerNode[idx] = node.liveConsumerNode[lastIdx];
3823
+ node.liveConsumerIndexOfThis[idx] = node.liveConsumerIndexOfThis[lastIdx];
3824
+ // Truncate the array.
3825
+ node.liveConsumerNode.length--;
3826
+ node.liveConsumerIndexOfThis.length--;
3827
+ // If the index is still valid, then we need to fix the index pointer from the producer to this
3828
+ // consumer, and update it from `lastIdx` to `idx` (accounting for the move above).
3829
+ if (idx < node.liveConsumerNode.length) {
3830
+ const idxProducer = node.liveConsumerIndexOfThis[idx];
3831
+ const consumer = node.liveConsumerNode[idx];
3832
+ assertConsumerNode(consumer);
3833
+ consumer.producerIndexOfThis[idxProducer] = idx;
3834
+ }
3835
+ }
3836
+ function consumerIsLive(node) {
3837
+ return node.consumerIsAlwaysLive || (node?.liveConsumerNode?.length ?? 0) > 0;
3838
+ }
3839
+ function assertConsumerNode(node) {
3840
+ node.producerNode ??= [];
3841
+ node.producerIndexOfThis ??= [];
3842
+ node.producerLastReadVersion ??= [];
3843
+ }
3844
+ function assertProducerNode(node) {
3845
+ node.liveConsumerNode ??= [];
3846
+ node.liveConsumerIndexOfThis ??= [];
3806
3847
  }
3807
3848
 
3808
3849
  /**
@@ -3811,10 +3852,21 @@ class ReactiveNode {
3811
3852
  * @developerPreview
3812
3853
  */
3813
3854
  function computed(computation, options) {
3814
- const node = new ComputedImpl(computation, options?.equal ?? defaultEquals);
3815
- // Casting here is required for g3, as TS inference behavior is slightly different between our
3816
- // version/options and g3's.
3817
- return createSignalFromFunction(node, node.signal.bind(node));
3855
+ const node = Object.create(COMPUTED_NODE);
3856
+ node.computation = computation;
3857
+ options?.equal && (node.equal = options.equal);
3858
+ const computed = () => {
3859
+ // Check if the value needs updating before returning it.
3860
+ producerUpdateValueVersion(node);
3861
+ // Record that someone looked at this signal.
3862
+ producerAccessed(node);
3863
+ if (node.value === ERRORED) {
3864
+ throw node.error;
3865
+ }
3866
+ return node.value;
3867
+ };
3868
+ computed[SIGNAL] = node;
3869
+ return computed;
3818
3870
  }
3819
3871
  /**
3820
3872
  * A dedicated symbol used before a computed value has been calculated for the first time.
@@ -3833,108 +3885,47 @@ const COMPUTING = Symbol('COMPUTING');
3833
3885
  * Explicitly typed as `any` so we can use it as signal's value.
3834
3886
  */
3835
3887
  const ERRORED = Symbol('ERRORED');
3836
- /**
3837
- * A computation, which derives a value from a declarative reactive expression.
3838
- *
3839
- * `Computed`s are both producers and consumers of reactivity.
3840
- */
3841
- class ComputedImpl extends ReactiveNode {
3842
- constructor(computation, equal) {
3843
- super();
3844
- this.computation = computation;
3845
- this.equal = equal;
3846
- /**
3847
- * Current value of the computation.
3848
- *
3849
- * This can also be one of the special values `UNSET`, `COMPUTING`, or `ERRORED`.
3850
- */
3851
- this.value = UNSET;
3852
- /**
3853
- * If `value` is `ERRORED`, the error caught from the last computation attempt which will
3854
- * be re-thrown.
3855
- */
3856
- this.error = null;
3857
- /**
3858
- * Flag indicating that the computation is currently stale, meaning that one of the
3859
- * dependencies has notified of a potential change.
3860
- *
3861
- * It's possible that no dependency has _actually_ changed, in which case the `stale`
3862
- * state can be resolved without recomputing the value.
3863
- */
3864
- this.stale = true;
3865
- this.consumerAllowSignalWrites = false;
3866
- }
3867
- onConsumerDependencyMayHaveChanged() {
3868
- if (this.stale) {
3869
- // We've already notified consumers that this value has potentially changed.
3870
- return;
3871
- }
3872
- // Record that the currently cached value may be stale.
3873
- this.stale = true;
3874
- // Notify any consumers about the potential change.
3875
- this.producerMayHaveChanged();
3876
- }
3877
- onProducerUpdateValueVersion() {
3878
- if (!this.stale) {
3879
- // The current value and its version are already up to date.
3880
- return;
3881
- }
3882
- // The current value is stale. Check whether we need to produce a new one.
3883
- if (this.value !== UNSET && this.value !== COMPUTING &&
3884
- !this.consumerPollProducersForChange()) {
3885
- // Even though we were previously notified of a potential dependency update, all of
3886
- // our dependencies report that they have not actually changed in value, so we can
3887
- // resolve the stale state without needing to recompute the current value.
3888
- this.stale = false;
3889
- return;
3890
- }
3891
- // The current value is stale, and needs to be recomputed. It still may not change -
3892
- // that depends on whether the newly computed value is equal to the old.
3893
- this.recomputeValue();
3894
- }
3895
- recomputeValue() {
3896
- if (this.value === COMPUTING) {
3888
+ const COMPUTED_NODE = {
3889
+ ...REACTIVE_NODE,
3890
+ value: UNSET,
3891
+ dirty: true,
3892
+ error: null,
3893
+ equal: defaultEquals,
3894
+ producerMustRecompute(node) {
3895
+ // Force a recomputation if there's no current value, or if the current value is in the process
3896
+ // of being calculated (which should throw an error).
3897
+ return node.value === UNSET || node.value === COMPUTING;
3898
+ },
3899
+ producerRecomputeValue(node) {
3900
+ if (node.value === COMPUTING) {
3897
3901
  // Our computation somehow led to a cyclic read of itself.
3898
3902
  throw new Error('Detected cycle in computations.');
3899
3903
  }
3900
- const oldValue = this.value;
3901
- this.value = COMPUTING;
3902
- // As we're re-running the computation, update our dependent tracking version number.
3903
- this.trackingVersion++;
3904
- const prevConsumer = setActiveConsumer(this);
3904
+ const oldValue = node.value;
3905
+ node.value = COMPUTING;
3906
+ const prevConsumer = consumerBeforeComputation(node);
3905
3907
  let newValue;
3906
3908
  try {
3907
- newValue = this.computation();
3909
+ newValue = node.computation();
3908
3910
  }
3909
3911
  catch (err) {
3910
3912
  newValue = ERRORED;
3911
- this.error = err;
3913
+ node.error = err;
3912
3914
  }
3913
3915
  finally {
3914
- setActiveConsumer(prevConsumer);
3916
+ consumerAfterComputation(node, prevConsumer);
3915
3917
  }
3916
- this.stale = false;
3917
3918
  if (oldValue !== UNSET && oldValue !== ERRORED && newValue !== ERRORED &&
3918
- this.equal(oldValue, newValue)) {
3919
+ node.equal(oldValue, newValue)) {
3919
3920
  // No change to `valueVersion` - old and new values are
3920
3921
  // semantically equivalent.
3921
- this.value = oldValue;
3922
+ node.value = oldValue;
3922
3923
  return;
3923
3924
  }
3924
- this.value = newValue;
3925
- this.valueVersion++;
3926
- }
3927
- signal() {
3928
- // Check if the value needs updating before returning it.
3929
- this.onProducerUpdateValueVersion();
3930
- // Record that someone looked at this signal.
3931
- this.producerAccessed();
3932
- if (this.value === ERRORED) {
3933
- throw this.error;
3934
- }
3935
- return this.value;
3936
- }
3937
- }
3925
+ node.value = newValue;
3926
+ node.version++;
3927
+ },
3928
+ };
3938
3929
 
3939
3930
  function defaultThrowError() {
3940
3931
  throw new Error();
@@ -3954,88 +3945,24 @@ function setThrowInvalidWriteToSignalError(fn) {
3954
3945
  * of setting a signal.
3955
3946
  */
3956
3947
  let postSignalSetFn = null;
3957
- class WritableSignalImpl extends ReactiveNode {
3958
- constructor(value, equal) {
3959
- super();
3960
- this.value = value;
3961
- this.equal = equal;
3962
- this.consumerAllowSignalWrites = false;
3963
- }
3964
- onConsumerDependencyMayHaveChanged() {
3965
- // This never happens for writable signals as they're not consumers.
3966
- }
3967
- onProducerUpdateValueVersion() {
3968
- // Writable signal value versions are always up to date.
3969
- }
3970
- /**
3971
- * Directly update the value of the signal to a new value, which may or may not be
3972
- * equal to the previous.
3973
- *
3974
- * In the event that `newValue` is semantically equal to the current value, `set` is
3975
- * a no-op.
3976
- */
3977
- set(newValue) {
3978
- if (!this.producerUpdatesAllowed) {
3979
- throwInvalidWriteToSignalError();
3980
- }
3981
- if (!this.equal(this.value, newValue)) {
3982
- this.value = newValue;
3983
- this.valueVersion++;
3984
- this.producerMayHaveChanged();
3985
- postSignalSetFn?.();
3986
- }
3987
- }
3988
- /**
3989
- * Derive a new value for the signal from its current value using the `updater` function.
3990
- *
3991
- * This is equivalent to calling `set` on the result of running `updater` on the current
3992
- * value.
3993
- */
3994
- update(updater) {
3995
- if (!this.producerUpdatesAllowed) {
3996
- throwInvalidWriteToSignalError();
3997
- }
3998
- this.set(updater(this.value));
3999
- }
4000
- /**
4001
- * Calls `mutator` on the current value and assumes that it has been mutated.
4002
- */
4003
- mutate(mutator) {
4004
- if (!this.producerUpdatesAllowed) {
4005
- throwInvalidWriteToSignalError();
4006
- }
4007
- // Mutate bypasses equality checks as it's by definition changing the value.
4008
- mutator(this.value);
4009
- this.valueVersion++;
4010
- this.producerMayHaveChanged();
4011
- postSignalSetFn?.();
4012
- }
4013
- asReadonly() {
4014
- if (this.readonlySignal === undefined) {
4015
- this.readonlySignal = createSignalFromFunction(this, () => this.signal());
4016
- }
4017
- return this.readonlySignal;
4018
- }
4019
- signal() {
4020
- this.producerAccessed();
4021
- return this.value;
4022
- }
4023
- }
4024
3948
  /**
4025
3949
  * Create a `Signal` that can be set or updated directly.
4026
3950
  *
4027
3951
  * @developerPreview
4028
3952
  */
4029
3953
  function signal(initialValue, options) {
4030
- const signalNode = new WritableSignalImpl(initialValue, options?.equal ?? defaultEquals);
4031
- // Casting here is required for g3, as TS inference behavior is slightly different between our
4032
- // version/options and g3's.
4033
- const signalFn = createSignalFromFunction(signalNode, signalNode.signal.bind(signalNode), {
4034
- set: signalNode.set.bind(signalNode),
4035
- update: signalNode.update.bind(signalNode),
4036
- mutate: signalNode.mutate.bind(signalNode),
4037
- asReadonly: signalNode.asReadonly.bind(signalNode)
4038
- });
3954
+ const node = Object.create(SIGNAL_NODE);
3955
+ node.value = initialValue;
3956
+ options?.equal && (node.equal = options.equal);
3957
+ function signalFn() {
3958
+ producerAccessed(node);
3959
+ return node.value;
3960
+ }
3961
+ signalFn.set = signalSetFn;
3962
+ signalFn.update = signalUpdateFn;
3963
+ signalFn.mutate = signalMutateFn;
3964
+ signalFn.asReadonly = signalAsReadonlyFn;
3965
+ signalFn[SIGNAL] = node;
4039
3966
  return signalFn;
4040
3967
  }
4041
3968
  function setPostSignalSetFn(fn) {
@@ -4043,6 +3970,50 @@ function setPostSignalSetFn(fn) {
4043
3970
  postSignalSetFn = fn;
4044
3971
  return prev;
4045
3972
  }
3973
+ const SIGNAL_NODE = {
3974
+ ...REACTIVE_NODE,
3975
+ equal: defaultEquals,
3976
+ readonlyFn: undefined,
3977
+ };
3978
+ function signalValueChanged(node) {
3979
+ node.version++;
3980
+ producerNotifyConsumers(node);
3981
+ postSignalSetFn?.();
3982
+ }
3983
+ function signalSetFn(newValue) {
3984
+ const node = this[SIGNAL];
3985
+ if (!producerUpdatesAllowed()) {
3986
+ throwInvalidWriteToSignalError();
3987
+ }
3988
+ if (!node.equal(node.value, newValue)) {
3989
+ node.value = newValue;
3990
+ signalValueChanged(node);
3991
+ }
3992
+ }
3993
+ function signalUpdateFn(updater) {
3994
+ if (!producerUpdatesAllowed()) {
3995
+ throwInvalidWriteToSignalError();
3996
+ }
3997
+ signalSetFn.call(this, updater(this[SIGNAL].value));
3998
+ }
3999
+ function signalMutateFn(mutator) {
4000
+ const node = this[SIGNAL];
4001
+ if (!producerUpdatesAllowed()) {
4002
+ throwInvalidWriteToSignalError();
4003
+ }
4004
+ // Mutate bypasses equality checks as it's by definition changing the value.
4005
+ mutator(node.value);
4006
+ signalValueChanged(node);
4007
+ }
4008
+ function signalAsReadonlyFn() {
4009
+ const node = this[SIGNAL];
4010
+ if (node.readonlyFn === undefined) {
4011
+ const readonlyFn = () => this();
4012
+ readonlyFn[SIGNAL] = node;
4013
+ node.readonlyFn = readonlyFn;
4014
+ }
4015
+ return node.readonlyFn;
4016
+ }
4046
4017
 
4047
4018
  /**
4048
4019
  * Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function
@@ -4062,63 +4033,53 @@ function untracked(nonReactiveReadsFn) {
4062
4033
  }
4063
4034
  }
4064
4035
 
4065
- const NOOP_CLEANUP_FN = () => { };
4066
- /**
4067
- * Watches a reactive expression and allows it to be scheduled to re-run
4068
- * when any dependencies notify of a change.
4069
- *
4070
- * `Watch` doesn't run reactive expressions itself, but relies on a consumer-
4071
- * provided scheduling operation to coordinate calling `Watch.run()`.
4072
- */
4073
- class Watch extends ReactiveNode {
4074
- constructor(watch, schedule, allowSignalWrites) {
4075
- super();
4076
- this.watch = watch;
4077
- this.schedule = schedule;
4078
- this.dirty = false;
4079
- this.cleanupFn = NOOP_CLEANUP_FN;
4080
- this.registerOnCleanup = (cleanupFn) => {
4081
- this.cleanupFn = cleanupFn;
4082
- };
4083
- this.consumerAllowSignalWrites = allowSignalWrites;
4084
- }
4085
- notify() {
4086
- if (!this.dirty) {
4087
- this.schedule(this);
4088
- }
4089
- this.dirty = true;
4090
- }
4091
- onConsumerDependencyMayHaveChanged() {
4092
- this.notify();
4093
- }
4094
- onProducerUpdateValueVersion() {
4095
- // Watches are not producers.
4096
- }
4097
- /**
4098
- * Execute the reactive expression in the context of this `Watch` consumer.
4099
- *
4100
- * Should be called by the user scheduling algorithm when the provided
4101
- * `schedule` hook is called by `Watch`.
4102
- */
4103
- run() {
4104
- this.dirty = false;
4105
- if (this.trackingVersion !== 0 && !this.consumerPollProducersForChange()) {
4036
+ function watch(fn, schedule, allowSignalWrites) {
4037
+ const node = Object.create(WATCH_NODE);
4038
+ if (allowSignalWrites) {
4039
+ node.consumerAllowSignalWrites = true;
4040
+ }
4041
+ node.fn = fn;
4042
+ node.schedule = schedule;
4043
+ const registerOnCleanup = (cleanupFn) => {
4044
+ node.cleanupFn = cleanupFn;
4045
+ };
4046
+ const run = () => {
4047
+ node.dirty = false;
4048
+ if (node.hasRun && !consumerPollProducersForChange(node)) {
4106
4049
  return;
4107
4050
  }
4108
- const prevConsumer = setActiveConsumer(this);
4109
- this.trackingVersion++;
4051
+ node.hasRun = true;
4052
+ const prevConsumer = consumerBeforeComputation(node);
4110
4053
  try {
4111
- this.cleanupFn();
4112
- this.cleanupFn = NOOP_CLEANUP_FN;
4113
- this.watch(this.registerOnCleanup);
4054
+ node.cleanupFn();
4055
+ node.cleanupFn = NOOP_CLEANUP_FN;
4056
+ node.fn(registerOnCleanup);
4114
4057
  }
4115
4058
  finally {
4116
- setActiveConsumer(prevConsumer);
4059
+ consumerAfterComputation(node, prevConsumer);
4117
4060
  }
4118
- }
4119
- cleanup() {
4120
- this.cleanupFn();
4121
- }
4061
+ };
4062
+ node.ref = {
4063
+ notify: () => consumerMarkDirty(node),
4064
+ run,
4065
+ cleanup: () => node.cleanupFn(),
4066
+ };
4067
+ return node.ref;
4068
+ }
4069
+ const NOOP_CLEANUP_FN = () => { };
4070
+ const WATCH_NODE = {
4071
+ ...REACTIVE_NODE,
4072
+ consumerIsAlwaysLive: true,
4073
+ consumerAllowSignalWrites: false,
4074
+ consumerMarkedDirty: (node) => {
4075
+ node.schedule(node.ref);
4076
+ },
4077
+ hasRun: false,
4078
+ cleanupFn: NOOP_CLEANUP_FN,
4079
+ };
4080
+
4081
+ function setAlternateWeakRefImpl(impl) {
4082
+ // TODO: remove this function
4122
4083
  }
4123
4084
 
4124
4085
  /**
@@ -6373,11 +6334,17 @@ function setAllowDuplicateNgModuleIdsForTest(allowDuplicates) {
6373
6334
  * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
6374
6335
  * the `Injector`. This provides an additional level of type safety.
6375
6336
  *
6376
- * ```
6377
- * interface MyInterface {...}
6378
- * const myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
6379
- * // myInterface is inferred to be MyInterface.
6380
- * ```
6337
+ * <div class="alert is-helpful">
6338
+ *
6339
+ * **Important Note**: Ensure that you use the same instance of the `InjectionToken` in both the
6340
+ * provider and the injection call. Creating a new instance of `InjectionToken` in different places,
6341
+ * even with the same description, will be treated as different tokens by Angular's DI system,
6342
+ * leading to a `NullInjectorError`.
6343
+ *
6344
+ * </div>
6345
+ *
6346
+ * <code-example format="typescript" language="typescript" path="injection-token/src/main.ts"
6347
+ * region="InjectionToken"></code-example>
6381
6348
  *
6382
6349
  * When creating an `InjectionToken`, you can optionally specify a factory function which returns
6383
6350
  * (possibly by creating) a default value of the parameterized type `T`. This sets up the
@@ -6404,7 +6371,6 @@ function setAllowDuplicateNgModuleIdsForTest(allowDuplicates) {
6404
6371
  *
6405
6372
  * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
6406
6373
  *
6407
- *
6408
6374
  * @publicApi
6409
6375
  */
6410
6376
  class InjectionToken {
@@ -8009,7 +7975,7 @@ const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
8009
7975
  /**
8010
7976
  * Delimiter in the disallowed strings which needs to be wrapped with zero with character.
8011
7977
  */
8012
- const COMMENT_DELIMITER = /(<|>)/;
7978
+ const COMMENT_DELIMITER = /(<|>)/g;
8013
7979
  const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
8014
7980
  /**
8015
7981
  * Escape the content of comment strings so that it can be safely inserted into a comment node.
@@ -8776,8 +8742,8 @@ function detachView(lContainer, removeIndex) {
8776
8742
  function destroyLView(tView, lView) {
8777
8743
  if (!(lView[FLAGS] & 256 /* LViewFlags.Destroyed */)) {
8778
8744
  const renderer = lView[RENDERER];
8779
- lView[REACTIVE_TEMPLATE_CONSUMER]?.destroy();
8780
- lView[REACTIVE_HOST_BINDING_CONSUMER]?.destroy();
8745
+ lView[REACTIVE_TEMPLATE_CONSUMER] && consumerDestroy(lView[REACTIVE_TEMPLATE_CONSUMER]);
8746
+ lView[REACTIVE_HOST_BINDING_CONSUMER] && consumerDestroy(lView[REACTIVE_HOST_BINDING_CONSUMER]);
8781
8747
  if (renderer.destroyNode) {
8782
8748
  applyView(tView, lView, renderer, 3 /* WalkTNodeTreeAction.Destroy */, null, null);
8783
8749
  }
@@ -10894,105 +10860,676 @@ class Renderer2 {
10894
10860
  this.destroyNode = null;
10895
10861
  }
10896
10862
  /**
10897
- * @internal
10898
- * @nocollapse
10863
+ * @internal
10864
+ * @nocollapse
10865
+ */
10866
+ static { this.__NG_ELEMENT_ID__ = () => injectRenderer2(); }
10867
+ }
10868
+ /** Injects a Renderer2 for the current component. */
10869
+ function injectRenderer2() {
10870
+ // We need the Renderer to be based on the component that it's being injected into, however since
10871
+ // DI happens before we've entered its view, `getLView` will return the parent view instead.
10872
+ const lView = getLView();
10873
+ const tNode = getCurrentTNode();
10874
+ const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
10875
+ return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
10876
+ }
10877
+
10878
+ /**
10879
+ * Sanitizer is used by the views to sanitize potentially dangerous values.
10880
+ *
10881
+ * @publicApi
10882
+ */
10883
+ class Sanitizer {
10884
+ /** @nocollapse */
10885
+ static { this.ɵprov = ɵɵdefineInjectable({
10886
+ token: Sanitizer,
10887
+ providedIn: 'root',
10888
+ factory: () => null,
10889
+ }); }
10890
+ }
10891
+
10892
+ /**
10893
+ * @description Represents the version of Angular
10894
+ *
10895
+ * @publicApi
10896
+ */
10897
+ class Version {
10898
+ constructor(full) {
10899
+ this.full = full;
10900
+ this.major = full.split('.')[0];
10901
+ this.minor = full.split('.')[1];
10902
+ this.patch = full.split('.').slice(2).join('.');
10903
+ }
10904
+ }
10905
+ /**
10906
+ * @publicApi
10907
+ */
10908
+ const VERSION = new Version('16.2.4');
10909
+
10910
+ // This default value is when checking the hierarchy for a token.
10911
+ //
10912
+ // It means both:
10913
+ // - the token is not provided by the current injector,
10914
+ // - only the element injectors should be checked (ie do not check module injectors
10915
+ //
10916
+ // mod1
10917
+ // /
10918
+ // el1 mod2
10919
+ // \ /
10920
+ // el2
10921
+ //
10922
+ // When requesting el2.injector.get(token), we should check in the following order and return the
10923
+ // first found value:
10924
+ // - el2.injector.get(token, default)
10925
+ // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
10926
+ // - mod2.injector.get(token, default)
10927
+ const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
10928
+
10929
+ /**
10930
+ * `DestroyRef` lets you set callbacks to run for any cleanup or destruction behavior.
10931
+ * The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
10932
+ * is injected in a component or directive, the callbacks run when that component or
10933
+ * directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
10934
+ *
10935
+ * @publicApi
10936
+ */
10937
+ class DestroyRef {
10938
+ /**
10939
+ * @internal
10940
+ * @nocollapse
10941
+ */
10942
+ static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
10943
+ /**
10944
+ * @internal
10945
+ * @nocollapse
10946
+ */
10947
+ static { this.__NG_ENV_ID__ = (injector) => injector; }
10948
+ }
10949
+ class NodeInjectorDestroyRef extends DestroyRef {
10950
+ constructor(_lView) {
10951
+ super();
10952
+ this._lView = _lView;
10953
+ }
10954
+ onDestroy(callback) {
10955
+ storeLViewOnDestroy(this._lView, callback);
10956
+ return () => removeLViewOnDestroy(this._lView, callback);
10957
+ }
10958
+ }
10959
+ function injectDestroyRef() {
10960
+ return new NodeInjectorDestroyRef(getLView());
10961
+ }
10962
+
10963
+ /// <reference types="rxjs" />
10964
+ class EventEmitter_ extends Subject {
10965
+ constructor(isAsync = false) {
10966
+ super();
10967
+ this.__isAsync = isAsync;
10968
+ }
10969
+ emit(value) {
10970
+ super.next(value);
10971
+ }
10972
+ subscribe(observerOrNext, error, complete) {
10973
+ let nextFn = observerOrNext;
10974
+ let errorFn = error || (() => null);
10975
+ let completeFn = complete;
10976
+ if (observerOrNext && typeof observerOrNext === 'object') {
10977
+ const observer = observerOrNext;
10978
+ nextFn = observer.next?.bind(observer);
10979
+ errorFn = observer.error?.bind(observer);
10980
+ completeFn = observer.complete?.bind(observer);
10981
+ }
10982
+ if (this.__isAsync) {
10983
+ errorFn = _wrapInTimeout(errorFn);
10984
+ if (nextFn) {
10985
+ nextFn = _wrapInTimeout(nextFn);
10986
+ }
10987
+ if (completeFn) {
10988
+ completeFn = _wrapInTimeout(completeFn);
10989
+ }
10990
+ }
10991
+ const sink = super.subscribe({ next: nextFn, error: errorFn, complete: completeFn });
10992
+ if (observerOrNext instanceof Subscription) {
10993
+ observerOrNext.add(sink);
10994
+ }
10995
+ return sink;
10996
+ }
10997
+ }
10998
+ function _wrapInTimeout(fn) {
10999
+ return (value) => {
11000
+ setTimeout(fn, undefined, value);
11001
+ };
11002
+ }
11003
+ /**
11004
+ * @publicApi
11005
+ */
11006
+ const EventEmitter = EventEmitter_;
11007
+
11008
+ function noop(...args) {
11009
+ // Do nothing.
11010
+ }
11011
+
11012
+ function getNativeRequestAnimationFrame() {
11013
+ // Note: the `getNativeRequestAnimationFrame` is used in the `NgZone` class, but we cannot use the
11014
+ // `inject` function. The `NgZone` instance may be created manually, and thus the injection
11015
+ // context will be unavailable. This might be enough to check whether `requestAnimationFrame` is
11016
+ // available because otherwise, we'll fall back to `setTimeout`.
11017
+ const isBrowser = typeof _global['requestAnimationFrame'] === 'function';
11018
+ // Note: `requestAnimationFrame` is unavailable when the code runs in the Node.js environment. We
11019
+ // use `setTimeout` because no changes are required other than checking if the current platform is
11020
+ // the browser. `setTimeout` is a well-established API that is available in both environments.
11021
+ // `requestAnimationFrame` is used in the browser to coalesce event tasks since event tasks are
11022
+ // usually executed within the same rendering frame (but this is more implementation details of
11023
+ // browsers).
11024
+ let nativeRequestAnimationFrame = _global[isBrowser ? 'requestAnimationFrame' : 'setTimeout'];
11025
+ let nativeCancelAnimationFrame = _global[isBrowser ? 'cancelAnimationFrame' : 'clearTimeout'];
11026
+ if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
11027
+ // Note: zone.js sets original implementations on patched APIs behind the
11028
+ // `__zone_symbol__OriginalDelegate` key (see `attachOriginToPatched`). Given the following
11029
+ // example: `window.requestAnimationFrame.__zone_symbol__OriginalDelegate`; this would return an
11030
+ // unpatched implementation of the `requestAnimationFrame`, which isn't intercepted by the
11031
+ // Angular zone. We use the unpatched implementation to avoid another change detection when
11032
+ // coalescing tasks.
11033
+ const unpatchedRequestAnimationFrame = nativeRequestAnimationFrame[Zone.__symbol__('OriginalDelegate')];
11034
+ if (unpatchedRequestAnimationFrame) {
11035
+ nativeRequestAnimationFrame = unpatchedRequestAnimationFrame;
11036
+ }
11037
+ const unpatchedCancelAnimationFrame = nativeCancelAnimationFrame[Zone.__symbol__('OriginalDelegate')];
11038
+ if (unpatchedCancelAnimationFrame) {
11039
+ nativeCancelAnimationFrame = unpatchedCancelAnimationFrame;
11040
+ }
11041
+ }
11042
+ return { nativeRequestAnimationFrame, nativeCancelAnimationFrame };
11043
+ }
11044
+
11045
+ class AsyncStackTaggingZoneSpec {
11046
+ constructor(namePrefix, consoleAsyncStackTaggingImpl = console) {
11047
+ this.name = 'asyncStackTagging for ' + namePrefix;
11048
+ this.createTask = consoleAsyncStackTaggingImpl?.createTask ?? (() => null);
11049
+ }
11050
+ onScheduleTask(delegate, _current, target, task) {
11051
+ task.consoleTask = this.createTask(`Zone - ${task.source || task.type}`);
11052
+ return delegate.scheduleTask(target, task);
11053
+ }
11054
+ onInvokeTask(delegate, _currentZone, targetZone, task, applyThis, applyArgs) {
11055
+ let ret;
11056
+ if (task.consoleTask) {
11057
+ ret = task.consoleTask.run(() => delegate.invokeTask(targetZone, task, applyThis, applyArgs));
11058
+ }
11059
+ else {
11060
+ ret = delegate.invokeTask(targetZone, task, applyThis, applyArgs);
11061
+ }
11062
+ return ret;
11063
+ }
11064
+ }
11065
+
11066
+ /**
11067
+ * An injectable service for executing work inside or outside of the Angular zone.
11068
+ *
11069
+ * The most common use of this service is to optimize performance when starting a work consisting of
11070
+ * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
11071
+ * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
11072
+ * can reenter the Angular zone via {@link #run}.
11073
+ *
11074
+ * <!-- TODO: add/fix links to:
11075
+ * - docs explaining zones and the use of zones in Angular and change-detection
11076
+ * - link to runOutsideAngular/run (throughout this file!)
11077
+ * -->
11078
+ *
11079
+ * @usageNotes
11080
+ * ### Example
11081
+ *
11082
+ * ```
11083
+ * import {Component, NgZone} from '@angular/core';
11084
+ * import {NgIf} from '@angular/common';
11085
+ *
11086
+ * @Component({
11087
+ * selector: 'ng-zone-demo',
11088
+ * template: `
11089
+ * <h2>Demo: NgZone</h2>
11090
+ *
11091
+ * <p>Progress: {{progress}}%</p>
11092
+ * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
11093
+ *
11094
+ * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
11095
+ * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
11096
+ * `,
11097
+ * })
11098
+ * export class NgZoneDemo {
11099
+ * progress: number = 0;
11100
+ * label: string;
11101
+ *
11102
+ * constructor(private _ngZone: NgZone) {}
11103
+ *
11104
+ * // Loop inside the Angular zone
11105
+ * // so the UI DOES refresh after each setTimeout cycle
11106
+ * processWithinAngularZone() {
11107
+ * this.label = 'inside';
11108
+ * this.progress = 0;
11109
+ * this._increaseProgress(() => console.log('Inside Done!'));
11110
+ * }
11111
+ *
11112
+ * // Loop outside of the Angular zone
11113
+ * // so the UI DOES NOT refresh after each setTimeout cycle
11114
+ * processOutsideOfAngularZone() {
11115
+ * this.label = 'outside';
11116
+ * this.progress = 0;
11117
+ * this._ngZone.runOutsideAngular(() => {
11118
+ * this._increaseProgress(() => {
11119
+ * // reenter the Angular zone and display done
11120
+ * this._ngZone.run(() => { console.log('Outside Done!'); });
11121
+ * });
11122
+ * });
11123
+ * }
11124
+ *
11125
+ * _increaseProgress(doneCallback: () => void) {
11126
+ * this.progress += 1;
11127
+ * console.log(`Current progress: ${this.progress}%`);
11128
+ *
11129
+ * if (this.progress < 100) {
11130
+ * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
11131
+ * } else {
11132
+ * doneCallback();
11133
+ * }
11134
+ * }
11135
+ * }
11136
+ * ```
11137
+ *
11138
+ * @publicApi
11139
+ */
11140
+ class NgZone {
11141
+ constructor({ enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false }) {
11142
+ this.hasPendingMacrotasks = false;
11143
+ this.hasPendingMicrotasks = false;
11144
+ /**
11145
+ * Whether there are no outstanding microtasks or macrotasks.
11146
+ */
11147
+ this.isStable = true;
11148
+ /**
11149
+ * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
11150
+ */
11151
+ this.onUnstable = new EventEmitter(false);
11152
+ /**
11153
+ * Notifies when there is no more microtasks enqueued in the current VM Turn.
11154
+ * This is a hint for Angular to do change detection, which may enqueue more microtasks.
11155
+ * For this reason this event can fire multiple times per VM Turn.
11156
+ */
11157
+ this.onMicrotaskEmpty = new EventEmitter(false);
11158
+ /**
11159
+ * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
11160
+ * implies we are about to relinquish VM turn.
11161
+ * This event gets called just once.
11162
+ */
11163
+ this.onStable = new EventEmitter(false);
11164
+ /**
11165
+ * Notifies that an error has been delivered.
11166
+ */
11167
+ this.onError = new EventEmitter(false);
11168
+ if (typeof Zone == 'undefined') {
11169
+ throw new RuntimeError(908 /* RuntimeErrorCode.MISSING_ZONEJS */, ngDevMode && `In this configuration Angular requires Zone.js`);
11170
+ }
11171
+ Zone.assertZonePatched();
11172
+ const self = this;
11173
+ self._nesting = 0;
11174
+ self._outer = self._inner = Zone.current;
11175
+ // AsyncStackTaggingZoneSpec provides `linked stack traces` to show
11176
+ // where the async operation is scheduled. For more details, refer
11177
+ // to this article, https://developer.chrome.com/blog/devtools-better-angular-debugging/
11178
+ // And we only import this AsyncStackTaggingZoneSpec in development mode,
11179
+ // in the production mode, the AsyncStackTaggingZoneSpec will be tree shaken away.
11180
+ if (ngDevMode) {
11181
+ self._inner = self._inner.fork(new AsyncStackTaggingZoneSpec('Angular'));
11182
+ }
11183
+ if (Zone['TaskTrackingZoneSpec']) {
11184
+ self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']);
11185
+ }
11186
+ if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
11187
+ self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
11188
+ }
11189
+ // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
11190
+ // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
11191
+ self.shouldCoalesceEventChangeDetection =
11192
+ !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
11193
+ self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
11194
+ self.lastRequestAnimationFrameId = -1;
11195
+ self.nativeRequestAnimationFrame = getNativeRequestAnimationFrame().nativeRequestAnimationFrame;
11196
+ forkInnerZoneWithAngularBehavior(self);
11197
+ }
11198
+ /**
11199
+ This method checks whether the method call happens within an Angular Zone instance.
11200
+ */
11201
+ static isInAngularZone() {
11202
+ // Zone needs to be checked, because this method might be called even when NoopNgZone is used.
11203
+ return typeof Zone !== 'undefined' && Zone.current.get('isAngularZone') === true;
11204
+ }
11205
+ /**
11206
+ Assures that the method is called within the Angular Zone, otherwise throws an error.
11207
+ */
11208
+ static assertInAngularZone() {
11209
+ if (!NgZone.isInAngularZone()) {
11210
+ throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to be in Angular Zone, but it is not!');
11211
+ }
11212
+ }
11213
+ /**
11214
+ Assures that the method is called outside of the Angular Zone, otherwise throws an error.
11215
+ */
11216
+ static assertNotInAngularZone() {
11217
+ if (NgZone.isInAngularZone()) {
11218
+ throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to not be in Angular Zone, but it is!');
11219
+ }
11220
+ }
11221
+ /**
11222
+ * Executes the `fn` function synchronously within the Angular zone and returns value returned by
11223
+ * the function.
11224
+ *
11225
+ * Running functions via `run` allows you to reenter Angular zone from a task that was executed
11226
+ * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
11227
+ *
11228
+ * Any future tasks or microtasks scheduled from within this function will continue executing from
11229
+ * within the Angular zone.
11230
+ *
11231
+ * If a synchronous error happens it will be rethrown and not reported via `onError`.
11232
+ */
11233
+ run(fn, applyThis, applyArgs) {
11234
+ return this._inner.run(fn, applyThis, applyArgs);
11235
+ }
11236
+ /**
11237
+ * Executes the `fn` function synchronously within the Angular zone as a task and returns value
11238
+ * returned by the function.
11239
+ *
11240
+ * Running functions via `run` allows you to reenter Angular zone from a task that was executed
11241
+ * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
11242
+ *
11243
+ * Any future tasks or microtasks scheduled from within this function will continue executing from
11244
+ * within the Angular zone.
11245
+ *
11246
+ * If a synchronous error happens it will be rethrown and not reported via `onError`.
11247
+ */
11248
+ runTask(fn, applyThis, applyArgs, name) {
11249
+ const zone = this._inner;
11250
+ const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
11251
+ try {
11252
+ return zone.runTask(task, applyThis, applyArgs);
11253
+ }
11254
+ finally {
11255
+ zone.cancelTask(task);
11256
+ }
11257
+ }
11258
+ /**
11259
+ * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
11260
+ * rethrown.
11261
+ */
11262
+ runGuarded(fn, applyThis, applyArgs) {
11263
+ return this._inner.runGuarded(fn, applyThis, applyArgs);
11264
+ }
11265
+ /**
11266
+ * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
11267
+ * the function.
11268
+ *
11269
+ * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
11270
+ * work that
11271
+ * doesn't trigger Angular change-detection or is subject to Angular's error handling.
11272
+ *
11273
+ * Any future tasks or microtasks scheduled from within this function will continue executing from
11274
+ * outside of the Angular zone.
11275
+ *
11276
+ * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
11277
+ */
11278
+ runOutsideAngular(fn) {
11279
+ return this._outer.run(fn);
11280
+ }
11281
+ }
11282
+ const EMPTY_PAYLOAD = {};
11283
+ function checkStable(zone) {
11284
+ // TODO: @JiaLiPassion, should check zone.isCheckStableRunning to prevent
11285
+ // re-entry. The case is:
11286
+ //
11287
+ // @Component({...})
11288
+ // export class AppComponent {
11289
+ // constructor(private ngZone: NgZone) {
11290
+ // this.ngZone.onStable.subscribe(() => {
11291
+ // this.ngZone.run(() => console.log('stable'););
11292
+ // });
11293
+ // }
11294
+ //
11295
+ // The onStable subscriber run another function inside ngZone
11296
+ // which causes `checkStable()` re-entry.
11297
+ // But this fix causes some issues in g3, so this fix will be
11298
+ // launched in another PR.
11299
+ if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
11300
+ try {
11301
+ zone._nesting++;
11302
+ zone.onMicrotaskEmpty.emit(null);
11303
+ }
11304
+ finally {
11305
+ zone._nesting--;
11306
+ if (!zone.hasPendingMicrotasks) {
11307
+ try {
11308
+ zone.runOutsideAngular(() => zone.onStable.emit(null));
11309
+ }
11310
+ finally {
11311
+ zone.isStable = true;
11312
+ }
11313
+ }
11314
+ }
11315
+ }
11316
+ }
11317
+ function delayChangeDetectionForEvents(zone) {
11318
+ /**
11319
+ * We also need to check _nesting here
11320
+ * Consider the following case with shouldCoalesceRunChangeDetection = true
11321
+ *
11322
+ * ngZone.run(() => {});
11323
+ * ngZone.run(() => {});
11324
+ *
11325
+ * We want the two `ngZone.run()` only trigger one change detection
11326
+ * when shouldCoalesceRunChangeDetection is true.
11327
+ * And because in this case, change detection run in async way(requestAnimationFrame),
11328
+ * so we also need to check the _nesting here to prevent multiple
11329
+ * change detections.
10899
11330
  */
10900
- static { this.__NG_ELEMENT_ID__ = () => injectRenderer2(); }
11331
+ if (zone.isCheckStableRunning || zone.lastRequestAnimationFrameId !== -1) {
11332
+ return;
11333
+ }
11334
+ zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(_global, () => {
11335
+ // This is a work around for https://github.com/angular/angular/issues/36839.
11336
+ // The core issue is that when event coalescing is enabled it is possible for microtasks
11337
+ // to get flushed too early (As is the case with `Promise.then`) between the
11338
+ // coalescing eventTasks.
11339
+ //
11340
+ // To workaround this we schedule a "fake" eventTask before we process the
11341
+ // coalescing eventTasks. The benefit of this is that the "fake" container eventTask
11342
+ // will prevent the microtasks queue from getting drained in between the coalescing
11343
+ // eventTask execution.
11344
+ if (!zone.fakeTopEventTask) {
11345
+ zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
11346
+ zone.lastRequestAnimationFrameId = -1;
11347
+ updateMicroTaskStatus(zone);
11348
+ zone.isCheckStableRunning = true;
11349
+ checkStable(zone);
11350
+ zone.isCheckStableRunning = false;
11351
+ }, undefined, () => { }, () => { });
11352
+ }
11353
+ zone.fakeTopEventTask.invoke();
11354
+ });
11355
+ updateMicroTaskStatus(zone);
10901
11356
  }
10902
- /** Injects a Renderer2 for the current component. */
10903
- function injectRenderer2() {
10904
- // We need the Renderer to be based on the component that it's being injected into, however since
10905
- // DI happens before we've entered its view, `getLView` will return the parent view instead.
10906
- const lView = getLView();
10907
- const tNode = getCurrentTNode();
10908
- const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
10909
- return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
11357
+ function forkInnerZoneWithAngularBehavior(zone) {
11358
+ const delayChangeDetectionForEventsDelegate = () => {
11359
+ delayChangeDetectionForEvents(zone);
11360
+ };
11361
+ zone._inner = zone._inner.fork({
11362
+ name: 'angular',
11363
+ properties: { 'isAngularZone': true },
11364
+ onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
11365
+ if (shouldBeIgnoredByZone(applyArgs)) {
11366
+ return delegate.invokeTask(target, task, applyThis, applyArgs);
11367
+ }
11368
+ try {
11369
+ onEnter(zone);
11370
+ return delegate.invokeTask(target, task, applyThis, applyArgs);
11371
+ }
11372
+ finally {
11373
+ if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
11374
+ zone.shouldCoalesceRunChangeDetection) {
11375
+ delayChangeDetectionForEventsDelegate();
11376
+ }
11377
+ onLeave(zone);
11378
+ }
11379
+ },
11380
+ onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
11381
+ try {
11382
+ onEnter(zone);
11383
+ return delegate.invoke(target, callback, applyThis, applyArgs, source);
11384
+ }
11385
+ finally {
11386
+ if (zone.shouldCoalesceRunChangeDetection) {
11387
+ delayChangeDetectionForEventsDelegate();
11388
+ }
11389
+ onLeave(zone);
11390
+ }
11391
+ },
11392
+ onHasTask: (delegate, current, target, hasTaskState) => {
11393
+ delegate.hasTask(target, hasTaskState);
11394
+ if (current === target) {
11395
+ // We are only interested in hasTask events which originate from our zone
11396
+ // (A child hasTask event is not interesting to us)
11397
+ if (hasTaskState.change == 'microTask') {
11398
+ zone._hasPendingMicrotasks = hasTaskState.microTask;
11399
+ updateMicroTaskStatus(zone);
11400
+ checkStable(zone);
11401
+ }
11402
+ else if (hasTaskState.change == 'macroTask') {
11403
+ zone.hasPendingMacrotasks = hasTaskState.macroTask;
11404
+ }
11405
+ }
11406
+ },
11407
+ onHandleError: (delegate, current, target, error) => {
11408
+ delegate.handleError(target, error);
11409
+ zone.runOutsideAngular(() => zone.onError.emit(error));
11410
+ return false;
11411
+ }
11412
+ });
10910
11413
  }
10911
-
10912
- /**
10913
- * Sanitizer is used by the views to sanitize potentially dangerous values.
10914
- *
10915
- * @publicApi
10916
- */
10917
- class Sanitizer {
10918
- /** @nocollapse */
10919
- static { this.ɵprov = ɵɵdefineInjectable({
10920
- token: Sanitizer,
10921
- providedIn: 'root',
10922
- factory: () => null,
10923
- }); }
11414
+ function updateMicroTaskStatus(zone) {
11415
+ if (zone._hasPendingMicrotasks ||
11416
+ ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
11417
+ zone.lastRequestAnimationFrameId !== -1)) {
11418
+ zone.hasPendingMicrotasks = true;
11419
+ }
11420
+ else {
11421
+ zone.hasPendingMicrotasks = false;
11422
+ }
10924
11423
  }
10925
-
10926
- /**
10927
- * @description Represents the version of Angular
10928
- *
10929
- * @publicApi
10930
- */
10931
- class Version {
10932
- constructor(full) {
10933
- this.full = full;
10934
- this.major = full.split('.')[0];
10935
- this.minor = full.split('.')[1];
10936
- this.patch = full.split('.').slice(2).join('.');
11424
+ function onEnter(zone) {
11425
+ zone._nesting++;
11426
+ if (zone.isStable) {
11427
+ zone.isStable = false;
11428
+ zone.onUnstable.emit(null);
10937
11429
  }
10938
11430
  }
11431
+ function onLeave(zone) {
11432
+ zone._nesting--;
11433
+ checkStable(zone);
11434
+ }
10939
11435
  /**
10940
- * @publicApi
11436
+ * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
11437
+ * to framework to perform rendering.
10941
11438
  */
10942
- const VERSION = new Version('16.2.2');
10943
-
10944
- // This default value is when checking the hierarchy for a token.
10945
- //
10946
- // It means both:
10947
- // - the token is not provided by the current injector,
10948
- // - only the element injectors should be checked (ie do not check module injectors
10949
- //
10950
- // mod1
10951
- // /
10952
- // el1 mod2
10953
- // \ /
10954
- // el2
10955
- //
10956
- // When requesting el2.injector.get(token), we should check in the following order and return the
10957
- // first found value:
10958
- // - el2.injector.get(token, default)
10959
- // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
10960
- // - mod2.injector.get(token, default)
10961
- const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
10962
-
11439
+ class NoopNgZone {
11440
+ constructor() {
11441
+ this.hasPendingMicrotasks = false;
11442
+ this.hasPendingMacrotasks = false;
11443
+ this.isStable = true;
11444
+ this.onUnstable = new EventEmitter();
11445
+ this.onMicrotaskEmpty = new EventEmitter();
11446
+ this.onStable = new EventEmitter();
11447
+ this.onError = new EventEmitter();
11448
+ }
11449
+ run(fn, applyThis, applyArgs) {
11450
+ return fn.apply(applyThis, applyArgs);
11451
+ }
11452
+ runGuarded(fn, applyThis, applyArgs) {
11453
+ return fn.apply(applyThis, applyArgs);
11454
+ }
11455
+ runOutsideAngular(fn) {
11456
+ return fn();
11457
+ }
11458
+ runTask(fn, applyThis, applyArgs, name) {
11459
+ return fn.apply(applyThis, applyArgs);
11460
+ }
11461
+ }
10963
11462
  /**
10964
- * `DestroyRef` lets you set callbacks to run for any cleanup or destruction behavior.
10965
- * The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
10966
- * is injected in a component or directive, the callbacks run when that component or
10967
- * directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
11463
+ * Token used to drive ApplicationRef.isStable
10968
11464
  *
10969
- * @publicApi
11465
+ * TODO: This should be moved entirely to NgZone (as a breaking change) so it can be tree-shakeable
11466
+ * for `NoopNgZone` which is always just an `Observable` of `true`. Additionally, we should consider
11467
+ * whether the property on `NgZone` should be `Observable` or `Signal`.
10970
11468
  */
10971
- class DestroyRef {
10972
- /**
10973
- * @internal
10974
- * @nocollapse
10975
- */
10976
- static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
10977
- /**
10978
- * @internal
10979
- * @nocollapse
10980
- */
10981
- static { this.__NG_ENV_ID__ = (injector) => injector; }
11469
+ const ZONE_IS_STABLE_OBSERVABLE = new InjectionToken(ngDevMode ? 'isStable Observable' : '', {
11470
+ providedIn: 'root',
11471
+ // TODO(atscott): Replace this with a suitable default like `new
11472
+ // BehaviorSubject(true).asObservable`. Again, long term this won't exist on ApplicationRef at
11473
+ // all but until we can remove it, we need a default value zoneless.
11474
+ factory: isStableFactory,
11475
+ });
11476
+ function isStableFactory() {
11477
+ const zone = inject$1(NgZone);
11478
+ let _stable = true;
11479
+ const isCurrentlyStable = new Observable((observer) => {
11480
+ _stable = zone.isStable && !zone.hasPendingMacrotasks && !zone.hasPendingMicrotasks;
11481
+ zone.runOutsideAngular(() => {
11482
+ observer.next(_stable);
11483
+ observer.complete();
11484
+ });
11485
+ });
11486
+ const isStable = new Observable((observer) => {
11487
+ // Create the subscription to onStable outside the Angular Zone so that
11488
+ // the callback is run outside the Angular Zone.
11489
+ let stableSub;
11490
+ zone.runOutsideAngular(() => {
11491
+ stableSub = zone.onStable.subscribe(() => {
11492
+ NgZone.assertNotInAngularZone();
11493
+ // Check whether there are no pending macro/micro tasks in the next tick
11494
+ // to allow for NgZone to update the state.
11495
+ queueMicrotask(() => {
11496
+ if (!_stable && !zone.hasPendingMacrotasks && !zone.hasPendingMicrotasks) {
11497
+ _stable = true;
11498
+ observer.next(true);
11499
+ }
11500
+ });
11501
+ });
11502
+ });
11503
+ const unstableSub = zone.onUnstable.subscribe(() => {
11504
+ NgZone.assertInAngularZone();
11505
+ if (_stable) {
11506
+ _stable = false;
11507
+ zone.runOutsideAngular(() => {
11508
+ observer.next(false);
11509
+ });
11510
+ }
11511
+ });
11512
+ return () => {
11513
+ stableSub.unsubscribe();
11514
+ unstableSub.unsubscribe();
11515
+ };
11516
+ });
11517
+ return merge$1(isCurrentlyStable, isStable.pipe(share()));
10982
11518
  }
10983
- class NodeInjectorDestroyRef extends DestroyRef {
10984
- constructor(_lView) {
10985
- super();
10986
- this._lView = _lView;
11519
+ function shouldBeIgnoredByZone(applyArgs) {
11520
+ if (!Array.isArray(applyArgs)) {
11521
+ return false;
10987
11522
  }
10988
- onDestroy(callback) {
10989
- storeLViewOnDestroy(this._lView, callback);
10990
- return () => removeLViewOnDestroy(this._lView, callback);
11523
+ // We should only ever get 1 arg passed through to invokeTask.
11524
+ // Short circuit here incase that behavior changes.
11525
+ if (applyArgs.length !== 1) {
11526
+ return false;
10991
11527
  }
11528
+ // Prevent triggering change detection when the __ignore_ng_zone__ flag is detected.
11529
+ return applyArgs[0].data?.['__ignore_ng_zone__'] === true;
10992
11530
  }
10993
- function injectDestroyRef() {
10994
- return new NodeInjectorDestroyRef(getLView());
10995
- }
11531
+
11532
+ // Public API for Zone
10996
11533
 
10997
11534
  /**
10998
11535
  * Register a callback to be invoked each time the application
@@ -11044,7 +11581,8 @@ function afterRender(callback, options) {
11044
11581
  let destroy;
11045
11582
  const unregisterFn = injector.get(DestroyRef).onDestroy(() => destroy?.());
11046
11583
  const manager = injector.get(AfterRenderEventManager);
11047
- const instance = new AfterRenderCallback(callback);
11584
+ const ngZone = injector.get(NgZone);
11585
+ const instance = new AfterRenderCallback(() => ngZone.runOutsideAngular(callback));
11048
11586
  destroy = () => {
11049
11587
  manager.unregister(instance);
11050
11588
  unregisterFn();
@@ -11103,9 +11641,10 @@ function afterNextRender(callback, options) {
11103
11641
  let destroy;
11104
11642
  const unregisterFn = injector.get(DestroyRef).onDestroy(() => destroy?.());
11105
11643
  const manager = injector.get(AfterRenderEventManager);
11644
+ const ngZone = injector.get(NgZone);
11106
11645
  const instance = new AfterRenderCallback(() => {
11107
11646
  destroy?.();
11108
- callback();
11647
+ ngZone.runOutsideAngular(callback);
11109
11648
  });
11110
11649
  destroy = () => {
11111
11650
  manager.unregister(instance);
@@ -11419,48 +11958,11 @@ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValu
11419
11958
  return { propName: undefined, oldValue, newValue };
11420
11959
  }
11421
11960
 
11422
- class ReactiveLViewConsumer extends ReactiveNode {
11423
- constructor() {
11424
- super(...arguments);
11425
- this.consumerAllowSignalWrites = false;
11426
- this._lView = null;
11427
- }
11428
- set lView(lView) {
11429
- (typeof ngDevMode === 'undefined' || ngDevMode) &&
11430
- assertEqual(this._lView, null, 'Consumer already associated with a view.');
11431
- this._lView = lView;
11432
- }
11433
- onConsumerDependencyMayHaveChanged() {
11434
- (typeof ngDevMode === 'undefined' || ngDevMode) &&
11435
- assertDefined(this._lView, 'Updating a signal during template or host binding execution is not allowed.');
11436
- markViewDirty(this._lView);
11437
- }
11438
- onProducerUpdateValueVersion() {
11439
- // This type doesn't implement the producer side of a `ReactiveNode`.
11440
- }
11441
- get hasReadASignal() {
11442
- return this.hasProducers;
11443
- }
11444
- runInContext(fn, rf, ctx) {
11445
- const prevConsumer = setActiveConsumer(this);
11446
- this.trackingVersion++;
11447
- try {
11448
- fn(rf, ctx);
11449
- }
11450
- finally {
11451
- setActiveConsumer(prevConsumer);
11452
- }
11453
- }
11454
- destroy() {
11455
- // Incrementing the version means that every producer which tries to update this consumer will
11456
- // consider its record stale, and not notify.
11457
- this.trackingVersion++;
11458
- }
11459
- }
11460
11961
  let currentConsumer = null;
11461
- function getOrCreateCurrentLViewConsumer() {
11462
- currentConsumer ??= new ReactiveLViewConsumer();
11463
- return currentConsumer;
11962
+ function setLViewForConsumer(node, lView) {
11963
+ (typeof ngDevMode === 'undefined' || ngDevMode) &&
11964
+ assertEqual(node.lView, null, 'Consumer already associated with a view.');
11965
+ node.lView = lView;
11464
11966
  }
11465
11967
  /**
11466
11968
  * Create a new template consumer pointing at the specified LView.
@@ -11482,12 +11984,29 @@ function getReactiveLViewConsumer(lView, slot) {
11482
11984
  */
11483
11985
  function commitLViewConsumerIfHasProducers(lView, slot) {
11484
11986
  const consumer = getOrCreateCurrentLViewConsumer();
11485
- if (!consumer.hasReadASignal) {
11987
+ if (!consumer.producerNode?.length) {
11486
11988
  return;
11487
11989
  }
11488
11990
  lView[slot] = currentConsumer;
11489
11991
  consumer.lView = lView;
11490
- currentConsumer = new ReactiveLViewConsumer();
11992
+ currentConsumer = createLViewConsumer();
11993
+ }
11994
+ const REACTIVE_LVIEW_CONSUMER_NODE = {
11995
+ ...REACTIVE_NODE,
11996
+ consumerIsAlwaysLive: true,
11997
+ consumerMarkedDirty: (node) => {
11998
+ (typeof ngDevMode === 'undefined' || ngDevMode) &&
11999
+ assertDefined(node.lView, 'Updating a signal during template or host binding execution is not allowed.');
12000
+ markViewDirty(node.lView);
12001
+ },
12002
+ lView: null,
12003
+ };
12004
+ function createLViewConsumer() {
12005
+ return Object.create(REACTIVE_LVIEW_CONSUMER_NODE);
12006
+ }
12007
+ function getOrCreateCurrentLViewConsumer() {
12008
+ currentConsumer ??= createLViewConsumer();
12009
+ return currentConsumer;
11491
12010
  }
11492
12011
 
11493
12012
  /** A special value which designates that a value has not changed. */
@@ -11604,8 +12123,15 @@ function processHostBindingOpCodes(tView, lView) {
11604
12123
  const bindingRootIndx = hostBindingOpCodes[++i];
11605
12124
  const hostBindingFn = hostBindingOpCodes[++i];
11606
12125
  setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
11607
- const context = lView[directiveIdx];
11608
- consumer.runInContext(hostBindingFn, 2 /* RenderFlags.Update */, context);
12126
+ consumer.dirty = false;
12127
+ const prevConsumer = consumerBeforeComputation(consumer);
12128
+ try {
12129
+ const context = lView[directiveIdx];
12130
+ hostBindingFn(2 /* RenderFlags.Update */, context);
12131
+ }
12132
+ finally {
12133
+ consumerAfterComputation(consumer, prevConsumer);
12134
+ }
11609
12135
  }
11610
12136
  }
11611
12137
  }
@@ -11745,17 +12271,16 @@ function executeTemplate(tView, lView, templateFn, rf, context) {
11745
12271
  }
11746
12272
  const preHookType = isUpdatePhase ? 2 /* ProfilerEvent.TemplateUpdateStart */ : 0 /* ProfilerEvent.TemplateCreateStart */;
11747
12273
  profiler(preHookType, context);
11748
- if (isUpdatePhase) {
11749
- consumer.runInContext(templateFn, rf, context);
11750
- }
11751
- else {
11752
- const prevConsumer = setActiveConsumer(null);
11753
- try {
11754
- templateFn(rf, context);
11755
- }
11756
- finally {
11757
- setActiveConsumer(prevConsumer);
12274
+ const effectiveConsumer = isUpdatePhase ? consumer : null;
12275
+ const prevConsumer = consumerBeforeComputation(effectiveConsumer);
12276
+ try {
12277
+ if (effectiveConsumer !== null) {
12278
+ effectiveConsumer.dirty = false;
11758
12279
  }
12280
+ templateFn(rf, context);
12281
+ }
12282
+ finally {
12283
+ consumerAfterComputation(effectiveConsumer, prevConsumer);
11759
12284
  }
11760
12285
  }
11761
12286
  finally {
@@ -13009,21 +13534,21 @@ class EffectManager {
13009
13534
  }
13010
13535
  create(effectFn, destroyRef, allowSignalWrites) {
13011
13536
  const zone = (typeof Zone === 'undefined') ? null : Zone.current;
13012
- const watch = new Watch(effectFn, (watch) => {
13537
+ const w = watch(effectFn, (watch) => {
13013
13538
  if (!this.all.has(watch)) {
13014
13539
  return;
13015
13540
  }
13016
13541
  this.queue.set(watch, zone);
13017
13542
  }, allowSignalWrites);
13018
- this.all.add(watch);
13543
+ this.all.add(w);
13019
13544
  // Effects start dirty.
13020
- watch.notify();
13545
+ w.notify();
13021
13546
  let unregisterOnDestroy;
13022
13547
  const destroy = () => {
13023
- watch.cleanup();
13548
+ w.cleanup();
13024
13549
  unregisterOnDestroy?.();
13025
- this.all.delete(watch);
13026
- this.queue.delete(watch);
13550
+ this.all.delete(w);
13551
+ this.queue.delete(w);
13027
13552
  };
13028
13553
  unregisterOnDestroy = destroyRef?.onDestroy(destroy);
13029
13554
  return {
@@ -13116,28 +13641,7 @@ function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
13116
13641
  // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
13117
13642
  // from the views in this container.
13118
13643
  if (isLContainer(lNode)) {
13119
- for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
13120
- const lViewInAContainer = lNode[i];
13121
- const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
13122
- if (lViewFirstChildTNode !== null) {
13123
- collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
13124
- }
13125
- }
13126
- // When an LContainer is created, the anchor (comment) node is:
13127
- // - (1) either reused in case of an ElementContainer (<ng-container>)
13128
- // - (2) or a new comment node is created
13129
- // In the first case, the anchor comment node would be added to the final
13130
- // list by the code above (`result.push(unwrapRNode(lNode))`), but the second
13131
- // case requires extra handling: the anchor node needs to be added to the
13132
- // final list manually. See additional information in the `createAnchorNode`
13133
- // function in the `view_container_ref.ts`.
13134
- //
13135
- // In the first case, the same reference would be stored in the `NATIVE`
13136
- // and `HOST` slots in an LContainer. Otherwise, this is the second case and
13137
- // we should add an element to the final list.
13138
- if (lNode[NATIVE] !== lNode[HOST]) {
13139
- result.push(lNode[NATIVE]);
13140
- }
13644
+ collectNativeNodesInLContainer(lNode, result);
13141
13645
  }
13142
13646
  const tNodeType = tNode.type;
13143
13647
  if (tNodeType & 8 /* TNodeType.ElementContainer */) {
@@ -13165,6 +13669,34 @@ function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
13165
13669
  }
13166
13670
  return result;
13167
13671
  }
13672
+ /**
13673
+ * Collects all root nodes in all views in a given LContainer.
13674
+ */
13675
+ function collectNativeNodesInLContainer(lContainer, result) {
13676
+ for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
13677
+ const lViewInAContainer = lContainer[i];
13678
+ const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
13679
+ if (lViewFirstChildTNode !== null) {
13680
+ collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
13681
+ }
13682
+ }
13683
+ // When an LContainer is created, the anchor (comment) node is:
13684
+ // - (1) either reused in case of an ElementContainer (<ng-container>)
13685
+ // - (2) or a new comment node is created
13686
+ // In the first case, the anchor comment node would be added to the final
13687
+ // list by the code in the `collectNativeNodes` function
13688
+ // (see the `result.push(unwrapRNode(lNode))` line), but the second
13689
+ // case requires extra handling: the anchor node needs to be added to the
13690
+ // final list manually. See additional information in the `createAnchorNode`
13691
+ // function in the `view_container_ref.ts`.
13692
+ //
13693
+ // In the first case, the same reference would be stored in the `NATIVE`
13694
+ // and `HOST` slots in an LContainer. Otherwise, this is the second case and
13695
+ // we should add an element to the final list.
13696
+ if (lContainer[NATIVE] !== lContainer[HOST]) {
13697
+ result.push(lContainer[NATIVE]);
13698
+ }
13699
+ }
13168
13700
 
13169
13701
  function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
13170
13702
  const environment = lView[ENVIRONMENT];
@@ -13400,15 +13932,15 @@ function detectChangesInView(lView, mode) {
13400
13932
  return;
13401
13933
  }
13402
13934
  const tView = lView[TVIEW];
13403
- if ((lView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */) &&
13935
+ const flags = lView[FLAGS];
13936
+ if ((flags & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */) &&
13404
13937
  mode === 0 /* ChangeDetectionMode.Global */) ||
13405
- lView[FLAGS] & 1024 /* LViewFlags.RefreshView */ ||
13938
+ flags & 1024 /* LViewFlags.RefreshView */ ||
13406
13939
  mode === 2 /* ChangeDetectionMode.BugToForceRefreshAndIgnoreViewFlags */) {
13407
13940
  refreshView(tView, lView, tView.template, lView[CONTEXT]);
13408
13941
  }
13409
13942
  else if (lView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
13410
13943
  detectChangesInEmbeddedViews(lView, 1 /* ChangeDetectionMode.Targeted */);
13411
- const tView = lView[TVIEW];
13412
13944
  const components = tView.components;
13413
13945
  if (components !== null) {
13414
13946
  detectChangesInChildComponents(lView, components, 1 /* ChangeDetectionMode.Targeted */);
@@ -17184,14 +17716,12 @@ function getTStylingRangePrev(tStylingRange) {
17184
17716
  }
17185
17717
  function getTStylingRangePrevDuplicate(tStylingRange) {
17186
17718
  ngDevMode && assertNumber(tStylingRange, 'expected number');
17187
- return (tStylingRange & 2 /* StylingRange.PREV_DUPLICATE */) ==
17188
- 2 /* StylingRange.PREV_DUPLICATE */;
17719
+ return (tStylingRange & 2 /* StylingRange.PREV_DUPLICATE */) == 2 /* StylingRange.PREV_DUPLICATE */;
17189
17720
  }
17190
17721
  function setTStylingRangePrev(tStylingRange, previous) {
17191
17722
  ngDevMode && assertNumber(tStylingRange, 'expected number');
17192
17723
  ngDevMode && assertNumberInRange(previous, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
17193
- return ((tStylingRange & ~4294836224 /* StylingRange.PREV_MASK */) |
17194
- (previous << 17 /* StylingRange.PREV_SHIFT */));
17724
+ return ((tStylingRange & ~4294836224 /* StylingRange.PREV_MASK */) | (previous << 17 /* StylingRange.PREV_SHIFT */));
17195
17725
  }
17196
17726
  function setTStylingRangePrevDuplicate(tStylingRange) {
17197
17727
  ngDevMode && assertNumber(tStylingRange, 'expected number');
@@ -17209,8 +17739,7 @@ function setTStylingRangeNext(tStylingRange, next) {
17209
17739
  }
17210
17740
  function getTStylingRangeNextDuplicate(tStylingRange) {
17211
17741
  ngDevMode && assertNumber(tStylingRange, 'expected number');
17212
- return (tStylingRange & 1 /* StylingRange.NEXT_DUPLICATE */) ===
17213
- 1 /* StylingRange.NEXT_DUPLICATE */;
17742
+ return ((tStylingRange) & 1 /* StylingRange.NEXT_DUPLICATE */) === 1 /* StylingRange.NEXT_DUPLICATE */;
17214
17743
  }
17215
17744
  function setTStylingRangeNextDuplicate(tStylingRange) {
17216
17745
  ngDevMode && assertNumber(tStylingRange, 'expected number');
@@ -23551,51 +24080,6 @@ function isPure(lView, index) {
23551
24080
  return lView[TVIEW].data[index].pure;
23552
24081
  }
23553
24082
 
23554
- /// <reference types="rxjs" />
23555
- class EventEmitter_ extends Subject {
23556
- constructor(isAsync = false) {
23557
- super();
23558
- this.__isAsync = isAsync;
23559
- }
23560
- emit(value) {
23561
- super.next(value);
23562
- }
23563
- subscribe(observerOrNext, error, complete) {
23564
- let nextFn = observerOrNext;
23565
- let errorFn = error || (() => null);
23566
- let completeFn = complete;
23567
- if (observerOrNext && typeof observerOrNext === 'object') {
23568
- const observer = observerOrNext;
23569
- nextFn = observer.next?.bind(observer);
23570
- errorFn = observer.error?.bind(observer);
23571
- completeFn = observer.complete?.bind(observer);
23572
- }
23573
- if (this.__isAsync) {
23574
- errorFn = _wrapInTimeout(errorFn);
23575
- if (nextFn) {
23576
- nextFn = _wrapInTimeout(nextFn);
23577
- }
23578
- if (completeFn) {
23579
- completeFn = _wrapInTimeout(completeFn);
23580
- }
23581
- }
23582
- const sink = super.subscribe({ next: nextFn, error: errorFn, complete: completeFn });
23583
- if (observerOrNext instanceof Subscription) {
23584
- observerOrNext.add(sink);
23585
- }
23586
- return sink;
23587
- }
23588
- }
23589
- function _wrapInTimeout(fn) {
23590
- return (value) => {
23591
- setTimeout(fn, undefined, value);
23592
- };
23593
- }
23594
- /**
23595
- * @publicApi
23596
- */
23597
- const EventEmitter = EventEmitter_;
23598
-
23599
24083
  function symbolIterator() {
23600
24084
  // @ts-expect-error accessing a private member
23601
24085
  return this._results[Symbol.iterator]();
@@ -24053,6 +24537,40 @@ function findMatchingDehydratedView(lContainer, template) {
24053
24537
  * A view container instance can contain other view containers,
24054
24538
  * creating a [view hierarchy](guide/glossary#view-hierarchy).
24055
24539
  *
24540
+ * @usageNotes
24541
+ *
24542
+ * The example below demonstrates how the `createComponent` function can be used
24543
+ * to create an instance of a ComponentRef dynamically and attach it to an ApplicationRef,
24544
+ * so that it gets included into change detection cycles.
24545
+ *
24546
+ * Note: the example uses standalone components, but the function can also be used for
24547
+ * non-standalone components (declared in an NgModule) as well.
24548
+ *
24549
+ * ```typescript
24550
+ * @Component({
24551
+ * standalone: true,
24552
+ * selector: 'dynamic',
24553
+ * template: `<span>This is a content of a dynamic component.</span>`,
24554
+ * })
24555
+ * class DynamicComponent {
24556
+ * vcr = inject(ViewContainerRef);
24557
+ * }
24558
+ *
24559
+ * @Component({
24560
+ * standalone: true,
24561
+ * selector: 'app',
24562
+ * template: `<main>Hi! This is the main content.</main>`,
24563
+ * })
24564
+ * class AppComponent {
24565
+ * vcr = inject(ViewContainerRef);
24566
+ *
24567
+ * ngAfterViewInit() {
24568
+ * const compRef = this.vcr.createComponent(DynamicComponent);
24569
+ * compRef.changeDetectorRef.detectChanges();
24570
+ * }
24571
+ * }
24572
+ * ```
24573
+ *
24056
24574
  * @see {@link ComponentRef}
24057
24575
  * @see {@link EmbeddedViewRef}
24058
24576
  *
@@ -26899,7 +27417,7 @@ class TestBedImpl {
26899
27417
  }
26900
27418
  const noNgZone = this.inject(ComponentFixtureNoNgZone, false);
26901
27419
  const autoDetect = this.inject(ComponentFixtureAutoDetect, false);
26902
- const ngZone = noNgZone ? null : this.inject(NgZone, null);
27420
+ const ngZone = noNgZone ? null : this.inject(NgZone$1, null);
26903
27421
  const componentFactory = new ɵRender3ComponentFactory(componentDef);
26904
27422
  const initComponent = () => {
26905
27423
  const componentRef = componentFactory.create(Injector$1.NULL, [], `#${rootElId}`, this.testModuleRef);