@angular/core 21.0.0-next.8 → 21.0.0-rc.0

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 (84) hide show
  1. package/fesm2022/_attribute-chunk.mjs +2 -14
  2. package/fesm2022/_attribute-chunk.mjs.map +1 -1
  3. package/fesm2022/_debug_node-chunk.mjs +15214 -28375
  4. package/fesm2022/_debug_node-chunk.mjs.map +1 -1
  5. package/fesm2022/_effect-chunk.mjs +402 -120
  6. package/fesm2022/_effect-chunk.mjs.map +1 -1
  7. package/fesm2022/_effect-chunk2.mjs +2951 -0
  8. package/fesm2022/_effect-chunk2.mjs.map +1 -0
  9. package/fesm2022/_not_found-chunk.mjs +18 -35
  10. package/fesm2022/_not_found-chunk.mjs.map +1 -1
  11. package/fesm2022/_resource-chunk.mjs +316 -563
  12. package/fesm2022/_resource-chunk.mjs.map +1 -1
  13. package/fesm2022/_untracked-chunk.mjs +96 -0
  14. package/fesm2022/_untracked-chunk.mjs.map +1 -0
  15. package/fesm2022/_weak_ref-chunk.mjs +2 -4
  16. package/fesm2022/_weak_ref-chunk.mjs.map +1 -1
  17. package/fesm2022/core.mjs +2466 -4309
  18. package/fesm2022/core.mjs.map +1 -1
  19. package/fesm2022/primitives-di.mjs +9 -9
  20. package/fesm2022/primitives-di.mjs.map +1 -1
  21. package/fesm2022/primitives-event-dispatch.mjs +626 -1460
  22. package/fesm2022/primitives-event-dispatch.mjs.map +1 -1
  23. package/fesm2022/primitives-signals.mjs +157 -191
  24. package/fesm2022/primitives-signals.mjs.map +1 -1
  25. package/fesm2022/rxjs-interop.mjs +208 -308
  26. package/fesm2022/rxjs-interop.mjs.map +1 -1
  27. package/fesm2022/testing.mjs +2305 -3164
  28. package/fesm2022/testing.mjs.map +1 -1
  29. package/package.json +8 -2
  30. package/resources/best-practices.md +56 -0
  31. package/schematics/bundles/add-bootstrap-context-to-server-main.cjs +7 -25
  32. package/schematics/bundles/application-config-core.cjs +8 -19
  33. package/schematics/bundles/{apply_import_manager-CBLmogDD.cjs → apply_import_manager-1Zs_gpB6.cjs} +4 -5
  34. package/schematics/bundles/bootstrap-options-migration.cjs +93 -132
  35. package/schematics/bundles/cleanup-unused-imports.cjs +9 -13
  36. package/schematics/bundles/common-to-standalone-migration.cjs +381 -0
  37. package/schematics/bundles/{compiler_host-T6xncpiw.cjs → compiler_host-DBwYMlTo.cjs} +10 -11
  38. package/schematics/bundles/control-flow-migration.cjs +29 -31
  39. package/schematics/bundles/{imports-DwPXlGFl.cjs → imports-DP72APSx.cjs} +1 -23
  40. package/schematics/bundles/{index-DWSaRJdz.cjs → index-B7I9sIUx.cjs} +36 -37
  41. package/schematics/bundles/inject-migration.cjs +9 -26
  42. package/schematics/bundles/leading_space-D9nQ8UQC.cjs +1 -1
  43. package/schematics/bundles/{migrate_ts_type_references-Cu-FR4L5.cjs → migrate_ts_type_references-UGIUl7En.cjs} +458 -24
  44. package/schematics/bundles/{ng_component_template-BkWiUuGG.cjs → ng_component_template-Dsuq1Lw7.cjs} +4 -5
  45. package/schematics/bundles/{ng_decorators-BI0uV7KI.cjs → ng_decorators-DSFlWYQY.cjs} +2 -2
  46. package/schematics/bundles/ngclass-to-class-migration.cjs +16 -19
  47. package/schematics/bundles/ngstyle-to-style-migration.cjs +15 -18
  48. package/schematics/bundles/nodes-B16H9JUd.cjs +1 -1
  49. package/schematics/bundles/output-migration.cjs +16 -19
  50. package/schematics/bundles/{parse_html-C97tKKp3.cjs → parse_html-8VLCL37B.cjs} +5 -5
  51. package/schematics/bundles/{project_paths-C6g3lqjX.cjs → project_paths-DvD50ouC.cjs} +14 -247
  52. package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.cjs +90 -0
  53. package/schematics/bundles/property_name-BBwFuqMe.cjs +1 -1
  54. package/schematics/bundles/route-lazy-loading.cjs +9 -25
  55. package/schematics/bundles/router-current-navigation.cjs +6 -17
  56. package/schematics/bundles/router-last-successful-navigation.cjs +6 -17
  57. package/schematics/bundles/router-testing-module-migration.cjs +7 -18
  58. package/schematics/bundles/self-closing-tags-migration.cjs +14 -17
  59. package/schematics/bundles/signal-input-migration.cjs +23 -26
  60. package/schematics/bundles/signal-queries-migration.cjs +22 -25
  61. package/schematics/bundles/signals.cjs +10 -13
  62. package/schematics/bundles/standalone-migration.cjs +22 -56
  63. package/schematics/bundles/symbol-BObKoqes.cjs +1 -1
  64. package/schematics/collection.json +6 -0
  65. package/schematics/migrations/common-to-standalone-migration/schema.json +14 -0
  66. package/types/_api-chunk.d.ts +1 -1
  67. package/types/_chrome_dev_tools_performance-chunk.d.ts +20 -12
  68. package/types/_discovery-chunk.d.ts +18 -14
  69. package/types/_effect-chunk.d.ts +1 -1
  70. package/types/_event_dispatcher-chunk.d.ts +1 -1
  71. package/types/_formatter-chunk.d.ts +4 -3
  72. package/types/_weak_ref-chunk.d.ts +1 -1
  73. package/types/core.d.ts +49 -100
  74. package/types/primitives-di.d.ts +1 -1
  75. package/types/primitives-event-dispatch.d.ts +1 -1
  76. package/types/primitives-signals.d.ts +2 -2
  77. package/types/rxjs-interop.d.ts +1 -1
  78. package/types/testing.d.ts +1 -1
  79. package/fesm2022/_root_effect_scheduler-chunk.mjs +0 -4630
  80. package/fesm2022/_root_effect_scheduler-chunk.mjs.map +0 -1
  81. package/fesm2022/_signal-chunk.mjs +0 -581
  82. package/fesm2022/_signal-chunk.mjs.map +0 -1
  83. package/schematics/bundles/index-BnmACOsq.cjs +0 -22319
  84. package/schematics/bundles/project_tsconfig_paths-CdhVNYMk.cjs +0 -51583
