@angular/core 17.0.6 → 17.0.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.
Files changed (60) hide show
  1. package/esm2022/primitives/signals/src/signal.mjs +2 -9
  2. package/esm2022/src/application/application_config.mjs +21 -0
  3. package/esm2022/src/application/application_init.mjs +188 -0
  4. package/esm2022/src/application/application_module.mjs +29 -0
  5. package/esm2022/src/application/application_ref.mjs +509 -0
  6. package/esm2022/src/application/application_tokens.mjs +121 -0
  7. package/esm2022/src/application/create_application.mjs +102 -0
  8. package/esm2022/src/change_detection/scheduling.mjs +103 -0
  9. package/esm2022/src/core.mjs +10 -7
  10. package/esm2022/src/core_private_export.mjs +5 -3
  11. package/esm2022/src/core_reactivity_export_internal.mjs +2 -2
  12. package/esm2022/src/core_render3_private_export.mjs +2 -2
  13. package/esm2022/src/error_handler.mjs +15 -1
  14. package/esm2022/src/hydration/annotate.mjs +1 -1
  15. package/esm2022/src/hydration/api.mjs +2 -2
  16. package/esm2022/src/hydration/cleanup.mjs +1 -1
  17. package/esm2022/src/image_performance_warning.mjs +2 -2
  18. package/esm2022/src/linker/query_list.mjs +8 -6
  19. package/esm2022/src/metadata/do_bootstrap.mjs +1 -1
  20. package/esm2022/src/platform/platform.mjs +135 -0
  21. package/esm2022/src/platform/platform_core_providers.mjs +15 -0
  22. package/esm2022/src/platform/platform_ref.mjs +179 -0
  23. package/esm2022/src/render3/instructions/change_detection.mjs +2 -4
  24. package/esm2022/src/render3/list_reconciliation.mjs +58 -24
  25. package/esm2022/src/render3/util/change_detection_utils.mjs +3 -1
  26. package/esm2022/src/render3/util/misc_utils.mjs +2 -2
  27. package/esm2022/src/render3/view_ref.mjs +7 -1
  28. package/esm2022/src/transfer_state.mjs +2 -2
  29. package/esm2022/src/util/performance.mjs +2 -2
  30. package/esm2022/src/version.mjs +1 -1
  31. package/esm2022/src/zone/ng_zone.mjs +10 -1
  32. package/esm2022/testing/src/component_fixture.mjs +20 -36
  33. package/esm2022/testing/src/logger.mjs +3 -3
  34. package/esm2022/testing/src/test_bed.mjs +5 -6
  35. package/fesm2022/core.mjs +1305 -1272
  36. package/fesm2022/core.mjs.map +1 -1
  37. package/fesm2022/primitives/signals.mjs +2 -9
  38. package/fesm2022/primitives/signals.mjs.map +1 -1
  39. package/fesm2022/rxjs-interop.mjs +1 -1
  40. package/fesm2022/testing.mjs +46 -64
  41. package/fesm2022/testing.mjs.map +1 -1
  42. package/index.d.ts +13 -14
  43. package/package.json +1 -1
  44. package/primitives/signals/index.d.ts +1 -1
  45. package/rxjs-interop/index.d.ts +1 -1
  46. package/schematics/migrations/block-template-entities/bundle.js +627 -476
  47. package/schematics/migrations/block-template-entities/bundle.js.map +3 -3
  48. package/schematics/migrations/compiler-options/bundle.js +13 -13
  49. package/schematics/migrations/transfer-state/bundle.js +13 -13
  50. package/schematics/ng-generate/control-flow-migration/bundle.js +783 -528
  51. package/schematics/ng-generate/control-flow-migration/bundle.js.map +3 -3
  52. package/schematics/ng-generate/standalone-migration/bundle.js +932 -758
  53. package/schematics/ng-generate/standalone-migration/bundle.js.map +3 -3
  54. package/testing/index.d.ts +6 -10
  55. package/esm2022/src/application_config.mjs +0 -21
  56. package/esm2022/src/application_init.mjs +0 -188
  57. package/esm2022/src/application_module.mjs +0 -29
  58. package/esm2022/src/application_ref.mjs +0 -997
  59. package/esm2022/src/application_tokens.mjs +0 -121
  60. package/esm2022/src/platform_core_providers.mjs +0 -15
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.6
2
+ * @license Angular v17.0.7
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -10427,7 +10427,7 @@ class Version {
10427
10427
  /**
10428
10428
  * @publicApi
10429
10429
  */
10430
- const VERSION = new Version('17.0.6');
10430
+ const VERSION = new Version('17.0.7');
10431
10431
 
10432
10432
  // This default value is when checking the hierarchy for a token.
10433
10433
  //
@@ -11762,6 +11762,19 @@ class ErrorHandler {
11762
11762
  return e || null;
11763
11763
  }
11764
11764
  }
11765
+ /**
11766
+ * `InjectionToken` used to configure how to call the `ErrorHandler`.
11767
+ *
11768
+ * `NgZone` is provided by default today so the default (and only) implementation for this
11769
+ * is calling `ErrorHandler.handleError` outside of the Angular zone.
11770
+ */
11771
+ const INTERNAL_APPLICATION_ERROR_HANDLER = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'internal error handler' : '', {
11772
+ providedIn: 'root',
11773
+ factory: () => {
11774
+ const userErrorHandler = inject(ErrorHandler);
11775
+ return userErrorHandler.handleError.bind(undefined);
11776
+ }
11777
+ });
11765
11778
 
11766
11779
  /**
11767
11780
  * Internal token that specifies whether DOM reuse logic
@@ -13306,9 +13319,6 @@ function detectChangesInternal(lView, notifyErrorHandler = true) {
13306
13319
  afterRenderEventManager?.begin();
13307
13320
  }
13308
13321
  try {
13309
- const tView = lView[TVIEW];
13310
- const context = lView[CONTEXT];
13311
- refreshView(tView, lView, tView.template, context);
13312
13322
  detectChangesInViewWhileDirty(lView);
13313
13323
  }
13314
13324
  catch (error) {
@@ -13329,6 +13339,7 @@ function detectChangesInternal(lView, notifyErrorHandler = true) {
13329
13339
  }
13330
13340
  }
13331
13341
  function detectChangesInViewWhileDirty(lView) {
13342
+ detectChangesInView(lView, 0 /* ChangeDetectionMode.Global */);
13332
13343
  let retries = 0;
13333
13344
  // If after running change detection, this view still needs to be refreshed or there are
13334
13345
  // descendants views that need to be refreshed due to re-dirtying during the change detection
@@ -13900,6 +13911,12 @@ class ViewRef$1 {
13900
13911
  * See {@link ChangeDetectorRef#detach} for more information.
13901
13912
  */
13902
13913
  detectChanges() {
13914
+ // Add `RefreshView` flag to ensure this view is refreshed if not already dirty.
13915
+ // `RefreshView` flag is used intentionally over `Dirty` because it gets cleared before
13916
+ // executing any of the actual refresh code while the `Dirty` flag doesn't get cleared
13917
+ // until the end of the refresh. Using `RefreshView` prevents creating a potential difference
13918
+ // in the state of the LViewFlags during template execution.
13919
+ this._lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
13903
13920
  detectChangesInternal(this._lView, this.notifyErrorHandler);
13904
13921
  }
13905
13922
  /**
@@ -14269,7 +14286,7 @@ function performanceMarkFeature(feature) {
14269
14286
  return;
14270
14287
  }
14271
14288
  markedFeatures.add(feature);
14272
- performance?.mark?.('mark_use_counter', { detail: { feature } });
14289
+ performance?.mark?.('mark_feature_usage', { detail: { feature } });
14273
14290
  }
14274
14291
 
14275
14292
  /// <reference types="rxjs" />
@@ -14840,6 +14857,15 @@ function shouldBeIgnoredByZone(applyArgs) {
14840
14857
  // Prevent triggering change detection when the __ignore_ng_zone__ flag is detected.
14841
14858
  return applyArgs[0].data?.['__ignore_ng_zone__'] === true;
14842
14859
  }
14860
+ function getNgZone(ngZoneToUse = 'zone.js', options) {
14861
+ if (ngZoneToUse === 'noop') {
14862
+ return new NoopNgZone();
14863
+ }
14864
+ if (ngZoneToUse === 'zone.js') {
14865
+ return new NgZone(options);
14866
+ }
14867
+ return ngZoneToUse;
14868
+ }
14843
14869
 
14844
14870
  // Public API for Zone
14845
14871
 
@@ -19586,7 +19612,7 @@ function reconcile(liveCollection, newCollection, trackByFn) {
19586
19612
  }
19587
19613
  // Fallback to the slow path: we need to learn more about the content of the live and new
19588
19614
  // collections.
19589
- detachedItems ??= new MultiMap();
19615
+ detachedItems ??= new UniqueValueMultiKeyMap();
19590
19616
  liveKeysInTheFuture ??=
19591
19617
  initLiveItemsInTheFuture(liveCollection, liveStartIdx, liveEndIdx, trackByFn);
19592
19618
  // Check if I'm inserting a previously detached item: if so, attach it here
@@ -19634,7 +19660,7 @@ function reconcile(liveCollection, newCollection, trackByFn) {
19634
19660
  newIterationResult = newCollectionIterator.next();
19635
19661
  }
19636
19662
  else {
19637
- detachedItems ??= new MultiMap();
19663
+ detachedItems ??= new UniqueValueMultiKeyMap();
19638
19664
  liveKeysInTheFuture ??=
19639
19665
  initLiveItemsInTheFuture(liveCollection, liveStartIdx, liveEndIdx, trackByFn);
19640
19666
  // Check if I'm inserting a previously detached item: if so, attach it here
@@ -19700,40 +19726,73 @@ function initLiveItemsInTheFuture(liveCollection, start, end, trackByFn) {
19700
19726
  }
19701
19727
  return keys;
19702
19728
  }
19703
- class MultiMap {
19729
+ /**
19730
+ * A specific, partial implementation of the Map interface with the following characteristics:
19731
+ * - allows multiple values for a given key;
19732
+ * - maintain FIFO order for multiple values corresponding to a given key;
19733
+ * - assumes that all values are unique.
19734
+ *
19735
+ * The implementation aims at having the minimal overhead for cases where keys are _not_ duplicated
19736
+ * (the most common case in the list reconciliation algorithm). To achieve this, the first value for
19737
+ * a given key is stored in a regular map. Then, when more values are set for a given key, we
19738
+ * maintain a form of linked list in a separate map. To maintain this linked list we assume that all
19739
+ * values (in the entire collection) are unique.
19740
+ */
19741
+ class UniqueValueMultiKeyMap {
19704
19742
  constructor() {
19705
- this.map = new Map();
19743
+ // A map from a key to the first value corresponding to this key.
19744
+ this.kvMap = new Map();
19745
+ // A map that acts as a linked list of values - each value maps to the next value in this "linked
19746
+ // list" (this only works if values are unique). Allocated lazily to avoid memory consumption when
19747
+ // there are no duplicated values.
19748
+ this._vMap = undefined;
19706
19749
  }
19707
19750
  has(key) {
19708
- const listOfKeys = this.map.get(key);
19709
- return listOfKeys !== undefined && listOfKeys.length > 0;
19751
+ return this.kvMap.has(key);
19710
19752
  }
19711
19753
  delete(key) {
19712
- const listOfKeys = this.map.get(key);
19713
- if (listOfKeys !== undefined) {
19714
- listOfKeys.shift();
19715
- return true;
19754
+ if (!this.has(key))
19755
+ return false;
19756
+ const value = this.kvMap.get(key);
19757
+ if (this._vMap !== undefined && this._vMap.has(value)) {
19758
+ this.kvMap.set(key, this._vMap.get(value));
19759
+ this._vMap.delete(value);
19716
19760
  }
19717
- return false;
19761
+ else {
19762
+ this.kvMap.delete(key);
19763
+ }
19764
+ return true;
19718
19765
  }
19719
19766
  get(key) {
19720
- const listOfKeys = this.map.get(key);
19721
- return listOfKeys !== undefined && listOfKeys.length > 0 ? listOfKeys[0] : undefined;
19767
+ return this.kvMap.get(key);
19722
19768
  }
19723
19769
  set(key, value) {
19724
- // if value is array, they we always store it as [value].
19725
- if (!this.map.has(key)) {
19726
- this.map.set(key, [value]);
19727
- return;
19770
+ if (this.kvMap.has(key)) {
19771
+ let prevValue = this.kvMap.get(key);
19772
+ ngDevMode &&
19773
+ assertNotSame(prevValue, value, `Detected a duplicated value ${value} for the key ${key}`);
19774
+ if (this._vMap === undefined) {
19775
+ this._vMap = new Map();
19776
+ }
19777
+ const vMap = this._vMap;
19778
+ while (vMap.has(prevValue)) {
19779
+ prevValue = vMap.get(prevValue);
19780
+ }
19781
+ vMap.set(prevValue, value);
19782
+ }
19783
+ else {
19784
+ this.kvMap.set(key, value);
19728
19785
  }
19729
- // THINK: this allows duplicate values, but I guess this is fine?
19730
- // Is the existing key an array or not?
19731
- this.map.get(key)?.push(value);
19732
19786
  }
19733
19787
  forEach(cb) {
19734
- for (const [key, values] of this.map) {
19735
- for (const value of values) {
19736
- cb(value, key);
19788
+ for (let [key, value] of this.kvMap) {
19789
+ cb(value, key);
19790
+ if (this._vMap !== undefined) {
19791
+ const vMap = this._vMap;
19792
+ while (vMap.has(value)) {
19793
+ value = vMap.get(value);
19794
+ cb(value, key);
19795
+ }
19737
19796
  }
19738
19797
  }
19739
19798
  }
@@ -27875,7 +27934,7 @@ class QueryList {
27875
27934
  * Returns `Observable` of `QueryList` notifying the subscriber of changes.
27876
27935
  */
27877
27936
  get changes() {
27878
- return this._changes || (this._changes = new EventEmitter());
27937
+ return this._changes ??= new EventEmitter();
27879
27938
  }
27880
27939
  /**
27881
27940
  * @param emitDistinctChangesOnly Whether `QueryList.changes` should fire only when actual change
@@ -27887,7 +27946,7 @@ class QueryList {
27887
27946
  this.dirty = true;
27888
27947
  this._results = [];
27889
27948
  this._changesDetected = false;
27890
- this._changes = null;
27949
+ this._changes = undefined;
27891
27950
  this.length = 0;
27892
27951
  this.first = undefined;
27893
27952
  this.last = undefined;
@@ -27978,7 +28037,7 @@ class QueryList {
27978
28037
  * Triggers a change event by emitting on the `changes` {@link EventEmitter}.
27979
28038
  */
27980
28039
  notifyOnChanges() {
27981
- if (this._changes && (this._changesDetected || !this._emitDistinctChangesOnly))
28040
+ if (this._changes !== undefined && (this._changesDetected || !this._emitDistinctChangesOnly))
27982
28041
  this._changes.emit(this);
27983
28042
  }
27984
28043
  /** internal */
@@ -27987,8 +28046,10 @@ class QueryList {
27987
28046
  }
27988
28047
  /** internal */
27989
28048
  destroy() {
27990
- this.changes.complete();
27991
- this.changes.unsubscribe();
28049
+ if (this._changes !== undefined) {
28050
+ this._changes.complete();
28051
+ this._changes.unsubscribe();
28052
+ }
27992
28053
  }
27993
28054
  }
27994
28055
 
@@ -29928,190 +29989,6 @@ const NgModule = makeDecorator('NgModule', (ngModule) => ngModule, undefined, un
29928
29989
  */
29929
29990
  const ITS_JUST_ANGULAR = true;
29930
29991
 
29931
- /**
29932
- * A [DI token](guide/glossary#di-token "DI token definition") that you can use to provide
29933
- * one or more initialization functions.
29934
- *
29935
- * The provided functions are injected at application startup and executed during
29936
- * app initialization. If any of these functions returns a Promise or an Observable, initialization
29937
- * does not complete until the Promise is resolved or the Observable is completed.
29938
- *
29939
- * You can, for example, create a factory function that loads language data
29940
- * or an external configuration, and provide that function to the `APP_INITIALIZER` token.
29941
- * The function is executed during the application bootstrap process,
29942
- * and the needed data is available on startup.
29943
- *
29944
- * @see {@link ApplicationInitStatus}
29945
- *
29946
- * @usageNotes
29947
- *
29948
- * The following example illustrates how to configure a multi-provider using `APP_INITIALIZER` token
29949
- * and a function returning a promise.
29950
- * ### Example with NgModule-based application
29951
- * ```
29952
- * function initializeApp(): Promise<any> {
29953
- * return new Promise((resolve, reject) => {
29954
- * // Do some asynchronous stuff
29955
- * resolve();
29956
- * });
29957
- * }
29958
- *
29959
- * @NgModule({
29960
- * imports: [BrowserModule],
29961
- * declarations: [AppComponent],
29962
- * bootstrap: [AppComponent],
29963
- * providers: [{
29964
- * provide: APP_INITIALIZER,
29965
- * useFactory: () => initializeApp,
29966
- * multi: true
29967
- * }]
29968
- * })
29969
- * export class AppModule {}
29970
- * ```
29971
- *
29972
- * ### Example with standalone application
29973
- * ```
29974
- * export function initializeApp(http: HttpClient) {
29975
- * return (): Promise<any> =>
29976
- * firstValueFrom(
29977
- * http
29978
- * .get("https://someUrl.com/api/user")
29979
- * .pipe(tap(user => { ... }))
29980
- * );
29981
- * }
29982
- *
29983
- * bootstrapApplication(App, {
29984
- * providers: [
29985
- * provideHttpClient(),
29986
- * {
29987
- * provide: APP_INITIALIZER,
29988
- * useFactory: initializeApp,
29989
- * multi: true,
29990
- * deps: [HttpClient],
29991
- * },
29992
- * ],
29993
- * });
29994
-
29995
- * ```
29996
- *
29997
- *
29998
- * It's also possible to configure a multi-provider using `APP_INITIALIZER` token and a function
29999
- * returning an observable, see an example below. Note: the `HttpClient` in this example is used for
30000
- * demo purposes to illustrate how the factory function can work with other providers available
30001
- * through DI.
30002
- *
30003
- * ### Example with NgModule-based application
30004
- * ```
30005
- * function initializeAppFactory(httpClient: HttpClient): () => Observable<any> {
30006
- * return () => httpClient.get("https://someUrl.com/api/user")
30007
- * .pipe(
30008
- * tap(user => { ... })
30009
- * );
30010
- * }
30011
- *
30012
- * @NgModule({
30013
- * imports: [BrowserModule, HttpClientModule],
30014
- * declarations: [AppComponent],
30015
- * bootstrap: [AppComponent],
30016
- * providers: [{
30017
- * provide: APP_INITIALIZER,
30018
- * useFactory: initializeAppFactory,
30019
- * deps: [HttpClient],
30020
- * multi: true
30021
- * }]
30022
- * })
30023
- * export class AppModule {}
30024
- * ```
30025
- *
30026
- * ### Example with standalone application
30027
- * ```
30028
- * function initializeAppFactory(httpClient: HttpClient): () => Observable<any> {
30029
- * return () => httpClient.get("https://someUrl.com/api/user")
30030
- * .pipe(
30031
- * tap(user => { ... })
30032
- * );
30033
- * }
30034
- *
30035
- * bootstrapApplication(App, {
30036
- * providers: [
30037
- * provideHttpClient(),
30038
- * {
30039
- * provide: APP_INITIALIZER,
30040
- * useFactory: initializeAppFactory,
30041
- * multi: true,
30042
- * deps: [HttpClient],
30043
- * },
30044
- * ],
30045
- * });
30046
- * ```
30047
- *
30048
- * @publicApi
30049
- */
30050
- const APP_INITIALIZER = new InjectionToken('Application Initializer');
30051
- /**
30052
- * A class that reflects the state of running {@link APP_INITIALIZER} functions.
30053
- *
30054
- * @publicApi
30055
- */
30056
- class ApplicationInitStatus {
30057
- constructor() {
30058
- this.initialized = false;
30059
- this.done = false;
30060
- this.donePromise = new Promise((res, rej) => {
30061
- this.resolve = res;
30062
- this.reject = rej;
30063
- });
30064
- this.appInits = inject(APP_INITIALIZER, { optional: true }) ?? [];
30065
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && !Array.isArray(this.appInits)) {
30066
- throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `APP_INITIALIZER` token value ' +
30067
- `(expected an array, but got ${typeof this.appInits}). ` +
30068
- 'Please check that the `APP_INITIALIZER` token is configured as a ' +
30069
- '`multi: true` provider.');
30070
- }
30071
- }
30072
- /** @internal */
30073
- runInitializers() {
30074
- if (this.initialized) {
30075
- return;
30076
- }
30077
- const asyncInitPromises = [];
30078
- for (const appInits of this.appInits) {
30079
- const initResult = appInits();
30080
- if (isPromise(initResult)) {
30081
- asyncInitPromises.push(initResult);
30082
- }
30083
- else if (isSubscribable(initResult)) {
30084
- const observableAsPromise = new Promise((resolve, reject) => {
30085
- initResult.subscribe({ complete: resolve, error: reject });
30086
- });
30087
- asyncInitPromises.push(observableAsPromise);
30088
- }
30089
- }
30090
- const complete = () => {
30091
- // @ts-expect-error overwriting a readonly
30092
- this.done = true;
30093
- this.resolve();
30094
- };
30095
- Promise.all(asyncInitPromises)
30096
- .then(() => {
30097
- complete();
30098
- })
30099
- .catch(e => {
30100
- this.reject(e);
30101
- });
30102
- if (asyncInitPromises.length === 0) {
30103
- complete();
30104
- }
30105
- this.initialized = true;
30106
- }
30107
- static { this.ɵfac = function ApplicationInitStatus_Factory(t) { return new (t || ApplicationInitStatus)(); }; }
30108
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationInitStatus, factory: ApplicationInitStatus.ɵfac, providedIn: 'root' }); }
30109
- }
30110
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
30111
- type: Injectable,
30112
- args: [{ providedIn: 'root' }]
30113
- }], () => [], null); })();
30114
-
30115
29992
  class Console {
30116
29993
  log(message) {
30117
29994
  // tslint:disable-next-line:no-console
@@ -30131,566 +30008,237 @@ class Console {
30131
30008
  }], null, null); })();
