@angular/core 17.3.6 → 17.3.7

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.
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.3.6
2
+ * @license Angular v17.3.7
3
3
  * (c) 2010-2024 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -1663,7 +1663,7 @@ class NullInjector {
1663
1663
  * The strategy that the default change detector uses to detect changes.
1664
1664
  * When set, takes effect the next time change detection is triggered.
1665
1665
  *
1666
- * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
1666
+ * @see [Change detection usage](/api/core/ChangeDetectorRef?tab=usage-notes)
1667
1667
  *
1668
1668
  * @publicApi
1669
1669
  */
@@ -14504,617 +14504,141 @@ function performanceMarkFeature(feature) {
14504
14504
  performance?.mark?.('mark_feature_usage', { detail: { feature } });
14505
14505
  }
14506
14506
 
14507
- function noop(...args) {
14508
- // Do nothing.
14509
- }
14510
-
14511
- function getNativeRequestAnimationFrame() {
14512
- // Note: the `getNativeRequestAnimationFrame` is used in the `NgZone` class, but we cannot use the
14513
- // `inject` function. The `NgZone` instance may be created manually, and thus the injection
14514
- // context will be unavailable. This might be enough to check whether `requestAnimationFrame` is
14515
- // available because otherwise, we'll fall back to `setTimeout`.
14516
- const isBrowser = typeof _global['requestAnimationFrame'] === 'function';
14517
- // Note: `requestAnimationFrame` is unavailable when the code runs in the Node.js environment. We
14518
- // use `setTimeout` because no changes are required other than checking if the current platform is
14519
- // the browser. `setTimeout` is a well-established API that is available in both environments.
14520
- // `requestAnimationFrame` is used in the browser to coalesce event tasks since event tasks are
14521
- // usually executed within the same rendering frame (but this is more implementation details of
14522
- // browsers).
14523
- let nativeRequestAnimationFrame = _global[isBrowser ? 'requestAnimationFrame' : 'setTimeout'];
14524
- let nativeCancelAnimationFrame = _global[isBrowser ? 'cancelAnimationFrame' : 'clearTimeout'];
14525
- if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
14526
- // Note: zone.js sets original implementations on patched APIs behind the
14527
- // `__zone_symbol__OriginalDelegate` key (see `attachOriginToPatched`). Given the following
14528
- // example: `window.requestAnimationFrame.__zone_symbol__OriginalDelegate`; this would return an
14529
- // unpatched implementation of the `requestAnimationFrame`, which isn't intercepted by the
14530
- // Angular zone. We use the unpatched implementation to avoid another change detection when
14531
- // coalescing tasks.
14532
- const unpatchedRequestAnimationFrame = nativeRequestAnimationFrame[Zone.__symbol__('OriginalDelegate')];
14533
- if (unpatchedRequestAnimationFrame) {
14534
- nativeRequestAnimationFrame = unpatchedRequestAnimationFrame;
14535
- }
14536
- const unpatchedCancelAnimationFrame = nativeCancelAnimationFrame[Zone.__symbol__('OriginalDelegate')];
14537
- if (unpatchedCancelAnimationFrame) {
14538
- nativeCancelAnimationFrame = unpatchedCancelAnimationFrame;
14539
- }
14540
- }
14541
- return { nativeRequestAnimationFrame, nativeCancelAnimationFrame };
14542
- }
14543
-
14544
- class AsyncStackTaggingZoneSpec {
14545
- constructor(namePrefix, consoleAsyncStackTaggingImpl = console) {
14546
- this.name = 'asyncStackTagging for ' + namePrefix;
14547
- this.createTask = consoleAsyncStackTaggingImpl?.createTask ?? (() => null);
14548
- }
14549
- onScheduleTask(delegate, _current, target, task) {
14550
- task.consoleTask = this.createTask(`Zone - ${task.source || task.type}`);
14551
- return delegate.scheduleTask(target, task);
14552
- }
14553
- onInvokeTask(delegate, _currentZone, targetZone, task, applyThis, applyArgs) {
14554
- let ret;
14555
- if (task.consoleTask) {
14556
- ret = task.consoleTask.run(() => delegate.invokeTask(targetZone, task, applyThis, applyArgs));
14557
- }
14558
- else {
14559
- ret = delegate.invokeTask(targetZone, task, applyThis, applyArgs);
14560
- }
14561
- return ret;
14562
- }
14507
+ /**
14508
+ * The phase to run an `afterRender` or `afterNextRender` callback in.
14509
+ *
14510
+ * Callbacks in the same phase run in the order they are registered. Phases run in the
14511
+ * following order after each render:
14512
+ *
14513
+ * 1. `AfterRenderPhase.EarlyRead`
14514
+ * 2. `AfterRenderPhase.Write`
14515
+ * 3. `AfterRenderPhase.MixedReadWrite`
14516
+ * 4. `AfterRenderPhase.Read`
14517
+ *
14518
+ * Angular is unable to verify or enforce that phases are used correctly, and instead
14519
+ * relies on each developer to follow the guidelines documented for each value and
14520
+ * carefully choose the appropriate one, refactoring their code if necessary. By doing
14521
+ * so, Angular is better able to minimize the performance degradation associated with
14522
+ * manual DOM access, ensuring the best experience for the end users of your application
14523
+ * or library.
14524
+ *
14525
+ * @developerPreview
14526
+ */
14527
+ var AfterRenderPhase;
14528
+ (function (AfterRenderPhase) {
14529
+ /**
14530
+ * Use `AfterRenderPhase.EarlyRead` for callbacks that only need to **read** from the
14531
+ * DOM before a subsequent `AfterRenderPhase.Write` callback, for example to perform
14532
+ * custom layout that the browser doesn't natively support. **Never** use this phase
14533
+ * for callbacks that can write to the DOM or when `AfterRenderPhase.Read` is adequate.
14534
+ *
14535
+ * <div class="alert is-important">
14536
+ *
14537
+ * Using this value can degrade performance.
14538
+ * Instead, prefer using built-in browser functionality when possible.
14539
+ *
14540
+ * </div>
14541
+ */
14542
+ AfterRenderPhase[AfterRenderPhase["EarlyRead"] = 0] = "EarlyRead";
14543
+ /**
14544
+ * Use `AfterRenderPhase.Write` for callbacks that only **write** to the DOM. **Never**
14545
+ * use this phase for callbacks that can read from the DOM.
14546
+ */
14547
+ AfterRenderPhase[AfterRenderPhase["Write"] = 1] = "Write";
14548
+ /**
14549
+ * Use `AfterRenderPhase.MixedReadWrite` for callbacks that read from or write to the
14550
+ * DOM, that haven't been refactored to use a different phase. **Never** use this phase
14551
+ * for callbacks that can use a different phase instead.
14552
+ *
14553
+ * <div class="alert is-critical">
14554
+ *
14555
+ * Using this value can **significantly** degrade performance.
14556
+ * Instead, prefer refactoring into multiple callbacks using a more specific phase.
14557
+ *
14558
+ * </div>
14559
+ */
14560
+ AfterRenderPhase[AfterRenderPhase["MixedReadWrite"] = 2] = "MixedReadWrite";
14561
+ /**
14562
+ * Use `AfterRenderPhase.Read` for callbacks that only **read** from the DOM. **Never**
14563
+ * use this phase for callbacks that can write to the DOM.
14564
+ */
14565
+ AfterRenderPhase[AfterRenderPhase["Read"] = 3] = "Read";
14566
+ })(AfterRenderPhase || (AfterRenderPhase = {}));
14567
+ /** `AfterRenderRef` that does nothing. */
14568
+ const NOOP_AFTER_RENDER_REF = {
14569
+ destroy() { }
14570
+ };
14571
+ /**
14572
+ * Register a callback to run once before any userspace `afterRender` or
14573
+ * `afterNextRender` callbacks.
14574
+ *
14575
+ * This function should almost always be used instead of `afterRender` or
14576
+ * `afterNextRender` for implementing framework functionality. Consider:
14577
+ *
14578
+ * 1.) `AfterRenderPhase.EarlyRead` is intended to be used for implementing
14579
+ * custom layout. If the framework itself mutates the DOM after *any*
14580
+ * `AfterRenderPhase.EarlyRead` callbacks are run, the phase can no
14581
+ * longer reliably serve its purpose.
14582
+ *
14583
+ * 2.) Importing `afterRender` in the framework can reduce the ability for it
14584
+ * to be tree-shaken, and the framework shouldn't need much of the behavior.
14585
+ */
14586
+ function internalAfterNextRender(callback, options) {
14587
+ const injector = options?.injector ?? inject(Injector);
14588
+ // Similarly to the public `afterNextRender` function, an internal one
14589
+ // is only invoked in a browser as long as the runOnServer option is not set.
14590
+ if (!options?.runOnServer && !isPlatformBrowser(injector))
14591
+ return;
14592
+ const afterRenderEventManager = injector.get(AfterRenderEventManager);
14593
+ afterRenderEventManager.internalCallbacks.push(callback);
14563
14594
  }
14564
-
14565
14595
  /**
14566
- * An injectable service for executing work inside or outside of the Angular zone.
14596
+ * Register a callback to be invoked each time the application
14597
+ * finishes rendering.
14567
14598
  *
14568
- * The most common use of this service is to optimize performance when starting a work consisting of
14569
- * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
14570
- * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
14571
- * can reenter the Angular zone via {@link #run}.
14599
+ * <div class="alert is-critical">
14572
14600
  *
14573
- * <!-- TODO: add/fix links to:
14574
- * - docs explaining zones and the use of zones in Angular and change-detection
14575
- * - link to runOutsideAngular/run (throughout this file!)
14576
- * -->
14601
+ * You should always explicitly specify a non-default [phase](api/core/AfterRenderPhase), or you
14602
+ * risk significant performance degradation.
14577
14603
  *
14578
- * @usageNotes
14579
- * ### Example
14604
+ * </div>
14580
14605
  *
14581
- * ```
14582
- * import {Component, NgZone} from '@angular/core';
14583
- * import {NgIf} from '@angular/common';
14606
+ * Note that the callback will run
14607
+ * - in the order it was registered
14608
+ * - once per render
14609
+ * - on browser platforms only
14584
14610
  *
14585
- * @Component({
14586
- * selector: 'ng-zone-demo',
14587
- * template: `
14588
- * <h2>Demo: NgZone</h2>
14611
+ * <div class="alert is-important">
14589
14612
  *
14590
- * <p>Progress: {{progress}}%</p>
14591
- * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
14613
+ * Components are not guaranteed to be [hydrated](guide/hydration) before the callback runs.
14614
+ * You must use caution when directly reading or writing the DOM and layout.
14592
14615
  *
14593
- * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
14594
- * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
14595
- * `,
14596
- * })
14597
- * export class NgZoneDemo {
14598
- * progress: number = 0;
14599
- * label: string;
14616
+ * </div>
14600
14617
  *
14601
- * constructor(private _ngZone: NgZone) {}
14618
+ * @param callback A callback function to register
14602
14619
  *
14603
- * // Loop inside the Angular zone
14604
- * // so the UI DOES refresh after each setTimeout cycle
14605
- * processWithinAngularZone() {
14606
- * this.label = 'inside';
14607
- * this.progress = 0;
14608
- * this._increaseProgress(() => console.log('Inside Done!'));
14609
- * }
14620
+ * @usageNotes
14610
14621
  *
14611
- * // Loop outside of the Angular zone
14612
- * // so the UI DOES NOT refresh after each setTimeout cycle
14613
- * processOutsideOfAngularZone() {
14614
- * this.label = 'outside';
14615
- * this.progress = 0;
14616
- * this._ngZone.runOutsideAngular(() => {
14617
- * this._increaseProgress(() => {
14618
- * // reenter the Angular zone and display done
14619
- * this._ngZone.run(() => { console.log('Outside Done!'); });
14620
- * });
14621
- * });
14622
- * }
14622
+ * Use `afterRender` to read or write the DOM after each render.
14623
14623
  *
14624
- * _increaseProgress(doneCallback: () => void) {
14625
- * this.progress += 1;
14626
- * console.log(`Current progress: ${this.progress}%`);
14624
+ * ### Example
14625
+ * ```ts
14626
+ * @Component({
14627
+ * selector: 'my-cmp',
14628
+ * template: `<span #content>{{ ... }}</span>`,
14629
+ * })
14630
+ * export class MyComponent {
14631
+ * @ViewChild('content') contentRef: ElementRef;
14627
14632
  *
14628
- * if (this.progress < 100) {
14629
- * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
14630
- * } else {
14631
- * doneCallback();
14632
- * }
14633
+ * constructor() {
14634
+ * afterRender(() => {
14635
+ * console.log('content height: ' + this.contentRef.nativeElement.scrollHeight);
14636
+ * }, {phase: AfterRenderPhase.Read});
14633
14637
  * }
14634
14638
  * }
14635
14639
  * ```
14636
14640
  *
14637
- * @publicApi
14638
- */
14639
- class NgZone {
14640
- constructor({ enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false }) {
14641
- this.hasPendingMacrotasks = false;
14642
- this.hasPendingMicrotasks = false;
14643
- /**
14644
- * Whether there are no outstanding microtasks or macrotasks.
14645
- */
14646
- this.isStable = true;
14647
- /**
14648
- * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
14649
- */
14650
- this.onUnstable = new EventEmitter(false);
14651
- /**
14652
- * Notifies when there is no more microtasks enqueued in the current VM Turn.
14653
- * This is a hint for Angular to do change detection, which may enqueue more microtasks.
14654
- * For this reason this event can fire multiple times per VM Turn.
14655
- */
14656
- this.onMicrotaskEmpty = new EventEmitter(false);
14657
- /**
14658
- * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
14659
- * implies we are about to relinquish VM turn.
14660
- * This event gets called just once.
14661
- */
14662
- this.onStable = new EventEmitter(false);
14663
- /**
14664
- * Notifies that an error has been delivered.
14665
- */
14666
- this.onError = new EventEmitter(false);
14667
- if (typeof Zone == 'undefined') {
14668
- throw new RuntimeError(908 /* RuntimeErrorCode.MISSING_ZONEJS */, ngDevMode && `In this configuration Angular requires Zone.js`);
14669
- }
14670
- Zone.assertZonePatched();
14671
- const self = this;
14672
- self._nesting = 0;
14673
- self._outer = self._inner = Zone.current;
14674
- // AsyncStackTaggingZoneSpec provides `linked stack traces` to show
14675
- // where the async operation is scheduled. For more details, refer
14676
- // to this article, https://developer.chrome.com/blog/devtools-better-angular-debugging/
14677
- // And we only import this AsyncStackTaggingZoneSpec in development mode,
14678
- // in the production mode, the AsyncStackTaggingZoneSpec will be tree shaken away.
14679
- if (ngDevMode) {
14680
- self._inner = self._inner.fork(new AsyncStackTaggingZoneSpec('Angular'));
14681
- }
14682
- if (Zone['TaskTrackingZoneSpec']) {
14683
- self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']);
14684
- }
14685
- if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
14686
- self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
14687
- }
14688
- // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
14689
- // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
14690
- self.shouldCoalesceEventChangeDetection =
14691
- !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
14692
- self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
14693
- self.lastRequestAnimationFrameId = -1;
14694
- self.nativeRequestAnimationFrame = getNativeRequestAnimationFrame().nativeRequestAnimationFrame;
14695
- forkInnerZoneWithAngularBehavior(self);
14696
- }
14697
- /**
14698
- This method checks whether the method call happens within an Angular Zone instance.
14699
- */
14700
- static isInAngularZone() {
14701
- // Zone needs to be checked, because this method might be called even when NoopNgZone is used.
14702
- return typeof Zone !== 'undefined' && Zone.current.get('isAngularZone') === true;
14703
- }
14704
- /**
14705
- Assures that the method is called within the Angular Zone, otherwise throws an error.
14706
- */
14707
- static assertInAngularZone() {
14708
- if (!NgZone.isInAngularZone()) {
14709
- throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to be in Angular Zone, but it is not!');
14710
- }
14711
- }
14712
- /**
14713
- Assures that the method is called outside of the Angular Zone, otherwise throws an error.
14714
- */
14715
- static assertNotInAngularZone() {
14716
- if (NgZone.isInAngularZone()) {
14717
- throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to not be in Angular Zone, but it is!');
14718
- }
14719
- }
14720
- /**
14721
- * Executes the `fn` function synchronously within the Angular zone and returns value returned by
14722
- * the function.
14723
- *
14724
- * Running functions via `run` allows you to reenter Angular zone from a task that was executed
14725
- * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
14726
- *
14727
- * Any future tasks or microtasks scheduled from within this function will continue executing from
14728
- * within the Angular zone.
14729
- *
14730
- * If a synchronous error happens it will be rethrown and not reported via `onError`.
14731
- */
14732
- run(fn, applyThis, applyArgs) {
14733
- return this._inner.run(fn, applyThis, applyArgs);
14734
- }
14735
- /**
14736
- * Executes the `fn` function synchronously within the Angular zone as a task and returns value
14737
- * returned by the function.
14738
- *
14739
- * Running functions via `run` allows you to reenter Angular zone from a task that was executed
14740
- * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
14741
- *
14742
- * Any future tasks or microtasks scheduled from within this function will continue executing from
14743
- * within the Angular zone.
14744
- *
14745
- * If a synchronous error happens it will be rethrown and not reported via `onError`.
14746
- */
14747
- runTask(fn, applyThis, applyArgs, name) {
14748
- const zone = this._inner;
14749
- const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
14750
- try {
14751
- return zone.runTask(task, applyThis, applyArgs);
14752
- }
14753
- finally {
14754
- zone.cancelTask(task);
14755
- }
14756
- }
14757
- /**
14758
- * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
14759
- * rethrown.
14760
- */
14761
- runGuarded(fn, applyThis, applyArgs) {
14762
- return this._inner.runGuarded(fn, applyThis, applyArgs);
14763
- }
14764
- /**
14765
- * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
14766
- * the function.
14767
- *
14768
- * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
14769
- * work that
14770
- * doesn't trigger Angular change-detection or is subject to Angular's error handling.
14771
- *
14772
- * Any future tasks or microtasks scheduled from within this function will continue executing from
14773
- * outside of the Angular zone.
14774
- *
14775
- * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
14776
- */
14777
- runOutsideAngular(fn) {
14778
- return this._outer.run(fn);
14779
- }
14780
- }
14781
- const EMPTY_PAYLOAD = {};
14782
- function checkStable(zone) {
14783
- // TODO: @JiaLiPassion, should check zone.isCheckStableRunning to prevent
14784
- // re-entry. The case is:
14785
- //
14786
- // @Component({...})
14787
- // export class AppComponent {
14788
- // constructor(private ngZone: NgZone) {
14789
- // this.ngZone.onStable.subscribe(() => {
14790
- // this.ngZone.run(() => console.log('stable'););
14791
- // });
14792
- // }
14793
- //
14794
- // The onStable subscriber run another function inside ngZone
14795
- // which causes `checkStable()` re-entry.
14796
- // But this fix causes some issues in g3, so this fix will be
14797
- // launched in another PR.
14798
- if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
14799
- try {
14800
- zone._nesting++;
14801
- zone.onMicrotaskEmpty.emit(null);
14802
- }
14803
- finally {
14804
- zone._nesting--;
14805
- if (!zone.hasPendingMicrotasks) {
14806
- try {
14807
- zone.runOutsideAngular(() => zone.onStable.emit(null));
14808
- }
14809
- finally {
14810
- zone.isStable = true;
14811
- }
14812
- }
14813
- }
14814
- }
14815
- }
14816
- function delayChangeDetectionForEvents(zone) {
14817
- /**
14818
- * We also need to check _nesting here
14819
- * Consider the following case with shouldCoalesceRunChangeDetection = true
14820
- *
14821
- * ngZone.run(() => {});
14822
- * ngZone.run(() => {});
14823
- *
14824
- * We want the two `ngZone.run()` only trigger one change detection
14825
- * when shouldCoalesceRunChangeDetection is true.
14826
- * And because in this case, change detection run in async way(requestAnimationFrame),
14827
- * so we also need to check the _nesting here to prevent multiple
14828
- * change detections.
14829
- */
14830
- if (zone.isCheckStableRunning || zone.lastRequestAnimationFrameId !== -1) {
14831
- return;
14832
- }
14833
- zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(_global, () => {
14834
- // This is a work around for https://github.com/angular/angular/issues/36839.
14835
- // The core issue is that when event coalescing is enabled it is possible for microtasks
14836
- // to get flushed too early (As is the case with `Promise.then`) between the
14837
- // coalescing eventTasks.
14838
- //
14839
- // To workaround this we schedule a "fake" eventTask before we process the
14840
- // coalescing eventTasks. The benefit of this is that the "fake" container eventTask
14841
- // will prevent the microtasks queue from getting drained in between the coalescing
14842
- // eventTask execution.
14843
- if (!zone.fakeTopEventTask) {
14844
- zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
14845
- zone.lastRequestAnimationFrameId = -1;
14846
- updateMicroTaskStatus(zone);
14847
- zone.isCheckStableRunning = true;
14848
- checkStable(zone);
14849
- zone.isCheckStableRunning = false;
14850
- }, undefined, () => { }, () => { });
14851
- }
14852
- zone.fakeTopEventTask.invoke();
14853
- });
14854
- updateMicroTaskStatus(zone);
14855
- }
14856
- function forkInnerZoneWithAngularBehavior(zone) {
14857
- const delayChangeDetectionForEventsDelegate = () => {
14858
- delayChangeDetectionForEvents(zone);
14859
- };
14860
- zone._inner = zone._inner.fork({
14861
- name: 'angular',
14862
- properties: { 'isAngularZone': true },
14863
- onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
14864
- if (shouldBeIgnoredByZone(applyArgs)) {
14865
- return delegate.invokeTask(target, task, applyThis, applyArgs);
14866
- }
14867
- try {
14868
- onEnter(zone);
14869
- return delegate.invokeTask(target, task, applyThis, applyArgs);
14870
- }
14871
- finally {
14872
- if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
14873
- zone.shouldCoalesceRunChangeDetection) {
14874
- delayChangeDetectionForEventsDelegate();
14875
- }
14876
- onLeave(zone);
14877
- }
14878
- },
14879
- onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
14880
- try {
14881
- onEnter(zone);
14882
- return delegate.invoke(target, callback, applyThis, applyArgs, source);
14883
- }
14884
- finally {
14885
- if (zone.shouldCoalesceRunChangeDetection) {
14886
- delayChangeDetectionForEventsDelegate();
14887
- }
14888
- onLeave(zone);
14889
- }
14890
- },
14891
- onHasTask: (delegate, current, target, hasTaskState) => {
14892
- delegate.hasTask(target, hasTaskState);
14893
- if (current === target) {
14894
- // We are only interested in hasTask events which originate from our zone
14895
- // (A child hasTask event is not interesting to us)
14896
- if (hasTaskState.change == 'microTask') {
14897
- zone._hasPendingMicrotasks = hasTaskState.microTask;
14898
- updateMicroTaskStatus(zone);
14899
- checkStable(zone);
14900
- }
14901
- else if (hasTaskState.change == 'macroTask') {
14902
- zone.hasPendingMacrotasks = hasTaskState.macroTask;
14903
- }
14904
- }
14905
- },
14906
- onHandleError: (delegate, current, target, error) => {
14907
- delegate.handleError(target, error);
14908
- zone.runOutsideAngular(() => zone.onError.emit(error));
14909
- return false;
14910
- }
14911
- });
14912
- }
14913
- function updateMicroTaskStatus(zone) {
14914
- if (zone._hasPendingMicrotasks ||
14915
- ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
14916
- zone.lastRequestAnimationFrameId !== -1)) {
14917
- zone.hasPendingMicrotasks = true;
14918
- }
14919
- else {
14920
- zone.hasPendingMicrotasks = false;
14921
- }
14922
- }
14923
- function onEnter(zone) {
14924
- zone._nesting++;
14925
- if (zone.isStable) {
14926
- zone.isStable = false;
14927
- zone.onUnstable.emit(null);
14928
- }
14929
- }
14930
- function onLeave(zone) {
14931
- zone._nesting--;
14932
- checkStable(zone);
14933
- }
14934
- /**
14935
- * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
14936
- * to framework to perform rendering.
14937
- */
14938
- class NoopNgZone {
14939
- constructor() {
14940
- this.hasPendingMicrotasks = false;
14941
- this.hasPendingMacrotasks = false;
14942
- this.isStable = true;
14943
- this.onUnstable = new EventEmitter();
14944
- this.onMicrotaskEmpty = new EventEmitter();
14945
- this.onStable = new EventEmitter();
14946
- this.onError = new EventEmitter();
14947
- }
14948
- run(fn, applyThis, applyArgs) {
14949
- return fn.apply(applyThis, applyArgs);
14950
- }
14951
- runGuarded(fn, applyThis, applyArgs) {
14952
- return fn.apply(applyThis, applyArgs);
14953
- }
14954
- runOutsideAngular(fn) {
14955
- return fn();
14956
- }
14957
- runTask(fn, applyThis, applyArgs, name) {
14958
- return fn.apply(applyThis, applyArgs);
14959
- }
14960
- }
14961
- function shouldBeIgnoredByZone(applyArgs) {
14962
- if (!Array.isArray(applyArgs)) {
14963
- return false;
14964
- }
14965
- // We should only ever get 1 arg passed through to invokeTask.
14966
- // Short circuit here incase that behavior changes.
14967
- if (applyArgs.length !== 1) {
14968
- return false;
14969
- }
14970
- // Prevent triggering change detection when the __ignore_ng_zone__ flag is detected.
14971
- return applyArgs[0].data?.['__ignore_ng_zone__'] === true;
14972
- }
14973
- function getNgZone(ngZoneToUse = 'zone.js', options) {
14974
- if (ngZoneToUse === 'noop') {
14975
- return new NoopNgZone();
14976
- }
14977
- if (ngZoneToUse === 'zone.js') {
14978
- return new NgZone(options);
14979
- }
14980
- return ngZoneToUse;
14981
- }
14982
-
14983
- /**
14984
- * The phase to run an `afterRender` or `afterNextRender` callback in.
14985
- *
14986
- * Callbacks in the same phase run in the order they are registered. Phases run in the
14987
- * following order after each render:
14988
- *
14989
- * 1. `AfterRenderPhase.EarlyRead`
14990
- * 2. `AfterRenderPhase.Write`
14991
- * 3. `AfterRenderPhase.MixedReadWrite`
14992
- * 4. `AfterRenderPhase.Read`
14993
- *
14994
- * Angular is unable to verify or enforce that phases are used correctly, and instead
14995
- * relies on each developer to follow the guidelines documented for each value and
14996
- * carefully choose the appropriate one, refactoring their code if necessary. By doing
14997
- * so, Angular is better able to minimize the performance degradation associated with
14998
- * manual DOM access, ensuring the best experience for the end users of your application
14999
- * or library.
15000
- *
15001
- * @developerPreview
15002
- */
15003
- var AfterRenderPhase;
15004
- (function (AfterRenderPhase) {
15005
- /**
15006
- * Use `AfterRenderPhase.EarlyRead` for callbacks that only need to **read** from the
15007
- * DOM before a subsequent `AfterRenderPhase.Write` callback, for example to perform
15008
- * custom layout that the browser doesn't natively support. **Never** use this phase
15009
- * for callbacks that can write to the DOM or when `AfterRenderPhase.Read` is adequate.
15010
- *
15011
- * <div class="alert is-important">
15012
- *
15013
- * Using this value can degrade performance.
15014
- * Instead, prefer using built-in browser functionality when possible.
15015
- *
15016
- * </div>
15017
- */
15018
- AfterRenderPhase[AfterRenderPhase["EarlyRead"] = 0] = "EarlyRead";
15019
- /**
15020
- * Use `AfterRenderPhase.Write` for callbacks that only **write** to the DOM. **Never**
15021
- * use this phase for callbacks that can read from the DOM.
15022
- */
15023
- AfterRenderPhase[AfterRenderPhase["Write"] = 1] = "Write";
15024
- /**
15025
- * Use `AfterRenderPhase.MixedReadWrite` for callbacks that read from or write to the
15026
- * DOM, that haven't been refactored to use a different phase. **Never** use this phase
15027
- * for callbacks that can use a different phase instead.
15028
- *
15029
- * <div class="alert is-critical">
15030
- *
15031
- * Using this value can **significantly** degrade performance.
15032
- * Instead, prefer refactoring into multiple callbacks using a more specific phase.
15033
- *
15034
- * </div>
15035
- */
15036
- AfterRenderPhase[AfterRenderPhase["MixedReadWrite"] = 2] = "MixedReadWrite";
15037
- /**
15038
- * Use `AfterRenderPhase.Read` for callbacks that only **read** from the DOM. **Never**
15039
- * use this phase for callbacks that can write to the DOM.
15040
- */
15041
- AfterRenderPhase[AfterRenderPhase["Read"] = 3] = "Read";
15042
- })(AfterRenderPhase || (AfterRenderPhase = {}));
15043
- /** `AfterRenderRef` that does nothing. */
15044
- const NOOP_AFTER_RENDER_REF = {
15045
- destroy() { }
15046
- };
15047
- /**
15048
- * Register a callback to run once before any userspace `afterRender` or
15049
- * `afterNextRender` callbacks.
15050
- *
15051
- * This function should almost always be used instead of `afterRender` or
15052
- * `afterNextRender` for implementing framework functionality. Consider:
15053
- *
15054
- * 1.) `AfterRenderPhase.EarlyRead` is intended to be used for implementing
15055
- * custom layout. If the framework itself mutates the DOM after *any*
15056
- * `AfterRenderPhase.EarlyRead` callbacks are run, the phase can no
15057
- * longer reliably serve its purpose.
15058
- *
15059
- * 2.) Importing `afterRender` in the framework can reduce the ability for it
15060
- * to be tree-shaken, and the framework shouldn't need much of the behavior.
15061
- */
15062
- function internalAfterNextRender(callback, options) {
15063
- const injector = options?.injector ?? inject(Injector);
15064
- // Similarly to the public `afterNextRender` function, an internal one
15065
- // is only invoked in a browser as long as the runOnServer option is not set.
15066
- if (!options?.runOnServer && !isPlatformBrowser(injector))
15067
- return;
15068
- const afterRenderEventManager = injector.get(AfterRenderEventManager);
15069
- afterRenderEventManager.internalCallbacks.push(callback);
15070
- }
15071
- /**
15072
- * Register a callback to be invoked each time the application
15073
- * finishes rendering.
15074
- *
15075
- * <div class="alert is-critical">
15076
- *
15077
- * You should always explicitly specify a non-default [phase](api/core/AfterRenderPhase), or you
15078
- * risk significant performance degradation.
15079
- *
15080
- * </div>
15081
- *
15082
- * Note that the callback will run
15083
- * - in the order it was registered
15084
- * - once per render
15085
- * - on browser platforms only
15086
- *
15087
- * <div class="alert is-important">
15088
- *
15089
- * Components are not guaranteed to be [hydrated](guide/hydration) before the callback runs.
15090
- * You must use caution when directly reading or writing the DOM and layout.
15091
- *
15092
- * </div>
15093
- *
15094
- * @param callback A callback function to register
15095
- *
15096
- * @usageNotes
15097
- *
15098
- * Use `afterRender` to read or write the DOM after each render.
15099
- *
15100
- * ### Example
15101
- * ```ts
15102
- * @Component({
15103
- * selector: 'my-cmp',
15104
- * template: `<span #content>{{ ... }}</span>`,
15105
- * })
15106
- * export class MyComponent {
15107
- * @ViewChild('content') contentRef: ElementRef;
15108
- *
15109
- * constructor() {
15110
- * afterRender(() => {
15111
- * console.log('content height: ' + this.contentRef.nativeElement.scrollHeight);
15112
- * }, {phase: AfterRenderPhase.Read});
15113
- * }
15114
- * }
15115
- * ```
15116
- *
15117
- * @developerPreview
14641
+ * @developerPreview
15118
14642
  */