@@ -1,4630 +0,0 @@
1
- /**
2
- * @license Angular v21.0.0-next.8
3
- * (c) 2010-2025 Google LLC. https://angular.dev/
4
- * License: MIT
5
- */
6
-
7
- import { getActiveConsumer, setActiveConsumer as setActiveConsumer$1, SIGNAL, createSignal } from './_signal-chunk.mjs';
8
- import { isNotFound, getCurrentInjector, setCurrentInjector } from './_not_found-chunk.mjs';
9
- import { setActiveConsumer } from '@angular/core/primitives/signals';
10
- import { isNotFound as isNotFound$1 } from '@angular/core/primitives/di';
11
- import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';
12
-
13
- /**
14
- * @description Represents the version of Angular
15
- *
16
- * @publicApi
17
- */
18
- class Version {
19
- full;
20
- major;
21
- minor;
22
- patch;
23
- constructor(full) {
24
- this.full = full;
25
- const parts = full.split('.');
26
- this.major = parts[0];
27
- this.minor = parts[1];
28
- this.patch = parts.slice(2).join('.');
29
- }
30
- }
31
- /**
32
- * @publicApi
33
- */
34
- const VERSION = /* @__PURE__ */ new Version('21.0.0-next.8');
35
-
36
- /**
37
- * Base URL for the error details page.
38
- *
39
- * Keep this constant in sync across:
40
- * - packages/compiler-cli/src/ngtsc/diagnostics/src/error_details_base_url.ts
41
- * - packages/core/src/error_details_base_url.ts
42
- */
43
- const ERROR_DETAILS_PAGE_BASE_URL = (() => {
44
- const versionSubDomain = VERSION.major !== '0' ? `v${VERSION.major}.` : '';
45
- return `https://${versionSubDomain}angular.dev/errors`;
46
- })();
47
- /**
48
- * URL for the XSS security documentation.
49
- */
50
- const XSS_SECURITY_URL = 'https://angular.dev/best-practices/security#preventing-cross-site-scripting-xss';
51
-
52
- /**
53
- * Class that represents a runtime error.
54
- * Formats and outputs the error message in a consistent way.
55
- *
56
- * Example:
57
- * ```ts
58
- * throw new RuntimeError(
59
- * RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED,
60
- * ngDevMode && 'Injector has already been destroyed.');
61
- * ```
62
- *
63
- * Note: the `message` argument contains a descriptive error message as a string in development
64
- * mode (when the `ngDevMode` is defined). In production mode (after tree-shaking pass), the
65
- * `message` argument becomes `false`, thus we account for it in the typings and the runtime
66
- * logic.
67
- */
68
- class RuntimeError extends Error {
69
- code;
70
- constructor(code, message) {
71
- super(formatRuntimeError(code, message));
72
- this.code = code;
73
- }
74
- }
75
- function formatRuntimeErrorCode(code) {
76
- // Error code might be a negative number, which is a special marker that instructs the logic to
77
- // generate a link to the error details page on angular.io.
78
- // We also prepend `0` to non-compile-time errors.
79
- return `NG0${Math.abs(code)}`;
80
- }
81
- /**
82
- * Called to format a runtime error.
83
- * See additional info on the `message` argument type in the `RuntimeError` class description.
84
- */
85
- function formatRuntimeError(code, message) {
86
- const fullCode = formatRuntimeErrorCode(code);
87
- let errorMessage = `${fullCode}${message ? ': ' + message : ''}`;
88
- if (ngDevMode && code < 0) {
89
- const addPeriodSeparator = !errorMessage.match(/[.,;!?\n]$/);
90
- const separator = addPeriodSeparator ? '.' : '';
91
- errorMessage = `${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
92
- }
93
- return errorMessage;
94
- }
95
-
96
- const _global = globalThis;
97
-
98
- function ngDevModeResetPerfCounters() {
99
- const locationString = typeof location !== 'undefined' ? location.toString() : '';
100
- const newCounters = {
101
- hydratedNodes: 0,
102
- hydratedComponents: 0,
103
- dehydratedViewsRemoved: 0,
104
- dehydratedViewsCleanupRuns: 0,
105
- componentsSkippedHydration: 0,
106
- deferBlocksWithIncrementalHydration: 0,
107
- };
108
- // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
109
- const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
110
- if (!allowNgDevModeTrue) {
111
- _global['ngDevMode'] = false;
112
- }
113
- else {
114
- if (typeof _global['ngDevMode'] !== 'object') {
115
- _global['ngDevMode'] = {};
116
- }
117
- Object.assign(_global['ngDevMode'], newCounters);
118
- }
119
- return newCounters;
120
- }
121
- /**
122
- * This function checks to see if the `ngDevMode` has been set. If yes,
123
- * then we honor it, otherwise we default to dev mode with additional checks.
124
- *
125
- * The idea is that unless we are doing production build where we explicitly
126
- * set `ngDevMode == false` we should be helping the developer by providing
127
- * as much early warning and errors as possible.
128
- *
129
- * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions
130
- * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode
131
- * is defined for the entire instruction set.
132
- *
133
- * When checking `ngDevMode` on toplevel, always init it before referencing it
134
- * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can
135
- * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595.
136
- *
137
- * Details on possible values for `ngDevMode` can be found on its docstring.
138
- */
139
- function initNgDevMode() {
140
- // The below checks are to ensure that calling `initNgDevMode` multiple times does not
141
- // reset the counters.
142
- // If the `ngDevMode` is not an object, then it means we have not created the perf counters
143
- // yet.
144
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
145
- if (typeof ngDevMode !== 'object' || Object.keys(ngDevMode).length === 0) {
146
- ngDevModeResetPerfCounters();
147
- }
148
- return typeof ngDevMode !== 'undefined' && !!ngDevMode;
149
- }
150
- return false;
151
- }
152
-
153
- function getClosureSafeProperty(objWithPropertyToExtract) {
154
- for (let key in objWithPropertyToExtract) {
155
- if (objWithPropertyToExtract[key] === getClosureSafeProperty) {
156
- return key;
157
- }
158
- }
159
- // Cannot change it to `RuntimeError` because the `util` target cannot
160
- // circularly depend on the `core` target.
161
- throw Error(typeof ngDevMode !== 'undefined' && ngDevMode
162
- ? 'Could not find renamed property on target object.'
163
- : '');
164
- }
165
- /**
166
- * Sets properties on a target object from a source object, but only if
167
- * the property doesn't already exist on the target object.
168
- * @param target The target to set properties on
169
- * @param source The source of the property keys and values to set
170
- */
171
- function fillProperties(target, source) {
172
- for (const key in source) {
173
- if (source.hasOwnProperty(key) && !target.hasOwnProperty(key)) {
174
- target[key] = source[key];
175
- }
176
- }
177
- }
178
-
179
- function stringify(token) {
180
- if (typeof token === 'string') {
181
- return token;
182
- }
183
- if (Array.isArray(token)) {
184
- return `[${token.map(stringify).join(', ')}]`;
185
- }
186
- if (token == null) {
187
- return '' + token;
188
- }
189
- const name = token.overriddenName || token.name;
190
- if (name) {
191
- return `${name}`;
192
- }
193
- const result = token.toString();
194
- if (result == null) {
195
- return '' + result;
196
- }
197
- const newLineIndex = result.indexOf('\n');
198
- return newLineIndex >= 0 ? result.slice(0, newLineIndex) : result;
199
- }
200
- /**
201
- * Concatenates two strings with separator, allocating new strings only when necessary.
202
- *
203
- * @param before before string.
204
- * @param separator separator string.
205
- * @param after after string.
206
- * @returns concatenated string.
207
- */
208
- function concatStringsWithSpace(before, after) {
209
- if (!before)
210
- return after || '';
211
- if (!after)
212
- return before;
213
- return `${before} ${after}`;
214
- }
215
- /**
216
- * Ellipses the string in the middle when longer than the max length
217
- *
218
- * @param string
219
- * @param maxLength of the output string
220
- * @returns ellipsed string with ... in the middle
221
- */
222
- function truncateMiddle(str, maxLength = 100) {
223
- if (!str || maxLength < 1 || str.length <= maxLength)
224
- return str;
225
- if (maxLength == 1)
226
- return str.substring(0, 1) + '...';
227
- const halfLimit = Math.round(maxLength / 2);
228
- return str.substring(0, halfLimit) + '...' + str.substring(str.length - halfLimit);
229
- }
230
-
231
- const __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty });
232
- /**
233
- * Allows to refer to references which are not yet defined.
234
- *
235
- * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
236
- * DI is declared, but not yet defined. It is also used when the `token` which we use when creating
237
- * a query is not yet defined.
238
- *
239
- * `forwardRef` is also used to break circularities in standalone components imports.
240
- *
241
- * @usageNotes
242
- * ### Circular dependency example
243
- * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'}
244
- *
245
- * ### Circular standalone reference import example
246
- * ```angular-ts
247
- * @Component({
248
- * imports: [ChildComponent],
249
- * selector: 'app-parent',
250
- * template: `<app-child [hideParent]="hideParent()"></app-child>`,
251
- * })
252
- * export class ParentComponent {
253
- * hideParent = input.required<boolean>();
254
- * }
255
- *
256
- *
257
- * @Component({
258
- * imports: [forwardRef(() => ParentComponent)],
259
- * selector: 'app-child',
260
- * template: `
261
- * @if(!hideParent() {
262
- * <app-parent/>
263
- * }
264
- * `,
265
- * })
266
- * export class ChildComponent {
267
- * hideParent = input.required<boolean>();
268
- * }
269
- * ```
270
- *
271
- * @publicApi
272
- */
273
- function forwardRef(forwardRefFn) {
274
- forwardRefFn.__forward_ref__ = forwardRef;
275
- forwardRefFn.toString = function () {
276
- return stringify(this());
277
- };
278
- return forwardRefFn;
279
- }
280
- /**
281
- * Lazily retrieves the reference value from a forwardRef.
282
- *
283
- * Acts as the identity function when given a non-forward-ref value.
284
- *
285
- * @usageNotes
286
- * ### Example
287
- *
288
- * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'}
289
- *
290
- * @see {@link forwardRef}
291
- * @publicApi
292
- */
293
- function resolveForwardRef(type) {
294
- return isForwardRef(type) ? type() : type;
295
- }
296
- /** Checks whether a function is wrapped by a `forwardRef`. */
297
- function isForwardRef(fn) {
298
- return (typeof fn === 'function' &&
299
- fn.hasOwnProperty(__forward_ref__) &&
300
- fn.__forward_ref__ === forwardRef);
301
- }
302
-
303
- // The functions in this file verify that the assumptions we are making
304
- // about state in an instruction are correct before implementing any logic.
305
- // They are meant only to be called in dev mode as sanity checks.
306
- function assertNumber(actual, msg) {
307
- if (!(typeof actual === 'number')) {
308
- throwError(msg, typeof actual, 'number', '===');
309
- }
310
- }
311
- function assertNumberInRange(actual, minInclusive, maxInclusive) {
312
- assertNumber(actual, 'Expected a number');
313
- assertLessThanOrEqual(actual, maxInclusive, 'Expected number to be less than or equal to');
314
- assertGreaterThanOrEqual(actual, minInclusive, 'Expected number to be greater than or equal to');
315
- }
316
- function assertString(actual, msg) {
317
- if (!(typeof actual === 'string')) {
318
- throwError(msg, actual === null ? 'null' : typeof actual, 'string', '===');
319
- }
320
- }
321
- function assertFunction(actual, msg) {
322
- if (!(typeof actual === 'function')) {
323
- throwError(msg, actual === null ? 'null' : typeof actual, 'function', '===');
324
- }
325
- }
326
- function assertEqual(actual, expected, msg) {
327
- if (!(actual == expected)) {
328
- throwError(msg, actual, expected, '==');
329
- }
330
- }
331
- function assertNotEqual(actual, expected, msg) {
332
- if (!(actual != expected)) {
333
- throwError(msg, actual, expected, '!=');
334
- }
335
- }
336
- function assertSame(actual, expected, msg) {
337
- if (!(actual === expected)) {
338
- throwError(msg, actual, expected, '===');
339
- }
340
- }
341
- function assertNotSame(actual, expected, msg) {
342
- if (!(actual !== expected)) {
343
- throwError(msg, actual, expected, '!==');
344
- }
345
- }
346
- function assertLessThan(actual, expected, msg) {
347
- if (!(actual < expected)) {
348
- throwError(msg, actual, expected, '<');
349
- }
350
- }
351
- function assertLessThanOrEqual(actual, expected, msg) {
352
- if (!(actual <= expected)) {
353
- throwError(msg, actual, expected, '<=');
354
- }
355
- }
356
- function assertGreaterThan(actual, expected, msg) {
357
- if (!(actual > expected)) {
358
- throwError(msg, actual, expected, '>');
359
- }
360
- }
361
- function assertGreaterThanOrEqual(actual, expected, msg) {
362
- if (!(actual >= expected)) {
363
- throwError(msg, actual, expected, '>=');
364
- }
365
- }
366
- function assertNotDefined(actual, msg) {
367
- if (actual != null) {
368
- throwError(msg, actual, null, '==');
369
- }
370
- }
371
- function assertDefined(actual, msg) {
372
- if (actual == null) {
373
- throwError(msg, actual, null, '!=');
374
- }
375
- }
376
- function throwError(msg, actual, expected, comparison) {
377
- throw new Error(`ASSERTION ERROR: ${msg}` +
378
- (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
379
- }
380
- function assertDomNode(node) {
381
- if (!(node instanceof Node)) {
382
- throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
383
- }
384
- }
385
- function assertElement(node) {
386
- if (!(node instanceof Element)) {
387
- throwError(`The provided value must be an element but got ${stringify(node)}`);
388
- }
389
- }
390
- function assertIndexInRange(arr, index) {
391
- assertDefined(arr, 'Array must be defined.');
392
- const maxLen = arr.length;
393
- if (index < 0 || index >= maxLen) {
394
- throwError(`Index expected to be less than ${maxLen} but got ${index}`);
395
- }
396
- }
397
- function assertOneOf(value, ...validValues) {
398
- if (validValues.indexOf(value) !== -1)
399
- return true;
400
- throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${JSON.stringify(value)}.`);
401
- }
402
- function assertNotReactive(fn) {
403
- if (getActiveConsumer() !== null) {
404
- throwError(`${fn}() should never be called in a reactive context.`);
405
- }
406
- }
407
-
408
- /**
409
- * Construct an injectable definition which defines how a token will be constructed by the DI
410
- * system, and in which injectors (if any) it will be available.
411
- *
412
- * This should be assigned to a static `ɵprov` field on a type, which will then be an
413
- * `InjectableType`.
414
- *
415
- * Options:
416
- * * `providedIn` determines which injectors will include the injectable, by either associating it
417
- * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
418
- * provided in the `'root'` injector, which will be the application-level injector in most apps.
419
- * * `factory` gives the zero argument function which will create an instance of the injectable.
420
- * The factory can call [`inject`](api/core/inject) to access the `Injector` and request injection
421
- * of dependencies.
422
- *
423
- * @codeGenApi
424
- * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
425
- */
426
- function ɵɵdefineInjectable(opts) {
427
- return {
428
- token: opts.token,
429
- providedIn: opts.providedIn || null,
430
- factory: opts.factory,
431
- value: undefined,
432
- };
433
- }
434
- /**
435
- * Construct an `InjectorDef` which configures an injector.
436
- *
437
- * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
438
- * `InjectorType`.
439
- *
440
- * Options:
441
- *
442
- * * `providers`: an optional array of providers to add to the injector. Each provider must
443
- * either have a factory or point to a type which has a `ɵprov` static property (the
444
- * type must be an `InjectableType`).
445
- * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
446
- * whose providers will also be added to the injector. Locally provided types will override
447
- * providers from imports.
448
- *
449
- * @codeGenApi
450
- */
451
- function ɵɵdefineInjector(options) {
452
- return { providers: options.providers || [], imports: options.imports || [] };
453
- }
454
- /**
455
- * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
456
- * inherited value.
457
- *
458
- * @param type A type which may have its own (non-inherited) `ɵprov`.
459
- */
460
- function getInjectableDef(type) {
461
- return getOwnDefinition(type, NG_PROV_DEF);
462
- }
463
- function isInjectable(type) {
464
- return getInjectableDef(type) !== null;
465
- }
466
- /**
467
- * Return definition only if it is defined directly on `type` and is not inherited from a base
468
- * class of `type`.
469
- */
470
- function getOwnDefinition(type, field) {
471
- // if the ɵprov prop exist but is undefined we still want to return null
472
- return (type.hasOwnProperty(field) && type[field]) || null;
473
- }
474
- /**
475
- * Read the injectable def (`ɵprov`) for `type` or read the `ɵprov` from one of its ancestors.
476
- *
477
- * @param type A type which may have `ɵprov`, via inheritance.
478
- *
479
- * @deprecated Will be removed in a future version of Angular, where an error will occur in the
480
- * scenario if we find the `ɵprov` on an ancestor only.
481
- */
482
- function getInheritedInjectableDef(type) {
483
- // if the ɵprov prop exist but is undefined we still want to return null
484
- const def = type?.[NG_PROV_DEF] ?? null;
485
- if (def) {
486
- ngDevMode &&
487
- console.warn(`DEPRECATED: DI is instantiating a token "${type.name}" that inherits its @Injectable decorator but does not provide one itself.\n` +
488
- `This will become an error in a future version of Angular. Please add @Injectable() to the "${type.name}" class.`);
489
- return def;
490
- }
491
- else {
492
- return null;
493
- }
494
- }
495
- /**
496
- * Read the injector def type in a way which is immune to accidentally reading inherited value.
497
- *
498
- * @param type type which may have an injector def (`ɵinj`)
499
- */
500
- function getInjectorDef(type) {
501
- return type && type.hasOwnProperty(NG_INJ_DEF) ? type[NG_INJ_DEF] : null;
502
- }
503
- const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty });
504
- const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty });
505
-
506
- /**
507
- * Creates a token that can be used in a DI Provider.
508
- *
509
- * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
510
- * runtime representation) such as when injecting an interface, callable type, array or
511
- * parameterized type.
512
- *
513
- * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
514
- * the `Injector`. This provides an additional level of type safety.
515
- *
516
- * <div class="docs-alert docs-alert-helpful">
517
- *
518
- * **Important Note**: Ensure that you use the same instance of the `InjectionToken` in both the
519
- * provider and the injection call. Creating a new instance of `InjectionToken` in different places,
520
- * even with the same description, will be treated as different tokens by Angular's DI system,
521
- * leading to a `NullInjectorError`.
522
- *
523
- * </div>
524
- *
525
- * {@example injection-token/src/main.ts region='InjectionToken'}
526
- *
527
- * When creating an `InjectionToken`, you can optionally specify a factory function which returns
528
- * (possibly by creating) a default value of the parameterized type `T`. This sets up the
529
- * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
530
- * application's root injector. If the factory function, which takes zero arguments, needs to inject
531
- * dependencies, it can do so using the [`inject`](api/core/inject) function.
532
- * As you can see in the Tree-shakable InjectionToken example below.
533
- *
534
- * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
535
- * overrides the above behavior and marks the token as belonging to a particular `@NgModule` (note:
536
- * this option is now deprecated). As mentioned above, `'root'` is the default value for
537
- * `providedIn`.
538
- *
539
- * The `providedIn: NgModule` and `providedIn: 'any'` options are deprecated.
540
- *
541
- * @usageNotes
542
- * ### Basic Examples
543
- *
544
- * ### Plain InjectionToken
545
- *
546
- * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
547
- *
548
- * ### Tree-shakable InjectionToken
549
- *
550
- * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
551
- *
552
- * @publicApi
553
- */
554
- class InjectionToken {
555
- _desc;
556
- /** @internal */
557
- ngMetadataName = 'InjectionToken';
558
- ɵprov;
559
- /**
560
- * @param _desc Description for the token,
561
- * used only for debugging purposes,
562
- * it should but does not need to be unique
563
- * @param options Options for the token's usage, as described above
564
- */
565
- constructor(_desc, options) {
566
- this._desc = _desc;
567
- this.ɵprov = undefined;
568
- if (typeof options == 'number') {
569
- (typeof ngDevMode === 'undefined' || ngDevMode) &&
570
- assertLessThan(options, 0, 'Only negative numbers are supported here');
571
- // This is a special hack to assign __NG_ELEMENT_ID__ to this instance.
572
- // See `InjectorMarkers`
573
- this.__NG_ELEMENT_ID__ = options;
574
- }
575
- else if (options !== undefined) {
576
- this.ɵprov = ɵɵdefineInjectable({
577
- token: this,
578
- providedIn: options.providedIn || 'root',
579
- factory: options.factory,
580
- });
581
- }
582
- }
583
- /**
584
- * @internal
585
- */
586
- get multi() {
587
- return this;
588
- }
589
- toString() {
590
- return `InjectionToken ${this._desc}`;
591
- }
592
- }
593
-
594
- let _injectorProfilerContext;
595
- function getInjectorProfilerContext() {
596
- !ngDevMode && throwError('getInjectorProfilerContext should never be called in production mode');
597
- return _injectorProfilerContext;
598
- }
599
- function setInjectorProfilerContext(context) {
600
- !ngDevMode && throwError('setInjectorProfilerContext should never be called in production mode');
601
- const previous = _injectorProfilerContext;
602
- _injectorProfilerContext = context;
603
- return previous;
604
- }
605
- const injectorProfilerCallbacks = [];
606
- const NOOP_PROFILER_REMOVAL = () => { };
607
- function removeProfiler(profiler) {
608
- const profilerIdx = injectorProfilerCallbacks.indexOf(profiler);
609
- if (profilerIdx !== -1) {
610
- injectorProfilerCallbacks.splice(profilerIdx, 1);
611
- }
612
- }
613
- /**
614
- * Adds a callback function which will be invoked during certain DI events within the
615
- * runtime (for example: injecting services, creating injectable instances, configuring providers).
616
- * Multiple profiler callbacks can be set: in this case profiling events are
617
- * reported to every registered callback.
618
- *
619
- * Warning: this function is *INTERNAL* and should not be relied upon in application's code.
620
- * The contract of the function might be changed in any release and/or the function can be removed
621
- * completely.
622
- *
623
- * @param profiler function provided by the caller or null value to disable profiling.
624
- * @returns a cleanup function that, when invoked, removes a given profiler callback.
625
- */
626
- function setInjectorProfiler(injectorProfiler) {
627
- !ngDevMode && throwError('setInjectorProfiler should never be called in production mode');
628
- if (injectorProfiler !== null) {
629
- if (!injectorProfilerCallbacks.includes(injectorProfiler)) {
630
- injectorProfilerCallbacks.push(injectorProfiler);
631
- }
632
- return () => removeProfiler(injectorProfiler);
633
- }
634
- else {
635
- injectorProfilerCallbacks.length = 0;
636
- return NOOP_PROFILER_REMOVAL;
637
- }
638
- }
639
- /**
640
- * Injector profiler function which emits on DI events executed by the runtime.
641
- *
642
- * @param event InjectorProfilerEvent corresponding to the DI event being emitted
643
- */
644
- function injectorProfiler(event) {
645
- !ngDevMode && throwError('Injector profiler should never be called in production mode');
646
- for (let i = 0; i < injectorProfilerCallbacks.length; i++) {
647
- const injectorProfilerCallback = injectorProfilerCallbacks[i];
648
- injectorProfilerCallback(event);
649
- }
650
- }
651
- /**
652
- * Emits an InjectorProfilerEventType.ProviderConfigured to the injector profiler. The data in the
653
- * emitted event includes the raw provider, as well as the token that provider is providing.
654
- *
655
- * @param eventProvider A provider object
656
- */
657
- function emitProviderConfiguredEvent(eventProvider, isViewProvider = false) {
658
- !ngDevMode && throwError('Injector profiler should never be called in production mode');
659
- let token;
660
- // if the provider is a TypeProvider (typeof provider is function) then the token is the
661
- // provider itself
662
- if (typeof eventProvider === 'function') {
663
- token = eventProvider;
664
- }
665
- // if the provider is an injection token, then the token is the injection token.
666
- else if (eventProvider instanceof InjectionToken) {
667
- token = eventProvider;
668
- }
669
- // in all other cases we can access the token via the `provide` property of the provider
670
- else {
671
- token = resolveForwardRef(eventProvider.provide);
672
- }
673
- let provider = eventProvider;
674
- // Injection tokens may define their own default provider which gets attached to the token itself
675
- // as `ɵprov`. In this case, we want to emit the provider that is attached to the token, not the
676
- // token itself.
677
- if (eventProvider instanceof InjectionToken) {
678
- provider = eventProvider.ɵprov || eventProvider;
679
- }
680
- injectorProfiler({
681
- type: 2 /* InjectorProfilerEventType.ProviderConfigured */,
682
- context: getInjectorProfilerContext(),
683
- providerRecord: { token, provider, isViewProvider },
684
- });
685
- }
686
- /**
687
- * Emits an event to the injector profiler when an instance corresponding to a given token is about to be created be an injector. Note that
688
- * the injector associated with this emission can be accessed by using getDebugInjectContext()
689
- *
690
- * @param instance an object created by an injector
691
- */
692
- function emitInjectorToCreateInstanceEvent(token) {
693
- !ngDevMode && throwError('Injector profiler should never be called in production mode');
694
- injectorProfiler({
695
- type: 4 /* InjectorProfilerEventType.InjectorToCreateInstanceEvent */,
696
- context: getInjectorProfilerContext(),
697
- token: token,
698
- });
699
- }
700
- /**
701
- * Emits an event to the injector profiler with the instance that was created. Note that
702
- * the injector associated with this emission can be accessed by using getDebugInjectContext()
703
- *
704
- * @param instance an object created by an injector
705
- */
706
- function emitInstanceCreatedByInjectorEvent(instance) {
707
- !ngDevMode && throwError('Injector profiler should never be called in production mode');
708
- injectorProfiler({
709
- type: 1 /* InjectorProfilerEventType.InstanceCreatedByInjector */,
710
- context: getInjectorProfilerContext(),
711
- instance: { value: instance },
712
- });
713
- }
714
- /**
715
- * @param token DI token associated with injected service
716
- * @param value the instance of the injected service (i.e the result of `inject(token)`)
717
- * @param flags the flags that the token was injected with
718
- */
719
- function emitInjectEvent(token, value, flags) {
720
- !ngDevMode && throwError('Injector profiler should never be called in production mode');
721
- injectorProfiler({
722
- type: 0 /* InjectorProfilerEventType.Inject */,
723
- context: getInjectorProfilerContext(),
724
- service: { token, value, flags },
725
- });
726
- }
727
- function emitEffectCreatedEvent(effect) {
728
- !ngDevMode && throwError('Injector profiler should never be called in production mode');
729
- injectorProfiler({
730
- type: 3 /* InjectorProfilerEventType.EffectCreated */,
731
- context: getInjectorProfilerContext(),
732
- effect,
733
- });
734
- }
735
- function runInInjectorProfilerContext(injector, token, callback) {
736
- !ngDevMode &&
737
- throwError('runInInjectorProfilerContext should never be called in production mode');
738
- const prevInjectContext = setInjectorProfilerContext({ injector, token });
739
- try {
740
- callback();
741
- }
742
- finally {
743
- setInjectorProfilerContext(prevInjectContext);
744
- }
745
- }
746
-
747
- function isEnvironmentProviders(value) {
748
- return value && !!value.ɵproviders;
749
- }
750
-
751
- const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty });
752
- const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty });
753
- const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty });
754
- const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty });
755
- const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty });
756
- /**
757
- * If a directive is diPublic, bloomAdd sets a property on the type with this constant as
758
- * the key and the directive's unique ID as the value. This allows us to map directives to their
759
- * bloom filter bit for DI.
760
- */
761
- // TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified.
762
- const NG_ELEMENT_ID = getClosureSafeProperty({
763
- __NG_ELEMENT_ID__: getClosureSafeProperty,
764
- });
765
- /**
766
- * The `NG_ENV_ID` field on a DI token indicates special processing in the `EnvironmentInjector`:
767
- * getting such tokens from the `EnvironmentInjector` will bypass the standard DI resolution
768
- * strategy and instead will return implementation produced by the `NG_ENV_ID` factory function.
769
- *
770
- * This particular retrieval of DI tokens is mostly done to eliminate circular dependencies and
771
- * improve tree-shaking.
772
- */
773
- const NG_ENV_ID = getClosureSafeProperty({ __NG_ENV_ID__: getClosureSafeProperty });
774
-
775
- /**
776
- * Used for stringify render output in Ivy.
777
- * Important! This function is very performance-sensitive and we should
778
- * be extra careful not to introduce megamorphic reads in it.
779
- * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations.
780
- */
781
- function renderStringify(value) {
782
- if (typeof value === 'string')
783
- return value;
784
- if (value == null)
785
- return '';
786
- // Use `String` so that it invokes the `toString` method of the value. Note that this
787
- // appears to be faster than calling `value.toString` (see `render_stringify` benchmark).
788
- return String(value);
789
- }
790
- /**
791
- * Used to stringify a value so that it can be displayed in an error message.
792
- *
793
- * Important! This function contains a megamorphic read and should only be
794
- * used for error messages.
795
- */
796
- function stringifyForError(value) {
797
- if (typeof value === 'function')
798
- return value.name || value.toString();
799
- if (typeof value === 'object' && value != null && typeof value.type === 'function') {
800
- return value.type.name || value.type.toString();
801
- }
802
- return renderStringify(value);
803
- }
804
- /**
805
- * Used to stringify a `Type` and including the file path and line number in which it is defined, if
806
- * possible, for better debugging experience.
807
- *
808
- * Important! This function contains a megamorphic read and should only be used for error messages.
809
- */
810
- function debugStringifyTypeForError(type) {
811
- // TODO(pmvald): Do some refactoring so that we can use getComponentDef here without creating
812
- // circular deps.
813
- let componentDef = type[NG_COMP_DEF] || null;
814
- if (componentDef !== null && componentDef.debugInfo) {
815
- return stringifyTypeFromDebugInfo(componentDef.debugInfo);
816
- }
817
- return stringifyForError(type);
818
- }
819
- // TODO(pmvald): Do some refactoring so that we can use the type ClassDebugInfo for the param
820
- // debugInfo here without creating circular deps.
821
- function stringifyTypeFromDebugInfo(debugInfo) {
822
- if (!debugInfo.filePath || !debugInfo.lineNumber) {
823
- return debugInfo.className;
824
- }
825
- else {
826
- return `${debugInfo.className} (at ${debugInfo.filePath}:${debugInfo.lineNumber})`;
827
- }
828
- }
829
-
830
- const NG_RUNTIME_ERROR_CODE = getClosureSafeProperty({ 'ngErrorCode': getClosureSafeProperty });
831
- const NG_RUNTIME_ERROR_MESSAGE = getClosureSafeProperty({ 'ngErrorMessage': getClosureSafeProperty });
832
- const NG_TOKEN_PATH = getClosureSafeProperty({ 'ngTokenPath': getClosureSafeProperty });
833
- /** Creates a circular dependency runtime error. */
834
- function cyclicDependencyError(token, path) {
835
- const message = ngDevMode ? `Circular dependency detected for \`${token}\`.` : '';
836
- return createRuntimeError(message, -200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, path);
837
- }
838
- /** Creates a circular dependency runtime error including a dependency path in the error message. */
839
- function cyclicDependencyErrorWithDetails(token, path) {
840
- return augmentRuntimeError(cyclicDependencyError(token, path), null);
841
- }
842
- function throwMixedMultiProviderError() {
843
- throw new Error(`Cannot mix multi providers and regular providers`);
844
- }
845
- function throwInvalidProviderError(ngModuleType, providers, provider) {
846
- if (ngModuleType && providers) {
847
- const providerDetail = providers.map((v) => (v == provider ? '?' + provider + '?' : '...'));
848
- throw new Error(`Invalid provider for the NgModule '${stringify(ngModuleType)}' - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`);
849
- }
850
- else if (isEnvironmentProviders(provider)) {
851
- if (provider.ɵfromNgModule) {
852
- throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, `Invalid providers from 'importProvidersFrom' present in a non-environment injector. 'importProvidersFrom' can't be used for component providers.`);
853
- }
854
- else {
855
- throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, `Invalid providers present in a non-environment injector. 'EnvironmentProviders' can't be used for component providers.`);
856
- }
857
- }
858
- else {
859
- throw new Error('Invalid provider');
860
- }
861
- }
862
- /** Throws an error when a token is not found in DI. */
863
- function throwProviderNotFoundError(token, injectorName) {
864
- const errorMessage = ngDevMode &&
865
- `No provider for ${stringifyForError(token)} found${injectorName ? ` in ${injectorName}` : ''}`;
866
- throw new RuntimeError(-201 /* RuntimeErrorCode.PROVIDER_NOT_FOUND */, errorMessage);
867
- }
868
- /**
869
- * Given an Error instance and the current token - update the monkey-patched
870
- * dependency path info to include that token.
871
- *
872
- * @param error Current instance of the Error class.
873
- * @param token Extra token that should be appended.
874
- */
875
- function prependTokenToDependencyPath(error, token) {
876
- error[NG_TOKEN_PATH] ??= [];
877
- // Append current token to the current token path. Since the error
878
- // is bubbling up, add the token in front of other tokens.
879
- const currentPath = error[NG_TOKEN_PATH];
880
- // Do not append the same token multiple times.
881
- let pathStr;
882
- if (typeof token === 'object' && 'multi' in token && token?.multi === true) {
883
- assertDefined(token.provide, 'Token with multi: true should have a provide property');
884
- pathStr = stringifyForError(token.provide);
885
- }
886
- else {
887
- pathStr = stringifyForError(token);
888
- }
889
- if (currentPath[0] !== pathStr) {
890
- error[NG_TOKEN_PATH].unshift(pathStr);
891
- }
892
- }
893
- /**
894
- * Modifies an Error instance with an updated error message
895
- * based on the accumulated dependency path.
896
- *
897
- * @param error Current instance of the Error class.
898
- * @param source Extra info about the injector which started
899
- * the resolution process, which eventually failed.
900
- */
901
- function augmentRuntimeError(error, source) {
902
- const tokenPath = error[NG_TOKEN_PATH];
903
- const errorCode = error[NG_RUNTIME_ERROR_CODE];
904
- const message = error[NG_RUNTIME_ERROR_MESSAGE] || error.message;
905
- error.message = formatErrorMessage(message, errorCode, tokenPath, source);
906
- return error;
907
- }
908
- /**
909
- * Creates an initial RuntimeError instance when a problem is detected.
910
- * Monkey-patches extra info in the RuntimeError instance, so that it can
911
- * be reused later, before throwing the final error.
912
- */
913
- function createRuntimeError(message, code, path) {
914
- // Cast to `any`, so that extra info can be monkey-patched onto this instance.
915
- const error = new RuntimeError(code, message);
916
- // Monkey-patch a runtime error code and a path onto an Error instance.
917
- error[NG_RUNTIME_ERROR_CODE] = code;
918
- error[NG_RUNTIME_ERROR_MESSAGE] = message;
919
- if (path) {
920
- error[NG_TOKEN_PATH] = path;
921
- }
922
- return error;
923
- }
924
- /**
925
- * Reads monkey-patched error code from the given Error instance.
926
- */
927
- function getRuntimeErrorCode(error) {
928
- return error[NG_RUNTIME_ERROR_CODE];
929
- }
930
- function formatErrorMessage(text, code, path = [], source = null) {
931
- let pathDetails = '';
932
- // If the path is empty or contains only one element (self) -
933
- // do not append additional info the error message.
934
- if (path && path.length > 1) {
935
- pathDetails = ` Path: ${path.join(' -> ')}.`;
936
- }
937
- const sourceDetails = source ? ` Source: ${source}.` : '';
938
- return formatRuntimeError(code, `${text}${sourceDetails}${pathDetails}`);
939
- }
940
-
941
- /**
942
- * Current implementation of inject.
943
- *
944
- * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
945
- * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
946
- * way for two reasons:
947
- * 1. `Injector` should not depend on ivy logic.
948
- * 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
949
- */
950
- let _injectImplementation;
951
- function getInjectImplementation() {
952
- return _injectImplementation;
953
- }
954
- /**
955
- * Sets the current inject implementation.
956
- */
957
- function setInjectImplementation(impl) {
958
- const previous = _injectImplementation;
959
- _injectImplementation = impl;
960
- return previous;
961
- }
962
- /**
963
- * Injects `root` tokens in limp mode.
964
- *
965
- * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
966
- * `"root"`. This is known as the limp mode injection. In such case the value is stored in the
967
- * injectable definition.
968
- */
969
- function injectRootLimpMode(token, notFoundValue, flags) {
970
- const injectableDef = getInjectableDef(token);
971
- if (injectableDef && injectableDef.providedIn == 'root') {
972
- return injectableDef.value === undefined
973
- ? (injectableDef.value = injectableDef.factory())
974
- : injectableDef.value;
975
- }
976
- if (flags & 8 /* InternalInjectFlags.Optional */)
977
- return null;
978
- if (notFoundValue !== undefined)
979
- return notFoundValue;
980
- throwProviderNotFoundError(token, 'Injector');
981
- }
982
- /**
983
- * Assert that `_injectImplementation` is not `fn`.
984
- *
985
- * This is useful, to prevent infinite recursion.
986
- *
987
- * @param fn Function which it should not equal to
988
- */
989
- function assertInjectImplementationNotEqual(fn) {
990
- ngDevMode &&
991
- assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion');
992
- }
993
-
994
- const _THROW_IF_NOT_FOUND = {};
995
- const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
996
- /*
997
- * Name of a property (that we patch onto DI decorator), which is used as an annotation of which
998
- * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators
999
- * in the code, thus making them tree-shakable.
1000
- */
1001
- const DI_DECORATOR_FLAG = '__NG_DI_FLAG__';
1002
- /**
1003
- * A wrapper around an `Injector` that implements the `PrimitivesInjector` interface.
1004
- *
1005
- * This is used to allow the `inject` function to be used with the new primitives-based DI system.
1006
- */
1007
- class RetrievingInjector {
1008
- injector;
1009
- constructor(injector) {
1010
- this.injector = injector;
1011
- }
1012
- retrieve(token, options) {
1013
- const flags = convertToBitFlags(options) || 0 /* InternalInjectFlags.Default */;
1014
- try {
1015
- return this.injector.get(token,
1016
- // When a dependency is requested with an optional flag, DI returns null as the default value.
1017
- (flags & 8 /* InternalInjectFlags.Optional */ ? null : THROW_IF_NOT_FOUND), flags);
1018
- }
1019
- catch (e) {
1020
- if (isNotFound(e)) {
1021
- return e;
1022
- }
1023
- throw e;
1024
- }
1025
- }
1026
- }
1027
- function injectInjectorOnly(token, flags = 0 /* InternalInjectFlags.Default */) {
1028
- const currentInjector = getCurrentInjector();
1029
- if (currentInjector === undefined) {
1030
- throw new RuntimeError(-203 /* RuntimeErrorCode.MISSING_INJECTION_CONTEXT */, ngDevMode &&
1031
- `The \`${stringify(token)}\` token injection failed. \`inject()\` function must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with \`runInInjectionContext\`.`);
1032
- }
1033
- else if (currentInjector === null) {
1034
- return injectRootLimpMode(token, undefined, flags);
1035
- }
1036
- else {
1037
- const options = convertToInjectOptions(flags);
1038
- // TODO: improve the typings here.
1039
- // `token` can be a multi: true provider definition, which is considered as a Token but not represented in the typings
1040
- const value = currentInjector.retrieve(token, options);
1041
- ngDevMode && emitInjectEvent(token, value, flags);
1042
- if (isNotFound(value)) {
1043
- if (options.optional) {
1044
- return null;
1045
- }
1046
- throw value;
1047
- }
1048
- return value;
1049
- }
1050
- }
1051
- function ɵɵinject(token, flags = 0 /* InternalInjectFlags.Default */) {
1052
- return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef(token), flags);
1053
- }
1054
- /**
1055
- * Throws an error indicating that a factory function could not be generated by the compiler for a
1056
- * particular class.
1057
- *
1058
- * The name of the class is not mentioned here, but will be in the generated factory function name
1059
- * and thus in the stack trace.
1060
- *
1061
- * @codeGenApi
1062
- */
1063
- function ɵɵinvalidFactoryDep(index) {
1064
- throw new RuntimeError(202 /* RuntimeErrorCode.INVALID_FACTORY_DEPENDENCY */, ngDevMode &&
1065
- `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${index} of the parameter list is invalid.
1066
- This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.
1067
-
1068
- Please check that 1) the type for the parameter at index ${index} is correct and 2) the correct Angular decorators are defined for this class and its ancestors.`);
1069
- }
1070
- /**
1071
- * Injects a token from the currently active injector.
1072
- * `inject` is only supported in an [injection context](guide/di/dependency-injection-context). It
1073
- * can be used during:
1074
- * - Construction (via the `constructor`) of a class being instantiated by the DI system, such
1075
- * as an `@Injectable` or `@Component`.
1076
- * - In the initializer for fields of such classes.
1077
- * - In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`.
1078
- * - In the `factory` function specified for an `InjectionToken`.
1079
- * - In a stackframe of a function call in a DI context
1080
- *
1081
- * @param token A token that represents a dependency that should be injected.
1082
- * @param flags Optional flags that control how injection is executed.
1083
- * The flags correspond to injection strategies that can be specified with
1084
- * parameter decorators `@Host`, `@Self`, `@SkipSelf`, and `@Optional`.
1085
- * @returns the injected value if operation is successful, `null` otherwise.
1086
- * @throws if called outside of a supported context.
1087
- *
1088
- * @usageNotes
1089
- * In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a
1090
- * field initializer:
1091
- *
1092
- * ```ts
1093
- * @Injectable({providedIn: 'root'})
1094
- * export class Car {
1095
- * radio: Radio|undefined;
1096
- * // OK: field initializer
1097
- * spareTyre = inject(Tyre);
1098
- *
1099
- * constructor() {
1100
- * // OK: constructor body
1101
- * this.radio = inject(Radio);
1102
- * }
1103
- * }
1104
- * ```
1105
- *
1106
- * It is also legal to call `inject` from a provider's factory:
1107
- *
1108
- * ```ts
1109
- * providers: [
1110
- * {provide: Car, useFactory: () => {
1111
- * // OK: a class factory
1112
- * const engine = inject(Engine);
1113
- * return new Car(engine);
1114
- * }}
1115
- * ]
1116
- * ```
1117
- *
1118
- * Calls to the `inject()` function outside of the class creation context will result in error. Most
1119
- * notably, calls to `inject()` are disallowed after a class instance was created, in methods
1120
- * (including lifecycle hooks):
1121
- *
1122
- * ```ts
1123
- * @Component({ ... })
1124
- * export class CarComponent {
1125
- * ngOnInit() {
1126
- * // ERROR: too late, the component instance was already created
1127
- * const engine = inject(Engine);
1128
- * engine.start();
1129
- * }
1130
- * }
1131
- * ```
1132
- *
1133
- * @publicApi
1134
- */
1135
- function inject(token, options) {
1136
- // The `as any` here _shouldn't_ be necessary, but without it JSCompiler
1137
- // throws a disambiguation error due to the multiple signatures.
1138
- return ɵɵinject(token, convertToBitFlags(options));
1139
- }
1140
- // Converts object-based DI flags (`InjectOptions`) to bit flags (`InjectFlags`).
1141
- function convertToBitFlags(flags) {
1142
- if (typeof flags === 'undefined' || typeof flags === 'number') {
1143
- return flags;
1144
- }
1145
- // While TypeScript doesn't accept it without a cast, bitwise OR with false-y values in
1146
- // JavaScript is a no-op. We can use that for a very codesize-efficient conversion from
1147
- // `InjectOptions` to `InjectFlags`.
1148
- return (0 /* InternalInjectFlags.Default */ | // comment to force a line break in the formatter
1149
- (flags.optional && 8 /* InternalInjectFlags.Optional */) |
1150
- (flags.host && 1 /* InternalInjectFlags.Host */) |
1151
- (flags.self && 2 /* InternalInjectFlags.Self */) |
1152
- (flags.skipSelf && 4 /* InternalInjectFlags.SkipSelf */));
1153
- }
1154
- // Converts bitflags to inject options
1155
- function convertToInjectOptions(flags) {
1156
- return {
1157
- optional: !!(flags & 8 /* InternalInjectFlags.Optional */),
1158
- host: !!(flags & 1 /* InternalInjectFlags.Host */),
1159
- self: !!(flags & 2 /* InternalInjectFlags.Self */),
1160
- skipSelf: !!(flags & 4 /* InternalInjectFlags.SkipSelf */),
1161
- };
1162
- }
1163
- function injectArgs(types) {
1164
- const args = [];
1165
- for (let i = 0; i < types.length; i++) {
1166
- const arg = resolveForwardRef(types[i]);
1167
- if (Array.isArray(arg)) {
1168
- if (arg.length === 0) {
1169
- throw new RuntimeError(900 /* RuntimeErrorCode.INVALID_DIFFER_INPUT */, ngDevMode && 'Arguments array must have arguments.');
1170
- }
1171
- let type = undefined;
1172
- let flags = 0 /* InternalInjectFlags.Default */;
1173
- for (let j = 0; j < arg.length; j++) {
1174
- const meta = arg[j];
1175
- const flag = getInjectFlag(meta);
1176
- if (typeof flag === 'number') {
1177
- // Special case when we handle @Inject decorator.
1178
- if (flag === -1 /* DecoratorFlags.Inject */) {
1179
- type = meta.token;
1180
- }
1181
- else {
1182
- flags |= flag;
1183
- }
1184
- }
1185
- else {
1186
- type = meta;
1187
- }
1188
- }
1189
- args.push(ɵɵinject(type, flags));
1190
- }
1191
- else {
1192
- args.push(ɵɵinject(arg));
1193
- }
1194
- }
1195
- return args;
1196
- }
1197
- /**
1198
- * Attaches a given InjectFlag to a given decorator using monkey-patching.
1199
- * Since DI decorators can be used in providers `deps` array (when provider is configured using
1200
- * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we
1201
- * attach the flag to make it available both as a static property and as a field on decorator
1202
- * instance.
1203
- *
1204
- * @param decorator Provided DI decorator.
1205
- * @param flag InjectFlag that should be applied.
1206
- */
1207
- function attachInjectFlag(decorator, flag) {
1208
- decorator[DI_DECORATOR_FLAG] = flag;
1209
- decorator.prototype[DI_DECORATOR_FLAG] = flag;
1210
- return decorator;
1211
- }
1212
- /**
1213
- * Reads monkey-patched property that contains InjectFlag attached to a decorator.
1214
- *
1215
- * @param token Token that may contain monkey-patched DI flags property.
1216
- */
1217
- function getInjectFlag(token) {
1218
- return token[DI_DECORATOR_FLAG];
1219
- }
1220
-
1221
- function getFactoryDef(type, throwNotFound) {
1222
- const hasFactoryDef = type.hasOwnProperty(NG_FACTORY_DEF);
1223
- if (!hasFactoryDef && throwNotFound === true && ngDevMode) {
1224
- throw new Error(`Type ${stringify(type)} does not have 'ɵfac' property.`);
1225
- }
1226
- return hasFactoryDef ? type[NG_FACTORY_DEF] : null;
1227
- }
1228
-
1229
- /**
1230
- * Determines if the contents of two arrays is identical
1231
- *
1232
- * @param a first array
1233
- * @param b second array
1234
- * @param identityAccessor Optional function for extracting stable object identity from a value in
1235
- * the array.
1236
- */
1237
- function arrayEquals(a, b, identityAccessor) {
1238
- if (a.length !== b.length)
1239
- return false;
1240
- for (let i = 0; i < a.length; i++) {
1241
- let valueA = a[i];
1242
- let valueB = b[i];
1243
- if (identityAccessor) {
1244
- valueA = identityAccessor(valueA);
1245
- valueB = identityAccessor(valueB);
1246
- }
1247
- if (valueB !== valueA) {
1248
- return false;
1249
- }
1250
- }
1251
- return true;
1252
- }
1253
- /**
1254
- * Flattens an array.
1255
- */
1256
- function flatten(list) {
1257
- return list.flat(Number.POSITIVE_INFINITY);
1258
- }
1259
- function deepForEach(input, fn) {
1260
- input.forEach((value) => (Array.isArray(value) ? deepForEach(value, fn) : fn(value)));
1261
- }
1262
- function addToArray(arr, index, value) {
1263
- // perf: array.push is faster than array.splice!
1264
- if (index >= arr.length) {
1265
- arr.push(value);
1266
- }
1267
- else {
1268
- arr.splice(index, 0, value);
1269
- }
1270
- }
1271
- function removeFromArray(arr, index) {
1272
- // perf: array.pop is faster than array.splice!
1273
- if (index >= arr.length - 1) {
1274
- return arr.pop();
1275
- }
1276
- else {
1277
- return arr.splice(index, 1)[0];
1278
- }
1279
- }
1280
- function newArray(size, value) {
1281
- const list = [];
1282
- for (let i = 0; i < size; i++) {
1283
- list.push(value);
1284
- }
1285
- return list;
1286
- }
1287
- /**
1288
- * Remove item from array (Same as `Array.splice()` but faster.)
1289
- *
1290
- * `Array.splice()` is not as fast because it has to allocate an array for the elements which were
1291
- * removed. This causes memory pressure and slows down code when most of the time we don't
1292
- * care about the deleted items array.
1293
- *
1294
- * https://jsperf.com/fast-array-splice (About 20x faster)
1295
- *
1296
- * @param array Array to splice
1297
- * @param index Index of element in array to remove.
1298
- * @param count Number of items to remove.
1299
- */
1300
- function arraySplice(array, index, count) {
1301
- const length = array.length - count;
1302
- while (index < length) {
1303
- array[index] = array[index + count];
1304
- index++;
1305
- }
1306
- while (count--) {
1307
- array.pop(); // shrink the array
1308
- }
1309
- }
1310
- /**
1311
- * Same as `Array.splice2(index, 0, value1, value2)` but faster.
1312
- *
1313
- * `Array.splice()` is not fast because it has to allocate an array for the elements which were
1314
- * removed. This causes memory pressure and slows down code when most of the time we don't
1315
- * care about the deleted items array.
1316
- *
1317
- * @param array Array to splice.
1318
- * @param index Index in array where the `value` should be added.
1319
- * @param value1 Value to add to array.
1320
- * @param value2 Value to add to array.
1321
- */
1322
- function arrayInsert2(array, index, value1, value2) {
1323
- ngDevMode && assertLessThanOrEqual(index, array.length, "Can't insert past array end.");
1324
- let end = array.length;
1325
- if (end == index) {
1326
- // inserting at the end.
1327
- array.push(value1, value2);
1328
- }
1329
- else if (end === 1) {
1330
- // corner case when we have less items in array than we have items to insert.
1331
- array.push(value2, array[0]);
1332
- array[0] = value1;
1333
- }
1334
- else {
1335
- end--;
1336
- array.push(array[end - 1], array[end]);
1337
- while (end > index) {
1338
- const previousEnd = end - 2;
1339
- array[end] = array[previousEnd];
1340
- end--;
1341
- }
1342
- array[index] = value1;
1343
- array[index + 1] = value2;
1344
- }
1345
- }
1346
- /**
1347
- * Set a `value` for a `key`.
1348
- *
1349
- * @param keyValueArray to modify.
1350
- * @param key The key to locate or create.
1351
- * @param value The value to set for a `key`.
1352
- * @returns index (always even) of where the value vas set.
1353
- */
1354
- function keyValueArraySet(keyValueArray, key, value) {
1355
- let index = keyValueArrayIndexOf(keyValueArray, key);
1356
- if (index >= 0) {
1357
- // if we found it set it.
1358
- keyValueArray[index | 1] = value;
1359
- }
1360
- else {
1361
- index = ~index;
1362
- arrayInsert2(keyValueArray, index, key, value);
1363
- }
1364
- return index;
1365
- }
1366
- /**
1367
- * Retrieve a `value` for a `key` (on `undefined` if not found.)
1368
- *
1369
- * @param keyValueArray to search.
1370
- * @param key The key to locate.
1371
- * @return The `value` stored at the `key` location or `undefined if not found.
1372
- */
1373
- function keyValueArrayGet(keyValueArray, key) {
1374
- const index = keyValueArrayIndexOf(keyValueArray, key);
1375
- if (index >= 0) {
1376
- // if we found it retrieve it.
1377
- return keyValueArray[index | 1];
1378
- }
1379
- return undefined;
1380
- }
1381
- /**
1382
- * Retrieve a `key` index value in the array or `-1` if not found.
1383
- *
1384
- * @param keyValueArray to search.
1385
- * @param key The key to locate.
1386
- * @returns index of where the key is (or should have been.)
1387
- * - positive (even) index if key found.
1388
- * - negative index if key not found. (`~index` (even) to get the index where it should have
1389
- * been inserted.)
1390
- */
1391
- function keyValueArrayIndexOf(keyValueArray, key) {
1392
- return _arrayIndexOfSorted(keyValueArray, key, 1);
1393
- }
1394
- /**
1395
- * INTERNAL: Get an index of an `value` in a sorted `array` by grouping search by `shift`.
1396
- *
1397
- * NOTE:
1398
- * - This uses binary search algorithm for fast removals.
1399
- *
1400
- * @param array A sorted array to binary search.
1401
- * @param value The value to look for.
1402
- * @param shift grouping shift.
1403
- * - `0` means look at every location
1404
- * - `1` means only look at every other (even) location (the odd locations are to be ignored as
1405
- * they are values.)
1406
- * @returns index of the value.
1407
- * - positive index if value found.
1408
- * - negative index if value not found. (`~index` to get the value where it should have been
1409
- * inserted)
1410
- */
1411
- function _arrayIndexOfSorted(array, value, shift) {
1412
- ngDevMode && assertEqual(Array.isArray(array), true, 'Expecting an array');
1413
- let start = 0;
1414
- let end = array.length >> shift;
1415
- while (end !== start) {
1416
- const middle = start + ((end - start) >> 1); // find the middle.
1417
- const current = array[middle << shift];
1418
- if (value === current) {
1419
- return middle << shift;
1420
- }
1421
- else if (current > value) {
1422
- end = middle;
1423
- }
1424
- else {
1425
- start = middle + 1; // We already searched middle so make it non-inclusive by adding 1
1426
- }
1427
- }
1428
- return ~(end << shift);
1429
- }
1430
-
1431
- /**
1432
- * This file contains reuseable "empty" symbols that can be used as default return values
1433
- * in different parts of the rendering code. Because the same symbols are returned, this
1434
- * allows for identity checks against these values to be consistently used by the framework
1435
- * code.
1436
- */
1437
- const EMPTY_OBJ = {};
1438
- const EMPTY_ARRAY = [];
1439
- // freezing the values prevents any code from accidentally inserting new values in
1440
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
1441
- // These property accesses can be ignored because ngDevMode will be set to false
1442
- // when optimizing code and the whole if statement will be dropped.
1443
- // tslint:disable-next-line:no-toplevel-property-access
1444
- Object.freeze(EMPTY_OBJ);
1445
- // tslint:disable-next-line:no-toplevel-property-access
1446
- Object.freeze(EMPTY_ARRAY);
1447
- }
1448
-
1449
- /**
1450
- * A multi-provider token for initialization functions that will run upon construction of an
1451
- * environment injector.
1452
- *
1453
- * @deprecated from v19.0.0, use provideEnvironmentInitializer instead
1454
- *
1455
- * @see {@link provideEnvironmentInitializer}
1456
- *
1457
- * Note: As opposed to the `APP_INITIALIZER` token, the `ENVIRONMENT_INITIALIZER` functions are not awaited,
1458
- * hence they should not be `async`.
1459
- *
1460
- * @publicApi
1461
- */
1462
- const ENVIRONMENT_INITIALIZER = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'ENVIRONMENT_INITIALIZER' : '');
1463
-
1464
- /**
1465
- * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors.
1466
- *
1467
- * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a
1468
- * project.
1469
- *
1470
- * @publicApi
1471
- */
1472
- const INJECTOR$1 = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'INJECTOR' : '',
1473
- // Disable tslint because this is const enum which gets inlined not top level prop access.
1474
- // tslint:disable-next-line: no-toplevel-property-access
1475
- -1 /* InjectorMarkers.Injector */);
1476
-
1477
- const INJECTOR_DEF_TYPES = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'INJECTOR_DEF_TYPES' : '');
1478
-
1479
- class NullInjector {
1480
- get(token, notFoundValue = THROW_IF_NOT_FOUND) {
1481
- if (notFoundValue === THROW_IF_NOT_FOUND) {
1482
- const message = ngDevMode ? `No provider found for \`${stringify(token)}\`.` : '';
1483
- const error = createRuntimeError(message, -201 /* RuntimeErrorCode.PROVIDER_NOT_FOUND */);
1484
- // Note: This is the name used by the primitives to identify a not found error.
1485
- error.name = 'ɵNotFound';
1486
- throw error;
1487
- }
1488
- return notFoundValue;
1489
- }
1490
- }
1491
-
1492
- function getNgModuleDef(type) {
1493
- return type[NG_MOD_DEF] || null;
1494
- }
1495
- function getNgModuleDefOrThrow(type) {
1496
- const ngModuleDef = getNgModuleDef(type);
1497
- if (!ngModuleDef) {
1498
- throw new RuntimeError(915 /* RuntimeErrorCode.MISSING_NG_MODULE_DEFINITION */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
1499
- `Type ${stringify(type)} does not have 'ɵmod' property.`);
1500
- }
1501
- return ngModuleDef;
1502
- }
1503
- /**
1504
- * The following getter methods retrieve the definition from the type. Currently the retrieval
1505
- * honors inheritance, but in the future we may change the rule to require that definitions are
1506
- * explicit. This would require some sort of migration strategy.
1507
- */
1508
- function getComponentDef(type) {
1509
- return type[NG_COMP_DEF] || null;
1510
- }
1511
- function getDirectiveDefOrThrow(type) {
1512
- const def = getDirectiveDef(type);
1513
- if (!def) {
1514
- throw new RuntimeError(916 /* RuntimeErrorCode.MISSING_DIRECTIVE_DEFINITION */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
1515
- `Type ${stringify(type)} does not have 'ɵdir' property.`);
1516
- }
1517
- return def;
1518
- }
1519
- function getDirectiveDef(type) {
1520
- return type[NG_DIR_DEF] || null;
1521
- }
1522
- function getPipeDef(type) {
1523
- return type[NG_PIPE_DEF] || null;
1524
- }
1525
- /**
1526
- * Checks whether a given Component, Directive or Pipe is marked as standalone.
1527
- * This will return false if passed anything other than a Component, Directive, or Pipe class
1528
- * See [this guide](guide/components/importing) for additional information:
1529
- *
1530
- * @param type A reference to a Component, Directive or Pipe.
1531
- * @publicApi
1532
- */
1533
- function isStandalone(type) {
1534
- const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef(type);
1535
- return def !== null && def.standalone;
1536
- }
1537
-
1538
- /**
1539
- * Wrap an array of `Provider`s into `EnvironmentProviders`, preventing them from being accidentally
1540
- * referenced in `@Component` in a component injector.
1541
- *
1542
- * @publicApi
1543
- */
1544
- function makeEnvironmentProviders(providers) {
1545
- return {
1546
- ɵproviders: providers,
1547
- };
1548
- }
1549
- /**
1550
- * @description
1551
- * This function is used to provide initialization functions that will be executed upon construction
1552
- * of an environment injector.
1553
- *
1554
- * Note that the provided initializer is run in the injection context.
1555
- *
1556
- * Previously, this was achieved using the `ENVIRONMENT_INITIALIZER` token which is now deprecated.
1557
- *
1558
- * @see {@link ENVIRONMENT_INITIALIZER}
1559
- *
1560
- * @usageNotes
1561
- * The following example illustrates how to configure an initialization function using
1562
- * `provideEnvironmentInitializer()`
1563
- * ```ts
1564
- * createEnvironmentInjector(
1565
- * [
1566
- * provideEnvironmentInitializer(() => {
1567
- * console.log('environment initialized');
1568
- * }),
1569
- * ],
1570
- * parentInjector
1571
- * );
1572
- * ```
1573
- *
1574
- * @publicApi
1575
- */
1576
- function provideEnvironmentInitializer(initializerFn) {
1577
- return makeEnvironmentProviders([
1578
- {
1579
- provide: ENVIRONMENT_INITIALIZER,
1580
- multi: true,
1581
- useValue: initializerFn,
1582
- },
1583
- ]);
1584
- }
1585
- /**
1586
- * Collects providers from all NgModules and standalone components, including transitively imported
1587
- * ones.
1588
- *
1589
- * Providers extracted via `importProvidersFrom` are only usable in an application injector or
1590
- * another environment injector (such as a route injector). They should not be used in component
1591
- * providers.
1592
- *
1593
- * More information about standalone components can be found in [this
1594
- * guide](guide/components/importing).
1595
- *
1596
- * @usageNotes
1597
- * The results of the `importProvidersFrom` call can be used in the `bootstrapApplication` call:
1598
- *
1599
- * ```ts
1600
- * await bootstrapApplication(RootComponent, {
1601
- * providers: [
1602
- * importProvidersFrom(NgModuleOne, NgModuleTwo)
1603
- * ]
1604
- * });
1605
- * ```
1606
- *
1607
- * You can also use the `importProvidersFrom` results in the `providers` field of a route, when a
1608
- * standalone component is used:
1609
- *
1610
- * ```ts
1611
- * export const ROUTES: Route[] = [
1612
- * {
1613
- * path: 'foo',
1614
- * providers: [
1615
- * importProvidersFrom(NgModuleOne, NgModuleTwo)
1616
- * ],
1617
- * component: YourStandaloneComponent
1618
- * }
1619
- * ];
1620
- * ```
1621
- *
1622
- * @returns Collected providers from the specified list of types.
1623
- * @publicApi
1624
- */
1625
- function importProvidersFrom(...sources) {
1626
- return {
1627
- ɵproviders: internalImportProvidersFrom(true, sources),
1628
- ɵfromNgModule: true,
1629
- };
1630
- }
1631
- function internalImportProvidersFrom(checkForStandaloneCmp, ...sources) {
1632
- const providersOut = [];
1633
- const dedup = new Set(); // already seen types
1634
- let injectorTypesWithProviders;
1635
- const collectProviders = (provider) => {
1636
- providersOut.push(provider);
1637
- };
1638
- deepForEach(sources, (source) => {
1639
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && checkForStandaloneCmp) {
1640
- const cmpDef = getComponentDef(source);
1641
- if (cmpDef?.standalone) {
1642
- throw new RuntimeError(800 /* RuntimeErrorCode.IMPORT_PROVIDERS_FROM_STANDALONE */, `Importing providers supports NgModule or ModuleWithProviders but got a standalone component "${stringifyForError(source)}"`);
1643
- }
1644
- }
1645
- // Narrow `source` to access the internal type analogue for `ModuleWithProviders`.
1646
- const internalSource = source;
1647
- if (walkProviderTree(internalSource, collectProviders, [], dedup)) {
1648
- injectorTypesWithProviders ||= [];
1649
- injectorTypesWithProviders.push(internalSource);
1650
- }
1651
- });
1652
- // Collect all providers from `ModuleWithProviders` types.
1653
- if (injectorTypesWithProviders !== undefined) {
1654
- processInjectorTypesWithProviders(injectorTypesWithProviders, collectProviders);
1655
- }
1656
- return providersOut;
1657
- }
1658
- /**
1659
- * Collects all providers from the list of `ModuleWithProviders` and appends them to the provided
1660
- * array.
1661
- */
1662
- function processInjectorTypesWithProviders(typesWithProviders, visitor) {
1663
- for (let i = 0; i < typesWithProviders.length; i++) {
1664
- const { ngModule, providers } = typesWithProviders[i];
1665
- deepForEachProvider(providers, (provider) => {
1666
- ngDevMode && validateProvider(provider, providers || EMPTY_ARRAY, ngModule);
1667
- visitor(provider, ngModule);
1668
- });
1669
- }
1670
- }
1671
- /**
1672
- * The logic visits an `InjectorType`, an `InjectorTypeWithProviders`, or a standalone
1673
- * `ComponentType`, and all of its transitive providers and collects providers.
1674
- *
1675
- * If an `InjectorTypeWithProviders` that declares providers besides the type is specified,
1676
- * the function will return "true" to indicate that the providers of the type definition need
1677
- * to be processed. This allows us to process providers of injector types after all imports of
1678
- * an injector definition are processed. (following View Engine semantics: see FW-1349)
1679
- */
1680
- function walkProviderTree(container, visitor, parents, dedup) {
1681
- container = resolveForwardRef(container);
1682
- if (!container)
1683
- return false;
1684
- // The actual type which had the definition. Usually `container`, but may be an unwrapped type
1685
- // from `InjectorTypeWithProviders`.
1686
- let defType = null;
1687
- let injDef = getInjectorDef(container);
1688
- const cmpDef = !injDef && getComponentDef(container);
1689
- if (!injDef && !cmpDef) {
1690
- // `container` is not an injector type or a component type. It might be:
1691
- // * An `InjectorTypeWithProviders` that wraps an injector type.
1692
- // * A standalone directive or pipe that got pulled in from a standalone component's
1693
- // dependencies.
1694
- // Try to unwrap it as an `InjectorTypeWithProviders` first.
1695
- const ngModule = container
1696
- .ngModule;
1697
- injDef = getInjectorDef(ngModule);
1698
- if (injDef) {
1699
- defType = ngModule;
1700
- }
1701
- else {
1702
- // Not a component or injector type, so ignore it.
1703
- return false;
1704
- }
1705
- }
1706
- else if (cmpDef && !cmpDef.standalone) {
1707
- return false;
1708
- }
1709
- else {
1710
- defType = container;
1711
- }
1712
- // Check for circular dependencies.
1713
- if (ngDevMode && parents.indexOf(defType) !== -1) {
1714
- const defName = stringify(defType);
1715
- const path = parents.map(stringify).concat(defName);
1716
- throw cyclicDependencyErrorWithDetails(defName, path);
1717
- }
1718
- // Check for multiple imports of the same module
1719
- const isDuplicate = dedup.has(defType);
1720
- if (cmpDef) {
1721
- if (isDuplicate) {
1722
- // This component definition has already been processed.
1723
- return false;
1724
- }
1725
- dedup.add(defType);
1726
- if (cmpDef.dependencies) {
1727
- const deps = typeof cmpDef.dependencies === 'function' ? cmpDef.dependencies() : cmpDef.dependencies;
1728
- for (const dep of deps) {
1729
- walkProviderTree(dep, visitor, parents, dedup);
1730
- }
1731
- }
1732
- }
1733
- else if (injDef) {
1734
- // First, include providers from any imports.
1735
- if (injDef.imports != null && !isDuplicate) {
1736
- // Before processing defType's imports, add it to the set of parents. This way, if it ends
1737
- // up deeply importing itself, this can be detected.
1738
- ngDevMode && parents.push(defType);
1739
- // Add it to the set of dedups. This way we can detect multiple imports of the same module
1740
- dedup.add(defType);
1741
- let importTypesWithProviders;
1742
- try {
1743
- deepForEach(injDef.imports, (imported) => {
1744
- if (walkProviderTree(imported, visitor, parents, dedup)) {
1745
- importTypesWithProviders ||= [];
1746
- // If the processed import is an injector type with providers, we store it in the
1747
- // list of import types with providers, so that we can process those afterwards.
1748
- importTypesWithProviders.push(imported);
1749
- }
1750
- });
1751
- }
1752
- finally {
1753
- // Remove it from the parents set when finished.
1754
- ngDevMode && parents.pop();
1755
- }
1756
- // Imports which are declared with providers (TypeWithProviders) need to be processed
1757
- // after all imported modules are processed. This is similar to how View Engine
1758
- // processes/merges module imports in the metadata resolver. See: FW-1349.
1759
- if (importTypesWithProviders !== undefined) {
1760
- processInjectorTypesWithProviders(importTypesWithProviders, visitor);
1761
- }
1762
- }
1763
- if (!isDuplicate) {
1764
- // Track the InjectorType and add a provider for it.
1765
- // It's important that this is done after the def's imports.
1766
- const factory = getFactoryDef(defType) || (() => new defType());
1767
- // Append extra providers to make more info available for consumers (to retrieve an injector
1768
- // type), as well as internally (to calculate an injection scope correctly and eagerly
1769
- // instantiate a `defType` when an injector is created).
1770
- // Provider to create `defType` using its factory.
1771
- visitor({ provide: defType, useFactory: factory, deps: EMPTY_ARRAY }, defType);
1772
- // Make this `defType` available to an internal logic that calculates injector scope.
1773
- visitor({ provide: INJECTOR_DEF_TYPES, useValue: defType, multi: true }, defType);
1774
- // Provider to eagerly instantiate `defType` via `INJECTOR_INITIALIZER`.
1775
- visitor({ provide: ENVIRONMENT_INITIALIZER, useValue: () => ɵɵinject(defType), multi: true }, defType);
1776
- }
1777
- // Next, include providers listed on the definition itself.
1778
- const defProviders = injDef.providers;
1779
- if (defProviders != null && !isDuplicate) {
1780
- const injectorType = container;
1781
- deepForEachProvider(defProviders, (provider) => {
1782
- ngDevMode && validateProvider(provider, defProviders, injectorType);
1783
- visitor(provider, injectorType);
1784
- });
1785
- }
1786
- }
1787
- else {
1788
- // Should not happen, but just in case.
1789
- return false;
1790
- }
1791
- return (defType !== container && container.providers !== undefined);
1792
- }
1793
- function validateProvider(provider, providers, containerType) {
1794
- if (isTypeProvider(provider) ||
1795
- isValueProvider(provider) ||
1796
- isFactoryProvider(provider) ||
1797
- isExistingProvider(provider)) {
1798
- return;
1799
- }
1800
- // Here we expect the provider to be a `useClass` provider (by elimination).
1801
- const classRef = resolveForwardRef(provider && (provider.useClass || provider.provide));
1802
- if (!classRef) {
1803
- throwInvalidProviderError(containerType, providers, provider);
1804
- }
1805
- }
1806
- function deepForEachProvider(providers, fn) {
1807
- for (let provider of providers) {
1808
- if (isEnvironmentProviders(provider)) {
1809
- provider = provider.ɵproviders;
1810
- }
1811
- if (Array.isArray(provider)) {
1812
- deepForEachProvider(provider, fn);
1813
- }
1814
- else {
1815
- fn(provider);
1816
- }
1817
- }
1818
- }
1819
- const USE_VALUE = getClosureSafeProperty({
1820
- provide: String,
1821
- useValue: getClosureSafeProperty,
1822
- });
1823
- function isValueProvider(value) {
1824
- return value !== null && typeof value == 'object' && USE_VALUE in value;
1825
- }
1826
- function isExistingProvider(value) {
1827
- return !!(value && value.useExisting);
1828
- }
1829
- function isFactoryProvider(value) {
1830
- return !!(value && value.useFactory);
1831
- }
1832
- function isTypeProvider(value) {
1833
- return typeof value === 'function';
1834
- }
1835
- function isClassProvider(value) {
1836
- return !!value.useClass;
1837
- }
1838
-
1839
- /**
1840
- * An internal token whose presence in an injector indicates that the injector should treat itself
1841
- * as a root scoped injector when processing requests for unknown tokens which may indicate
1842
- * they are provided in the root scope.
1843
- */
1844
- const INJECTOR_SCOPE = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'Set Injector scope.' : '');
1845
-
1846
- /**
1847
- * Marker which indicates that a value has not yet been created from the factory function.
1848
- */
1849
- const NOT_YET = {};
1850
- /**
1851
- * Marker which indicates that the factory function for a token is in the process of being called.
1852
- *
1853
- * If the injector is asked to inject a token with its value set to CIRCULAR, that indicates
1854
- * injection of a dependency has recursively attempted to inject the original token, and there is
1855
- * a circular dependency among the providers.
1856
- */
1857
- const CIRCULAR = {};
1858
- /**
1859
- * A lazily initialized NullInjector.
1860
- */
1861
- let NULL_INJECTOR = undefined;
1862
- function getNullInjector() {
1863
- if (NULL_INJECTOR === undefined) {
1864
- NULL_INJECTOR = new NullInjector();
1865
- }
1866
- return NULL_INJECTOR;
1867
- }
1868
- /**
1869
- * An `Injector` that's part of the environment injector hierarchy, which exists outside of the
1870
- * component tree.
1871
- *
1872
- * @publicApi
1873
- */
1874
- class EnvironmentInjector {
1875
- }
1876
- class R3Injector extends EnvironmentInjector {
1877
- parent;
1878
- source;
1879
- scopes;
1880
- /**
1881
- * Map of tokens to records which contain the instances of those tokens.
1882
- * - `null` value implies that we don't have the record. Used by tree-shakable injectors
1883
- * to prevent further searches.
1884
- */
1885
- records = new Map();
1886
- /**
1887
- * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks.
1888
- */
1889
- _ngOnDestroyHooks = new Set();
1890
- _onDestroyHooks = [];
1891
- /**
1892
- * Flag indicating that this injector was previously destroyed.
1893
- */
1894
- get destroyed() {
1895
- return this._destroyed;
1896
- }
1897
- _destroyed = false;
1898
- injectorDefTypes;
1899
- constructor(providers, parent, source, scopes) {
1900
- super();
1901
- this.parent = parent;
1902
- this.source = source;
1903
- this.scopes = scopes;
1904
- // Start off by creating Records for every provider.
1905
- forEachSingleProvider(providers, (provider) => this.processProvider(provider));
1906
- // Make sure the INJECTOR token provides this injector.
1907
- this.records.set(INJECTOR$1, makeRecord(undefined, this));
1908
- // And `EnvironmentInjector` if the current injector is supposed to be env-scoped.
1909
- if (scopes.has('environment')) {
1910
- this.records.set(EnvironmentInjector, makeRecord(undefined, this));
1911
- }
1912
- // Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide
1913
- // any injectable scoped to APP_ROOT_SCOPE.
1914
- const record = this.records.get(INJECTOR_SCOPE);
1915
- if (record != null && typeof record.value === 'string') {
1916
- this.scopes.add(record.value);
1917
- }
1918
- this.injectorDefTypes = new Set(this.get(INJECTOR_DEF_TYPES, EMPTY_ARRAY, { self: true }));
1919
- }
1920
- retrieve(token, options) {
1921
- const flags = convertToBitFlags(options) || 0 /* InternalInjectFlags.Default */;
1922
- try {
1923
- return this.get(token,
1924
- // When a dependency is requested with an optional flag, DI returns null as the default value.
1925
- THROW_IF_NOT_FOUND, flags);
1926
- }
1927
- catch (e) {
1928
- if (isNotFound$1(e)) {
1929
- return e;
1930
- }
1931
- throw e;
1932
- }
1933
- }
1934
- /**
1935
- * Destroy the injector and release references to every instance or provider associated with it.
1936
- *
1937
- * Also calls the `OnDestroy` lifecycle hooks of every instance that was created for which a
1938
- * hook was found.
1939
- */
1940
- destroy() {
1941
- assertNotDestroyed(this);
1942
- // Set destroyed = true first, in case lifecycle hooks re-enter destroy().
1943
- this._destroyed = true;
1944
- const prevConsumer = setActiveConsumer(null);
1945
- try {
1946
- // Call all the lifecycle hooks.
1947
- for (const service of this._ngOnDestroyHooks) {
1948
- service.ngOnDestroy();
1949
- }
1950
- const onDestroyHooks = this._onDestroyHooks;
1951
- // Reset the _onDestroyHooks array before iterating over it to prevent hooks that unregister
1952
- // themselves from mutating the array during iteration.
1953
- this._onDestroyHooks = [];
1954
- for (const hook of onDestroyHooks) {
1955
- hook();
1956
- }
1957
- }
1958
- finally {
1959
- // Release all references.
1960
- this.records.clear();
1961
- this._ngOnDestroyHooks.clear();
1962
- this.injectorDefTypes.clear();
1963
- setActiveConsumer(prevConsumer);
1964
- }
1965
- }
1966
- onDestroy(callback) {
1967
- assertNotDestroyed(this);
1968
- this._onDestroyHooks.push(callback);
1969
- return () => this.removeOnDestroy(callback);
1970
- }
1971
- runInContext(fn) {
1972
- assertNotDestroyed(this);
1973
- const previousInjector = setCurrentInjector(this);
1974
- const previousInjectImplementation = setInjectImplementation(undefined);
1975
- let prevInjectContext;
1976
- if (ngDevMode) {
1977
- prevInjectContext = setInjectorProfilerContext({ injector: this, token: null });
1978
- }
1979
- try {
1980
- return fn();
1981
- }
1982
- finally {
1983
- setCurrentInjector(previousInjector);
1984
- setInjectImplementation(previousInjectImplementation);
1985
- ngDevMode && setInjectorProfilerContext(prevInjectContext);
1986
- }
1987
- }
1988
- get(token, notFoundValue = THROW_IF_NOT_FOUND, options) {
1989
- assertNotDestroyed(this);
1990
- if (token.hasOwnProperty(NG_ENV_ID)) {
1991
- return token[NG_ENV_ID](this);
1992
- }
1993
- const flags = convertToBitFlags(options);
1994
- // Set the injection context.
1995
- let prevInjectContext;
1996
- if (ngDevMode) {
1997
- prevInjectContext = setInjectorProfilerContext({ injector: this, token: token });
1998
- }
1999
- const previousInjector = setCurrentInjector(this);
2000
- const previousInjectImplementation = setInjectImplementation(undefined);
2001
- try {
2002
- // Check for the SkipSelf flag.
2003
- if (!(flags & 4 /* InternalInjectFlags.SkipSelf */)) {
2004
- // SkipSelf isn't set, check if the record belongs to this injector.
2005
- let record = this.records.get(token);
2006
- if (record === undefined) {
2007
- // No record, but maybe the token is scoped to this injector. Look for an injectable
2008
- // def with a scope matching this injector.
2009
- const def = couldBeInjectableType(token) && getInjectableDef(token);
2010
- if (def && this.injectableDefInScope(def)) {
2011
- // Found an injectable def and it's scoped to this injector. Pretend as if it was here
2012
- // all along.
2013
- if (ngDevMode) {
2014
- runInInjectorProfilerContext(this, token, () => {
2015
- emitProviderConfiguredEvent(token);
2016
- });
2017
- }
2018
- record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET);
2019
- }
2020
- else {
2021
- record = null;
2022
- }
2023
- this.records.set(token, record);
2024
- }
2025
- // If a record was found, get the instance for it and return it.
2026
- if (record != null /* NOT null || undefined */) {
2027
- return this.hydrate(token, record, flags);
2028
- }
2029
- }
2030
- // Select the next injector based on the Self flag - if self is set, the next injector is
2031
- // the NullInjector, otherwise it's the parent.
2032
- const nextInjector = !(flags & 2 /* InternalInjectFlags.Self */) ? this.parent : getNullInjector();
2033
- // Set the notFoundValue based on the Optional flag - if optional is set and notFoundValue
2034
- // is undefined, the value is null, otherwise it's the notFoundValue.
2035
- notFoundValue =
2036
- flags & 8 /* InternalInjectFlags.Optional */ && notFoundValue === THROW_IF_NOT_FOUND
2037
- ? null
2038
- : notFoundValue;
2039
- return nextInjector.get(token, notFoundValue);
2040
- }
2041
- catch (error) {
2042
- // If there was a cyclic dependency error or a token was not found,
2043
- // an error is thrown at the level where the problem was detected.
2044
- // The error propagates up the call stack and the code below appends
2045
- // the current token into the path. As a result, the full path is assembled
2046
- // at the very top of the call stack, so the final error message can be
2047
- // formatted to include that path.
2048
- const errorCode = getRuntimeErrorCode(error);
2049
- if (errorCode === -200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */ ||
2050
- errorCode === -201 /* RuntimeErrorCode.PROVIDER_NOT_FOUND */) {
2051
- // Note: we use `if (ngDevMode) { ... }` instead of an early return.
2052
- // ESBuild is conservative about removing dead code that follows `return;`
2053
- // inside a function body, so the block may remain in the bundle.
2054
- // Using a conditional ensures the dev-only logic is reliably tree-shaken
2055
- // in production builds.
2056
- if (ngDevMode) {
2057
- prependTokenToDependencyPath(error, token);
2058
- if (previousInjector) {
2059
- // We still have a parent injector, keep throwing
2060
- throw error;
2061
- }
2062
- else {
2063
- // Format & throw the final error message when we don't have any previous injector
2064
- throw augmentRuntimeError(error, this.source);
2065
- }
2066
- }
2067
- else {
2068
- throw new RuntimeError(errorCode, null);
2069
- }
2070
- }
2071
- else {
2072
- throw error;
2073
- }
2074
- }
2075
- finally {
2076
- // Lastly, restore the previous injection context.
2077
- setInjectImplementation(previousInjectImplementation);
2078
- setCurrentInjector(previousInjector);
2079
- ngDevMode && setInjectorProfilerContext(prevInjectContext);
2080
- }
2081
- }
2082
- /** @internal */
2083
- resolveInjectorInitializers() {
2084
- const prevConsumer = setActiveConsumer(null);
2085
- const previousInjector = setCurrentInjector(this);
2086
- const previousInjectImplementation = setInjectImplementation(undefined);
2087
- let prevInjectContext;
2088
- if (ngDevMode) {
2089
- prevInjectContext = setInjectorProfilerContext({ injector: this, token: null });
2090
- }
2091
- try {
2092
- const initializers = this.get(ENVIRONMENT_INITIALIZER, EMPTY_ARRAY, { self: true });
2093
- if (ngDevMode && !Array.isArray(initializers)) {
2094
- throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `ENVIRONMENT_INITIALIZER` token value ' +
2095
- `(expected an array, but got ${typeof initializers}). ` +
2096
- 'Please check that the `ENVIRONMENT_INITIALIZER` token is configured as a ' +
2097
- '`multi: true` provider.');
2098
- }
2099
- for (const initializer of initializers) {
2100
- initializer();
2101
- }
2102
- }
2103
- finally {
2104
- setCurrentInjector(previousInjector);
2105
- setInjectImplementation(previousInjectImplementation);
2106
- ngDevMode && setInjectorProfilerContext(prevInjectContext);
2107
- setActiveConsumer(prevConsumer);
2108
- }
2109
- }
2110
- toString() {
2111
- const tokens = [];
2112
- const records = this.records;
2113
- for (const token of records.keys()) {
2114
- tokens.push(stringify(token));
2115
- }
2116
- return `R3Injector[${tokens.join(', ')}]`;
2117
- }
2118
- /**
2119
- * Process a `SingleProvider` and add it.
2120
- */
2121
- processProvider(provider) {
2122
- // Determine the token from the provider. Either it's its own token, or has a {provide: ...}
2123
- // property.
2124
- provider = resolveForwardRef(provider);
2125
- let token = isTypeProvider(provider)
2126
- ? provider
2127
- : resolveForwardRef(provider && provider.provide);
2128
- // Construct a `Record` for the provider.
2129
- const record = providerToRecord(provider);
2130
- if (ngDevMode) {
2131
- runInInjectorProfilerContext(this, token, () => {
2132
- // Emit InjectorProfilerEventType.Create if provider is a value provider because
2133
- // these are the only providers that do not go through the value hydration logic
2134
- // where this event would normally be emitted from.
2135
- if (isValueProvider(provider)) {
2136
- emitInjectorToCreateInstanceEvent(token);
2137
- emitInstanceCreatedByInjectorEvent(provider.useValue);
2138
- }
2139
- emitProviderConfiguredEvent(provider);
2140
- });
2141
- }
2142
- if (!isTypeProvider(provider) && provider.multi === true) {
2143
- // If the provider indicates that it's a multi-provider, process it specially.
2144
- // First check whether it's been defined already.
2145
- let multiRecord = this.records.get(token);
2146
- if (multiRecord) {
2147
- // It has. Throw a nice error if
2148
- if (ngDevMode && multiRecord.multi === undefined) {
2149
- throwMixedMultiProviderError();
2150
- }
2151
- }
2152
- else {
2153
- multiRecord = makeRecord(undefined, NOT_YET, true);
2154
- multiRecord.factory = () => injectArgs(multiRecord.multi);
2155
- this.records.set(token, multiRecord);
2156
- }
2157
- token = provider;
2158
- multiRecord.multi.push(provider);
2159
- }
2160
- else {
2161
- if (ngDevMode) {
2162
- const existing = this.records.get(token);
2163
- if (existing && existing.multi !== undefined) {
2164
- throwMixedMultiProviderError();
2165
- }
2166
- }
2167
- }
2168
- this.records.set(token, record);
2169
- }
2170
- hydrate(token, record, flags) {
2171
- const prevConsumer = setActiveConsumer(null);
2172
- try {
2173
- if (record.value === CIRCULAR) {
2174
- throw cyclicDependencyError(stringify(token));
2175
- }
2176
- else if (record.value === NOT_YET) {
2177
- record.value = CIRCULAR;
2178
- if (ngDevMode) {
2179
- runInInjectorProfilerContext(this, token, () => {
2180
- emitInjectorToCreateInstanceEvent(token);
2181
- record.value = record.factory(undefined, flags);
2182
- emitInstanceCreatedByInjectorEvent(record.value);
2183
- });
2184
- }
2185
- else {
2186
- record.value = record.factory(undefined, flags);
2187
- }
2188
- }
2189
- if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) {
2190
- this._ngOnDestroyHooks.add(record.value);
2191
- }
2192
- return record.value;
2193
- }
2194
- finally {
2195
- setActiveConsumer(prevConsumer);
2196
- }
2197
- }
2198
- injectableDefInScope(def) {
2199
- if (!def.providedIn) {
2200
- return false;
2201
- }
2202
- const providedIn = resolveForwardRef(def.providedIn);
2203
- if (typeof providedIn === 'string') {
2204
- return providedIn === 'any' || this.scopes.has(providedIn);
2205
- }
2206
- else {
2207
- return this.injectorDefTypes.has(providedIn);
2208
- }
2209
- }
2210
- removeOnDestroy(callback) {
2211
- const destroyCBIdx = this._onDestroyHooks.indexOf(callback);
2212
- if (destroyCBIdx !== -1) {
2213
- this._onDestroyHooks.splice(destroyCBIdx, 1);
2214
- }
2215
- }
2216
- }
2217
- function injectableDefOrInjectorDefFactory(token) {
2218
- // Most tokens will have an injectable def directly on them, which specifies a factory directly.
2219
- const injectableDef = getInjectableDef(token);
2220
- const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token);
2221
- if (factory !== null) {
2222
- return factory;
2223
- }
2224
- // InjectionTokens should have an injectable def (ɵprov) and thus should be handled above.
2225
- // If it's missing that, it's an error.
2226
- if (token instanceof InjectionToken) {
2227
- throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Token ${stringify(token)} is missing a ɵprov definition.`);
2228
- }
2229
- // Undecorated types can sometimes be created if they have no constructor arguments.
2230
- if (token instanceof Function) {
2231
- return getUndecoratedInjectableFactory(token);
2232
- }
2233
- // There was no way to resolve a factory for this token.
2234
- throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && 'unreachable');
2235
- }
2236
- function getUndecoratedInjectableFactory(token) {
2237
- // If the token has parameters then it has dependencies that we cannot resolve implicitly.
2238
- const paramLength = token.length;
2239
- if (paramLength > 0) {
2240
- throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode &&
2241
- `Can't resolve all parameters for ${stringify(token)}: (${newArray(paramLength, '?').join(', ')}).`);
2242
- }
2243
- // The constructor function appears to have no parameters.
2244
- // This might be because it inherits from a super-class. In which case, use an injectable
2245
- // def from an ancestor if there is one.
2246
- // Otherwise this really is a simple class with no dependencies, so return a factory that
2247
- // just instantiates the zero-arg constructor.
2248
- const inheritedInjectableDef = getInheritedInjectableDef(token);
2249
- if (inheritedInjectableDef !== null) {
2250
- return () => inheritedInjectableDef.factory(token);
2251
- }
2252
- else {
2253
- return () => new token();
2254
- }
2255
- }
2256
- function providerToRecord(provider) {
2257
- if (isValueProvider(provider)) {
2258
- return makeRecord(undefined, provider.useValue);
2259
- }
2260
- else {
2261
- const factory = providerToFactory(provider);
2262
- return makeRecord(factory, NOT_YET);
2263
- }
2264
- }
2265
- /**
2266
- * Converts a `SingleProvider` into a factory function.
2267
- *
2268
- * @param provider provider to convert to factory
2269
- */
2270
- function providerToFactory(provider, ngModuleType, providers) {
2271
- let factory = undefined;
2272
- if (ngDevMode && isEnvironmentProviders(provider)) {
2273
- throwInvalidProviderError(undefined, providers, provider);
2274
- }
2275
- if (isTypeProvider(provider)) {
2276
- const unwrappedProvider = resolveForwardRef(provider);
2277
- return getFactoryDef(unwrappedProvider) || injectableDefOrInjectorDefFactory(unwrappedProvider);
2278
- }
2279
- else {
2280
- if (isValueProvider(provider)) {
2281
- factory = () => resolveForwardRef(provider.useValue);
2282
- }
2283
- else if (isFactoryProvider(provider)) {
2284
- factory = () => provider.useFactory(...injectArgs(provider.deps || []));
2285
- }
2286
- else if (isExistingProvider(provider)) {
2287
- factory = (_, flags) => ɵɵinject(resolveForwardRef(provider.useExisting), flags !== undefined && flags & 8 /* InternalInjectFlags.Optional */
2288
- ? 8 /* InternalInjectFlags.Optional */
2289
- : undefined);
2290
- }
2291
- else {
2292
- const classRef = resolveForwardRef(provider &&
2293
- (provider.useClass || provider.provide));
2294
- if (ngDevMode && !classRef) {
2295
- throwInvalidProviderError(ngModuleType, providers, provider);
2296
- }
2297
- if (hasDeps(provider)) {
2298
- factory = () => new classRef(...injectArgs(provider.deps));
2299
- }
2300
- else {
2301
- return getFactoryDef(classRef) || injectableDefOrInjectorDefFactory(classRef);
2302
- }
2303
- }
2304
- }
2305
- return factory;
2306
- }
2307
- function assertNotDestroyed(injector) {
2308
- if (injector.destroyed) {
2309
- throw new RuntimeError(205 /* RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED */, ngDevMode && 'Injector has already been destroyed.');
2310
- }
2311
- }
2312
- function makeRecord(factory, value, multi = false) {
2313
- return {
2314
- factory: factory,
2315
- value: value,
2316
- multi: multi ? [] : undefined,
2317
- };
2318
- }
2319
- function hasDeps(value) {
2320
- return !!value.deps;
2321
- }
2322
- function hasOnDestroy(value) {
2323
- return (value !== null &&
2324
- typeof value === 'object' &&
2325
- typeof value.ngOnDestroy === 'function');
2326
- }
2327
- function couldBeInjectableType(value) {
2328
- return (typeof value === 'function' ||
2329
- (typeof value === 'object' && value.ngMetadataName === 'InjectionToken'));
2330
- }
2331
- function forEachSingleProvider(providers, fn) {
2332
- for (const provider of providers) {
2333
- if (Array.isArray(provider)) {
2334
- forEachSingleProvider(provider, fn);
2335
- }
2336
- else if (provider && isEnvironmentProviders(provider)) {
2337
- forEachSingleProvider(provider.ɵproviders, fn);
2338
- }
2339
- else {
2340
- fn(provider);
2341
- }
2342
- }
2343
- }
2344
-
2345
- /**
2346
- * Runs the given function in the [context](guide/di/dependency-injection-context) of the given
2347
- * `Injector`.
2348
- *
2349
- * Within the function's stack frame, [`inject`](api/core/inject) can be used to inject dependencies
2350
- * from the given `Injector`. Note that `inject` is only usable synchronously, and cannot be used in
2351
- * any asynchronous callbacks or after any `await` points.
2352
- *
2353
- * @param injector the injector which will satisfy calls to [`inject`](api/core/inject) while `fn`
2354
- * is executing
2355
- * @param fn the closure to be run in the context of `injector`
2356
- * @returns the return value of the function, if any
2357
- * @publicApi
2358
- */
2359
- function runInInjectionContext(injector, fn) {
2360
- let internalInjector;
2361
- if (injector instanceof R3Injector) {
2362
- assertNotDestroyed(injector);
2363
- internalInjector = injector;
2364
- }
2365
- else {
2366
- internalInjector = new RetrievingInjector(injector);
2367
- }
2368
- let prevInjectorProfilerContext;
2369
- if (ngDevMode) {
2370
- prevInjectorProfilerContext = setInjectorProfilerContext({ injector, token: null });
2371
- }
2372
- const prevInjector = setCurrentInjector(internalInjector);
2373
- const previousInjectImplementation = setInjectImplementation(undefined);
2374
- try {
2375
- return fn();
2376
- }
2377
- finally {
2378
- setCurrentInjector(prevInjector);
2379
- ngDevMode && setInjectorProfilerContext(prevInjectorProfilerContext);
2380
- setInjectImplementation(previousInjectImplementation);
2381
- }
2382
- }
2383
- /**
2384
- * Whether the current stack frame is inside an injection context.
2385
- */
2386
- function isInInjectionContext() {
2387
- return getInjectImplementation() !== undefined || getCurrentInjector() != null;
2388
- }
2389
- /**
2390
- * Asserts that the current stack frame is within an [injection
2391
- * context](guide/di/dependency-injection-context) and has access to `inject`.
2392
- *
2393
- * @param debugFn a reference to the function making the assertion (used for the error message).
2394
- *
2395
- * @see [Asserts the context](guide/di/dependency-injection-context#asserts-the-context)
2396
- *
2397
- * @publicApi
2398
- */
2399
- function assertInInjectionContext(debugFn) {
2400
- // Taking a `Function` instead of a string name here prevents the unminified name of the function
2401
- // from being retained in the bundle regardless of minification.
2402
- if (!isInInjectionContext()) {
2403
- throw new RuntimeError(-203 /* RuntimeErrorCode.MISSING_INJECTION_CONTEXT */, ngDevMode &&
2404
- debugFn.name +
2405
- '() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`');
2406
- }
2407
- }
2408
-
2409
- // Below are constants for LView indices to help us look up LView members
2410
- // without having to remember the specific indices.
2411
- // Uglify will inline these when minifying so there shouldn't be a cost.
2412
- const HOST = 0;
2413
- const TVIEW = 1;
2414
- // Shared with LContainer
2415
- const FLAGS = 2;
2416
- const PARENT = 3;
2417
- const NEXT = 4;
2418
- const T_HOST = 5;
2419
- // End shared with LContainer
2420
- const HYDRATION = 6;
2421
- const CLEANUP = 7;
2422
- const CONTEXT = 8;
2423
- const INJECTOR = 9;
2424
- const ENVIRONMENT = 10;
2425
- const RENDERER = 11;
2426
- const CHILD_HEAD = 12;
2427
- const CHILD_TAIL = 13;
2428
- // FIXME(misko): Investigate if the three declarations aren't all same thing.
2429
- const DECLARATION_VIEW = 14;
2430
- const DECLARATION_COMPONENT_VIEW = 15;
2431
- const DECLARATION_LCONTAINER = 16;
2432
- const PREORDER_HOOK_FLAGS = 17;
2433
- const QUERIES = 18;
2434
- const ID = 19;
2435
- const EMBEDDED_VIEW_INJECTOR = 20;
2436
- const ON_DESTROY_HOOKS = 21;
2437
- const EFFECTS_TO_SCHEDULE = 22;
2438
- const EFFECTS = 23;
2439
- const REACTIVE_TEMPLATE_CONSUMER = 24;
2440
- const AFTER_RENDER_SEQUENCES_TO_ADD = 25;
2441
- const ANIMATIONS = 26;
2442
- /**
2443
- * Size of LView's header. Necessary to adjust for it when setting slots.
2444
- *
2445
- * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
2446
- * instruction index into `LView` index. All other indexes should be in the `LView` index space and
2447
- * there should be no need to refer to `HEADER_OFFSET` anywhere else.
2448
- */
2449
- const HEADER_OFFSET = 27;
2450
-
2451
- /**
2452
- * Special location which allows easy identification of type. If we have an array which was
2453
- * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
2454
- * `LContainer`.
2455
- */
2456
- const TYPE = 1;
2457
- /**
2458
- * Below are constants for LContainer indices to help us look up LContainer members
2459
- * without having to remember the specific indices.
2460
- * Uglify will inline these when minifying so there shouldn't be a cost.
2461
- */
2462
- // FLAGS, PARENT, NEXT, and T_HOST are indices 2, 3, 4, and 5
2463
- // As we already have these constants in LView, we don't need to re-create them.
2464
- const DEHYDRATED_VIEWS = 6;
2465
- const NATIVE = 7;
2466
- const VIEW_REFS = 8;
2467
- const MOVED_VIEWS = 9;
2468
- /**
2469
- * Size of LContainer's header. Represents the index after which all views in the
2470
- * container will be inserted. We need to keep a record of current views so we know
2471
- * which views are already in the DOM (and don't need to be re-added) and so we can
2472
- * remove views from the DOM when they are no longer required.
2473
- */
2474
- const CONTAINER_HEADER_OFFSET = 10;
2475
-
2476
- /**
2477
- * True if `value` is `LView`.
2478
- * @param value wrapped value of `RNode`, `LView`, `LContainer`
2479
- */
2480
- function isLView(value) {
2481
- return Array.isArray(value) && typeof value[TYPE] === 'object';
2482
- }
2483
- /**
2484
- * True if `value` is `LContainer`.
2485
- * @param value wrapped value of `RNode`, `LView`, `LContainer`
2486
- */
2487
- function isLContainer(value) {
2488
- return Array.isArray(value) && value[TYPE] === true;
2489
- }
2490
- function isContentQueryHost(tNode) {
2491
- return (tNode.flags & 4 /* TNodeFlags.hasContentQuery */) !== 0;
2492
- }
2493
- function isComponentHost(tNode) {
2494
- return tNode.componentOffset > -1;
2495
- }
2496
- function isDirectiveHost(tNode) {
2497
- return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
2498
- }
2499
- function isComponentDef(def) {
2500
- return !!def.template;
2501
- }
2502
- function isRootView(target) {
2503
- // Determines whether a given LView is marked as a root view.
2504
- return (target[FLAGS] & 512 /* LViewFlags.IsRoot */) !== 0;
2505
- }
2506
- function isProjectionTNode(tNode) {
2507
- return (tNode.type & 16 /* TNodeType.Projection */) === 16 /* TNodeType.Projection */;
2508
- }
2509
- function hasI18n(lView) {
2510
- return (lView[FLAGS] & 32 /* LViewFlags.HasI18n */) === 32 /* LViewFlags.HasI18n */;
2511
- }
2512
- function isDestroyed(lView) {
2513
- // Determines whether a given LView is marked as destroyed.
2514
- return (lView[FLAGS] & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */;
2515
- }
2516
-
2517
- // [Assert functions do not constraint type when they are guarded by a truthy
2518
- // expression.](https://github.com/microsoft/TypeScript/issues/37295)
2519
- function assertTNodeForLView(tNode, lView) {
2520
- assertTNodeForTView(tNode, lView[TVIEW]);
2521
- }
2522
- function assertTNodeCreationIndex(lView, index) {
2523
- const adjustedIndex = index + HEADER_OFFSET;
2524
- assertIndexInRange(lView, adjustedIndex);
2525
- assertLessThan(adjustedIndex, lView[TVIEW].bindingStartIndex, 'TNodes should be created before any bindings');
2526
- }
2527
- function assertTNodeForTView(tNode, tView) {
2528
- assertTNode(tNode);
2529
- const tData = tView.data;
2530
- for (let i = HEADER_OFFSET; i < tData.length; i++) {
2531
- if (tData[i] === tNode) {
2532
- return;
2533
- }
2534
- }
2535
- throwError('This TNode does not belong to this TView.');
2536
- }
2537
- function assertTNode(tNode) {
2538
- assertDefined(tNode, 'TNode must be defined');
2539
- if (!(tNode && typeof tNode === 'object' && tNode.hasOwnProperty('directiveStylingLast'))) {
2540
- throwError('Not of type TNode, got: ' + tNode);
2541
- }
2542
- }
2543
- function assertTIcu(tIcu) {
2544
- assertDefined(tIcu, 'Expected TIcu to be defined');
2545
- if (!(typeof tIcu.currentCaseLViewIndex === 'number')) {
2546
- throwError('Object is not of TIcu type.');
2547
- }
2548
- }
2549
- function assertComponentType(actual, msg = "Type passed in is not ComponentType, it does not have 'ɵcmp' property.") {
2550
- if (!getComponentDef(actual)) {
2551
- throwError(msg);
2552
- }
2553
- }
2554
- function assertNgModuleType(actual, msg = "Type passed in is not NgModuleType, it does not have 'ɵmod' property.") {
2555
- if (!getNgModuleDef(actual)) {
2556
- throwError(msg);
2557
- }
2558
- }
2559
- function assertHasParent(tNode) {
2560
- assertDefined(tNode, 'currentTNode should exist!');
2561
- assertDefined(tNode.parent, 'currentTNode should have a parent');
2562
- }
2563
- function assertLContainer(value) {
2564
- assertDefined(value, 'LContainer must be defined');
2565
- assertEqual(isLContainer(value), true, 'Expecting LContainer');
2566
- }
2567
- function assertLViewOrUndefined(value) {
2568
- value && assertEqual(isLView(value), true, 'Expecting LView or undefined or null');
2569
- }
2570
- function assertLView(value) {
2571
- assertDefined(value, 'LView must be defined');
2572
- assertEqual(isLView(value), true, 'Expecting LView');
2573
- }
2574
- function assertFirstCreatePass(tView, errMessage) {
2575
- assertEqual(tView.firstCreatePass, true, errMessage || 'Should only be called in first create pass.');
2576
- }
2577
- function assertFirstUpdatePass(tView, errMessage) {
2578
- assertEqual(tView.firstUpdatePass, true, 'Should only be called in first update pass.');
2579
- }
2580
- /**
2581
- * This is a basic sanity check that an object is probably a directive def. DirectiveDef is
2582
- * an interface, so we can't do a direct instanceof check.
2583
- */
2584
- function assertDirectiveDef(obj) {
2585
- if (obj.type === undefined || obj.selectors == undefined || obj.inputs === undefined) {
2586
- throwError(`Expected a DirectiveDef/ComponentDef and this object does not seem to have the expected shape.`);
2587
- }
2588
- }
2589
- function assertIndexInDeclRange(tView, index) {
2590
- assertBetween(HEADER_OFFSET, tView.bindingStartIndex, index);
2591
- }
2592
- function assertIndexInExpandoRange(lView, index) {
2593
- const tView = lView[1];
2594
- assertBetween(tView.expandoStartIndex, lView.length, index);
2595
- }
2596
- function assertBetween(lower, upper, index) {
2597
- if (!(lower <= index && index < upper)) {
2598
- throwError(`Index out of range (expecting ${lower} <= ${index} < ${upper})`);
2599
- }
2600
- }
2601
- function assertProjectionSlots(lView, errMessage) {
2602
- assertDefined(lView[DECLARATION_COMPONENT_VIEW], 'Component views should exist.');
2603
- assertDefined(lView[DECLARATION_COMPONENT_VIEW][T_HOST].projection, 'Components with projection nodes (<ng-content>) must have projection slots defined.');
2604
- }
2605
- function assertParentView(lView, errMessage) {
2606
- assertDefined(lView, "Component views should always have a parent view (component's host view)");
2607
- }
2608
- /**
2609
- * This is a basic sanity check that the `injectorIndex` seems to point to what looks like a
2610
- * NodeInjector data structure.
2611
- *
2612
- * @param lView `LView` which should be checked.
2613
- * @param injectorIndex index into the `LView` where the `NodeInjector` is expected.
2614
- */
2615
- function assertNodeInjector(lView, injectorIndex) {
2616
- assertIndexInExpandoRange(lView, injectorIndex);
2617
- assertIndexInExpandoRange(lView, injectorIndex + 8 /* NodeInjectorOffset.PARENT */);
2618
- assertNumber(lView[injectorIndex + 0], 'injectorIndex should point to a bloom filter');
2619
- assertNumber(lView[injectorIndex + 1], 'injectorIndex should point to a bloom filter');
2620
- assertNumber(lView[injectorIndex + 2], 'injectorIndex should point to a bloom filter');
2621
- assertNumber(lView[injectorIndex + 3], 'injectorIndex should point to a bloom filter');
2622
- assertNumber(lView[injectorIndex + 4], 'injectorIndex should point to a bloom filter');
2623
- assertNumber(lView[injectorIndex + 5], 'injectorIndex should point to a bloom filter');
2624
- assertNumber(lView[injectorIndex + 6], 'injectorIndex should point to a bloom filter');
2625
- assertNumber(lView[injectorIndex + 7], 'injectorIndex should point to a bloom filter');
2626
- assertNumber(lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */], 'injectorIndex should point to parent injector');
2627
- }
2628
-
2629
- const SVG_NAMESPACE = 'svg';
2630
- const MATH_ML_NAMESPACE = 'math';
2631
-
2632
- /**
2633
- * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
2634
- * in same location in `LView`. This is because we don't want to pre-allocate space for it
2635
- * because the storage is sparse. This file contains utilities for dealing with such data types.
2636
- *
2637
- * How do we know what is stored at a given location in `LView`.
2638
- * - `Array.isArray(value) === false` => `RNode` (The normal storage value)
2639
- * - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value.
2640
- * - `typeof value[TYPE] === 'object'` => `LView`
2641
- * - This happens when we have a component at a given location
2642
- * - `typeof value[TYPE] === true` => `LContainer`
2643
- * - This happens when we have `LContainer` binding at a given location.
2644
- *
2645
- *
2646
- * NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.
2647
- */
2648
- /**
2649
- * Returns `RNode`.
2650
- * @param value wrapped value of `RNode`, `LView`, `LContainer`
2651
- */
2652
- function unwrapRNode(value) {
2653
- while (Array.isArray(value)) {
2654
- value = value[HOST];
2655
- }
2656
- return value;
2657
- }
2658
- /**
2659
- * Returns `LView` or `null` if not found.
2660
- * @param value wrapped value of `RNode`, `LView`, `LContainer`
2661
- */
2662
- function unwrapLView(value) {
2663
- while (Array.isArray(value)) {
2664
- // This check is same as `isLView()` but we don't call at as we don't want to call
2665
- // `Array.isArray()` twice and give JITer more work for inlining.
2666
- if (typeof value[TYPE] === 'object')
2667
- return value;
2668
- value = value[HOST];
2669
- }
2670
- return null;
2671
- }
2672
- /**
2673
- * Retrieves an element value from the provided `viewData`, by unwrapping
2674
- * from any containers, component views, or style contexts.
2675
- */
2676
- function getNativeByIndex(index, lView) {
2677
- ngDevMode && assertIndexInRange(lView, index);
2678
- ngDevMode && assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Expected to be past HEADER_OFFSET');
2679
- return unwrapRNode(lView[index]);
2680
- }
2681
- /**
2682
- * Retrieve an `RNode` for a given `TNode` and `LView`.
2683
- *
2684
- * This function guarantees in dev mode to retrieve a non-null `RNode`.
2685
- *
2686
- * @param tNode
2687
- * @param lView
2688
- */
2689
- function getNativeByTNode(tNode, lView) {
2690
- ngDevMode && assertTNodeForLView(tNode, lView);
2691
- ngDevMode && assertIndexInRange(lView, tNode.index);
2692
- const node = unwrapRNode(lView[tNode.index]);
2693
- return node;
2694
- }
2695
- /**
2696
- * Retrieve an `RNode` or `null` for a given `TNode` and `LView`.
2697
- *
2698
- * Some `TNode`s don't have associated `RNode`s. For example `Projection`
2699
- *
2700
- * @param tNode
2701
- * @param lView
2702
- */
2703
- function getNativeByTNodeOrNull(tNode, lView) {
2704
- const index = tNode === null ? -1 : tNode.index;
2705
- if (index !== -1) {
2706
- ngDevMode && assertTNodeForLView(tNode, lView);
2707
- const node = unwrapRNode(lView[index]);
2708
- return node;
2709
- }
2710
- return null;
2711
- }
2712
- // fixme(misko): The return Type should be `TNode|null`
2713
- function getTNode(tView, index) {
2714
- ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
2715
- ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode');
2716
- const tNode = tView.data[index];
2717
- ngDevMode && tNode !== null && assertTNode(tNode);
2718
- return tNode;
2719
- }
2720
- /** Retrieves a value from any `LView` or `TData`. */
2721
- function load(view, index) {
2722
- ngDevMode && assertIndexInRange(view, index);
2723
- return view[index];
2724
- }
2725
- /** Store a value in the `data` at a given `index`. */
2726
- function store(tView, lView, index, value) {
2727
- // We don't store any static data for local variables, so the first time
2728
- // we see the template, we should store as null to avoid a sparse array
2729
- if (index >= tView.data.length) {
2730
- tView.data[index] = null;
2731
- tView.blueprint[index] = null;
2732
- }
2733
- lView[index] = value;
2734
- }
2735
- function getComponentLViewByIndex(nodeIndex, hostView) {
2736
- // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
2737
- ngDevMode && assertIndexInRange(hostView, nodeIndex);
2738
- const slotValue = hostView[nodeIndex];
2739
- const lView = isLView(slotValue) ? slotValue : slotValue[HOST];
2740
- return lView;
2741
- }
2742
- /** Checks whether a given view is in creation mode */
2743
- function isCreationMode(view) {
2744
- return (view[FLAGS] & 4 /* LViewFlags.CreationMode */) === 4 /* LViewFlags.CreationMode */;
2745
- }
2746
- /**
2747
- * Returns a boolean for whether the view is attached to the change detection tree.
2748
- *
2749
- * Note: This determines whether a view should be checked, not whether it's inserted
2750
- * into a container. For that, you'll want `viewAttachedToContainer` below.
2751
- */
2752
- function viewAttachedToChangeDetector(view) {
2753
- return (view[FLAGS] & 128 /* LViewFlags.Attached */) === 128 /* LViewFlags.Attached */;
2754
- }
2755
- /** Returns a boolean for whether the view is attached to a container. */
2756
- function viewAttachedToContainer(view) {
2757
- return isLContainer(view[PARENT]);
2758
- }
2759
- function getConstant(consts, index) {
2760
- if (index === null || index === undefined)
2761
- return null;
2762
- ngDevMode && assertIndexInRange(consts, index);
2763
- return consts[index];
2764
- }
2765
- /**
2766
- * Resets the pre-order hook flags of the view.
2767
- * @param lView the LView on which the flags are reset
2768
- */
2769
- function resetPreOrderHookFlags(lView) {
2770
- lView[PREORDER_HOOK_FLAGS] = 0;
2771
- }
2772
- /**
2773
- * Adds the `RefreshView` flag from the lView and updates HAS_CHILD_VIEWS_TO_REFRESH flag of
2774
- * parents.
2775
- */
2776
- function markViewForRefresh(lView) {
2777
- if (lView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
2778
- return;
2779
- }
2780
- lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
2781
- if (viewAttachedToChangeDetector(lView)) {
2782
- markAncestorsForTraversal(lView);
2783
- }
2784
- }
2785
- /**
2786
- * Walks up the LView hierarchy.
2787
- * @param nestingLevel Number of times to walk up in hierarchy.
2788
- * @param currentView View from which to start the lookup.
2789
- */
2790
- function walkUpViews(nestingLevel, currentView) {
2791
- while (nestingLevel > 0) {
2792
- ngDevMode &&
2793
- assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.');
2794
- currentView = currentView[DECLARATION_VIEW];
2795
- nestingLevel--;
2796
- }
2797
- return currentView;
2798
- }
2799
- function requiresRefreshOrTraversal(lView) {
2800
- return !!(lView[FLAGS] & (1024 /* LViewFlags.RefreshView */ | 8192 /* LViewFlags.HasChildViewsToRefresh */) ||
2801
- lView[REACTIVE_TEMPLATE_CONSUMER]?.dirty);
2802
- }
2803
- /**
2804
- * Updates the `HasChildViewsToRefresh` flag on the parents of the `LView` as well as the
2805
- * parents above.
2806
- */
2807
- function updateAncestorTraversalFlagsOnAttach(lView) {
2808
- lView[ENVIRONMENT].changeDetectionScheduler?.notify(8 /* NotificationSource.ViewAttached */);
2809
- if (lView[FLAGS] & 64 /* LViewFlags.Dirty */) {
2810
- lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
2811
- }
2812
- if (requiresRefreshOrTraversal(lView)) {
2813
- markAncestorsForTraversal(lView);
2814
- }
2815
- }
2816
- /**
2817
- * Ensures views above the given `lView` are traversed during change detection even when they are
2818
- * not dirty.
2819
- *
2820
- * This is done by setting the `HAS_CHILD_VIEWS_TO_REFRESH` flag up to the root, stopping when the
2821
- * flag is already `true` or the `lView` is detached.
2822
- */
2823
- function markAncestorsForTraversal(lView) {
2824
- lView[ENVIRONMENT].changeDetectionScheduler?.notify(0 /* NotificationSource.MarkAncestorsForTraversal */);
2825
- let parent = getLViewParent(lView);
2826
- while (parent !== null) {
2827
- // We stop adding markers to the ancestors once we reach one that already has the marker. This
2828
- // is to avoid needlessly traversing all the way to the root when the marker already exists.
2829
- if (parent[FLAGS] & 8192 /* LViewFlags.HasChildViewsToRefresh */) {
2830
- break;
2831
- }
2832
- parent[FLAGS] |= 8192 /* LViewFlags.HasChildViewsToRefresh */;
2833
- if (!viewAttachedToChangeDetector(parent)) {
2834
- break;
2835
- }
2836
- parent = getLViewParent(parent);
2837
- }
2838
- }
2839
- /**
2840
- * Stores a LView-specific destroy callback.
2841
- */
2842
- function storeLViewOnDestroy(lView, onDestroyCallback) {
2843
- if (isDestroyed(lView)) {
2844
- throw new RuntimeError(911 /* RuntimeErrorCode.VIEW_ALREADY_DESTROYED */, ngDevMode && 'View has already been destroyed.');
2845
- }
2846
- if (lView[ON_DESTROY_HOOKS] === null) {
2847
- lView[ON_DESTROY_HOOKS] = [];
2848
- }
2849
- lView[ON_DESTROY_HOOKS].push(onDestroyCallback);
2850
- }
2851
- /**
2852
- * Removes previously registered LView-specific destroy callback.
2853
- */
2854
- function removeLViewOnDestroy(lView, onDestroyCallback) {
2855
- if (lView[ON_DESTROY_HOOKS] === null)
2856
- return;
2857
- const destroyCBIdx = lView[ON_DESTROY_HOOKS].indexOf(onDestroyCallback);
2858
- if (destroyCBIdx !== -1) {
2859
- lView[ON_DESTROY_HOOKS].splice(destroyCBIdx, 1);
2860
- }
2861
- }
2862
- /**
2863
- * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of
2864
- * that LContainer, which is an LView
2865
- * @param lView the lView whose parent to get
2866
- */
2867
- function getLViewParent(lView) {
2868
- ngDevMode && assertLView(lView);
2869
- const parent = lView[PARENT];
2870
- return isLContainer(parent) ? parent[PARENT] : parent;
2871
- }
2872
- function getOrCreateLViewCleanup(view) {
2873
- // top level variables should not be exported for performance reasons (PERF_NOTES.md)
2874
- return (view[CLEANUP] ??= []);
2875
- }
2876
- function getOrCreateTViewCleanup(tView) {
2877
- return (tView.cleanup ??= []);
2878
- }
2879
- /**
2880
- * Saves context for this cleanup function in LView.cleanupInstances.
2881
- *
2882
- * On the first template pass, saves in TView:
2883
- * - Cleanup function
2884
- * - Index of context we just saved in LView.cleanupInstances
2885
- */
2886
- function storeCleanupWithContext(tView, lView, context, cleanupFn) {
2887
- const lCleanup = getOrCreateLViewCleanup(lView);
2888
- // Historically the `storeCleanupWithContext` was used to register both framework-level and
2889
- // user-defined cleanup callbacks, but over time those two types of cleanups were separated.
2890
- // This dev mode checks assures that user-level cleanup callbacks are _not_ stored in data
2891
- // structures reserved for framework-specific hooks.
2892
- ngDevMode &&
2893
- assertDefined(context, 'Cleanup context is mandatory when registering framework-level destroy hooks');
2894
- lCleanup.push(context);
2895
- if (tView.firstCreatePass) {
2896
- getOrCreateTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1);
2897
- }
2898
- else {
2899
- // Make sure that no new framework-level cleanup functions are registered after the first
2900
- // template pass is done (and TView data structures are meant to fully constructed).
2901
- if (ngDevMode) {
2902
- Object.freeze(getOrCreateTViewCleanup(tView));
2903
- }
2904
- }
2905
- }
2906
-
2907
- const instructionState = {
2908
- lFrame: createLFrame(null),
2909
- bindingsEnabled: true,
2910
- skipHydrationRootTNode: null,
2911
- };
2912
- var CheckNoChangesMode;
2913
- (function (CheckNoChangesMode) {
2914
- CheckNoChangesMode[CheckNoChangesMode["Off"] = 0] = "Off";
2915
- CheckNoChangesMode[CheckNoChangesMode["Exhaustive"] = 1] = "Exhaustive";
2916
- CheckNoChangesMode[CheckNoChangesMode["OnlyDirtyViews"] = 2] = "OnlyDirtyViews";
2917
- })(CheckNoChangesMode || (CheckNoChangesMode = {}));
2918
- /**
2919
- * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
2920
- *
2921
- * Necessary to support ChangeDetectorRef.checkNoChanges().
2922
- *
2923
- * The `checkNoChanges` function is invoked only in ngDevMode=true and verifies that no unintended
2924
- * changes exist in the change detector or its children.
2925
- */
2926
- let _checkNoChangesMode = 0; /* CheckNoChangesMode.Off */
2927
- /**
2928
- * Flag used to indicate that we are in the middle running change detection on a view
2929
- *
2930
- * @see detectChangesInViewWhileDirty
2931
- */
2932
- let _isRefreshingViews = false;
2933
- function getElementDepthCount() {
2934
- return instructionState.lFrame.elementDepthCount;
2935
- }
2936
- function increaseElementDepthCount() {
2937
- instructionState.lFrame.elementDepthCount++;
2938
- }
2939
- function decreaseElementDepthCount() {
2940
- instructionState.lFrame.elementDepthCount--;
2941
- }
2942
- function getBindingsEnabled() {
2943
- return instructionState.bindingsEnabled;
2944
- }
2945
- /**
2946
- * Returns true if currently inside a skip hydration block.
2947
- * @returns boolean
2948
- */
2949
- function isInSkipHydrationBlock() {
2950
- return instructionState.skipHydrationRootTNode !== null;
2951
- }
2952
- /**
2953
- * Returns true if this is the root TNode of the skip hydration block.
2954
- * @param tNode the current TNode
2955
- * @returns boolean
2956
- */
2957
- function isSkipHydrationRootTNode(tNode) {
2958
- return instructionState.skipHydrationRootTNode === tNode;
2959
- }
2960
- /**
2961
- * Enables directive matching on elements.
2962
- *
2963
- * * Example:
2964
- * ```html
2965
- * <my-comp my-directive>
2966
- * Should match component / directive.
2967
- * </my-comp>
2968
- * <div ngNonBindable>
2969
- * <!-- ɵɵdisableBindings() -->
2970
- * <my-comp my-directive>
2971
- * Should not match component / directive because we are in ngNonBindable.
2972
- * </my-comp>
2973
- * <!-- ɵɵenableBindings() -->
2974
- * </div>
2975
- * ```
2976
- *
2977
- * @codeGenApi
2978
- */
2979
- function ɵɵenableBindings() {
2980
- instructionState.bindingsEnabled = true;
2981
- }
2982
- /**
2983
- * Sets a flag to specify that the TNode is in a skip hydration block.
2984
- * @param tNode the current TNode
2985
- */
2986
- function enterSkipHydrationBlock(tNode) {
2987
- instructionState.skipHydrationRootTNode = tNode;
2988
- }
2989
- /**
2990
- * Disables directive matching on element.
2991
- *
2992
- * * Example:
2993
- * ```html
2994
- * <my-comp my-directive>
2995
- * Should match component / directive.
2996
- * </my-comp>
2997
- * <div ngNonBindable>
2998
- * <!-- ɵɵdisableBindings() -->
2999
- * <my-comp my-directive>
3000
- * Should not match component / directive because we are in ngNonBindable.
3001
- * </my-comp>
3002
- * <!-- ɵɵenableBindings() -->
3003
- * </div>
3004
- * ```
3005
- *
3006
- * @codeGenApi
3007
- */
3008
- function ɵɵdisableBindings() {
3009
- instructionState.bindingsEnabled = false;
3010
- }
3011
- /**
3012
- * Clears the root skip hydration node when leaving a skip hydration block.
3013
- */
3014
- function leaveSkipHydrationBlock() {
3015
- instructionState.skipHydrationRootTNode = null;
3016
- }
3017
- /**
3018
- * Return the current `LView`.
3019
- */
3020
- function getLView() {
3021
- return instructionState.lFrame.lView;
3022
- }
3023
- /**
3024
- * Return the current `TView`.
3025
- */
3026
- function getTView() {
3027
- return instructionState.lFrame.tView;
3028
- }
3029
- /**
3030
- * Restores `contextViewData` to the given OpaqueViewState instance.
3031
- *
3032
- * Used in conjunction with the getCurrentView() instruction to save a snapshot
3033
- * of the current view and restore it when listeners are invoked. This allows
3034
- * walking the declaration view tree in listeners to get vars from parent views.
3035
- *
3036
- * @param viewToRestore The OpaqueViewState instance to restore.
3037
- * @returns Context of the restored OpaqueViewState instance.
3038
- *
3039
- * @codeGenApi
3040
- */
3041
- function ɵɵrestoreView(viewToRestore) {
3042
- instructionState.lFrame.contextLView = viewToRestore;
3043
- return viewToRestore[CONTEXT];
3044
- }
3045
- /**
3046
- * Clears the view set in `ɵɵrestoreView` from memory. Returns the passed in
3047
- * value so that it can be used as a return value of an instruction.
3048
- *
3049
- * @codeGenApi
3050
- */
3051
- function ɵɵresetView(value) {
3052
- instructionState.lFrame.contextLView = null;
3053
- return value;
3054
- }
3055
- function getCurrentTNode() {
3056
- let currentTNode = getCurrentTNodePlaceholderOk();
3057
- while (currentTNode !== null && currentTNode.type === 64 /* TNodeType.Placeholder */) {
3058
- currentTNode = currentTNode.parent;
3059
- }
3060
- return currentTNode;
3061
- }
3062
- function getCurrentTNodePlaceholderOk() {
3063
- return instructionState.lFrame.currentTNode;
3064
- }
3065
- function getCurrentParentTNode() {
3066
- const lFrame = instructionState.lFrame;
3067
- const currentTNode = lFrame.currentTNode;
3068
- return lFrame.isParent ? currentTNode : currentTNode.parent;
3069
- }
3070
- function setCurrentTNode(tNode, isParent) {
3071
- ngDevMode && tNode && assertTNodeForTView(tNode, instructionState.lFrame.tView);
3072
- const lFrame = instructionState.lFrame;
3073
- lFrame.currentTNode = tNode;
3074
- lFrame.isParent = isParent;
3075
- }
3076
- function isCurrentTNodeParent() {
3077
- return instructionState.lFrame.isParent;
3078
- }
3079
- function setCurrentTNodeAsNotParent() {
3080
- instructionState.lFrame.isParent = false;
3081
- }
3082
- function getContextLView() {
3083
- const contextLView = instructionState.lFrame.contextLView;
3084
- ngDevMode && assertDefined(contextLView, 'contextLView must be defined.');
3085
- return contextLView;
3086
- }
3087
- function isInCheckNoChangesMode() {
3088
- !ngDevMode && throwError('Must never be called in production mode');
3089
- return _checkNoChangesMode !== CheckNoChangesMode.Off;
3090
- }
3091
- function isExhaustiveCheckNoChanges() {
3092
- !ngDevMode && throwError('Must never be called in production mode');
3093
- return _checkNoChangesMode === CheckNoChangesMode.Exhaustive;
3094
- }
3095
- function setIsInCheckNoChangesMode(mode) {
3096
- !ngDevMode && throwError('Must never be called in production mode');
3097
- _checkNoChangesMode = mode;
3098
- }
3099
- function isRefreshingViews() {
3100
- return _isRefreshingViews;
3101
- }
3102
- function setIsRefreshingViews(mode) {
3103
- const prev = _isRefreshingViews;
3104
- _isRefreshingViews = mode;
3105
- return prev;
3106
- }
3107
- // top level variables should not be exported for performance reasons (PERF_NOTES.md)
3108
- function getBindingRoot() {
3109
- const lFrame = instructionState.lFrame;
3110
- let index = lFrame.bindingRootIndex;
3111
- if (index === -1) {
3112
- index = lFrame.bindingRootIndex = lFrame.tView.bindingStartIndex;
3113
- }
3114
- return index;
3115
- }
3116
- function getBindingIndex() {
3117
- return instructionState.lFrame.bindingIndex;
3118
- }
3119
- function setBindingIndex(value) {
3120
- return (instructionState.lFrame.bindingIndex = value);
3121
- }
3122
- function nextBindingIndex() {
3123
- return instructionState.lFrame.bindingIndex++;
3124
- }
3125
- function incrementBindingIndex(count) {
3126
- const lFrame = instructionState.lFrame;
3127
- const index = lFrame.bindingIndex;
3128
- lFrame.bindingIndex = lFrame.bindingIndex + count;
3129
- return index;
3130
- }
3131
- function isInI18nBlock() {
3132
- return instructionState.lFrame.inI18n;
3133
- }
3134
- function setInI18nBlock(isInI18nBlock) {
3135
- instructionState.lFrame.inI18n = isInI18nBlock;
3136
- }
3137
- /**
3138
- * Set a new binding root index so that host template functions can execute.
3139
- *
3140
- * Bindings inside the host template are 0 index. But because we don't know ahead of time
3141
- * how many host bindings we have we can't pre-compute them. For this reason they are all
3142
- * 0 index and we just shift the root so that they match next available location in the LView.
3143
- *
3144
- * @param bindingRootIndex Root index for `hostBindings`
3145
- * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive
3146
- * whose `hostBindings` are being processed.
3147
- */
3148
- function setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex) {
3149
- const lFrame = instructionState.lFrame;
3150
- lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex;
3151
- setCurrentDirectiveIndex(currentDirectiveIndex);
3152
- }
3153
- /**
3154
- * When host binding is executing this points to the directive index.
3155
- * `TView.data[getCurrentDirectiveIndex()]` is `DirectiveDef`
3156
- * `LView[getCurrentDirectiveIndex()]` is directive instance.
3157
- */
3158
- function getCurrentDirectiveIndex() {
3159
- return instructionState.lFrame.currentDirectiveIndex;
3160
- }
3161
- /**
3162
- * Sets an index of a directive whose `hostBindings` are being processed.
3163
- *
3164
- * @param currentDirectiveIndex `TData` index where current directive instance can be found.
3165
- */
3166
- function setCurrentDirectiveIndex(currentDirectiveIndex) {
3167
- instructionState.lFrame.currentDirectiveIndex = currentDirectiveIndex;
3168
- }
3169
- /**
3170
- * Retrieve the current `DirectiveDef` which is active when `hostBindings` instruction is being
3171
- * executed.
3172
- *
3173
- * @param tData Current `TData` where the `DirectiveDef` will be looked up at.
3174
- */
3175
- function getCurrentDirectiveDef(tData) {
3176
- const currentDirectiveIndex = instructionState.lFrame.currentDirectiveIndex;
3177
- return currentDirectiveIndex === -1 ? null : tData[currentDirectiveIndex];
3178
- }
3179
- function getCurrentQueryIndex() {
3180
- return instructionState.lFrame.currentQueryIndex;
3181
- }
3182
- function setCurrentQueryIndex(value) {
3183
- instructionState.lFrame.currentQueryIndex = value;
3184
- }
3185
- /**
3186
- * Returns a `TNode` of the location where the current `LView` is declared at.
3187
- *
3188
- * @param lView an `LView` that we want to find parent `TNode` for.
3189
- */
3190
- function getDeclarationTNode(lView) {
3191
- const tView = lView[TVIEW];
3192
- // Return the declaration parent for embedded views
3193
- if (tView.type === 2 /* TViewType.Embedded */) {
3194
- ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
3195
- return tView.declTNode;
3196
- }
3197
- // Components don't have `TView.declTNode` because each instance of component could be
3198
- // inserted in different location, hence `TView.declTNode` is meaningless.
3199
- // Falling back to `T_HOST` in case we cross component boundary.
3200
- if (tView.type === 1 /* TViewType.Component */) {
3201
- return lView[T_HOST];
3202
- }
3203
- // Remaining TNode type is `TViewType.Root` which doesn't have a parent TNode.
3204
- return null;
3205
- }
3206
- /**
3207
- * This is a light weight version of the `enterView` which is needed by the DI system.
3208
- *
3209
- * @param lView `LView` location of the DI context.
3210
- * @param tNode `TNode` for DI context
3211
- * @param flags DI context flags. if `SkipSelf` flag is set than we walk up the declaration
3212
- * tree from `tNode` until we find parent declared `TElementNode`.
3213
- * @returns `true` if we have successfully entered DI associated with `tNode` (or with declared
3214
- * `TNode` if `flags` has `SkipSelf`). Failing to enter DI implies that no associated
3215
- * `NodeInjector` can be found and we should instead use `ModuleInjector`.
3216
- * - If `true` than this call must be fallowed by `leaveDI`
3217
- * - If `false` than this call failed and we should NOT call `leaveDI`
3218
- */
3219
- function enterDI(lView, tNode, flags) {
3220
- ngDevMode && assertLViewOrUndefined(lView);
3221
- if (flags & 4 /* InternalInjectFlags.SkipSelf */) {
3222
- ngDevMode && assertTNodeForTView(tNode, lView[TVIEW]);
3223
- let parentTNode = tNode;
3224
- let parentLView = lView;
3225
- while (true) {
3226
- ngDevMode && assertDefined(parentTNode, 'Parent TNode should be defined');
3227
- parentTNode = parentTNode.parent;
3228
- if (parentTNode === null && !(flags & 1 /* InternalInjectFlags.Host */)) {
3229
- parentTNode = getDeclarationTNode(parentLView);
3230
- if (parentTNode === null)
3231
- break;
3232
- // In this case, a parent exists and is definitely an element. So it will definitely
3233
- // have an existing lView as the declaration view, which is why we can assume it's defined.
3234
- ngDevMode && assertDefined(parentLView, 'Parent LView should be defined');
3235
- parentLView = parentLView[DECLARATION_VIEW];
3236
- // In Ivy there are Comment nodes that correspond to ngIf and NgFor embedded directives
3237
- // We want to skip those and look only at Elements and ElementContainers to ensure
3238
- // we're looking at true parent nodes, and not content or other types.
3239
- if (parentTNode.type & (2 /* TNodeType.Element */ | 8 /* TNodeType.ElementContainer */)) {
3240
- break;
3241
- }
3242
- }
3243
- else {
3244
- break;
3245
- }
3246
- }
3247
- if (parentTNode === null) {
3248
- // If we failed to find a parent TNode this means that we should use module injector.
3249
- return false;
3250
- }
3251
- else {
3252
- tNode = parentTNode;
3253
- lView = parentLView;
3254
- }
3255
- }
3256
- ngDevMode && assertTNodeForLView(tNode, lView);
3257
- const lFrame = (instructionState.lFrame = allocLFrame());
3258
- lFrame.currentTNode = tNode;
3259
- lFrame.lView = lView;
3260
- return true;
3261
- }
3262
- /**
3263
- * Swap the current lView with a new lView.
3264
- *
3265
- * For performance reasons we store the lView in the top level of the module.
3266
- * This way we minimize the number of properties to read. Whenever a new view
3267
- * is entered we have to store the lView for later, and when the view is
3268
- * exited the state has to be restored
3269
- *
3270
- * @param newView New lView to become active
3271
- * @returns the previously active lView;
3272
- */
3273
- function enterView(newView) {
3274
- ngDevMode && assertNotEqual(newView[0], newView[1], '????');
3275
- ngDevMode && assertLViewOrUndefined(newView);
3276
- const newLFrame = allocLFrame();
3277
- if (ngDevMode) {
3278
- assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
3279
- assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
3280
- assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
3281
- assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
3282
- assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
3283
- assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
3284
- assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
3285
- assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
3286
- assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
3287
- }
3288
- const tView = newView[TVIEW];
3289
- instructionState.lFrame = newLFrame;
3290
- ngDevMode && tView.firstChild && assertTNodeForTView(tView.firstChild, tView);
3291
- newLFrame.currentTNode = tView.firstChild;
3292
- newLFrame.lView = newView;
3293
- newLFrame.tView = tView;
3294
- newLFrame.contextLView = newView;
3295
- newLFrame.bindingIndex = tView.bindingStartIndex;
3296
- newLFrame.inI18n = false;
3297
- }
3298
- /**
3299
- * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure.
3300
- */
3301
- function allocLFrame() {
3302
- const currentLFrame = instructionState.lFrame;
3303
- const childLFrame = currentLFrame === null ? null : currentLFrame.child;
3304
- const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame;
3305
- return newLFrame;
3306
- }
3307
- function createLFrame(parent) {
3308
- const lFrame = {
3309
- currentTNode: null,
3310
- isParent: true,
3311
- lView: null,
3312
- tView: null,
3313
- selectedIndex: -1,
3314
- contextLView: null,
3315
- elementDepthCount: 0,
3316
- currentNamespace: null,
3317
- currentDirectiveIndex: -1,
3318
- bindingRootIndex: -1,
3319
- bindingIndex: -1,
3320
- currentQueryIndex: 0,
3321
- parent: parent,
3322
- child: null,
3323
- inI18n: false,
3324
- };
3325
- parent !== null && (parent.child = lFrame); // link the new LFrame for reuse.
3326
- return lFrame;
3327
- }
3328
- /**
3329
- * A lightweight version of leave which is used with DI.
3330
- *
3331
- * This function only resets `currentTNode` and `LView` as those are the only properties
3332
- * used with DI (`enterDI()`).
3333
- *
3334
- * NOTE: This function is reexported as `leaveDI`. However `leaveDI` has return type of `void` where
3335
- * as `leaveViewLight` has `LFrame`. This is so that `leaveViewLight` can be used in `leaveView`.
3336
- */
3337
- function leaveViewLight() {
3338
- const oldLFrame = instructionState.lFrame;
3339
- instructionState.lFrame = oldLFrame.parent;
3340
- oldLFrame.currentTNode = null;
3341
- oldLFrame.lView = null;
3342
- return oldLFrame;
3343
- }
3344
- /**
3345
- * This is a lightweight version of the `leaveView` which is needed by the DI system.
3346
- *
3347
- * NOTE: this function is an alias so that we can change the type of the function to have `void`
3348
- * return type.
3349
- */
3350
- const leaveDI = leaveViewLight;
3351
- /**
3352
- * Leave the current `LView`
3353
- *
3354
- * This pops the `LFrame` with the associated `LView` from the stack.
3355
- *
3356
- * IMPORTANT: We must zero out the `LFrame` values here otherwise they will be retained. This is
3357
- * because for performance reasons we don't release `LFrame` but rather keep it for next use.
3358
- */
3359
- function leaveView() {
3360
- const oldLFrame = leaveViewLight();
3361
- oldLFrame.isParent = true;
3362
- oldLFrame.tView = null;
3363
- oldLFrame.selectedIndex = -1;
3364
- oldLFrame.contextLView = null;
3365
- oldLFrame.elementDepthCount = 0;
3366
- oldLFrame.currentDirectiveIndex = -1;
3367
- oldLFrame.currentNamespace = null;
3368
- oldLFrame.bindingRootIndex = -1;
3369
- oldLFrame.bindingIndex = -1;
3370
- oldLFrame.currentQueryIndex = 0;
3371
- }
3372
- function nextContextImpl(level) {
3373
- const contextLView = (instructionState.lFrame.contextLView = walkUpViews(level, instructionState.lFrame.contextLView));
3374
- return contextLView[CONTEXT];
3375
- }
3376
- /**
3377
- * Gets the currently selected element index.
3378
- *
3379
- * Used with {@link property} instruction (and more in the future) to identify the index in the
3380
- * current `LView` to act on.
3381
- */
3382
- function getSelectedIndex() {
3383
- return instructionState.lFrame.selectedIndex;
3384
- }
3385
- /**
3386
- * Sets the most recent index passed to {@link select}
3387
- *
3388
- * Used with {@link property} instruction (and more in the future) to identify the index in the
3389
- * current `LView` to act on.
3390
- *
3391
- * (Note that if an "exit function" was set earlier (via `setElementExitFn()`) then that will be
3392
- * run if and when the provided `index` value is different from the current selected index value.)
3393
- */
3394
- function setSelectedIndex(index) {
3395
- ngDevMode &&
3396
- index !== -1 &&
3397
- assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
3398
- ngDevMode &&
3399
- assertLessThan(index, instructionState.lFrame.lView.length, "Can't set index passed end of LView");
3400
- instructionState.lFrame.selectedIndex = index;
3401
- }
3402
- /**
3403
- * Gets the `tNode` that represents currently selected element.
3404
- */
3405
- function getSelectedTNode() {
3406
- const lFrame = instructionState.lFrame;
3407
- return getTNode(lFrame.tView, lFrame.selectedIndex);
3408
- }
3409
- /**
3410
- * Sets the namespace used to create elements to `'http://www.w3.org/2000/svg'` in global state.
3411
- *
3412
- * @codeGenApi
3413
- */
3414
- function ɵɵnamespaceSVG() {
3415
- instructionState.lFrame.currentNamespace = SVG_NAMESPACE;
3416
- }
3417
- /**
3418
- * Sets the namespace used to create elements to `'http://www.w3.org/1998/MathML/'` in global state.
3419
- *
3420
- * @codeGenApi
3421
- */
3422
- function ɵɵnamespaceMathML() {
3423
- instructionState.lFrame.currentNamespace = MATH_ML_NAMESPACE;
3424
- }
3425
- /**
3426
- * Sets the namespace used to create elements to `null`, which forces element creation to use
3427
- * `createElement` rather than `createElementNS`.
3428
- *
3429
- * @codeGenApi
3430
- */
3431
- function ɵɵnamespaceHTML() {
3432
- namespaceHTMLInternal();
3433
- }
3434
- /**
3435
- * Sets the namespace used to create elements to `null`, which forces element creation to use
3436
- * `createElement` rather than `createElementNS`.
3437
- */
3438
- function namespaceHTMLInternal() {
3439
- instructionState.lFrame.currentNamespace = null;
3440
- }
3441
- function getNamespace() {
3442
- return instructionState.lFrame.currentNamespace;
3443
- }
3444
- let _wasLastNodeCreated = true;
3445
- /**
3446
- * Retrieves a global flag that indicates whether the most recent DOM node
3447
- * was created or hydrated.
3448
- */
3449
- function wasLastNodeCreated() {
3450
- return _wasLastNodeCreated;
3451
- }
3452
- /**
3453
- * Sets a global flag to indicate whether the most recent DOM node
3454
- * was created or hydrated.
3455
- */
3456
- function lastNodeWasCreated(flag) {
3457
- _wasLastNodeCreated = flag;
3458
- }
3459
-
3460
- /**
3461
- * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s.
3462
- */
3463
- function createInjector(defType, parent = null, additionalProviders = null, name) {
3464
- const injector = createInjectorWithoutInjectorInstances(defType, parent, additionalProviders, name);
3465
- injector.resolveInjectorInitializers();
3466
- return injector;
3467
- }
3468
- /**
3469
- * Creates a new injector without eagerly resolving its injector types. Can be used in places
3470
- * where resolving the injector types immediately can lead to an infinite loop. The injector types
3471
- * should be resolved at a later point by calling `_resolveInjectorDefTypes`.
3472
- */
3473
- function createInjectorWithoutInjectorInstances(defType, parent = null, additionalProviders = null, name, scopes = new Set()) {
3474
- const providers = [additionalProviders || EMPTY_ARRAY, importProvidersFrom(defType)];
3475
- name = name || (typeof defType === 'object' ? undefined : stringify(defType));
3476
- return new R3Injector(providers, parent || getNullInjector(), name || null, scopes);
3477
- }
3478
-
3479
- /**
3480
- * Concrete injectors implement this interface. Injectors are configured
3481
- * with [providers](guide/di/dependency-injection-providers) that associate
3482
- * dependencies of various types with [injection tokens](guide/di/dependency-injection-providers).
3483
- *
3484
- * @see [DI Providers](guide/di/dependency-injection-providers).
3485
- * @see {@link StaticProvider}
3486
- *
3487
- * @usageNotes
3488
- *
3489
- * The following example creates a service injector instance.
3490
- *
3491
- * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
3492
- *
3493
- * ### Usage example
3494
- *
3495
- * {@example core/di/ts/injector_spec.ts region='Injector'}
3496
- *
3497
- * `Injector` returns itself when given `Injector` as a token:
3498
- *
3499
- * {@example core/di/ts/injector_spec.ts region='injectInjector'}
3500
- *
3501
- * @publicApi
3502
- */
3503
- class Injector {
3504
- static THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
3505
- static NULL = new NullInjector();
3506
- static create(options, parent) {
3507
- if (Array.isArray(options)) {
3508
- return createInjector({ name: '' }, parent, options, '');
3509
- }
3510
- else {
3511
- const name = options.name ?? '';
3512
- return createInjector({ name }, options.parent, options.providers, name);
3513
- }
3514
- }
3515
- /** @nocollapse */
3516
- static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({
3517
- token: Injector,
3518
- providedIn: 'any',
3519
- factory: () => ɵɵinject(INJECTOR$1),
3520
- });
3521
- /**
3522
- * @internal
3523
- * @nocollapse
3524
- */
3525
- static __NG_ELEMENT_ID__ = -1 /* InjectorMarkers.Injector */;
3526
- }
3527
-
3528
- /**
3529
- * A DI Token representing the main rendering context.
3530
- * In a browser and SSR this is the DOM Document.
3531
- * When using SSR, that document is created by [Domino](https://github.com/angular/domino).
3532
- *
3533
- * @publicApi
3534
- */
3535
- const DOCUMENT = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'DocumentToken' : '');
3536
-
3537
- /**
3538
- * `DestroyRef` lets you set callbacks to run for any cleanup or destruction behavior.
3539
- * The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
3540
- * is injected in a component or directive, the callbacks run when that component or
3541
- * directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
3542
- *
3543
- * @publicApi
3544
- */
3545
- class DestroyRef {
3546
- /**
3547
- * @internal
3548
- * @nocollapse
3549
- */
3550
- static __NG_ELEMENT_ID__ = injectDestroyRef;
3551
- /**
3552
- * @internal
3553
- * @nocollapse
3554
- */
3555
- static __NG_ENV_ID__ = (injector) => injector;
3556
- }
3557
- class NodeInjectorDestroyRef extends DestroyRef {
3558
- _lView;
3559
- constructor(_lView) {
3560
- super();
3561
- this._lView = _lView;
3562
- }
3563
- get destroyed() {
3564
- return isDestroyed(this._lView);
3565
- }
3566
- onDestroy(callback) {
3567
- const lView = this._lView;
3568
- storeLViewOnDestroy(lView, callback);
3569
- return () => removeLViewOnDestroy(lView, callback);
3570
- }
3571
- }
3572
- function injectDestroyRef() {
3573
- return new NodeInjectorDestroyRef(getLView());
3574
- }
3575
-
3576
- const SCHEDULE_IN_ROOT_ZONE_DEFAULT = false;
3577
-
3578
- /**
3579
- * Internal implementation of the pending tasks service.
3580
- */
3581
- class PendingTasksInternal {
3582
- taskId = 0;
3583
- pendingTasks = new Set();
3584
- destroyed = false;
3585
- pendingTask = new BehaviorSubject(false);
3586
- get hasPendingTasks() {
3587
- // Accessing the value of a closed `BehaviorSubject` throws an error.
3588
- return this.destroyed ? false : this.pendingTask.value;
3589
- }
3590
- /**
3591
- * In case the service is about to be destroyed, return a self-completing observable.
3592
- * Otherwise, return the observable that emits the current state of pending tasks.
3593
- */
3594
- get hasPendingTasksObservable() {
3595
- if (this.destroyed) {
3596
- // Manually creating the observable pulls less symbols from RxJS than `of(false)`.
3597
- return new Observable((subscriber) => {
3598
- subscriber.next(false);
3599
- subscriber.complete();
3600
- });
3601
- }
3602
- return this.pendingTask;
3603
- }
3604
- add() {
3605
- // Emitting a value to a closed subject throws an error.
3606
- if (!this.hasPendingTasks && !this.destroyed) {
3607
- this.pendingTask.next(true);
3608
- }
3609
- const taskId = this.taskId++;
3610
- this.pendingTasks.add(taskId);
3611
- return taskId;
3612
- }
3613
- has(taskId) {
3614
- return this.pendingTasks.has(taskId);
3615
- }
3616
- remove(taskId) {
3617
- this.pendingTasks.delete(taskId);
3618
- if (this.pendingTasks.size === 0 && this.hasPendingTasks) {
3619
- this.pendingTask.next(false);
3620
- }
3621
- }
3622
- ngOnDestroy() {
3623
- this.pendingTasks.clear();
3624
- if (this.hasPendingTasks) {
3625
- this.pendingTask.next(false);
3626
- }
3627
- // We call `unsubscribe()` to release observers, as users may forget to
3628
- // unsubscribe manually when subscribing to `isStable`. We do not call
3629
- // `complete()` because it is unsafe; if someone subscribes using the `first`
3630
- // operator and the observable completes before emitting a value,
3631
- // RxJS will throw an error.
3632
- this.destroyed = true;
3633
- this.pendingTask.unsubscribe();
3634
- }
3635
- /** @nocollapse */
3636
- static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({
3637
- token: PendingTasksInternal,
3638
- providedIn: 'root',
3639
- factory: () => new PendingTasksInternal(),
3640
- });
3641
- }
3642
-
3643
- class EventEmitter_ extends Subject {
3644
- // tslint:disable-next-line:require-internal-with-underscore
3645
- __isAsync;
3646
- destroyRef = undefined;
3647
- pendingTasks = undefined;
3648
- constructor(isAsync = false) {
3649
- super();
3650
- this.__isAsync = isAsync;
3651
- // Attempt to retrieve a `DestroyRef` and `PendingTasks` optionally.
3652
- // For backwards compatibility reasons, this cannot be required.
3653
- if (isInInjectionContext()) {
3654
- // `DestroyRef` is optional because it is not available in all contexts.
3655
- // But it is useful to properly complete the `EventEmitter` if used with `outputToObservable`
3656
- // when the component/directive is destroyed. (See `outputToObservable` for more details.)
3657
- this.destroyRef = inject(DestroyRef, { optional: true }) ?? undefined;
3658
- this.pendingTasks = inject(PendingTasksInternal, { optional: true }) ?? undefined;
3659
- }
3660
- }
3661
- emit(value) {
3662
- const prevConsumer = setActiveConsumer$1(null);
3663
- try {
3664
- super.next(value);
3665
- }
3666
- finally {
3667
- setActiveConsumer$1(prevConsumer);
3668
- }
3669
- }
3670
- subscribe(observerOrNext, error, complete) {
3671
- let nextFn = observerOrNext;
3672
- let errorFn = error || (() => null);
3673
- let completeFn = complete;
3674
- if (observerOrNext && typeof observerOrNext === 'object') {
3675
- const observer = observerOrNext;
3676
- nextFn = observer.next?.bind(observer);
3677
- errorFn = observer.error?.bind(observer);
3678
- completeFn = observer.complete?.bind(observer);
3679
- }
3680
- if (this.__isAsync) {
3681
- errorFn = this.wrapInTimeout(errorFn);
3682
- if (nextFn) {
3683
- nextFn = this.wrapInTimeout(nextFn);
3684
- }
3685
- if (completeFn) {
3686
- completeFn = this.wrapInTimeout(completeFn);
3687
- }
3688
- }
3689
- const sink = super.subscribe({ next: nextFn, error: errorFn, complete: completeFn });
3690
- if (observerOrNext instanceof Subscription) {
3691
- observerOrNext.add(sink);
3692
- }
3693
- return sink;
3694
- }
3695
- wrapInTimeout(fn) {
3696
- return (value) => {
3697
- const taskId = this.pendingTasks?.add();
3698
- setTimeout(() => {
3699
- try {
3700
- fn(value);
3701
- }
3702
- finally {
3703
- if (taskId !== undefined) {
3704
- this.pendingTasks?.remove(taskId);
3705
- }
3706
- }
3707
- });
3708
- };
3709
- }
3710
- }
3711
- /**
3712
- * @publicApi
3713
- */
3714
- const EventEmitter = EventEmitter_;
3715
-
3716
- function noop(...args) {
3717
- // Do nothing.
3718
- }
3719
-
3720
- /**
3721
- * Gets a scheduling function that runs the callback after the first of setTimeout and
3722
- * requestAnimationFrame resolves.
3723
- *
3724
- * - `requestAnimationFrame` ensures that change detection runs ahead of a browser repaint.
3725
- * This ensures that the create and update passes of a change detection always happen
3726
- * in the same frame.
3727
- * - When the browser is resource-starved, `rAF` can execute _before_ a `setTimeout` because
3728
- * rendering is a very high priority process. This means that `setTimeout` cannot guarantee
3729
- * same-frame create and update pass, when `setTimeout` is used to schedule the update phase.
3730
- * - While `rAF` gives us the desirable same-frame updates, it has two limitations that
3731
- * prevent it from being used alone. First, it does not run in background tabs, which would
3732
- * prevent Angular from initializing an application when opened in a new tab (for example).
3733
- * Second, repeated calls to requestAnimationFrame will execute at the refresh rate of the
3734
- * hardware (~16ms for a 60Hz display). This would cause significant slowdown of tests that
3735
- * are written with several updates and asserts in the form of "update; await stable; assert;".
3736
- * - Both `setTimeout` and `rAF` are able to "coalesce" several events from a single user
3737
- * interaction into a single change detection. Importantly, this reduces view tree traversals when
3738
- * compared to an alternative timing mechanism like `queueMicrotask`, where change detection would
3739
- * then be interleaves between each event.
3740
- *
3741
- * By running change detection after the first of `setTimeout` and `rAF` to execute, we get the
3742
- * best of both worlds.
3743
- *
3744
- * @returns a function to cancel the scheduled callback
3745
- */
3746
- function scheduleCallbackWithRafRace(callback) {
3747
- let timeoutId;
3748
- let animationFrameId;
3749
- function cleanup() {
3750
- callback = noop;
3751
- try {
3752
- if (animationFrameId !== undefined && typeof cancelAnimationFrame === 'function') {
3753
- cancelAnimationFrame(animationFrameId);
3754
- }
3755
- if (timeoutId !== undefined) {
3756
- clearTimeout(timeoutId);
3757
- }
3758
- }
3759
- catch {
3760
- // Clearing/canceling can fail in tests due to the timing of functions being patched and unpatched
3761
- // Just ignore the errors - we protect ourselves from this issue by also making the callback a no-op.
3762
- }
3763
- }
3764
- timeoutId = setTimeout(() => {
3765
- callback();
3766
- cleanup();
3767
- });
3768
- if (typeof requestAnimationFrame === 'function') {
3769
- animationFrameId = requestAnimationFrame(() => {
3770
- callback();
3771
- cleanup();
3772
- });
3773
- }
3774
- return () => cleanup();
3775
- }
3776
- function scheduleCallbackWithMicrotask(callback) {
3777
- queueMicrotask(() => callback());
3778
- return () => {
3779
- callback = noop;
3780
- };
3781
- }
3782
-
3783
- class AsyncStackTaggingZoneSpec {
3784
- createTask;
3785
- constructor(namePrefix, consoleAsyncStackTaggingImpl = console) {
3786
- this.name = 'asyncStackTagging for ' + namePrefix;
3787
- this.createTask = consoleAsyncStackTaggingImpl?.createTask ?? (() => null);
3788
- }
3789
- // ZoneSpec implementation below.
3790
- name;
3791
- onScheduleTask(delegate, _current, target, task) {
3792
- task.consoleTask = this.createTask(`Zone - ${task.source || task.type}`);
3793
- return delegate.scheduleTask(target, task);
3794
- }
3795
- onInvokeTask(delegate, _currentZone, targetZone, task, applyThis, applyArgs) {
3796
- let ret;
3797
- if (task.consoleTask) {
3798
- ret = task.consoleTask.run(() => delegate.invokeTask(targetZone, task, applyThis, applyArgs));
3799
- }
3800
- else {
3801
- ret = delegate.invokeTask(targetZone, task, applyThis, applyArgs);
3802
- }
3803
- return ret;
3804
- }
3805
- }
3806
-
3807
- const isAngularZoneProperty = 'isAngularZone';
3808
- const angularZoneInstanceIdProperty = isAngularZoneProperty + '_ID';
3809
- let ngZoneInstanceId = 0;
3810
- /**
3811
- * An injectable service for executing work inside or outside of the Angular zone.
3812
- *
3813
- * The most common use of this service is to optimize performance when starting a work consisting of
3814
- * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
3815
- * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
3816
- * can reenter the Angular zone via {@link #run}.
3817
- *
3818
- * <!-- TODO: add/fix links to:
3819
- * - docs explaining zones and the use of zones in Angular and change-detection
3820
- * - link to runOutsideAngular/run (throughout this file!)
3821
- * -->
3822
- *
3823
- * @usageNotes
3824
- * ### Example
3825
- *
3826
- * ```ts
3827
- * import {Component, NgZone} from '@angular/core';
3828
- *
3829
- * @Component({
3830
- * selector: 'ng-zone-demo',
3831
- * template: `
3832
- * <h2>Demo: NgZone</h2>
3833
- *
3834
- * <p>Progress: {{progress}}%</p>
3835
- * @if(progress >= 100) {
3836
- * <p>Done processing {{label}} of Angular zone!</p>
3837
- * }
3838
- *
3839
- * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
3840
- * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
3841
- * `,
3842
- * })
3843
- * export class NgZoneDemo {
3844
- * progress: number = 0;
3845
- * label: string;
3846
- *
3847
- * constructor(private _ngZone: NgZone) {}
3848
- *
3849
- * // Loop inside the Angular zone
3850
- * // so the UI DOES refresh after each setTimeout cycle
3851
- * processWithinAngularZone() {
3852
- * this.label = 'inside';
3853
- * this.progress = 0;
3854
- * this._increaseProgress(() => console.log('Inside Done!'));
3855
- * }
3856
- *
3857
- * // Loop outside of the Angular zone
3858
- * // so the UI DOES NOT refresh after each setTimeout cycle
3859
- * processOutsideOfAngularZone() {
3860
- * this.label = 'outside';
3861
- * this.progress = 0;
3862
- * this._ngZone.runOutsideAngular(() => {
3863
- * this._increaseProgress(() => {
3864
- * // reenter the Angular zone and display done
3865
- * this._ngZone.run(() => { console.log('Outside Done!'); });
3866
- * });
3867
- * });
3868
- * }
3869
- *
3870
- * _increaseProgress(doneCallback: () => void) {
3871
- * this.progress += 1;
3872
- * console.log(`Current progress: ${this.progress}%`);
3873
- *
3874
- * if (this.progress < 100) {
3875
- * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
3876
- * } else {
3877
- * doneCallback();
3878
- * }
3879
- * }
3880
- * }
3881
- * ```
3882
- *
3883
- * @publicApi
3884
- */
3885
- class NgZone {
3886
- hasPendingMacrotasks = false;
3887
- hasPendingMicrotasks = false;
3888
- /**
3889
- * Whether there are no outstanding microtasks or macrotasks.
3890
- */
3891
- isStable = true;
3892
- /**
3893
- * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
3894
- */
3895
- onUnstable = new EventEmitter(false);
3896
- /**
3897
- * Notifies when there is no more microtasks enqueued in the current VM Turn.
3898
- * This is a hint for Angular to do change detection, which may enqueue more microtasks.
3899
- * For this reason this event can fire multiple times per VM Turn.
3900
- */
3901
- onMicrotaskEmpty = new EventEmitter(false);
3902
- /**
3903
- * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
3904
- * implies we are about to relinquish VM turn.
3905
- * This event gets called just once.
3906
- */
3907
- onStable = new EventEmitter(false);
3908
- /**
3909
- * Notifies that an error has been delivered.
3910
- */
3911
- onError = new EventEmitter(false);
3912
- constructor(options) {
3913
- const { enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false, scheduleInRootZone = SCHEDULE_IN_ROOT_ZONE_DEFAULT, } = options;
3914
- if (typeof Zone == 'undefined') {
3915
- throw new RuntimeError(908 /* RuntimeErrorCode.MISSING_ZONEJS */, ngDevMode && `In this configuration Angular requires Zone.js`);
3916
- }
3917
- Zone.assertZonePatched();
3918
- const self = this;
3919
- self._nesting = 0;
3920
- self._outer = self._inner = Zone.current;
3921
- // AsyncStackTaggingZoneSpec provides `linked stack traces` to show
3922
- // where the async operation is scheduled. For more details, refer
3923
- // to this article, https://developer.chrome.com/blog/devtools-better-angular-debugging/
3924
- // And we only import this AsyncStackTaggingZoneSpec in development mode,
3925
- // in the production mode, the AsyncStackTaggingZoneSpec will be tree shaken away.
3926
- if (ngDevMode) {
3927
- self._inner = self._inner.fork(new AsyncStackTaggingZoneSpec('Angular'));
3928
- }
3929
- if (Zone['TaskTrackingZoneSpec']) {
3930
- self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']());
3931
- }
3932
- if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
3933
- self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
3934
- }
3935
- // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
3936
- // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
3937
- self.shouldCoalesceEventChangeDetection =
3938
- !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
3939
- self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
3940
- self.callbackScheduled = false;
3941
- self.scheduleInRootZone = scheduleInRootZone;
3942
- forkInnerZoneWithAngularBehavior(self);
3943
- }
3944
- /**
3945
- This method checks whether the method call happens within an Angular Zone instance.
3946
- */
3947
- static isInAngularZone() {
3948
- // Zone needs to be checked, because this method might be called even when NoopNgZone is used.
3949
- return typeof Zone !== 'undefined' && Zone.current.get(isAngularZoneProperty) === true;
3950
- }
3951
- /**
3952
- Assures that the method is called within the Angular Zone, otherwise throws an error.
3953
- */
3954
- static assertInAngularZone() {
3955
- if (!NgZone.isInAngularZone()) {
3956
- throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to be in Angular Zone, but it is not!');
3957
- }
3958
- }
3959
- /**
3960
- Assures that the method is called outside of the Angular Zone, otherwise throws an error.
3961
- */
3962
- static assertNotInAngularZone() {
3963
- if (NgZone.isInAngularZone()) {
3964
- throw new RuntimeError(909 /* RuntimeErrorCode.UNEXPECTED_ZONE_STATE */, ngDevMode && 'Expected to not be in Angular Zone, but it is!');
3965
- }
3966
- }
3967
- /**
3968
- * Executes the `fn` function synchronously within the Angular zone and returns value returned by
3969
- * the function.
3970
- *
3971
- * Running functions via `run` allows you to reenter Angular zone from a task that was executed
3972
- * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
3973
- *
3974
- * Any future tasks or microtasks scheduled from within this function will continue executing from
3975
- * within the Angular zone.
3976
- *
3977
- * If a synchronous error happens it will be rethrown and not reported via `onError`.
3978
- */
3979
- run(fn, applyThis, applyArgs) {
3980
- return this._inner.run(fn, applyThis, applyArgs);
3981
- }
3982
- /**
3983
- * Executes the `fn` function synchronously within the Angular zone as a task and returns value
3984
- * returned by the function.
3985
- *
3986
- * Running functions via `runTask` allows you to reenter Angular zone from a task that was executed
3987
- * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
3988
- *
3989
- * Any future tasks or microtasks scheduled from within this function will continue executing from
3990
- * within the Angular zone.
3991
- *
3992
- * If a synchronous error happens it will be rethrown and not reported via `onError`.
3993
- */
3994
- runTask(fn, applyThis, applyArgs, name) {
3995
- const zone = this._inner;
3996
- const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
3997
- try {
3998
- return zone.runTask(task, applyThis, applyArgs);
3999
- }
4000
- finally {
4001
- zone.cancelTask(task);
4002
- }
4003
- }
4004
- /**
4005
- * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
4006
- * rethrown.
4007
- */
4008
- runGuarded(fn, applyThis, applyArgs) {
4009
- return this._inner.runGuarded(fn, applyThis, applyArgs);
4010
- }
4011
- /**
4012
- * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
4013
- * the function.
4014
- *
4015
- * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
4016
- * work that
4017
- * doesn't trigger Angular change-detection or is subject to Angular's error handling.
4018
- *
4019
- * Any future tasks or microtasks scheduled from within this function will continue executing from
4020
- * outside of the Angular zone.
4021
- *
4022
- * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
4023
- */
4024
- runOutsideAngular(fn) {
4025
- return this._outer.run(fn);
4026
- }
4027
- }
4028
- const EMPTY_PAYLOAD = {};
4029
- function checkStable(zone) {
4030
- // TODO: @JiaLiPassion, should check zone.isCheckStableRunning to prevent
4031
- // re-entry. The case is:
4032
- //
4033
- // @Component({...})
4034
- // export class AppComponent {
4035
- // constructor(private ngZone: NgZone) {
4036
- // this.ngZone.onStable.subscribe(() => {
4037
- // this.ngZone.run(() => console.log('stable'););
4038
- // });
4039
- // }
4040
- //
4041
- // The onStable subscriber run another function inside ngZone
4042
- // which causes `checkStable()` re-entry.
4043
- // But this fix causes some issues in g3, so this fix will be
4044
- // launched in another PR.
4045
- if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
4046
- try {
4047
- zone._nesting++;
4048
- zone.onMicrotaskEmpty.emit(null);
4049
- }
4050
- finally {
4051
- zone._nesting--;
4052
- if (!zone.hasPendingMicrotasks) {
4053
- try {
4054
- zone.runOutsideAngular(() => zone.onStable.emit(null));
4055
- }
4056
- finally {
4057
- zone.isStable = true;
4058
- }
4059
- }
4060
- }
4061
- }
4062
- }
4063
- function delayChangeDetectionForEvents(zone) {
4064
- /**
4065
- * We also need to check _nesting here
4066
- * Consider the following case with shouldCoalesceRunChangeDetection = true
4067
- *
4068
- * ngZone.run(() => {});
4069
- * ngZone.run(() => {});
4070
- *
4071
- * We want the two `ngZone.run()` only trigger one change detection
4072
- * when shouldCoalesceRunChangeDetection is true.
4073
- * And because in this case, change detection run in async way(requestAnimationFrame),
4074
- * so we also need to check the _nesting here to prevent multiple
4075
- * change detections.
4076
- */
4077
- if (zone.isCheckStableRunning || zone.callbackScheduled) {
4078
- return;
4079
- }
4080
- zone.callbackScheduled = true;
4081
- function scheduleCheckStable() {
4082
- scheduleCallbackWithRafRace(() => {
4083
- zone.callbackScheduled = false;
4084
- updateMicroTaskStatus(zone);
4085
- zone.isCheckStableRunning = true;
4086
- checkStable(zone);
4087
- zone.isCheckStableRunning = false;
4088
- });
4089
- }
4090
- if (zone.scheduleInRootZone) {
4091
- Zone.root.run(() => {
4092
- scheduleCheckStable();
4093
- });
4094
- }
4095
- else {
4096
- zone._outer.run(() => {
4097
- scheduleCheckStable();
4098
- });
4099
- }
4100
- updateMicroTaskStatus(zone);
4101
- }
4102
- function forkInnerZoneWithAngularBehavior(zone) {
4103
- const delayChangeDetectionForEventsDelegate = () => {
4104
- delayChangeDetectionForEvents(zone);
4105
- };
4106
- const instanceId = ngZoneInstanceId++;
4107
- zone._inner = zone._inner.fork({
4108
- name: 'angular',
4109
- properties: {
4110
- [isAngularZoneProperty]: true,
4111
- [angularZoneInstanceIdProperty]: instanceId,
4112
- [angularZoneInstanceIdProperty + instanceId]: true,
4113
- },
4114
- onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
4115
- // Prevent triggering change detection when the flag is detected.
4116
- if (shouldBeIgnoredByZone(applyArgs)) {
4117
- return delegate.invokeTask(target, task, applyThis, applyArgs);
4118
- }
4119
- try {
4120
- onEnter(zone);
4121
- return delegate.invokeTask(target, task, applyThis, applyArgs);
4122
- }
4123
- finally {
4124
- if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
4125
- zone.shouldCoalesceRunChangeDetection) {
4126
- delayChangeDetectionForEventsDelegate();
4127
- }
4128
- onLeave(zone);
4129
- }
4130
- },
4131
- onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
4132
- try {
4133
- onEnter(zone);
4134
- return delegate.invoke(target, callback, applyThis, applyArgs, source);
4135
- }
4136
- finally {
4137
- if (zone.shouldCoalesceRunChangeDetection &&
4138
- // Do not delay change detection when the task is the scheduler's tick.
4139
- // We need to synchronously trigger the stability logic so that the
4140
- // zone-based scheduler can prevent a duplicate ApplicationRef.tick
4141
- // by first checking if the scheduler tick is running. This does seem a bit roundabout,
4142
- // but we _do_ still want to trigger all the correct events when we exit the zone.run
4143
- // (`onMicrotaskEmpty` and `onStable` _should_ emit; developers can have code which
4144
- // relies on these events happening after change detection runs).
4145
- // Note: `zone.callbackScheduled` is already in delayChangeDetectionForEventsDelegate
4146
- // but is added here as well to prevent reads of applyArgs when not necessary
4147
- !zone.callbackScheduled &&
4148
- !isSchedulerTick(applyArgs)) {
4149
- delayChangeDetectionForEventsDelegate();
4150
- }
4151
- onLeave(zone);
4152
- }
4153
- },
4154
- onHasTask: (delegate, current, target, hasTaskState) => {
4155
- delegate.hasTask(target, hasTaskState);
4156
- if (current === target) {
4157
- // We are only interested in hasTask events which originate from our zone
4158
- // (A child hasTask event is not interesting to us)
4159
- if (hasTaskState.change == 'microTask') {
4160
- zone._hasPendingMicrotasks = hasTaskState.microTask;
4161
- updateMicroTaskStatus(zone);
4162
- checkStable(zone);
4163
- }
4164
- else if (hasTaskState.change == 'macroTask') {
4165
- zone.hasPendingMacrotasks = hasTaskState.macroTask;
4166
- }
4167
- }
4168
- },
4169
- onHandleError: (delegate, current, target, error) => {
4170
- delegate.handleError(target, error);
4171
- zone.runOutsideAngular(() => zone.onError.emit(error));
4172
- return false;
4173
- },
4174
- });
4175
- }
4176
- function updateMicroTaskStatus(zone) {
4177
- if (zone._hasPendingMicrotasks ||
4178
- ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
4179
- zone.callbackScheduled === true)) {
4180
- zone.hasPendingMicrotasks = true;
4181
- }
4182
- else {
4183
- zone.hasPendingMicrotasks = false;
4184
- }
4185
- }
4186
- function onEnter(zone) {
4187
- zone._nesting++;
4188
- if (zone.isStable) {
4189
- zone.isStable = false;
4190
- zone.onUnstable.emit(null);
4191
- }
4192
- }
4193
- function onLeave(zone) {
4194
- zone._nesting--;
4195
- checkStable(zone);
4196
- }
4197
- /**
4198
- * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
4199
- * to framework to perform rendering.
4200
- */
4201
- class NoopNgZone {
4202
- hasPendingMicrotasks = false;
4203
- hasPendingMacrotasks = false;
4204
- isStable = true;
4205
- onUnstable = new EventEmitter();
4206
- onMicrotaskEmpty = new EventEmitter();
4207
- onStable = new EventEmitter();
4208
- onError = new EventEmitter();
4209
- run(fn, applyThis, applyArgs) {
4210
- return fn.apply(applyThis, applyArgs);
4211
- }
4212
- runGuarded(fn, applyThis, applyArgs) {
4213
- return fn.apply(applyThis, applyArgs);
4214
- }
4215
- runOutsideAngular(fn) {
4216
- return fn();
4217
- }
4218
- runTask(fn, applyThis, applyArgs, name) {
4219
- return fn.apply(applyThis, applyArgs);
4220
- }
4221
- }
4222
- function shouldBeIgnoredByZone(applyArgs) {
4223
- return hasApplyArgsData(applyArgs, '__ignore_ng_zone__');
4224
- }
4225
- function isSchedulerTick(applyArgs) {
4226
- return hasApplyArgsData(applyArgs, '__scheduler_tick__');
4227
- }
4228
- function hasApplyArgsData(applyArgs, key) {
4229
- if (!Array.isArray(applyArgs)) {
4230
- return false;
4231
- }
4232
- // We should only ever get 1 arg passed through to invokeTask.
4233
- // Short circuit here incase that behavior changes.
4234
- if (applyArgs.length !== 1) {
4235
- return false;
4236
- }
4237
- return applyArgs[0]?.data?.[key] === true;
4238
- }
4239
-
4240
- /**
4241
- * Provides a hook for centralized exception handling.
4242
- *
4243
- * The default implementation of `ErrorHandler` prints error messages to the `console`. To
4244
- * intercept error handling, write a custom exception handler that replaces this default as
4245
- * appropriate for your app.
4246
- *
4247
- * @usageNotes
4248
- * ### Example
4249
- *
4250
- * ```ts
4251
- * class MyErrorHandler implements ErrorHandler {
4252
- * handleError(error) {
4253
- * // do something with the exception
4254
- * }
4255
- * }
4256
- *
4257
- * // Provide in standalone apps
4258
- * bootstrapApplication(AppComponent, {
4259
- * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
4260
- * })
4261
- *
4262
- * // Provide in module-based apps
4263
- * @NgModule({
4264
- * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
4265
- * })
4266
- * class MyModule {}
4267
- * ```
4268
- *
4269
- * @publicApi
4270
- *
4271
- * @see [Unhandled errors in Angular](best-practices/error-handling)
4272
- *
4273
- */
4274
- class ErrorHandler {
4275
- /**
4276
- * @internal
4277
- */
4278
- _console = console;
4279
- handleError(error) {
4280
- this._console.error('ERROR', error);
4281
- }
4282
- }
4283
- /**
4284
- * `InjectionToken` used to configure how to call the `ErrorHandler`.
4285
- */
4286
- const INTERNAL_APPLICATION_ERROR_HANDLER = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'internal error handler' : '', {
4287
- providedIn: 'root',
4288
- factory: () => {
4289
- // The user's error handler may depend on things that create a circular dependency
4290
- // so we inject it lazily.
4291
- const zone = inject(NgZone);
4292
- const injector = inject(EnvironmentInjector);
4293
- let userErrorHandler;
4294
- return (e) => {
4295
- zone.runOutsideAngular(() => {
4296
- if (injector.destroyed && !userErrorHandler) {
4297
- setTimeout(() => {
4298
- throw e;
4299
- });
4300
- }
4301
- else {
4302
- userErrorHandler ??= injector.get(ErrorHandler);
4303
- userErrorHandler.handleError(e);
4304
- }
4305
- });
4306
- };
4307
- },
4308
- });
4309
- const errorHandlerEnvironmentInitializer = {
4310
- provide: ENVIRONMENT_INITIALIZER,
4311
- useValue: () => {
4312
- const handler = inject(ErrorHandler, { optional: true });
4313
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && handler === null) {
4314
- throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, `A required Injectable was not found in the dependency injection tree. ` +
4315
- 'If you are bootstrapping an NgModule, make sure that the `BrowserModule` is imported.');
4316
- }
4317
- },
4318
- multi: true,
4319
- };
4320
- const globalErrorListeners = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'GlobalErrorListeners' : '', {
4321
- providedIn: 'root',
4322
- factory: () => {
4323
- if (typeof ngServerMode !== 'undefined' && ngServerMode) {
4324
- return;
4325
- }
4326
- const window = inject(DOCUMENT).defaultView;
4327
- if (!window) {
4328
- return;
4329
- }
4330
- const errorHandler = inject(INTERNAL_APPLICATION_ERROR_HANDLER);
4331
- const rejectionListener = (e) => {
4332
- errorHandler(e.reason);
4333
- e.preventDefault();
4334
- };
4335
- const errorListener = (e) => {
4336
- if (e.error) {
4337
- errorHandler(e.error);
4338
- }
4339
- else {
4340
- errorHandler(new Error(ngDevMode
4341
- ? `An ErrorEvent with no error occurred. See Error.cause for details: ${e.message}`
4342
- : e.message, { cause: e }));
4343
- }
4344
- e.preventDefault();
4345
- };
4346
- const setupEventListeners = () => {
4347
- window.addEventListener('unhandledrejection', rejectionListener);
4348
- window.addEventListener('error', errorListener);
4349
- };
4350
- // Angular doesn't have to run change detection whenever any asynchronous tasks are invoked in
4351
- // the scope of this functionality.
4352
- if (typeof Zone !== 'undefined') {
4353
- Zone.root.run(setupEventListeners);
4354
- }
4355
- else {
4356
- setupEventListeners();
4357
- }
4358
- inject(DestroyRef).onDestroy(() => {
4359
- window.removeEventListener('error', errorListener);
4360
- window.removeEventListener('unhandledrejection', rejectionListener);
4361
- });
4362
- },
4363
- });
4364
- /**
4365
- * Provides an environment initializer which forwards unhandled errors to the ErrorHandler.
4366
- *
4367
- * The listeners added are for the window's 'unhandledrejection' and 'error' events.
4368
- *
4369
- * @publicApi
4370
- */
4371
- function provideBrowserGlobalErrorListeners() {
4372
- return makeEnvironmentProviders([
4373
- provideEnvironmentInitializer(() => void inject(globalErrorListeners)),
4374
- ]);
4375
- }
4376
-
4377
- /**
4378
- * Checks if the given `value` is a reactive `Signal`.
4379
- *
4380
- * @publicApi 17.0
4381
- */
4382
- function isSignal(value) {
4383
- return typeof value === 'function' && value[SIGNAL] !== undefined;
4384
- }
4385
-
4386
- /**
4387
- * Utility function used during template type checking to extract the value from a `WritableSignal`.
4388
- * @codeGenApi
4389
- */
4390
- function ɵunwrapWritableSignal(value) {
4391
- // Note: the function uses `WRITABLE_SIGNAL` as a brand instead of `WritableSignal<T>`,
4392
- // because the latter incorrectly unwraps non-signal getter functions.
4393
- return null;
4394
- }
4395
- /**
4396
- * Create a `Signal` that can be set or updated directly.
4397
- */
4398
- function signal(initialValue, options) {
4399
- const [get, set, update] = createSignal(initialValue, options?.equal);
4400
- const signalFn = get;
4401
- const node = signalFn[SIGNAL];
4402
- signalFn.set = set;
4403
- signalFn.update = update;
4404
- signalFn.asReadonly = signalAsReadonlyFn.bind(signalFn);
4405
- if (ngDevMode) {
4406
- signalFn.toString = () => `[Signal: ${signalFn()}]`;
4407
- node.debugName = options?.debugName;
4408
- }
4409
- return signalFn;
4410
- }
4411
- function signalAsReadonlyFn() {
4412
- const node = this[SIGNAL];
4413
- if (node.readonlyFn === undefined) {
4414
- const readonlyFn = () => this();
4415
- readonlyFn[SIGNAL] = node;
4416
- node.readonlyFn = readonlyFn;
4417
- }
4418
- return node.readonlyFn;
4419
- }
4420
- /**
4421
- * Checks if the given `value` is a writeable signal.
4422
- */
4423
- function isWritableSignal(value) {
4424
- return isSignal(value) && typeof value.set === 'function';
4425
- }
4426
-
4427
- /**
4428
- * Injectable that is notified when an `LView` is made aware of changes to application state.
4429
- */
4430
- class ChangeDetectionScheduler {
4431
- }
4432
- /** Token used to indicate if zoneless was enabled via provideZonelessChangeDetection(). */
4433
- const ZONELESS_ENABLED = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'Zoneless enabled' : '', { providedIn: 'root', factory: () => true });
4434
- /** Token used to indicate `provideZonelessChangeDetection` was used. */
4435
- const PROVIDED_ZONELESS = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'Zoneless provided' : '', { providedIn: 'root', factory: () => false });
4436
- // TODO(atscott): Remove in v19. Scheduler should be done with runOutsideAngular.
4437
- const SCHEDULE_IN_ROOT_ZONE = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'run changes outside zone in root' : '');
4438
-
4439
- /**
4440
- * Asserts that the current stack frame is not within a reactive context. Useful
4441
- * to disallow certain code from running inside a reactive context (see {@link /api/core/rxjs-interop/toSignal toSignal})
4442
- *
4443
- * @param debugFn a reference to the function making the assertion (used for the error message).
4444
- *
4445
- * @publicApi
4446
- */
4447
- function assertNotInReactiveContext(debugFn, extraContext) {
4448
- // Taking a `Function` instead of a string name here prevents the un-minified name of the function
4449
- // from being retained in the bundle regardless of minification.
4450
- if (getActiveConsumer() !== null) {
4451
- throw new RuntimeError(-602 /* RuntimeErrorCode.ASSERTION_NOT_INSIDE_REACTIVE_CONTEXT */, ngDevMode &&
4452
- `${debugFn.name}() cannot be called from within a reactive context.${extraContext ? ` ${extraContext}` : ''}`);
4453
- }
4454
- }
4455
-
4456
- class ViewContext {
4457
- view;
4458
- node;
4459
- constructor(view, node) {
4460
- this.view = view;
4461
- this.node = node;
4462
- }
4463
- /**
4464
- * @internal
4465
- * @nocollapse
4466
- */
4467
- static __NG_ELEMENT_ID__ = injectViewContext;
4468
- }
4469
- function injectViewContext() {
4470
- return new ViewContext(getLView(), getCurrentTNode());
4471
- }
4472
-
4473
- /**
4474
- * Service that keeps track of pending tasks contributing to the stableness of Angular
4475
- * application. While several existing Angular services (ex.: `HttpClient`) will internally manage
4476
- * tasks influencing stability, this API gives control over stability to library and application
4477
- * developers for specific cases not covered by Angular internals.
4478
- *
4479
- * The concept of stability comes into play in several important scenarios:
4480
- * - SSR process needs to wait for the application stability before serializing and sending rendered
4481
- * HTML;
4482
- * - tests might want to delay assertions until the application becomes stable;
4483
- *
4484
- * @usageNotes
4485
- * ```ts
4486
- * const pendingTasks = inject(PendingTasks);
4487
- * const taskCleanup = pendingTasks.add();
4488
- * // do work that should block application's stability and then:
4489
- * taskCleanup();
4490
- * ```
4491
- *
4492
- * @publicApi 20.0
4493
- */
4494
- class PendingTasks {
4495
- internalPendingTasks = inject(PendingTasksInternal);
4496
- scheduler = inject(ChangeDetectionScheduler);
4497
- errorHandler = inject(INTERNAL_APPLICATION_ERROR_HANDLER);
4498
- /**
4499
- * Adds a new task that should block application's stability.
4500
- * @returns A cleanup function that removes a task when called.
4501
- */
4502
- add() {
4503
- const taskId = this.internalPendingTasks.add();
4504
- return () => {
4505
- if (!this.internalPendingTasks.has(taskId)) {
4506
- // This pending task has already been cleared.
4507
- return;
4508
- }
4509
- // Notifying the scheduler will hold application stability open until the next tick.
4510
- this.scheduler.notify(11 /* NotificationSource.PendingTaskRemoved */);
4511
- this.internalPendingTasks.remove(taskId);
4512
- };
4513
- }
4514
- /**
4515
- * Runs an asynchronous function and blocks the application's stability until the function completes.
4516
- *
4517
- * ```ts
4518
- * pendingTasks.run(async () => {
4519
- * const userData = await fetch('/api/user');
4520
- * this.userData.set(userData);
4521
- * });
4522
- * ```
4523
- *
4524
- * @param fn The asynchronous function to execute
4525
- * @developerPreview 19.0
4526
- */
4527
- run(fn) {
4528
- const removeTask = this.add();
4529
- fn().catch(this.errorHandler).finally(removeTask);
4530
- }
4531
- /** @nocollapse */
4532
- static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({
4533
- token: PendingTasks,
4534
- providedIn: 'root',
4535
- factory: () => new PendingTasks(),
4536
- });
4537
- }
4538
-
4539
- /**
4540
- * A scheduler which manages the execution of effects.
4541
- */
4542
- class EffectScheduler {
4543
- /** @nocollapse */
4544
- static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({
4545
- token: EffectScheduler,
4546
- providedIn: 'root',
4547
- factory: () => new ZoneAwareEffectScheduler(),
4548
- });
4549
- }
4550
- /**
4551
- * A wrapper around `ZoneAwareQueueingScheduler` that schedules flushing via the microtask queue
4552
- * when.
4553
- */
4554
- class ZoneAwareEffectScheduler {
4555
- dirtyEffectCount = 0;
4556
- queues = new Map();
4557
- add(handle) {
4558
- this.enqueue(handle);
4559
- this.schedule(handle);
4560
- }
4561
- schedule(handle) {
4562
- if (!handle.dirty) {
4563
- return;
4564
- }
4565
- this.dirtyEffectCount++;
4566
- }
4567
- remove(handle) {
4568
- const zone = handle.zone;
4569
- const queue = this.queues.get(zone);
4570
- if (!queue.has(handle)) {
4571
- return;
4572
- }
4573
- queue.delete(handle);
4574
- if (handle.dirty) {
4575
- this.dirtyEffectCount--;
4576
- }
4577
- }
4578
- enqueue(handle) {
4579
- const zone = handle.zone;
4580
- if (!this.queues.has(zone)) {
4581
- this.queues.set(zone, new Set());
4582
- }
4583
- const queue = this.queues.get(zone);
4584
- if (queue.has(handle)) {
4585
- return;
4586
- }
4587
- queue.add(handle);
4588
- }
4589
- /**
4590
- * Run all scheduled effects.
4591
- *
4592
- * Execution order of effects within the same zone is guaranteed to be FIFO, but there is no
4593
- * ordering guarantee between effects scheduled in different zones.
4594
- */
4595
- flush() {
4596
- while (this.dirtyEffectCount > 0) {
4597
- let ranOneEffect = false;
4598
- for (const [zone, queue] of this.queues) {
4599
- // `zone` here must be defined.
4600
- if (zone === null) {
4601
- ranOneEffect ||= this.flushQueue(queue);
4602
- }
4603
- else {
4604
- ranOneEffect ||= zone.run(() => this.flushQueue(queue));
4605
- }
4606
- }
4607
- // Safeguard against infinite looping if somehow our dirty effect count gets out of sync with
4608
- // the dirty flag across all the effects.
4609
- if (!ranOneEffect) {
4610
- this.dirtyEffectCount = 0;
4611
- }
4612
- }
4613
- }
4614
- flushQueue(queue) {
4615
- let ranOneEffect = false;
4616
- for (const handle of queue) {
4617
- if (!handle.dirty) {
4618
- continue;
4619
- }
4620
- this.dirtyEffectCount--;
4621
- ranOneEffect = true;
4622
- // TODO: what happens if this throws an error?
4623
- handle.run();
4624
- }
4625
- return ranOneEffect;
4626
- }
4627
- }
4628
-
4629
- export { AFTER_RENDER_SEQUENCES_TO_ADD, ANIMATIONS, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTAINER_HEADER_OFFSET, CONTEXT, ChangeDetectionScheduler, CheckNoChangesMode, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, DECLARATION_VIEW, DEHYDRATED_VIEWS, DOCUMENT, DestroyRef, EFFECTS, EFFECTS_TO_SCHEDULE, EMBEDDED_VIEW_INJECTOR, EMPTY_ARRAY, EMPTY_OBJ, ENVIRONMENT, ENVIRONMENT_INITIALIZER, EffectScheduler, EnvironmentInjector, ErrorHandler, EventEmitter, FLAGS, HEADER_OFFSET, HOST, HYDRATION, ID, INJECTOR$1 as INJECTOR, INJECTOR as INJECTOR$1, INJECTOR_DEF_TYPES, INJECTOR_SCOPE, INTERNAL_APPLICATION_ERROR_HANDLER, InjectionToken, Injector, MATH_ML_NAMESPACE, MOVED_VIEWS, NATIVE, NEXT, NG_COMP_DEF, NG_DIR_DEF, NG_ELEMENT_ID, NG_FACTORY_DEF, NG_INJ_DEF, NG_MOD_DEF, NG_PIPE_DEF, NG_PROV_DEF, NgZone, NodeInjectorDestroyRef, NoopNgZone, NullInjector, ON_DESTROY_HOOKS, PARENT, PREORDER_HOOK_FLAGS, PROVIDED_ZONELESS, PendingTasks, PendingTasksInternal, QUERIES, R3Injector, REACTIVE_TEMPLATE_CONSUMER, RENDERER, RuntimeError, SCHEDULE_IN_ROOT_ZONE, SCHEDULE_IN_ROOT_ZONE_DEFAULT, SVG_NAMESPACE, TVIEW, T_HOST, VERSION, VIEW_REFS, Version, ViewContext, XSS_SECURITY_URL, ZONELESS_ENABLED, _global, addToArray, angularZoneInstanceIdProperty, arrayEquals, arrayInsert2, arraySplice, assertComponentType, assertDefined, assertDirectiveDef, assertDomNode, assertElement, assertEqual, assertFirstCreatePass, assertFirstUpdatePass, assertFunction, assertGreaterThan, assertGreaterThanOrEqual, assertHasParent, assertInInjectionContext, assertIndexInDeclRange, assertIndexInExpandoRange, assertIndexInRange, assertInjectImplementationNotEqual, assertLContainer, assertLView, assertLessThan, assertNgModuleType, assertNodeInjector, assertNotDefined, assertNotEqual, assertNotInReactiveContext, assertNotReactive, assertNotSame, assertNumber, assertNumberInRange, assertOneOf, assertParentView, assertProjectionSlots, assertSame, assertString, assertTIcu, assertTNode, assertTNodeCreationIndex, assertTNodeForLView, assertTNodeForTView, attachInjectFlag, concatStringsWithSpace, convertToBitFlags, createInjector, createInjectorWithoutInjectorInstances, cyclicDependencyError, cyclicDependencyErrorWithDetails, debugStringifyTypeForError, decreaseElementDepthCount, deepForEach, emitEffectCreatedEvent, emitInjectEvent, emitInjectorToCreateInstanceEvent, emitInstanceCreatedByInjectorEvent, emitProviderConfiguredEvent, enterDI, enterSkipHydrationBlock, enterView, errorHandlerEnvironmentInitializer, fillProperties, flatten, formatRuntimeError, forwardRef, getBindingIndex, getBindingRoot, getBindingsEnabled, getClosureSafeProperty, getComponentDef, getComponentLViewByIndex, getConstant, getContextLView, getCurrentDirectiveDef, getCurrentDirectiveIndex, getCurrentParentTNode, getCurrentQueryIndex, getCurrentTNode, getCurrentTNodePlaceholderOk, getDirectiveDef, getDirectiveDefOrThrow, getElementDepthCount, getFactoryDef, getInjectableDef, getInjectorDef, getLView, getLViewParent, getNamespace, getNativeByIndex, getNativeByTNode, getNativeByTNodeOrNull, getNgModuleDef, getNgModuleDefOrThrow, getNullInjector, getOrCreateLViewCleanup, getOrCreateTViewCleanup, getPipeDef, getSelectedIndex, getSelectedTNode, getTNode, getTView, hasI18n, importProvidersFrom, increaseElementDepthCount, incrementBindingIndex, initNgDevMode, inject, injectRootLimpMode, internalImportProvidersFrom, isClassProvider, isComponentDef, isComponentHost, isContentQueryHost, isCreationMode, isCurrentTNodeParent, isDestroyed, isDirectiveHost, isEnvironmentProviders, isExhaustiveCheckNoChanges, isForwardRef, isInCheckNoChangesMode, isInI18nBlock, isInInjectionContext, isInSkipHydrationBlock, isInjectable, isLContainer, isLView, isProjectionTNode, isRefreshingViews, isRootView, isSignal, isSkipHydrationRootTNode, isStandalone, isTypeProvider, isWritableSignal, keyValueArrayGet, keyValueArrayIndexOf, keyValueArraySet, lastNodeWasCreated, leaveDI, leaveSkipHydrationBlock, leaveView, load, makeEnvironmentProviders, markAncestorsForTraversal, markViewForRefresh, newArray, nextBindingIndex, nextContextImpl, noop, provideBrowserGlobalErrorListeners, provideEnvironmentInitializer, providerToFactory, removeFromArray, removeLViewOnDestroy, renderStringify, requiresRefreshOrTraversal, resetPreOrderHookFlags, resolveForwardRef, runInInjectionContext, runInInjectorProfilerContext, scheduleCallbackWithMicrotask, scheduleCallbackWithRafRace, setBindingIndex, setBindingRootForHostBindings, setCurrentDirectiveIndex, setCurrentQueryIndex, setCurrentTNode, setCurrentTNodeAsNotParent, setInI18nBlock, setInjectImplementation, setInjectorProfiler, setInjectorProfilerContext, setIsInCheckNoChangesMode, setIsRefreshingViews, setSelectedIndex, signal, signalAsReadonlyFn, store, storeCleanupWithContext, storeLViewOnDestroy, stringify, stringifyForError, throwError, throwProviderNotFoundError, truncateMiddle, unwrapLView, unwrapRNode, updateAncestorTraversalFlagsOnAttach, viewAttachedToChangeDetector, viewAttachedToContainer, walkProviderTree, walkUpViews, wasLastNodeCreated, ɵunwrapWritableSignal, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdisableBindings, ɵɵenableBindings, ɵɵinject, ɵɵinvalidFactoryDep, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵresetView, ɵɵrestoreView };
4630
- //# sourceMappingURL=_root_effect_scheduler-chunk.mjs.map