30132
30009
 
30133
30010
  /**
30134
- * Work out the locale from the potential global properties.
30011
+ * *Internal* service that keeps track of pending tasks happening in the system
30012
+ * during the initial rendering. No tasks are tracked after an initial
30013
+ * rendering.
30135
30014
  *
30136
- * * Closure Compiler: use `goog.LOCALE`.
30137
- * * Ivy enabled: use `$localize.locale`
30015
+ * This information is needed to make sure that the serialization on the server
30016
+ * is delayed until all tasks in the queue (such as an initial navigation or a
30017
+ * pending HTTP request) are completed.
30138
30018
  */
30139
- function getGlobalLocale() {
30140
- if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
30141
- typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
30142
- // * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
30143
- // * In order to preserve backwards compatibility, we use Angular default value over
30144
- // Closure Compiler's one.
30145
- return goog.LOCALE;
30019
+ class InitialRenderPendingTasks {
30020
+ constructor() {
30021
+ this.taskId = 0;
30022
+ this.pendingTasks = new Set();
30023
+ this.hasPendingTasks = new BehaviorSubject(false);
30146
30024
  }
30147
- else {
30148
- // KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
30149
- // COMPILE-TIME INLINER.
30150
- //
30151
- // * During compile time inlining of translations the expression will be replaced
30152
- // with a string literal that is the current locale. Other forms of this expression are not
30153
- // guaranteed to be replaced.
30154
- //
30155
- // * During runtime translation evaluation, the developer is required to set `$localize.locale`
30156
- // if required, or just to provide their own `LOCALE_ID` provider.
30157
- return (typeof $localize !== 'undefined' && $localize.locale) || DEFAULT_LOCALE_ID;
30025
+ add() {
30026
+ this.hasPendingTasks.next(true);
30027
+ const taskId = this.taskId++;
30028
+ this.pendingTasks.add(taskId);
30029
+ return taskId;
30030
+ }
30031
+ remove(taskId) {
30032
+ this.pendingTasks.delete(taskId);
30033
+ if (this.pendingTasks.size === 0) {
30034
+ this.hasPendingTasks.next(false);
30035
+ }
30036
+ }
30037
+ ngOnDestroy() {
30038
+ this.pendingTasks.clear();
30039
+ this.hasPendingTasks.next(false);
30158
30040
  }
30041
+ static { this.ɵfac = function InitialRenderPendingTasks_Factory(t) { return new (t || InitialRenderPendingTasks)(); }; }
30042
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: InitialRenderPendingTasks, factory: InitialRenderPendingTasks.ɵfac, providedIn: 'root' }); }
30159
30043
  }
30044
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(InitialRenderPendingTasks, [{
30045
+ type: Injectable,
30046
+ args: [{ providedIn: 'root' }]
30047
+ }], null, null); })();
30048
+
30160
30049
  /**
30161
- * Provide this token to set the locale of your application.
30162
- * It is used for i18n extraction, by i18n pipes (DatePipe, I18nPluralPipe, CurrencyPipe,
30163
- * DecimalPipe and PercentPipe) and by ICU expressions.
30164
- *
30165
- * See the [i18n guide](guide/i18n-common-locale-id) for more information.
30050
+ * Combination of NgModuleFactory and ComponentFactories.
30166
30051
  *
30167
- * @usageNotes
30168
- * ### Example
30052
+ * @publicApi
30169
30053
  *
30170
- * ```typescript
30171
- * import { LOCALE_ID } from '@angular/core';
30172
- * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
30173
- * import { AppModule } from './app/app.module';
30054
+ * @deprecated
30055
+ * Ivy JIT mode doesn't require accessing this symbol.
30056
+ * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
30057
+ * additional context.
30058
+ */
30059
+ class ModuleWithComponentFactories {
30060
+ constructor(ngModuleFactory, componentFactories) {
30061
+ this.ngModuleFactory = ngModuleFactory;
30062
+ this.componentFactories = componentFactories;
30063
+ }
30064
+ }
30065
+ /**
30066
+ * Low-level service for running the angular compiler during runtime
30067
+ * to create {@link ComponentFactory}s, which
30068
+ * can later be used to create and render a Component instance.
30174
30069
  *
30175
- * platformBrowserDynamic().bootstrapModule(AppModule, {
30176
- * providers: [{provide: LOCALE_ID, useValue: 'en-US' }]
30177
- * });
30178
- * ```
30070
+ * Each `@NgModule` provides an own `Compiler` to its injector,
30071
+ * that will use the directives/pipes of the ng module for compilation
30072
+ * of components.
30179
30073
  *
30180
30074
  * @publicApi
30075
+ *
30076
+ * @deprecated
30077
+ * Ivy JIT mode doesn't require accessing this symbol.
30078
+ * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
30079
+ * additional context.
30181
30080
  */
30182
- const LOCALE_ID = new InjectionToken('LocaleId', {
30183
- providedIn: 'root',
30184
- factory: () => inject(LOCALE_ID, InjectFlags.Optional | InjectFlags.SkipSelf) || getGlobalLocale(),
30185
- });
30081
+ class Compiler {
30082
+ /**
30083
+ * Compiles the given NgModule and all of its components. All templates of the components
30084
+ * have to be inlined.
30085
+ */
30086
+ compileModuleSync(moduleType) {
30087
+ return new NgModuleFactory(moduleType);
30088
+ }
30089
+ /**
30090
+ * Compiles the given NgModule and all of its components
30091
+ */
30092
+ compileModuleAsync(moduleType) {
30093
+ return Promise.resolve(this.compileModuleSync(moduleType));
30094
+ }
30095
+ /**
30096
+ * Same as {@link #compileModuleSync} but also creates ComponentFactories for all components.
30097
+ */
30098
+ compileModuleAndAllComponentsSync(moduleType) {
30099
+ const ngModuleFactory = this.compileModuleSync(moduleType);
30100
+ const moduleDef = getNgModuleDef(moduleType);
30101
+ const componentFactories = maybeUnwrapFn(moduleDef.declarations)
30102
+ .reduce((factories, declaration) => {
30103
+ const componentDef = getComponentDef(declaration);
30104
+ componentDef && factories.push(new ComponentFactory(componentDef));
30105
+ return factories;
30106
+ }, []);
30107
+ return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
30108
+ }
30109
+ /**
30110
+ * Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components.
30111
+ */
30112
+ compileModuleAndAllComponentsAsync(moduleType) {
30113
+ return Promise.resolve(this.compileModuleAndAllComponentsSync(moduleType));
30114
+ }
30115
+ /**
30116
+ * Clears all caches.
30117
+ */
30118
+ clearCache() { }
30119
+ /**
30120
+ * Clears the cache for the given component/ngModule.
30121
+ */
30122
+ clearCacheFor(type) { }
30123
+ /**
30124
+ * Returns the id for a given NgModule, if one is defined and known to the compiler.
30125
+ */
30126
+ getModuleId(moduleType) {
30127
+ return undefined;
30128
+ }
30129
+ static { this.ɵfac = function Compiler_Factory(t) { return new (t || Compiler)(); }; }
30130
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Compiler, factory: Compiler.ɵfac, providedIn: 'root' }); }
30131
+ }
30132
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Compiler, [{
30133
+ type: Injectable,
30134
+ args: [{ providedIn: 'root' }]
30135
+ }], null, null); })();
30186
30136
  /**
30187
- * Provide this token to set the default currency code your application uses for
30188
- * CurrencyPipe when there is no currency code passed into it. This is only used by
30189
- * CurrencyPipe and has no relation to locale currency. Defaults to USD if not configured.
30190
- *
30191
- * See the [i18n guide](guide/i18n-common-locale-id) for more information.
30192
- *
30193
- * <div class="alert is-helpful">
30137
+ * Token to provide CompilerOptions in the platform injector.
30194
30138
  *
30195
- * **Deprecation notice:**
30139
+ * @publicApi
30140
+ */
30141
+ const COMPILER_OPTIONS = new InjectionToken('compilerOptions');
30142
+ /**
30143
+ * A factory for creating a Compiler
30196
30144
  *
30197
- * The default currency code is currently always `USD` but this is deprecated from v9.
30145
+ * @publicApi
30198
30146
  *
30199
- * **In v10 the default currency code will be taken from the current locale.**
30147
+ * @deprecated
30148
+ * Ivy JIT mode doesn't require accessing this symbol.
30149
+ * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
30150
+ * additional context.
30151
+ */
30152
+ class CompilerFactory {
30153
+ }
30154
+
30155
+ /**
30156
+ * These are the data structures that our framework injector profiler will fill with data in order
30157
+ * to support DI debugging APIs.
30200
30158
  *
30201
- * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in
30202
- * your application `NgModule`:
30159
+ * resolverToTokenToDependencies: Maps an injector to a Map of tokens to an Array of
30160
+ * dependencies. Injector -> Token -> Dependencies This is used to support the
30161
+ * getDependenciesFromInjectable API, which takes in an injector and a token and returns it's
30162
+ * dependencies.
30203
30163
  *
30204
- * ```ts
30205
- * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
30206
- * ```
30164
+ * resolverToProviders: Maps a DI resolver (an Injector or a TNode) to the providers configured
30165
+ * within it This is used to support the getInjectorProviders API, which takes in an injector and
30166
+ * returns the providers that it was configured with. Note that for the element injector case we
30167
+ * use the TNode instead of the LView as the DI resolver. This is because the registration of
30168
+ * providers happens only once per type of TNode. If an injector is created with an identical TNode,
30169
+ * the providers for that injector will not be reconfigured.
30207
30170
  *
30208
- * </div>
30171
+ * standaloneInjectorToComponent: Maps the injector of a standalone component to the standalone
30172
+ * component that it is associated with. Used in the getInjectorProviders API, specificially in the
30173
+ * discovery of import paths for each provider. This is necessary because the imports array of a
30174
+ * standalone component is processed and configured in its standalone injector, but exists within
30175
+ * the component's definition. Because getInjectorProviders takes in an injector, if that injector
30176
+ * is the injector of a standalone component, we need to be able to discover the place where the
30177
+ * imports array is located (the component) in order to flatten the imports array within it to
30178
+ * discover all of it's providers.
30209
30179
  *
30210
- * @usageNotes
30211
- * ### Example
30212
30180
  *
30213
- * ```typescript
30214
- * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
30215
- * import { AppModule } from './app/app.module';
30181
+ * All of these data structures are instantiated with WeakMaps. This will ensure that the presence
30182
+ * of any object in the keys of these maps does not prevent the garbage collector from collecting
30183
+ * those objects. Because of this property of WeakMaps, these data structures will never be the
30184
+ * source of a memory leak.
30216
30185
  *
30217
- * platformBrowserDynamic().bootstrapModule(AppModule, {
30218
- * providers: [{provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' }]
30219
- * });
30220
- * ```
30186
+ * An example of this advantage: When components are destroyed, we don't need to do
30187
+ * any additional work to remove that component from our mappings.
30221
30188
  *
30222
- * @publicApi
30223
30189
  */