15119
14643
  function afterRender(callback, options) {
15120
14644
  ngDevMode &&
@@ -15220,14 +14744,13 @@ class AfterRenderCallback {
15220
14744
  constructor(phase, callbackFn) {
15221
14745
  this.phase = phase;
15222
14746
  this.callbackFn = callbackFn;
15223
- this.zone = inject(NgZone);
15224
14747
  this.errorHandler = inject(ErrorHandler, { optional: true });
15225
14748
  // Registering a callback will notify the scheduler.
15226
14749
  inject(ChangeDetectionScheduler, { optional: true })?.notify(1 /* NotificationType.AfterRenderHooks */);
15227
14750
  }
15228
14751
  invoke() {
15229
14752
  try {
15230
- this.zone.runOutsideAngular(this.callbackFn);
14753
+ this.callbackFn();
15231
14754
  }
15232
14755
  catch (err) {
15233
14756
  this.errorHandler?.handleError(err);
@@ -16022,7 +15545,7 @@ function createRootComponent(componentView, rootComponentDef, rootDirectives, ho
16022
15545
  function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) {
16023
15546
  if (rootSelectorOrNode) {
16024
15547
  // The placeholder will be replaced with the actual version at build time.
16025
- setUpAttributes(hostRenderer, hostRNode, ['ng-version', '17.3.6']);
15548
+ setUpAttributes(hostRenderer, hostRNode, ['ng-version', '17.3.7']);
16026
15549
  }
16027
15550
  else {
16028
15551
  // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
@@ -17448,1210 +16971,1686 @@ function restoreComponentResolutionQueue(queue) {
17448
16971
  function isComponentResourceResolutionQueueEmpty() {
17449
16972
  return componentResourceResolutionQueue.size === 0;
17450
16973
  }
17451
- function unwrapResponse(response) {
17452
- return typeof response == 'string' ? response : response.text();
16974
+ function unwrapResponse(response) {
16975
+ return typeof response == 'string' ? response : response.text();
16976
+ }
16977
+ function componentDefResolved(type) {
16978
+ componentDefPendingResolution.delete(type);
16979
+ }
16980
+
16981
+ /**
16982
+ * Map of module-id to the corresponding NgModule.
16983
+ */
16984
+ const modules = new Map();
16985
+ /**
16986
+ * Whether to check for duplicate NgModule registrations.
16987
+ *
16988
+ * This can be disabled for testing.
16989
+ */
16990
+ let checkForDuplicateNgModules = true;
16991
+ function assertSameOrNotExisting(id, type, incoming) {
16992
+ if (type && type !== incoming && checkForDuplicateNgModules) {
16993
+ throw new Error(`Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`);
16994
+ }
16995
+ }
16996
+ /**
16997
+ * Adds the given NgModule type to Angular's NgModule registry.
16998
+ *
16999
+ * This is generated as a side-effect of NgModule compilation. Note that the `id` is passed in
17000
+ * explicitly and not read from the NgModule definition. This is for two reasons: it avoids a
17001
+ * megamorphic read, and in JIT there's a chicken-and-egg problem where the NgModule may not be
17002
+ * fully resolved when it's registered.
17003
+ *
17004
+ * @codeGenApi
17005
+ */
17006
+ function registerNgModuleType(ngModuleType, id) {
17007
+ const existing = modules.get(id) || null;
17008
+ assertSameOrNotExisting(id, existing, ngModuleType);
17009
+ modules.set(id, ngModuleType);
17010
+ }
17011
+ function clearModulesForTest() {
17012
+ modules.clear();
17013
+ }
17014
+ function getRegisteredNgModuleType(id) {
17015
+ return modules.get(id);
17016
+ }
17017
+ /**
17018
+ * Control whether the NgModule registration system enforces that each NgModule type registered has
17019
+ * a unique id.
17020
+ *
17021
+ * This is useful for testing as the NgModule registry cannot be properly reset between tests with
17022
+ * Angular's current API.
17023
+ */
17024
+ function setAllowDuplicateNgModuleIdsForTest(allowDuplicates) {
17025
+ checkForDuplicateNgModules = !allowDuplicates;
17026
+ }
17027
+
17028
+ /**
17029
+ * Validation function invoked at runtime for each binding that might potentially
17030
+ * represent a security-sensitive attribute of an <iframe>.
17031
+ * See `IFRAME_SECURITY_SENSITIVE_ATTRS` in the
17032
+ * `packages/compiler/src/schema/dom_security_schema.ts` script for the full list
17033
+ * of such attributes.
17034
+ *
17035
+ * @codeGenApi
17036
+ */
17037
+ function ɵɵvalidateIframeAttribute(attrValue, tagName, attrName) {
17038
+ const lView = getLView();
17039
+ const tNode = getSelectedTNode();
17040
+ const element = getNativeByTNode(tNode, lView);
17041
+ // Restrict any dynamic bindings of security-sensitive attributes/properties
17042
+ // on an <iframe> for security reasons.
17043
+ if (tNode.type === 2 /* TNodeType.Element */ && tagName.toLowerCase() === 'iframe') {
17044
+ const iframe = element;
17045
+ // Unset previously applied `src` and `srcdoc` if we come across a situation when
17046
+ // a security-sensitive attribute is set later via an attribute/property binding.
17047
+ iframe.src = '';
17048
+ iframe.srcdoc = trustedHTMLFromString('');
17049
+ // Also remove the <iframe> from the document.
17050
+ nativeRemoveNode(lView[RENDERER], iframe);
17051
+ const errorMessage = ngDevMode &&
17052
+ `Angular has detected that the \`${attrName}\` was applied ` +
17053
+ `as a binding to an <iframe>${getTemplateLocationDetails(lView)}. ` +
17054
+ `For security reasons, the \`${attrName}\` can be set on an <iframe> ` +
17055
+ `as a static attribute only. \n` +
17056
+ `To fix this, switch the \`${attrName}\` binding to a static attribute ` +
17057
+ `in a template or in host bindings section.`;
17058
+ throw new RuntimeError(-910 /* RuntimeErrorCode.UNSAFE_IFRAME_ATTRS */, errorMessage);
17059
+ }
17060
+ return attrValue;
17061
+ }
17062
+
17063
+ function getSuperType(type) {
17064
+ return Object.getPrototypeOf(type.prototype).constructor;
17065
+ }
17066
+ /**
17067
+ * Merges the definition from a super class to a sub class.
17068
+ * @param definition The definition that is a SubClass of another directive of component
17069
+ *
17070
+ * @codeGenApi
17071
+ */
17072
+ function ɵɵInheritDefinitionFeature(definition) {
17073
+ let superType = getSuperType(definition.type);
17074
+ let shouldInheritFields = true;
17075
+ const inheritanceChain = [definition];
17076
+ while (superType) {
17077
+ let superDef = undefined;
17078
+ if (isComponentDef(definition)) {
17079
+ // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17080
+ superDef = superType.ɵcmp || superType.ɵdir;
17081
+ }
17082
+ else {
17083
+ if (superType.ɵcmp) {
17084
+ throw new RuntimeError(903 /* RuntimeErrorCode.INVALID_INHERITANCE */, ngDevMode &&
17085
+ `Directives cannot inherit Components. Directive ${stringifyForError(definition.type)} is attempting to extend component ${stringifyForError(superType)}`);
17086
+ }
17087
+ // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17088
+ superDef = superType.ɵdir;
17089
+ }
17090
+ if (superDef) {
17091
+ if (shouldInheritFields) {
17092
+ inheritanceChain.push(superDef);
17093
+ // Some fields in the definition may be empty, if there were no values to put in them that
17094
+ // would've justified object creation. Unwrap them if necessary.
17095
+ const writeableDef = definition;
17096
+ writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
17097
+ writeableDef.inputTransforms = maybeUnwrapEmpty(definition.inputTransforms);
17098
+ writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
17099
+ writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
17100
+ // Merge hostBindings
17101
+ const superHostBindings = superDef.hostBindings;
17102
+ superHostBindings && inheritHostBindings(definition, superHostBindings);
17103
+ // Merge queries
17104
+ const superViewQuery = superDef.viewQuery;
17105
+ const superContentQueries = superDef.contentQueries;
17106
+ superViewQuery && inheritViewQuery(definition, superViewQuery);
17107
+ superContentQueries && inheritContentQueries(definition, superContentQueries);
17108
+ // Merge inputs and outputs
17109
+ mergeInputsWithTransforms(definition, superDef);
17110
+ fillProperties(definition.outputs, superDef.outputs);
17111
+ // Merge animations metadata.
17112
+ // If `superDef` is a Component, the `data` field is present (defaults to an empty object).
17113
+ if (isComponentDef(superDef) && superDef.data.animation) {
17114
+ // If super def is a Component, the `definition` is also a Component, since Directives can
17115
+ // not inherit Components (we throw an error above and cannot reach this code).
17116
+ const defData = definition.data;
17117
+ defData.animation = (defData.animation || []).concat(superDef.data.animation);
17118
+ }
17119
+ }
17120
+ // Run parent features
17121
+ const features = superDef.features;
17122
+ if (features) {
17123
+ for (let i = 0; i < features.length; i++) {
17124
+ const feature = features[i];
17125
+ if (feature && feature.ngInherit) {
17126
+ feature(definition);
17127
+ }
17128
+ // If `InheritDefinitionFeature` is a part of the current `superDef`, it means that this
17129
+ // def already has all the necessary information inherited from its super class(es), so we
17130
+ // can stop merging fields from super classes. However we need to iterate through the
17131
+ // prototype chain to look for classes that might contain other "features" (like
17132
+ // NgOnChanges), which we should invoke for the original `definition`. We set the
17133
+ // `shouldInheritFields` flag to indicate that, essentially skipping fields inheritance
17134
+ // logic and only invoking functions from the "features" list.
17135
+ if (feature === ɵɵInheritDefinitionFeature) {
17136
+ shouldInheritFields = false;
17137
+ }
17138
+ }
17139
+ }
17140
+ }
17141
+ superType = Object.getPrototypeOf(superType);
17142
+ }
17143
+ mergeHostAttrsAcrossInheritance(inheritanceChain);
17144
+ }
17145
+ function mergeInputsWithTransforms(target, source) {
17146
+ for (const key in source.inputs) {
17147
+ if (!source.inputs.hasOwnProperty(key)) {
17148
+ continue;
17149
+ }
17150
+ if (target.inputs.hasOwnProperty(key)) {
17151
+ continue;
17152
+ }
17153
+ const value = source.inputs[key];
17154
+ if (value === undefined) {
17155
+ continue;
17156
+ }
17157
+ target.inputs[key] = value;
17158
+ target.declaredInputs[key] = source.declaredInputs[key];
17159
+ // If the input is inherited, and we have a transform for it, we also inherit it.
17160
+ // Note that transforms should not be inherited if the input has its own metadata
17161
+ // in the `source` directive itself already (i.e. the input is re-declared/overridden).
17162
+ if (source.inputTransforms !== null) {
17163
+ // Note: transforms are stored with their minified names.
17164
+ // Perf: only access the minified name when there are source transforms.
17165
+ const minifiedName = Array.isArray(value) ? value[0] : value;
17166
+ if (!source.inputTransforms.hasOwnProperty(minifiedName)) {
17167
+ continue;
17168
+ }
17169
+ target.inputTransforms ??= {};
17170
+ target.inputTransforms[minifiedName] = source.inputTransforms[minifiedName];
17171
+ }
17172
+ }
17173
+ }
17174
+ /**
17175
+ * Merge the `hostAttrs` and `hostVars` from the inherited parent to the base class.
17176
+ *
17177
+ * @param inheritanceChain A list of `WritableDefs` starting at the top most type and listing
17178
+ * sub-types in order. For each type take the `hostAttrs` and `hostVars` and merge it with the child
17179
+ * type.
17180
+ */
17181
+ function mergeHostAttrsAcrossInheritance(inheritanceChain) {
17182
+ let hostVars = 0;
17183
+ let hostAttrs = null;
17184
+ // We process the inheritance order from the base to the leaves here.
17185
+ for (let i = inheritanceChain.length - 1; i >= 0; i--) {
17186
+ const def = inheritanceChain[i];
17187
+ // For each `hostVars`, we need to add the superclass amount.
17188
+ def.hostVars = (hostVars += def.hostVars);
17189
+ // for each `hostAttrs` we need to merge it with superclass.
17190
+ def.hostAttrs =
17191
+ mergeHostAttrs(def.hostAttrs, hostAttrs = mergeHostAttrs(hostAttrs, def.hostAttrs));
17192
+ }
17193
+ }
17194
+ function maybeUnwrapEmpty(value) {
17195
+ if (value === EMPTY_OBJ) {
17196
+ return {};
17197
+ }
17198
+ else if (value === EMPTY_ARRAY) {
17199
+ return [];
17200
+ }
17201
+ else {
17202
+ return value;
17203
+ }
17204
+ }
17205
+ function inheritViewQuery(definition, superViewQuery) {
17206
+ const prevViewQuery = definition.viewQuery;
17207
+ if (prevViewQuery) {
17208
+ definition.viewQuery = (rf, ctx) => {
17209
+ superViewQuery(rf, ctx);
17210
+ prevViewQuery(rf, ctx);
17211
+ };
17212
+ }
17213
+ else {
17214
+ definition.viewQuery = superViewQuery;
17215
+ }
17216
+ }
17217
+ function inheritContentQueries(definition, superContentQueries) {
17218
+ const prevContentQueries = definition.contentQueries;
17219
+ if (prevContentQueries) {
17220
+ definition.contentQueries = (rf, ctx, directiveIndex) => {
17221
+ superContentQueries(rf, ctx, directiveIndex);
17222
+ prevContentQueries(rf, ctx, directiveIndex);
17223
+ };
17224
+ }
17225
+ else {
17226
+ definition.contentQueries = superContentQueries;
17227
+ }
17453
17228
  }
17454
- function componentDefResolved(type) {
17455
- componentDefPendingResolution.delete(type);
17229
+ function inheritHostBindings(definition, superHostBindings) {
17230
+ const prevHostBindings = definition.hostBindings;
17231
+ if (prevHostBindings) {
17232
+ definition.hostBindings = (rf, ctx) => {
17233
+ superHostBindings(rf, ctx);
17234
+ prevHostBindings(rf, ctx);
17235
+ };
17236
+ }
17237
+ else {
17238
+ definition.hostBindings = superHostBindings;
17239
+ }
17456
17240
  }
17457
17241
 
17458
17242
  /**
17459
- * Map of module-id to the corresponding NgModule.
17243
+ * Fields which exist on either directive or component definitions, and need to be copied from
17244
+ * parent to child classes by the `ɵɵCopyDefinitionFeature`.
17460
17245
  */
17461
- const modules = new Map();
17246
+ const COPY_DIRECTIVE_FIELDS = [
17247
+ // The child class should use the providers of its parent.
17248
+ 'providersResolver',
17249
+ // Not listed here are any fields which are handled by the `ɵɵInheritDefinitionFeature`, such
17250
+ // as inputs, outputs, and host binding functions.
17251
+ ];
17462
17252
  /**
17463
- * Whether to check for duplicate NgModule registrations.
17253
+ * Fields which exist only on component definitions, and need to be copied from parent to child
17254
+ * classes by the `ɵɵCopyDefinitionFeature`.
17464
17255
  *
17465
- * This can be disabled for testing.
17256
+ * The type here allows any field of `ComponentDef` which is not also a property of `DirectiveDef`,
17257
+ * since those should go in `COPY_DIRECTIVE_FIELDS` above.
17466
17258
  */
17467
- let checkForDuplicateNgModules = true;
17468
- function assertSameOrNotExisting(id, type, incoming) {
17469
- if (type && type !== incoming && checkForDuplicateNgModules) {
17470
- throw new Error(`Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`);
17259
+ const COPY_COMPONENT_FIELDS = [
17260
+ // The child class should use the template function of its parent, including all template
17261
+ // semantics.
17262
+ 'template',
17263
+ 'decls',
17264
+ 'consts',
17265
+ 'vars',
17266
+ 'onPush',
17267
+ 'ngContentSelectors',
17268
+ // The child class should use the CSS styles of its parent, including all styling semantics.
17269
+ 'styles',
17270
+ 'encapsulation',
17271
+ // The child class should be checked by the runtime in the same way as its parent.
17272
+ 'schemas',
17273
+ ];
17274
+ /**
17275
+ * Copies the fields not handled by the `ɵɵInheritDefinitionFeature` from the supertype of a
17276
+ * definition.
17277
+ *
17278
+ * This exists primarily to support ngcc migration of an existing View Engine pattern, where an
17279
+ * entire decorator is inherited from a parent to a child class. When ngcc detects this case, it
17280
+ * generates a skeleton definition on the child class, and applies this feature.
17281
+ *
17282
+ * The `ɵɵCopyDefinitionFeature` then copies any needed fields from the parent class' definition,
17283
+ * including things like the component template function.
17284
+ *
17285
+ * @param definition The definition of a child class which inherits from a parent class with its
17286
+ * own definition.
17287
+ *
17288
+ * @codeGenApi
17289
+ */
17290
+ function ɵɵCopyDefinitionFeature(definition) {
17291
+ let superType = getSuperType(definition.type);
17292
+ let superDef = undefined;
17293
+ if (isComponentDef(definition)) {
17294
+ // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17295
+ superDef = superType.ɵcmp;
17296
+ }
17297
+ else {
17298
+ // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17299
+ superDef = superType.ɵdir;
17300
+ }
17301
+ // Needed because `definition` fields are readonly.
17302
+ const defAny = definition;
17303
+ // Copy over any fields that apply to either directives or components.
17304
+ for (const field of COPY_DIRECTIVE_FIELDS) {
17305
+ defAny[field] = superDef[field];
17306
+ }
17307
+ if (isComponentDef(superDef)) {
17308
+ // Copy over any component-specific fields.
17309
+ for (const field of COPY_COMPONENT_FIELDS) {
17310
+ defAny[field] = superDef[field];
17311
+ }
17471
17312
  }
17472
17313
  }
17314
+
17473
17315
  /**
17474
- * Adds the given NgModule type to Angular's NgModule registry.
17316
+ * This feature adds the host directives behavior to a directive definition by patching a
17317
+ * function onto it. The expectation is that the runtime will invoke the function during
17318
+ * directive matching.
17475
17319
  *
17476
- * This is generated as a side-effect of NgModule compilation. Note that the `id` is passed in
17477
- * explicitly and not read from the NgModule definition. This is for two reasons: it avoids a
17478
- * megamorphic read, and in JIT there's a chicken-and-egg problem where the NgModule may not be
17479
- * fully resolved when it's registered.
17320
+ * For example:
17321
+ * ```ts
17322
+ * class ComponentWithHostDirective {
17323
+ * static ɵcmp = defineComponent({
17324
+ * type: ComponentWithHostDirective,
17325
+ * features: [ɵɵHostDirectivesFeature([
17326
+ * SimpleHostDirective,
17327
+ * {directive: AdvancedHostDirective, inputs: ['foo: alias'], outputs: ['bar']},
17328
+ * ])]
17329
+ * });
17330
+ * }
17331
+ * ```
17480
17332
  *
17481
17333
  * @codeGenApi
17482
17334
  */
17483
- function registerNgModuleType(ngModuleType, id) {
17484
- const existing = modules.get(id) || null;
17485
- assertSameOrNotExisting(id, existing, ngModuleType);
17486
- modules.set(id, ngModuleType);
17335
+ function ɵɵHostDirectivesFeature(rawHostDirectives) {
17336
+ const feature = (definition) => {
17337
+ const resolved = (Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
17338
+ return typeof dir === 'function' ?
17339
+ { directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
17340
+ {
17341
+ directive: resolveForwardRef(dir.directive),
17342
+ inputs: bindingArrayToMap(dir.inputs),
17343
+ outputs: bindingArrayToMap(dir.outputs)
17344
+ };
17345
+ });
17346
+ if (definition.hostDirectives === null) {
17347
+ definition.findHostDirectiveDefs = findHostDirectiveDefs;
17348
+ definition.hostDirectives = resolved;
17349
+ }
17350
+ else {
17351
+ definition.hostDirectives.unshift(...resolved);
17352
+ }
17353
+ };
17354
+ feature.ngInherit = true;
17355
+ return feature;
17487
17356
  }
17488
- function clearModulesForTest() {
17489
- modules.clear();
17357
+ function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
17358
+ if (currentDef.hostDirectives !== null) {
17359
+ for (const hostDirectiveConfig of currentDef.hostDirectives) {
17360
+ const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
17361
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
17362
+ validateHostDirective(hostDirectiveConfig, hostDirectiveDef);
17363
+ }
17364
+ // We need to patch the `declaredInputs` so that
17365
+ // `ngOnChanges` can map the properties correctly.
17366
+ patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
17367
+ // Host directives execute before the host so that its host bindings can be overwritten.
17368
+ findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
17369
+ hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
17370
+ matchedDefs.push(hostDirectiveDef);
17371
+ }
17372
+ }
17490
17373
  }
17491
- function getRegisteredNgModuleType(id) {
17492
- return modules.get(id);
17374
+ /**
17375
+ * Converts an array in the form of `['publicName', 'alias', 'otherPublicName', 'otherAlias']` into
17376
+ * a map in the form of `{publicName: 'alias', otherPublicName: 'otherAlias'}`.
17377
+ */
17378
+ function bindingArrayToMap(bindings) {
17379
+ if (bindings === undefined || bindings.length === 0) {
17380
+ return EMPTY_OBJ;
17381
+ }
17382
+ const result = {};
17383
+ for (let i = 0; i < bindings.length; i += 2) {
17384
+ result[bindings[i]] = bindings[i + 1];
17385
+ }
17386
+ return result;
17493
17387
  }
17494
17388
  /**
17495
- * Control whether the NgModule registration system enforces that each NgModule type registered has
17496
- * a unique id.
17389
+ * `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
17390
+ * `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
17391
+ * minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
17392
+ * will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
17393
+ * minification.
17497
17394
  *
17498
- * This is useful for testing as the NgModule registry cannot be properly reset between tests with
17499
- * Angular's current API.
17395
+ * This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
17396
+ * definition is declared. When a property is written to the directive instance, the
17397
+ * `NgOnChangesFeature` will try to remap the property name being written to using the
17398
+ * `declaredInputs`.
17399
+ *
17400
+ * Since the host directive input remapping happens during directive matching, `declaredInputs`
17401
+ * won't contain the new alias that the input is available under. This function addresses the
17402
+ * issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
17403
+ * this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
17404
+ * is used *only* by the `NgOnChangesFeature` when determining what name is used in the
17405
+ * `SimpleChanges` object which won't be reached if an input doesn't exist.
17500
17406
  */
17501
- function setAllowDuplicateNgModuleIdsForTest(allowDuplicates) {
17502
- checkForDuplicateNgModules = !allowDuplicates;
17407
+ function patchDeclaredInputs(declaredInputs, exposedInputs) {
17408
+ for (const publicName in exposedInputs) {
17409
+ if (exposedInputs.hasOwnProperty(publicName)) {
17410
+ const remappedPublicName = exposedInputs[publicName];
17411
+ const privateName = declaredInputs[publicName];
17412
+ // We *technically* shouldn't be able to hit this case because we can't have multiple
17413
+ // inputs on the same property and we have validations against conflicting aliases in
17414
+ // `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
17415
+ // with the wrong name so we have a non-user-friendly assertion here just in case.
17416
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
17417
+ declaredInputs.hasOwnProperty(remappedPublicName)) {
17418
+ assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
17419
+ }
17420
+ declaredInputs[remappedPublicName] = privateName;
17421
+ }
17422
+ }
17423
+ }
17424
+ /**
17425
+ * Verifies that the host directive has been configured correctly.
17426
+ * @param hostDirectiveConfig Host directive configuration object.
17427
+ * @param directiveDef Directive definition of the host directive.
17428
+ */
17429
+ function validateHostDirective(hostDirectiveConfig, directiveDef) {
17430
+ const type = hostDirectiveConfig.directive;
17431
+ if (directiveDef === null) {
17432
+ if (getComponentDef(type) !== null) {
17433
+ throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
17434
+ }
17435
+ throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
17436
+ `Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
17437
+ }
17438
+ if (!directiveDef.standalone) {
17439
+ throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
17440
+ }
17441
+ validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
17442
+ validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
17443
+ }
17444
+ /**
17445
+ * Checks that the host directive inputs/outputs configuration is valid.
17446
+ * @param bindingType Kind of binding that is being validated. Used in the error message.
17447
+ * @param def Definition of the host directive that is being validated against.
17448
+ * @param hostDirectiveBindings Host directive mapping object that shold be validated.
17449
+ */
17450
+ function validateMappings(bindingType, def, hostDirectiveBindings) {
17451
+ const className = def.type.name;
17452
+ const bindings = bindingType === 'input' ? def.inputs : def.outputs;
17453
+ for (const publicName in hostDirectiveBindings) {
17454
+ if (hostDirectiveBindings.hasOwnProperty(publicName)) {
17455
+ if (!bindings.hasOwnProperty(publicName)) {
17456
+ throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
17457
+ }
17458
+ const remappedPublicName = hostDirectiveBindings[publicName];
17459
+ if (bindings.hasOwnProperty(remappedPublicName) && remappedPublicName !== publicName) {
17460
+ throw new RuntimeError(312 /* RuntimeErrorCode.HOST_DIRECTIVE_CONFLICTING_ALIAS */, `Cannot alias ${bindingType} ${publicName} of host directive ${className} to ${remappedPublicName}, because it already has a different ${bindingType} with the same public name.`);
17461
+ }
17462
+ }
17463
+ }
17503
17464
  }
17504
17465
 
17505
17466
  /**
17506
- * Validation function invoked at runtime for each binding that might potentially
17507
- * represent a security-sensitive attribute of an <iframe>.
17508
- * See `IFRAME_SECURITY_SENSITIVE_ATTRS` in the
17509
- * `packages/compiler/src/schema/dom_security_schema.ts` script for the full list
17510
- * of such attributes.
17467
+ * Decorates the directive definition with support for input transform functions.
17468
+ *
17469
+ * If the directive uses inheritance, the feature should be included before the
17470
+ * `InheritDefinitionFeature` to ensure that the `inputTransforms` field is populated.
17511
17471
  *
17512
17472
  * @codeGenApi
17513
17473
  */
17514
- function ɵɵvalidateIframeAttribute(attrValue, tagName, attrName) {
17515
- const lView = getLView();
17516
- const tNode = getSelectedTNode();
17517
- const element = getNativeByTNode(tNode, lView);
17518
- // Restrict any dynamic bindings of security-sensitive attributes/properties
17519
- // on an <iframe> for security reasons.
17520
- if (tNode.type === 2 /* TNodeType.Element */ && tagName.toLowerCase() === 'iframe') {
17521
- const iframe = element;
17522
- // Unset previously applied `src` and `srcdoc` if we come across a situation when
17523
- // a security-sensitive attribute is set later via an attribute/property binding.
17524
- iframe.src = '';
17525
- iframe.srcdoc = trustedHTMLFromString('');
17526
- // Also remove the <iframe> from the document.
17527
- nativeRemoveNode(lView[RENDERER], iframe);
17528
- const errorMessage = ngDevMode &&
17529
- `Angular has detected that the \`${attrName}\` was applied ` +
17530
- `as a binding to an <iframe>${getTemplateLocationDetails(lView)}. ` +
17531
- `For security reasons, the \`${attrName}\` can be set on an <iframe> ` +
17532
- `as a static attribute only. \n` +
17533
- `To fix this, switch the \`${attrName}\` binding to a static attribute ` +
17534
- `in a template or in host bindings section.`;
17535
- throw new RuntimeError(-910 /* RuntimeErrorCode.UNSAFE_IFRAME_ATTRS */, errorMessage);
17474
+ function ɵɵInputTransformsFeature(definition) {
17475
+ const inputs = definition.inputConfig;
17476
+ const inputTransforms = {};
17477
+ for (const minifiedKey in inputs) {
17478
+ if (inputs.hasOwnProperty(minifiedKey)) {
17479
+ // Note: the private names are used for the keys, rather than the public ones, because public
17480
+ // names can be re-aliased in host directives which would invalidate the lookup.
17481
+ const value = inputs[minifiedKey];
17482
+ if (Array.isArray(value) && value[3]) {
17483
+ inputTransforms[minifiedKey] = value[3];
17484
+ }
17485
+ }
17536
17486
  }
17537
- return attrValue;
17487
+ definition.inputTransforms = inputTransforms;
17538
17488
  }
17539
17489
 
17540
- function getSuperType(type) {
17541
- return Object.getPrototypeOf(type.prototype).constructor;
17542
- }
17543
17490
  /**
17544
- * Merges the definition from a super class to a sub class.
17545
- * @param definition The definition that is a SubClass of another directive of component
17491
+ * Represents an instance of an `NgModule` created by an `NgModuleFactory`.
17492
+ * Provides access to the `NgModule` instance and related objects.
17546
17493
  *
17547
- * @codeGenApi
17494
+ * @publicApi
17548
17495
  */
17549
- function ɵɵInheritDefinitionFeature(definition) {
17550
- let superType = getSuperType(definition.type);
17551
- let shouldInheritFields = true;
17552
- const inheritanceChain = [definition];
17553
- while (superType) {
17554
- let superDef = undefined;
17555
- if (isComponentDef(definition)) {
17556
- // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17557
- superDef = superType.ɵcmp || superType.ɵdir;
17558
- }
17559
- else {
17560
- if (superType.ɵcmp) {
17561
- throw new RuntimeError(903 /* RuntimeErrorCode.INVALID_INHERITANCE */, ngDevMode &&
17562
- `Directives cannot inherit Components. Directive ${stringifyForError(definition.type)} is attempting to extend component ${stringifyForError(superType)}`);
17563
- }
17564
- // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17565
- superDef = superType.ɵdir;
17566
- }
17567
- if (superDef) {
17568
- if (shouldInheritFields) {
17569
- inheritanceChain.push(superDef);
17570
- // Some fields in the definition may be empty, if there were no values to put in them that
17571
- // would've justified object creation. Unwrap them if necessary.
17572
- const writeableDef = definition;
17573
- writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
17574
- writeableDef.inputTransforms = maybeUnwrapEmpty(definition.inputTransforms);
17575
- writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
17576
- writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
17577
- // Merge hostBindings
17578
- const superHostBindings = superDef.hostBindings;
17579
- superHostBindings && inheritHostBindings(definition, superHostBindings);
17580
- // Merge queries
17581
- const superViewQuery = superDef.viewQuery;
17582
- const superContentQueries = superDef.contentQueries;
17583
- superViewQuery && inheritViewQuery(definition, superViewQuery);
17584
- superContentQueries && inheritContentQueries(definition, superContentQueries);
17585
- // Merge inputs and outputs
17586
- mergeInputsWithTransforms(definition, superDef);
17587
- fillProperties(definition.outputs, superDef.outputs);
17588
- // Merge animations metadata.
17589
- // If `superDef` is a Component, the `data` field is present (defaults to an empty object).
17590
- if (isComponentDef(superDef) && superDef.data.animation) {
17591
- // If super def is a Component, the `definition` is also a Component, since Directives can
17592
- // not inherit Components (we throw an error above and cannot reach this code).
17593
- const defData = definition.data;
17594
- defData.animation = (defData.animation || []).concat(superDef.data.animation);
17595
- }
17596
- }
17597
- // Run parent features
17598
- const features = superDef.features;
17599
- if (features) {
17600
- for (let i = 0; i < features.length; i++) {
17601
- const feature = features[i];
17602
- if (feature && feature.ngInherit) {
17603
- feature(definition);
17604
- }
17605
- // If `InheritDefinitionFeature` is a part of the current `superDef`, it means that this
17606
- // def already has all the necessary information inherited from its super class(es), so we
17607
- // can stop merging fields from super classes. However we need to iterate through the
17608
- // prototype chain to look for classes that might contain other "features" (like
17609
- // NgOnChanges), which we should invoke for the original `definition`. We set the
17610
- // `shouldInheritFields` flag to indicate that, essentially skipping fields inheritance
17611
- // logic and only invoking functions from the "features" list.
17612
- if (feature === ɵɵInheritDefinitionFeature) {
17613
- shouldInheritFields = false;
17614
- }
17615
- }
17616
- }
17617
- }
17618
- superType = Object.getPrototypeOf(superType);
17619
- }
17620
- mergeHostAttrsAcrossInheritance(inheritanceChain);
17496
+ class NgModuleRef$1 {
17621
17497
  }
17622
- function mergeInputsWithTransforms(target, source) {
17623
- for (const key in source.inputs) {
17624
- if (!source.inputs.hasOwnProperty(key)) {
17625
- continue;
17626
- }
17627
- if (target.inputs.hasOwnProperty(key)) {
17628
- continue;
17629
- }
17630
- const value = source.inputs[key];
17631
- if (value === undefined) {
17632
- continue;
17633
- }
17634
- target.inputs[key] = value;
17635
- target.declaredInputs[key] = source.declaredInputs[key];
17636
- // If the input is inherited, and we have a transform for it, we also inherit it.
17637
- // Note that transforms should not be inherited if the input has its own metadata
17638
- // in the `source` directive itself already (i.e. the input is re-declared/overridden).
17639
- if (source.inputTransforms !== null) {
17640
- // Note: transforms are stored with their minified names.
17641
- // Perf: only access the minified name when there are source transforms.
17642
- const minifiedName = Array.isArray(value) ? value[0] : value;
17643
- if (!source.inputTransforms.hasOwnProperty(minifiedName)) {
17644
- continue;
17645
- }
17646
- target.inputTransforms ??= {};
17647
- target.inputTransforms[minifiedName] = source.inputTransforms[minifiedName];
17648
- }
17649
- }
17498
+ /**
17499
+ * @publicApi
17500
+ *
17501
+ * @deprecated
17502
+ * This class was mostly used as a part of ViewEngine-based JIT API and is no longer needed in Ivy
17503
+ * JIT mode. See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes)
17504
+ * for additional context. Angular provides APIs that accept NgModule classes directly (such as
17505
+ * [PlatformRef.bootstrapModule](api/core/PlatformRef#bootstrapModule) and
17506
+ * [createNgModule](api/core/createNgModule)), consider switching to those APIs instead of
17507
+ * using factory-based ones.
17508
+ */
17509
+ class NgModuleFactory$1 {
17650
17510
  }
17511
+
17651
17512
  /**
17652
- * Merge the `hostAttrs` and `hostVars` from the inherited parent to the base class.
17513
+ * Returns a new NgModuleRef instance based on the NgModule class and parent injector provided.
17653
17514
  *
17654
- * @param inheritanceChain A list of `WritableDefs` starting at the top most type and listing
17655
- * sub-types in order. For each type take the `hostAttrs` and `hostVars` and merge it with the child
17656
- * type.
17515
+ * @param ngModule NgModule class.
17516
+ * @param parentInjector Optional injector instance to use as a parent for the module injector. If
17517
+ * not provided, `NullInjector` will be used instead.
17518
+ * @returns NgModuleRef that represents an NgModule instance.
17519
+ *
17520
+ * @publicApi
17657
17521
  */
17658
- function mergeHostAttrsAcrossInheritance(inheritanceChain) {
17659
- let hostVars = 0;
17660
- let hostAttrs = null;
17661
- // We process the inheritance order from the base to the leaves here.
17662
- for (let i = inheritanceChain.length - 1; i >= 0; i--) {
17663
- const def = inheritanceChain[i];
17664
- // For each `hostVars`, we need to add the superclass amount.
17665
- def.hostVars = (hostVars += def.hostVars);
17666
- // for each `hostAttrs` we need to merge it with superclass.
17667
- def.hostAttrs =
17668
- mergeHostAttrs(def.hostAttrs, hostAttrs = mergeHostAttrs(hostAttrs, def.hostAttrs));
17669
- }
17522
+ function createNgModule(ngModule, parentInjector) {
17523
+ return new NgModuleRef(ngModule, parentInjector ?? null, []);
17670
17524
  }
17671
- function maybeUnwrapEmpty(value) {
17672
- if (value === EMPTY_OBJ) {
17673
- return {};
17674
- }
17675
- else if (value === EMPTY_ARRAY) {
17676
- return [];
17525
+ /**
17526
+ * The `createNgModule` function alias for backwards-compatibility.
17527
+ * Please avoid using it directly and use `createNgModule` instead.
17528
+ *
17529
+ * @deprecated Use `createNgModule` instead.
17530
+ */
17531
+ const createNgModuleRef = createNgModule;
17532
+ class NgModuleRef extends NgModuleRef$1 {
17533
+ constructor(ngModuleType, _parent, additionalProviders) {
17534
+ super();
17535
+ this._parent = _parent;
17536
+ // tslint:disable-next-line:require-internal-with-underscore
17537
+ this._bootstrapComponents = [];
17538
+ this.destroyCbs = [];
17539
+ // When bootstrapping a module we have a dependency graph that looks like this:
17540
+ // ApplicationRef -> ComponentFactoryResolver -> NgModuleRef. The problem is that if the
17541
+ // module being resolved tries to inject the ComponentFactoryResolver, it'll create a
17542
+ // circular dependency which will result in a runtime error, because the injector doesn't
17543
+ // exist yet. We work around the issue by creating the ComponentFactoryResolver ourselves
17544
+ // and providing it, rather than letting the injector resolve it.
17545
+ this.componentFactoryResolver = new ComponentFactoryResolver(this);
17546
+ const ngModuleDef = getNgModuleDef(ngModuleType);
17547
+ ngDevMode &&
17548
+ assertDefined(ngModuleDef, `NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`);
17549
+ this._bootstrapComponents = maybeUnwrapFn(ngModuleDef.bootstrap);
17550
+ this._r3Injector = createInjectorWithoutInjectorInstances(ngModuleType, _parent, [
17551
+ { provide: NgModuleRef$1, useValue: this }, {
17552
+ provide: ComponentFactoryResolver$1,
17553
+ useValue: this.componentFactoryResolver
17554
+ },
17555
+ ...additionalProviders
17556
+ ], stringify(ngModuleType), new Set(['environment']));
17557
+ // We need to resolve the injector types separately from the injector creation, because
17558
+ // the module might be trying to use this ref in its constructor for DI which will cause a
17559
+ // circular error that will eventually error out, because the injector isn't created yet.
17560
+ this._r3Injector.resolveInjectorInitializers();
17561
+ this.instance = this._r3Injector.get(ngModuleType);
17677
17562
  }
17678
- else {
17679
- return value;
17563
+ get injector() {
17564
+ return this._r3Injector;
17680
17565
  }
17681
- }
17682
- function inheritViewQuery(definition, superViewQuery) {
17683
- const prevViewQuery = definition.viewQuery;
17684
- if (prevViewQuery) {
17685
- definition.viewQuery = (rf, ctx) => {
17686
- superViewQuery(rf, ctx);
17687
- prevViewQuery(rf, ctx);
17688
- };
17566
+ destroy() {
17567
+ ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
17568
+ const injector = this._r3Injector;
17569
+ !injector.destroyed && injector.destroy();
17570
+ this.destroyCbs.forEach(fn => fn());
17571
+ this.destroyCbs = null;
17689
17572
  }
17690
- else {
17691
- definition.viewQuery = superViewQuery;
17573
+ onDestroy(callback) {
17574
+ ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
17575
+ this.destroyCbs.push(callback);
17692
17576
  }
17693
17577
  }
17694
- function inheritContentQueries(definition, superContentQueries) {
17695
- const prevContentQueries = definition.contentQueries;
17696
- if (prevContentQueries) {
17697
- definition.contentQueries = (rf, ctx, directiveIndex) => {
17698
- superContentQueries(rf, ctx, directiveIndex);
17699
- prevContentQueries(rf, ctx, directiveIndex);
17700
- };
17578
+ class NgModuleFactory extends NgModuleFactory$1 {
17579
+ constructor(moduleType) {
17580
+ super();
17581
+ this.moduleType = moduleType;
17701
17582
  }
17702
- else {
17703
- definition.contentQueries = superContentQueries;
17583
+ create(parentInjector) {
17584
+ return new NgModuleRef(this.moduleType, parentInjector, []);
17704
17585
  }
17705
17586
  }
17706
- function inheritHostBindings(definition, superHostBindings) {
17707
- const prevHostBindings = definition.hostBindings;
17708
- if (prevHostBindings) {
17709
- definition.hostBindings = (rf, ctx) => {
17710
- superHostBindings(rf, ctx);
17711
- prevHostBindings(rf, ctx);
17712
- };
17587
+ function createNgModuleRefWithProviders(moduleType, parentInjector, additionalProviders) {
17588
+ return new NgModuleRef(moduleType, parentInjector, additionalProviders);
17589
+ }
17590
+ class EnvironmentNgModuleRefAdapter extends NgModuleRef$1 {
17591
+ constructor(config) {
17592
+ super();
17593
+ this.componentFactoryResolver = new ComponentFactoryResolver(this);
17594
+ this.instance = null;
17595
+ const injector = new R3Injector([
17596
+ ...config.providers,
17597
+ { provide: NgModuleRef$1, useValue: this },
17598
+ { provide: ComponentFactoryResolver$1, useValue: this.componentFactoryResolver },
17599
+ ], config.parent || getNullInjector(), config.debugName, new Set(['environment']));
17600
+ this.injector = injector;
17601
+ if (config.runEnvironmentInitializers) {
17602
+ injector.resolveInjectorInitializers();
17603
+ }
17713
17604
  }
17714
- else {
17715
- definition.hostBindings = superHostBindings;
17605
+ destroy() {
17606
+ this.injector.destroy();
17607
+ }
17608
+ onDestroy(callback) {
17609
+ this.injector.onDestroy(callback);
17716
17610
  }
17717
17611
  }
17718
-
17719
- /**
17720
- * Fields which exist on either directive or component definitions, and need to be copied from
17721
- * parent to child classes by the `ɵɵCopyDefinitionFeature`.
17722
- */
17723
- const COPY_DIRECTIVE_FIELDS = [
17724
- // The child class should use the providers of its parent.
17725
- 'providersResolver',
17726
- // Not listed here are any fields which are handled by the `ɵɵInheritDefinitionFeature`, such
17727
- // as inputs, outputs, and host binding functions.
17728
- ];
17729
- /**
17730
- * Fields which exist only on component definitions, and need to be copied from parent to child
17731
- * classes by the `ɵɵCopyDefinitionFeature`.
17732
- *
17733
- * The type here allows any field of `ComponentDef` which is not also a property of `DirectiveDef`,
17734
- * since those should go in `COPY_DIRECTIVE_FIELDS` above.
17735
- */
17736
- const COPY_COMPONENT_FIELDS = [
17737
- // The child class should use the template function of its parent, including all template
17738
- // semantics.
17739
- 'template',
17740
- 'decls',
17741
- 'consts',
17742
- 'vars',
17743
- 'onPush',
17744
- 'ngContentSelectors',
17745
- // The child class should use the CSS styles of its parent, including all styling semantics.
17746
- 'styles',
17747
- 'encapsulation',
17748
- // The child class should be checked by the runtime in the same way as its parent.
17749
- 'schemas',
17750
- ];
17751
17612
  /**
17752
- * Copies the fields not handled by the `ɵɵInheritDefinitionFeature` from the supertype of a
17753
- * definition.
17613
+ * Create a new environment injector.
17754
17614
  *
17755
- * This exists primarily to support ngcc migration of an existing View Engine pattern, where an
17756
- * entire decorator is inherited from a parent to a child class. When ngcc detects this case, it
17757
- * generates a skeleton definition on the child class, and applies this feature.
17615
+ * Learn more about environment injectors in
17616
+ * [this guide](guide/standalone-components#environment-injectors).
17758
17617
  *
17759
- * The `ɵɵCopyDefinitionFeature` then copies any needed fields from the parent class' definition,
17760
- * including things like the component template function.
17618
+ * @param providers An array of providers.
17619
+ * @param parent A parent environment injector.
17620
+ * @param debugName An optional name for this injector instance, which will be used in error
17621
+ * messages.
17761
17622
  *
17762
- * @param definition The definition of a child class which inherits from a parent class with its
17763
- * own definition.
17623
+ * @publicApi
17624
+ */
17625
+ function createEnvironmentInjector(providers, parent, debugName = null) {
17626
+ const adapter = new EnvironmentNgModuleRefAdapter({ providers, parent, debugName, runEnvironmentInitializers: true });
17627
+ return adapter.injector;
17628
+ }
17629
+
17630
+ /**
17631
+ * A service used by the framework to create and cache injector instances.
17764
17632
  *
17765
- * @codeGenApi
17633
+ * This service is used to create a single injector instance for each defer
17634
+ * block definition, to avoid creating an injector for each defer block instance
17635
+ * of a certain type.
17766
17636
  */
17767
- function ɵɵCopyDefinitionFeature(definition) {
17768
- let superType = getSuperType(definition.type);
17769
- let superDef = undefined;
17770
- if (isComponentDef(definition)) {
17771
- // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17772
- superDef = superType.ɵcmp;
17773
- }
17774
- else {
17775
- // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
17776
- superDef = superType.ɵdir;
17637
+ class CachedInjectorService {
17638
+ constructor() {
17639
+ this.cachedInjectors = new Map();
17777
17640
  }
17778
- // Needed because `definition` fields are readonly.
17779
- const defAny = definition;
17780
- // Copy over any fields that apply to either directives or components.
17781
- for (const field of COPY_DIRECTIVE_FIELDS) {
17782
- defAny[field] = superDef[field];
17641
+ getOrCreateInjector(key, parentInjector, providers, debugName) {
17642
+ if (!this.cachedInjectors.has(key)) {
17643
+ const injector = providers.length > 0 ?
17644
+ createEnvironmentInjector(providers, parentInjector, debugName) :
17645
+ null;
17646
+ this.cachedInjectors.set(key, injector);
17647
+ }
17648
+ return this.cachedInjectors.get(key);
17783
17649
  }
17784
- if (isComponentDef(superDef)) {
17785
- // Copy over any component-specific fields.
17786
- for (const field of COPY_COMPONENT_FIELDS) {
17787
- defAny[field] = superDef[field];
17650
+ ngOnDestroy() {
17651
+ try {
17652
+ for (const injector of this.cachedInjectors.values()) {
17653
+ if (injector !== null) {
17654
+ injector.destroy();
17655
+ }
17656
+ }
17657
+ }
17658
+ finally {
17659
+ this.cachedInjectors.clear();
17788
17660
  }
17789
17661
  }
17662
+ /** @nocollapse */
17663
+ static { this.ɵprov = ɵɵdefineInjectable({
17664
+ token: CachedInjectorService,
17665
+ providedIn: 'environment',
17666
+ factory: () => new CachedInjectorService(),
17667
+ }); }
17790
17668
  }
17791
17669
 
17792
17670
  /**
17793
- * This feature adds the host directives behavior to a directive definition by patching a
17794
- * function onto it. The expectation is that the runtime will invoke the function during
17795
- * directive matching.
17796
- *
17797
- * For example:
17798
- * ```ts
17799
- * class ComponentWithHostDirective {
17800
- * static ɵcmp = defineComponent({
17801
- * type: ComponentWithHostDirective,
17802
- * features: [ɵɵHostDirectivesFeature([
17803
- * SimpleHostDirective,
17804
- * {directive: AdvancedHostDirective, inputs: ['foo: alias'], outputs: ['bar']},
17805
- * ])]
17806
- * });
17807
- * }
17808
- * ```
17671
+ * The name of a field that Angular monkey-patches onto a component
17672
+ * class to store a function that loads defer-loadable dependencies
17673
+ * and applies metadata to a class.
17674
+ */
17675
+ const ASYNC_COMPONENT_METADATA_FN = '__ngAsyncComponentMetadataFn__';
17676
+ /**
17677
+ * If a given component has unresolved async metadata - returns a reference
17678
+ * to a function that applies component metadata after resolving defer-loadable
17679
+ * dependencies. Otherwise - this function returns `null`.
17680
+ */
17681
+ function getAsyncClassMetadataFn(type) {
17682
+ const componentClass = type; // cast to `any`, so that we can read a monkey-patched field
17683
+ return componentClass[ASYNC_COMPONENT_METADATA_FN] ?? null;
17684
+ }
17685
+ /**
17686
+ * Handles the process of applying metadata info to a component class in case
17687
+ * component template has defer blocks (thus some dependencies became deferrable).
17809
17688
  *
17810
- * @codeGenApi
17689
+ * @param type Component class where metadata should be added
17690
+ * @param dependencyLoaderFn Function that loads dependencies
17691
+ * @param metadataSetterFn Function that forms a scope in which the `setClassMetadata` is invoked
17811
17692
  */
17812
- function ɵɵHostDirectivesFeature(rawHostDirectives) {
17813
- const feature = (definition) => {
17814
- const resolved = (Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
17815
- return typeof dir === 'function' ?
17816
- { directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
17817
- {
17818
- directive: resolveForwardRef(dir.directive),
17819
- inputs: bindingArrayToMap(dir.inputs),
17820
- outputs: bindingArrayToMap(dir.outputs)
17821
- };
17822
- });
17823
- if (definition.hostDirectives === null) {
17824
- definition.findHostDirectiveDefs = findHostDirectiveDefs;
17825
- definition.hostDirectives = resolved;
17826
- }
17827
- else {
17828
- definition.hostDirectives.unshift(...resolved);
17829
- }
17830
- };
17831
- feature.ngInherit = true;
17832
- return feature;
17693
+ function setClassMetadataAsync(type, dependencyLoaderFn, metadataSetterFn) {
17694
+ const componentClass = type; // cast to `any`, so that we can monkey-patch it
17695
+ componentClass[ASYNC_COMPONENT_METADATA_FN] = () => Promise.all(dependencyLoaderFn()).then(dependencies => {
17696
+ metadataSetterFn(...dependencies);
17697
+ // Metadata is now set, reset field value to indicate that this component
17698
+ // can by used/compiled synchronously.
17699
+ componentClass[ASYNC_COMPONENT_METADATA_FN] = null;
17700
+ return dependencies;
17701
+ });
17702
+ return componentClass[ASYNC_COMPONENT_METADATA_FN];
17833
17703
  }
17834
- function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
17835
- if (currentDef.hostDirectives !== null) {
17836
- for (const hostDirectiveConfig of currentDef.hostDirectives) {
17837
- const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
17838
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
17839
- validateHostDirective(hostDirectiveConfig, hostDirectiveDef);
17704
+ /**
17705
+ * Adds decorator, constructor, and property metadata to a given type via static metadata fields
17706
+ * on the type.
17707
+ *
17708
+ * These metadata fields can later be read with Angular's `ReflectionCapabilities` API.
17709
+ *
17710
+ * Calls to `setClassMetadata` can be guarded by ngDevMode, resulting in the metadata assignments
17711
+ * being tree-shaken away during production builds.
17712
+ */
17713
+ function setClassMetadata(type, decorators, ctorParameters, propDecorators) {
17714
+ return noSideEffects(() => {
17715
+ const clazz = type;
17716
+ if (decorators !== null) {
17717
+ if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) {
17718
+ clazz.decorators.push(...decorators);
17719
+ }
17720
+ else {
17721
+ clazz.decorators = decorators;
17840
17722
  }
17841
- // We need to patch the `declaredInputs` so that
17842
- // `ngOnChanges` can map the properties correctly.
17843
- patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
17844
- // Host directives execute before the host so that its host bindings can be overwritten.
17845
- findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
17846
- hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
17847
- matchedDefs.push(hostDirectiveDef);
17848
17723
  }
17849
- }
17724
+ if (ctorParameters !== null) {
17725
+ // Rather than merging, clobber the existing parameters. If other projects exist which
17726
+ // use tsickle-style annotations and reflect over them in the same way, this could
17727
+ // cause issues, but that is vanishingly unlikely.
17728
+ clazz.ctorParameters = ctorParameters;
17729
+ }
17730
+ if (propDecorators !== null) {
17731
+ // The property decorator objects are merged as it is possible different fields have
17732
+ // different decorator types. Decorators on individual fields are not merged, as it's
17733
+ // also incredibly unlikely that a field will be decorated both with an Angular
17734
+ // decorator and a non-Angular decorator that's also been downleveled.
17735
+ if (clazz.hasOwnProperty('propDecorators') && clazz.propDecorators !== undefined) {
17736
+ clazz.propDecorators = { ...clazz.propDecorators, ...propDecorators };
17737
+ }
17738
+ else {
17739
+ clazz.propDecorators = propDecorators;
17740
+ }
17741
+ }
17742
+ });
17850
17743
  }
17744
+
17745
+ /*
17746
+ * This file exists to support compilation of @angular/core in Ivy mode.
17747
+ *
17748
+ * When the Angular compiler processes a compilation unit, it normally writes imports to
17749
+ * @angular/core. When compiling the core package itself this strategy isn't usable. Instead, the
17750
+ * compiler writes imports to this file.
17751
+ *
17752
+ * Only a subset of such imports are supported - core is not allowed to declare components or pipes.
17753
+ * A check in ngtsc's `R3SymbolsImportRewriter` validates this condition. The rewriter is only used
17754
+ * when compiling @angular/core and is responsible for translating an external name (prefixed with
17755
+ * ɵ) to the internal symbol name as exported below.
17756
+ *
17757
+ * The below symbols are used for @Injectable and @NgModule compilation.
17758
+ */
17851
17759
  /**
17852
- * Converts an array in the form of `['publicName', 'alias', 'otherPublicName', 'otherAlias']` into
17853
- * a map in the form of `{publicName: 'alias', otherPublicName: 'otherAlias'}`.
17760
+ * The existence of this constant (in this particular file) informs the Angular compiler that the
17761
+ * current program is actually @angular/core, which needs to be compiled specially.
17854
17762
  */
17855
- function bindingArrayToMap(bindings) {
17856
- if (bindings === undefined || bindings.length === 0) {
17857
- return EMPTY_OBJ;
17858
- }
17859
- const result = {};
17860
- for (let i = 0; i < bindings.length; i += 2) {
17861
- result[bindings[i]] = bindings[i + 1];
17862
- }
17863
- return result;
17864
- }
17763
+ const ITS_JUST_ANGULAR = true;
17764
+
17865
17765
  /**
17866
- * `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
17867
- * `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
17868
- * minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
17869
- * will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
17870
- * minification.
17766
+ * *Internal* service that keeps track of pending tasks happening in the system.
17871
17767
  *
17872
- * This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
17873
- * definition is declared. When a property is written to the directive instance, the
17874
- * `NgOnChangesFeature` will try to remap the property name being written to using the
17875
- * `declaredInputs`.
17768
+ * This information is needed to make sure that the serialization on the server
17769
+ * is delayed until all tasks in the queue (such as an initial navigation or a
17770
+ * pending HTTP request) are completed.
17876
17771
  *
17877
- * Since the host directive input remapping happens during directive matching, `declaredInputs`
17878
- * won't contain the new alias that the input is available under. This function addresses the
17879
- * issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
17880
- * this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
17881
- * is used *only* by the `NgOnChangesFeature` when determining what name is used in the
17882
- * `SimpleChanges` object which won't be reached if an input doesn't exist.
17772
+ * Pending tasks continue to contribute to the stableness of `ApplicationRef`
17773
+ * throughout the lifetime of the application.
17883
17774
  */
17884
- function patchDeclaredInputs(declaredInputs, exposedInputs) {
17885
- for (const publicName in exposedInputs) {
17886
- if (exposedInputs.hasOwnProperty(publicName)) {
17887
- const remappedPublicName = exposedInputs[publicName];
17888
- const privateName = declaredInputs[publicName];
17889
- // We *technically* shouldn't be able to hit this case because we can't have multiple
17890
- // inputs on the same property and we have validations against conflicting aliases in
17891
- // `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
17892
- // with the wrong name so we have a non-user-friendly assertion here just in case.
17893
- if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
17894
- declaredInputs.hasOwnProperty(remappedPublicName)) {
17895
- assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
17896
- }
17897
- declaredInputs[remappedPublicName] = privateName;
17775
+ class PendingTasks {
17776
+ constructor() {
17777
+ this.taskId = 0;
17778
+ this.pendingTasks = new Set();
17779
+ this.hasPendingTasks = new BehaviorSubject(false);
17780
+ }
17781
+ get _hasPendingTasks() {
17782
+ return this.hasPendingTasks.value;
17783
+ }
17784
+ add() {
17785
+ if (!this._hasPendingTasks) {
17786
+ this.hasPendingTasks.next(true);
17787
+ }
17788
+ const taskId = this.taskId++;
17789
+ this.pendingTasks.add(taskId);
17790
+ return taskId;
17791
+ }
17792
+ remove(taskId) {
17793
+ this.pendingTasks.delete(taskId);
17794
+ if (this.pendingTasks.size === 0 && this._hasPendingTasks) {
17795
+ this.hasPendingTasks.next(false);
17796
+ }
17797
+ }
17798
+ ngOnDestroy() {
17799
+ this.pendingTasks.clear();
17800
+ if (this._hasPendingTasks) {
17801
+ this.hasPendingTasks.next(false);
17898
17802
  }
17899
17803
  }
17804
+ static { this.ɵfac = function PendingTasks_Factory(t) { return new (t || PendingTasks)(); }; }
17805
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: PendingTasks, factory: PendingTasks.ɵfac, providedIn: 'root' }); }
17900
17806
  }
17901
- /**
17902
- * Verifies that the host directive has been configured correctly.
17903
- * @param hostDirectiveConfig Host directive configuration object.
17904
- * @param directiveDef Directive definition of the host directive.
17905
- */
17906
- function validateHostDirective(hostDirectiveConfig, directiveDef) {
17907
- const type = hostDirectiveConfig.directive;
17908
- if (directiveDef === null) {
17909
- if (getComponentDef(type) !== null) {
17910
- throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
17807
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PendingTasks, [{
17808
+ type: Injectable,
17809
+ args: [{ providedIn: 'root' }]
17810
+ }], null, null); })();
17811
+
17812
+ function isIterable(obj) {
17813
+ return obj !== null && typeof obj === 'object' && obj[Symbol.iterator] !== undefined;
17814
+ }
17815
+ function isListLikeIterable(obj) {
17816
+ if (!isJsObject(obj))
17817
+ return false;
17818
+ return Array.isArray(obj) ||
17819
+ (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
17820
+ Symbol.iterator in obj); // JS Iterable have a Symbol.iterator prop
17821
+ }
17822
+ function areIterablesEqual(a, b, comparator) {
17823
+ const iterator1 = a[Symbol.iterator]();
17824
+ const iterator2 = b[Symbol.iterator]();
17825
+ while (true) {
17826
+ const item1 = iterator1.next();
17827
+ const item2 = iterator2.next();
17828
+ if (item1.done && item2.done)
17829
+ return true;
17830
+ if (item1.done || item2.done)
17831
+ return false;
17832
+ if (!comparator(item1.value, item2.value))
17833
+ return false;
17834
+ }
17835
+ }
17836
+ function iterateListLike(obj, fn) {
17837
+ if (Array.isArray(obj)) {
17838
+ for (let i = 0; i < obj.length; i++) {
17839
+ fn(obj[i]);
17911
17840
  }
17912
- throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
17913
- `Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
17914
17841
  }
17915
- if (!directiveDef.standalone) {
17916
- throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
17842
+ else {
17843
+ const iterator = obj[Symbol.iterator]();
17844
+ let item;
17845
+ while (!((item = iterator.next()).done)) {
17846
+ fn(item.value);
17847
+ }
17917
17848
  }
17918
- validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
17919
- validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
17920
17849
  }
17921
- /**
17922
- * Checks that the host directive inputs/outputs configuration is valid.
17923
- * @param bindingType Kind of binding that is being validated. Used in the error message.
17924
- * @param def Definition of the host directive that is being validated against.
17925
- * @param hostDirectiveBindings Host directive mapping object that shold be validated.
17926
- */
17927
- function validateMappings(bindingType, def, hostDirectiveBindings) {
17928
- const className = def.type.name;
17929
- const bindings = bindingType === 'input' ? def.inputs : def.outputs;
17930
- for (const publicName in hostDirectiveBindings) {
17931
- if (hostDirectiveBindings.hasOwnProperty(publicName)) {
17932
- if (!bindings.hasOwnProperty(publicName)) {
17933
- throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
17934
- }
17935
- const remappedPublicName = hostDirectiveBindings[publicName];
17936
- if (bindings.hasOwnProperty(remappedPublicName) && remappedPublicName !== publicName) {
17937
- throw new RuntimeError(312 /* RuntimeErrorCode.HOST_DIRECTIVE_CONFLICTING_ALIAS */, `Cannot alias ${bindingType} ${publicName} of host directive ${className} to ${remappedPublicName}, because it already has a different ${bindingType} with the same public name.`);
17938
- }
17850
+ function isJsObject(o) {
17851
+ return o !== null && (typeof o === 'function' || typeof o === 'object');
17852
+ }
17853
+
17854
+ function devModeEqual(a, b) {
17855
+ const isListLikeIterableA = isListLikeIterable(a);
17856
+ const isListLikeIterableB = isListLikeIterable(b);
17857
+ if (isListLikeIterableA && isListLikeIterableB) {
17858
+ return areIterablesEqual(a, b, devModeEqual);
17859
+ }
17860
+ else {
17861
+ const isAObject = a && (typeof a === 'object' || typeof a === 'function');
17862
+ const isBObject = b && (typeof b === 'object' || typeof b === 'function');
17863
+ if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
17864
+ return true;
17865
+ }
17866
+ else {
17867
+ return Object.is(a, b);
17939
17868
  }
17940
17869
  }
17941
17870
  }
17942
17871
 
17872
+ // TODO(misko): consider inlining
17873
+ /** Updates binding and returns the value. */
17874
+ function updateBinding(lView, bindingIndex, value) {
17875
+ return lView[bindingIndex] = value;
17876
+ }
17877
+ /** Gets the current binding value. */
17878
+ function getBinding(lView, bindingIndex) {
17879
+ ngDevMode && assertIndexInRange(lView, bindingIndex);
17880
+ ngDevMode &&
17881
+ assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
17882
+ return lView[bindingIndex];
17883
+ }
17943
17884
  /**
17944
- * Decorates the directive definition with support for input transform functions.
17885
+ * Updates binding if changed, then returns whether it was updated.
17945
17886
  *
17946
- * If the directive uses inheritance, the feature should be included before the
17947
- * `InheritDefinitionFeature` to ensure that the `inputTransforms` field is populated.
17887
+ * This function also checks the `CheckNoChangesMode` and throws if changes are made.
17888
+ * Some changes (Objects/iterables) during `CheckNoChangesMode` are exempt to comply with VE
17889
+ * behavior.
17948
17890
  *
17949
- * @codeGenApi
17891
+ * @param lView current `LView`
17892
+ * @param bindingIndex The binding in the `LView` to check
17893
+ * @param value New value to check against `lView[bindingIndex]`
17894
+ * @returns `true` if the bindings has changed. (Throws if binding has changed during
17895
+ * `CheckNoChangesMode`)
17950
17896
  */
17951
- function ɵɵInputTransformsFeature(definition) {
17952
- const inputs = definition.inputConfig;
17953
- const inputTransforms = {};
17954
- for (const minifiedKey in inputs) {
17955
- if (inputs.hasOwnProperty(minifiedKey)) {
17956
- // Note: the private names are used for the keys, rather than the public ones, because public
17957
- // names can be re-aliased in host directives which would invalidate the lookup.
17958
- const value = inputs[minifiedKey];
17959
- if (Array.isArray(value) && value[3]) {
17960
- inputTransforms[minifiedKey] = value[3];
17897
+ function bindingUpdated(lView, bindingIndex, value) {
17898
+ ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
17899
+ ngDevMode &&
17900
+ assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`);
17901
+ const oldValue = lView[bindingIndex];
17902
+ if (Object.is(oldValue, value)) {
17903
+ return false;
17904
+ }
17905
+ else {
17906
+ if (ngDevMode && isInCheckNoChangesMode()) {
17907
+ // View engine didn't report undefined values as changed on the first checkNoChanges pass
17908
+ // (before the change detection was run).
17909
+ const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
17910
+ if (!devModeEqual(oldValueToCompare, value)) {
17911
+ const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
17912
+ throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName, lView);
17961
17913
  }
17914
+ // There was a change, but the `devModeEqual` decided that the change is exempt from an error.
17915
+ // For this reason we exit as if no change. The early exit is needed to prevent the changed
17916
+ // value to be written into `LView` (If we would write the new value that we would not see it
17917
+ // as change on next CD.)
17918
+ return false;
17962
17919
  }
17920
+ lView[bindingIndex] = value;
17921
+ return true;
17963
17922
  }
17964
- definition.inputTransforms = inputTransforms;
17965
17923
  }
17966
-
17967
- /**
17968
- * Represents an instance of an `NgModule` created by an `NgModuleFactory`.
17969
- * Provides access to the `NgModule` instance and related objects.
17970
- *
17971
- * @publicApi
17972
- */
17973
- class NgModuleRef$1 {
17924
+ /** Updates 2 bindings if changed, then returns whether either was updated. */
17925
+ function bindingUpdated2(lView, bindingIndex, exp1, exp2) {
17926
+ const different = bindingUpdated(lView, bindingIndex, exp1);
17927
+ return bindingUpdated(lView, bindingIndex + 1, exp2) || different;
17928
+ }
17929
+ /** Updates 3 bindings if changed, then returns whether any was updated. */
17930
+ function bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) {
17931
+ const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
17932
+ return bindingUpdated(lView, bindingIndex + 2, exp3) || different;
17933
+ }
17934
+ /** Updates 4 bindings if changed, then returns whether any was updated. */
17935
+ function bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) {
17936
+ const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
17937
+ return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different;
17974
17938
  }
17939
+
17975
17940
  /**
17976
- * @publicApi
17977
- *
17978
- * @deprecated
17979
- * This class was mostly used as a part of ViewEngine-based JIT API and is no longer needed in Ivy
17980
- * JIT mode. See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes)
17981
- * for additional context. Angular provides APIs that accept NgModule classes directly (such as
17982
- * [PlatformRef.bootstrapModule](api/core/PlatformRef#bootstrapModule) and
17983
- * [createNgModule](api/core/createNgModule)), consider switching to those APIs instead of
17984
- * using factory-based ones.
17941
+ * Checks whether a TNode is considered detached, i.e. not present in the
17942
+ * translated i18n template. We should not attempt hydration for such nodes
17943
+ * and instead, use a regular "creation mode".
17985
17944
  */
17986
- class NgModuleFactory$1 {
17945
+ function isDetachedByI18n(tNode) {
17946
+ return (tNode.flags & 32 /* TNodeFlags.isDetached */) === 32 /* TNodeFlags.isDetached */;
17987
17947
  }
17988
17948
 
17949
+ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
17950
+ ngDevMode && assertFirstCreatePass(tView);
17951
+ ngDevMode && ngDevMode.firstCreatePass++;
17952
+ const tViewConsts = tView.consts;
17953
+ // TODO(pk): refactor getOrCreateTNode to have the "create" only version
17954
+ const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
17955
+ resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
17956
+ registerPostOrderHooks(tView, tNode);
17957
+ const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, null /* ssrId */);
17958
+ if (tView.queries !== null) {
17959
+ tView.queries.template(tView, tNode);
17960
+ embeddedTView.queries = tView.queries.embeddedTView(tNode);
17961
+ }
17962
+ return tNode;
17963
+ }
17989
17964
  /**
17990
- * Returns a new NgModuleRef instance based on the NgModule class and parent injector provided.
17965
+ * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
17991
17966
  *
17992
- * @param ngModule NgModule class.
17993
- * @param parentInjector Optional injector instance to use as a parent for the module injector. If
17994
- * not provided, `NullInjector` will be used instead.
17995
- * @returns NgModuleRef that represents an NgModule instance.
17967
+ * <ng-template #foo>
17968
+ * <div></div>
17969
+ * </ng-template>
17996
17970
  *
17997
- * @publicApi
17998
- */
17999
- function createNgModule(ngModule, parentInjector) {
18000
- return new NgModuleRef(ngModule, parentInjector ?? null, []);
18001
- }
18002
- /**
18003
- * The `createNgModule` function alias for backwards-compatibility.
18004
- * Please avoid using it directly and use `createNgModule` instead.
17971
+ * @param index The index of the container in the data array
17972
+ * @param templateFn Inline template
17973
+ * @param decls The number of nodes, local refs, and pipes for this template
17974
+ * @param vars The number of bindings for this template
17975
+ * @param tagName The name of the container element, if applicable
17976
+ * @param attrsIndex Index of template attributes in the `consts` array.
17977
+ * @param localRefs Index of the local references in the `consts` array.
17978
+ * @param localRefExtractor A function which extracts local-refs values from the template.
17979
+ * Defaults to the current element associated with the local-ref.
18005
17980
  *
18006
- * @deprecated Use `createNgModule` instead.
17981
+ * @codeGenApi
18007
17982
  */
18008
- const createNgModuleRef = createNgModule;
18009
- class NgModuleRef extends NgModuleRef$1 {
18010
- constructor(ngModuleType, _parent, additionalProviders) {
18011
- super();
18012
- this._parent = _parent;
18013
- // tslint:disable-next-line:require-internal-with-underscore
18014
- this._bootstrapComponents = [];
18015
- this.destroyCbs = [];
18016
- // When bootstrapping a module we have a dependency graph that looks like this:
18017
- // ApplicationRef -> ComponentFactoryResolver -> NgModuleRef. The problem is that if the
18018
- // module being resolved tries to inject the ComponentFactoryResolver, it'll create a
18019
- // circular dependency which will result in a runtime error, because the injector doesn't
18020
- // exist yet. We work around the issue by creating the ComponentFactoryResolver ourselves
18021
- // and providing it, rather than letting the injector resolve it.
18022
- this.componentFactoryResolver = new ComponentFactoryResolver(this);
18023
- const ngModuleDef = getNgModuleDef(ngModuleType);
18024
- ngDevMode &&
18025
- assertDefined(ngModuleDef, `NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`);
18026
- this._bootstrapComponents = maybeUnwrapFn(ngModuleDef.bootstrap);
18027
- this._r3Injector = createInjectorWithoutInjectorInstances(ngModuleType, _parent, [
18028
- { provide: NgModuleRef$1, useValue: this }, {
18029
- provide: ComponentFactoryResolver$1,
18030
- useValue: this.componentFactoryResolver
18031
- },
18032
- ...additionalProviders
18033
- ], stringify(ngModuleType), new Set(['environment']));
18034
- // We need to resolve the injector types separately from the injector creation, because
18035
- // the module might be trying to use this ref in its constructor for DI which will cause a
18036
- // circular error that will eventually error out, because the injector isn't created yet.
18037
- this._r3Injector.resolveInjectorInitializers();
18038
- this.instance = this._r3Injector.get(ngModuleType);
18039
- }
18040
- get injector() {
18041
- return this._r3Injector;
18042
- }
18043
- destroy() {
18044
- ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
18045
- const injector = this._r3Injector;
18046
- !injector.destroyed && injector.destroy();
18047
- this.destroyCbs.forEach(fn => fn());
18048
- this.destroyCbs = null;
18049
- }
18050
- onDestroy(callback) {
18051
- ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
18052
- this.destroyCbs.push(callback);
17983
+ function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
17984
+ const lView = getLView();
17985
+ const tView = getTView();
17986
+ const adjustedIndex = index + HEADER_OFFSET;
17987
+ const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
17988
+ tView.data[adjustedIndex];
17989
+ setCurrentTNode(tNode, false);
17990
+ const comment = _locateOrCreateContainerAnchor(tView, lView, tNode, index);
17991
+ if (wasLastNodeCreated()) {
17992
+ appendChild(tView, lView, comment, tNode);
18053
17993
  }
18054
- }
18055
- class NgModuleFactory extends NgModuleFactory$1 {
18056
- constructor(moduleType) {
18057
- super();
18058
- this.moduleType = moduleType;
17994
+ attachPatchData(comment, lView);
17995
+ const lContainer = createLContainer(comment, lView, comment, tNode);
17996
+ lView[adjustedIndex] = lContainer;
17997
+ addToViewTree(lView, lContainer);
17998
+ // If hydration is enabled, looks up dehydrated views in the DOM
17999
+ // using hydration annotation info and stores those views on LContainer.
18000
+ // In client-only mode, this function is a noop.
18001
+ populateDehydratedViewsInLContainer(lContainer, tNode, lView);
18002
+ if (isDirectiveHost(tNode)) {
18003
+ createDirectivesInstances(tView, lView, tNode);
18059
18004
  }
18060
- create(parentInjector) {
18061
- return new NgModuleRef(this.moduleType, parentInjector, []);
18005
+ if (localRefsIndex != null) {
18006
+ saveResolvedLocalsInData(lView, tNode, localRefExtractor);
18062
18007
  }
18008
+ return ɵɵtemplate;
18063
18009
  }
18064
- function createNgModuleRefWithProviders(moduleType, parentInjector, additionalProviders) {
18065
- return new NgModuleRef(moduleType, parentInjector, additionalProviders);
18010
+ let _locateOrCreateContainerAnchor = createContainerAnchorImpl;
18011
+ /**
18012
+ * Regular creation mode for LContainers and their anchor (comment) nodes.
18013
+ */
18014
+ function createContainerAnchorImpl(tView, lView, tNode, index) {
18015
+ lastNodeWasCreated(true);
18016
+ return lView[RENDERER].createComment(ngDevMode ? 'container' : '');
18066
18017
  }
18067
- class EnvironmentNgModuleRefAdapter extends NgModuleRef$1 {
18068
- constructor(config) {
18069
- super();
18070
- this.componentFactoryResolver = new ComponentFactoryResolver(this);
18071
- this.instance = null;
18072
- const injector = new R3Injector([
18073
- ...config.providers,
18074
- { provide: NgModuleRef$1, useValue: this },
18075
- { provide: ComponentFactoryResolver$1, useValue: this.componentFactoryResolver },
18076
- ], config.parent || getNullInjector(), config.debugName, new Set(['environment']));
18077
- this.injector = injector;
18078
- if (config.runEnvironmentInitializers) {
18079
- injector.resolveInjectorInitializers();
18080
- }
18018
+ /**
18019
+ * Enables hydration code path (to lookup existing elements in DOM)
18020
+ * in addition to the regular creation mode for LContainers and their
18021
+ * anchor (comment) nodes.
18022
+ */
18023
+ function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
18024
+ const hydrationInfo = lView[HYDRATION];
18025
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1() ||
18026
+ isDetachedByI18n(tNode) || isDisconnectedNode$1(hydrationInfo, index);
18027
+ lastNodeWasCreated(isNodeCreationMode);
18028
+ // Regular creation mode.
18029
+ if (isNodeCreationMode) {
18030
+ return createContainerAnchorImpl(tView, lView, tNode, index);
18081
18031
  }
18082
- destroy() {
18083
- this.injector.destroy();
18032
+ const ssrId = hydrationInfo.data[TEMPLATES]?.[index] ?? null;
18033
+ // Apply `ssrId` value to the underlying TView if it was not previously set.
18034
+ //
18035
+ // There might be situations when the same component is present in a template
18036
+ // multiple times and some instances are opted-out of using hydration via
18037
+ // `ngSkipHydration` attribute. In this scenario, at the time a TView is created,
18038
+ // the `ssrId` might be `null` (if the first component is opted-out of hydration).
18039
+ // The code below makes sure that the `ssrId` is applied to the TView if it's still
18040
+ // `null` and verifies we never try to override it with a different value.
18041
+ if (ssrId !== null && tNode.tView !== null) {
18042
+ if (tNode.tView.ssrId === null) {
18043
+ tNode.tView.ssrId = ssrId;
18044
+ }
18045
+ else {
18046
+ ngDevMode &&
18047
+ assertEqual(tNode.tView.ssrId, ssrId, 'Unexpected value of the `ssrId` for this TView');
18048
+ }
18084
18049
  }
18085
- onDestroy(callback) {
18086
- this.injector.onDestroy(callback);
18050
+ // Hydration mode, looking up existing elements in DOM.
18051
+ const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
18052
+ ngDevMode && validateNodeExists(currentRNode, lView, tNode);
18053
+ setSegmentHead(hydrationInfo, index, currentRNode);
18054
+ const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
18055
+ const comment = siblingAfter(viewContainerSize, currentRNode);
18056
+ if (ngDevMode) {
18057
+ validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
18058
+ markRNodeAsClaimedByHydration(comment);
18087
18059
  }
18060
+ return comment;
18061
+ }
18062
+ function enableLocateOrCreateContainerAnchorImpl() {
18063
+ _locateOrCreateContainerAnchor = locateOrCreateContainerAnchorImpl;
18088
18064
  }
18065
+
18066
+ /**
18067
+ * Describes the state of defer block dependency loading.
18068
+ */
18069
+ var DeferDependenciesLoadingState;
18070
+ (function (DeferDependenciesLoadingState) {
18071
+ /** Initial state, dependency loading is not yet triggered */
18072
+ DeferDependenciesLoadingState[DeferDependenciesLoadingState["NOT_STARTED"] = 0] = "NOT_STARTED";
18073
+ /** Dependency loading is in progress */
18074
+ DeferDependenciesLoadingState[DeferDependenciesLoadingState["IN_PROGRESS"] = 1] = "IN_PROGRESS";
18075
+ /** Dependency loading has completed successfully */
18076
+ DeferDependenciesLoadingState[DeferDependenciesLoadingState["COMPLETE"] = 2] = "COMPLETE";
18077
+ /** Dependency loading has failed */
18078
+ DeferDependenciesLoadingState[DeferDependenciesLoadingState["FAILED"] = 3] = "FAILED";
18079
+ })(DeferDependenciesLoadingState || (DeferDependenciesLoadingState = {}));
18080
+ /** Slot index where `minimum` parameter value is stored. */
18081
+ const MINIMUM_SLOT = 0;
18082
+ /** Slot index where `after` parameter value is stored. */
18083
+ const LOADING_AFTER_SLOT = 1;
18089
18084
  /**
18090
- * Create a new environment injector.
18091
- *
18092
- * Learn more about environment injectors in
18093
- * [this guide](guide/standalone-components#environment-injectors).
18085
+ * Describes the current state of this defer block instance.
18094
18086
  *
18095
- * @param providers An array of providers.
18096
- * @param parent A parent environment injector.
18097
- * @param debugName An optional name for this injector instance, which will be used in error
18098
- * messages.
18087
+ * @publicApi
18088
+ * @developerPreview
18089
+ */
18090
+ var DeferBlockState;
18091
+ (function (DeferBlockState) {
18092
+ /** The placeholder block content is rendered */
18093
+ DeferBlockState[DeferBlockState["Placeholder"] = 0] = "Placeholder";
18094
+ /** The loading block content is rendered */
18095
+ DeferBlockState[DeferBlockState["Loading"] = 1] = "Loading";
18096
+ /** The main content block content is rendered */
18097
+ DeferBlockState[DeferBlockState["Complete"] = 2] = "Complete";
18098
+ /** The error block content is rendered */
18099
+ DeferBlockState[DeferBlockState["Error"] = 3] = "Error";
18100
+ })(DeferBlockState || (DeferBlockState = {}));
18101
+ /**
18102
+ * Describes the initial state of this defer block instance.
18099
18103
  *
18104
+ * Note: this state is internal only and *must* be represented
18105
+ * with a number lower than any value in the `DeferBlockState` enum.
18106
+ */
18107
+ var DeferBlockInternalState;
18108
+ (function (DeferBlockInternalState) {
18109
+ /** Initial state. Nothing is rendered yet. */
18110
+ DeferBlockInternalState[DeferBlockInternalState["Initial"] = -1] = "Initial";
18111
+ })(DeferBlockInternalState || (DeferBlockInternalState = {}));
18112
+ const NEXT_DEFER_BLOCK_STATE = 0;
18113
+ // Note: it's *important* to keep the state in this slot, because this slot
18114
+ // is used by runtime logic to differentiate between LViews, LContainers and
18115
+ // other types (see `isLView` and `isLContainer` functions). In case of defer
18116
+ // blocks, this slot would always be a number.
18117
+ const DEFER_BLOCK_STATE = 1;
18118
+ const STATE_IS_FROZEN_UNTIL = 2;
18119
+ const LOADING_AFTER_CLEANUP_FN = 3;
18120
+ const TRIGGER_CLEANUP_FNS = 4;
18121
+ const PREFETCH_TRIGGER_CLEANUP_FNS = 5;
18122
+ /**
18123
+ * Options for configuring defer blocks behavior.
18100
18124
  * @publicApi
18125
+ * @developerPreview
18101
18126
  */
18102
- function createEnvironmentInjector(providers, parent, debugName = null) {
18103
- const adapter = new EnvironmentNgModuleRefAdapter({ providers, parent, debugName, runEnvironmentInitializers: true });
18104
- return adapter.injector;
18105
- }
18127
+ var DeferBlockBehavior;
18128
+ (function (DeferBlockBehavior) {
18129
+ /**
18130
+ * Manual triggering mode for defer blocks. Provides control over when defer blocks render
18131
+ * and which state they render.
18132
+ */
18133
+ DeferBlockBehavior[DeferBlockBehavior["Manual"] = 0] = "Manual";
18134
+ /**
18135
+ * Playthrough mode for defer blocks. This mode behaves like defer blocks would in a browser.
18136
+ * This is the default behavior in test environments.
18137
+ */
18138
+ DeferBlockBehavior[DeferBlockBehavior["Playthrough"] = 1] = "Playthrough";
18139
+ })(DeferBlockBehavior || (DeferBlockBehavior = {}));
18106
18140
 
18107
- /**
18108
- * A service used by the framework to create and cache injector instances.
18141
+ /*!
18142
+ * @license
18143
+ * Copyright Google LLC All Rights Reserved.
18109
18144
  *
18110
- * This service is used to create a single injector instance for each defer
18111
- * block definition, to avoid creating an injector for each defer block instance
18112
- * of a certain type.
18145
+ * Use of this source code is governed by an MIT-style license that can be
18146
+ * found in the LICENSE file at https://angular.io/license
18113
18147
  */
18114
- class CachedInjectorService {
18115
- constructor() {
18116
- this.cachedInjectors = new Map();
18148
+ /**
18149
+ * Registers a cleanup function associated with a prefetching trigger
18150
+ * or a regular trigger of a defer block.
18151
+ */
18152
+ function storeTriggerCleanupFn(type, lDetails, cleanupFn) {
18153
+ const key = type === 1 /* TriggerType.Prefetch */ ? PREFETCH_TRIGGER_CLEANUP_FNS : TRIGGER_CLEANUP_FNS;
18154
+ if (lDetails[key] === null) {
18155
+ lDetails[key] = [];
18117
18156
  }
18118
- getOrCreateInjector(key, parentInjector, providers, debugName) {
18119
- if (!this.cachedInjectors.has(key)) {
18120
- const injector = providers.length > 0 ?
18121
- createEnvironmentInjector(providers, parentInjector, debugName) :
18122
- null;
18123
- this.cachedInjectors.set(key, injector);
18157
+ lDetails[key].push(cleanupFn);
18158
+ }
18159
+ /**
18160
+ * Invokes registered cleanup functions either for prefetch or for regular triggers.
18161
+ */
18162
+ function invokeTriggerCleanupFns(type, lDetails) {
18163
+ const key = type === 1 /* TriggerType.Prefetch */ ? PREFETCH_TRIGGER_CLEANUP_FNS : TRIGGER_CLEANUP_FNS;
18164
+ const cleanupFns = lDetails[key];
18165
+ if (cleanupFns !== null) {
18166
+ for (const cleanupFn of cleanupFns) {
18167
+ cleanupFn();
18124
18168
  }
18125
- return this.cachedInjectors.get(key);
18169
+ lDetails[key] = null;
18126
18170
  }
18127
- ngOnDestroy() {
18128
- try {
18129
- for (const injector of this.cachedInjectors.values()) {
18130
- if (injector !== null) {
18131
- injector.destroy();
18132
- }
18133
- }
18171
+ }
18172
+ /**
18173
+ * Invokes registered cleanup functions for both prefetch and regular triggers.
18174
+ */
18175
+ function invokeAllTriggerCleanupFns(lDetails) {
18176
+ invokeTriggerCleanupFns(1 /* TriggerType.Prefetch */, lDetails);
18177
+ invokeTriggerCleanupFns(0 /* TriggerType.Regular */, lDetails);
18178
+ }
18179
+
18180
+ function noop(...args) {
18181
+ // Do nothing.
18182
+ }
18183
+
18184
+ function getNativeRequestAnimationFrame() {
18185
+ // Note: the `getNativeRequestAnimationFrame` is used in the `NgZone` class, but we cannot use the
18186
+ // `inject` function. The `NgZone` instance may be created manually, and thus the injection
18187
+ // context will be unavailable. This might be enough to check whether `requestAnimationFrame` is
18188
+ // available because otherwise, we'll fall back to `setTimeout`.
18189
+ const isBrowser = typeof _global['requestAnimationFrame'] === 'function';
18190
+ // Note: `requestAnimationFrame` is unavailable when the code runs in the Node.js environment. We
18191
+ // use `setTimeout` because no changes are required other than checking if the current platform is
18192
+ // the browser. `setTimeout` is a well-established API that is available in both environments.
18193
+ // `requestAnimationFrame` is used in the browser to coalesce event tasks since event tasks are
18194
+ // usually executed within the same rendering frame (but this is more implementation details of
18195
+ // browsers).
18196
+ let nativeRequestAnimationFrame = _global[isBrowser ? 'requestAnimationFrame' : 'setTimeout'];
18197
+ let nativeCancelAnimationFrame = _global[isBrowser ? 'cancelAnimationFrame' : 'clearTimeout'];
18198
+ if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
18199
+ // Note: zone.js sets original implementations on patched APIs behind the
18200
+ // `__zone_symbol__OriginalDelegate` key (see `attachOriginToPatched`). Given the following
18201
+ // example: `window.requestAnimationFrame.__zone_symbol__OriginalDelegate`; this would return an
18202
+ // unpatched implementation of the `requestAnimationFrame`, which isn't intercepted by the
18203
+ // Angular zone. We use the unpatched implementation to avoid another change detection when
18204
+ // coalescing tasks.
18205
+ const unpatchedRequestAnimationFrame = nativeRequestAnimationFrame[Zone.__symbol__('OriginalDelegate')];
18206
+ if (unpatchedRequestAnimationFrame) {
18207
+ nativeRequestAnimationFrame = unpatchedRequestAnimationFrame;
18134
18208
  }
18135
- finally {
18136
- this.cachedInjectors.clear();
18209
+ const unpatchedCancelAnimationFrame = nativeCancelAnimationFrame[Zone.__symbol__('OriginalDelegate')];
18210
+ if (unpatchedCancelAnimationFrame) {
18211
+ nativeCancelAnimationFrame = unpatchedCancelAnimationFrame;
18137
18212
  }
18138
18213
  }
18139
- /** @nocollapse */
18140
- static { this.ɵprov = ɵɵdefineInjectable({
18141
- token: CachedInjectorService,
18142
- providedIn: 'environment',
18143
- factory: () => new CachedInjectorService(),
18144
- }); }
18214
+ return { nativeRequestAnimationFrame, nativeCancelAnimationFrame };
18145
18215
  }
18146
18216
 
18147
- /**
18148
- * The name of a field that Angular monkey-patches onto a component
18149
- * class to store a function that loads defer-loadable dependencies
18150
- * and applies metadata to a class.
18151
- */
18152
- const ASYNC_COMPONENT_METADATA_FN = '__ngAsyncComponentMetadataFn__';
18153
- /**
18154
- * If a given component has unresolved async metadata - returns a reference
18155
- * to a function that applies component metadata after resolving defer-loadable
18156
- * dependencies. Otherwise - this function returns `null`.
18157
- */
18158
- function getAsyncClassMetadataFn(type) {
18159
- const componentClass = type; // cast to `any`, so that we can read a monkey-patched field
18160
- return componentClass[ASYNC_COMPONENT_METADATA_FN] ?? null;
18217
+ class AsyncStackTaggingZoneSpec {
18218
+ constructor(namePrefix, consoleAsyncStackTaggingImpl = console) {
18219
+ this.name = 'asyncStackTagging for ' + namePrefix;
18220
+ this.createTask = consoleAsyncStackTaggingImpl?.createTask ?? (() => null);
18221
+ }
18222
+ onScheduleTask(delegate, _current, target, task) {
18223
+ task.consoleTask = this.createTask(`Zone - ${task.source || task.type}`);
18224
+ return delegate.scheduleTask(target, task);
18225
+ }
18226
+ onInvokeTask(delegate, _currentZone, targetZone, task, applyThis, applyArgs) {
18227
+ let ret;
18228
+ if (task.consoleTask) {
18229
+ ret = task.consoleTask.run(() => delegate.invokeTask(targetZone, task, applyThis, applyArgs));
18230
+ }
18231
+ else {
18232
+ ret = delegate.invokeTask(targetZone, task, applyThis, applyArgs);
18233
+ }
18234
+ return ret;
18235
+ }
18161
18236
  }
18237
+
18162
18238
  /**
18163
- * Handles the process of applying metadata info to a component class in case
18164
- * component template has defer blocks (thus some dependencies became deferrable).
18239
+ * An injectable service for executing work inside or outside of the Angular zone.
18240
+ *
18241
+ * The most common use of this service is to optimize performance when starting a work consisting of
18242
+ * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
18243
+ * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
18244
+ * can reenter the Angular zone via {@link #run}.
18245
+ *
18246
+ * <!-- TODO: add/fix links to:
18247
+ * - docs explaining zones and the use of zones in Angular and change-detection
18248
+ * - link to runOutsideAngular/run (throughout this file!)
18249
+ * -->
18250
+ *
18251
+ * @usageNotes
18252
+ * ### Example
18253
+ *
18254
+ * ```
18255
+ * import {Component, NgZone} from '@angular/core';
18256
+ * import {NgIf} from '@angular/common';
18257
+ *
18258
+ * @Component({
18259
+ * selector: 'ng-zone-demo',
18260
+ * template: `
18261
+ * <h2>Demo: NgZone</h2>
18262
+ *
18263
+ * <p>Progress: {{progress}}%</p>
18264
+ * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
18265
+ *
18266
+ * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
18267
+ * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
18268
+ * `,
18269
+ * })
18270
+ * export class NgZoneDemo {
18271
+ * progress: number = 0;
18272
+ * label: string;
18273
+ *
18274
+ * constructor(private _ngZone: NgZone) {}
18275
+ *
18276
+ * // Loop inside the Angular zone
18277
+ * // so the UI DOES refresh after each setTimeout cycle
18278
+ * processWithinAngularZone() {
18279
+ * this.label = 'inside';
18280
+ * this.progress = 0;
18281
+ * this._increaseProgress(() => console.log('Inside Done!'));
18282
+ * }
18283
+ *
18284
+ * // Loop outside of the Angular zone
18285
+ * // so the UI DOES NOT refresh after each setTimeout cycle
18286
+ * processOutsideOfAngularZone() {
18287
+ * this.label = 'outside';
18288
+ * this.progress = 0;
18289
+ * this._ngZone.runOutsideAngular(() => {
18290
+ * this._increaseProgress(() => {
18291
+ * // reenter the Angular zone and display done
18292
+ * this._ngZone.run(() => { console.log('Outside Done!'); });
18293
+ * });
18294
+ * });
18295
+ * }
18165
18296
  *
18166
- * @param type Component class where metadata should be added
18167
- * @param dependencyLoaderFn Function that loads dependencies
18168
- * @param metadataSetterFn Function that forms a scope in which the `setClassMetadata` is invoked
18169
- */
18170
- function setClassMetadataAsync(type, dependencyLoaderFn, metadataSetterFn) {
18171
- const componentClass = type; // cast to `any`, so that we can monkey-patch it
18172
- componentClass[ASYNC_COMPONENT_METADATA_FN] = () => Promise.all(dependencyLoaderFn()).then(dependencies => {
18173
- metadataSetterFn(...dependencies);
18174
- // Metadata is now set, reset field value to indicate that this component
18175
- // can by used/compiled synchronously.
18176
- componentClass[ASYNC_COMPONENT_METADATA_FN] = null;
18177
- return dependencies;
18178
- });
18179
- return componentClass[ASYNC_COMPONENT_METADATA_FN];
18180
- }
18181
- /**
18182
- * Adds decorator, constructor, and property metadata to a given type via static metadata fields
18183
- * on the type.
18297
+ * _increaseProgress(doneCallback: () => void) {
18298
+ * this.progress += 1;
18299
+ * console.log(`Current progress: ${this.progress}%`);
18184
18300
  *
18185
- * These metadata fields can later be read with Angular's `ReflectionCapabilities` API.
18301
+ * if (this.progress < 100) {
18302
+ * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
18303
+ * } else {
18304
+ * doneCallback();
18305
+ * }
18306
+ * }
18307
+ * }
18308
+ * ```
18186
18309
  *
18187
- * Calls to `setClassMetadata` can be guarded by ngDevMode, resulting in the metadata assignments
18188
- * being tree-shaken away during production builds.
18310
+ * @publicApi
18189
18311
  */
18190
- function setClassMetadata(type, decorators, ctorParameters, propDecorators) {
18191
- return noSideEffects(() => {
18192
- const clazz = type;
18193
- if (decorators !== null) {
18194
- if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) {
18195
- clazz.decorators.push(...decorators);
18196
- }
18197
- else {
18198
- clazz.decorators = decorators;
18199
- }
18312
+ class NgZone {
18313
+ constructor({ enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false }) {
18314
+ this.hasPendingMacrotasks = false;
18315
+ this.hasPendingMicrotasks = false;
18316
+ /**
18317
+ * Whether there are no outstanding microtasks or macrotasks.
18318
+ */
18319
+ this.isStable = true;
18320
+ /**
18321
+ * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
18322
+ */
18323
+ this.onUnstable = new EventEmitter(false);
18324
+ /**
18325
+ * Notifies when there is no more microtasks enqueued in the current VM Turn.
18326
+ * This is a hint for Angular to do change detection, which may enqueue more microtasks.
18327
+ * For this reason this event can fire multiple times per VM Turn.
18328
+ */
18329
+ this.onMicrotaskEmpty = new EventEmitter(false);
18330
+ /**
18331
+ * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
18332
+ * implies we are about to relinquish VM turn.
18333
+ * This event gets called just once.
18334
+ */
18335
+ this.onStable = new EventEmitter(false);
18336
+ /**
18337
+ * Notifies that an error has been delivered.
18338
+ */
18339
+ this.onError = new EventEmitter(false);
18340
+ if (typeof Zone == 'undefined') {
18341
+ throw new RuntimeError(908 /* RuntimeErrorCode.MISSING_ZONEJS */, ngDevMode && `In this configuration Angular requires Zone.js`);
18200
18342
  }
18201
- if (ctorParameters !== null) {
18202
- // Rather than merging, clobber the existing parameters. If other projects exist which
18203
- // use tsickle-style annotations and reflect over them in the same way, this could
18204
- // cause issues, but that is vanishingly unlikely.
18205
- clazz.ctorParameters = ctorParameters;
18343
+ Zone.assertZonePatched();
18344
+ const self = this;
18345
+ self._nesting = 0;
18346
+ self._outer = self._inner = Zone.current;
18347
+ // AsyncStackTaggingZoneSpec provides `linked stack traces` to show
18348
+ // where the async operation is scheduled. For more details, refer
18349
+ // to this article, https://developer.chrome.com/blog/devtools-better-angular-debugging/
18350
+ // And we only import this AsyncStackTaggingZoneSpec in development mode,
18351
+ // in the production mode, the AsyncStackTaggingZoneSpec will be tree shaken away.
18352
+ if (ngDevMode) {
18353
+ self._inner = self._inner.fork(new AsyncStackTaggingZoneSpec('Angular'));
18206
18354
  }
18207
- if (propDecorators !== null) {
18208
- // The property decorator objects are merged as it is possible different fields have
18209
- // different decorator types. Decorators on individual fields are not merged, as it's
18210
- // also incredibly unlikely that a field will be decorated both with an Angular
18211
- // decorator and a non-Angular decorator that's also been downleveled.
18212
- if (clazz.hasOwnProperty('propDecorators') && clazz.propDecorators !== undefined) {
18213
- clazz.propDecorators = { ...clazz.propDecorators, ...propDecorators };
18214
- }
18215
- else {
18216
- clazz.propDecorators = propDecorators;
18217
- }
18355
+ if (Zone['TaskTrackingZoneSpec']) {
18356
+ self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']);
18218
18357
  }
18219
- });
18220
- }
18221
-
18222
- /*
18223
- * This file exists to support compilation of @angular/core in Ivy mode.
18224
- *
18225
- * When the Angular compiler processes a compilation unit, it normally writes imports to
18226
- * @angular/core. When compiling the core package itself this strategy isn't usable. Instead, the
18227
- * compiler writes imports to this file.
18228
- *
18229
- * Only a subset of such imports are supported - core is not allowed to declare components or pipes.
18230
- * A check in ngtsc's `R3SymbolsImportRewriter` validates this condition. The rewriter is only used
18231
- * when compiling @angular/core and is responsible for translating an external name (prefixed with
18232
- * ɵ) to the internal symbol name as exported below.
18233
- *
18234
- * The below symbols are used for @Injectable and @NgModule compilation.
18235
- */
18236
- /**
18237
- * The existence of this constant (in this particular file) informs the Angular compiler that the
18238
- * current program is actually @angular/core, which needs to be compiled specially.
18239
- */
18240
- const ITS_JUST_ANGULAR = true;
18241
-
18242
- /**
18243
- * *Internal* service that keeps track of pending tasks happening in the system.
18244
- *
18245
- * This information is needed to make sure that the serialization on the server
18246
- * is delayed until all tasks in the queue (such as an initial navigation or a
18247
- * pending HTTP request) are completed.
18248
- *
18249
- * Pending tasks continue to contribute to the stableness of `ApplicationRef`
18250
- * throughout the lifetime of the application.
18251
- */
18252
- class PendingTasks {
18253
- constructor() {
18254
- this.taskId = 0;
18255
- this.pendingTasks = new Set();
18256
- this.hasPendingTasks = new BehaviorSubject(false);
18257
- }
18258
- get _hasPendingTasks() {
18259
- return this.hasPendingTasks.value;
18260
- }
18261
- add() {
18262
- if (!this._hasPendingTasks) {
18263
- this.hasPendingTasks.next(true);
18358
+ if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
18359
+ self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
18264
18360
  }
18265
- const taskId = this.taskId++;
18266
- this.pendingTasks.add(taskId);
18267
- return taskId;
18361
+ // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
18362
+ // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
18363
+ self.shouldCoalesceEventChangeDetection =
18364
+ !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
18365
+ self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
18366
+ self.lastRequestAnimationFrameId = -1;
18367
+ self.nativeRequestAnimationFrame = getNativeRequestAnimationFrame().nativeRequestAnimationFrame;
18368
+ forkInnerZoneWithAngularBehavior(self);
18268
18369
  }
18269
- remove(taskId) {
18270
- this.pendingTasks.delete(taskId);
18271
- if (this.pendingTasks.size === 0 && this._hasPendingTasks) {
18272
- this.hasPendingTasks.next(false);
18370
+ /**
18371
+ This method checks whether the method call happens within an Angular Zone instance.
18372
+ */
18373
+ static isInAngularZone() {
18374
+ // Zone needs to be checked, because this method might be called even when NoopNgZone is used.
18375
+ return typeof Zone !== 'undefined' && Zone.current.get('isAngularZone') === true;
18376
+ }
18377
+ /**
18378
+ Assures that the method is called within the Angular Zone, otherwise throws an error.
18379
+ */
18380
+ static assertInAngularZone() {
18381
+ if (!NgZone.isInAngularZone()) {
18382
+ throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to be in Angular Zone, but it is not!');
18273
18383
  }
18274
18384
  }
18275
- ngOnDestroy() {
18276
- this.pendingTasks.clear();
18277
- if (this._hasPendingTasks) {
18278
- this.hasPendingTasks.next(false);
18385
+ /**
18386
+ Assures that the method is called outside of the Angular Zone, otherwise throws an error.
18387
+ */
18388
+ static assertNotInAngularZone() {
18389
+ if (NgZone.isInAngularZone()) {
18390
+ throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to not be in Angular Zone, but it is!');
18279
18391
  }
18280
18392
  }
18281
- static { this.ɵfac = function PendingTasks_Factory(t) { return new (t || PendingTasks)(); }; }
18282
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: PendingTasks, factory: PendingTasks.ɵfac, providedIn: 'root' }); }
18283
- }
18284
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PendingTasks, [{
18285
- type: Injectable,
18286
- args: [{ providedIn: 'root' }]
18287
- }], null, null); })();
18288
-
18289
- function isIterable(obj) {
18290
- return obj !== null && typeof obj === 'object' && obj[Symbol.iterator] !== undefined;
18291
- }
18292
- function isListLikeIterable(obj) {
18293
- if (!isJsObject(obj))
18294
- return false;
18295
- return Array.isArray(obj) ||
18296
- (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
18297
- Symbol.iterator in obj); // JS Iterable have a Symbol.iterator prop
18298
- }
18299
- function areIterablesEqual(a, b, comparator) {
18300
- const iterator1 = a[Symbol.iterator]();
18301
- const iterator2 = b[Symbol.iterator]();
18302
- while (true) {
18303
- const item1 = iterator1.next();
18304
- const item2 = iterator2.next();
18305
- if (item1.done && item2.done)
18306
- return true;
18307
- if (item1.done || item2.done)
18308
- return false;
18309
- if (!comparator(item1.value, item2.value))
18310
- return false;
18393
+ /**
18394
+ * Executes the `fn` function synchronously within the Angular zone and returns value returned by
18395
+ * the function.
18396
+ *
18397
+ * Running functions via `run` allows you to reenter Angular zone from a task that was executed
18398
+ * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
18399
+ *
18400
+ * Any future tasks or microtasks scheduled from within this function will continue executing from
18401
+ * within the Angular zone.
18402
+ *
18403
+ * If a synchronous error happens it will be rethrown and not reported via `onError`.
18404
+ */
18405
+ run(fn, applyThis, applyArgs) {
18406
+ return this._inner.run(fn, applyThis, applyArgs);
18311
18407
  }
18312
- }
18313
- function iterateListLike(obj, fn) {
18314
- if (Array.isArray(obj)) {
18315
- for (let i = 0; i < obj.length; i++) {
18316
- fn(obj[i]);
18408
+ /**
18409
+ * Executes the `fn` function synchronously within the Angular zone as a task and returns value
18410
+ * returned by the function.
18411
+ *
18412
+ * Running functions via `run` allows you to reenter Angular zone from a task that was executed
18413
+ * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
18414
+ *
18415
+ * Any future tasks or microtasks scheduled from within this function will continue executing from
18416
+ * within the Angular zone.
18417
+ *
18418
+ * If a synchronous error happens it will be rethrown and not reported via `onError`.
18419
+ */
18420
+ runTask(fn, applyThis, applyArgs, name) {
18421
+ const zone = this._inner;
18422
+ const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
18423
+ try {
18424
+ return zone.runTask(task, applyThis, applyArgs);
18425
+ }
18426
+ finally {
18427
+ zone.cancelTask(task);
18317
18428
  }
18318
18429
  }
18319
- else {
18320
- const iterator = obj[Symbol.iterator]();
18321
- let item;
18322
- while (!((item = iterator.next()).done)) {
18323
- fn(item.value);
18324
- }
18430
+ /**
18431
+ * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
18432
+ * rethrown.
18433
+ */
18434
+ runGuarded(fn, applyThis, applyArgs) {
18435
+ return this._inner.runGuarded(fn, applyThis, applyArgs);
18325
18436
  }
18326
- }
18327
- function isJsObject(o) {
18328
- return o !== null && (typeof o === 'function' || typeof o === 'object');
18329
- }
18330
-
18331
- function devModeEqual(a, b) {
18332
- const isListLikeIterableA = isListLikeIterable(a);
18333
- const isListLikeIterableB = isListLikeIterable(b);
18334
- if (isListLikeIterableA && isListLikeIterableB) {
18335
- return areIterablesEqual(a, b, devModeEqual);
18437
+ /**
18438
+ * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
18439
+ * the function.
18440
+ *
18441
+ * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
18442
+ * work that
18443
+ * doesn't trigger Angular change-detection or is subject to Angular's error handling.
18444
+ *
18445
+ * Any future tasks or microtasks scheduled from within this function will continue executing from
18446
+ * outside of the Angular zone.
18447
+ *
18448
+ * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
18449
+ */
18450
+ runOutsideAngular(fn) {
18451
+ return this._outer.run(fn);
18336
18452
  }
18337
- else {
18338
- const isAObject = a && (typeof a === 'object' || typeof a === 'function');
18339
- const isBObject = b && (typeof b === 'object' || typeof b === 'function');
18340
- if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
18341
- return true;
18453
+ }
18454
+ const EMPTY_PAYLOAD = {};
18455
+ function checkStable(zone) {
18456
+ // TODO: @JiaLiPassion, should check zone.isCheckStableRunning to prevent
18457
+ // re-entry. The case is:
18458
+ //
18459
+ // @Component({...})
18460
+ // export class AppComponent {
18461
+ // constructor(private ngZone: NgZone) {
18462
+ // this.ngZone.onStable.subscribe(() => {
18463
+ // this.ngZone.run(() => console.log('stable'););
18464
+ // });
18465
+ // }
18466
+ //
18467
+ // The onStable subscriber run another function inside ngZone
18468
+ // which causes `checkStable()` re-entry.
18469
+ // But this fix causes some issues in g3, so this fix will be
18470
+ // launched in another PR.
18471
+ if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
18472
+ try {
18473
+ zone._nesting++;
18474
+ zone.onMicrotaskEmpty.emit(null);
18342
18475
  }
18343
- else {
18344
- return Object.is(a, b);
18476
+ finally {
18477
+ zone._nesting--;
18478
+ if (!zone.hasPendingMicrotasks) {
18479
+ try {
18480
+ zone.runOutsideAngular(() => zone.onStable.emit(null));
18481
+ }
18482
+ finally {
18483
+ zone.isStable = true;
18484
+ }
18485
+ }
18345
18486
  }
18346
18487
  }
18347
18488
  }
18348
-
18349
- // TODO(misko): consider inlining
18350
- /** Updates binding and returns the value. */
18351
- function updateBinding(lView, bindingIndex, value) {
18352
- return lView[bindingIndex] = value;
18353
- }
18354
- /** Gets the current binding value. */
18355
- function getBinding(lView, bindingIndex) {
18356
- ngDevMode && assertIndexInRange(lView, bindingIndex);
18357
- ngDevMode &&
18358
- assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
18359
- return lView[bindingIndex];
18360
- }
18361
- /**
18362
- * Updates binding if changed, then returns whether it was updated.
18363
- *
18364
- * This function also checks the `CheckNoChangesMode` and throws if changes are made.
18365
- * Some changes (Objects/iterables) during `CheckNoChangesMode` are exempt to comply with VE
18366
- * behavior.
18367
- *
18368
- * @param lView current `LView`
18369
- * @param bindingIndex The binding in the `LView` to check
18370
- * @param value New value to check against `lView[bindingIndex]`
18371
- * @returns `true` if the bindings has changed. (Throws if binding has changed during
18372
- * `CheckNoChangesMode`)
18373
- */
18374
- function bindingUpdated(lView, bindingIndex, value) {
18375
- ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
18376
- ngDevMode &&
18377
- assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`);
18378
- const oldValue = lView[bindingIndex];
18379
- if (Object.is(oldValue, value)) {
18380
- return false;
18489
+ function delayChangeDetectionForEvents(zone) {
18490
+ /**
18491
+ * We also need to check _nesting here
18492
+ * Consider the following case with shouldCoalesceRunChangeDetection = true
18493
+ *
18494
+ * ngZone.run(() => {});
18495
+ * ngZone.run(() => {});
18496
+ *
18497
+ * We want the two `ngZone.run()` only trigger one change detection
18498
+ * when shouldCoalesceRunChangeDetection is true.
18499
+ * And because in this case, change detection run in async way(requestAnimationFrame),
18500
+ * so we also need to check the _nesting here to prevent multiple
18501
+ * change detections.
18502
+ */
18503
+ if (zone.isCheckStableRunning || zone.lastRequestAnimationFrameId !== -1) {
18504
+ return;
18381
18505
  }
18382
- else {
18383
- if (ngDevMode && isInCheckNoChangesMode()) {
18384
- // View engine didn't report undefined values as changed on the first checkNoChanges pass
18385
- // (before the change detection was run).
18386
- const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
18387
- if (!devModeEqual(oldValueToCompare, value)) {
18388
- const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
18389
- throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName, lView);
18506
+ zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(_global, () => {
18507
+ // This is a work around for https://github.com/angular/angular/issues/36839.
18508
+ // The core issue is that when event coalescing is enabled it is possible for microtasks
18509
+ // to get flushed too early (As is the case with `Promise.then`) between the
18510
+ // coalescing eventTasks.
18511
+ //
18512
+ // To workaround this we schedule a "fake" eventTask before we process the
18513
+ // coalescing eventTasks. The benefit of this is that the "fake" container eventTask
18514
+ // will prevent the microtasks queue from getting drained in between the coalescing
18515
+ // eventTask execution.
18516
+ if (!zone.fakeTopEventTask) {
18517
+ zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
18518
+ zone.lastRequestAnimationFrameId = -1;
18519
+ updateMicroTaskStatus(zone);
18520
+ zone.isCheckStableRunning = true;
18521
+ checkStable(zone);
18522
+ zone.isCheckStableRunning = false;
18523
+ }, undefined, () => { }, () => { });
18524
+ }
18525
+ zone.fakeTopEventTask.invoke();
18526
+ });
18527
+ updateMicroTaskStatus(zone);
18528
+ }
18529
+ function forkInnerZoneWithAngularBehavior(zone) {
18530
+ const delayChangeDetectionForEventsDelegate = () => {
18531
+ delayChangeDetectionForEvents(zone);
18532
+ };
18533
+ zone._inner = zone._inner.fork({
18534
+ name: 'angular',
18535
+ properties: { 'isAngularZone': true },
18536
+ onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
18537
+ if (shouldBeIgnoredByZone(applyArgs)) {
18538
+ return delegate.invokeTask(target, task, applyThis, applyArgs);
18390
18539
  }
18391
- // There was a change, but the `devModeEqual` decided that the change is exempt from an error.
18392
- // For this reason we exit as if no change. The early exit is needed to prevent the changed
18393
- // value to be written into `LView` (If we would write the new value that we would not see it
18394
- // as change on next CD.)
18540
+ try {
18541
+ onEnter(zone);
18542
+ return delegate.invokeTask(target, task, applyThis, applyArgs);
18543
+ }
18544
+ finally {
18545
+ if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
18546
+ zone.shouldCoalesceRunChangeDetection) {
18547
+ delayChangeDetectionForEventsDelegate();
18548
+ }
18549
+ onLeave(zone);
18550
+ }
18551
+ },
18552
+ onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
18553
+ try {
18554
+ onEnter(zone);
18555
+ return delegate.invoke(target, callback, applyThis, applyArgs, source);
18556
+ }
18557
+ finally {
18558
+ if (zone.shouldCoalesceRunChangeDetection) {
18559
+ delayChangeDetectionForEventsDelegate();
18560
+ }
18561
+ onLeave(zone);
18562
+ }
18563
+ },
18564
+ onHasTask: (delegate, current, target, hasTaskState) => {
18565
+ delegate.hasTask(target, hasTaskState);
18566
+ if (current === target) {
18567
+ // We are only interested in hasTask events which originate from our zone
18568
+ // (A child hasTask event is not interesting to us)
18569
+ if (hasTaskState.change == 'microTask') {
18570
+ zone._hasPendingMicrotasks = hasTaskState.microTask;
18571
+ updateMicroTaskStatus(zone);
18572
+ checkStable(zone);
18573
+ }
18574
+ else if (hasTaskState.change == 'macroTask') {
18575
+ zone.hasPendingMacrotasks = hasTaskState.macroTask;
18576
+ }
18577
+ }
18578
+ },
18579
+ onHandleError: (delegate, current, target, error) => {
18580
+ delegate.handleError(target, error);
18581
+ zone.runOutsideAngular(() => zone.onError.emit(error));
18395
18582
  return false;
18396
18583
  }
18397
- lView[bindingIndex] = value;
18398
- return true;
18399
- }
18400
- }
18401
- /** Updates 2 bindings if changed, then returns whether either was updated. */
18402
- function bindingUpdated2(lView, bindingIndex, exp1, exp2) {
18403
- const different = bindingUpdated(lView, bindingIndex, exp1);
18404
- return bindingUpdated(lView, bindingIndex + 1, exp2) || different;
18405
- }
18406
- /** Updates 3 bindings if changed, then returns whether any was updated. */
18407
- function bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) {
18408
- const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
18409
- return bindingUpdated(lView, bindingIndex + 2, exp3) || different;
18410
- }
18411
- /** Updates 4 bindings if changed, then returns whether any was updated. */
18412
- function bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) {
18413
- const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
18414
- return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different;
18415
- }
18416
-
18417
- /**
18418
- * Checks whether a TNode is considered detached, i.e. not present in the
18419
- * translated i18n template. We should not attempt hydration for such nodes
18420
- * and instead, use a regular "creation mode".
18421
- */
18422
- function isDetachedByI18n(tNode) {
18423
- return (tNode.flags & 32 /* TNodeFlags.isDetached */) === 32 /* TNodeFlags.isDetached */;
18424
- }
18425
-
18426
- function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
18427
- ngDevMode && assertFirstCreatePass(tView);
18428
- ngDevMode && ngDevMode.firstCreatePass++;
18429
- const tViewConsts = tView.consts;
18430
- // TODO(pk): refactor getOrCreateTNode to have the "create" only version
18431
- const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
18432
- resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
18433
- registerPostOrderHooks(tView, tNode);
18434
- const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, null /* ssrId */);
18435
- if (tView.queries !== null) {
18436
- tView.queries.template(tView, tNode);
18437
- embeddedTView.queries = tView.queries.embeddedTView(tNode);
18438
- }
18439
- return tNode;
18584
+ });
18440
18585
  }
18441
- /**
18442
- * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
18443
- *
18444
- * <ng-template #foo>
18445
- * <div></div>
18446
- * </ng-template>
18447
- *
18448
- * @param index The index of the container in the data array
18449
- * @param templateFn Inline template
18450
- * @param decls The number of nodes, local refs, and pipes for this template
18451
- * @param vars The number of bindings for this template
18452
- * @param tagName The name of the container element, if applicable
18453
- * @param attrsIndex Index of template attributes in the `consts` array.
18454
- * @param localRefs Index of the local references in the `consts` array.
18455
- * @param localRefExtractor A function which extracts local-refs values from the template.
18456
- * Defaults to the current element associated with the local-ref.
18457
- *
18458
- * @codeGenApi
18459
- */
18460
- function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
18461
- const lView = getLView();
18462
- const tView = getTView();
18463
- const adjustedIndex = index + HEADER_OFFSET;
18464
- const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
18465
- tView.data[adjustedIndex];
18466
- setCurrentTNode(tNode, false);
18467
- const comment = _locateOrCreateContainerAnchor(tView, lView, tNode, index);
18468
- if (wasLastNodeCreated()) {
18469
- appendChild(tView, lView, comment, tNode);
18586
+ function updateMicroTaskStatus(zone) {
18587
+ if (zone._hasPendingMicrotasks ||
18588
+ ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
18589
+ zone.lastRequestAnimationFrameId !== -1)) {
18590
+ zone.hasPendingMicrotasks = true;
18470
18591
  }
18471
- attachPatchData(comment, lView);
18472
- const lContainer = createLContainer(comment, lView, comment, tNode);
18473
- lView[adjustedIndex] = lContainer;
18474
- addToViewTree(lView, lContainer);
18475
- // If hydration is enabled, looks up dehydrated views in the DOM
18476
- // using hydration annotation info and stores those views on LContainer.
18477
- // In client-only mode, this function is a noop.
18478
- populateDehydratedViewsInLContainer(lContainer, tNode, lView);
18479
- if (isDirectiveHost(tNode)) {
18480
- createDirectivesInstances(tView, lView, tNode);
18592
+ else {
18593
+ zone.hasPendingMicrotasks = false;
18481
18594
  }
18482
- if (localRefsIndex != null) {
18483
- saveResolvedLocalsInData(lView, tNode, localRefExtractor);
18595
+ }
18596
+ function onEnter(zone) {
18597
+ zone._nesting++;
18598
+ if (zone.isStable) {
18599
+ zone.isStable = false;
18600
+ zone.onUnstable.emit(null);
18484
18601
  }
18485
- return ɵɵtemplate;
18486
18602
  }
18487
- let _locateOrCreateContainerAnchor = createContainerAnchorImpl;
18488
- /**
18489
- * Regular creation mode for LContainers and their anchor (comment) nodes.
18490
- */
18491
- function createContainerAnchorImpl(tView, lView, tNode, index) {
18492
- lastNodeWasCreated(true);
18493
- return lView[RENDERER].createComment(ngDevMode ? 'container' : '');
18603
+ function onLeave(zone) {
18604
+ zone._nesting--;
18605
+ checkStable(zone);
18494
18606
  }
18495
18607
  /**
18496
- * Enables hydration code path (to lookup existing elements in DOM)
18497
- * in addition to the regular creation mode for LContainers and their
18498
- * anchor (comment) nodes.
18608
+ * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
18609
+ * to framework to perform rendering.
18499
18610
  */
18500
- function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
18501
- const hydrationInfo = lView[HYDRATION];
18502
- const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1() ||
18503
- isDetachedByI18n(tNode) || isDisconnectedNode$1(hydrationInfo, index);
18504
- lastNodeWasCreated(isNodeCreationMode);
18505
- // Regular creation mode.
18506
- if (isNodeCreationMode) {
18507
- return createContainerAnchorImpl(tView, lView, tNode, index);
18611
+ class NoopNgZone {
18612
+ constructor() {
18613
+ this.hasPendingMicrotasks = false;
18614
+ this.hasPendingMacrotasks = false;
18615
+ this.isStable = true;
18616
+ this.onUnstable = new EventEmitter();
18617
+ this.onMicrotaskEmpty = new EventEmitter();
18618
+ this.onStable = new EventEmitter();
18619
+ this.onError = new EventEmitter();
18508
18620
  }
18509
- const ssrId = hydrationInfo.data[TEMPLATES]?.[index] ?? null;
18510
- // Apply `ssrId` value to the underlying TView if it was not previously set.
18511
- //
18512
- // There might be situations when the same component is present in a template
18513
- // multiple times and some instances are opted-out of using hydration via
18514
- // `ngSkipHydration` attribute. In this scenario, at the time a TView is created,
18515
- // the `ssrId` might be `null` (if the first component is opted-out of hydration).
18516
- // The code below makes sure that the `ssrId` is applied to the TView if it's still
18517
- // `null` and verifies we never try to override it with a different value.
18518
- if (ssrId !== null && tNode.tView !== null) {
18519
- if (tNode.tView.ssrId === null) {
18520
- tNode.tView.ssrId = ssrId;
18521
- }
18522
- else {
18523
- ngDevMode &&
18524
- assertEqual(tNode.tView.ssrId, ssrId, 'Unexpected value of the `ssrId` for this TView');
18525
- }
18621
+ run(fn, applyThis, applyArgs) {
18622
+ return fn.apply(applyThis, applyArgs);
18526
18623
  }
18527
- // Hydration mode, looking up existing elements in DOM.
18528
- const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
18529
- ngDevMode && validateNodeExists(currentRNode, lView, tNode);
18530
- setSegmentHead(hydrationInfo, index, currentRNode);
18531
- const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
18532
- const comment = siblingAfter(viewContainerSize, currentRNode);
18533
- if (ngDevMode) {
18534
- validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
18535
- markRNodeAsClaimedByHydration(comment);
18624
+ runGuarded(fn, applyThis, applyArgs) {
18625
+ return fn.apply(applyThis, applyArgs);
18536
18626
  }
18537
- return comment;
18538
- }
18539
- function enableLocateOrCreateContainerAnchorImpl() {
18540
- _locateOrCreateContainerAnchor = locateOrCreateContainerAnchorImpl;
18541
- }
18542
-
18543
- /**
18544
- * Describes the state of defer block dependency loading.
18545
- */
18546
- var DeferDependenciesLoadingState;
18547
- (function (DeferDependenciesLoadingState) {
18548
- /** Initial state, dependency loading is not yet triggered */
18549
- DeferDependenciesLoadingState[DeferDependenciesLoadingState["NOT_STARTED"] = 0] = "NOT_STARTED";
18550
- /** Dependency loading is in progress */
18551
- DeferDependenciesLoadingState[DeferDependenciesLoadingState["IN_PROGRESS"] = 1] = "IN_PROGRESS";
18552
- /** Dependency loading has completed successfully */
18553
- DeferDependenciesLoadingState[DeferDependenciesLoadingState["COMPLETE"] = 2] = "COMPLETE";
18554
- /** Dependency loading has failed */
18555
- DeferDependenciesLoadingState[DeferDependenciesLoadingState["FAILED"] = 3] = "FAILED";
18556
- })(DeferDependenciesLoadingState || (DeferDependenciesLoadingState = {}));
18557
- /** Slot index where `minimum` parameter value is stored. */
18558
- const MINIMUM_SLOT = 0;
18559
- /** Slot index where `after` parameter value is stored. */
18560
- const LOADING_AFTER_SLOT = 1;
18561
- /**
18562
- * Describes the current state of this defer block instance.
18563
- *
18564
- * @publicApi
18565
- * @developerPreview
18566
- */
18567
- var DeferBlockState;
18568
- (function (DeferBlockState) {
18569
- /** The placeholder block content is rendered */
18570
- DeferBlockState[DeferBlockState["Placeholder"] = 0] = "Placeholder";
18571
- /** The loading block content is rendered */
18572
- DeferBlockState[DeferBlockState["Loading"] = 1] = "Loading";
18573
- /** The main content block content is rendered */
18574
- DeferBlockState[DeferBlockState["Complete"] = 2] = "Complete";
18575
- /** The error block content is rendered */
18576
- DeferBlockState[DeferBlockState["Error"] = 3] = "Error";
18577
- })(DeferBlockState || (DeferBlockState = {}));
18578
- /**
18579
- * Describes the initial state of this defer block instance.
18580
- *
18581
- * Note: this state is internal only and *must* be represented
18582
- * with a number lower than any value in the `DeferBlockState` enum.
18583
- */
18584
- var DeferBlockInternalState;
18585
- (function (DeferBlockInternalState) {
18586
- /** Initial state. Nothing is rendered yet. */
18587
- DeferBlockInternalState[DeferBlockInternalState["Initial"] = -1] = "Initial";
18588
- })(DeferBlockInternalState || (DeferBlockInternalState = {}));
18589
- const NEXT_DEFER_BLOCK_STATE = 0;
18590
- // Note: it's *important* to keep the state in this slot, because this slot
18591
- // is used by runtime logic to differentiate between LViews, LContainers and
18592
- // other types (see `isLView` and `isLContainer` functions). In case of defer
18593
- // blocks, this slot would always be a number.
18594
- const DEFER_BLOCK_STATE = 1;
18595
- const STATE_IS_FROZEN_UNTIL = 2;
18596
- const LOADING_AFTER_CLEANUP_FN = 3;
18597
- const TRIGGER_CLEANUP_FNS = 4;
18598
- const PREFETCH_TRIGGER_CLEANUP_FNS = 5;
18599
- /**
18600
- * Options for configuring defer blocks behavior.
18601
- * @publicApi
18602
- * @developerPreview
18603
- */
18604
- var DeferBlockBehavior;
18605
- (function (DeferBlockBehavior) {
18606
- /**
18607
- * Manual triggering mode for defer blocks. Provides control over when defer blocks render
18608
- * and which state they render.
18609
- */
18610
- DeferBlockBehavior[DeferBlockBehavior["Manual"] = 0] = "Manual";
18611
- /**
18612
- * Playthrough mode for defer blocks. This mode behaves like defer blocks would in a browser.
18613
- * This is the default behavior in test environments.
18614
- */
18615
- DeferBlockBehavior[DeferBlockBehavior["Playthrough"] = 1] = "Playthrough";
18616
- })(DeferBlockBehavior || (DeferBlockBehavior = {}));
18617
-
18618
- /*!
18619
- * @license
18620
- * Copyright Google LLC All Rights Reserved.
18621
- *
18622
- * Use of this source code is governed by an MIT-style license that can be
18623
- * found in the LICENSE file at https://angular.io/license
18624
- */
18625
- /**
18626
- * Registers a cleanup function associated with a prefetching trigger
18627
- * or a regular trigger of a defer block.
18628
- */
18629
- function storeTriggerCleanupFn(type, lDetails, cleanupFn) {
18630
- const key = type === 1 /* TriggerType.Prefetch */ ? PREFETCH_TRIGGER_CLEANUP_FNS : TRIGGER_CLEANUP_FNS;
18631
- if (lDetails[key] === null) {
18632
- lDetails[key] = [];
18627
+ runOutsideAngular(fn) {
18628
+ return fn();
18629
+ }
18630
+ runTask(fn, applyThis, applyArgs, name) {
18631
+ return fn.apply(applyThis, applyArgs);
18633
18632
  }
18634
- lDetails[key].push(cleanupFn);
18635
18633
  }
18636
- /**
18637
- * Invokes registered cleanup functions either for prefetch or for regular triggers.
18638
- */
18639
- function invokeTriggerCleanupFns(type, lDetails) {
18640
- const key = type === 1 /* TriggerType.Prefetch */ ? PREFETCH_TRIGGER_CLEANUP_FNS : TRIGGER_CLEANUP_FNS;
18641
- const cleanupFns = lDetails[key];
18642
- if (cleanupFns !== null) {
18643
- for (const cleanupFn of cleanupFns) {
18644
- cleanupFn();
18645
- }
18646
- lDetails[key] = null;
18634
+ function shouldBeIgnoredByZone(applyArgs) {
18635
+ if (!Array.isArray(applyArgs)) {
18636
+ return false;
18637
+ }
18638
+ // We should only ever get 1 arg passed through to invokeTask.
18639
+ // Short circuit here incase that behavior changes.
18640
+ if (applyArgs.length !== 1) {
18641
+ return false;
18647
18642
  }
18643
+ // Prevent triggering change detection when the __ignore_ng_zone__ flag is detected.
18644
+ return applyArgs[0].data?.['__ignore_ng_zone__'] === true;
18648
18645
  }
18649
- /**
18650
- * Invokes registered cleanup functions for both prefetch and regular triggers.
18651
- */
18652
- function invokeAllTriggerCleanupFns(lDetails) {
18653
- invokeTriggerCleanupFns(1 /* TriggerType.Prefetch */, lDetails);
18654
- invokeTriggerCleanupFns(0 /* TriggerType.Regular */, lDetails);
18646
+ function getNgZone(ngZoneToUse = 'zone.js', options) {
18647
+ if (ngZoneToUse === 'noop') {
18648
+ return new NoopNgZone();
18649
+ }
18650
+ if (ngZoneToUse === 'zone.js') {
18651
+ return new NgZone(options);
18652
+ }
18653
+ return ngZoneToUse;
18655
18654
  }
18656
18655
 
18657
18656
  // Public API for Zone
@@ -29853,7 +29852,7 @@ class Version {
29853
29852
  /**
29854
29853
  * @publicApi
29855
29854
  */
29856
- const VERSION = new Version('17.3.6');
29855
+ const VERSION = new Version('17.3.7');
29857
29856
 
29858
29857
  class Console {
29859
29858
  log(message) {
@@ -30714,7 +30713,10 @@ let _published = false;
30714
30713
  function publishDefaultGlobalUtils$1() {
30715
30714
  if (!_published) {
30716
30715
  _published = true;
30717
- setupFrameworkInjectorProfiler();
30716
+ if (typeof window !== 'undefined') {
30717
+ // Only configure the injector profiler when running in the browser.
30718
+ setupFrameworkInjectorProfiler();
30719
+ }
30718
30720
  for (const [methodName, method] of Object.entries(globalUtilsFunctions)) {
30719
30721
  publishGlobalUtil(methodName, method);
30720
30722
  }