30224
- const DEFAULT_CURRENCY_CODE = new InjectionToken('DefaultCurrencyCode', {
30225
- providedIn: 'root',
30226
- factory: () => USD_CURRENCY_CODE,
30227
- });
30190
+ class DIDebugData {
30191
+ constructor() {
30192
+ this.resolverToTokenToDependencies = new WeakMap();
30193
+ this.resolverToProviders = new WeakMap();
30194
+ this.standaloneInjectorToComponent = new WeakMap();
30195
+ }
30196
+ reset() {
30197
+ this.resolverToTokenToDependencies =
30198
+ new WeakMap();
30199
+ this.resolverToProviders = new WeakMap();
30200
+ this.standaloneInjectorToComponent = new WeakMap();
30201
+ }
30202
+ }
30203
+ let frameworkDIDebugData = new DIDebugData();
30204
+ function getFrameworkDIDebugData() {
30205
+ return frameworkDIDebugData;
30206
+ }
30228
30207
  /**
30229
- * Use this token at bootstrap to provide the content of your translation file (`xtb`,
30230
- * `xlf` or `xlf2`) when you want to translate your application in another language.
30208
+ * Initalize default handling of injector events. This handling parses events
30209
+ * as they are emitted and constructs the data structures necessary to support
30210
+ * some of debug APIs.
30231
30211
  *
30232
- * See the [i18n guide](guide/i18n-common-merge) for more information.
30212
+ * See handleInjectEvent, handleCreateEvent and handleProviderConfiguredEvent
30213
+ * for descriptions of each handler
30233
30214
  *
30234
- * @usageNotes
30235
- * ### Example
30215
+ * Supported APIs:
30216
+ * - getDependenciesFromInjectable
30217
+ * - getInjectorProviders
30218
+ */
30219
+ function setupFrameworkInjectorProfiler() {
30220
+ frameworkDIDebugData.reset();
30221
+ setInjectorProfiler((injectorProfilerEvent) => handleInjectorProfilerEvent(injectorProfilerEvent));
30222
+ }
30223
+ function handleInjectorProfilerEvent(injectorProfilerEvent) {
30224
+ const { context, type } = injectorProfilerEvent;
30225
+ if (type === 0 /* InjectorProfilerEventType.Inject */) {
30226
+ handleInjectEvent(context, injectorProfilerEvent.service);
30227
+ }
30228
+ else if (type === 1 /* InjectorProfilerEventType.InstanceCreatedByInjector */) {
30229
+ handleInstanceCreatedByInjectorEvent(context, injectorProfilerEvent.instance);
30230
+ }
30231
+ else if (type === 2 /* InjectorProfilerEventType.ProviderConfigured */) {
30232
+ handleProviderConfiguredEvent(context, injectorProfilerEvent.providerRecord);
30233
+ }
30234
+ }
30235
+ /**
30236
30236
  *
30237
- * ```typescript
30238
- * import { TRANSLATIONS } from '@angular/core';
30239
- * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
30240
- * import { AppModule } from './app/app.module';
30237
+ * Stores the injected service in frameworkDIDebugData.resolverToTokenToDependencies
30238
+ * based on it's injector and token.
30241
30239
  *
30242
- * // content of your translation file
30243
- * const translations = '....';
30244
- *
30245
- * platformBrowserDynamic().bootstrapModule(AppModule, {
30246
- * providers: [{provide: TRANSLATIONS, useValue: translations }]
30247
- * });
30248
- * ```
30249
- *
30250
- * @publicApi
30251
- */
30252
- const TRANSLATIONS = new InjectionToken('Translations');
30253
- /**
30254
- * Provide this token at bootstrap to set the format of your {@link TRANSLATIONS}: `xtb`,
30255
- * `xlf` or `xlf2`.
30256
- *
30257
- * See the [i18n guide](guide/i18n-common-merge) for more information.
30258
- *
30259
- * @usageNotes
30260
- * ### Example
30261
- *
30262
- * ```typescript
30263
- * import { TRANSLATIONS_FORMAT } from '@angular/core';
30264
- * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
30265
- * import { AppModule } from './app/app.module';
30266
- *
30267
- * platformBrowserDynamic().bootstrapModule(AppModule, {
30268
- * providers: [{provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }]
30269
- * });
30270
- * ```
30271
- *
30272
- * @publicApi
30273
- */
30274
- const TRANSLATIONS_FORMAT = new InjectionToken('TranslationsFormat');
30275
- /**
30276
- * Use this enum at bootstrap as an option of `bootstrapModule` to define the strategy
30277
- * that the compiler should use in case of missing translations:
30278
- * - Error: throw if you have missing translations.
30279
- * - Warning (default): show a warning in the console and/or shell.
30280
- * - Ignore: do nothing.
30281
- *
30282
- * See the [i18n guide](guide/i18n-common-merge#report-missing-translations) for more information.
30283
- *
30284
- * @usageNotes
30285
- * ### Example
30286
- * ```typescript
30287
- * import { MissingTranslationStrategy } from '@angular/core';
30288
- * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
30289
- * import { AppModule } from './app/app.module';
30290
- *
30291
- * platformBrowserDynamic().bootstrapModule(AppModule, {
30292
- * missingTranslation: MissingTranslationStrategy.Error
30293
- * });
30294
- * ```
30295
- *
30296
- * @publicApi
30297
- */
30298
- var MissingTranslationStrategy;
30299
- (function (MissingTranslationStrategy) {
30300
- MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
30301
- MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
30302
- MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
30303
- })(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
30304
-
30305
- // A delay in milliseconds before the scan is run after onLoad, to avoid any
30306
- // potential race conditions with other LCP-related functions. This delay
30307
- // happens outside of the main JavaScript execution and will only effect the timing
30308
- // on when the warning becomes visible in the console.
30309
- const SCAN_DELAY = 200;
30310
- const OVERSIZED_IMAGE_TOLERANCE = 1200;
30311
- class ImagePerformanceWarning {
30312
- constructor() {
30313
- // Map of full image URLs -> original `ngSrc` values.
30314
- this.window = null;
30315
- this.observer = null;
30316
- this.options = inject(IMAGE_CONFIG);
30317
- this.ngZone = inject(NgZone);
30318
- }
30319
- start() {
30320
- if (typeof PerformanceObserver === 'undefined' ||
30321
- (this.options?.disableImageSizeWarning && this.options?.disableImageLazyLoadWarning)) {
30322
- return;
30323
- }
30324
- this.observer = this.initPerformanceObserver();
30325
- const doc = getDocument();
30326
- const win = doc.defaultView;
30327
- if (typeof win !== 'undefined') {
30328
- this.window = win;
30329
- // Wait to avoid race conditions where LCP image triggers
30330
- // load event before it's recorded by the performance observer
30331
- const waitToScan = () => {
30332
- setTimeout(this.scanImages.bind(this), SCAN_DELAY);
30333
- };
30334
- // Angular doesn't have to run change detection whenever any asynchronous tasks are invoked in
30335
- // the scope of this functionality.
30336
- this.ngZone.runOutsideAngular(() => {
30337
- // Consider the case when the application is created and destroyed multiple times.
30338
- // Typically, applications are created instantly once the page is loaded, and the
30339
- // `window.load` listener is always triggered. However, the `window.load` event will never
30340
- // be fired if the page is loaded, and the application is created later. Checking for
30341
- // `readyState` is the easiest way to determine whether the page has been loaded or not.
30342
- if (doc.readyState === 'complete') {
30343
- waitToScan();
30344
- }
30345
- else {
30346
- this.window?.addEventListener('load', waitToScan, { once: true });
30347
- }
30348
- });
30349
- }
30350
- }
30351
- ngOnDestroy() {
30352
- this.observer?.disconnect();
30353
- }
30354
- initPerformanceObserver() {
30355
- if (typeof PerformanceObserver === 'undefined') {
30356
- return null;
30357
- }
30358
- const observer = new PerformanceObserver((entryList) => {
30359
- const entries = entryList.getEntries();
30360
- if (entries.length === 0)
30361
- return;
30362
- // We use the latest entry produced by the `PerformanceObserver` as the best
30363
- // signal on which element is actually an LCP one. As an example, the first image to load on
30364
- // a page, by virtue of being the only thing on the page so far, is often a LCP candidate
30365
- // and gets reported by PerformanceObserver, but isn't necessarily the LCP element.
30366
- const lcpElement = entries[entries.length - 1];
30367
- // Cast to `any` due to missing `element` on the `LargestContentfulPaint` type of entry.
30368
- // See https://developer.mozilla.org/en-US/docs/Web/API/LargestContentfulPaint
30369
- const imgSrc = lcpElement.element?.src ?? '';
30370
- // Exclude `data:` and `blob:` URLs, since they are fetched resources.
30371
- if (imgSrc.startsWith('data:') || imgSrc.startsWith('blob:'))
30372
- return;
30373
- this.lcpImageUrl = imgSrc;
30374
- });
30375
- observer.observe({ type: 'largest-contentful-paint', buffered: true });
30376
- return observer;
30377
- }
30378
- scanImages() {
30379
- const images = getDocument().querySelectorAll('img');
30380
- let lcpElementFound, lcpElementLoadedCorrectly = false;
30381
- images.forEach(image => {
30382
- if (!this.options?.disableImageSizeWarning) {
30383
- for (const image of images) {
30384
- // Image elements using the NgOptimizedImage directive are excluded,
30385
- // as that directive has its own version of this check.
30386
- if (!image.getAttribute('ng-img') && this.isOversized(image)) {
30387
- logOversizedImageWarning(image.src);
30388
- }
30389
- }
30390
- }
30391
- if (!this.options?.disableImageLazyLoadWarning && this.lcpImageUrl) {
30392
- if (image.src === this.lcpImageUrl) {
30393
- lcpElementFound = true;
30394
- if (image.loading !== 'lazy' || image.getAttribute('ng-img')) {
30395
- // This variable is set to true and never goes back to false to account
30396
- // for the case where multiple images have the same src url, and some
30397
- // have lazy loading while others don't.
30398
- // Also ignore NgOptimizedImage because there's a different warning for that.
30399
- lcpElementLoadedCorrectly = true;
30400
- }
30401
- }
30402
- }
30403
- });
30404
- if (lcpElementFound && !lcpElementLoadedCorrectly && this.lcpImageUrl &&
30405
- !this.options?.disableImageLazyLoadWarning) {
30406
- logLazyLCPWarning(this.lcpImageUrl);
30407
- }
30408
- }
30409
- isOversized(image) {
30410
- if (!this.window) {
30411
- return false;
30412
- }
30413
- const computedStyle = this.window.getComputedStyle(image);
30414
- let renderedWidth = parseFloat(computedStyle.getPropertyValue('width'));
30415
- let renderedHeight = parseFloat(computedStyle.getPropertyValue('height'));
30416
- const boxSizing = computedStyle.getPropertyValue('box-sizing');
30417
- const objectFit = computedStyle.getPropertyValue('object-fit');
30418
- if (objectFit === `cover`) {
30419
- // Object fit cover may indicate a use case such as a sprite sheet where
30420
- // this warning does not apply.
30421
- return false;
30422
- }
30423
- if (boxSizing === 'border-box') {
30424
- const paddingTop = computedStyle.getPropertyValue('padding-top');
30425
- const paddingRight = computedStyle.getPropertyValue('padding-right');
30426
- const paddingBottom = computedStyle.getPropertyValue('padding-bottom');
30427
- const paddingLeft = computedStyle.getPropertyValue('padding-left');
30428
- renderedWidth -= parseFloat(paddingRight) + parseFloat(paddingLeft);
30429
- renderedHeight -= parseFloat(paddingTop) + parseFloat(paddingBottom);
30430
- }
30431
- const intrinsicWidth = image.naturalWidth;
30432
- const intrinsicHeight = image.naturalHeight;
30433
- const recommendedWidth = this.window.devicePixelRatio * renderedWidth;
30434
- const recommendedHeight = this.window.devicePixelRatio * renderedHeight;
30435
- const oversizedWidth = (intrinsicWidth - recommendedWidth) >= OVERSIZED_IMAGE_TOLERANCE;
30436
- const oversizedHeight = (intrinsicHeight - recommendedHeight) >= OVERSIZED_IMAGE_TOLERANCE;
30437
- return oversizedWidth || oversizedHeight;
30438
- }
30439
- static { this.ɵfac = function ImagePerformanceWarning_Factory(t) { return new (t || ImagePerformanceWarning)(); }; }
30440
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ImagePerformanceWarning, factory: ImagePerformanceWarning.ɵfac, providedIn: 'root' }); }
30441
- }
30442
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ImagePerformanceWarning, [{
30443
- type: Injectable,
30444
- args: [{ providedIn: 'root' }]
30445
- }], null, null); })();
30446
- function logLazyLCPWarning(src) {
30447
- console.warn(formatRuntimeError(-913 /* RuntimeErrorCode.IMAGE_PERFORMANCE_WARNING */, `An image with src ${src} is the Largest Contentful Paint (LCP) element ` +
30448
- `but was given a "loading" value of "lazy", which can negatively impact ` +
30449
- `application loading performance. This warning can be addressed by ` +
30450
- `changing the loading value of the LCP image to "eager", or by using the ` +
30451
- `NgOptimizedImage directive's prioritization utilities. For more ` +
30452
- `information about addressing or disabling this warning, see ` +
30453
- `https://angular.io/errors/NG0913`));
30454
- }
30455
- function logOversizedImageWarning(src) {
30456
- console.warn(formatRuntimeError(-913 /* RuntimeErrorCode.IMAGE_PERFORMANCE_WARNING */, `An image with src ${src} has intrinsic file dimensions much larger than its ` +
30457
- `rendered size. This can negatively impact application loading performance. ` +
30458
- `For more information about addressing or disabling this warning, see ` +
30459
- `https://angular.io/errors/NG0913`));
30460
- }
30461
-
30462
- /**
30463
- * *Internal* service that keeps track of pending tasks happening in the system
30464
- * during the initial rendering. No tasks are tracked after an initial
30465
- * rendering.
30466
- *
30467
- * This information is needed to make sure that the serialization on the server
30468
- * is delayed until all tasks in the queue (such as an initial navigation or a
30469
- * pending HTTP request) are completed.
30470
- */
30471
- class InitialRenderPendingTasks {
30472
- constructor() {
30473
- this.taskId = 0;
30474
- this.pendingTasks = new Set();
30475
- this.hasPendingTasks = new BehaviorSubject(false);
30476
- }
30477
- add() {
30478
- this.hasPendingTasks.next(true);
30479
- const taskId = this.taskId++;
30480
- this.pendingTasks.add(taskId);
30481
- return taskId;
30482
- }
30483
- remove(taskId) {
30484
- this.pendingTasks.delete(taskId);
30485
- if (this.pendingTasks.size === 0) {
30486
- this.hasPendingTasks.next(false);
30487
- }
30488
- }
30489
- ngOnDestroy() {
30490
- this.pendingTasks.clear();
30491
- this.hasPendingTasks.next(false);
30492
- }
30493
- static { this.ɵfac = function InitialRenderPendingTasks_Factory(t) { return new (t || InitialRenderPendingTasks)(); }; }
30494
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: InitialRenderPendingTasks, factory: InitialRenderPendingTasks.ɵfac, providedIn: 'root' }); }
30495
- }
30496
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(InitialRenderPendingTasks, [{
30497
- type: Injectable,
30498
- args: [{ providedIn: 'root' }]
30499
- }], null, null); })();
30500
-
30501
- /**
30502
- * Combination of NgModuleFactory and ComponentFactories.
30503
- *
30504
- * @publicApi
30505
- *
30506
- * @deprecated
30507
- * Ivy JIT mode doesn't require accessing this symbol.
30508
- * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
30509
- * additional context.
30510
- */
30511
- class ModuleWithComponentFactories {
30512
- constructor(ngModuleFactory, componentFactories) {
30513
- this.ngModuleFactory = ngModuleFactory;
30514
- this.componentFactories = componentFactories;
30515
- }
30516
- }
30517
- /**
30518
- * Low-level service for running the angular compiler during runtime
30519
- * to create {@link ComponentFactory}s, which
30520
- * can later be used to create and render a Component instance.
30521
- *
30522
- * Each `@NgModule` provides an own `Compiler` to its injector,
30523
- * that will use the directives/pipes of the ng module for compilation
30524
- * of components.
30525
- *
30526
- * @publicApi
30527
- *
30528
- * @deprecated
30529
- * Ivy JIT mode doesn't require accessing this symbol.
30530
- * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
30531
- * additional context.
30532
- */
30533
- class Compiler {
30534
- /**
30535
- * Compiles the given NgModule and all of its components. All templates of the components
30536
- * have to be inlined.
30537
- */
30538
- compileModuleSync(moduleType) {
30539
- return new NgModuleFactory(moduleType);
30540
- }
30541
- /**
30542
- * Compiles the given NgModule and all of its components
30543
- */
30544
- compileModuleAsync(moduleType) {
30545
- return Promise.resolve(this.compileModuleSync(moduleType));
30546
- }
30547
- /**
30548
- * Same as {@link #compileModuleSync} but also creates ComponentFactories for all components.
30549
- */
30550
- compileModuleAndAllComponentsSync(moduleType) {
30551
- const ngModuleFactory = this.compileModuleSync(moduleType);
30552
- const moduleDef = getNgModuleDef(moduleType);
30553
- const componentFactories = maybeUnwrapFn(moduleDef.declarations)
30554
- .reduce((factories, declaration) => {
30555
- const componentDef = getComponentDef(declaration);
30556
- componentDef && factories.push(new ComponentFactory(componentDef));
30557
- return factories;
30558
- }, []);
30559
- return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
30560
- }
30561
- /**
30562
- * Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components.
30563
- */
30564
- compileModuleAndAllComponentsAsync(moduleType) {
30565
- return Promise.resolve(this.compileModuleAndAllComponentsSync(moduleType));
30566
- }
30567
- /**
30568
- * Clears all caches.
30569
- */
30570
- clearCache() { }
30571
- /**
30572
- * Clears the cache for the given component/ngModule.
30573
- */
30574
- clearCacheFor(type) { }
30575
- /**
30576
- * Returns the id for a given NgModule, if one is defined and known to the compiler.
30577
- */
30578
- getModuleId(moduleType) {
30579
- return undefined;
30580
- }
30581
- static { this.ɵfac = function Compiler_Factory(t) { return new (t || Compiler)(); }; }
30582
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Compiler, factory: Compiler.ɵfac, providedIn: 'root' }); }
30583
- }
30584
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Compiler, [{
30585
- type: Injectable,
30586
- args: [{ providedIn: 'root' }]
30587
- }], null, null); })();
30588
- /**
30589
- * Token to provide CompilerOptions in the platform injector.
30590
- *
30591
- * @publicApi
30592
- */
30593
- const COMPILER_OPTIONS = new InjectionToken('compilerOptions');
30594
- /**
30595
- * A factory for creating a Compiler
30596
- *
30597
- * @publicApi
30598
- *
30599
- * @deprecated
30600
- * Ivy JIT mode doesn't require accessing this symbol.
30601
- * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
30602
- * additional context.
30603
- */
30604
- class CompilerFactory {
30605
- }
30606
-
30607
- /**
30608
- * These are the data structures that our framework injector profiler will fill with data in order
30609
- * to support DI debugging APIs.
30610
- *
30611
- * resolverToTokenToDependencies: Maps an injector to a Map of tokens to an Array of
30612
- * dependencies. Injector -> Token -> Dependencies This is used to support the
30613
- * getDependenciesFromInjectable API, which takes in an injector and a token and returns it's
30614
- * dependencies.
30615
- *
30616
- * resolverToProviders: Maps a DI resolver (an Injector or a TNode) to the providers configured
30617
- * within it This is used to support the getInjectorProviders API, which takes in an injector and
30618
- * returns the providers that it was configured with. Note that for the element injector case we
30619
- * use the TNode instead of the LView as the DI resolver. This is because the registration of
30620
- * providers happens only once per type of TNode. If an injector is created with an identical TNode,
30621
- * the providers for that injector will not be reconfigured.
30622
- *
30623
- * standaloneInjectorToComponent: Maps the injector of a standalone component to the standalone
30624
- * component that it is associated with. Used in the getInjectorProviders API, specificially in the
30625
- * discovery of import paths for each provider. This is necessary because the imports array of a
30626
- * standalone component is processed and configured in its standalone injector, but exists within
30627
- * the component's definition. Because getInjectorProviders takes in an injector, if that injector
30628
- * is the injector of a standalone component, we need to be able to discover the place where the
30629
- * imports array is located (the component) in order to flatten the imports array within it to
30630
- * discover all of it's providers.
30631
- *
30632
- *
30633
- * All of these data structures are instantiated with WeakMaps. This will ensure that the presence
30634
- * of any object in the keys of these maps does not prevent the garbage collector from collecting
30635
- * those objects. Because of this property of WeakMaps, these data structures will never be the
30636
- * source of a memory leak.
30637
- *
30638
- * An example of this advantage: When components are destroyed, we don't need to do
30639
- * any additional work to remove that component from our mappings.
30640
- *
30641
- */
30642
- class DIDebugData {
30643
- constructor() {
30644
- this.resolverToTokenToDependencies = new WeakMap();
30645
- this.resolverToProviders = new WeakMap();
30646
- this.standaloneInjectorToComponent = new WeakMap();
30647
- }
30648
- reset() {
30649
- this.resolverToTokenToDependencies =
30650
- new WeakMap();
30651
- this.resolverToProviders = new WeakMap();
30652
- this.standaloneInjectorToComponent = new WeakMap();
30653
- }
30654
- }
30655
- let frameworkDIDebugData = new DIDebugData();
30656
- function getFrameworkDIDebugData() {
30657
- return frameworkDIDebugData;
30658
- }
30659
- /**
30660
- * Initalize default handling of injector events. This handling parses events
30661
- * as they are emitted and constructs the data structures necessary to support
30662
- * some of debug APIs.
30663
- *
30664
- * See handleInjectEvent, handleCreateEvent and handleProviderConfiguredEvent
30665
- * for descriptions of each handler
30666
- *
30667
- * Supported APIs:
30668
- * - getDependenciesFromInjectable
30669
- * - getInjectorProviders
30670
- */
30671
- function setupFrameworkInjectorProfiler() {
30672
- frameworkDIDebugData.reset();
30673
- setInjectorProfiler((injectorProfilerEvent) => handleInjectorProfilerEvent(injectorProfilerEvent));
30674
- }
30675
- function handleInjectorProfilerEvent(injectorProfilerEvent) {
30676
- const { context, type } = injectorProfilerEvent;
30677
- if (type === 0 /* InjectorProfilerEventType.Inject */) {
30678
- handleInjectEvent(context, injectorProfilerEvent.service);
30679
- }
30680
- else if (type === 1 /* InjectorProfilerEventType.InstanceCreatedByInjector */) {
30681
- handleInstanceCreatedByInjectorEvent(context, injectorProfilerEvent.instance);
30682
- }
30683
- else if (type === 2 /* InjectorProfilerEventType.ProviderConfigured */) {
30684
- handleProviderConfiguredEvent(context, injectorProfilerEvent.providerRecord);
30685
- }
30686
- }
30687
- /**
30688
- *
30689
- * Stores the injected service in frameworkDIDebugData.resolverToTokenToDependencies
30690
- * based on it's injector and token.
30691
- *
30692
- * @param context InjectorProfilerContext the injection context that this event occurred in.
30693
- * @param data InjectedService the service associated with this inject event.
30240
+ * @param context InjectorProfilerContext the injection context that this event occurred in.
30241
+ * @param data InjectedService the service associated with this inject event.
30694
30242
  *
30695
30243
  */
30696
30244
  function handleInjectEvent(context, data) {
@@ -30864,6 +30412,7 @@ function applyChanges(component) {
30864
30412
  */
30865
30413
  function detectChanges(component) {
30866
30414
  const view = getComponentViewByInstance(component);
30415
+ view[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
30867
30416
  detectChangesInternal(view);
30868
30417
  }
30869
30418
 
@@ -31759,19 +31308,190 @@ function setTestabilityGetter(getter) {
31759
31308
  }
31760
31309
  let _testabilityGetter;
31761
31310
 
31762
- let _platformInjector = null;
31763
31311
  /**
31764
- * Internal token to indicate whether having multiple bootstrapped platform should be allowed (only
31765
- * one bootstrapped platform is allowed by default). This token helps to support SSR scenarios.
31312
+ * A [DI token](guide/glossary#di-token "DI token definition") that you can use to provide
31313
+ * one or more initialization functions.
31314
+ *
31315
+ * The provided functions are injected at application startup and executed during
31316
+ * app initialization. If any of these functions returns a Promise or an Observable, initialization
31317
+ * does not complete until the Promise is resolved or the Observable is completed.
31318
+ *
31319
+ * You can, for example, create a factory function that loads language data
31320
+ * or an external configuration, and provide that function to the `APP_INITIALIZER` token.
31321
+ * The function is executed during the application bootstrap process,
31322
+ * and the needed data is available on startup.
31323
+ *
31324
+ * @see {@link ApplicationInitStatus}
31325
+ *
31326
+ * @usageNotes
31327
+ *
31328
+ * The following example illustrates how to configure a multi-provider using `APP_INITIALIZER` token
31329
+ * and a function returning a promise.
31330
+ * ### Example with NgModule-based application
31331
+ * ```
31332
+ * function initializeApp(): Promise<any> {
31333
+ * return new Promise((resolve, reject) => {
31334
+ * // Do some asynchronous stuff
31335
+ * resolve();
31336
+ * });
31337
+ * }
31338
+ *
31339
+ * @NgModule({
31340
+ * imports: [BrowserModule],
31341
+ * declarations: [AppComponent],
31342
+ * bootstrap: [AppComponent],
31343
+ * providers: [{
31344
+ * provide: APP_INITIALIZER,
31345
+ * useFactory: () => initializeApp,
31346
+ * multi: true
31347
+ * }]
31348
+ * })
31349
+ * export class AppModule {}
31350
+ * ```
31351
+ *
31352
+ * ### Example with standalone application
31353
+ * ```
31354
+ * export function initializeApp(http: HttpClient) {
31355
+ * return (): Promise<any> =>
31356
+ * firstValueFrom(
31357
+ * http
31358
+ * .get("https://someUrl.com/api/user")
31359
+ * .pipe(tap(user => { ... }))
31360
+ * );
31361
+ * }
31362
+ *
31363
+ * bootstrapApplication(App, {
31364
+ * providers: [
31365
+ * provideHttpClient(),
31366
+ * {
31367
+ * provide: APP_INITIALIZER,
31368
+ * useFactory: initializeApp,
31369
+ * multi: true,
31370
+ * deps: [HttpClient],
31371
+ * },
31372
+ * ],
31373
+ * });
31374
+
31375
+ * ```
31376
+ *
31377
+ *
31378
+ * It's also possible to configure a multi-provider using `APP_INITIALIZER` token and a function
31379
+ * returning an observable, see an example below. Note: the `HttpClient` in this example is used for
31380
+ * demo purposes to illustrate how the factory function can work with other providers available
31381
+ * through DI.
31382
+ *
31383
+ * ### Example with NgModule-based application
31384
+ * ```
31385
+ * function initializeAppFactory(httpClient: HttpClient): () => Observable<any> {
31386
+ * return () => httpClient.get("https://someUrl.com/api/user")
31387
+ * .pipe(
31388
+ * tap(user => { ... })
31389
+ * );
31390
+ * }
31391
+ *
31392
+ * @NgModule({
31393
+ * imports: [BrowserModule, HttpClientModule],
31394
+ * declarations: [AppComponent],
31395
+ * bootstrap: [AppComponent],
31396
+ * providers: [{
31397
+ * provide: APP_INITIALIZER,
31398
+ * useFactory: initializeAppFactory,
31399
+ * deps: [HttpClient],
31400
+ * multi: true
31401
+ * }]
31402
+ * })
31403
+ * export class AppModule {}
31404
+ * ```
31405
+ *
31406
+ * ### Example with standalone application
31407
+ * ```
31408
+ * function initializeAppFactory(httpClient: HttpClient): () => Observable<any> {
31409
+ * return () => httpClient.get("https://someUrl.com/api/user")
31410
+ * .pipe(
31411
+ * tap(user => { ... })
31412
+ * );
31413
+ * }
31414
+ *
31415
+ * bootstrapApplication(App, {
31416
+ * providers: [
31417
+ * provideHttpClient(),
31418
+ * {
31419
+ * provide: APP_INITIALIZER,
31420
+ * useFactory: initializeAppFactory,
31421
+ * multi: true,
31422
+ * deps: [HttpClient],
31423
+ * },
31424
+ * ],
31425
+ * });
31426
+ * ```
31427
+ *
31428
+ * @publicApi
31766
31429
  */
31767
- const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken');
31430
+ const APP_INITIALIZER = new InjectionToken('Application Initializer');
31768
31431
  /**
31769
- * Internal token that allows to register extra callbacks that should be invoked during the
31770
- * `PlatformRef.destroy` operation. This token is needed to avoid a direct reference to the
31771
- * `PlatformRef` class (i.e. register the callback via `PlatformRef.onDestroy`), thus making the
31772
- * entire class tree-shakeable.
31432
+ * A class that reflects the state of running {@link APP_INITIALIZER} functions.
31433
+ *
31434
+ * @publicApi
31773
31435
  */
31774
- const PLATFORM_DESTROY_LISTENERS = new InjectionToken('PlatformDestroyListeners');
31436
+ class ApplicationInitStatus {
31437
+ constructor() {
31438
+ this.initialized = false;
31439
+ this.done = false;
31440
+ this.donePromise = new Promise((res, rej) => {
31441
+ this.resolve = res;
31442
+ this.reject = rej;
31443
+ });
31444
+ this.appInits = inject(APP_INITIALIZER, { optional: true }) ?? [];
31445
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && !Array.isArray(this.appInits)) {
31446
+ throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `APP_INITIALIZER` token value ' +
31447
+ `(expected an array, but got ${typeof this.appInits}). ` +
31448
+ 'Please check that the `APP_INITIALIZER` token is configured as a ' +
31449
+ '`multi: true` provider.');
31450
+ }
31451
+ }
31452
+ /** @internal */
31453
+ runInitializers() {
31454
+ if (this.initialized) {
31455
+ return;
31456
+ }
31457
+ const asyncInitPromises = [];
31458
+ for (const appInits of this.appInits) {
31459
+ const initResult = appInits();
31460
+ if (isPromise(initResult)) {
31461
+ asyncInitPromises.push(initResult);
31462
+ }
31463
+ else if (isSubscribable(initResult)) {
31464
+ const observableAsPromise = new Promise((resolve, reject) => {
31465
+ initResult.subscribe({ complete: resolve, error: reject });
31466
+ });
31467
+ asyncInitPromises.push(observableAsPromise);
31468
+ }
31469
+ }
31470
+ const complete = () => {
31471
+ // @ts-expect-error overwriting a readonly
31472
+ this.done = true;
31473
+ this.resolve();
31474
+ };
31475
+ Promise.all(asyncInitPromises)
31476
+ .then(() => {
31477
+ complete();
31478
+ })
31479
+ .catch(e => {
31480
+ this.reject(e);
31481
+ });
31482
+ if (asyncInitPromises.length === 0) {
31483
+ complete();
31484
+ }
31485
+ this.initialized = true;
31486
+ }
31487
+ static { this.ɵfac = function ApplicationInitStatus_Factory(t) { return new (t || ApplicationInitStatus)(); }; }
31488
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationInitStatus, factory: ApplicationInitStatus.ɵfac, providedIn: 'root' }); }
31489
+ }
31490
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
31491
+ type: Injectable,
31492
+ args: [{ providedIn: 'root' }]
31493
+ }], () => [], null); })();
31494
+
31775
31495
  /**
31776
31496
  * A [DI token](guide/glossary#di-token "DI token definition") that provides a set of callbacks to
31777
31497
  * be called for every component that is bootstrapped.
@@ -31849,374 +31569,6 @@ class NgProbeToken {
31849
31569
  this.token = token;
31850
31570
  }
31851
31571
  }
31852
- /**
31853
- * Creates a platform.
31854
- * Platforms must be created on launch using this function.
31855
- *
31856
- * @publicApi
31857
- */
31858
- function createPlatform(injector) {
31859
- if (_platformInjector && !_platformInjector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
31860
- throw new RuntimeError(400 /* RuntimeErrorCode.MULTIPLE_PLATFORMS */, ngDevMode &&
31861
- 'There can be only one platform. Destroy the previous one to create a new one.');
31862
- }
31863
- publishDefaultGlobalUtils();
31864
- publishSignalConfiguration();
31865
- _platformInjector = injector;
31866
- const platform = injector.get(PlatformRef);
31867
- runPlatformInitializers(injector);
31868
- return platform;
31869
- }
31870
- /**
31871
- * The goal of this function is to bootstrap a platform injector,
31872
- * but avoid referencing `PlatformRef` class.
31873
- * This function is needed for bootstrapping a Standalone Component.
31874
- */
31875
- function createOrReusePlatformInjector(providers = []) {
31876
- // If a platform injector already exists, it means that the platform
31877
- // is already bootstrapped and no additional actions are required.
31878
- if (_platformInjector)
31879
- return _platformInjector;
31880
- publishDefaultGlobalUtils();
31881
- // Otherwise, setup a new platform injector and run platform initializers.
31882
- const injector = createPlatformInjector(providers);
31883
- _platformInjector = injector;
31884
- publishSignalConfiguration();
31885
- runPlatformInitializers(injector);
31886
- return injector;
31887
- }
31888
- function runPlatformInitializers(injector) {
31889
- const inits = injector.get(PLATFORM_INITIALIZER, null);
31890
- inits?.forEach((init) => init());
31891
- }
31892
- /**
31893
- * Internal create application API that implements the core application creation logic and optional
31894
- * bootstrap logic.
31895
- *
31896
- * Platforms (such as `platform-browser`) may require different set of application and platform
31897
- * providers for an application to function correctly. As a result, platforms may use this function
31898
- * internally and supply the necessary providers during the bootstrap, while exposing
31899
- * platform-specific APIs as a part of their public API.
31900
- *
31901
- * @returns A promise that returns an `ApplicationRef` instance once resolved.
31902
- */
31903
- function internalCreateApplication(config) {
31904
- try {
31905
- const { rootComponent, appProviders, platformProviders } = config;
31906
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && rootComponent !== undefined) {
31907
- assertStandaloneComponentType(rootComponent);
31908
- }
31909
- const platformInjector = createOrReusePlatformInjector(platformProviders);
31910
- // Create root application injector based on a set of providers configured at the platform
31911
- // bootstrap level as well as providers passed to the bootstrap call by a user.
31912
- const allAppProviders = [
31913
- provideZoneChangeDetection(),
31914
- ...(appProviders || []),
31915
- ];
31916
- const adapter = new EnvironmentNgModuleRefAdapter({
31917
- providers: allAppProviders,
31918
- parent: platformInjector,
31919
- debugName: (typeof ngDevMode === 'undefined' || ngDevMode) ? 'Environment Injector' : '',
31920
- // We skip environment initializers because we need to run them inside the NgZone, which
31921
- // happens after we get the NgZone instance from the Injector.
31922
- runEnvironmentInitializers: false,
31923
- });
31924
- const envInjector = adapter.injector;
31925
- const ngZone = envInjector.get(NgZone);
31926
- return ngZone.run(() => {
31927
- envInjector.resolveInjectorInitializers();
31928
- const exceptionHandler = envInjector.get(ErrorHandler, null);
31929
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && !exceptionHandler) {
31930
- throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, 'No `ErrorHandler` found in the Dependency Injection tree.');
31931
- }
31932
- let onErrorSubscription;
31933
- ngZone.runOutsideAngular(() => {
31934
- onErrorSubscription = ngZone.onError.subscribe({
31935
- next: (error) => {
31936
- exceptionHandler.handleError(error);
31937
- }
31938
- });
31939
- });
31940
- // If the whole platform is destroyed, invoke the `destroy` method
31941
- // for all bootstrapped applications as well.
31942
- const destroyListener = () => envInjector.destroy();
31943
- const onPlatformDestroyListeners = platformInjector.get(PLATFORM_DESTROY_LISTENERS);
31944
- onPlatformDestroyListeners.add(destroyListener);
31945
- envInjector.onDestroy(() => {
31946
- onErrorSubscription.unsubscribe();
31947
- onPlatformDestroyListeners.delete(destroyListener);
31948
- });
31949
- return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
31950
- const initStatus = envInjector.get(ApplicationInitStatus);
31951
- initStatus.runInitializers();
31952
- return initStatus.donePromise.then(() => {
31953
- const localeId = envInjector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
31954
- setLocaleId(localeId || DEFAULT_LOCALE_ID);
31955
- const appRef = envInjector.get(ApplicationRef);
31956
- if (rootComponent !== undefined) {
31957
- appRef.bootstrap(rootComponent);
31958
- }
31959
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
31960
- const imagePerformanceService = envInjector.get(ImagePerformanceWarning);
31961
- imagePerformanceService.start();
31962
- }
31963
- return appRef;
31964
- });
31965
- });
31966
- });
31967
- }
31968
- catch (e) {
31969
- return Promise.reject(e);
31970
- }
31971
- }
31972
- /**
31973
- * Creates a factory for a platform. Can be used to provide or override `Providers` specific to
31974
- * your application's runtime needs, such as `PLATFORM_INITIALIZER` and `PLATFORM_ID`.
31975
- * @param parentPlatformFactory Another platform factory to modify. Allows you to compose factories
31976
- * to build up configurations that might be required by different libraries or parts of the
31977
- * application.
31978
- * @param name Identifies the new platform factory.
31979
- * @param providers A set of dependency providers for platforms created with the new factory.
31980
- *
31981
- * @publicApi
31982
- */
31983
- function createPlatformFactory(parentPlatformFactory, name, providers = []) {
31984
- const desc = `Platform: ${name}`;
31985
- const marker = new InjectionToken(desc);
31986
- return (extraProviders = []) => {
31987
- let platform = getPlatform();
31988
- if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
31989
- const platformProviders = [
31990
- ...providers,
31991
- ...extraProviders,
31992
- { provide: marker, useValue: true }
31993
- ];
31994
- if (parentPlatformFactory) {
31995
- parentPlatformFactory(platformProviders);
31996
- }
31997
- else {
31998
- createPlatform(createPlatformInjector(platformProviders, desc));
31999
- }
32000
- }
32001
- return assertPlatform(marker);
32002
- };
32003
- }
32004
- /**
32005
- * Checks that there is currently a platform that contains the given token as a provider.
32006
- *
32007
- * @publicApi
32008
- */
32009
- function assertPlatform(requiredToken) {
32010
- const platform = getPlatform();
32011
- if (!platform) {
32012
- throw new RuntimeError(401 /* RuntimeErrorCode.PLATFORM_NOT_FOUND */, ngDevMode && 'No platform exists!');
32013
- }
32014
- if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
32015
- !platform.injector.get(requiredToken, null)) {
32016
- throw new RuntimeError(400 /* RuntimeErrorCode.MULTIPLE_PLATFORMS */, 'A platform with a different configuration has been created. Please destroy it first.');
32017
- }
32018
- return platform;
32019
- }
32020
- /**
32021
- * Helper function to create an instance of a platform injector (that maintains the 'platform'
32022
- * scope).
32023
- */
32024
- function createPlatformInjector(providers = [], name) {
32025
- return Injector.create({
32026
- name,
32027
- providers: [
32028
- { provide: INJECTOR_SCOPE, useValue: 'platform' },
32029
- { provide: PLATFORM_DESTROY_LISTENERS, useValue: new Set([() => _platformInjector = null]) },
32030
- ...providers
32031
- ],
32032
- });
32033
- }
32034
- /**
32035
- * Destroys the current Angular platform and all Angular applications on the page.
32036
- * Destroys all modules and listeners registered with the platform.
32037
- *
32038
- * @publicApi
32039
- */
32040
- function destroyPlatform() {
32041
- getPlatform()?.destroy();
32042
- }
32043
- /**
32044
- * Returns the current platform.
32045
- *
32046
- * @publicApi
32047
- */
32048
- function getPlatform() {
32049
- return _platformInjector?.get(PlatformRef) ?? null;
32050
- }
32051
- /**
32052
- * The Angular platform is the entry point for Angular on a web page.
32053
- * Each page has exactly one platform. Services (such as reflection) which are common
32054
- * to every Angular application running on the page are bound in its scope.
32055
- * A page's platform is initialized implicitly when a platform is created using a platform
32056
- * factory such as `PlatformBrowser`, or explicitly by calling the `createPlatform()` function.
32057
- *
32058
- * @publicApi
32059
- */
32060
- class PlatformRef {
32061
- /** @internal */
32062
- constructor(_injector) {
32063
- this._injector = _injector;
32064
- this._modules = [];
32065
- this._destroyListeners = [];
32066
- this._destroyed = false;
32067
- }
32068
- /**
32069
- * Creates an instance of an `@NgModule` for the given platform.
32070
- *
32071
- * @deprecated Passing NgModule factories as the `PlatformRef.bootstrapModuleFactory` function
32072
- * argument is deprecated. Use the `PlatformRef.bootstrapModule` API instead.
32073
- */
32074
- bootstrapModuleFactory(moduleFactory, options) {
32075
- // Note: We need to create the NgZone _before_ we instantiate the module,
32076
- // as instantiating the module creates some providers eagerly.
32077
- // So we create a mini parent injector that just contains the new NgZone and
32078
- // pass that as parent to the NgModuleFactory.
32079
- const ngZone = getNgZone(options?.ngZone, getNgZoneOptions({
32080
- eventCoalescing: options?.ngZoneEventCoalescing,
32081
- runCoalescing: options?.ngZoneRunCoalescing
32082
- }));
32083
- // Note: Create ngZoneInjector within ngZone.run so that all of the instantiated services are
32084
- // created within the Angular zone
32085
- // Do not try to replace ngZone.run with ApplicationRef#run because ApplicationRef would then be
32086
- // created outside of the Angular zone.
32087
- return ngZone.run(() => {
32088
- const moduleRef = createNgModuleRefWithProviders(moduleFactory.moduleType, this.injector, internalProvideZoneChangeDetection(() => ngZone));
32089
- if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
32090
- moduleRef.injector.get(PROVIDED_NG_ZONE, null) !== null) {
32091
- throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, '`bootstrapModule` does not support `provideZoneChangeDetection`. Use `BootstrapOptions` instead.');
32092
- }
32093
- const exceptionHandler = moduleRef.injector.get(ErrorHandler, null);
32094
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && exceptionHandler === null) {
32095
- throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, 'No ErrorHandler. Is platform module (BrowserModule) included?');
32096
- }
32097
- ngZone.runOutsideAngular(() => {
32098
- const subscription = ngZone.onError.subscribe({
32099
- next: (error) => {
32100
- exceptionHandler.handleError(error);
32101
- }
32102
- });
32103
- moduleRef.onDestroy(() => {
32104
- remove(this._modules, moduleRef);
32105
- subscription.unsubscribe();
32106
- });
32107
- });
32108
- return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
32109
- const initStatus = moduleRef.injector.get(ApplicationInitStatus);
32110
- initStatus.runInitializers();
32111
- return initStatus.donePromise.then(() => {
32112
- // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy
32113
- const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
32114
- setLocaleId(localeId || DEFAULT_LOCALE_ID);
32115
- this._moduleDoBootstrap(moduleRef);
32116
- return moduleRef;
32117
- });
32118
- });
32119
- });
32120
- }
32121
- /**
32122
- * Creates an instance of an `@NgModule` for a given platform.
32123
- *
32124
- * @usageNotes
32125
- * ### Simple Example
32126
- *
32127
- * ```typescript
32128
- * @NgModule({
32129
- * imports: [BrowserModule]
32130
- * })
32131
- * class MyModule {}
32132
- *
32133
- * let moduleRef = platformBrowser().bootstrapModule(MyModule);
32134
- * ```
32135
- *
32136
- */
32137
- bootstrapModule(moduleType, compilerOptions = []) {
32138
- const options = optionsReducer({}, compilerOptions);
32139
- return compileNgModuleFactory(this.injector, options, moduleType)
32140
- .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
32141
- }
32142
- _moduleDoBootstrap(moduleRef) {
32143
- const appRef = moduleRef.injector.get(ApplicationRef);
32144
- if (moduleRef._bootstrapComponents.length > 0) {
32145
- moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
32146
- }
32147
- else if (moduleRef.instance.ngDoBootstrap) {
32148
- moduleRef.instance.ngDoBootstrap(appRef);
32149
- }
32150
- else {
32151
- throw new RuntimeError(-403 /* RuntimeErrorCode.BOOTSTRAP_COMPONENTS_NOT_FOUND */, ngDevMode &&
32152
- `The module ${stringify(moduleRef.instance.constructor)} was bootstrapped, ` +
32153
- `but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
32154
- `Please define one of these.`);
32155
- }
32156
- this._modules.push(moduleRef);
32157
- }
32158
- /**
32159
- * Registers a listener to be called when the platform is destroyed.
32160
- */
32161
- onDestroy(callback) {
32162
- this._destroyListeners.push(callback);
32163
- }
32164
- /**
32165
- * Retrieves the platform {@link Injector}, which is the parent injector for
32166
- * every Angular application on the page and provides singleton providers.
32167
- */
32168
- get injector() {
32169
- return this._injector;
32170
- }
32171
- /**
32172
- * Destroys the current Angular platform and all Angular applications on the page.
32173
- * Destroys all modules and listeners registered with the platform.
32174
- */
32175
- destroy() {
32176
- if (this._destroyed) {
32177
- throw new RuntimeError(404 /* RuntimeErrorCode.PLATFORM_ALREADY_DESTROYED */, ngDevMode && 'The platform has already been destroyed!');
32178
- }
32179
- this._modules.slice().forEach(module => module.destroy());
32180
- this._destroyListeners.forEach(listener => listener());
32181
- const destroyListeners = this._injector.get(PLATFORM_DESTROY_LISTENERS, null);
32182
- if (destroyListeners) {
32183
- destroyListeners.forEach(listener => listener());
32184
- destroyListeners.clear();
32185
- }
32186
- this._destroyed = true;
32187
- }
32188
- /**
32189
- * Indicates whether this instance was destroyed.
32190
- */
32191
- get destroyed() {
32192
- return this._destroyed;
32193
- }
32194
- static { this.ɵfac = function PlatformRef_Factory(t) { return new (t || PlatformRef)(ɵɵinject(Injector)); }; }
32195
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: PlatformRef, factory: PlatformRef.ɵfac, providedIn: 'platform' }); }
32196
- }
32197
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PlatformRef, [{
32198
- type: Injectable,
32199
- args: [{ providedIn: 'platform' }]
32200
- }], () => [{ type: Injector }], null); })();
32201
- // Transforms a set of `BootstrapOptions` (supported by the NgModule-based bootstrap APIs) ->
32202
- // `NgZoneOptions` that are recognized by the NgZone constructor. Passing no options will result in
32203
- // a set of default options returned.
32204
- function getNgZoneOptions(options) {
32205
- return {
32206
- enableLongStackTrace: typeof ngDevMode === 'undefined' ? false : !!ngDevMode,
32207
- shouldCoalesceEventChangeDetection: options?.eventCoalescing ?? false,
32208
- shouldCoalesceRunChangeDetection: options?.runCoalescing ?? false,
32209
- };
32210
- }
32211
- function getNgZone(ngZoneToUse = 'zone.js', options) {
32212
- if (ngZoneToUse === 'noop') {
32213
- return new NoopNgZone();
32214
- }
32215
- if (ngZoneToUse === 'zone.js') {
32216
- return new NgZone(options);
32217
- }
32218
- return ngZoneToUse;
32219
- }
32220
31572
  function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
32221
31573
  try {
32222
31574
  const result = callback();
@@ -32357,7 +31709,7 @@ class ApplicationRef {
32357
31709
  * Returns an Observable that indicates when the application is stable or unstable.
32358
31710
  */
32359
31711
  this.isStable = inject(InitialRenderPendingTasks)
32360
- .hasPendingTasks.pipe(switchMap(hasPendingTasks => hasPendingTasks ? of(false) : this.zoneIsStable), distinctUntilChanged(), share());
31712
+ .hasPendingTasks.pipe(switchMap(hasPendingTasks => hasPendingTasks ? of(false) : this.zoneIsStable), distinctUntilChanged());
32361
31713
  this._injector = inject(EnvironmentInjector);
32362
31714
  }
32363
31715
  /**
@@ -32536,179 +31888,629 @@ class ApplicationRef {
32536
31888
  }
32537
31889
  }
32538
31890
  /**
32539
- * Registers a listener to be called when an instance is destroyed.
32540
- *
32541
- * @param callback A callback function to add as a listener.
32542
- * @returns A function which unregisters a listener.
31891
+ * Registers a listener to be called when an instance is destroyed.
31892
+ *
31893
+ * @param callback A callback function to add as a listener.
31894
+ * @returns A function which unregisters a listener.
31895
+ */
31896
+ onDestroy(callback) {
31897
+ (typeof ngDevMode === 'undefined' || ngDevMode) && this.warnIfDestroyed();
31898
+ this._destroyListeners.push(callback);
31899
+ return () => remove(this._destroyListeners, callback);
31900
+ }
31901
+ /**
31902
+ * Destroys an Angular application represented by this `ApplicationRef`. Calling this function
31903
+ * will destroy the associated environment injectors as well as all the bootstrapped components
31904
+ * with their views.
31905
+ */
31906
+ destroy() {
31907
+ if (this._destroyed) {
31908
+ throw new RuntimeError(406 /* RuntimeErrorCode.APPLICATION_REF_ALREADY_DESTROYED */, ngDevMode && 'This instance of the `ApplicationRef` has already been destroyed.');
31909
+ }
31910
+ const injector = this._injector;
31911
+ // Check that this injector instance supports destroy operation.
31912
+ if (injector.destroy && !injector.destroyed) {
31913
+ // Destroying an underlying injector will trigger the `ngOnDestroy` lifecycle
31914
+ // hook, which invokes the remaining cleanup actions.
31915
+ injector.destroy();
31916
+ }
31917
+ }
31918
+ /**
31919
+ * Returns the number of attached views.
31920
+ */
31921
+ get viewCount() {
31922
+ return this._views.length;
31923
+ }
31924
+ warnIfDestroyed() {
31925
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && this._destroyed) {
31926
+ console.warn(formatRuntimeError(406 /* RuntimeErrorCode.APPLICATION_REF_ALREADY_DESTROYED */, 'This instance of the `ApplicationRef` has already been destroyed.'));
31927
+ }
31928
+ }
31929
+ static { this.ɵfac = function ApplicationRef_Factory(t) { return new (t || ApplicationRef)(); }; }
31930
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationRef, factory: ApplicationRef.ɵfac, providedIn: 'root' }); }
31931
+ }
31932
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationRef, [{
31933
+ type: Injectable,
31934
+ args: [{ providedIn: 'root' }]
31935
+ }], null, null); })();
31936
+ function remove(list, el) {
31937
+ const index = list.indexOf(el);
31938
+ if (index > -1) {
31939
+ list.splice(index, 1);
31940
+ }
31941
+ }
31942
+ function _lastDefined(args) {
31943
+ for (let i = args.length - 1; i >= 0; i--) {
31944
+ if (args[i] !== undefined) {
31945
+ return args[i];
31946
+ }
31947
+ }
31948
+ return undefined;
31949
+ }
31950
+ let whenStableStore;
31951
+ /**
31952
+ * Returns a Promise that resolves when the application becomes stable after this method is called
31953
+ * the first time.
31954
+ */
31955
+ function whenStable(applicationRef) {
31956
+ whenStableStore ??= new WeakMap();
31957
+ const cachedWhenStable = whenStableStore.get(applicationRef);
31958
+ if (cachedWhenStable) {
31959
+ return cachedWhenStable;
31960
+ }
31961
+ const whenStablePromise = applicationRef.isStable.pipe(first((isStable) => isStable)).toPromise().then(() => void 0);
31962
+ whenStableStore.set(applicationRef, whenStablePromise);
31963
+ // Be a good citizen and clean the store `onDestroy` even though we are using `WeakMap`.
31964
+ applicationRef.onDestroy(() => whenStableStore?.delete(applicationRef));
31965
+ return whenStablePromise;
31966
+ }
31967
+
31968
+ class NgZoneChangeDetectionScheduler {
31969
+ constructor() {
31970
+ this.zone = inject(NgZone);
31971
+ this.applicationRef = inject(ApplicationRef);
31972
+ }
31973
+ initialize() {
31974
+ if (this._onMicrotaskEmptySubscription) {
31975
+ return;
31976
+ }
31977
+ this._onMicrotaskEmptySubscription = this.zone.onMicrotaskEmpty.subscribe({
31978
+ next: () => {
31979
+ this.zone.run(() => {
31980
+ this.applicationRef.tick();
31981
+ });
31982
+ }
31983
+ });
31984
+ }
31985
+ ngOnDestroy() {
31986
+ this._onMicrotaskEmptySubscription?.unsubscribe();
31987
+ }
31988
+ static { this.ɵfac = function NgZoneChangeDetectionScheduler_Factory(t) { return new (t || NgZoneChangeDetectionScheduler)(); }; }
31989
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: NgZoneChangeDetectionScheduler, factory: NgZoneChangeDetectionScheduler.ɵfac, providedIn: 'root' }); }
31990
+ }
31991
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NgZoneChangeDetectionScheduler, [{
31992
+ type: Injectable,
31993
+ args: [{ providedIn: 'root' }]
31994
+ }], null, null); })();
31995
+ /**
31996
+ * Internal token used to verify that `provideZoneChangeDetection` is not used
31997
+ * with the bootstrapModule API.
31998
+ */
31999
+ const PROVIDED_NG_ZONE = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'provideZoneChangeDetection token' : '');
32000
+ function internalProvideZoneChangeDetection(ngZoneFactory) {
32001
+ return [
32002
+ { provide: NgZone, useFactory: ngZoneFactory },
32003
+ {
32004
+ provide: ENVIRONMENT_INITIALIZER,
32005
+ multi: true,
32006
+ useFactory: () => {
32007
+ const ngZoneChangeDetectionScheduler = inject(NgZoneChangeDetectionScheduler, { optional: true });
32008
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
32009
+ ngZoneChangeDetectionScheduler === null) {
32010
+ throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, `A required Injectable was not found in the dependency injection tree. ` +
32011
+ 'If you are bootstrapping an NgModule, make sure that the `BrowserModule` is imported.');
32012
+ }
32013
+ return () => ngZoneChangeDetectionScheduler.initialize();
32014
+ },
32015
+ },
32016
+ { provide: INTERNAL_APPLICATION_ERROR_HANDLER, useFactory: ngZoneApplicationErrorHandlerFactory },
32017
+ { provide: ZONE_IS_STABLE_OBSERVABLE, useFactory: isStableFactory },
32018
+ ];
32019
+ }
32020
+ function ngZoneApplicationErrorHandlerFactory() {
32021
+ const zone = inject(NgZone);
32022
+ const userErrorHandler = inject(ErrorHandler);
32023
+ return (e) => zone.runOutsideAngular(() => userErrorHandler.handleError(e));
32024
+ }
32025
+ /**
32026
+ * Provides `NgZone`-based change detection for the application bootstrapped using
32027
+ * `bootstrapApplication`.
32028
+ *
32029
+ * `NgZone` is already provided in applications by default. This provider allows you to configure
32030
+ * options like `eventCoalescing` in the `NgZone`.
32031
+ * This provider is not available for `platformBrowser().bootstrapModule`, which uses
32032
+ * `BootstrapOptions` instead.
32033
+ *
32034
+ * @usageNotes
32035
+ * ```typescript
32036
+ * bootstrapApplication(MyApp, {providers: [
32037
+ * provideZoneChangeDetection({eventCoalescing: true}),
32038
+ * ]});
32039
+ * ```
32040
+ *
32041
+ * @publicApi
32042
+ * @see {@link bootstrapApplication}
32043
+ * @see {@link NgZoneOptions}
32044
+ */
32045
+ function provideZoneChangeDetection(options) {
32046
+ const zoneProviders = internalProvideZoneChangeDetection(() => new NgZone(getNgZoneOptions(options)));
32047
+ return makeEnvironmentProviders([
32048
+ (typeof ngDevMode === 'undefined' || ngDevMode) ? { provide: PROVIDED_NG_ZONE, useValue: true } :
32049
+ [],
32050
+ zoneProviders,
32051
+ ]);
32052
+ }
32053
+ // Transforms a set of `BootstrapOptions` (supported by the NgModule-based bootstrap APIs) ->
32054
+ // `NgZoneOptions` that are recognized by the NgZone constructor. Passing no options will result in
32055
+ // a set of default options returned.
32056
+ function getNgZoneOptions(options) {
32057
+ return {
32058
+ enableLongStackTrace: typeof ngDevMode === 'undefined' ? false : !!ngDevMode,
32059
+ shouldCoalesceEventChangeDetection: options?.eventCoalescing ?? false,
32060
+ shouldCoalesceRunChangeDetection: options?.runCoalescing ?? false,
32061
+ };
32062
+ }
32063
+
32064
+ /**
32065
+ * Work out the locale from the potential global properties.
32066
+ *
32067
+ * * Closure Compiler: use `goog.LOCALE`.
32068
+ * * Ivy enabled: use `$localize.locale`
32069
+ */
32070
+ function getGlobalLocale() {
32071
+ if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
32072
+ typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
32073
+ // * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
32074
+ // * In order to preserve backwards compatibility, we use Angular default value over
32075
+ // Closure Compiler's one.
32076
+ return goog.LOCALE;
32077
+ }
32078
+ else {
32079
+ // KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
32080
+ // COMPILE-TIME INLINER.
32081
+ //
32082
+ // * During compile time inlining of translations the expression will be replaced
32083
+ // with a string literal that is the current locale. Other forms of this expression are not
32084
+ // guaranteed to be replaced.
32085
+ //
32086
+ // * During runtime translation evaluation, the developer is required to set `$localize.locale`
32087
+ // if required, or just to provide their own `LOCALE_ID` provider.
32088
+ return (typeof $localize !== 'undefined' && $localize.locale) || DEFAULT_LOCALE_ID;
32089
+ }
32090
+ }
32091
+ /**
32092
+ * Provide this token to set the locale of your application.
32093
+ * It is used for i18n extraction, by i18n pipes (DatePipe, I18nPluralPipe, CurrencyPipe,
32094
+ * DecimalPipe and PercentPipe) and by ICU expressions.
32095
+ *
32096
+ * See the [i18n guide](guide/i18n-common-locale-id) for more information.
32097
+ *
32098
+ * @usageNotes
32099
+ * ### Example
32100
+ *
32101
+ * ```typescript
32102
+ * import { LOCALE_ID } from '@angular/core';
32103
+ * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
32104
+ * import { AppModule } from './app/app.module';
32105
+ *
32106
+ * platformBrowserDynamic().bootstrapModule(AppModule, {
32107
+ * providers: [{provide: LOCALE_ID, useValue: 'en-US' }]
32108
+ * });
32109
+ * ```
32110
+ *
32111
+ * @publicApi
32112
+ */
32113
+ const LOCALE_ID = new InjectionToken('LocaleId', {
32114
+ providedIn: 'root',
32115
+ factory: () => inject(LOCALE_ID, InjectFlags.Optional | InjectFlags.SkipSelf) || getGlobalLocale(),
32116
+ });
32117
+ /**
32118
+ * Provide this token to set the default currency code your application uses for
32119
+ * CurrencyPipe when there is no currency code passed into it. This is only used by
32120
+ * CurrencyPipe and has no relation to locale currency. Defaults to USD if not configured.
32121
+ *
32122
+ * See the [i18n guide](guide/i18n-common-locale-id) for more information.
32123
+ *
32124
+ * <div class="alert is-helpful">
32125
+ *
32126
+ * **Deprecation notice:**
32127
+ *
32128
+ * The default currency code is currently always `USD` but this is deprecated from v9.
32129
+ *
32130
+ * **In v10 the default currency code will be taken from the current locale.**
32131
+ *
32132
+ * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in
32133
+ * your application `NgModule`:
32134
+ *
32135
+ * ```ts
32136
+ * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
32137
+ * ```
32138
+ *
32139
+ * </div>
32140
+ *
32141
+ * @usageNotes
32142
+ * ### Example
32143
+ *
32144
+ * ```typescript
32145
+ * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
32146
+ * import { AppModule } from './app/app.module';
32147
+ *
32148
+ * platformBrowserDynamic().bootstrapModule(AppModule, {
32149
+ * providers: [{provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' }]
32150
+ * });
32151
+ * ```
32152
+ *
32153
+ * @publicApi
32154
+ */
32155
+ const DEFAULT_CURRENCY_CODE = new InjectionToken('DefaultCurrencyCode', {
32156
+ providedIn: 'root',
32157
+ factory: () => USD_CURRENCY_CODE,
32158
+ });
32159
+ /**
32160
+ * Use this token at bootstrap to provide the content of your translation file (`xtb`,
32161
+ * `xlf` or `xlf2`) when you want to translate your application in another language.
32162
+ *
32163
+ * See the [i18n guide](guide/i18n-common-merge) for more information.
32164
+ *
32165
+ * @usageNotes
32166
+ * ### Example
32167
+ *
32168
+ * ```typescript
32169
+ * import { TRANSLATIONS } from '@angular/core';
32170
+ * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
32171
+ * import { AppModule } from './app/app.module';
32172
+ *
32173
+ * // content of your translation file
32174
+ * const translations = '....';
32175
+ *
32176
+ * platformBrowserDynamic().bootstrapModule(AppModule, {
32177
+ * providers: [{provide: TRANSLATIONS, useValue: translations }]
32178
+ * });
32179
+ * ```
32180
+ *
32181
+ * @publicApi
32182
+ */
32183
+ const TRANSLATIONS = new InjectionToken('Translations');
32184
+ /**
32185
+ * Provide this token at bootstrap to set the format of your {@link TRANSLATIONS}: `xtb`,
32186
+ * `xlf` or `xlf2`.
32187
+ *
32188
+ * See the [i18n guide](guide/i18n-common-merge) for more information.
32189
+ *
32190
+ * @usageNotes
32191
+ * ### Example
32192
+ *
32193
+ * ```typescript
32194
+ * import { TRANSLATIONS_FORMAT } from '@angular/core';
32195
+ * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
32196
+ * import { AppModule } from './app/app.module';
32197
+ *
32198
+ * platformBrowserDynamic().bootstrapModule(AppModule, {
32199
+ * providers: [{provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }]
32200
+ * });
32201
+ * ```
32202
+ *
32203
+ * @publicApi
32204
+ */
32205
+ const TRANSLATIONS_FORMAT = new InjectionToken('TranslationsFormat');
32206
+ /**
32207
+ * Use this enum at bootstrap as an option of `bootstrapModule` to define the strategy
32208
+ * that the compiler should use in case of missing translations:
32209
+ * - Error: throw if you have missing translations.
32210
+ * - Warning (default): show a warning in the console and/or shell.
32211
+ * - Ignore: do nothing.
32212
+ *
32213
+ * See the [i18n guide](guide/i18n-common-merge#report-missing-translations) for more information.
32214
+ *
32215
+ * @usageNotes
32216
+ * ### Example
32217
+ * ```typescript
32218
+ * import { MissingTranslationStrategy } from '@angular/core';
32219
+ * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
32220
+ * import { AppModule } from './app/app.module';
32221
+ *
32222
+ * platformBrowserDynamic().bootstrapModule(AppModule, {
32223
+ * missingTranslation: MissingTranslationStrategy.Error
32224
+ * });
32225
+ * ```
32226
+ *
32227
+ * @publicApi
32228
+ */
32229
+ var MissingTranslationStrategy;
32230
+ (function (MissingTranslationStrategy) {
32231
+ MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
32232
+ MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
32233
+ MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
32234
+ })(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
32235
+
32236
+ /**
32237
+ * Internal token that allows to register extra callbacks that should be invoked during the
32238
+ * `PlatformRef.destroy` operation. This token is needed to avoid a direct reference to the
32239
+ * `PlatformRef` class (i.e. register the callback via `PlatformRef.onDestroy`), thus making the
32240
+ * entire class tree-shakeable.
32241
+ */
32242
+ const PLATFORM_DESTROY_LISTENERS = new InjectionToken('PlatformDestroyListeners');
32243
+ /**
32244
+ * The Angular platform is the entry point for Angular on a web page.
32245
+ * Each page has exactly one platform. Services (such as reflection) which are common
32246
+ * to every Angular application running on the page are bound in its scope.
32247
+ * A page's platform is initialized implicitly when a platform is created using a platform
32248
+ * factory such as `PlatformBrowser`, or explicitly by calling the `createPlatform()` function.
32249
+ *
32250
+ * @publicApi
32251
+ */
32252
+ class PlatformRef {
32253
+ /** @internal */
32254
+ constructor(_injector) {
32255
+ this._injector = _injector;
32256
+ this._modules = [];
32257
+ this._destroyListeners = [];
32258
+ this._destroyed = false;
32259
+ }
32260
+ /**
32261
+ * Creates an instance of an `@NgModule` for the given platform.
32262
+ *
32263
+ * @deprecated Passing NgModule factories as the `PlatformRef.bootstrapModuleFactory` function
32264
+ * argument is deprecated. Use the `PlatformRef.bootstrapModule` API instead.
32265
+ */
32266
+ bootstrapModuleFactory(moduleFactory, options) {
32267
+ // Note: We need to create the NgZone _before_ we instantiate the module,
32268
+ // as instantiating the module creates some providers eagerly.
32269
+ // So we create a mini parent injector that just contains the new NgZone and
32270
+ // pass that as parent to the NgModuleFactory.
32271
+ const ngZone = getNgZone(options?.ngZone, getNgZoneOptions({
32272
+ eventCoalescing: options?.ngZoneEventCoalescing,
32273
+ runCoalescing: options?.ngZoneRunCoalescing
32274
+ }));
32275
+ // Note: Create ngZoneInjector within ngZone.run so that all of the instantiated services are
32276
+ // created within the Angular zone
32277
+ // Do not try to replace ngZone.run with ApplicationRef#run because ApplicationRef would then be
32278
+ // created outside of the Angular zone.
32279
+ return ngZone.run(() => {
32280
+ const moduleRef = createNgModuleRefWithProviders(moduleFactory.moduleType, this.injector, internalProvideZoneChangeDetection(() => ngZone));
32281
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
32282
+ moduleRef.injector.get(PROVIDED_NG_ZONE, null) !== null) {
32283
+ throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, '`bootstrapModule` does not support `provideZoneChangeDetection`. Use `BootstrapOptions` instead.');
32284
+ }
32285
+ const exceptionHandler = moduleRef.injector.get(ErrorHandler, null);
32286
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && exceptionHandler === null) {
32287
+ throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, 'No ErrorHandler. Is platform module (BrowserModule) included?');
32288
+ }
32289
+ ngZone.runOutsideAngular(() => {
32290
+ const subscription = ngZone.onError.subscribe({
32291
+ next: (error) => {
32292
+ exceptionHandler.handleError(error);
32293
+ }
32294
+ });
32295
+ moduleRef.onDestroy(() => {
32296
+ remove(this._modules, moduleRef);
32297
+ subscription.unsubscribe();
32298
+ });
32299
+ });
32300
+ return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
32301
+ const initStatus = moduleRef.injector.get(ApplicationInitStatus);
32302
+ initStatus.runInitializers();
32303
+ return initStatus.donePromise.then(() => {
32304
+ // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy
32305
+ const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
32306
+ setLocaleId(localeId || DEFAULT_LOCALE_ID);
32307
+ this._moduleDoBootstrap(moduleRef);
32308
+ return moduleRef;
32309
+ });
32310
+ });
32311
+ });
32312
+ }
32313
+ /**
32314
+ * Creates an instance of an `@NgModule` for a given platform.
32315
+ *
32316
+ * @usageNotes
32317
+ * ### Simple Example
32318
+ *
32319
+ * ```typescript
32320
+ * @NgModule({
32321
+ * imports: [BrowserModule]
32322
+ * })
32323
+ * class MyModule {}
32324
+ *
32325
+ * let moduleRef = platformBrowser().bootstrapModule(MyModule);
32326
+ * ```
32327
+ *
32328
+ */
32329
+ bootstrapModule(moduleType, compilerOptions = []) {
32330
+ const options = optionsReducer({}, compilerOptions);
32331
+ return compileNgModuleFactory(this.injector, options, moduleType)
32332
+ .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
32333
+ }
32334
+ _moduleDoBootstrap(moduleRef) {
32335
+ const appRef = moduleRef.injector.get(ApplicationRef);
32336
+ if (moduleRef._bootstrapComponents.length > 0) {
32337
+ moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
32338
+ }
32339
+ else if (moduleRef.instance.ngDoBootstrap) {
32340
+ moduleRef.instance.ngDoBootstrap(appRef);
32341
+ }
32342
+ else {
32343
+ throw new RuntimeError(-403 /* RuntimeErrorCode.BOOTSTRAP_COMPONENTS_NOT_FOUND */, ngDevMode &&
32344
+ `The module ${stringify(moduleRef.instance.constructor)} was bootstrapped, ` +
32345
+ `but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
32346
+ `Please define one of these.`);
32347
+ }
32348
+ this._modules.push(moduleRef);
32349
+ }
32350
+ /**
32351
+ * Registers a listener to be called when the platform is destroyed.
32543
32352
  */
32544
32353
  onDestroy(callback) {
32545
- (typeof ngDevMode === 'undefined' || ngDevMode) && this.warnIfDestroyed();
32546
32354
  this._destroyListeners.push(callback);
32547
- return () => remove(this._destroyListeners, callback);
32548
32355
  }
32549
32356
  /**
32550
- * Destroys an Angular application represented by this `ApplicationRef`. Calling this function
32551
- * will destroy the associated environment injectors as well as all the bootstrapped components
32552
- * with their views.
32357
+ * Retrieves the platform {@link Injector}, which is the parent injector for
32358
+ * every Angular application on the page and provides singleton providers.
32359
+ */
32360
+ get injector() {
32361
+ return this._injector;
32362
+ }
32363
+ /**
32364
+ * Destroys the current Angular platform and all Angular applications on the page.
32365
+ * Destroys all modules and listeners registered with the platform.
32553
32366
  */
32554
32367
  destroy() {
32555
32368
  if (this._destroyed) {
32556
- throw new RuntimeError(406 /* RuntimeErrorCode.APPLICATION_REF_ALREADY_DESTROYED */, ngDevMode && 'This instance of the `ApplicationRef` has already been destroyed.');
32369
+ throw new RuntimeError(404 /* RuntimeErrorCode.PLATFORM_ALREADY_DESTROYED */, ngDevMode && 'The platform has already been destroyed!');
32557
32370
  }
32558
- const injector = this._injector;
32559
- // Check that this injector instance supports destroy operation.
32560
- if (injector.destroy && !injector.destroyed) {
32561
- // Destroying an underlying injector will trigger the `ngOnDestroy` lifecycle
32562
- // hook, which invokes the remaining cleanup actions.
32563
- injector.destroy();
32371
+ this._modules.slice().forEach(module => module.destroy());
32372
+ this._destroyListeners.forEach(listener => listener());
32373
+ const destroyListeners = this._injector.get(PLATFORM_DESTROY_LISTENERS, null);
32374
+ if (destroyListeners) {
32375
+ destroyListeners.forEach(listener => listener());
32376
+ destroyListeners.clear();
32564
32377
  }
32378
+ this._destroyed = true;
32565
32379
  }
32566
32380
  /**
32567
- * Returns the number of attached views.
32381
+ * Indicates whether this instance was destroyed.
32568
32382
  */
32569
- get viewCount() {
32570
- return this._views.length;
32571
- }
32572
- warnIfDestroyed() {
32573
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && this._destroyed) {
32574
- console.warn(formatRuntimeError(406 /* RuntimeErrorCode.APPLICATION_REF_ALREADY_DESTROYED */, 'This instance of the `ApplicationRef` has already been destroyed.'));
32575
- }
32383
+ get destroyed() {
32384
+ return this._destroyed;
32576
32385
  }
32577
- static { this.ɵfac = function ApplicationRef_Factory(t) { return new (t || ApplicationRef)(); }; }
32578
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationRef, factory: ApplicationRef.ɵfac, providedIn: 'root' }); }
32386
+ static { this.ɵfac = function PlatformRef_Factory(t) { return new (t || PlatformRef)(ɵɵinject(Injector)); }; }
32387
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: PlatformRef, factory: PlatformRef.ɵfac, providedIn: 'platform' }); }
32579
32388
  }
32580
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationRef, [{
32389
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PlatformRef, [{
32581
32390
  type: Injectable,
32582
- args: [{ providedIn: 'root' }]
32583
- }], null, null); })();
32584
- function remove(list, el) {
32585
- const index = list.indexOf(el);
32586
- if (index > -1) {
32587
- list.splice(index, 1);
32391
+ args: [{ providedIn: 'platform' }]
32392
+ }], () => [{ type: Injector }], null); })();
32393
+
32394
+ let _platformInjector = null;
32395
+ /**
32396
+ * Internal token to indicate whether having multiple bootstrapped platform should be allowed (only
32397
+ * one bootstrapped platform is allowed by default). This token helps to support SSR scenarios.
32398
+ */
32399
+ const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken');
32400
+ /**
32401
+ * Creates a platform.
32402
+ * Platforms must be created on launch using this function.
32403
+ *
32404
+ * @publicApi
32405
+ */
32406
+ function createPlatform(injector) {
32407
+ if (_platformInjector && !_platformInjector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
32408
+ throw new RuntimeError(400 /* RuntimeErrorCode.MULTIPLE_PLATFORMS */, ngDevMode &&
32409
+ 'There can be only one platform. Destroy the previous one to create a new one.');
32588
32410
  }
32411
+ publishDefaultGlobalUtils();
32412
+ publishSignalConfiguration();
32413
+ _platformInjector = injector;
32414
+ const platform = injector.get(PlatformRef);
32415
+ runPlatformInitializers(injector);
32416
+ return platform;
32589
32417
  }
32590
- function _lastDefined(args) {
32591
- for (let i = args.length - 1; i >= 0; i--) {
32592
- if (args[i] !== undefined) {
32593
- return args[i];
32418
+ /**
32419
+ * Creates a factory for a platform. Can be used to provide or override `Providers` specific to
32420
+ * your application's runtime needs, such as `PLATFORM_INITIALIZER` and `PLATFORM_ID`.
32421
+ * @param parentPlatformFactory Another platform factory to modify. Allows you to compose factories
32422
+ * to build up configurations that might be required by different libraries or parts of the
32423
+ * application.
32424
+ * @param name Identifies the new platform factory.
32425
+ * @param providers A set of dependency providers for platforms created with the new factory.
32426
+ *
32427
+ * @publicApi
32428
+ */
32429
+ function createPlatformFactory(parentPlatformFactory, name, providers = []) {
32430
+ const desc = `Platform: ${name}`;
32431
+ const marker = new InjectionToken(desc);
32432
+ return (extraProviders = []) => {
32433
+ let platform = getPlatform();
32434
+ if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
32435
+ const platformProviders = [...providers, ...extraProviders, { provide: marker, useValue: true }];
32436
+ if (parentPlatformFactory) {
32437
+ parentPlatformFactory(platformProviders);
32438
+ }
32439
+ else {
32440
+ createPlatform(createPlatformInjector(platformProviders, desc));
32441
+ }
32594
32442
  }
32595
- }
32596
- return undefined;
32443
+ return assertPlatform(marker);
32444
+ };
32597
32445
  }
32598
32446
  /**
32599
- * `InjectionToken` used to configure how to call the `ErrorHandler`.
32600
- *
32601
- * `NgZone` is provided by default today so the default (and only) implementation for this
32602
- * is calling `ErrorHandler.handleError` outside of the Angular zone.
32447
+ * Helper function to create an instance of a platform injector (that maintains the 'platform'
32448
+ * scope).
32603
32449
  */
32604
- const INTERNAL_APPLICATION_ERROR_HANDLER = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'internal error handler' : '', {
32605
- providedIn: 'root',
32606
- factory: () => {
32607
- const userErrorHandler = inject(ErrorHandler);
32608
- return userErrorHandler.handleError.bind(undefined);
32609
- }
32610
- });
32611
- function ngZoneApplicationErrorHandlerFactory() {
32612
- const zone = inject(NgZone);
32613
- const userErrorHandler = inject(ErrorHandler);
32614
- return (e) => zone.runOutsideAngular(() => userErrorHandler.handleError(e));
32450
+ function createPlatformInjector(providers = [], name) {
32451
+ return Injector.create({
32452
+ name,
32453
+ providers: [
32454
+ { provide: INJECTOR_SCOPE, useValue: 'platform' },
32455
+ { provide: PLATFORM_DESTROY_LISTENERS, useValue: new Set([() => _platformInjector = null]) },
32456
+ ...providers
32457
+ ],
32458
+ });
32615
32459
  }
32616
- class NgZoneChangeDetectionScheduler {
32617
- constructor() {
32618
- this.zone = inject(NgZone);
32619
- this.applicationRef = inject(ApplicationRef);
32620
- }
32621
- initialize() {
32622
- if (this._onMicrotaskEmptySubscription) {
32623
- return;
32624
- }
32625
- this._onMicrotaskEmptySubscription = this.zone.onMicrotaskEmpty.subscribe({
32626
- next: () => {
32627
- this.zone.run(() => {
32628
- this.applicationRef.tick();
32629
- });
32630
- }
32631
- });
32460
+ /**
32461
+ * Checks that there is currently a platform that contains the given token as a provider.
32462
+ *
32463
+ * @publicApi
32464
+ */
32465
+ function assertPlatform(requiredToken) {
32466
+ const platform = getPlatform();
32467
+ if (!platform) {
32468
+ throw new RuntimeError(401 /* RuntimeErrorCode.PLATFORM_NOT_FOUND */, ngDevMode && 'No platform exists!');
32632
32469
  }
32633
- ngOnDestroy() {
32634
- this._onMicrotaskEmptySubscription?.unsubscribe();
32470
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
32471
+ !platform.injector.get(requiredToken, null)) {
32472
+ throw new RuntimeError(400 /* RuntimeErrorCode.MULTIPLE_PLATFORMS */, 'A platform with a different configuration has been created. Please destroy it first.');
32635
32473
  }
32636
- static { this.ɵfac = function NgZoneChangeDetectionScheduler_Factory(t) { return new (t || NgZoneChangeDetectionScheduler)(); }; }
32637
- static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: NgZoneChangeDetectionScheduler, factory: NgZoneChangeDetectionScheduler.ɵfac, providedIn: 'root' }); }
32474
+ return platform;
32638
32475
  }
32639
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NgZoneChangeDetectionScheduler, [{
32640
- type: Injectable,
32641
- args: [{ providedIn: 'root' }]
32642
- }], null, null); })();
32643
32476
  /**
32644
- * Internal token used to verify that `provideZoneChangeDetection` is not used
32645
- * with the bootstrapModule API.
32477
+ * Returns the current platform.
32478
+ *
32479
+ * @publicApi
32646
32480
  */
32647
- const PROVIDED_NG_ZONE = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'provideZoneChangeDetection token' : '');
32648
- function internalProvideZoneChangeDetection(ngZoneFactory) {
32649
- return [
32650
- { provide: NgZone, useFactory: ngZoneFactory },
32651
- {
32652
- provide: ENVIRONMENT_INITIALIZER,
32653
- multi: true,
32654
- useFactory: () => {
32655
- const ngZoneChangeDetectionScheduler = inject(NgZoneChangeDetectionScheduler, { optional: true });
32656
- if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
32657
- ngZoneChangeDetectionScheduler === null) {
32658
- throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, `A required Injectable was not found in the dependency injection tree. ` +
32659
- 'If you are bootstrapping an NgModule, make sure that the `BrowserModule` is imported.');
32660
- }
32661
- return () => ngZoneChangeDetectionScheduler.initialize();
32662
- },
32663
- },
32664
- { provide: INTERNAL_APPLICATION_ERROR_HANDLER, useFactory: ngZoneApplicationErrorHandlerFactory },
32665
- { provide: ZONE_IS_STABLE_OBSERVABLE, useFactory: isStableFactory },
32666
- ];
32481
+ function getPlatform() {
32482
+ return _platformInjector?.get(PlatformRef) ?? null;
32667
32483
  }
32668
32484
  /**
32669
- * Provides `NgZone`-based change detection for the application bootstrapped using
32670
- * `bootstrapApplication`.
32671
- *
32672
- * `NgZone` is already provided in applications by default. This provider allows you to configure
32673
- * options like `eventCoalescing` in the `NgZone`.
32674
- * This provider is not available for `platformBrowser().bootstrapModule`, which uses
32675
- * `BootstrapOptions` instead.
32676
- *
32677
- * @usageNotes
32678
- * ```typescript
32679
- * bootstrapApplication(MyApp, {providers: [
32680
- * provideZoneChangeDetection({eventCoalescing: true}),
32681
- * ]});
32682
- * ```
32485
+ * Destroys the current Angular platform and all Angular applications on the page.
32486
+ * Destroys all modules and listeners registered with the platform.
32683
32487
  *
32684
32488
  * @publicApi
32685
- * @see {@link bootstrapApplication}
32686
- * @see {@link NgZoneOptions}
32687
32489
  */
32688
- function provideZoneChangeDetection(options) {
32689
- const zoneProviders = internalProvideZoneChangeDetection(() => new NgZone(getNgZoneOptions(options)));
32690
- return makeEnvironmentProviders([
32691
- (typeof ngDevMode === 'undefined' || ngDevMode) ? { provide: PROVIDED_NG_ZONE, useValue: true } :
32692
- [],
32693
- zoneProviders,
32694
- ]);
32490
+ function destroyPlatform() {
32491
+ getPlatform()?.destroy();
32695
32492
  }
32696
- let whenStableStore;
32697
32493
  /**
32698
- * Returns a Promise that resolves when the application becomes stable after this method is called
32699
- * the first time.
32494
+ * The goal of this function is to bootstrap a platform injector,
32495
+ * but avoid referencing `PlatformRef` class.
32496
+ * This function is needed for bootstrapping a Standalone Component.
32700
32497
  */
32701
- function whenStable(applicationRef) {
32702
- whenStableStore ??= new WeakMap();
32703
- const cachedWhenStable = whenStableStore.get(applicationRef);
32704
- if (cachedWhenStable) {
32705
- return cachedWhenStable;
32706
- }
32707
- const whenStablePromise = applicationRef.isStable.pipe(first((isStable) => isStable)).toPromise().then(() => void 0);
32708
- whenStableStore.set(applicationRef, whenStablePromise);
32709
- // Be a good citizen and clean the store `onDestroy` even though we are using `WeakMap`.
32710
- applicationRef.onDestroy(() => whenStableStore?.delete(applicationRef));
32711
- return whenStablePromise;
32498
+ function createOrReusePlatformInjector(providers = []) {
32499
+ // If a platform injector already exists, it means that the platform
32500
+ // is already bootstrapped and no additional actions are required.
32501
+ if (_platformInjector)
32502
+ return _platformInjector;
32503
+ publishDefaultGlobalUtils();
32504
+ // Otherwise, setup a new platform injector and run platform initializers.
32505
+ const injector = createPlatformInjector(providers);
32506
+ _platformInjector = injector;
32507
+ publishSignalConfiguration();
32508
+ runPlatformInitializers(injector);
32509
+ return injector;
32510
+ }
32511
+ function runPlatformInitializers(injector) {
32512
+ const inits = injector.get(PLATFORM_INITIALIZER, null);
32513
+ inits?.forEach((init) => init());
32712
32514
  }
32713
32515
 
32714
32516
  /**
@@ -33868,14 +33670,7 @@ function signalSetFn(node, newValue) {
33868
33670
  if (!producerUpdatesAllowed()) {
33869
33671
  throwInvalidWriteToSignalError();
33870
33672
  }
33871
- const value = node.value;
33872
- if (Object.is(value, newValue)) {
33873
- if (typeof ngDevMode !== 'undefined' && ngDevMode && !node.equal(value, newValue)) {
33874
- console.warn('Signal value equality implementations should always return `true` for' +
33875
- ' values that are the same according to `Object.is` but returned `false` instead.');
33876
- }
33877
- }
33878
- else if (!node.equal(value, newValue)) {
33673
+ if (!node.equal(node.value, newValue)) {
33879
33674
  node.value = newValue;
33880
33675
  signalValueChanged(node);
33881
33676
  }
@@ -33989,6 +33784,244 @@ function setAlternateWeakRefImpl(impl) {
33989
33784
  // TODO: remove this function
33990
33785
  }
33991
33786
 
33787
+ // A delay in milliseconds before the scan is run after onLoad, to avoid any
33788
+ // potential race conditions with other LCP-related functions. This delay
33789
+ // happens outside of the main JavaScript execution and will only effect the timing
33790
+ // on when the warning becomes visible in the console.
33791
+ const SCAN_DELAY = 200;
33792
+ const OVERSIZED_IMAGE_TOLERANCE = 1200;
33793
+ class ImagePerformanceWarning {
33794
+ constructor() {
33795
+ // Map of full image URLs -> original `ngSrc` values.
33796
+ this.window = null;
33797
+ this.observer = null;
33798
+ this.options = inject(IMAGE_CONFIG);
33799
+ this.ngZone = inject(NgZone);
33800
+ }
33801
+ start() {
33802
+ if (typeof PerformanceObserver === 'undefined' ||
33803
+ (this.options?.disableImageSizeWarning && this.options?.disableImageLazyLoadWarning)) {
33804
+ return;
33805
+ }
33806
+ this.observer = this.initPerformanceObserver();
33807
+ const doc = getDocument();
33808
+ const win = doc.defaultView;
33809
+ if (typeof win !== 'undefined') {
33810
+ this.window = win;
33811
+ // Wait to avoid race conditions where LCP image triggers
33812
+ // load event before it's recorded by the performance observer
33813
+ const waitToScan = () => {
33814
+ setTimeout(this.scanImages.bind(this), SCAN_DELAY);
33815
+ };
33816
+ // Angular doesn't have to run change detection whenever any asynchronous tasks are invoked in
33817
+ // the scope of this functionality.
33818
+ this.ngZone.runOutsideAngular(() => {
33819
+ // Consider the case when the application is created and destroyed multiple times.
33820
+ // Typically, applications are created instantly once the page is loaded, and the
33821
+ // `window.load` listener is always triggered. However, the `window.load` event will never
33822
+ // be fired if the page is loaded, and the application is created later. Checking for
33823
+ // `readyState` is the easiest way to determine whether the page has been loaded or not.
33824
+ if (doc.readyState === 'complete') {
33825
+ waitToScan();
33826
+ }
33827
+ else {
33828
+ this.window?.addEventListener('load', waitToScan, { once: true });
33829
+ }
33830
+ });
33831
+ }
33832
+ }
33833
+ ngOnDestroy() {
33834
+ this.observer?.disconnect();
33835
+ }
33836
+ initPerformanceObserver() {
33837
+ if (typeof PerformanceObserver === 'undefined') {
33838
+ return null;
33839
+ }
33840
+ const observer = new PerformanceObserver((entryList) => {
33841
+ const entries = entryList.getEntries();
33842
+ if (entries.length === 0)
33843
+ return;
33844
+ // We use the latest entry produced by the `PerformanceObserver` as the best
33845
+ // signal on which element is actually an LCP one. As an example, the first image to load on
33846
+ // a page, by virtue of being the only thing on the page so far, is often a LCP candidate
33847
+ // and gets reported by PerformanceObserver, but isn't necessarily the LCP element.
33848
+ const lcpElement = entries[entries.length - 1];
33849
+ // Cast to `any` due to missing `element` on the `LargestContentfulPaint` type of entry.
33850
+ // See https://developer.mozilla.org/en-US/docs/Web/API/LargestContentfulPaint
33851
+ const imgSrc = lcpElement.element?.src ?? '';
33852
+ // Exclude `data:` and `blob:` URLs, since they are fetched resources.
33853
+ if (imgSrc.startsWith('data:') || imgSrc.startsWith('blob:'))
33854
+ return;
33855
+ this.lcpImageUrl = imgSrc;
33856
+ });
33857
+ observer.observe({ type: 'largest-contentful-paint', buffered: true });
33858
+ return observer;
33859
+ }
33860
+ scanImages() {
33861
+ const images = getDocument().querySelectorAll('img');
33862
+ let lcpElementFound, lcpElementLoadedCorrectly = false;
33863
+ images.forEach(image => {
33864
+ if (!this.options?.disableImageSizeWarning) {
33865
+ for (const image of images) {
33866
+ // Image elements using the NgOptimizedImage directive are excluded,
33867
+ // as that directive has its own version of this check.
33868
+ if (!image.getAttribute('ng-img') && this.isOversized(image)) {
33869
+ logOversizedImageWarning(image.src);
33870
+ }
33871
+ }
33872
+ }
33873
+ if (!this.options?.disableImageLazyLoadWarning && this.lcpImageUrl) {
33874
+ if (image.src === this.lcpImageUrl) {
33875
+ lcpElementFound = true;
33876
+ if (image.loading !== 'lazy' || image.getAttribute('ng-img')) {
33877
+ // This variable is set to true and never goes back to false to account
33878
+ // for the case where multiple images have the same src url, and some
33879
+ // have lazy loading while others don't.
33880
+ // Also ignore NgOptimizedImage because there's a different warning for that.
33881
+ lcpElementLoadedCorrectly = true;
33882
+ }
33883
+ }
33884
+ }
33885
+ });
33886
+ if (lcpElementFound && !lcpElementLoadedCorrectly && this.lcpImageUrl &&
33887
+ !this.options?.disableImageLazyLoadWarning) {
33888
+ logLazyLCPWarning(this.lcpImageUrl);
33889
+ }
33890
+ }
33891
+ isOversized(image) {
33892
+ if (!this.window) {
33893
+ return false;
33894
+ }
33895
+ const computedStyle = this.window.getComputedStyle(image);
33896
+ let renderedWidth = parseFloat(computedStyle.getPropertyValue('width'));
33897
+ let renderedHeight = parseFloat(computedStyle.getPropertyValue('height'));
33898
+ const boxSizing = computedStyle.getPropertyValue('box-sizing');
33899
+ const objectFit = computedStyle.getPropertyValue('object-fit');
33900
+ if (objectFit === `cover`) {
33901
+ // Object fit cover may indicate a use case such as a sprite sheet where
33902
+ // this warning does not apply.
33903
+ return false;
33904
+ }
33905
+ if (boxSizing === 'border-box') {
33906
+ const paddingTop = computedStyle.getPropertyValue('padding-top');
33907
+ const paddingRight = computedStyle.getPropertyValue('padding-right');
33908
+ const paddingBottom = computedStyle.getPropertyValue('padding-bottom');
33909
+ const paddingLeft = computedStyle.getPropertyValue('padding-left');
33910
+ renderedWidth -= parseFloat(paddingRight) + parseFloat(paddingLeft);
33911
+ renderedHeight -= parseFloat(paddingTop) + parseFloat(paddingBottom);
33912
+ }
33913
+ const intrinsicWidth = image.naturalWidth;
33914
+ const intrinsicHeight = image.naturalHeight;
33915
+ const recommendedWidth = this.window.devicePixelRatio * renderedWidth;
33916
+ const recommendedHeight = this.window.devicePixelRatio * renderedHeight;
33917
+ const oversizedWidth = (intrinsicWidth - recommendedWidth) >= OVERSIZED_IMAGE_TOLERANCE;
33918
+ const oversizedHeight = (intrinsicHeight - recommendedHeight) >= OVERSIZED_IMAGE_TOLERANCE;
33919
+ return oversizedWidth || oversizedHeight;
33920
+ }
33921
+ static { this.ɵfac = function ImagePerformanceWarning_Factory(t) { return new (t || ImagePerformanceWarning)(); }; }
33922
+ static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ImagePerformanceWarning, factory: ImagePerformanceWarning.ɵfac, providedIn: 'root' }); }
33923
+ }
33924
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ImagePerformanceWarning, [{
33925
+ type: Injectable,
33926
+ args: [{ providedIn: 'root' }]
33927
+ }], null, null); })();
33928
+ function logLazyLCPWarning(src) {
33929
+ console.warn(formatRuntimeError(-913 /* RuntimeErrorCode.IMAGE_PERFORMANCE_WARNING */, `An image with src ${src} is the Largest Contentful Paint (LCP) element ` +
33930
+ `but was given a "loading" value of "lazy", which can negatively impact ` +
33931
+ `application loading performance. This warning can be addressed by ` +
33932
+ `changing the loading value of the LCP image to "eager", or by using the ` +
33933
+ `NgOptimizedImage directive's prioritization utilities. For more ` +
33934
+ `information about addressing or disabling this warning, see ` +
33935
+ `https://angular.io/errors/NG0913`));
33936
+ }
33937
+ function logOversizedImageWarning(src) {
33938
+ console.warn(formatRuntimeError(-913 /* RuntimeErrorCode.IMAGE_PERFORMANCE_WARNING */, `An image with src ${src} has intrinsic file dimensions much larger than its ` +
33939
+ `rendered size. This can negatively impact application loading performance. ` +
33940
+ `For more information about addressing or disabling this warning, see ` +
33941
+ `https://angular.io/errors/NG0913`));
33942
+ }
33943
+
33944
+ /**
33945
+ * Internal create application API that implements the core application creation logic and optional
33946
+ * bootstrap logic.
33947
+ *
33948
+ * Platforms (such as `platform-browser`) may require different set of application and platform
33949
+ * providers for an application to function correctly. As a result, platforms may use this function
33950
+ * internally and supply the necessary providers during the bootstrap, while exposing
33951
+ * platform-specific APIs as a part of their public API.
33952
+ *
33953
+ * @returns A promise that returns an `ApplicationRef` instance once resolved.
33954
+ */
33955
+ function internalCreateApplication(config) {
33956
+ try {
33957
+ const { rootComponent, appProviders, platformProviders } = config;
33958
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && rootComponent !== undefined) {
33959
+ assertStandaloneComponentType(rootComponent);
33960
+ }
33961
+ const platformInjector = createOrReusePlatformInjector(platformProviders);
33962
+ // Create root application injector based on a set of providers configured at the platform
33963
+ // bootstrap level as well as providers passed to the bootstrap call by a user.
33964
+ const allAppProviders = [
33965
+ provideZoneChangeDetection(),
33966
+ ...(appProviders || []),
33967
+ ];
33968
+ const adapter = new EnvironmentNgModuleRefAdapter({
33969
+ providers: allAppProviders,
33970
+ parent: platformInjector,
33971
+ debugName: (typeof ngDevMode === 'undefined' || ngDevMode) ? 'Environment Injector' : '',
33972
+ // We skip environment initializers because we need to run them inside the NgZone, which
33973
+ // happens after we get the NgZone instance from the Injector.
33974
+ runEnvironmentInitializers: false,
33975
+ });
33976
+ const envInjector = adapter.injector;
33977
+ const ngZone = envInjector.get(NgZone);
33978
+ return ngZone.run(() => {
33979
+ envInjector.resolveInjectorInitializers();
33980
+ const exceptionHandler = envInjector.get(ErrorHandler, null);
33981
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && !exceptionHandler) {
33982
+ throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, 'No `ErrorHandler` found in the Dependency Injection tree.');
33983
+ }
33984
+ let onErrorSubscription;
33985
+ ngZone.runOutsideAngular(() => {
33986
+ onErrorSubscription = ngZone.onError.subscribe({
33987
+ next: (error) => {
33988
+ exceptionHandler.handleError(error);
33989
+ }
33990
+ });
33991
+ });
33992
+ // If the whole platform is destroyed, invoke the `destroy` method
33993
+ // for all bootstrapped applications as well.
33994
+ const destroyListener = () => envInjector.destroy();
33995
+ const onPlatformDestroyListeners = platformInjector.get(PLATFORM_DESTROY_LISTENERS);
33996
+ onPlatformDestroyListeners.add(destroyListener);
33997
+ envInjector.onDestroy(() => {
33998
+ onErrorSubscription.unsubscribe();
33999
+ onPlatformDestroyListeners.delete(destroyListener);
34000
+ });
34001
+ return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
34002
+ const initStatus = envInjector.get(ApplicationInitStatus);
34003
+ initStatus.runInitializers();
34004
+ return initStatus.donePromise.then(() => {
34005
+ const localeId = envInjector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
34006
+ setLocaleId(localeId || DEFAULT_LOCALE_ID);
34007
+ const appRef = envInjector.get(ApplicationRef);
34008
+ if (rootComponent !== undefined) {
34009
+ appRef.bootstrap(rootComponent);
34010
+ }
34011
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
34012
+ const imagePerformanceService = envInjector.get(ImagePerformanceWarning);
34013
+ imagePerformanceService.start();
34014
+ }
34015
+ return appRef;
34016
+ });
34017
+ });
34018
+ });
34019
+ }
34020
+ catch (e) {
34021
+ return Promise.reject(e);
34022
+ }
34023
+ }
34024
+
33992
34025
  /**
33993
34026
  * Retrieves all defer blocks in a given LView.
33994
34027
  *