UNPKG

1.21 MBJavaScriptView Raw
1/**
2 * @license Angular v14.0.3
3 * (c) 2010-2022 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { Subject, Subscription, Observable, merge as merge$1 } from 'rxjs';
8import { share } from 'rxjs/operators';
9
10/**
11 * @license
12 * Copyright Google LLC All Rights Reserved.
13 *
14 * Use of this source code is governed by an MIT-style license that can be
15 * found in the LICENSE file at https://angular.io/license
16 */
17function getClosureSafeProperty(objWithPropertyToExtract) {
18 for (let key in objWithPropertyToExtract) {
19 if (objWithPropertyToExtract[key] === getClosureSafeProperty) {
20 return key;
21 }
22 }
23 throw Error('Could not find renamed property on target object.');
24}
25/**
26 * Sets properties on a target object from a source object, but only if
27 * the property doesn't already exist on the target object.
28 * @param target The target to set properties on
29 * @param source The source of the property keys and values to set
30 */
31function fillProperties(target, source) {
32 for (const key in source) {
33 if (source.hasOwnProperty(key) && !target.hasOwnProperty(key)) {
34 target[key] = source[key];
35 }
36 }
37}
38
39/**
40 * @license
41 * Copyright Google LLC All Rights Reserved.
42 *
43 * Use of this source code is governed by an MIT-style license that can be
44 * found in the LICENSE file at https://angular.io/license
45 */
46function stringify(token) {
47 if (typeof token === 'string') {
48 return token;
49 }
50 if (Array.isArray(token)) {
51 return '[' + token.map(stringify).join(', ') + ']';
52 }
53 if (token == null) {
54 return '' + token;
55 }
56 if (token.overriddenName) {
57 return `${token.overriddenName}`;
58 }
59 if (token.name) {
60 return `${token.name}`;
61 }
62 const res = token.toString();
63 if (res == null) {
64 return '' + res;
65 }
66 const newLineIndex = res.indexOf('\n');
67 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
68}
69/**
70 * Concatenates two strings with separator, allocating new strings only when necessary.
71 *
72 * @param before before string.
73 * @param separator separator string.
74 * @param after after string.
75 * @returns concatenated string.
76 */
77function concatStringsWithSpace(before, after) {
78 return (before == null || before === '') ?
79 (after === null ? '' : after) :
80 ((after == null || after === '') ? before : before + ' ' + after);
81}
82
83/**
84 * @license
85 * Copyright Google LLC All Rights Reserved.
86 *
87 * Use of this source code is governed by an MIT-style license that can be
88 * found in the LICENSE file at https://angular.io/license
89 */
90const __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty });
91/**
92 * Allows to refer to references which are not yet defined.
93 *
94 * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
95 * DI is declared, but not yet defined. It is also used when the `token` which we use when creating
96 * a query is not yet defined.
97 *
98 * @usageNotes
99 * ### Example
100 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'}
101 * @publicApi
102 */
103function forwardRef(forwardRefFn) {
104 forwardRefFn.__forward_ref__ = forwardRef;
105 forwardRefFn.toString = function () {
106 return stringify(this());
107 };
108 return forwardRefFn;
109}
110/**
111 * Lazily retrieves the reference value from a forwardRef.
112 *
113 * Acts as the identity function when given a non-forward-ref value.
114 *
115 * @usageNotes
116 * ### Example
117 *
118 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'}
119 *
120 * @see `forwardRef`
121 * @publicApi
122 */
123function resolveForwardRef(type) {
124 return isForwardRef(type) ? type() : type;
125}
126/** Checks whether a function is wrapped by a `forwardRef`. */
127function isForwardRef(fn) {
128 return typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
129 fn.__forward_ref__ === forwardRef;
130}
131
132/**
133 * @license
134 * Copyright Google LLC All Rights Reserved.
135 *
136 * Use of this source code is governed by an MIT-style license that can be
137 * found in the LICENSE file at https://angular.io/license
138 */
139/**
140 * Base URL for the error details page.
141 *
142 * Keep the files below in full sync:
143 * - packages/compiler-cli/src/ngtsc/diagnostics/src/error_details_base_url.ts
144 * - packages/core/src/error_details_base_url.ts
145 */
146const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors';
147
148/**
149 * @license
150 * Copyright Google LLC All Rights Reserved.
151 *
152 * Use of this source code is governed by an MIT-style license that can be
153 * found in the LICENSE file at https://angular.io/license
154 */
155/**
156 * Class that represents a runtime error.
157 * Formats and outputs the error message in a consistent way.
158 *
159 * Example:
160 * ```
161 * throw new RuntimeError(
162 * RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED,
163 * ngDevMode && 'Injector has already been destroyed.');
164 * ```
165 *
166 * Note: the `message` argument contains a descriptive error message as a string in development
167 * mode (when the `ngDevMode` is defined). In production mode (after tree-shaking pass), the
168 * `message` argument becomes `false`, thus we account for it in the typings and the runtime logic.
169 */
170class RuntimeError extends Error {
171 constructor(code, message) {
172 super(formatRuntimeError(code, message));
173 this.code = code;
174 }
175}
176/**
177 * Called to format a runtime error.
178 * See additional info on the `message` argument type in the `RuntimeError` class description.
179 */
180function formatRuntimeError(code, message) {
181 // Error code might be a negative number, which is a special marker that instructs the logic to
182 // generate a link to the error details page on angular.io.
183 const fullCode = `NG0${Math.abs(code)}`;
184 let errorMessage = `${fullCode}${message ? ': ' + message.trim() : ''}`;
185 if (ngDevMode && code < 0) {
186 const addPeriodSeparator = !errorMessage.match(/[.,;!?]$/);
187 const separator = addPeriodSeparator ? '.' : '';
188 errorMessage =
189 `${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
190 }
191 return errorMessage;
192}
193
194/**
195 * @license
196 * Copyright Google LLC All Rights Reserved.
197 *
198 * Use of this source code is governed by an MIT-style license that can be
199 * found in the LICENSE file at https://angular.io/license
200 */
201/**
202 * Used for stringify render output in Ivy.
203 * Important! This function is very performance-sensitive and we should
204 * be extra careful not to introduce megamorphic reads in it.
205 * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations.
206 */
207function renderStringify(value) {
208 if (typeof value === 'string')
209 return value;
210 if (value == null)
211 return '';
212 // Use `String` so that it invokes the `toString` method of the value. Note that this
213 // appears to be faster than calling `value.toString` (see `render_stringify` benchmark).
214 return String(value);
215}
216/**
217 * Used to stringify a value so that it can be displayed in an error message.
218 * Important! This function contains a megamorphic read and should only be
219 * used for error messages.
220 */
221function stringifyForError(value) {
222 if (typeof value === 'function')
223 return value.name || value.toString();
224 if (typeof value === 'object' && value != null && typeof value.type === 'function') {
225 return value.type.name || value.type.toString();
226 }
227 return renderStringify(value);
228}
229
230/**
231 * @license
232 * Copyright Google LLC All Rights Reserved.
233 *
234 * Use of this source code is governed by an MIT-style license that can be
235 * found in the LICENSE file at https://angular.io/license
236 */
237/** Called when directives inject each other (creating a circular dependency) */
238function throwCyclicDependencyError(token, path) {
239 const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
240 throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, `Circular dependency in DI detected for ${token}${depPath}`);
241}
242function throwMixedMultiProviderError() {
243 throw new Error(`Cannot mix multi providers and regular providers`);
244}
245function throwInvalidProviderError(ngModuleType, providers, provider) {
246 if (ngModuleType && providers) {
247 const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...');
248 throw new Error(`Invalid provider for the NgModule '${stringify(ngModuleType)}' - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`);
249 }
250 else if (provider.ɵproviders) {
251 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.`);
252 }
253 else {
254 throw new Error('Invalid provider');
255 }
256}
257/** Throws an error when a token is not found in DI. */
258function throwProviderNotFoundError(token, injectorName) {
259 const injectorDetails = injectorName ? ` in ${injectorName}` : '';
260 throw new RuntimeError(-201 /* RuntimeErrorCode.PROVIDER_NOT_FOUND */, ngDevMode && `No provider for ${stringifyForError(token)} found${injectorDetails}`);
261}
262
263/**
264 * @license
265 * Copyright Google LLC All Rights Reserved.
266 *
267 * Use of this source code is governed by an MIT-style license that can be
268 * found in the LICENSE file at https://angular.io/license
269 */
270function assertNumber(actual, msg) {
271 if (!(typeof actual === 'number')) {
272 throwError(msg, typeof actual, 'number', '===');
273 }
274}
275function assertNumberInRange(actual, minInclusive, maxInclusive) {
276 assertNumber(actual, 'Expected a number');
277 assertLessThanOrEqual(actual, maxInclusive, 'Expected number to be less than or equal to');
278 assertGreaterThanOrEqual(actual, minInclusive, 'Expected number to be greater than or equal to');
279}
280function assertString(actual, msg) {
281 if (!(typeof actual === 'string')) {
282 throwError(msg, actual === null ? 'null' : typeof actual, 'string', '===');
283 }
284}
285function assertFunction(actual, msg) {
286 if (!(typeof actual === 'function')) {
287 throwError(msg, actual === null ? 'null' : typeof actual, 'function', '===');
288 }
289}
290function assertEqual(actual, expected, msg) {
291 if (!(actual == expected)) {
292 throwError(msg, actual, expected, '==');
293 }
294}
295function assertNotEqual(actual, expected, msg) {
296 if (!(actual != expected)) {
297 throwError(msg, actual, expected, '!=');
298 }
299}
300function assertSame(actual, expected, msg) {
301 if (!(actual === expected)) {
302 throwError(msg, actual, expected, '===');
303 }
304}
305function assertNotSame(actual, expected, msg) {
306 if (!(actual !== expected)) {
307 throwError(msg, actual, expected, '!==');
308 }
309}
310function assertLessThan(actual, expected, msg) {
311 if (!(actual < expected)) {
312 throwError(msg, actual, expected, '<');
313 }
314}
315function assertLessThanOrEqual(actual, expected, msg) {
316 if (!(actual <= expected)) {
317 throwError(msg, actual, expected, '<=');
318 }
319}
320function assertGreaterThan(actual, expected, msg) {
321 if (!(actual > expected)) {
322 throwError(msg, actual, expected, '>');
323 }
324}
325function assertGreaterThanOrEqual(actual, expected, msg) {
326 if (!(actual >= expected)) {
327 throwError(msg, actual, expected, '>=');
328 }
329}
330function assertNotDefined(actual, msg) {
331 if (actual != null) {
332 throwError(msg, actual, null, '==');
333 }
334}
335function assertDefined(actual, msg) {
336 if (actual == null) {
337 throwError(msg, actual, null, '!=');
338 }
339}
340function throwError(msg, actual, expected, comparison) {
341 throw new Error(`ASSERTION ERROR: ${msg}` +
342 (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
343}
344function assertDomNode(node) {
345 // If we're in a worker, `Node` will not be defined.
346 if (!(typeof Node !== 'undefined' && node instanceof Node) &&
347 !(typeof node === 'object' && node != null &&
348 node.constructor.name === 'WebWorkerRenderNode')) {
349 throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
350 }
351}
352function assertIndexInRange(arr, index) {
353 assertDefined(arr, 'Array must be defined.');
354 const maxLen = arr.length;
355 if (index < 0 || index >= maxLen) {
356 throwError(`Index expected to be less than ${maxLen} but got ${index}`);
357 }
358}
359function assertOneOf(value, ...validValues) {
360 if (validValues.indexOf(value) !== -1)
361 return true;
362 throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${JSON.stringify(value)}.`);
363}
364
365/**
366 * @license
367 * Copyright Google LLC All Rights Reserved.
368 *
369 * Use of this source code is governed by an MIT-style license that can be
370 * found in the LICENSE file at https://angular.io/license
371 */
372/**
373 * Construct an injectable definition which defines how a token will be constructed by the DI
374 * system, and in which injectors (if any) it will be available.
375 *
376 * This should be assigned to a static `ɵprov` field on a type, which will then be an
377 * `InjectableType`.
378 *
379 * Options:
380 * * `providedIn` determines which injectors will include the injectable, by either associating it
381 * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
382 * provided in the `'root'` injector, which will be the application-level injector in most apps.
383 * * `factory` gives the zero argument function which will create an instance of the injectable.
384 * The factory can call `inject` to access the `Injector` and request injection of dependencies.
385 *
386 * @codeGenApi
387 * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
388 */
389function ɵɵdefineInjectable(opts) {
390 return {
391 token: opts.token,
392 providedIn: opts.providedIn || null,
393 factory: opts.factory,
394 value: undefined,
395 };
396}
397/**
398 * @deprecated in v8, delete after v10. This API should be used only by generated code, and that
399 * code should now use ɵɵdefineInjectable instead.
400 * @publicApi
401 */
402const defineInjectable = ɵɵdefineInjectable;
403/**
404 * Construct an `InjectorDef` which configures an injector.
405 *
406 * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
407 * `InjectorType`.
408 *
409 * Options:
410 *
411 * * `providers`: an optional array of providers to add to the injector. Each provider must
412 * either have a factory or point to a type which has a `ɵprov` static property (the
413 * type must be an `InjectableType`).
414 * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
415 * whose providers will also be added to the injector. Locally provided types will override
416 * providers from imports.
417 *
418 * @codeGenApi
419 */
420function ɵɵdefineInjector(options) {
421 return { providers: options.providers || [], imports: options.imports || [] };
422}
423/**
424 * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
425 * inherited value.
426 *
427 * @param type A type which may have its own (non-inherited) `ɵprov`.
428 */
429function getInjectableDef(type) {
430 return getOwnDefinition(type, NG_PROV_DEF) || getOwnDefinition(type, NG_INJECTABLE_DEF);
431}
432/**
433 * Return definition only if it is defined directly on `type` and is not inherited from a base
434 * class of `type`.
435 */
436function getOwnDefinition(type, field) {
437 return type.hasOwnProperty(field) ? type[field] : null;
438}
439/**
440 * Read the injectable def (`ɵprov`) for `type` or read the `ɵprov` from one of its ancestors.
441 *
442 * @param type A type which may have `ɵprov`, via inheritance.
443 *
444 * @deprecated Will be removed in a future version of Angular, where an error will occur in the
445 * scenario if we find the `ɵprov` on an ancestor only.
446 */
447function getInheritedInjectableDef(type) {
448 const def = type && (type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF]);
449 if (def) {
450 const typeName = getTypeName(type);
451 // TODO(FW-1307): Re-add ngDevMode when closure can handle it
452 // ngDevMode &&
453 console.warn(`DEPRECATED: DI is instantiating a token "${typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` +
454 `This will become an error in a future version of Angular. Please add @Injectable() to the "${typeName}" class.`);
455 return def;
456 }
457 else {
458 return null;
459 }
460}
461/** Gets the name of a type, accounting for some cross-browser differences. */
462function getTypeName(type) {
463 // `Function.prototype.name` behaves differently between IE and other browsers. In most browsers
464 // it'll always return the name of the function itself, no matter how many other functions it
465 // inherits from. On IE the function doesn't have its own `name` property, but it takes it from
466 // the lowest level in the prototype chain. E.g. if we have `class Foo extends Parent` most
467 // browsers will evaluate `Foo.name` to `Foo` while IE will return `Parent`. We work around
468 // the issue by converting the function to a string and parsing its name out that way via a regex.
469 if (type.hasOwnProperty('name')) {
470 return type.name;
471 }
472 const match = ('' + type).match(/^function\s*([^\s(]+)/);
473 return match === null ? '' : match[1];
474}
475/**
476 * Read the injector def type in a way which is immune to accidentally reading inherited value.
477 *
478 * @param type type which may have an injector def (`ɵinj`)
479 */
480function getInjectorDef(type) {
481 return type && (type.hasOwnProperty(NG_INJ_DEF) || type.hasOwnProperty(NG_INJECTOR_DEF)) ?
482 type[NG_INJ_DEF] :
483 null;
484}
485const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty });
486const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty });
487// We need to keep these around so we can read off old defs if new defs are unavailable
488const NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty });
489const NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty });
490
491/**
492 * @license
493 * Copyright Google LLC All Rights Reserved.
494 *
495 * Use of this source code is governed by an MIT-style license that can be
496 * found in the LICENSE file at https://angular.io/license
497 */
498/**
499 * Injection flags for DI.
500 *
501 * @publicApi
502 */
503var InjectFlags;
504(function (InjectFlags) {
505 // TODO(alxhub): make this 'const' (and remove `InternalInjectFlags` enum) when ngc no longer
506 // writes exports of it into ngfactory files.
507 /** Check self and check parent injector if needed */
508 InjectFlags[InjectFlags["Default"] = 0] = "Default";
509 /**
510 * Specifies that an injector should retrieve a dependency from any injector until reaching the
511 * host element of the current component. (Only used with Element Injector)
512 */
513 InjectFlags[InjectFlags["Host"] = 1] = "Host";
514 /** Don't ascend to ancestors of the node requesting injection. */
515 InjectFlags[InjectFlags["Self"] = 2] = "Self";
516 /** Skip the node that is requesting injection. */
517 InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf";
518 /** Inject `defaultValue` instead if token not found. */
519 InjectFlags[InjectFlags["Optional"] = 8] = "Optional";
520})(InjectFlags || (InjectFlags = {}));
521
522/**
523 * @license
524 * Copyright Google LLC All Rights Reserved.
525 *
526 * Use of this source code is governed by an MIT-style license that can be
527 * found in the LICENSE file at https://angular.io/license
528 */
529/**
530 * Current implementation of inject.
531 *
532 * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
533 * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
534 * way for two reasons:
535 * 1. `Injector` should not depend on ivy logic.
536 * 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
537 */
538let _injectImplementation;
539function getInjectImplementation() {
540 return _injectImplementation;
541}
542/**
543 * Sets the current inject implementation.
544 */
545function setInjectImplementation(impl) {
546 const previous = _injectImplementation;
547 _injectImplementation = impl;
548 return previous;
549}
550/**
551 * Injects `root` tokens in limp mode.
552 *
553 * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
554 * `"root"`. This is known as the limp mode injection. In such case the value is stored in the
555 * injectable definition.
556 */
557function injectRootLimpMode(token, notFoundValue, flags) {
558 const injectableDef = getInjectableDef(token);
559 if (injectableDef && injectableDef.providedIn == 'root') {
560 return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
561 injectableDef.value;
562 }
563 if (flags & InjectFlags.Optional)
564 return null;
565 if (notFoundValue !== undefined)
566 return notFoundValue;
567 throwProviderNotFoundError(stringify(token), 'Injector');
568}
569/**
570 * Assert that `_injectImplementation` is not `fn`.
571 *
572 * This is useful, to prevent infinite recursion.
573 *
574 * @param fn Function which it should not equal to
575 */
576function assertInjectImplementationNotEqual(fn) {
577 ngDevMode &&
578 assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion');
579}
580
581/**
582 * @license
583 * Copyright Google LLC All Rights Reserved.
584 *
585 * Use of this source code is governed by an MIT-style license that can be
586 * found in the LICENSE file at https://angular.io/license
587 */
588/**
589 * Convince closure compiler that the wrapped function has no side-effects.
590 *
591 * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to
592 * allow us to execute a function but have closure compiler mark the call as no-side-effects.
593 * It is important that the return value for the `noSideEffects` function be assigned
594 * to something which is retained otherwise the call to `noSideEffects` will be removed by closure
595 * compiler.
596 */
597function noSideEffects(fn) {
598 return { toString: fn }.toString();
599}
600
601/**
602 * @license
603 * Copyright Google LLC All Rights Reserved.
604 *
605 * Use of this source code is governed by an MIT-style license that can be
606 * found in the LICENSE file at https://angular.io/license
607 */
608/**
609 * The strategy that the default change detector uses to detect changes.
610 * When set, takes effect the next time change detection is triggered.
611 *
612 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
613 *
614 * @publicApi
615 */
616var ChangeDetectionStrategy;
617(function (ChangeDetectionStrategy) {
618 /**
619 * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated
620 * until reactivated by setting the strategy to `Default` (`CheckAlways`).
621 * Change detection can still be explicitly invoked.
622 * This strategy applies to all child directives and cannot be overridden.
623 */
624 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
625 /**
626 * Use the default `CheckAlways` strategy, in which change detection is automatic until
627 * explicitly deactivated.
628 */
629 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
630})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
631/**
632 * Defines the possible states of the default change detector.
633 * @see `ChangeDetectorRef`
634 */
635var ChangeDetectorStatus;
636(function (ChangeDetectorStatus) {
637 /**
638 * A state in which, after calling `detectChanges()`, the change detector
639 * state becomes `Checked`, and must be explicitly invoked or reactivated.
640 */
641 ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce";
642 /**
643 * A state in which change detection is skipped until the change detector mode
644 * becomes `CheckOnce`.
645 */
646 ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked";
647 /**
648 * A state in which change detection continues automatically until explicitly
649 * deactivated.
650 */
651 ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways";
652 /**
653 * A state in which a change detector sub tree is not a part of the main tree and
654 * should be skipped.
655 */
656 ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached";
657 /**
658 * Indicates that the change detector encountered an error checking a binding
659 * or calling a directive lifecycle method and is now in an inconsistent state. Change
660 * detectors in this state do not detect changes.
661 */
662 ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored";
663 /**
664 * Indicates that the change detector has been destroyed.
665 */
666 ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed";
667})(ChangeDetectorStatus || (ChangeDetectorStatus = {}));
668/**
669 * Reports whether a given strategy is currently the default for change detection.
670 * @param changeDetectionStrategy The strategy to check.
671 * @returns True if the given strategy is the current default, false otherwise.
672 * @see `ChangeDetectorStatus`
673 * @see `ChangeDetectorRef`
674 */
675function isDefaultChangeDetectionStrategy(changeDetectionStrategy) {
676 return changeDetectionStrategy == null ||
677 changeDetectionStrategy === ChangeDetectionStrategy.Default;
678}
679
680/**
681 * @license
682 * Copyright Google LLC All Rights Reserved.
683 *
684 * Use of this source code is governed by an MIT-style license that can be
685 * found in the LICENSE file at https://angular.io/license
686 */
687/**
688 * Defines the CSS styles encapsulation policies for the {@link Component} decorator's
689 * `encapsulation` option.
690 *
691 * See {@link Component#encapsulation encapsulation}.
692 *
693 * @usageNotes
694 * ### Example
695 *
696 * {@example core/ts/metadata/encapsulation.ts region='longform'}
697 *
698 * @publicApi
699 */
700var ViewEncapsulation$1;
701(function (ViewEncapsulation) {
702 // TODO: consider making `ViewEncapsulation` a `const enum` instead. See
703 // https://github.com/angular/angular/issues/44119 for additional information.
704 /**
705 * Emulates a native Shadow DOM encapsulation behavior by adding a specific attribute to the
706 * component's host element and applying the same attribute to all the CSS selectors provided
707 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls}.
708 *
709 * This is the default option.
710 */
711 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
712 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
713 /**
714 * Doesn't provide any sort of CSS style encapsulation, meaning that all the styles provided
715 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls} are applicable
716 * to any HTML element of the application regardless of their host Component.
717 */
718 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
719 /**
720 * Uses the browser's native Shadow DOM API to encapsulate CSS styles, meaning that it creates
721 * a ShadowRoot for the component's host element which is then used to encapsulate
722 * all the Component's styling.
723 */
724 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
725})(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
726
727/**
728 * @license
729 * Copyright Google LLC All Rights Reserved.
730 *
731 * Use of this source code is governed by an MIT-style license that can be
732 * found in the LICENSE file at https://angular.io/license
733 */
734// Always use __globalThis if available, which is the spec-defined global variable across all
735// environments, then fallback to __global first, because in Node tests both __global and
736// __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof
737// checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
738// https://github.com/terser/terser/issues/250.
739const _global = ( /* @__PURE__ */(() => (typeof globalThis !== 'undefined' && globalThis) ||
740 (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
741 (typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
742 self instanceof WorkerGlobalScope && self))());
743
744/**
745 * @license
746 * Copyright Google LLC All Rights Reserved.
747 *
748 * Use of this source code is governed by an MIT-style license that can be
749 * found in the LICENSE file at https://angular.io/license
750 */
751function ngDevModeResetPerfCounters() {
752 const locationString = typeof location !== 'undefined' ? location.toString() : '';
753 const newCounters = {
754 namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1,
755 firstCreatePass: 0,
756 tNode: 0,
757 tView: 0,
758 rendererCreateTextNode: 0,
759 rendererSetText: 0,
760 rendererCreateElement: 0,
761 rendererAddEventListener: 0,
762 rendererSetAttribute: 0,
763 rendererRemoveAttribute: 0,
764 rendererSetProperty: 0,
765 rendererSetClassName: 0,
766 rendererAddClass: 0,
767 rendererRemoveClass: 0,
768 rendererSetStyle: 0,
769 rendererRemoveStyle: 0,
770 rendererDestroy: 0,
771 rendererDestroyNode: 0,
772 rendererMoveNode: 0,
773 rendererRemoveNode: 0,
774 rendererAppendChild: 0,
775 rendererInsertBefore: 0,
776 rendererCreateComment: 0,
777 };
778 // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
779 const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
780 _global['ngDevMode'] = allowNgDevModeTrue && newCounters;
781 return newCounters;
782}
783/**
784 * This function checks to see if the `ngDevMode` has been set. If yes,
785 * then we honor it, otherwise we default to dev mode with additional checks.
786 *
787 * The idea is that unless we are doing production build where we explicitly
788 * set `ngDevMode == false` we should be helping the developer by providing
789 * as much early warning and errors as possible.
790 *
791 * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions
792 * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode
793 * is defined for the entire instruction set.
794 *
795 * When checking `ngDevMode` on toplevel, always init it before referencing it
796 * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can
797 * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595.
798 *
799 * Details on possible values for `ngDevMode` can be found on its docstring.
800 *
801 * NOTE:
802 * - changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`.
803 */
804function initNgDevMode() {
805 // The below checks are to ensure that calling `initNgDevMode` multiple times does not
806 // reset the counters.
807 // If the `ngDevMode` is not an object, then it means we have not created the perf counters
808 // yet.
809 if (typeof ngDevMode === 'undefined' || ngDevMode) {
810 if (typeof ngDevMode !== 'object') {
811 ngDevModeResetPerfCounters();
812 }
813 return typeof ngDevMode !== 'undefined' && !!ngDevMode;
814 }
815 return false;
816}
817
818/**
819 * @license
820 * Copyright Google LLC All Rights Reserved.
821 *
822 * Use of this source code is governed by an MIT-style license that can be
823 * found in the LICENSE file at https://angular.io/license
824 */
825/**
826 * This file contains reuseable "empty" symbols that can be used as default return values
827 * in different parts of the rendering code. Because the same symbols are returned, this
828 * allows for identity checks against these values to be consistently used by the framework
829 * code.
830 */
831const EMPTY_OBJ = {};
832const EMPTY_ARRAY = [];
833// freezing the values prevents any code from accidentally inserting new values in
834if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
835 // These property accesses can be ignored because ngDevMode will be set to false
836 // when optimizing code and the whole if statement will be dropped.
837 // tslint:disable-next-line:no-toplevel-property-access
838 Object.freeze(EMPTY_OBJ);
839 // tslint:disable-next-line:no-toplevel-property-access
840 Object.freeze(EMPTY_ARRAY);
841}
842
843/**
844 * @license
845 * Copyright Google LLC All Rights Reserved.
846 *
847 * Use of this source code is governed by an MIT-style license that can be
848 * found in the LICENSE file at https://angular.io/license
849 */
850const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty });
851const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty });
852const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty });
853const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty });
854const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty });
855/**
856 * If a directive is diPublic, bloomAdd sets a property on the type with this constant as
857 * the key and the directive's unique ID as the value. This allows us to map directives to their
858 * bloom filter bit for DI.
859 */
860// TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified.
861const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty });
862
863/**
864 * @license
865 * Copyright Google LLC All Rights Reserved.
866 *
867 * Use of this source code is governed by an MIT-style license that can be
868 * found in the LICENSE file at https://angular.io/license
869 */
870/** Counter used to generate unique IDs for component definitions. */
871let componentDefCount = 0;
872/**
873 * Create a component definition object.
874 *
875 *
876 * # Example
877 * ```
878 * class MyDirective {
879 * // Generated by Angular Template Compiler
880 * // [Symbol] syntax will not be supported by TypeScript until v2.7
881 * static ɵcmp = defineComponent({
882 * ...
883 * });
884 * }
885 * ```
886 * @codeGenApi
887 */
888function ɵɵdefineComponent(componentDefinition) {
889 return noSideEffects(() => {
890 // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
891 // See the `initNgDevMode` docstring for more information.
892 (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
893 const type = componentDefinition.type;
894 const standalone = componentDefinition.standalone === true;
895 const declaredInputs = {};
896 const def = {
897 type: type,
898 providersResolver: null,
899 decls: componentDefinition.decls,
900 vars: componentDefinition.vars,
901 factory: null,
902 template: componentDefinition.template || null,
903 consts: componentDefinition.consts || null,
904 ngContentSelectors: componentDefinition.ngContentSelectors,
905 hostBindings: componentDefinition.hostBindings || null,
906 hostVars: componentDefinition.hostVars || 0,
907 hostAttrs: componentDefinition.hostAttrs || null,
908 contentQueries: componentDefinition.contentQueries || null,
909 declaredInputs: declaredInputs,
910 inputs: null,
911 outputs: null,
912 exportAs: componentDefinition.exportAs || null,
913 onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
914 directiveDefs: null,
915 pipeDefs: null,
916 standalone,
917 dependencies: standalone && componentDefinition.dependencies || null,
918 getStandaloneInjector: null,
919 selectors: componentDefinition.selectors || EMPTY_ARRAY,
920 viewQuery: componentDefinition.viewQuery || null,
921 features: componentDefinition.features || null,
922 data: componentDefinition.data || {},
923 encapsulation: componentDefinition.encapsulation || ViewEncapsulation$1.Emulated,
924 id: `c${componentDefCount++}`,
925 styles: componentDefinition.styles || EMPTY_ARRAY,
926 _: null,
927 setInput: null,
928 schemas: componentDefinition.schemas || null,
929 tView: null,
930 };
931 const dependencies = componentDefinition.dependencies;
932 const feature = componentDefinition.features;
933 def.inputs = invertObject(componentDefinition.inputs, declaredInputs),
934 def.outputs = invertObject(componentDefinition.outputs),
935 feature && feature.forEach((fn) => fn(def));
936 def.directiveDefs = dependencies ?
937 (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
938 .map(extractDirectiveDef)
939 .filter(nonNull)) :
940 null;
941 def.pipeDefs = dependencies ?
942 (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
943 .map(getPipeDef$1)
944 .filter(nonNull)) :
945 null;
946 return def;
947 });
948}
949/**
950 * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
951 * definition, when generating a direct reference in the component file would otherwise create an
952 * import cycle.
953 *
954 * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
955 *
956 * @codeGenApi
957 */
958function ɵɵsetComponentScope(type, directives, pipes) {
959 const def = type.ɵcmp;
960 def.directiveDefs = () => (typeof directives === 'function' ? directives() : directives).map(extractDirectiveDef);
961 def.pipeDefs = () => (typeof pipes === 'function' ? pipes() : pipes).map(getPipeDef$1);
962}
963function extractDirectiveDef(type) {
964 return getComponentDef(type) || getDirectiveDef(type);
965}
966function nonNull(value) {
967 return value !== null;
968}
969const autoRegisterModuleById = {};
970/**
971 * @codeGenApi
972 */
973function ɵɵdefineNgModule(def) {
974 return noSideEffects(() => {
975 const res = {
976 type: def.type,
977 bootstrap: def.bootstrap || EMPTY_ARRAY,
978 declarations: def.declarations || EMPTY_ARRAY,
979 imports: def.imports || EMPTY_ARRAY,
980 exports: def.exports || EMPTY_ARRAY,
981 transitiveCompileScopes: null,
982 schemas: def.schemas || null,
983 id: def.id || null,
984 };
985 if (def.id != null) {
986 autoRegisterModuleById[def.id] = def.type;
987 }
988 return res;
989 });
990}
991/**
992 * Adds the module metadata that is necessary to compute the module's transitive scope to an
993 * existing module definition.
994 *
995 * Scope metadata of modules is not used in production builds, so calls to this function can be
996 * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
997 * to become eligible for tree-shaking as well.
998 *
999 * @codeGenApi
1000 */
1001function ɵɵsetNgModuleScope(type, scope) {
1002 return noSideEffects(() => {
1003 const ngModuleDef = getNgModuleDef(type, true);
1004 ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
1005 ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
1006 ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
1007 });
1008}
1009/**
1010 * Inverts an inputs or outputs lookup such that the keys, which were the
1011 * minified keys, are part of the values, and the values are parsed so that
1012 * the publicName of the property is the new key
1013 *
1014 * e.g. for
1015 *
1016 * ```
1017 * class Comp {
1018 * @Input()
1019 * propName1: string;
1020 *
1021 * @Input('publicName2')
1022 * declaredPropName2: number;
1023 * }
1024 * ```
1025 *
1026 * will be serialized as
1027 *
1028 * ```
1029 * {
1030 * propName1: 'propName1',
1031 * declaredPropName2: ['publicName2', 'declaredPropName2'],
1032 * }
1033 * ```
1034 *
1035 * which is than translated by the minifier as:
1036 *
1037 * ```
1038 * {
1039 * minifiedPropName1: 'propName1',
1040 * minifiedPropName2: ['publicName2', 'declaredPropName2'],
1041 * }
1042 * ```
1043 *
1044 * becomes: (public name => minifiedName)
1045 *
1046 * ```
1047 * {
1048 * 'propName1': 'minifiedPropName1',
1049 * 'publicName2': 'minifiedPropName2',
1050 * }
1051 * ```
1052 *
1053 * Optionally the function can take `secondary` which will result in: (public name => declared name)
1054 *
1055 * ```
1056 * {
1057 * 'propName1': 'propName1',
1058 * 'publicName2': 'declaredPropName2',
1059 * }
1060 * ```
1061 *
1062
1063 */
1064function invertObject(obj, secondary) {
1065 if (obj == null)
1066 return EMPTY_OBJ;
1067 const newLookup = {};
1068 for (const minifiedKey in obj) {
1069 if (obj.hasOwnProperty(minifiedKey)) {
1070 let publicName = obj[minifiedKey];
1071 let declaredName = publicName;
1072 if (Array.isArray(publicName)) {
1073 declaredName = publicName[1];
1074 publicName = publicName[0];
1075 }
1076 newLookup[publicName] = minifiedKey;
1077 if (secondary) {
1078 (secondary[publicName] = declaredName);
1079 }
1080 }
1081 }
1082 return newLookup;
1083}
1084/**
1085 * Create a directive definition object.
1086 *
1087 * # Example
1088 * ```ts
1089 * class MyDirective {
1090 * // Generated by Angular Template Compiler
1091 * // [Symbol] syntax will not be supported by TypeScript until v2.7
1092 * static ɵdir = ɵɵdefineDirective({
1093 * ...
1094 * });
1095 * }
1096 * ```
1097 *
1098 * @codeGenApi
1099 */
1100const ɵɵdefineDirective = ɵɵdefineComponent;
1101/**
1102 * Create a pipe definition object.
1103 *
1104 * # Example
1105 * ```
1106 * class MyPipe implements PipeTransform {
1107 * // Generated by Angular Template Compiler
1108 * static ɵpipe = definePipe({
1109 * ...
1110 * });
1111 * }
1112 * ```
1113 * @param pipeDef Pipe definition generated by the compiler
1114 *
1115 * @codeGenApi
1116 */
1117function ɵɵdefinePipe(pipeDef) {
1118 return {
1119 type: pipeDef.type,
1120 name: pipeDef.name,
1121 factory: null,
1122 pure: pipeDef.pure !== false,
1123 standalone: pipeDef.standalone === true,
1124 onDestroy: pipeDef.type.prototype.ngOnDestroy || null
1125 };
1126}
1127/**
1128 * The following getter methods retrieve the definition from the type. Currently the retrieval
1129 * honors inheritance, but in the future we may change the rule to require that definitions are
1130 * explicit. This would require some sort of migration strategy.
1131 */
1132function getComponentDef(type) {
1133 return type[NG_COMP_DEF] || null;
1134}
1135function getDirectiveDef(type) {
1136 return type[NG_DIR_DEF] || null;
1137}
1138function getPipeDef$1(type) {
1139 return type[NG_PIPE_DEF] || null;
1140}
1141function getNgModuleDef(type, throwNotFound) {
1142 const ngModuleDef = type[NG_MOD_DEF] || null;
1143 if (!ngModuleDef && throwNotFound === true) {
1144 throw new Error(`Type ${stringify(type)} does not have 'ɵmod' property.`);
1145 }
1146 return ngModuleDef;
1147}
1148
1149/**
1150 * Special location which allows easy identification of type. If we have an array which was
1151 * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
1152 * `LContainer`.
1153 */
1154const TYPE = 1;
1155/**
1156 * Below are constants for LContainer indices to help us look up LContainer members
1157 * without having to remember the specific indices.
1158 * Uglify will inline these when minifying so there shouldn't be a cost.
1159 */
1160/**
1161 * Flag to signify that this `LContainer` may have transplanted views which need to be change
1162 * detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
1163 *
1164 * This flag, once set, is never unset for the `LContainer`. This means that when unset we can skip
1165 * a lot of work in `refreshEmbeddedViews`. But when set we still need to verify
1166 * that the `MOVED_VIEWS` are transplanted and on-push.
1167 */
1168const HAS_TRANSPLANTED_VIEWS = 2;
1169// PARENT, NEXT, TRANSPLANTED_VIEWS_TO_REFRESH are indices 3, 4, and 5
1170// As we already have these constants in LView, we don't need to re-create them.
1171// T_HOST is index 6
1172// We already have this constants in LView, we don't need to re-create it.
1173const NATIVE = 7;
1174const VIEW_REFS = 8;
1175const MOVED_VIEWS = 9;
1176/**
1177 * Size of LContainer's header. Represents the index after which all views in the
1178 * container will be inserted. We need to keep a record of current views so we know
1179 * which views are already in the DOM (and don't need to be re-added) and so we can
1180 * remove views from the DOM when they are no longer required.
1181 */
1182const CONTAINER_HEADER_OFFSET = 10;
1183// Note: This hack is necessary so we don't erroneously get a circular dependency
1184// failure based on types.
1185const unusedValueExportToPlacateAjd$8 = 1;
1186
1187/**
1188 * @license
1189 * Copyright Google LLC All Rights Reserved.
1190 *
1191 * Use of this source code is governed by an MIT-style license that can be
1192 * found in the LICENSE file at https://angular.io/license
1193 */
1194// Below are constants for LView indices to help us look up LView members
1195// without having to remember the specific indices.
1196// Uglify will inline these when minifying so there shouldn't be a cost.
1197const HOST = 0;
1198const TVIEW = 1;
1199const FLAGS = 2;
1200const PARENT = 3;
1201const NEXT = 4;
1202const TRANSPLANTED_VIEWS_TO_REFRESH = 5;
1203const T_HOST = 6;
1204const CLEANUP = 7;
1205const CONTEXT = 8;
1206const INJECTOR$1 = 9;
1207const RENDERER_FACTORY = 10;
1208const RENDERER = 11;
1209const SANITIZER = 12;
1210const CHILD_HEAD = 13;
1211const CHILD_TAIL = 14;
1212// FIXME(misko): Investigate if the three declarations aren't all same thing.
1213const DECLARATION_VIEW = 15;
1214const DECLARATION_COMPONENT_VIEW = 16;
1215const DECLARATION_LCONTAINER = 17;
1216const PREORDER_HOOK_FLAGS = 18;
1217const QUERIES = 19;
1218const ID = 20;
1219const EMBEDDED_VIEW_INJECTOR = 21;
1220/**
1221 * Size of LView's header. Necessary to adjust for it when setting slots.
1222 *
1223 * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
1224 * instruction index into `LView` index. All other indexes should be in the `LView` index space and
1225 * there should be no need to refer to `HEADER_OFFSET` anywhere else.
1226 */
1227const HEADER_OFFSET = 22;
1228/**
1229 * Converts `TViewType` into human readable text.
1230 * Make sure this matches with `TViewType`
1231 */
1232const TViewTypeAsString = [
1233 'Root',
1234 'Component',
1235 'Embedded', // 2
1236];
1237// Note: This hack is necessary so we don't erroneously get a circular dependency
1238// failure based on types.
1239const unusedValueExportToPlacateAjd$7 = 1;
1240
1241/**
1242 * @license
1243 * Copyright Google LLC All Rights Reserved.
1244 *
1245 * Use of this source code is governed by an MIT-style license that can be
1246 * found in the LICENSE file at https://angular.io/license
1247 */
1248/**
1249 * True if `value` is `LView`.
1250 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1251 */
1252function isLView(value) {
1253 return Array.isArray(value) && typeof value[TYPE] === 'object';
1254}
1255/**
1256 * True if `value` is `LContainer`.
1257 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1258 */
1259function isLContainer(value) {
1260 return Array.isArray(value) && value[TYPE] === true;
1261}
1262function isContentQueryHost(tNode) {
1263 return (tNode.flags & 8 /* TNodeFlags.hasContentQuery */) !== 0;
1264}
1265function isComponentHost(tNode) {
1266 return (tNode.flags & 2 /* TNodeFlags.isComponentHost */) === 2 /* TNodeFlags.isComponentHost */;
1267}
1268function isDirectiveHost(tNode) {
1269 return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
1270}
1271function isComponentDef(def) {
1272 return def.template !== null;
1273}
1274function isRootView(target) {
1275 return (target[FLAGS] & 256 /* LViewFlags.IsRoot */) !== 0;
1276}
1277
1278/**
1279 * @license
1280 * Copyright Google LLC All Rights Reserved.
1281 *
1282 * Use of this source code is governed by an MIT-style license that can be
1283 * found in the LICENSE file at https://angular.io/license
1284 */
1285// [Assert functions do not constraint type when they are guarded by a truthy
1286// expression.](https://github.com/microsoft/TypeScript/issues/37295)
1287function assertTNodeForLView(tNode, lView) {
1288 assertTNodeForTView(tNode, lView[TVIEW]);
1289}
1290function assertTNodeForTView(tNode, tView) {
1291 assertTNode(tNode);
1292 tNode.hasOwnProperty('tView_') &&
1293 assertEqual(tNode.tView_, tView, 'This TNode does not belong to this TView.');
1294}
1295function assertTNode(tNode) {
1296 assertDefined(tNode, 'TNode must be defined');
1297 if (!(tNode && typeof tNode === 'object' && tNode.hasOwnProperty('directiveStylingLast'))) {
1298 throwError('Not of type TNode, got: ' + tNode);
1299 }
1300}
1301function assertTIcu(tIcu) {
1302 assertDefined(tIcu, 'Expected TIcu to be defined');
1303 if (!(typeof tIcu.currentCaseLViewIndex === 'number')) {
1304 throwError('Object is not of TIcu type.');
1305 }
1306}
1307function assertComponentType(actual, msg = 'Type passed in is not ComponentType, it does not have \'ɵcmp\' property.') {
1308 if (!getComponentDef(actual)) {
1309 throwError(msg);
1310 }
1311}
1312function assertNgModuleType(actual, msg = 'Type passed in is not NgModuleType, it does not have \'ɵmod\' property.') {
1313 if (!getNgModuleDef(actual)) {
1314 throwError(msg);
1315 }
1316}
1317function assertCurrentTNodeIsParent(isParent) {
1318 assertEqual(isParent, true, 'currentTNode should be a parent');
1319}
1320function assertHasParent(tNode) {
1321 assertDefined(tNode, 'currentTNode should exist!');
1322 assertDefined(tNode.parent, 'currentTNode should have a parent');
1323}
1324function assertDataNext(lView, index, arr) {
1325 if (arr == null)
1326 arr = lView;
1327 assertEqual(arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`);
1328}
1329function assertLContainer(value) {
1330 assertDefined(value, 'LContainer must be defined');
1331 assertEqual(isLContainer(value), true, 'Expecting LContainer');
1332}
1333function assertLViewOrUndefined(value) {
1334 value && assertEqual(isLView(value), true, 'Expecting LView or undefined or null');
1335}
1336function assertLView(value) {
1337 assertDefined(value, 'LView must be defined');
1338 assertEqual(isLView(value), true, 'Expecting LView');
1339}
1340function assertFirstCreatePass(tView, errMessage) {
1341 assertEqual(tView.firstCreatePass, true, errMessage || 'Should only be called in first create pass.');
1342}
1343function assertFirstUpdatePass(tView, errMessage) {
1344 assertEqual(tView.firstUpdatePass, true, errMessage || 'Should only be called in first update pass.');
1345}
1346/**
1347 * This is a basic sanity check that an object is probably a directive def. DirectiveDef is
1348 * an interface, so we can't do a direct instanceof check.
1349 */
1350function assertDirectiveDef(obj) {
1351 if (obj.type === undefined || obj.selectors == undefined || obj.inputs === undefined) {
1352 throwError(`Expected a DirectiveDef/ComponentDef and this object does not seem to have the expected shape.`);
1353 }
1354}
1355function assertIndexInDeclRange(lView, index) {
1356 const tView = lView[1];
1357 assertBetween(HEADER_OFFSET, tView.bindingStartIndex, index);
1358}
1359function assertIndexInVarsRange(lView, index) {
1360 const tView = lView[1];
1361 assertBetween(tView.bindingStartIndex, tView.expandoStartIndex, index);
1362}
1363function assertIndexInExpandoRange(lView, index) {
1364 const tView = lView[1];
1365 assertBetween(tView.expandoStartIndex, lView.length, index);
1366}
1367function assertBetween(lower, upper, index) {
1368 if (!(lower <= index && index < upper)) {
1369 throwError(`Index out of range (expecting ${lower} <= ${index} < ${upper})`);
1370 }
1371}
1372function assertProjectionSlots(lView, errMessage) {
1373 assertDefined(lView[DECLARATION_COMPONENT_VIEW], 'Component views should exist.');
1374 assertDefined(lView[DECLARATION_COMPONENT_VIEW][T_HOST].projection, errMessage ||
1375 'Components with projection nodes (<ng-content>) must have projection slots defined.');
1376}
1377function assertParentView(lView, errMessage) {
1378 assertDefined(lView, errMessage || 'Component views should always have a parent view (component\'s host view)');
1379}
1380/**
1381 * This is a basic sanity check that the `injectorIndex` seems to point to what looks like a
1382 * NodeInjector data structure.
1383 *
1384 * @param lView `LView` which should be checked.
1385 * @param injectorIndex index into the `LView` where the `NodeInjector` is expected.
1386 */
1387function assertNodeInjector(lView, injectorIndex) {
1388 assertIndexInExpandoRange(lView, injectorIndex);
1389 assertIndexInExpandoRange(lView, injectorIndex + 8 /* NodeInjectorOffset.PARENT */);
1390 assertNumber(lView[injectorIndex + 0], 'injectorIndex should point to a bloom filter');
1391 assertNumber(lView[injectorIndex + 1], 'injectorIndex should point to a bloom filter');
1392 assertNumber(lView[injectorIndex + 2], 'injectorIndex should point to a bloom filter');
1393 assertNumber(lView[injectorIndex + 3], 'injectorIndex should point to a bloom filter');
1394 assertNumber(lView[injectorIndex + 4], 'injectorIndex should point to a bloom filter');
1395 assertNumber(lView[injectorIndex + 5], 'injectorIndex should point to a bloom filter');
1396 assertNumber(lView[injectorIndex + 6], 'injectorIndex should point to a bloom filter');
1397 assertNumber(lView[injectorIndex + 7], 'injectorIndex should point to a bloom filter');
1398 assertNumber(lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */], 'injectorIndex should point to parent injector');
1399}
1400
1401/**
1402 * @license
1403 * Copyright Google LLC All Rights Reserved.
1404 *
1405 * Use of this source code is governed by an MIT-style license that can be
1406 * found in the LICENSE file at https://angular.io/license
1407 */
1408function getFactoryDef(type, throwNotFound) {
1409 const hasFactoryDef = type.hasOwnProperty(NG_FACTORY_DEF);
1410 if (!hasFactoryDef && throwNotFound === true && ngDevMode) {
1411 throw new Error(`Type ${stringify(type)} does not have 'ɵfac' property.`);
1412 }
1413 return hasFactoryDef ? type[NG_FACTORY_DEF] : null;
1414}
1415
1416/**
1417 * @license
1418 * Copyright Google LLC All Rights Reserved.
1419 *
1420 * Use of this source code is governed by an MIT-style license that can be
1421 * found in the LICENSE file at https://angular.io/license
1422 */
1423/**
1424 * Represents a basic change from a previous to a new value for a single
1425 * property on a directive instance. Passed as a value in a
1426 * {@link SimpleChanges} object to the `ngOnChanges` hook.
1427 *
1428 * @see `OnChanges`
1429 *
1430 * @publicApi
1431 */
1432class SimpleChange {
1433 constructor(previousValue, currentValue, firstChange) {
1434 this.previousValue = previousValue;
1435 this.currentValue = currentValue;
1436 this.firstChange = firstChange;
1437 }
1438 /**
1439 * Check whether the new value is the first value assigned.
1440 */
1441 isFirstChange() {
1442 return this.firstChange;
1443 }
1444}
1445
1446/**
1447 * @license
1448 * Copyright Google LLC All Rights Reserved.
1449 *
1450 * Use of this source code is governed by an MIT-style license that can be
1451 * found in the LICENSE file at https://angular.io/license
1452 */
1453/**
1454 * The NgOnChangesFeature decorates a component with support for the ngOnChanges
1455 * lifecycle hook, so it should be included in any component that implements
1456 * that hook.
1457 *
1458 * If the component or directive uses inheritance, the NgOnChangesFeature MUST
1459 * be included as a feature AFTER {@link InheritDefinitionFeature}, otherwise
1460 * inherited properties will not be propagated to the ngOnChanges lifecycle
1461 * hook.
1462 *
1463 * Example usage:
1464 *
1465 * ```
1466 * static ɵcmp = defineComponent({
1467 * ...
1468 * inputs: {name: 'publicName'},
1469 * features: [NgOnChangesFeature]
1470 * });
1471 * ```
1472 *
1473 * @codeGenApi
1474 */
1475function ɵɵNgOnChangesFeature() {
1476 return NgOnChangesFeatureImpl;
1477}
1478function NgOnChangesFeatureImpl(definition) {
1479 if (definition.type.prototype.ngOnChanges) {
1480 definition.setInput = ngOnChangesSetInput;
1481 }
1482 return rememberChangeHistoryAndInvokeOnChangesHook;
1483}
1484// This option ensures that the ngOnChanges lifecycle hook will be inherited
1485// from superclasses (in InheritDefinitionFeature).
1486/** @nocollapse */
1487// tslint:disable-next-line:no-toplevel-property-access
1488ɵɵNgOnChangesFeature.ngInherit = true;
1489/**
1490 * This is a synthetic lifecycle hook which gets inserted into `TView.preOrderHooks` to simulate
1491 * `ngOnChanges`.
1492 *
1493 * The hook reads the `NgSimpleChangesStore` data from the component instance and if changes are
1494 * found it invokes `ngOnChanges` on the component instance.
1495 *
1496 * @param this Component instance. Because this function gets inserted into `TView.preOrderHooks`,
1497 * it is guaranteed to be called with component instance.
1498 */
1499function rememberChangeHistoryAndInvokeOnChangesHook() {
1500 const simpleChangesStore = getSimpleChangesStore(this);
1501 const current = simpleChangesStore === null || simpleChangesStore === void 0 ? void 0 : simpleChangesStore.current;
1502 if (current) {
1503 const previous = simpleChangesStore.previous;
1504 if (previous === EMPTY_OBJ) {
1505 simpleChangesStore.previous = current;
1506 }
1507 else {
1508 // New changes are copied to the previous store, so that we don't lose history for inputs
1509 // which were not changed this time
1510 for (let key in current) {
1511 previous[key] = current[key];
1512 }
1513 }
1514 simpleChangesStore.current = null;
1515 this.ngOnChanges(current);
1516 }
1517}
1518function ngOnChangesSetInput(instance, value, publicName, privateName) {
1519 const simpleChangesStore = getSimpleChangesStore(instance) ||
1520 setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
1521 const current = simpleChangesStore.current || (simpleChangesStore.current = {});
1522 const previous = simpleChangesStore.previous;
1523 const declaredName = this.declaredInputs[publicName];
1524 const previousChange = previous[declaredName];
1525 current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
1526 instance[privateName] = value;
1527}
1528const SIMPLE_CHANGES_STORE = '__ngSimpleChanges__';
1529function getSimpleChangesStore(instance) {
1530 return instance[SIMPLE_CHANGES_STORE] || null;
1531}
1532function setSimpleChangesStore(instance, store) {
1533 return instance[SIMPLE_CHANGES_STORE] = store;
1534}
1535
1536/**
1537 * @license
1538 * Copyright Google LLC All Rights Reserved.
1539 *
1540 * Use of this source code is governed by an MIT-style license that can be
1541 * found in the LICENSE file at https://angular.io/license
1542 */
1543let profilerCallback = null;
1544/**
1545 * Sets the callback function which will be invoked before and after performing certain actions at
1546 * runtime (for example, before and after running change detection).
1547 *
1548 * Warning: this function is *INTERNAL* and should not be relied upon in application's code.
1549 * The contract of the function might be changed in any release and/or the function can be removed
1550 * completely.
1551 *
1552 * @param profiler function provided by the caller or null value to disable profiling.
1553 */
1554const setProfiler = (profiler) => {
1555 profilerCallback = profiler;
1556};
1557/**
1558 * Profiler function which wraps user code executed by the runtime.
1559 *
1560 * @param event ProfilerEvent corresponding to the execution context
1561 * @param instance component instance
1562 * @param hookOrListener lifecycle hook function or output listener. The value depends on the
1563 * execution context
1564 * @returns
1565 */
1566const profiler = function (event, instance, hookOrListener) {
1567 if (profilerCallback != null /* both `null` and `undefined` */) {
1568 profilerCallback(event, instance, hookOrListener);
1569 }
1570};
1571
1572/**
1573 * @license
1574 * Copyright Google LLC All Rights Reserved.
1575 *
1576 * Use of this source code is governed by an MIT-style license that can be
1577 * found in the LICENSE file at https://angular.io/license
1578 */
1579const SVG_NAMESPACE = 'svg';
1580const SVG_NAMESPACE_URI = 'http://www.w3.org/2000/svg';
1581const MATH_ML_NAMESPACE = 'math';
1582const MATH_ML_NAMESPACE_URI = 'http://www.w3.org/1998/MathML/';
1583function getNamespaceUri(namespace) {
1584 const name = namespace.toLowerCase();
1585 return name === SVG_NAMESPACE ? SVG_NAMESPACE_URI :
1586 (name === MATH_ML_NAMESPACE ? MATH_ML_NAMESPACE_URI : null);
1587}
1588
1589/**
1590 * @license
1591 * Copyright Google LLC All Rights Reserved.
1592 *
1593 * Use of this source code is governed by an MIT-style license that can be
1594 * found in the LICENSE file at https://angular.io/license
1595 */
1596/**
1597 * Most of the use of `document` in Angular is from within the DI system so it is possible to simply
1598 * inject the `DOCUMENT` token and are done.
1599 *
1600 * Ivy is special because it does not rely upon the DI and must get hold of the document some other
1601 * way.
1602 *
1603 * The solution is to define `getDocument()` and `setDocument()` top-level functions for ivy.
1604 * Wherever ivy needs the global document, it calls `getDocument()` instead.
1605 *
1606 * When running ivy outside of a browser environment, it is necessary to call `setDocument()` to
1607 * tell ivy what the global `document` is.
1608 *
1609 * Angular does this for us in each of the standard platforms (`Browser`, `Server`, and `WebWorker`)
1610 * by calling `setDocument()` when providing the `DOCUMENT` token.
1611 */
1612let DOCUMENT = undefined;
1613/**
1614 * Tell ivy what the `document` is for this platform.
1615 *
1616 * It is only necessary to call this if the current platform is not a browser.
1617 *
1618 * @param document The object representing the global `document` in this environment.
1619 */
1620function setDocument(document) {
1621 DOCUMENT = document;
1622}
1623/**
1624 * Access the object that represents the `document` for this platform.
1625 *
1626 * Ivy calls this whenever it needs to access the `document` object.
1627 * For example to create the renderer or to do sanitization.
1628 */
1629function getDocument() {
1630 if (DOCUMENT !== undefined) {
1631 return DOCUMENT;
1632 }
1633 else if (typeof document !== 'undefined') {
1634 return document;
1635 }
1636 // No "document" can be found. This should only happen if we are running ivy outside Angular and
1637 // the current platform is not a browser. Since this is not a supported scenario at the moment
1638 // this should not happen in Angular apps.
1639 // Once we support running ivy outside of Angular we will need to publish `setDocument()` as a
1640 // public API. Meanwhile we just return `undefined` and let the application fail.
1641 return undefined;
1642}
1643
1644/**
1645 * @license
1646 * Copyright Google LLC All Rights Reserved.
1647 *
1648 * Use of this source code is governed by an MIT-style license that can be
1649 * found in the LICENSE file at https://angular.io/license
1650 */
1651// TODO: cleanup once the code is merged in angular/angular
1652var RendererStyleFlags3;
1653(function (RendererStyleFlags3) {
1654 RendererStyleFlags3[RendererStyleFlags3["Important"] = 1] = "Important";
1655 RendererStyleFlags3[RendererStyleFlags3["DashCase"] = 2] = "DashCase";
1656})(RendererStyleFlags3 || (RendererStyleFlags3 = {}));
1657/** Returns whether the `renderer` is a `ProceduralRenderer3` */
1658function isProceduralRenderer(renderer) {
1659 return !!(renderer.listen);
1660}
1661const domRendererFactory3 = {
1662 createRenderer: (hostElement, rendererType) => {
1663 return getDocument();
1664 }
1665};
1666// Note: This hack is necessary so we don't erroneously get a circular dependency
1667// failure based on types.
1668const unusedValueExportToPlacateAjd$6 = 1;
1669
1670/**
1671 * @license
1672 * Copyright Google LLC All Rights Reserved.
1673 *
1674 * Use of this source code is governed by an MIT-style license that can be
1675 * found in the LICENSE file at https://angular.io/license
1676 */
1677/**
1678 * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
1679 * in same location in `LView`. This is because we don't want to pre-allocate space for it
1680 * because the storage is sparse. This file contains utilities for dealing with such data types.
1681 *
1682 * How do we know what is stored at a given location in `LView`.
1683 * - `Array.isArray(value) === false` => `RNode` (The normal storage value)
1684 * - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value.
1685 * - `typeof value[TYPE] === 'object'` => `LView`
1686 * - This happens when we have a component at a given location
1687 * - `typeof value[TYPE] === true` => `LContainer`
1688 * - This happens when we have `LContainer` binding at a given location.
1689 *
1690 *
1691 * NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.
1692 */
1693/**
1694 * Returns `RNode`.
1695 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1696 */
1697function unwrapRNode(value) {
1698 while (Array.isArray(value)) {
1699 value = value[HOST];
1700 }
1701 return value;
1702}
1703/**
1704 * Returns `LView` or `null` if not found.
1705 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1706 */
1707function unwrapLView(value) {
1708 while (Array.isArray(value)) {
1709 // This check is same as `isLView()` but we don't call at as we don't want to call
1710 // `Array.isArray()` twice and give JITer more work for inlining.
1711 if (typeof value[TYPE] === 'object')
1712 return value;
1713 value = value[HOST];
1714 }
1715 return null;
1716}
1717/**
1718 * Returns `LContainer` or `null` if not found.
1719 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1720 */
1721function unwrapLContainer(value) {
1722 while (Array.isArray(value)) {
1723 // This check is same as `isLContainer()` but we don't call at as we don't want to call
1724 // `Array.isArray()` twice and give JITer more work for inlining.
1725 if (value[TYPE] === true)
1726 return value;
1727 value = value[HOST];
1728 }
1729 return null;
1730}
1731/**
1732 * Retrieves an element value from the provided `viewData`, by unwrapping
1733 * from any containers, component views, or style contexts.
1734 */
1735function getNativeByIndex(index, lView) {
1736 ngDevMode && assertIndexInRange(lView, index);
1737 ngDevMode && assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Expected to be past HEADER_OFFSET');
1738 return unwrapRNode(lView[index]);
1739}
1740/**
1741 * Retrieve an `RNode` for a given `TNode` and `LView`.
1742 *
1743 * This function guarantees in dev mode to retrieve a non-null `RNode`.
1744 *
1745 * @param tNode
1746 * @param lView
1747 */
1748function getNativeByTNode(tNode, lView) {
1749 ngDevMode && assertTNodeForLView(tNode, lView);
1750 ngDevMode && assertIndexInRange(lView, tNode.index);
1751 const node = unwrapRNode(lView[tNode.index]);
1752 ngDevMode && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
1753 return node;
1754}
1755/**
1756 * Retrieve an `RNode` or `null` for a given `TNode` and `LView`.
1757 *
1758 * Some `TNode`s don't have associated `RNode`s. For example `Projection`
1759 *
1760 * @param tNode
1761 * @param lView
1762 */
1763function getNativeByTNodeOrNull(tNode, lView) {
1764 const index = tNode === null ? -1 : tNode.index;
1765 if (index !== -1) {
1766 ngDevMode && assertTNodeForLView(tNode, lView);
1767 const node = unwrapRNode(lView[index]);
1768 ngDevMode && node !== null && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
1769 return node;
1770 }
1771 return null;
1772}
1773// fixme(misko): The return Type should be `TNode|null`
1774function getTNode(tView, index) {
1775 ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
1776 ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode');
1777 const tNode = tView.data[index];
1778 ngDevMode && tNode !== null && assertTNode(tNode);
1779 return tNode;
1780}
1781/** Retrieves a value from any `LView` or `TData`. */
1782function load(view, index) {
1783 ngDevMode && assertIndexInRange(view, index);
1784 return view[index];
1785}
1786function getComponentLViewByIndex(nodeIndex, hostView) {
1787 // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
1788 ngDevMode && assertIndexInRange(hostView, nodeIndex);
1789 const slotValue = hostView[nodeIndex];
1790 const lView = isLView(slotValue) ? slotValue : slotValue[HOST];
1791 return lView;
1792}
1793/** Checks whether a given view is in creation mode */
1794function isCreationMode(view) {
1795 return (view[FLAGS] & 4 /* LViewFlags.CreationMode */) === 4 /* LViewFlags.CreationMode */;
1796}
1797/**
1798 * Returns a boolean for whether the view is attached to the change detection tree.
1799 *
1800 * Note: This determines whether a view should be checked, not whether it's inserted
1801 * into a container. For that, you'll want `viewAttachedToContainer` below.
1802 */
1803function viewAttachedToChangeDetector(view) {
1804 return (view[FLAGS] & 64 /* LViewFlags.Attached */) === 64 /* LViewFlags.Attached */;
1805}
1806/** Returns a boolean for whether the view is attached to a container. */
1807function viewAttachedToContainer(view) {
1808 return isLContainer(view[PARENT]);
1809}
1810function getConstant(consts, index) {
1811 if (index === null || index === undefined)
1812 return null;
1813 ngDevMode && assertIndexInRange(consts, index);
1814 return consts[index];
1815}
1816/**
1817 * Resets the pre-order hook flags of the view.
1818 * @param lView the LView on which the flags are reset
1819 */
1820function resetPreOrderHookFlags(lView) {
1821 lView[PREORDER_HOOK_FLAGS] = 0;
1822}
1823/**
1824 * Updates the `TRANSPLANTED_VIEWS_TO_REFRESH` counter on the `LContainer` as well as the parents
1825 * whose
1826 * 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
1827 * or
1828 * 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
1829 */
1830function updateTransplantedViewCount(lContainer, amount) {
1831 lContainer[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
1832 let viewOrContainer = lContainer;
1833 let parent = lContainer[PARENT];
1834 while (parent !== null &&
1835 ((amount === 1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 1) ||
1836 (amount === -1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 0))) {
1837 parent[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
1838 viewOrContainer = parent;
1839 parent = parent[PARENT];
1840 }
1841}
1842
1843/**
1844 * @license
1845 * Copyright Google LLC All Rights Reserved.
1846 *
1847 * Use of this source code is governed by an MIT-style license that can be
1848 * found in the LICENSE file at https://angular.io/license
1849 */
1850const instructionState = {
1851 lFrame: createLFrame(null),
1852 bindingsEnabled: true,
1853};
1854/**
1855 * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
1856 *
1857 * Necessary to support ChangeDetectorRef.checkNoChanges().
1858 *
1859 * The `checkNoChanges` function is invoked only in ngDevMode=true and verifies that no unintended
1860 * changes exist in the change detector or its children.
1861 */
1862let _isInCheckNoChangesMode = false;
1863/**
1864 * Returns true if the instruction state stack is empty.
1865 *
1866 * Intended to be called from tests only (tree shaken otherwise).
1867 */
1868function specOnlyIsInstructionStateEmpty() {
1869 return instructionState.lFrame.parent === null;
1870}
1871function getElementDepthCount() {
1872 return instructionState.lFrame.elementDepthCount;
1873}
1874function increaseElementDepthCount() {
1875 instructionState.lFrame.elementDepthCount++;
1876}
1877function decreaseElementDepthCount() {
1878 instructionState.lFrame.elementDepthCount--;
1879}
1880function getBindingsEnabled() {
1881 return instructionState.bindingsEnabled;
1882}
1883/**
1884 * Enables directive matching on elements.
1885 *
1886 * * Example:
1887 * ```
1888 * <my-comp my-directive>
1889 * Should match component / directive.
1890 * </my-comp>
1891 * <div ngNonBindable>
1892 * <!-- ɵɵdisableBindings() -->
1893 * <my-comp my-directive>
1894 * Should not match component / directive because we are in ngNonBindable.
1895 * </my-comp>
1896 * <!-- ɵɵenableBindings() -->
1897 * </div>
1898 * ```
1899 *
1900 * @codeGenApi
1901 */
1902function ɵɵenableBindings() {
1903 instructionState.bindingsEnabled = true;
1904}
1905/**
1906 * Disables directive matching on element.
1907 *
1908 * * Example:
1909 * ```
1910 * <my-comp my-directive>
1911 * Should match component / directive.
1912 * </my-comp>
1913 * <div ngNonBindable>
1914 * <!-- ɵɵdisableBindings() -->
1915 * <my-comp my-directive>
1916 * Should not match component / directive because we are in ngNonBindable.
1917 * </my-comp>
1918 * <!-- ɵɵenableBindings() -->
1919 * </div>
1920 * ```
1921 *
1922 * @codeGenApi
1923 */
1924function ɵɵdisableBindings() {
1925 instructionState.bindingsEnabled = false;
1926}
1927/**
1928 * Return the current `LView`.
1929 */
1930function getLView() {
1931 return instructionState.lFrame.lView;
1932}
1933/**
1934 * Return the current `TView`.
1935 */
1936function getTView() {
1937 return instructionState.lFrame.tView;
1938}
1939/**
1940 * Restores `contextViewData` to the given OpaqueViewState instance.
1941 *
1942 * Used in conjunction with the getCurrentView() instruction to save a snapshot
1943 * of the current view and restore it when listeners are invoked. This allows
1944 * walking the declaration view tree in listeners to get vars from parent views.
1945 *
1946 * @param viewToRestore The OpaqueViewState instance to restore.
1947 * @returns Context of the restored OpaqueViewState instance.
1948 *
1949 * @codeGenApi
1950 */
1951function ɵɵrestoreView(viewToRestore) {
1952 instructionState.lFrame.contextLView = viewToRestore;
1953 return viewToRestore[CONTEXT];
1954}
1955/**
1956 * Clears the view set in `ɵɵrestoreView` from memory. Returns the passed in
1957 * value so that it can be used as a return value of an instruction.
1958 *
1959 * @codeGenApi
1960 */
1961function ɵɵresetView(value) {
1962 instructionState.lFrame.contextLView = null;
1963 return value;
1964}
1965function getCurrentTNode() {
1966 let currentTNode = getCurrentTNodePlaceholderOk();
1967 while (currentTNode !== null && currentTNode.type === 64 /* TNodeType.Placeholder */) {
1968 currentTNode = currentTNode.parent;
1969 }
1970 return currentTNode;
1971}
1972function getCurrentTNodePlaceholderOk() {
1973 return instructionState.lFrame.currentTNode;
1974}
1975function getCurrentParentTNode() {
1976 const lFrame = instructionState.lFrame;
1977 const currentTNode = lFrame.currentTNode;
1978 return lFrame.isParent ? currentTNode : currentTNode.parent;
1979}
1980function setCurrentTNode(tNode, isParent) {
1981 ngDevMode && tNode && assertTNodeForTView(tNode, instructionState.lFrame.tView);
1982 const lFrame = instructionState.lFrame;
1983 lFrame.currentTNode = tNode;
1984 lFrame.isParent = isParent;
1985}
1986function isCurrentTNodeParent() {
1987 return instructionState.lFrame.isParent;
1988}
1989function setCurrentTNodeAsNotParent() {
1990 instructionState.lFrame.isParent = false;
1991}
1992function setCurrentTNodeAsParent() {
1993 instructionState.lFrame.isParent = true;
1994}
1995function getContextLView() {
1996 const contextLView = instructionState.lFrame.contextLView;
1997 ngDevMode && assertDefined(contextLView, 'contextLView must be defined.');
1998 return contextLView;
1999}
2000function isInCheckNoChangesMode() {
2001 !ngDevMode && throwError('Must never be called in production mode');
2002 return _isInCheckNoChangesMode;
2003}
2004function setIsInCheckNoChangesMode(mode) {
2005 !ngDevMode && throwError('Must never be called in production mode');
2006 _isInCheckNoChangesMode = mode;
2007}
2008// top level variables should not be exported for performance reasons (PERF_NOTES.md)
2009function getBindingRoot() {
2010 const lFrame = instructionState.lFrame;
2011 let index = lFrame.bindingRootIndex;
2012 if (index === -1) {
2013 index = lFrame.bindingRootIndex = lFrame.tView.bindingStartIndex;
2014 }
2015 return index;
2016}
2017function getBindingIndex() {
2018 return instructionState.lFrame.bindingIndex;
2019}
2020function setBindingIndex(value) {
2021 return instructionState.lFrame.bindingIndex = value;
2022}
2023function nextBindingIndex() {
2024 return instructionState.lFrame.bindingIndex++;
2025}
2026function incrementBindingIndex(count) {
2027 const lFrame = instructionState.lFrame;
2028 const index = lFrame.bindingIndex;
2029 lFrame.bindingIndex = lFrame.bindingIndex + count;
2030 return index;
2031}
2032function isInI18nBlock() {
2033 return instructionState.lFrame.inI18n;
2034}
2035function setInI18nBlock(isInI18nBlock) {
2036 instructionState.lFrame.inI18n = isInI18nBlock;
2037}
2038/**
2039 * Set a new binding root index so that host template functions can execute.
2040 *
2041 * Bindings inside the host template are 0 index. But because we don't know ahead of time
2042 * how many host bindings we have we can't pre-compute them. For this reason they are all
2043 * 0 index and we just shift the root so that they match next available location in the LView.
2044 *
2045 * @param bindingRootIndex Root index for `hostBindings`
2046 * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive
2047 * whose `hostBindings` are being processed.
2048 */
2049function setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex) {
2050 const lFrame = instructionState.lFrame;
2051 lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex;
2052 setCurrentDirectiveIndex(currentDirectiveIndex);
2053}
2054/**
2055 * When host binding is executing this points to the directive index.
2056 * `TView.data[getCurrentDirectiveIndex()]` is `DirectiveDef`
2057 * `LView[getCurrentDirectiveIndex()]` is directive instance.
2058 */
2059function getCurrentDirectiveIndex() {
2060 return instructionState.lFrame.currentDirectiveIndex;
2061}
2062/**
2063 * Sets an index of a directive whose `hostBindings` are being processed.
2064 *
2065 * @param currentDirectiveIndex `TData` index where current directive instance can be found.
2066 */
2067function setCurrentDirectiveIndex(currentDirectiveIndex) {
2068 instructionState.lFrame.currentDirectiveIndex = currentDirectiveIndex;
2069}
2070/**
2071 * Retrieve the current `DirectiveDef` which is active when `hostBindings` instruction is being
2072 * executed.
2073 *
2074 * @param tData Current `TData` where the `DirectiveDef` will be looked up at.
2075 */
2076function getCurrentDirectiveDef(tData) {
2077 const currentDirectiveIndex = instructionState.lFrame.currentDirectiveIndex;
2078 return currentDirectiveIndex === -1 ? null : tData[currentDirectiveIndex];
2079}
2080function getCurrentQueryIndex() {
2081 return instructionState.lFrame.currentQueryIndex;
2082}
2083function setCurrentQueryIndex(value) {
2084 instructionState.lFrame.currentQueryIndex = value;
2085}
2086/**
2087 * Returns a `TNode` of the location where the current `LView` is declared at.
2088 *
2089 * @param lView an `LView` that we want to find parent `TNode` for.
2090 */
2091function getDeclarationTNode(lView) {
2092 const tView = lView[TVIEW];
2093 // Return the declaration parent for embedded views
2094 if (tView.type === 2 /* TViewType.Embedded */) {
2095 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
2096 return tView.declTNode;
2097 }
2098 // Components don't have `TView.declTNode` because each instance of component could be
2099 // inserted in different location, hence `TView.declTNode` is meaningless.
2100 // Falling back to `T_HOST` in case we cross component boundary.
2101 if (tView.type === 1 /* TViewType.Component */) {
2102 return lView[T_HOST];
2103 }
2104 // Remaining TNode type is `TViewType.Root` which doesn't have a parent TNode.
2105 return null;
2106}
2107/**
2108 * This is a light weight version of the `enterView` which is needed by the DI system.
2109 *
2110 * @param lView `LView` location of the DI context.
2111 * @param tNode `TNode` for DI context
2112 * @param flags DI context flags. if `SkipSelf` flag is set than we walk up the declaration
2113 * tree from `tNode` until we find parent declared `TElementNode`.
2114 * @returns `true` if we have successfully entered DI associated with `tNode` (or with declared
2115 * `TNode` if `flags` has `SkipSelf`). Failing to enter DI implies that no associated
2116 * `NodeInjector` can be found and we should instead use `ModuleInjector`.
2117 * - If `true` than this call must be fallowed by `leaveDI`
2118 * - If `false` than this call failed and we should NOT call `leaveDI`
2119 */
2120function enterDI(lView, tNode, flags) {
2121 ngDevMode && assertLViewOrUndefined(lView);
2122 if (flags & InjectFlags.SkipSelf) {
2123 ngDevMode && assertTNodeForTView(tNode, lView[TVIEW]);
2124 let parentTNode = tNode;
2125 let parentLView = lView;
2126 while (true) {
2127 ngDevMode && assertDefined(parentTNode, 'Parent TNode should be defined');
2128 parentTNode = parentTNode.parent;
2129 if (parentTNode === null && !(flags & InjectFlags.Host)) {
2130 parentTNode = getDeclarationTNode(parentLView);
2131 if (parentTNode === null)
2132 break;
2133 // In this case, a parent exists and is definitely an element. So it will definitely
2134 // have an existing lView as the declaration view, which is why we can assume it's defined.
2135 ngDevMode && assertDefined(parentLView, 'Parent LView should be defined');
2136 parentLView = parentLView[DECLARATION_VIEW];
2137 // In Ivy there are Comment nodes that correspond to ngIf and NgFor embedded directives
2138 // We want to skip those and look only at Elements and ElementContainers to ensure
2139 // we're looking at true parent nodes, and not content or other types.
2140 if (parentTNode.type & (2 /* TNodeType.Element */ | 8 /* TNodeType.ElementContainer */)) {
2141 break;
2142 }
2143 }
2144 else {
2145 break;
2146 }
2147 }
2148 if (parentTNode === null) {
2149 // If we failed to find a parent TNode this means that we should use module injector.
2150 return false;
2151 }
2152 else {
2153 tNode = parentTNode;
2154 lView = parentLView;
2155 }
2156 }
2157 ngDevMode && assertTNodeForLView(tNode, lView);
2158 const lFrame = instructionState.lFrame = allocLFrame();
2159 lFrame.currentTNode = tNode;
2160 lFrame.lView = lView;
2161 return true;
2162}
2163/**
2164 * Swap the current lView with a new lView.
2165 *
2166 * For performance reasons we store the lView in the top level of the module.
2167 * This way we minimize the number of properties to read. Whenever a new view
2168 * is entered we have to store the lView for later, and when the view is
2169 * exited the state has to be restored
2170 *
2171 * @param newView New lView to become active
2172 * @returns the previously active lView;
2173 */
2174function enterView(newView) {
2175 ngDevMode && assertNotEqual(newView[0], newView[1], '????');
2176 ngDevMode && assertLViewOrUndefined(newView);
2177 const newLFrame = allocLFrame();
2178 if (ngDevMode) {
2179 assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
2180 assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
2181 assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
2182 assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
2183 assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
2184 assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
2185 assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
2186 assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
2187 assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
2188 }
2189 const tView = newView[TVIEW];
2190 instructionState.lFrame = newLFrame;
2191 ngDevMode && tView.firstChild && assertTNodeForTView(tView.firstChild, tView);
2192 newLFrame.currentTNode = tView.firstChild;
2193 newLFrame.lView = newView;
2194 newLFrame.tView = tView;
2195 newLFrame.contextLView = newView;
2196 newLFrame.bindingIndex = tView.bindingStartIndex;
2197 newLFrame.inI18n = false;
2198}
2199/**
2200 * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure.
2201 */
2202function allocLFrame() {
2203 const currentLFrame = instructionState.lFrame;
2204 const childLFrame = currentLFrame === null ? null : currentLFrame.child;
2205 const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame;
2206 return newLFrame;
2207}
2208function createLFrame(parent) {
2209 const lFrame = {
2210 currentTNode: null,
2211 isParent: true,
2212 lView: null,
2213 tView: null,
2214 selectedIndex: -1,
2215 contextLView: null,
2216 elementDepthCount: 0,
2217 currentNamespace: null,
2218 currentDirectiveIndex: -1,
2219 bindingRootIndex: -1,
2220 bindingIndex: -1,
2221 currentQueryIndex: 0,
2222 parent: parent,
2223 child: null,
2224 inI18n: false,
2225 };
2226 parent !== null && (parent.child = lFrame); // link the new LFrame for reuse.
2227 return lFrame;
2228}
2229/**
2230 * A lightweight version of leave which is used with DI.
2231 *
2232 * This function only resets `currentTNode` and `LView` as those are the only properties
2233 * used with DI (`enterDI()`).
2234 *
2235 * NOTE: This function is reexported as `leaveDI`. However `leaveDI` has return type of `void` where
2236 * as `leaveViewLight` has `LFrame`. This is so that `leaveViewLight` can be used in `leaveView`.
2237 */
2238function leaveViewLight() {
2239 const oldLFrame = instructionState.lFrame;
2240 instructionState.lFrame = oldLFrame.parent;
2241 oldLFrame.currentTNode = null;
2242 oldLFrame.lView = null;
2243 return oldLFrame;
2244}
2245/**
2246 * This is a lightweight version of the `leaveView` which is needed by the DI system.
2247 *
2248 * NOTE: this function is an alias so that we can change the type of the function to have `void`
2249 * return type.
2250 */
2251const leaveDI = leaveViewLight;
2252/**
2253 * Leave the current `LView`
2254 *
2255 * This pops the `LFrame` with the associated `LView` from the stack.
2256 *
2257 * IMPORTANT: We must zero out the `LFrame` values here otherwise they will be retained. This is
2258 * because for performance reasons we don't release `LFrame` but rather keep it for next use.
2259 */
2260function leaveView() {
2261 const oldLFrame = leaveViewLight();
2262 oldLFrame.isParent = true;
2263 oldLFrame.tView = null;
2264 oldLFrame.selectedIndex = -1;
2265 oldLFrame.contextLView = null;
2266 oldLFrame.elementDepthCount = 0;
2267 oldLFrame.currentDirectiveIndex = -1;
2268 oldLFrame.currentNamespace = null;
2269 oldLFrame.bindingRootIndex = -1;
2270 oldLFrame.bindingIndex = -1;
2271 oldLFrame.currentQueryIndex = 0;
2272}
2273function nextContextImpl(level) {
2274 const contextLView = instructionState.lFrame.contextLView =
2275 walkUpViews(level, instructionState.lFrame.contextLView);
2276 return contextLView[CONTEXT];
2277}
2278function walkUpViews(nestingLevel, currentView) {
2279 while (nestingLevel > 0) {
2280 ngDevMode &&
2281 assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.');
2282 currentView = currentView[DECLARATION_VIEW];
2283 nestingLevel--;
2284 }
2285 return currentView;
2286}
2287/**
2288 * Gets the currently selected element index.
2289 *
2290 * Used with {@link property} instruction (and more in the future) to identify the index in the
2291 * current `LView` to act on.
2292 */
2293function getSelectedIndex() {
2294 return instructionState.lFrame.selectedIndex;
2295}
2296/**
2297 * Sets the most recent index passed to {@link select}
2298 *
2299 * Used with {@link property} instruction (and more in the future) to identify the index in the
2300 * current `LView` to act on.
2301 *
2302 * (Note that if an "exit function" was set earlier (via `setElementExitFn()`) then that will be
2303 * run if and when the provided `index` value is different from the current selected index value.)
2304 */
2305function setSelectedIndex(index) {
2306 ngDevMode && index !== -1 &&
2307 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
2308 ngDevMode &&
2309 assertLessThan(index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView');
2310 instructionState.lFrame.selectedIndex = index;
2311}
2312/**
2313 * Gets the `tNode` that represents currently selected element.
2314 */
2315function getSelectedTNode() {
2316 const lFrame = instructionState.lFrame;
2317 return getTNode(lFrame.tView, lFrame.selectedIndex);
2318}
2319/**
2320 * Sets the namespace used to create elements to `'http://www.w3.org/2000/svg'` in global state.
2321 *
2322 * @codeGenApi
2323 */
2324function ɵɵnamespaceSVG() {
2325 instructionState.lFrame.currentNamespace = SVG_NAMESPACE;
2326}
2327/**
2328 * Sets the namespace used to create elements to `'http://www.w3.org/1998/MathML/'` in global state.
2329 *
2330 * @codeGenApi
2331 */
2332function ɵɵnamespaceMathML() {
2333 instructionState.lFrame.currentNamespace = MATH_ML_NAMESPACE;
2334}
2335/**
2336 * Sets the namespace used to create elements to `null`, which forces element creation to use
2337 * `createElement` rather than `createElementNS`.
2338 *
2339 * @codeGenApi
2340 */
2341function ɵɵnamespaceHTML() {
2342 namespaceHTMLInternal();
2343}
2344/**
2345 * Sets the namespace used to create elements to `null`, which forces element creation to use
2346 * `createElement` rather than `createElementNS`.
2347 */
2348function namespaceHTMLInternal() {
2349 instructionState.lFrame.currentNamespace = null;
2350}
2351function getNamespace$1() {
2352 return instructionState.lFrame.currentNamespace;
2353}
2354
2355/**
2356 * @license
2357 * Copyright Google LLC All Rights Reserved.
2358 *
2359 * Use of this source code is governed by an MIT-style license that can be
2360 * found in the LICENSE file at https://angular.io/license
2361 */
2362/**
2363 * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`.
2364 *
2365 * Must be run *only* on the first template pass.
2366 *
2367 * Sets up the pre-order hooks on the provided `tView`,
2368 * see {@link HookData} for details about the data structure.
2369 *
2370 * @param directiveIndex The index of the directive in LView
2371 * @param directiveDef The definition containing the hooks to setup in tView
2372 * @param tView The current TView
2373 */
2374function registerPreOrderHooks(directiveIndex, directiveDef, tView) {
2375 ngDevMode && assertFirstCreatePass(tView);
2376 const { ngOnChanges, ngOnInit, ngDoCheck } = directiveDef.type.prototype;
2377 if (ngOnChanges) {
2378 const wrappedOnChanges = NgOnChangesFeatureImpl(directiveDef);
2379 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, wrappedOnChanges);
2380 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = []))
2381 .push(directiveIndex, wrappedOnChanges);
2382 }
2383 if (ngOnInit) {
2384 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(0 - directiveIndex, ngOnInit);
2385 }
2386 if (ngDoCheck) {
2387 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, ngDoCheck);
2388 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, ngDoCheck);
2389 }
2390}
2391/**
2392 *
2393 * Loops through the directives on the provided `tNode` and queues hooks to be
2394 * run that are not initialization hooks.
2395 *
2396 * Should be executed during `elementEnd()` and similar to
2397 * preserve hook execution order. Content, view, and destroy hooks for projected
2398 * components and directives must be called *before* their hosts.
2399 *
2400 * Sets up the content, view, and destroy hooks on the provided `tView`,
2401 * see {@link HookData} for details about the data structure.
2402 *
2403 * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up
2404 * separately at `elementStart`.
2405 *
2406 * @param tView The current TView
2407 * @param tNode The TNode whose directives are to be searched for hooks to queue
2408 */
2409function registerPostOrderHooks(tView, tNode) {
2410 ngDevMode && assertFirstCreatePass(tView);
2411 // It's necessary to loop through the directives at elementEnd() (rather than processing in
2412 // directiveCreate) so we can preserve the current hook order. Content, view, and destroy
2413 // hooks for projected components and directives must be called *before* their hosts.
2414 for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) {
2415 const directiveDef = tView.data[i];
2416 ngDevMode && assertDefined(directiveDef, 'Expecting DirectiveDef');
2417 const lifecycleHooks = directiveDef.type.prototype;
2418 const { ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked, ngOnDestroy } = lifecycleHooks;
2419 if (ngAfterContentInit) {
2420 (tView.contentHooks || (tView.contentHooks = [])).push(-i, ngAfterContentInit);
2421 }
2422 if (ngAfterContentChecked) {
2423 (tView.contentHooks || (tView.contentHooks = [])).push(i, ngAfterContentChecked);
2424 (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, ngAfterContentChecked);
2425 }
2426 if (ngAfterViewInit) {
2427 (tView.viewHooks || (tView.viewHooks = [])).push(-i, ngAfterViewInit);
2428 }
2429 if (ngAfterViewChecked) {
2430 (tView.viewHooks || (tView.viewHooks = [])).push(i, ngAfterViewChecked);
2431 (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, ngAfterViewChecked);
2432 }
2433 if (ngOnDestroy != null) {
2434 (tView.destroyHooks || (tView.destroyHooks = [])).push(i, ngOnDestroy);
2435 }
2436 }
2437}
2438/**
2439 * Executing hooks requires complex logic as we need to deal with 2 constraints.
2440 *
2441 * 1. Init hooks (ngOnInit, ngAfterContentInit, ngAfterViewInit) must all be executed once and only
2442 * once, across many change detection cycles. This must be true even if some hooks throw, or if
2443 * some recursively trigger a change detection cycle.
2444 * To solve that, it is required to track the state of the execution of these init hooks.
2445 * This is done by storing and maintaining flags in the view: the {@link InitPhaseState},
2446 * and the index within that phase. They can be seen as a cursor in the following structure:
2447 * [[onInit1, onInit2], [afterContentInit1], [afterViewInit1, afterViewInit2, afterViewInit3]]
2448 * They are are stored as flags in LView[FLAGS].
2449 *
2450 * 2. Pre-order hooks can be executed in batches, because of the select instruction.
2451 * To be able to pause and resume their execution, we also need some state about the hook's array
2452 * that is being processed:
2453 * - the index of the next hook to be executed
2454 * - the number of init hooks already found in the processed part of the array
2455 * They are are stored as flags in LView[PREORDER_HOOK_FLAGS].
2456 */
2457/**
2458 * Executes pre-order check hooks ( OnChanges, DoChanges) given a view where all the init hooks were
2459 * executed once. This is a light version of executeInitAndCheckPreOrderHooks where we can skip read
2460 * / write of the init-hooks related flags.
2461 * @param lView The LView where hooks are defined
2462 * @param hooks Hooks to be run
2463 * @param nodeIndex 3 cases depending on the value:
2464 * - undefined: all hooks from the array should be executed (post-order case)
2465 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2466 * flushing the remaining hooks)
2467 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2468 * case, when executing select(number))
2469 */
2470function executeCheckHooks(lView, hooks, nodeIndex) {
2471 callHooks(lView, hooks, 3 /* InitPhaseState.InitPhaseCompleted */, nodeIndex);
2472}
2473/**
2474 * Executes post-order init and check hooks (one of AfterContentInit, AfterContentChecked,
2475 * AfterViewInit, AfterViewChecked) given a view where there are pending init hooks to be executed.
2476 * @param lView The LView where hooks are defined
2477 * @param hooks Hooks to be run
2478 * @param initPhase A phase for which hooks should be run
2479 * @param nodeIndex 3 cases depending on the value:
2480 * - undefined: all hooks from the array should be executed (post-order case)
2481 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2482 * flushing the remaining hooks)
2483 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2484 * case, when executing select(number))
2485 */
2486function executeInitAndCheckHooks(lView, hooks, initPhase, nodeIndex) {
2487 ngDevMode &&
2488 assertNotEqual(initPhase, 3 /* InitPhaseState.InitPhaseCompleted */, 'Init pre-order hooks should not be called more than once');
2489 if ((lView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
2490 callHooks(lView, hooks, initPhase, nodeIndex);
2491 }
2492}
2493function incrementInitPhaseFlags(lView, initPhase) {
2494 ngDevMode &&
2495 assertNotEqual(initPhase, 3 /* InitPhaseState.InitPhaseCompleted */, 'Init hooks phase should not be incremented after all init hooks have been run.');
2496 let flags = lView[FLAGS];
2497 if ((flags & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
2498 flags &= 2047 /* LViewFlags.IndexWithinInitPhaseReset */;
2499 flags += 1 /* LViewFlags.InitPhaseStateIncrementer */;
2500 lView[FLAGS] = flags;
2501 }
2502}
2503/**
2504 * Calls lifecycle hooks with their contexts, skipping init hooks if it's not
2505 * the first LView pass
2506 *
2507 * @param currentView The current view
2508 * @param arr The array in which the hooks are found
2509 * @param initPhaseState the current state of the init phase
2510 * @param currentNodeIndex 3 cases depending on the value:
2511 * - undefined: all hooks from the array should be executed (post-order case)
2512 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2513 * flushing the remaining hooks)
2514 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2515 * case, when executing select(number))
2516 */
2517function callHooks(currentView, arr, initPhase, currentNodeIndex) {
2518 ngDevMode &&
2519 assertEqual(isInCheckNoChangesMode(), false, 'Hooks should never be run when in check no changes mode.');
2520 const startIndex = currentNodeIndex !== undefined ?
2521 (currentView[PREORDER_HOOK_FLAGS] & 65535 /* PreOrderHookFlags.IndexOfTheNextPreOrderHookMaskMask */) :
2522 0;
2523 const nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1;
2524 const max = arr.length - 1; // Stop the loop at length - 1, because we look for the hook at i + 1
2525 let lastNodeIndexFound = 0;
2526 for (let i = startIndex; i < max; i++) {
2527 const hook = arr[i + 1];
2528 if (typeof hook === 'number') {
2529 lastNodeIndexFound = arr[i];
2530 if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) {
2531 break;
2532 }
2533 }
2534 else {
2535 const isInitHook = arr[i] < 0;
2536 if (isInitHook)
2537 currentView[PREORDER_HOOK_FLAGS] += 65536 /* PreOrderHookFlags.NumberOfInitHooksCalledIncrementer */;
2538 if (lastNodeIndexFound < nodeIndexLimit || nodeIndexLimit == -1) {
2539 callHook(currentView, initPhase, arr, i);
2540 currentView[PREORDER_HOOK_FLAGS] =
2541 (currentView[PREORDER_HOOK_FLAGS] & 4294901760 /* PreOrderHookFlags.NumberOfInitHooksCalledMask */) + i +
2542 2;
2543 }
2544 i++;
2545 }
2546 }
2547}
2548/**
2549 * Execute one hook against the current `LView`.
2550 *
2551 * @param currentView The current view
2552 * @param initPhaseState the current state of the init phase
2553 * @param arr The array in which the hooks are found
2554 * @param i The current index within the hook data array
2555 */
2556function callHook(currentView, initPhase, arr, i) {
2557 const isInitHook = arr[i] < 0;
2558 const hook = arr[i + 1];
2559 const directiveIndex = isInitHook ? -arr[i] : arr[i];
2560 const directive = currentView[directiveIndex];
2561 if (isInitHook) {
2562 const indexWithintInitPhase = currentView[FLAGS] >> 11 /* LViewFlags.IndexWithinInitPhaseShift */;
2563 // The init phase state must be always checked here as it may have been recursively updated.
2564 if (indexWithintInitPhase <
2565 (currentView[PREORDER_HOOK_FLAGS] >> 16 /* PreOrderHookFlags.NumberOfInitHooksCalledShift */) &&
2566 (currentView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
2567 currentView[FLAGS] += 2048 /* LViewFlags.IndexWithinInitPhaseIncrementer */;
2568 profiler(4 /* ProfilerEvent.LifecycleHookStart */, directive, hook);
2569 try {
2570 hook.call(directive);
2571 }
2572 finally {
2573 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, directive, hook);
2574 }
2575 }
2576 }
2577 else {
2578 profiler(4 /* ProfilerEvent.LifecycleHookStart */, directive, hook);
2579 try {
2580 hook.call(directive);
2581 }
2582 finally {
2583 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, directive, hook);
2584 }
2585 }
2586}
2587
2588/**
2589 * @license
2590 * Copyright Google LLC All Rights Reserved.
2591 *
2592 * Use of this source code is governed by an MIT-style license that can be
2593 * found in the LICENSE file at https://angular.io/license
2594 */
2595const NO_PARENT_INJECTOR = -1;
2596/**
2597 * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in
2598 * `TView.data`. This allows us to store information about the current node's tokens (which
2599 * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
2600 * shared, so they live in `LView`).
2601 *
2602 * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter
2603 * determines whether a directive is available on the associated node or not. This prevents us
2604 * from searching the directives array at this level unless it's probable the directive is in it.
2605 *
2606 * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
2607 *
2608 * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed
2609 * using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
2610 * will differ based on where it is flattened into the main array, so it's not possible to know
2611 * the indices ahead of time and save their types here. The interfaces are still included here
2612 * for documentation purposes.
2613 *
2614 * export interface LInjector extends Array<any> {
2615 *
2616 * // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
2617 * [0]: number;
2618 *
2619 * // Cumulative bloom for directive IDs 32-63
2620 * [1]: number;
2621 *
2622 * // Cumulative bloom for directive IDs 64-95
2623 * [2]: number;
2624 *
2625 * // Cumulative bloom for directive IDs 96-127
2626 * [3]: number;
2627 *
2628 * // Cumulative bloom for directive IDs 128-159
2629 * [4]: number;
2630 *
2631 * // Cumulative bloom for directive IDs 160 - 191
2632 * [5]: number;
2633 *
2634 * // Cumulative bloom for directive IDs 192 - 223
2635 * [6]: number;
2636 *
2637 * // Cumulative bloom for directive IDs 224 - 255
2638 * [7]: number;
2639 *
2640 * // We need to store a reference to the injector's parent so DI can keep looking up
2641 * // the injector tree until it finds the dependency it's looking for.
2642 * [PARENT_INJECTOR]: number;
2643 * }
2644 *
2645 * export interface TInjector extends Array<any> {
2646 *
2647 * // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
2648 * [0]: number;
2649 *
2650 * // Shared node bloom for directive IDs 32-63
2651 * [1]: number;
2652 *
2653 * // Shared node bloom for directive IDs 64-95
2654 * [2]: number;
2655 *
2656 * // Shared node bloom for directive IDs 96-127
2657 * [3]: number;
2658 *
2659 * // Shared node bloom for directive IDs 128-159
2660 * [4]: number;
2661 *
2662 * // Shared node bloom for directive IDs 160 - 191
2663 * [5]: number;
2664 *
2665 * // Shared node bloom for directive IDs 192 - 223
2666 * [6]: number;
2667 *
2668 * // Shared node bloom for directive IDs 224 - 255
2669 * [7]: number;
2670 *
2671 * // Necessary to find directive indices for a particular node.
2672 * [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
2673 * }
2674 */
2675/**
2676 * Factory for creating instances of injectors in the NodeInjector.
2677 *
2678 * This factory is complicated by the fact that it can resolve `multi` factories as well.
2679 *
2680 * NOTE: Some of the fields are optional which means that this class has two hidden classes.
2681 * - One without `multi` support (most common)
2682 * - One with `multi` values, (rare).
2683 *
2684 * Since VMs can cache up to 4 inline hidden classes this is OK.
2685 *
2686 * - Single factory: Only `resolving` and `factory` is defined.
2687 * - `providers` factory: `componentProviders` is a number and `index = -1`.
2688 * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`.
2689 */
2690class NodeInjectorFactory {
2691 constructor(
2692 /**
2693 * Factory to invoke in order to create a new instance.
2694 */
2695 factory,
2696 /**
2697 * Set to `true` if the token is declared in `viewProviders` (or if it is component).
2698 */
2699 isViewProvider, injectImplementation) {
2700 this.factory = factory;
2701 /**
2702 * Marker set to true during factory invocation to see if we get into recursive loop.
2703 * Recursive loop causes an error to be displayed.
2704 */
2705 this.resolving = false;
2706 ngDevMode && assertDefined(factory, 'Factory not specified');
2707 ngDevMode && assertEqual(typeof factory, 'function', 'Expected factory function.');
2708 this.canSeeViewProviders = isViewProvider;
2709 this.injectImpl = injectImplementation;
2710 }
2711}
2712function isFactory(obj) {
2713 return obj instanceof NodeInjectorFactory;
2714}
2715// Note: This hack is necessary so we don't erroneously get a circular dependency
2716// failure based on types.
2717const unusedValueExportToPlacateAjd$5 = 1;
2718
2719/**
2720 * Converts `TNodeType` into human readable text.
2721 * Make sure this matches with `TNodeType`
2722 */
2723function toTNodeTypeAsString(tNodeType) {
2724 let text = '';
2725 (tNodeType & 1 /* TNodeType.Text */) && (text += '|Text');
2726 (tNodeType & 2 /* TNodeType.Element */) && (text += '|Element');
2727 (tNodeType & 4 /* TNodeType.Container */) && (text += '|Container');
2728 (tNodeType & 8 /* TNodeType.ElementContainer */) && (text += '|ElementContainer');
2729 (tNodeType & 16 /* TNodeType.Projection */) && (text += '|Projection');
2730 (tNodeType & 32 /* TNodeType.Icu */) && (text += '|IcuContainer');
2731 (tNodeType & 64 /* TNodeType.Placeholder */) && (text += '|Placeholder');
2732 return text.length > 0 ? text.substring(1) : text;
2733}
2734// Note: This hack is necessary so we don't erroneously get a circular dependency
2735// failure based on types.
2736const unusedValueExportToPlacateAjd$4 = 1;
2737/**
2738 * Returns `true` if the `TNode` has a directive which has `@Input()` for `class` binding.
2739 *
2740 * ```
2741 * <div my-dir [class]="exp"></div>
2742 * ```
2743 * and
2744 * ```
2745 * @Directive({
2746 * })
2747 * class MyDirective {
2748 * @Input()
2749 * class: string;
2750 * }
2751 * ```
2752 *
2753 * In the above case it is necessary to write the reconciled styling information into the
2754 * directive's input.
2755 *
2756 * @param tNode
2757 */
2758function hasClassInput(tNode) {
2759 return (tNode.flags & 16 /* TNodeFlags.hasClassInput */) !== 0;
2760}
2761/**
2762 * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
2763 *
2764 * ```
2765 * <div my-dir [style]="exp"></div>
2766 * ```
2767 * and
2768 * ```
2769 * @Directive({
2770 * })
2771 * class MyDirective {
2772 * @Input()
2773 * class: string;
2774 * }
2775 * ```
2776 *
2777 * In the above case it is necessary to write the reconciled styling information into the
2778 * directive's input.
2779 *
2780 * @param tNode
2781 */
2782function hasStyleInput(tNode) {
2783 return (tNode.flags & 32 /* TNodeFlags.hasStyleInput */) !== 0;
2784}
2785
2786/**
2787 * @license
2788 * Copyright Google LLC All Rights Reserved.
2789 *
2790 * Use of this source code is governed by an MIT-style license that can be
2791 * found in the LICENSE file at https://angular.io/license
2792 */
2793function assertTNodeType(tNode, expectedTypes, message) {
2794 assertDefined(tNode, 'should be called with a TNode');
2795 if ((tNode.type & expectedTypes) === 0) {
2796 throwError(message ||
2797 `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
2798 }
2799}
2800function assertPureTNodeType(type) {
2801 if (!(type === 2 /* TNodeType.Element */ || //
2802 type === 1 /* TNodeType.Text */ || //
2803 type === 4 /* TNodeType.Container */ || //
2804 type === 8 /* TNodeType.ElementContainer */ || //
2805 type === 32 /* TNodeType.Icu */ || //
2806 type === 16 /* TNodeType.Projection */ || //
2807 type === 64 /* TNodeType.Placeholder */)) {
2808 throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
2809 }
2810}
2811
2812/**
2813 * Assigns all attribute values to the provided element via the inferred renderer.
2814 *
2815 * This function accepts two forms of attribute entries:
2816 *
2817 * default: (key, value):
2818 * attrs = [key1, value1, key2, value2]
2819 *
2820 * namespaced: (NAMESPACE_MARKER, uri, name, value)
2821 * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
2822 *
2823 * The `attrs` array can contain a mix of both the default and namespaced entries.
2824 * The "default" values are set without a marker, but if the function comes across
2825 * a marker value then it will attempt to set a namespaced value. If the marker is
2826 * not of a namespaced value then the function will quit and return the index value
2827 * where it stopped during the iteration of the attrs array.
2828 *
2829 * See [AttributeMarker] to understand what the namespace marker value is.
2830 *
2831 * Note that this instruction does not support assigning style and class values to
2832 * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
2833 * are applied to an element.
2834 * @param renderer The renderer to be used
2835 * @param native The element that the attributes will be assigned to
2836 * @param attrs The attribute array of values that will be assigned to the element
2837 * @returns the index value that was last accessed in the attributes array
2838 */
2839function setUpAttributes(renderer, native, attrs) {
2840 const isProc = isProceduralRenderer(renderer);
2841 let i = 0;
2842 while (i < attrs.length) {
2843 const value = attrs[i];
2844 if (typeof value === 'number') {
2845 // only namespaces are supported. Other value types (such as style/class
2846 // entries) are not supported in this function.
2847 if (value !== 0 /* AttributeMarker.NamespaceURI */) {
2848 break;
2849 }
2850 // we just landed on the marker value ... therefore
2851 // we should skip to the next entry
2852 i++;
2853 const namespaceURI = attrs[i++];
2854 const attrName = attrs[i++];
2855 const attrVal = attrs[i++];
2856 ngDevMode && ngDevMode.rendererSetAttribute++;
2857 isProc ?
2858 renderer.setAttribute(native, attrName, attrVal, namespaceURI) :
2859 native.setAttributeNS(namespaceURI, attrName, attrVal);
2860 }
2861 else {
2862 // attrName is string;
2863 const attrName = value;
2864 const attrVal = attrs[++i];
2865 // Standard attributes
2866 ngDevMode && ngDevMode.rendererSetAttribute++;
2867 if (isAnimationProp(attrName)) {
2868 if (isProc) {
2869 renderer.setProperty(native, attrName, attrVal);
2870 }
2871 }
2872 else {
2873 isProc ?
2874 renderer.setAttribute(native, attrName, attrVal) :
2875 native.setAttribute(attrName, attrVal);
2876 }
2877 i++;
2878 }
2879 }
2880 // another piece of code may iterate over the same attributes array. Therefore
2881 // it may be helpful to return the exact spot where the attributes array exited
2882 // whether by running into an unsupported marker or if all the static values were
2883 // iterated over.
2884 return i;
2885}
2886/**
2887 * Test whether the given value is a marker that indicates that the following
2888 * attribute values in a `TAttributes` array are only the names of attributes,
2889 * and not name-value pairs.
2890 * @param marker The attribute marker to test.
2891 * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
2892 */
2893function isNameOnlyAttributeMarker(marker) {
2894 return marker === 3 /* AttributeMarker.Bindings */ || marker === 4 /* AttributeMarker.Template */ ||
2895 marker === 6 /* AttributeMarker.I18n */;
2896}
2897function isAnimationProp(name) {
2898 // Perf note: accessing charCodeAt to check for the first character of a string is faster as
2899 // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
2900 // charCodeAt doesn't allocate memory to return a substring.
2901 return name.charCodeAt(0) === 64 /* CharCode.AT_SIGN */;
2902}
2903/**
2904 * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
2905 *
2906 * This merge function keeps the order of attrs same.
2907 *
2908 * @param dst Location of where the merged `TAttributes` should end up.
2909 * @param src `TAttributes` which should be appended to `dst`
2910 */
2911function mergeHostAttrs(dst, src) {
2912 if (src === null || src.length === 0) {
2913 // do nothing
2914 }
2915 else if (dst === null || dst.length === 0) {
2916 // We have source, but dst is empty, just make a copy.
2917 dst = src.slice();
2918 }
2919 else {
2920 let srcMarker = -1 /* AttributeMarker.ImplicitAttributes */;
2921 for (let i = 0; i < src.length; i++) {
2922 const item = src[i];
2923 if (typeof item === 'number') {
2924 srcMarker = item;
2925 }
2926 else {
2927 if (srcMarker === 0 /* AttributeMarker.NamespaceURI */) {
2928 // Case where we need to consume `key1`, `key2`, `value` items.
2929 }
2930 else if (srcMarker === -1 /* AttributeMarker.ImplicitAttributes */ ||
2931 srcMarker === 2 /* AttributeMarker.Styles */) {
2932 // Case where we have to consume `key1` and `value` only.
2933 mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
2934 }
2935 else {
2936 // Case where we have to consume `key1` only.
2937 mergeHostAttribute(dst, srcMarker, item, null, null);
2938 }
2939 }
2940 }
2941 }
2942 return dst;
2943}
2944/**
2945 * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
2946 *
2947 * @param dst `TAttributes` to append to.
2948 * @param marker Region where the `key`/`value` should be added.
2949 * @param key1 Key to add to `TAttributes`
2950 * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
2951 * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
2952 */
2953function mergeHostAttribute(dst, marker, key1, key2, value) {
2954 let i = 0;
2955 // Assume that new markers will be inserted at the end.
2956 let markerInsertPosition = dst.length;
2957 // scan until correct type.
2958 if (marker === -1 /* AttributeMarker.ImplicitAttributes */) {
2959 markerInsertPosition = -1;
2960 }
2961 else {
2962 while (i < dst.length) {
2963 const dstValue = dst[i++];
2964 if (typeof dstValue === 'number') {
2965 if (dstValue === marker) {
2966 markerInsertPosition = -1;
2967 break;
2968 }
2969 else if (dstValue > marker) {
2970 // We need to save this as we want the markers to be inserted in specific order.
2971 markerInsertPosition = i - 1;
2972 break;
2973 }
2974 }
2975 }
2976 }
2977 // search until you find place of insertion
2978 while (i < dst.length) {
2979 const item = dst[i];
2980 if (typeof item === 'number') {
2981 // since `i` started as the index after the marker, we did not find it if we are at the next
2982 // marker
2983 break;
2984 }
2985 else if (item === key1) {
2986 // We already have same token
2987 if (key2 === null) {
2988 if (value !== null) {
2989 dst[i + 1] = value;
2990 }
2991 return;
2992 }
2993 else if (key2 === dst[i + 1]) {
2994 dst[i + 2] = value;
2995 return;
2996 }
2997 }
2998 // Increment counter.
2999 i++;
3000 if (key2 !== null)
3001 i++;
3002 if (value !== null)
3003 i++;
3004 }
3005 // insert at location.
3006 if (markerInsertPosition !== -1) {
3007 dst.splice(markerInsertPosition, 0, marker);
3008 i = markerInsertPosition + 1;
3009 }
3010 dst.splice(i++, 0, key1);
3011 if (key2 !== null) {
3012 dst.splice(i++, 0, key2);
3013 }
3014 if (value !== null) {
3015 dst.splice(i++, 0, value);
3016 }
3017}
3018
3019/**
3020 * @license
3021 * Copyright Google LLC All Rights Reserved.
3022 *
3023 * Use of this source code is governed by an MIT-style license that can be
3024 * found in the LICENSE file at https://angular.io/license
3025 */
3026/// Parent Injector Utils ///////////////////////////////////////////////////////////////
3027function hasParentInjector(parentLocation) {
3028 return parentLocation !== NO_PARENT_INJECTOR;
3029}
3030function getParentInjectorIndex(parentLocation) {
3031 ngDevMode && assertNumber(parentLocation, 'Number expected');
3032 ngDevMode && assertNotEqual(parentLocation, -1, 'Not a valid state.');
3033 const parentInjectorIndex = parentLocation & 32767 /* RelativeInjectorLocationFlags.InjectorIndexMask */;
3034 ngDevMode &&
3035 assertGreaterThan(parentInjectorIndex, HEADER_OFFSET, 'Parent injector must be pointing past HEADER_OFFSET.');
3036 return parentLocation & 32767 /* RelativeInjectorLocationFlags.InjectorIndexMask */;
3037}
3038function getParentInjectorViewOffset(parentLocation) {
3039 return parentLocation >> 16 /* RelativeInjectorLocationFlags.ViewOffsetShift */;
3040}
3041/**
3042 * Unwraps a parent injector location number to find the view offset from the current injector,
3043 * then walks up the declaration view tree until the view is found that contains the parent
3044 * injector.
3045 *
3046 * @param location The location of the parent injector, which contains the view offset
3047 * @param startView The LView instance from which to start walking up the view tree
3048 * @returns The LView instance that contains the parent injector
3049 */
3050function getParentInjectorView(location, startView) {
3051 let viewOffset = getParentInjectorViewOffset(location);
3052 let parentView = startView;
3053 // For most cases, the parent injector can be found on the host node (e.g. for component
3054 // or container), but we must keep the loop here to support the rarer case of deeply nested
3055 // <ng-template> tags or inline views, where the parent injector might live many views
3056 // above the child injector.
3057 while (viewOffset > 0) {
3058 parentView = parentView[DECLARATION_VIEW];
3059 viewOffset--;
3060 }
3061 return parentView;
3062}
3063
3064/**
3065 * @license
3066 * Copyright Google LLC All Rights Reserved.
3067 *
3068 * Use of this source code is governed by an MIT-style license that can be
3069 * found in the LICENSE file at https://angular.io/license
3070 */
3071/**
3072 * Defines if the call to `inject` should include `viewProviders` in its resolution.
3073 *
3074 * This is set to true when we try to instantiate a component. This value is reset in
3075 * `getNodeInjectable` to a value which matches the declaration location of the token about to be
3076 * instantiated. This is done so that if we are injecting a token which was declared outside of
3077 * `viewProviders` we don't accidentally pull `viewProviders` in.
3078 *
3079 * Example:
3080 *
3081 * ```
3082 * @Injectable()
3083 * class MyService {
3084 * constructor(public value: String) {}
3085 * }
3086 *
3087 * @Component({
3088 * providers: [
3089 * MyService,
3090 * {provide: String, value: 'providers' }
3091 * ]
3092 * viewProviders: [
3093 * {provide: String, value: 'viewProviders'}
3094 * ]
3095 * })
3096 * class MyComponent {
3097 * constructor(myService: MyService, value: String) {
3098 * // We expect that Component can see into `viewProviders`.
3099 * expect(value).toEqual('viewProviders');
3100 * // `MyService` was not declared in `viewProviders` hence it can't see it.
3101 * expect(myService.value).toEqual('providers');
3102 * }
3103 * }
3104 *
3105 * ```
3106 */
3107let includeViewProviders = true;
3108function setIncludeViewProviders(v) {
3109 const oldValue = includeViewProviders;
3110 includeViewProviders = v;
3111 return oldValue;
3112}
3113/**
3114 * The number of slots in each bloom filter (used by DI). The larger this number, the fewer
3115 * directives that will share slots, and thus, the fewer false positives when checking for
3116 * the existence of a directive.
3117 */
3118const BLOOM_SIZE = 256;
3119const BLOOM_MASK = BLOOM_SIZE - 1;
3120/**
3121 * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits,
3122 * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash
3123 * number.
3124 */
3125const BLOOM_BUCKET_BITS = 5;
3126/** Counter used to generate unique IDs for directives. */
3127let nextNgElementId = 0;
3128/** Value used when something wasn't found by an injector. */
3129const NOT_FOUND = {};
3130/**
3131 * Registers this directive as present in its node's injector by flipping the directive's
3132 * corresponding bit in the injector's bloom filter.
3133 *
3134 * @param injectorIndex The index of the node injector where this token should be registered
3135 * @param tView The TView for the injector's bloom filters
3136 * @param type The directive token to register
3137 */
3138function bloomAdd(injectorIndex, tView, type) {
3139 ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
3140 let id;
3141 if (typeof type === 'string') {
3142 id = type.charCodeAt(0) || 0;
3143 }
3144 else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
3145 id = type[NG_ELEMENT_ID];
3146 }
3147 // Set a unique ID on the directive type, so if something tries to inject the directive,
3148 // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
3149 if (id == null) {
3150 id = type[NG_ELEMENT_ID] = nextNgElementId++;
3151 }
3152 // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
3153 // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
3154 const bloomHash = id & BLOOM_MASK;
3155 // Create a mask that targets the specific bit associated with the directive.
3156 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
3157 // to bit positions 0 - 31 in a 32 bit integer.
3158 const mask = 1 << bloomHash;
3159 // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`.
3160 // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask
3161 // should be written to.
3162 tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask;
3163}
3164/**
3165 * Creates (or gets an existing) injector for a given element or container.
3166 *
3167 * @param tNode for which an injector should be retrieved / created.
3168 * @param lView View where the node is stored
3169 * @returns Node injector
3170 */
3171function getOrCreateNodeInjectorForNode(tNode, lView) {
3172 const existingInjectorIndex = getInjectorIndex(tNode, lView);
3173 if (existingInjectorIndex !== -1) {
3174 return existingInjectorIndex;
3175 }
3176 const tView = lView[TVIEW];
3177 if (tView.firstCreatePass) {
3178 tNode.injectorIndex = lView.length;
3179 insertBloom(tView.data, tNode); // foundation for node bloom
3180 insertBloom(lView, null); // foundation for cumulative bloom
3181 insertBloom(tView.blueprint, null);
3182 }
3183 const parentLoc = getParentInjectorLocation(tNode, lView);
3184 const injectorIndex = tNode.injectorIndex;
3185 // If a parent injector can't be found, its location is set to -1.
3186 // In that case, we don't need to set up a cumulative bloom
3187 if (hasParentInjector(parentLoc)) {
3188 const parentIndex = getParentInjectorIndex(parentLoc);
3189 const parentLView = getParentInjectorView(parentLoc, lView);
3190 const parentData = parentLView[TVIEW].data;
3191 // Creates a cumulative bloom filter that merges the parent's bloom filter
3192 // and its own cumulative bloom (which contains tokens for all ancestors)
3193 for (let i = 0; i < 8 /* NodeInjectorOffset.BLOOM_SIZE */; i++) {
3194 lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
3195 }
3196 }
3197 lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */] = parentLoc;
3198 return injectorIndex;
3199}
3200function insertBloom(arr, footer) {
3201 arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
3202}
3203function getInjectorIndex(tNode, lView) {
3204 if (tNode.injectorIndex === -1 ||
3205 // If the injector index is the same as its parent's injector index, then the index has been
3206 // copied down from the parent node. No injector has been created yet on this node.
3207 (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
3208 // After the first template pass, the injector index might exist but the parent values
3209 // might not have been calculated yet for this instance
3210 lView[tNode.injectorIndex + 8 /* NodeInjectorOffset.PARENT */] === null) {
3211 return -1;
3212 }
3213 else {
3214 ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
3215 return tNode.injectorIndex;
3216 }
3217}
3218/**
3219 * Finds the index of the parent injector, with a view offset if applicable. Used to set the
3220 * parent injector initially.
3221 *
3222 * @returns Returns a number that is the combination of the number of LViews that we have to go up
3223 * to find the LView containing the parent inject AND the index of the injector within that LView.
3224 */
3225function getParentInjectorLocation(tNode, lView) {
3226 if (tNode.parent && tNode.parent.injectorIndex !== -1) {
3227 // If we have a parent `TNode` and there is an injector associated with it we are done, because
3228 // the parent injector is within the current `LView`.
3229 return tNode.parent.injectorIndex; // ViewOffset is 0
3230 }
3231 // When parent injector location is computed it may be outside of the current view. (ie it could
3232 // be pointing to a declared parent location). This variable stores number of declaration parents
3233 // we need to walk up in order to find the parent injector location.
3234 let declarationViewOffset = 0;
3235 let parentTNode = null;
3236 let lViewCursor = lView;
3237 // The parent injector is not in the current `LView`. We will have to walk the declared parent
3238 // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
3239 // `NodeInjector`.
3240 while (lViewCursor !== null) {
3241 parentTNode = getTNodeFromLView(lViewCursor);
3242 if (parentTNode === null) {
3243 // If we have no parent, than we are done.
3244 return NO_PARENT_INJECTOR;
3245 }
3246 ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]);
3247 // Every iteration of the loop requires that we go to the declared parent.
3248 declarationViewOffset++;
3249 lViewCursor = lViewCursor[DECLARATION_VIEW];
3250 if (parentTNode.injectorIndex !== -1) {
3251 // We found a NodeInjector which points to something.
3252 return (parentTNode.injectorIndex |
3253 (declarationViewOffset << 16 /* RelativeInjectorLocationFlags.ViewOffsetShift */));
3254 }
3255 }
3256 return NO_PARENT_INJECTOR;
3257}
3258/**
3259 * Makes a type or an injection token public to the DI system by adding it to an
3260 * injector's bloom filter.
3261 *
3262 * @param di The node injector in which a directive will be added
3263 * @param token The type or the injection token to be made public
3264 */
3265function diPublicInInjector(injectorIndex, tView, token) {
3266 bloomAdd(injectorIndex, tView, token);
3267}
3268/**
3269 * Inject static attribute value into directive constructor.
3270 *
3271 * This method is used with `factory` functions which are generated as part of
3272 * `defineDirective` or `defineComponent`. The method retrieves the static value
3273 * of an attribute. (Dynamic attributes are not supported since they are not resolved
3274 * at the time of injection and can change over time.)
3275 *
3276 * # Example
3277 * Given:
3278 * ```
3279 * @Component(...)
3280 * class MyComponent {
3281 * constructor(@Attribute('title') title: string) { ... }
3282 * }
3283 * ```
3284 * When instantiated with
3285 * ```
3286 * <my-component title="Hello"></my-component>
3287 * ```
3288 *
3289 * Then factory method generated is:
3290 * ```
3291 * MyComponent.ɵcmp = defineComponent({
3292 * factory: () => new MyComponent(injectAttribute('title'))
3293 * ...
3294 * })
3295 * ```
3296 *
3297 * @publicApi
3298 */
3299function injectAttributeImpl(tNode, attrNameToInject) {
3300 ngDevMode && assertTNodeType(tNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */);
3301 ngDevMode && assertDefined(tNode, 'expecting tNode');
3302 if (attrNameToInject === 'class') {
3303 return tNode.classes;
3304 }
3305 if (attrNameToInject === 'style') {
3306 return tNode.styles;
3307 }
3308 const attrs = tNode.attrs;
3309 if (attrs) {
3310 const attrsLength = attrs.length;
3311 let i = 0;
3312 while (i < attrsLength) {
3313 const value = attrs[i];
3314 // If we hit a `Bindings` or `Template` marker then we are done.
3315 if (isNameOnlyAttributeMarker(value))
3316 break;
3317 // Skip namespaced attributes
3318 if (value === 0 /* AttributeMarker.NamespaceURI */) {
3319 // we skip the next two values
3320 // as namespaced attributes looks like
3321 // [..., AttributeMarker.NamespaceURI, 'http://someuri.com/test', 'test:exist',
3322 // 'existValue', ...]
3323 i = i + 2;
3324 }
3325 else if (typeof value === 'number') {
3326 // Skip to the first value of the marked attribute.
3327 i++;
3328 while (i < attrsLength && typeof attrs[i] === 'string') {
3329 i++;
3330 }
3331 }
3332 else if (value === attrNameToInject) {
3333 return attrs[i + 1];
3334 }
3335 else {
3336 i = i + 2;
3337 }
3338 }
3339 }
3340 return null;
3341}
3342function notFoundValueOrThrow(notFoundValue, token, flags) {
3343 if (flags & InjectFlags.Optional) {
3344 return notFoundValue;
3345 }
3346 else {
3347 throwProviderNotFoundError(token, 'NodeInjector');
3348 }
3349}
3350/**
3351 * Returns the value associated to the given token from the ModuleInjector or throws exception
3352 *
3353 * @param lView The `LView` that contains the `tNode`
3354 * @param token The token to look for
3355 * @param flags Injection flags
3356 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3357 * @returns the value from the injector or throws an exception
3358 */
3359function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) {
3360 if (flags & InjectFlags.Optional && notFoundValue === undefined) {
3361 // This must be set or the NullInjector will throw for optional deps
3362 notFoundValue = null;
3363 }
3364 if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
3365 const moduleInjector = lView[INJECTOR$1];
3366 // switch to `injectInjectorOnly` implementation for module injector, since module injector
3367 // should not have access to Component/Directive DI scope (that may happen through
3368 // `directiveInject` implementation)
3369 const previousInjectImplementation = setInjectImplementation(undefined);
3370 try {
3371 if (moduleInjector) {
3372 return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
3373 }
3374 else {
3375 return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
3376 }
3377 }
3378 finally {
3379 setInjectImplementation(previousInjectImplementation);
3380 }
3381 }
3382 return notFoundValueOrThrow(notFoundValue, token, flags);
3383}
3384/**
3385 * Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
3386 *
3387 * Look for the injector providing the token by walking up the node injector tree and then
3388 * the module injector tree.
3389 *
3390 * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom
3391 * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`)
3392 *
3393 * @param tNode The Node where the search for the injector should start
3394 * @param lView The `LView` that contains the `tNode`
3395 * @param token The token to look for
3396 * @param flags Injection flags
3397 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3398 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
3399 */
3400function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) {
3401 if (tNode !== null) {
3402 // If the view or any of its ancestors have an embedded
3403 // view injector, we have to look it up there first.
3404 if (lView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) {
3405 const embeddedInjectorValue = lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, NOT_FOUND);
3406 if (embeddedInjectorValue !== NOT_FOUND) {
3407 return embeddedInjectorValue;
3408 }
3409 }
3410 // Otherwise try the node injector.
3411 const value = lookupTokenUsingNodeInjector(tNode, lView, token, flags, NOT_FOUND);
3412 if (value !== NOT_FOUND) {
3413 return value;
3414 }
3415 }
3416 // Finally, fall back to the module injector.
3417 return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
3418}
3419/**
3420 * Returns the value associated to the given token from the node injector.
3421 *
3422 * @param tNode The Node where the search for the injector should start
3423 * @param lView The `LView` that contains the `tNode`
3424 * @param token The token to look for
3425 * @param flags Injection flags
3426 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3427 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
3428 */
3429function lookupTokenUsingNodeInjector(tNode, lView, token, flags, notFoundValue) {
3430 const bloomHash = bloomHashBitOrFactory(token);
3431 // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
3432 // so just call the factory function to create it.
3433 if (typeof bloomHash === 'function') {
3434 if (!enterDI(lView, tNode, flags)) {
3435 // Failed to enter DI, try module injector instead. If a token is injected with the @Host
3436 // flag, the module injector is not searched for that token in Ivy.
3437 return (flags & InjectFlags.Host) ?
3438 notFoundValueOrThrow(notFoundValue, token, flags) :
3439 lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
3440 }
3441 try {
3442 const value = bloomHash(flags);
3443 if (value == null && !(flags & InjectFlags.Optional)) {
3444 throwProviderNotFoundError(token);
3445 }
3446 else {
3447 return value;
3448 }
3449 }
3450 finally {
3451 leaveDI();
3452 }
3453 }
3454 else if (typeof bloomHash === 'number') {
3455 // A reference to the previous injector TView that was found while climbing the element
3456 // injector tree. This is used to know if viewProviders can be accessed on the current
3457 // injector.
3458 let previousTView = null;
3459 let injectorIndex = getInjectorIndex(tNode, lView);
3460 let parentLocation = NO_PARENT_INJECTOR;
3461 let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
3462 // If we should skip this injector, or if there is no injector on this node, start by
3463 // searching the parent injector.
3464 if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
3465 parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
3466 lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */];
3467 if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
3468 injectorIndex = -1;
3469 }
3470 else {
3471 previousTView = lView[TVIEW];
3472 injectorIndex = getParentInjectorIndex(parentLocation);
3473 lView = getParentInjectorView(parentLocation, lView);
3474 }
3475 }
3476 // Traverse up the injector tree until we find a potential match or until we know there
3477 // *isn't* a match.
3478 while (injectorIndex !== -1) {
3479 ngDevMode && assertNodeInjector(lView, injectorIndex);
3480 // Check the current injector. If it matches, see if it contains token.
3481 const tView = lView[TVIEW];
3482 ngDevMode &&
3483 assertTNodeForLView(tView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */], lView);
3484 if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
3485 // At this point, we have an injector which *may* contain the token, so we step through
3486 // the providers and directives associated with the injector's corresponding node to get
3487 // the instance.
3488 const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode);
3489 if (instance !== NOT_FOUND) {
3490 return instance;
3491 }
3492 }
3493 parentLocation = lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */];
3494 if (parentLocation !== NO_PARENT_INJECTOR &&
3495 shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */] === hostTElementNode) &&
3496 bloomHasToken(bloomHash, injectorIndex, lView)) {
3497 // The def wasn't found anywhere on this node, so it was a false positive.
3498 // Traverse up the tree and continue searching.
3499 previousTView = tView;
3500 injectorIndex = getParentInjectorIndex(parentLocation);
3501 lView = getParentInjectorView(parentLocation, lView);
3502 }
3503 else {
3504 // If we should not search parent OR If the ancestor bloom filter value does not have the
3505 // bit corresponding to the directive we can give up on traversing up to find the specific
3506 // injector.
3507 injectorIndex = -1;
3508 }
3509 }
3510 }
3511 return notFoundValue;
3512}
3513function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) {
3514 const currentTView = lView[TVIEW];
3515 const tNode = currentTView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
3516 // First, we need to determine if view providers can be accessed by the starting element.
3517 // There are two possibilities
3518 const canAccessViewProviders = previousTView == null ?
3519 // 1) This is the first invocation `previousTView == null` which means that we are at the
3520 // `TNode` of where injector is starting to look. In such a case the only time we are allowed
3521 // to look into the ViewProviders is if:
3522 // - we are on a component
3523 // - AND the injector set `includeViewProviders` to true (implying that the token can see
3524 // ViewProviders because it is the Component or a Service which itself was declared in
3525 // ViewProviders)
3526 (isComponentHost(tNode) && includeViewProviders) :
3527 // 2) `previousTView != null` which means that we are now walking across the parent nodes.
3528 // In such a case we are only allowed to look into the ViewProviders if:
3529 // - We just crossed from child View to Parent View `previousTView != currentTView`
3530 // - AND the parent TNode is an Element.
3531 // This means that we just came from the Component's View and therefore are allowed to see
3532 // into the ViewProviders.
3533 (previousTView != currentTView && ((tNode.type & 3 /* TNodeType.AnyRNode */) !== 0));
3534 // This special case happens when there is a @host on the inject and when we are searching
3535 // on the host element node.
3536 const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode;
3537 const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase);
3538 if (injectableIdx !== null) {
3539 return getNodeInjectable(lView, currentTView, injectableIdx, tNode);
3540 }
3541 else {
3542 return NOT_FOUND;
3543 }
3544}
3545/**
3546 * Searches for the given token among the node's directives and providers.
3547 *
3548 * @param tNode TNode on which directives are present.
3549 * @param tView The tView we are currently processing
3550 * @param token Provider token or type of a directive to look for.
3551 * @param canAccessViewProviders Whether view providers should be considered.
3552 * @param isHostSpecialCase Whether the host special case applies.
3553 * @returns Index of a found directive or provider, or null when none found.
3554 */
3555function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) {
3556 const nodeProviderIndexes = tNode.providerIndexes;
3557 const tInjectables = tView.data;
3558 const injectablesStart = nodeProviderIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */;
3559 const directivesStart = tNode.directiveStart;
3560 const directiveEnd = tNode.directiveEnd;
3561 const cptViewProvidersCount = nodeProviderIndexes >> 20 /* TNodeProviderIndexes.CptViewProvidersCountShift */;
3562 const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount;
3563 // When the host special case applies, only the viewProviders and the component are visible
3564 const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd;
3565 for (let i = startingIndex; i < endIndex; i++) {
3566 const providerTokenOrDef = tInjectables[i];
3567 if (i < directivesStart && token === providerTokenOrDef ||
3568 i >= directivesStart && providerTokenOrDef.type === token) {
3569 return i;
3570 }
3571 }
3572 if (isHostSpecialCase) {
3573 const dirDef = tInjectables[directivesStart];
3574 if (dirDef && isComponentDef(dirDef) && dirDef.type === token) {
3575 return directivesStart;
3576 }
3577 }
3578 return null;
3579}
3580/**
3581 * Retrieve or instantiate the injectable from the `LView` at particular `index`.
3582 *
3583 * This function checks to see if the value has already been instantiated and if so returns the
3584 * cached `injectable`. Otherwise if it detects that the value is still a factory it
3585 * instantiates the `injectable` and caches the value.
3586 */
3587function getNodeInjectable(lView, tView, index, tNode) {
3588 let value = lView[index];
3589 const tData = tView.data;
3590 if (isFactory(value)) {
3591 const factory = value;
3592 if (factory.resolving) {
3593 throwCyclicDependencyError(stringifyForError(tData[index]));
3594 }
3595 const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
3596 factory.resolving = true;
3597 const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
3598 const success = enterDI(lView, tNode, InjectFlags.Default);
3599 ngDevMode &&
3600 assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.');
3601 try {
3602 value = lView[index] = factory.factory(undefined, tData, lView, tNode);
3603 // This code path is hit for both directives and providers.
3604 // For perf reasons, we want to avoid searching for hooks on providers.
3605 // It does no harm to try (the hooks just won't exist), but the extra
3606 // checks are unnecessary and this is a hot path. So we check to see
3607 // if the index of the dependency is in the directive range for this
3608 // tNode. If it's not, we know it's a provider and skip hook registration.
3609 if (tView.firstCreatePass && index >= tNode.directiveStart) {
3610 ngDevMode && assertDirectiveDef(tData[index]);
3611 registerPreOrderHooks(index, tData[index], tView);
3612 }
3613 }
3614 finally {
3615 previousInjectImplementation !== null &&
3616 setInjectImplementation(previousInjectImplementation);
3617 setIncludeViewProviders(previousIncludeViewProviders);
3618 factory.resolving = false;
3619 leaveDI();
3620 }
3621 }
3622 return value;
3623}
3624/**
3625 * Returns the bit in an injector's bloom filter that should be used to determine whether or not
3626 * the directive might be provided by the injector.
3627 *
3628 * When a directive is public, it is added to the bloom filter and given a unique ID that can be
3629 * retrieved on the Type. When the directive isn't public or the token is not a directive `null`
3630 * is returned as the node injector can not possibly provide that token.
3631 *
3632 * @param token the injection token
3633 * @returns the matching bit to check in the bloom filter or `null` if the token is not known.
3634 * When the returned value is negative then it represents special values such as `Injector`.
3635 */
3636function bloomHashBitOrFactory(token) {
3637 ngDevMode && assertDefined(token, 'token must be defined');
3638 if (typeof token === 'string') {
3639 return token.charCodeAt(0) || 0;
3640 }
3641 const tokenId =
3642 // First check with `hasOwnProperty` so we don't get an inherited ID.
3643 token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined;
3644 // Negative token IDs are used for special objects such as `Injector`
3645 if (typeof tokenId === 'number') {
3646 if (tokenId >= 0) {
3647 return tokenId & BLOOM_MASK;
3648 }
3649 else {
3650 ngDevMode &&
3651 assertEqual(tokenId, -1 /* InjectorMarkers.Injector */, 'Expecting to get Special Injector Id');
3652 return createNodeInjector;
3653 }
3654 }
3655 else {
3656 return tokenId;
3657 }
3658}
3659function bloomHasToken(bloomHash, injectorIndex, injectorView) {
3660 // Create a mask that targets the specific bit associated with the directive we're looking for.
3661 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
3662 // to bit positions 0 - 31 in a 32 bit integer.
3663 const mask = 1 << bloomHash;
3664 // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of
3665 // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset
3666 // that should be used.
3667 const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)];
3668 // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
3669 // this injector is a potential match.
3670 return !!(value & mask);
3671}
3672/** Returns true if flags prevent parent injector from being searched for tokens */
3673function shouldSearchParent(flags, isFirstHostTNode) {
3674 return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode);
3675}
3676class NodeInjector {
3677 constructor(_tNode, _lView) {
3678 this._tNode = _tNode;
3679 this._lView = _lView;
3680 }
3681 get(token, notFoundValue, flags) {
3682 return getOrCreateInjectable(this._tNode, this._lView, token, flags, notFoundValue);
3683 }
3684}
3685/** Creates a `NodeInjector` for the current node. */
3686function createNodeInjector() {
3687 return new NodeInjector(getCurrentTNode(), getLView());
3688}
3689/**
3690 * @codeGenApi
3691 */
3692function ɵɵgetInheritedFactory(type) {
3693 return noSideEffects(() => {
3694 const ownConstructor = type.prototype.constructor;
3695 const ownFactory = ownConstructor[NG_FACTORY_DEF] || getFactoryOf(ownConstructor);
3696 const objectPrototype = Object.prototype;
3697 let parent = Object.getPrototypeOf(type.prototype).constructor;
3698 // Go up the prototype until we hit `Object`.
3699 while (parent && parent !== objectPrototype) {
3700 const factory = parent[NG_FACTORY_DEF] || getFactoryOf(parent);
3701 // If we hit something that has a factory and the factory isn't the same as the type,
3702 // we've found the inherited factory. Note the check that the factory isn't the type's
3703 // own factory is redundant in most cases, but if the user has custom decorators on the
3704 // class, this lookup will start one level down in the prototype chain, causing us to
3705 // find the own factory first and potentially triggering an infinite loop downstream.
3706 if (factory && factory !== ownFactory) {
3707 return factory;
3708 }
3709 parent = Object.getPrototypeOf(parent);
3710 }
3711 // There is no factory defined. Either this was improper usage of inheritance
3712 // (no Angular decorator on the superclass) or there is no constructor at all
3713 // in the inheritance chain. Since the two cases cannot be distinguished, the
3714 // latter has to be assumed.
3715 return t => new t();
3716 });
3717}
3718function getFactoryOf(type) {
3719 if (isForwardRef(type)) {
3720 return () => {
3721 const factory = getFactoryOf(resolveForwardRef(type));
3722 return factory && factory();
3723 };
3724 }
3725 return getFactoryDef(type);
3726}
3727/**
3728 * Returns a value from the closest embedded or node injector.
3729 *
3730 * @param tNode The Node where the search for the injector should start
3731 * @param lView The `LView` that contains the `tNode`
3732 * @param token The token to look for
3733 * @param flags Injection flags
3734 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3735 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
3736 */
3737function lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, notFoundValue) {
3738 let currentTNode = tNode;
3739 let currentLView = lView;
3740 // When an LView with an embedded view injector is inserted, it'll likely be interlaced with
3741 // nodes who may have injectors (e.g. node injector -> embedded view injector -> node injector).
3742 // Since the bloom filters for the node injectors have already been constructed and we don't
3743 // have a way of extracting the records from an injector, the only way to maintain the correct
3744 // hierarchy when resolving the value is to walk it node-by-node while attempting to resolve
3745 // the token at each level.
3746 while (currentTNode !== null && currentLView !== null &&
3747 (currentLView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) &&
3748 !(currentLView[FLAGS] & 256 /* LViewFlags.IsRoot */)) {
3749 ngDevMode && assertTNodeForLView(currentTNode, currentLView);
3750 // Note that this lookup on the node injector is using the `Self` flag, because
3751 // we don't want the node injector to look at any parent injectors since we
3752 // may hit the embedded view injector first.
3753 const nodeInjectorValue = lookupTokenUsingNodeInjector(currentTNode, currentLView, token, flags | InjectFlags.Self, NOT_FOUND);
3754 if (nodeInjectorValue !== NOT_FOUND) {
3755 return nodeInjectorValue;
3756 }
3757 // Has an explicit type due to a TS bug: https://github.com/microsoft/TypeScript/issues/33191
3758 let parentTNode = currentTNode.parent;
3759 // `TNode.parent` includes the parent within the current view only. If it doesn't exist,
3760 // it means that we've hit the view boundary and we need to go up to the next view.
3761 if (!parentTNode) {
3762 // Before we go to the next LView, check if the token exists on the current embedded injector.
3763 const embeddedViewInjector = currentLView[EMBEDDED_VIEW_INJECTOR];
3764 if (embeddedViewInjector) {
3765 const embeddedViewInjectorValue = embeddedViewInjector.get(token, NOT_FOUND, flags);
3766 if (embeddedViewInjectorValue !== NOT_FOUND) {
3767 return embeddedViewInjectorValue;
3768 }
3769 }
3770 // Otherwise keep going up the tree.
3771 parentTNode = getTNodeFromLView(currentLView);
3772 currentLView = currentLView[DECLARATION_VIEW];
3773 }
3774 currentTNode = parentTNode;
3775 }
3776 return notFoundValue;
3777}
3778/** Gets the TNode associated with an LView inside of the declaration view. */
3779function getTNodeFromLView(lView) {
3780 const tView = lView[TVIEW];
3781 const tViewType = tView.type;
3782 // The parent pointer differs based on `TView.type`.
3783 if (tViewType === 2 /* TViewType.Embedded */) {
3784 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
3785 return tView.declTNode;
3786 }
3787 else if (tViewType === 1 /* TViewType.Component */) {
3788 // Components don't have `TView.declTNode` because each instance of component could be
3789 // inserted in different location, hence `TView.declTNode` is meaningless.
3790 return lView[T_HOST];
3791 }
3792 return null;
3793}
3794
3795/**
3796 * @license
3797 * Copyright Google LLC All Rights Reserved.
3798 *
3799 * Use of this source code is governed by an MIT-style license that can be
3800 * found in the LICENSE file at https://angular.io/license
3801 */
3802/**
3803 * Facade for the attribute injection from DI.
3804 *
3805 * @codeGenApi
3806 */
3807function ɵɵinjectAttribute(attrNameToInject) {
3808 return injectAttributeImpl(getCurrentTNode(), attrNameToInject);
3809}
3810
3811/**
3812 * @license
3813 * Copyright Google LLC All Rights Reserved.
3814 *
3815 * Use of this source code is governed by an MIT-style license that can be
3816 * found in the LICENSE file at https://angular.io/license
3817 */
3818const ANNOTATIONS = '__annotations__';
3819const PARAMETERS = '__parameters__';
3820const PROP_METADATA = '__prop__metadata__';
3821/**
3822 * @suppress {globalThis}
3823 */
3824function makeDecorator(name, props, parentClass, additionalProcessing, typeFn) {
3825 return noSideEffects(() => {
3826 const metaCtor = makeMetadataCtor(props);
3827 function DecoratorFactory(...args) {
3828 if (this instanceof DecoratorFactory) {
3829 metaCtor.call(this, ...args);
3830 return this;
3831 }
3832 const annotationInstance = new DecoratorFactory(...args);
3833 return function TypeDecorator(cls) {
3834 if (typeFn)
3835 typeFn(cls, ...args);
3836 // Use of Object.defineProperty is important since it creates non-enumerable property which
3837 // prevents the property is copied during subclassing.
3838 const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
3839 cls[ANNOTATIONS] :
3840 Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
3841 annotations.push(annotationInstance);
3842 if (additionalProcessing)
3843 additionalProcessing(cls);
3844 return cls;
3845 };
3846 }
3847 if (parentClass) {
3848 DecoratorFactory.prototype = Object.create(parentClass.prototype);
3849 }
3850 DecoratorFactory.prototype.ngMetadataName = name;
3851 DecoratorFactory.annotationCls = DecoratorFactory;
3852 return DecoratorFactory;
3853 });
3854}
3855function makeMetadataCtor(props) {
3856 return function ctor(...args) {
3857 if (props) {
3858 const values = props(...args);
3859 for (const propName in values) {
3860 this[propName] = values[propName];
3861 }
3862 }
3863 };
3864}
3865function makeParamDecorator(name, props, parentClass) {
3866 return noSideEffects(() => {
3867 const metaCtor = makeMetadataCtor(props);
3868 function ParamDecoratorFactory(...args) {
3869 if (this instanceof ParamDecoratorFactory) {
3870 metaCtor.apply(this, args);
3871 return this;
3872 }
3873 const annotationInstance = new ParamDecoratorFactory(...args);
3874 ParamDecorator.annotation = annotationInstance;
3875 return ParamDecorator;
3876 function ParamDecorator(cls, unusedKey, index) {
3877 // Use of Object.defineProperty is important since it creates non-enumerable property which
3878 // prevents the property is copied during subclassing.
3879 const parameters = cls.hasOwnProperty(PARAMETERS) ?
3880 cls[PARAMETERS] :
3881 Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS];
3882 // there might be gaps if some in between parameters do not have annotations.
3883 // we pad with nulls.
3884 while (parameters.length <= index) {
3885 parameters.push(null);
3886 }
3887 (parameters[index] = parameters[index] || []).push(annotationInstance);
3888 return cls;
3889 }
3890 }
3891 if (parentClass) {
3892 ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
3893 }
3894 ParamDecoratorFactory.prototype.ngMetadataName = name;
3895 ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
3896 return ParamDecoratorFactory;
3897 });
3898}
3899function makePropDecorator(name, props, parentClass, additionalProcessing) {
3900 return noSideEffects(() => {
3901 const metaCtor = makeMetadataCtor(props);
3902 function PropDecoratorFactory(...args) {
3903 if (this instanceof PropDecoratorFactory) {
3904 metaCtor.apply(this, args);
3905 return this;
3906 }
3907 const decoratorInstance = new PropDecoratorFactory(...args);
3908 function PropDecorator(target, name) {
3909 const constructor = target.constructor;
3910 // Use of Object.defineProperty is important because it creates a non-enumerable property
3911 // which prevents the property from being copied during subclassing.
3912 const meta = constructor.hasOwnProperty(PROP_METADATA) ?
3913 constructor[PROP_METADATA] :
3914 Object.defineProperty(constructor, PROP_METADATA, { value: {} })[PROP_METADATA];
3915 meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
3916 meta[name].unshift(decoratorInstance);
3917 if (additionalProcessing)
3918 additionalProcessing(target, name, ...args);
3919 }
3920 return PropDecorator;
3921 }
3922 if (parentClass) {
3923 PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
3924 }
3925 PropDecoratorFactory.prototype.ngMetadataName = name;
3926 PropDecoratorFactory.annotationCls = PropDecoratorFactory;
3927 return PropDecoratorFactory;
3928 });
3929}
3930
3931/**
3932 * @license
3933 * Copyright Google LLC All Rights Reserved.
3934 *
3935 * Use of this source code is governed by an MIT-style license that can be
3936 * found in the LICENSE file at https://angular.io/license
3937 */
3938/**
3939 * Attribute decorator and metadata.
3940 *
3941 * @Annotation
3942 * @publicApi
3943 */
3944const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName) }));
3945
3946/**
3947 * @license
3948 * Copyright Google LLC All Rights Reserved.
3949 *
3950 * Use of this source code is governed by an MIT-style license that can be
3951 * found in the LICENSE file at https://angular.io/license
3952 */
3953/**
3954 * Creates a token that can be used in a DI Provider.
3955 *
3956 * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
3957 * runtime representation) such as when injecting an interface, callable type, array or
3958 * parameterized type.
3959 *
3960 * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
3961 * the `Injector`. This provides an additional level of type safety.
3962 *
3963 * ```
3964 * interface MyInterface {...}
3965 * const myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
3966 * // myInterface is inferred to be MyInterface.
3967 * ```
3968 *
3969 * When creating an `InjectionToken`, you can optionally specify a factory function which returns
3970 * (possibly by creating) a default value of the parameterized type `T`. This sets up the
3971 * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
3972 * application's root injector. If the factory function, which takes zero arguments, needs to inject
3973 * dependencies, it can do so using the `inject` function.
3974 * As you can see in the Tree-shakable InjectionToken example below.
3975 *
3976 * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
3977 * overrides the above behavior and marks the token as belonging to a particular `@NgModule`. As
3978 * mentioned above, `'root'` is the default value for `providedIn`.
3979 *
3980 * @usageNotes
3981 * ### Basic Examples
3982 *
3983 * ### Plain InjectionToken
3984 *
3985 * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
3986 *
3987 * ### Tree-shakable InjectionToken
3988 *
3989 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
3990 *
3991 *
3992 * @publicApi
3993 */
3994class InjectionToken {
3995 /**
3996 * @param _desc Description for the token,
3997 * used only for debugging purposes,
3998 * it should but does not need to be unique
3999 * @param options Options for the token's usage, as described above
4000 */
4001 constructor(_desc, options) {
4002 this._desc = _desc;
4003 /** @internal */
4004 this.ngMetadataName = 'InjectionToken';
4005 this.ɵprov = undefined;
4006 if (typeof options == 'number') {
4007 (typeof ngDevMode === 'undefined' || ngDevMode) &&
4008 assertLessThan(options, 0, 'Only negative numbers are supported here');
4009 // This is a special hack to assign __NG_ELEMENT_ID__ to this instance.
4010 // See `InjectorMarkers`
4011 this.__NG_ELEMENT_ID__ = options;
4012 }
4013 else if (options !== undefined) {
4014 this.ɵprov = ɵɵdefineInjectable({
4015 token: this,
4016 providedIn: options.providedIn || 'root',
4017 factory: options.factory,
4018 });
4019 }
4020 }
4021 /**
4022 * @internal
4023 */
4024 get multi() {
4025 return this;
4026 }
4027 toString() {
4028 return `InjectionToken ${this._desc}`;
4029 }
4030}
4031
4032/**
4033 * @license
4034 * Copyright Google LLC All Rights Reserved.
4035 *
4036 * Use of this source code is governed by an MIT-style license that can be
4037 * found in the LICENSE file at https://angular.io/license
4038 */
4039/**
4040 * A DI token that you can use to create a virtual [provider](guide/glossary#provider)
4041 * that will populate the `entryComponents` field of components and NgModules
4042 * based on its `useValue` property value.
4043 * All components that are referenced in the `useValue` value (either directly
4044 * or in a nested array or map) are added to the `entryComponents` property.
4045 *
4046 * @usageNotes
4047 *
4048 * The following example shows how the router can populate the `entryComponents`
4049 * field of an NgModule based on a router configuration that refers
4050 * to components.
4051 *
4052 * ```typescript
4053 * // helper function inside the router
4054 * function provideRoutes(routes) {
4055 * return [
4056 * {provide: ROUTES, useValue: routes},
4057 * {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: routes, multi: true}
4058 * ];
4059 * }
4060 *
4061 * // user code
4062 * let routes = [
4063 * {path: '/root', component: RootComp},
4064 * {path: '/teams', component: TeamsComp}
4065 * ];
4066 *
4067 * @NgModule({
4068 * providers: [provideRoutes(routes)]
4069 * })
4070 * class ModuleWithRoutes {}
4071 * ```
4072 *
4073 * @publicApi
4074 * @deprecated Since 9.0.0. With Ivy, this property is no longer necessary.
4075 */
4076const ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForEntryComponents');
4077// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
4078// explicitly set.
4079const emitDistinctChangesOnlyDefaultValue = true;
4080/**
4081 * Base class for query metadata.
4082 *
4083 * @see `ContentChildren`.
4084 * @see `ContentChild`.
4085 * @see `ViewChildren`.
4086 * @see `ViewChild`.
4087 *
4088 * @publicApi
4089 */
4090class Query {
4091}
4092/**
4093 * ContentChildren decorator and metadata.
4094 *
4095 *
4096 * @Annotation
4097 * @publicApi
4098 */
4099const ContentChildren = makePropDecorator('ContentChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)), Query);
4100/**
4101 * ContentChild decorator and metadata.
4102 *
4103 *
4104 * @Annotation
4105 *
4106 * @publicApi
4107 */
4108const ContentChild = makePropDecorator('ContentChild', (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data)), Query);
4109/**
4110 * ViewChildren decorator and metadata.
4111 *
4112 * @Annotation
4113 * @publicApi
4114 */
4115const ViewChildren = makePropDecorator('ViewChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)), Query);
4116/**
4117 * ViewChild decorator and metadata.
4118 *
4119 * @Annotation
4120 * @publicApi
4121 */
4122const ViewChild = makePropDecorator('ViewChild', (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data)), Query);
4123
4124/**
4125 * @license
4126 * Copyright Google LLC All Rights Reserved.
4127 *
4128 * Use of this source code is governed by an MIT-style license that can be
4129 * found in the LICENSE file at https://angular.io/license
4130 */
4131var FactoryTarget;
4132(function (FactoryTarget) {
4133 FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
4134 FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
4135 FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
4136 FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
4137 FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
4138})(FactoryTarget || (FactoryTarget = {}));
4139var R3TemplateDependencyKind;
4140(function (R3TemplateDependencyKind) {
4141 R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive";
4142 R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe";
4143 R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule";
4144})(R3TemplateDependencyKind || (R3TemplateDependencyKind = {}));
4145var ViewEncapsulation;
4146(function (ViewEncapsulation) {
4147 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
4148 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
4149 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
4150 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
4151})(ViewEncapsulation || (ViewEncapsulation = {}));
4152
4153/**
4154 * @license
4155 * Copyright Google LLC All Rights Reserved.
4156 *
4157 * Use of this source code is governed by an MIT-style license that can be
4158 * found in the LICENSE file at https://angular.io/license
4159 */
4160function getCompilerFacade(request) {
4161 const globalNg = _global['ng'];
4162 if (globalNg && globalNg.ɵcompilerFacade) {
4163 return globalNg.ɵcompilerFacade;
4164 }
4165 if (typeof ngDevMode === 'undefined' || ngDevMode) {
4166 // Log the type as an error so that a developer can easily navigate to the type from the
4167 // console.
4168 console.error(`JIT compilation failed for ${request.kind}`, request.type);
4169 let message = `The ${request.kind} '${request
4170 .type.name}' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.\n\n`;
4171 if (request.usage === 1 /* JitCompilerUsage.PartialDeclaration */) {
4172 message += `The ${request.kind} is part of a library that has been partially compiled.\n`;
4173 message +=
4174 `However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.\n`;
4175 message += '\n';
4176 message +=
4177 `Ideally, the library is processed using the Angular Linker to become fully AOT compiled.\n`;
4178 }
4179 else {
4180 message +=
4181 `JIT compilation is discouraged for production use-cases! Consider using AOT mode instead.\n`;
4182 }
4183 message +=
4184 `Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',\n`;
4185 message +=
4186 `or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`;
4187 throw new Error(message);
4188 }
4189 else {
4190 throw new Error('JIT compiler unavailable');
4191 }
4192}
4193
4194/**
4195 * @license
4196 * Copyright Google LLC All Rights Reserved.
4197 *
4198 * Use of this source code is governed by an MIT-style license that can be
4199 * found in the LICENSE file at https://angular.io/license
4200 */
4201/**
4202 * @description
4203 *
4204 * Represents a type that a Component or other object is instances of.
4205 *
4206 * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is represented by
4207 * the `MyCustomComponent` constructor function.
4208 *
4209 * @publicApi
4210 */
4211const Type = Function;
4212function isType(v) {
4213 return typeof v === 'function';
4214}
4215
4216/**
4217 * @license
4218 * Copyright Google LLC All Rights Reserved.
4219 *
4220 * Use of this source code is governed by an MIT-style license that can be
4221 * found in the LICENSE file at https://angular.io/license
4222 */
4223/**
4224 * Equivalent to ES6 spread, add each item to an array.
4225 *
4226 * @param items The items to add
4227 * @param arr The array to which you want to add the items
4228 */
4229function addAllToArray(items, arr) {
4230 for (let i = 0; i < items.length; i++) {
4231 arr.push(items[i]);
4232 }
4233}
4234/**
4235 * Determines if the contents of two arrays is identical
4236 *
4237 * @param a first array
4238 * @param b second array
4239 * @param identityAccessor Optional function for extracting stable object identity from a value in
4240 * the array.
4241 */
4242function arrayEquals(a, b, identityAccessor) {
4243 if (a.length !== b.length)
4244 return false;
4245 for (let i = 0; i < a.length; i++) {
4246 let valueA = a[i];
4247 let valueB = b[i];
4248 if (identityAccessor) {
4249 valueA = identityAccessor(valueA);
4250 valueB = identityAccessor(valueB);
4251 }
4252 if (valueB !== valueA) {
4253 return false;
4254 }
4255 }
4256 return true;
4257}
4258/**
4259 * Flattens an array.
4260 */
4261function flatten(list, dst) {
4262 if (dst === undefined)
4263 dst = list;
4264 for (let i = 0; i < list.length; i++) {
4265 let item = list[i];
4266 if (Array.isArray(item)) {
4267 // we need to inline it.
4268 if (dst === list) {
4269 // Our assumption that the list was already flat was wrong and
4270 // we need to clone flat since we need to write to it.
4271 dst = list.slice(0, i);
4272 }
4273 flatten(item, dst);
4274 }
4275 else if (dst !== list) {
4276 dst.push(item);
4277 }
4278 }
4279 return dst;
4280}
4281function deepForEach(input, fn) {
4282 input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value));
4283}
4284function addToArray(arr, index, value) {
4285 // perf: array.push is faster than array.splice!
4286 if (index >= arr.length) {
4287 arr.push(value);
4288 }
4289 else {
4290 arr.splice(index, 0, value);
4291 }
4292}
4293function removeFromArray(arr, index) {
4294 // perf: array.pop is faster than array.splice!
4295 if (index >= arr.length - 1) {
4296 return arr.pop();
4297 }
4298 else {
4299 return arr.splice(index, 1)[0];
4300 }
4301}
4302function newArray(size, value) {
4303 const list = [];
4304 for (let i = 0; i < size; i++) {
4305 list.push(value);
4306 }
4307 return list;
4308}
4309/**
4310 * Remove item from array (Same as `Array.splice()` but faster.)
4311 *
4312 * `Array.splice()` is not as fast because it has to allocate an array for the elements which were
4313 * removed. This causes memory pressure and slows down code when most of the time we don't
4314 * care about the deleted items array.
4315 *
4316 * https://jsperf.com/fast-array-splice (About 20x faster)
4317 *
4318 * @param array Array to splice
4319 * @param index Index of element in array to remove.
4320 * @param count Number of items to remove.
4321 */
4322function arraySplice(array, index, count) {
4323 const length = array.length - count;
4324 while (index < length) {
4325 array[index] = array[index + count];
4326 index++;
4327 }
4328 while (count--) {
4329 array.pop(); // shrink the array
4330 }
4331}
4332/**
4333 * Same as `Array.splice(index, 0, value)` but faster.
4334 *
4335 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
4336 * removed. This causes memory pressure and slows down code when most of the time we don't
4337 * care about the deleted items array.
4338 *
4339 * @param array Array to splice.
4340 * @param index Index in array where the `value` should be added.
4341 * @param value Value to add to array.
4342 */
4343function arrayInsert(array, index, value) {
4344 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
4345 let end = array.length;
4346 while (end > index) {
4347 const previousEnd = end - 1;
4348 array[end] = array[previousEnd];
4349 end = previousEnd;
4350 }
4351 array[index] = value;
4352}
4353/**
4354 * Same as `Array.splice2(index, 0, value1, value2)` but faster.
4355 *
4356 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
4357 * removed. This causes memory pressure and slows down code when most of the time we don't
4358 * care about the deleted items array.
4359 *
4360 * @param array Array to splice.
4361 * @param index Index in array where the `value` should be added.
4362 * @param value1 Value to add to array.
4363 * @param value2 Value to add to array.
4364 */
4365function arrayInsert2(array, index, value1, value2) {
4366 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
4367 let end = array.length;
4368 if (end == index) {
4369 // inserting at the end.
4370 array.push(value1, value2);
4371 }
4372 else if (end === 1) {
4373 // corner case when we have less items in array than we have items to insert.
4374 array.push(value2, array[0]);
4375 array[0] = value1;
4376 }
4377 else {
4378 end--;
4379 array.push(array[end - 1], array[end]);
4380 while (end > index) {
4381 const previousEnd = end - 2;
4382 array[end] = array[previousEnd];
4383 end--;
4384 }
4385 array[index] = value1;
4386 array[index + 1] = value2;
4387 }
4388}
4389/**
4390 * Insert a `value` into an `array` so that the array remains sorted.
4391 *
4392 * NOTE:
4393 * - Duplicates are not allowed, and are ignored.
4394 * - This uses binary search algorithm for fast inserts.
4395 *
4396 * @param array A sorted array to insert into.
4397 * @param value The value to insert.
4398 * @returns index of the inserted value.
4399 */
4400function arrayInsertSorted(array, value) {
4401 let index = arrayIndexOfSorted(array, value);
4402 if (index < 0) {
4403 // if we did not find it insert it.
4404 index = ~index;
4405 arrayInsert(array, index, value);
4406 }
4407 return index;
4408}
4409/**
4410 * Remove `value` from a sorted `array`.
4411 *
4412 * NOTE:
4413 * - This uses binary search algorithm for fast removals.
4414 *
4415 * @param array A sorted array to remove from.
4416 * @param value The value to remove.
4417 * @returns index of the removed value.
4418 * - positive index if value found and removed.
4419 * - negative index if value not found. (`~index` to get the value where it should have been
4420 * inserted)
4421 */
4422function arrayRemoveSorted(array, value) {
4423 const index = arrayIndexOfSorted(array, value);
4424 if (index >= 0) {
4425 arraySplice(array, index, 1);
4426 }
4427 return index;
4428}
4429/**
4430 * Get an index of an `value` in a sorted `array`.
4431 *
4432 * NOTE:
4433 * - This uses binary search algorithm for fast removals.
4434 *
4435 * @param array A sorted array to binary search.
4436 * @param value The value to look for.
4437 * @returns index of the value.
4438 * - positive index if value found.
4439 * - negative index if value not found. (`~index` to get the value where it should have been
4440 * located)
4441 */
4442function arrayIndexOfSorted(array, value) {
4443 return _arrayIndexOfSorted(array, value, 0);
4444}
4445/**
4446 * Set a `value` for a `key`.
4447 *
4448 * @param keyValueArray to modify.
4449 * @param key The key to locate or create.
4450 * @param value The value to set for a `key`.
4451 * @returns index (always even) of where the value vas set.
4452 */
4453function keyValueArraySet(keyValueArray, key, value) {
4454 let index = keyValueArrayIndexOf(keyValueArray, key);
4455 if (index >= 0) {
4456 // if we found it set it.
4457 keyValueArray[index | 1] = value;
4458 }
4459 else {
4460 index = ~index;
4461 arrayInsert2(keyValueArray, index, key, value);
4462 }
4463 return index;
4464}
4465/**
4466 * Retrieve a `value` for a `key` (on `undefined` if not found.)
4467 *
4468 * @param keyValueArray to search.
4469 * @param key The key to locate.
4470 * @return The `value` stored at the `key` location or `undefined if not found.
4471 */
4472function keyValueArrayGet(keyValueArray, key) {
4473 const index = keyValueArrayIndexOf(keyValueArray, key);
4474 if (index >= 0) {
4475 // if we found it retrieve it.
4476 return keyValueArray[index | 1];
4477 }
4478 return undefined;
4479}
4480/**
4481 * Retrieve a `key` index value in the array or `-1` if not found.
4482 *
4483 * @param keyValueArray to search.
4484 * @param key The key to locate.
4485 * @returns index of where the key is (or should have been.)
4486 * - positive (even) index if key found.
4487 * - negative index if key not found. (`~index` (even) to get the index where it should have
4488 * been inserted.)
4489 */
4490function keyValueArrayIndexOf(keyValueArray, key) {
4491 return _arrayIndexOfSorted(keyValueArray, key, 1);
4492}
4493/**
4494 * Delete a `key` (and `value`) from the `KeyValueArray`.
4495 *
4496 * @param keyValueArray to modify.
4497 * @param key The key to locate or delete (if exist).
4498 * @returns index of where the key was (or should have been.)
4499 * - positive (even) index if key found and deleted.
4500 * - negative index if key not found. (`~index` (even) to get the index where it should have
4501 * been.)
4502 */
4503function keyValueArrayDelete(keyValueArray, key) {
4504 const index = keyValueArrayIndexOf(keyValueArray, key);
4505 if (index >= 0) {
4506 // if we found it remove it.
4507 arraySplice(keyValueArray, index, 2);
4508 }
4509 return index;
4510}
4511/**
4512 * INTERNAL: Get an index of an `value` in a sorted `array` by grouping search by `shift`.
4513 *
4514 * NOTE:
4515 * - This uses binary search algorithm for fast removals.
4516 *
4517 * @param array A sorted array to binary search.
4518 * @param value The value to look for.
4519 * @param shift grouping shift.
4520 * - `0` means look at every location
4521 * - `1` means only look at every other (even) location (the odd locations are to be ignored as
4522 * they are values.)
4523 * @returns index of the value.
4524 * - positive index if value found.
4525 * - negative index if value not found. (`~index` to get the value where it should have been
4526 * inserted)
4527 */
4528function _arrayIndexOfSorted(array, value, shift) {
4529 ngDevMode && assertEqual(Array.isArray(array), true, 'Expecting an array');
4530 let start = 0;
4531 let end = array.length >> shift;
4532 while (end !== start) {
4533 const middle = start + ((end - start) >> 1); // find the middle.
4534 const current = array[middle << shift];
4535 if (value === current) {
4536 return (middle << shift);
4537 }
4538 else if (current > value) {
4539 end = middle;
4540 }
4541 else {
4542 start = middle + 1; // We already searched middle so make it non-inclusive by adding 1
4543 }
4544 }
4545 return ~(end << shift);
4546}
4547
4548/**
4549 * @license
4550 * Copyright Google LLC All Rights Reserved.
4551 *
4552 * Use of this source code is governed by an MIT-style license that can be
4553 * found in the LICENSE file at https://angular.io/license
4554 */
4555/*
4556 * #########################
4557 * Attention: These Regular expressions have to hold even if the code is minified!
4558 * ##########################
4559 */
4560/**
4561 * Regular expression that detects pass-through constructors for ES5 output. This Regex
4562 * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
4563 * it intends to capture the pattern where existing constructors have been downleveled from
4564 * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
4565 *
4566 * ```
4567 * function MyClass() {
4568 * var _this = _super.apply(this, arguments) || this;
4569 * ```
4570 *
4571 * downleveled to ES5 with `downlevelIteration` for TypeScript < 4.2:
4572 * ```
4573 * function MyClass() {
4574 * var _this = _super.apply(this, __spread(arguments)) || this;
4575 * ```
4576 *
4577 * or downleveled to ES5 with `downlevelIteration` for TypeScript >= 4.2:
4578 * ```
4579 * function MyClass() {
4580 * var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
4581 * ```
4582 *
4583 * More details can be found in: https://github.com/angular/angular/issues/38453.
4584 */
4585const ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|(?:[^()]+\(\[\],)?[^()]+\(arguments\).*)\)/;
4586/** Regular expression that detects ES2015 classes which extend from other classes. */
4587const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
4588/**
4589 * Regular expression that detects ES2015 classes which extend from other classes and
4590 * have an explicit constructor defined.
4591 */
4592const ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
4593/**
4594 * Regular expression that detects ES2015 classes which extend from other classes
4595 * and inherit a constructor.
4596 */
4597const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{[^}]*super\(\.\.\.arguments\)/;
4598/**
4599 * Determine whether a stringified type is a class which delegates its constructor
4600 * to its parent.
4601 *
4602 * This is not trivial since compiled code can actually contain a constructor function
4603 * even if the original source code did not. For instance, when the child class contains
4604 * an initialized instance property.
4605 */
4606function isDelegateCtor(typeStr) {
4607 return ES5_DELEGATE_CTOR.test(typeStr) ||
4608 ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
4609 (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
4610}
4611class ReflectionCapabilities {
4612 constructor(reflect) {
4613 this._reflect = reflect || _global['Reflect'];
4614 }
4615 factory(t) {
4616 return (...args) => new t(...args);
4617 }
4618 /** @internal */
4619 _zipTypesAndAnnotations(paramTypes, paramAnnotations) {
4620 let result;
4621 if (typeof paramTypes === 'undefined') {
4622 result = newArray(paramAnnotations.length);
4623 }
4624 else {
4625 result = newArray(paramTypes.length);
4626 }
4627 for (let i = 0; i < result.length; i++) {
4628 // TS outputs Object for parameters without types, while Traceur omits
4629 // the annotations. For now we preserve the Traceur behavior to aid
4630 // migration, but this can be revisited.
4631 if (typeof paramTypes === 'undefined') {
4632 result[i] = [];
4633 }
4634 else if (paramTypes[i] && paramTypes[i] != Object) {
4635 result[i] = [paramTypes[i]];
4636 }
4637 else {
4638 result[i] = [];
4639 }
4640 if (paramAnnotations && paramAnnotations[i] != null) {
4641 result[i] = result[i].concat(paramAnnotations[i]);
4642 }
4643 }
4644 return result;
4645 }
4646 _ownParameters(type, parentCtor) {
4647 const typeStr = type.toString();
4648 // If we have no decorators, we only have function.length as metadata.
4649 // In that case, to detect whether a child class declared an own constructor or not,
4650 // we need to look inside of that constructor to check whether it is
4651 // just calling the parent.
4652 // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
4653 // that sets 'design:paramtypes' to []
4654 // if a class inherits from another class but has no ctor declared itself.
4655 if (isDelegateCtor(typeStr)) {
4656 return null;
4657 }
4658 // Prefer the direct API.
4659 if (type.parameters && type.parameters !== parentCtor.parameters) {
4660 return type.parameters;
4661 }
4662 // API of tsickle for lowering decorators to properties on the class.
4663 const tsickleCtorParams = type.ctorParameters;
4664 if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
4665 // Newer tsickle uses a function closure
4666 // Retain the non-function case for compatibility with older tsickle
4667 const ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
4668 const paramTypes = ctorParameters.map((ctorParam) => ctorParam && ctorParam.type);
4669 const paramAnnotations = ctorParameters.map((ctorParam) => ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
4670 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
4671 }
4672 // API for metadata created by invoking the decorators.
4673 const paramAnnotations = type.hasOwnProperty(PARAMETERS) && type[PARAMETERS];
4674 const paramTypes = this._reflect && this._reflect.getOwnMetadata &&
4675 this._reflect.getOwnMetadata('design:paramtypes', type);
4676 if (paramTypes || paramAnnotations) {
4677 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
4678 }
4679 // If a class has no decorators, at least create metadata
4680 // based on function.length.
4681 // Note: We know that this is a real constructor as we checked
4682 // the content of the constructor above.
4683 return newArray(type.length);
4684 }
4685 parameters(type) {
4686 // Note: only report metadata if we have at least one class decorator
4687 // to stay in sync with the static reflector.
4688 if (!isType(type)) {
4689 return [];
4690 }
4691 const parentCtor = getParentCtor(type);
4692 let parameters = this._ownParameters(type, parentCtor);
4693 if (!parameters && parentCtor !== Object) {
4694 parameters = this.parameters(parentCtor);
4695 }
4696 return parameters || [];
4697 }
4698 _ownAnnotations(typeOrFunc, parentCtor) {
4699 // Prefer the direct API.
4700 if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
4701 let annotations = typeOrFunc.annotations;
4702 if (typeof annotations === 'function' && annotations.annotations) {
4703 annotations = annotations.annotations;
4704 }
4705 return annotations;
4706 }
4707 // API of tsickle for lowering decorators to properties on the class.
4708 if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) {
4709 return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators);
4710 }
4711 // API for metadata created by invoking the decorators.
4712 if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
4713 return typeOrFunc[ANNOTATIONS];
4714 }
4715 return null;
4716 }
4717 annotations(typeOrFunc) {
4718 if (!isType(typeOrFunc)) {
4719 return [];
4720 }
4721 const parentCtor = getParentCtor(typeOrFunc);
4722 const ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
4723 const parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
4724 return parentAnnotations.concat(ownAnnotations);
4725 }
4726 _ownPropMetadata(typeOrFunc, parentCtor) {
4727 // Prefer the direct API.
4728 if (typeOrFunc.propMetadata &&
4729 typeOrFunc.propMetadata !== parentCtor.propMetadata) {
4730 let propMetadata = typeOrFunc.propMetadata;
4731 if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
4732 propMetadata = propMetadata.propMetadata;
4733 }
4734 return propMetadata;
4735 }
4736 // API of tsickle for lowering decorators to properties on the class.
4737 if (typeOrFunc.propDecorators &&
4738 typeOrFunc.propDecorators !== parentCtor.propDecorators) {
4739 const propDecorators = typeOrFunc.propDecorators;
4740 const propMetadata = {};
4741 Object.keys(propDecorators).forEach(prop => {
4742 propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
4743 });
4744 return propMetadata;
4745 }
4746 // API for metadata created by invoking the decorators.
4747 if (typeOrFunc.hasOwnProperty(PROP_METADATA)) {
4748 return typeOrFunc[PROP_METADATA];
4749 }
4750 return null;
4751 }
4752 propMetadata(typeOrFunc) {
4753 if (!isType(typeOrFunc)) {
4754 return {};
4755 }
4756 const parentCtor = getParentCtor(typeOrFunc);
4757 const propMetadata = {};
4758 if (parentCtor !== Object) {
4759 const parentPropMetadata = this.propMetadata(parentCtor);
4760 Object.keys(parentPropMetadata).forEach((propName) => {
4761 propMetadata[propName] = parentPropMetadata[propName];
4762 });
4763 }
4764 const ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
4765 if (ownPropMetadata) {
4766 Object.keys(ownPropMetadata).forEach((propName) => {
4767 const decorators = [];
4768 if (propMetadata.hasOwnProperty(propName)) {
4769 decorators.push(...propMetadata[propName]);
4770 }
4771 decorators.push(...ownPropMetadata[propName]);
4772 propMetadata[propName] = decorators;
4773 });
4774 }
4775 return propMetadata;
4776 }
4777 ownPropMetadata(typeOrFunc) {
4778 if (!isType(typeOrFunc)) {
4779 return {};
4780 }
4781 return this._ownPropMetadata(typeOrFunc, getParentCtor(typeOrFunc)) || {};
4782 }
4783 hasLifecycleHook(type, lcProperty) {
4784 return type instanceof Type && lcProperty in type.prototype;
4785 }
4786}
4787function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
4788 if (!decoratorInvocations) {
4789 return [];
4790 }
4791 return decoratorInvocations.map(decoratorInvocation => {
4792 const decoratorType = decoratorInvocation.type;
4793 const annotationCls = decoratorType.annotationCls;
4794 const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
4795 return new annotationCls(...annotationArgs);
4796 });
4797}
4798function getParentCtor(ctor) {
4799 const parentProto = ctor.prototype ? Object.getPrototypeOf(ctor.prototype) : null;
4800 const parentCtor = parentProto ? parentProto.constructor : null;
4801 // Note: We always use `Object` as the null value
4802 // to simplify checking later on.
4803 return parentCtor || Object;
4804}
4805
4806/**
4807 * @license
4808 * Copyright Google LLC All Rights Reserved.
4809 *
4810 * Use of this source code is governed by an MIT-style license that can be
4811 * found in the LICENSE file at https://angular.io/license
4812 */
4813const _THROW_IF_NOT_FOUND = {};
4814const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
4815/*
4816 * Name of a property (that we patch onto DI decorator), which is used as an annotation of which
4817 * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators
4818 * in the code, thus making them tree-shakable.
4819 */
4820const DI_DECORATOR_FLAG = '__NG_DI_FLAG__';
4821const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath';
4822const NG_TOKEN_PATH = 'ngTokenPath';
4823const NEW_LINE = /\n/gm;
4824const NO_NEW_LINE = 'ɵ';
4825const SOURCE = '__source';
4826/**
4827 * Current injector value used by `inject`.
4828 * - `undefined`: it is an error to call `inject`
4829 * - `null`: `inject` can be called but there is no injector (limp-mode).
4830 * - Injector instance: Use the injector for resolution.
4831 */
4832let _currentInjector = undefined;
4833function setCurrentInjector(injector) {
4834 const former = _currentInjector;
4835 _currentInjector = injector;
4836 return former;
4837}
4838function injectInjectorOnly(token, flags = InjectFlags.Default) {
4839 if (_currentInjector === undefined) {
4840 throw new RuntimeError(-203 /* RuntimeErrorCode.MISSING_INJECTION_CONTEXT */, ngDevMode &&
4841 `inject() must be called from an injection context (a constructor, a factory function or a field initializer)`);
4842 }
4843 else if (_currentInjector === null) {
4844 return injectRootLimpMode(token, undefined, flags);
4845 }
4846 else {
4847 return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
4848 }
4849}
4850function ɵɵinject(token, flags = InjectFlags.Default) {
4851 return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef(token), flags);
4852}
4853/**
4854 * Throws an error indicating that a factory function could not be generated by the compiler for a
4855 * particular class.
4856 *
4857 * This instruction allows the actual error message to be optimized away when ngDevMode is turned
4858 * off, saving bytes of generated code while still providing a good experience in dev mode.
4859 *
4860 * The name of the class is not mentioned here, but will be in the generated factory function name
4861 * and thus in the stack trace.
4862 *
4863 * @codeGenApi
4864 */
4865function ɵɵinvalidFactoryDep(index) {
4866 const msg = ngDevMode ?
4867 `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${index} of the parameter list is invalid.
4868This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.
4869
4870Please 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.` :
4871 'invalid';
4872 throw new Error(msg);
4873}
4874/**
4875 * Injects a token from the currently active injector.
4876 * `inject` is only supported during instantiation of a dependency by the DI system. It can be used
4877 * during:
4878 * - Construction (via the `constructor`) of a class being instantiated by the DI system, such
4879 * as an `@Injectable` or `@Component`.
4880 * - In the initializer for fields of such classes.
4881 * - In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`.
4882 * - In the `factory` function specified for an `InjectionToken`.
4883 *
4884 * @param token A token that represents a dependency that should be injected.
4885 * @param flags Optional flags that control how injection is executed.
4886 * The flags correspond to injection strategies that can be specified with
4887 * parameter decorators `@Host`, `@Self`, `@SkipSef`, and `@Optional`.
4888 * @returns the injected value if operation is successful, `null` otherwise.
4889 * @throws if called outside of a supported context.
4890 *
4891 * @usageNotes
4892 * In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a
4893 * field initializer:
4894 *
4895 * ```typescript
4896 * @Injectable({providedIn: 'root'})
4897 * export class Car {
4898 * radio: Radio|undefined;
4899 * // OK: field initializer
4900 * spareTyre = inject(Tyre);
4901 *
4902 * constructor() {
4903 * // OK: constructor body
4904 * this.radio = inject(Radio);
4905 * }
4906 * }
4907 * ```
4908 *
4909 * It is also legal to call `inject` from a provider's factory:
4910 *
4911 * ```typescript
4912 * providers: [
4913 * {provide: Car, useFactory: () => {
4914 * // OK: a class factory
4915 * const engine = inject(Engine);
4916 * return new Car(engine);
4917 * }}
4918 * ]
4919 * ```
4920 *
4921 * Calls to the `inject()` function outside of the class creation context will result in error. Most
4922 * notably, calls to `inject()` are disallowed after a class instance was created, in methods
4923 * (including lifecycle hooks):
4924 *
4925 * ```typescript
4926 * @Component({ ... })
4927 * export class CarComponent {
4928 * ngOnInit() {
4929 * // ERROR: too late, the component instance was already created
4930 * const engine = inject(Engine);
4931 * engine.start();
4932 * }
4933 * }
4934 * ```
4935 *
4936 * @publicApi
4937 */
4938function inject(token, flags = InjectFlags.Default) {
4939 return ɵɵinject(token, flags);
4940}
4941function injectArgs(types) {
4942 const args = [];
4943 for (let i = 0; i < types.length; i++) {
4944 const arg = resolveForwardRef(types[i]);
4945 if (Array.isArray(arg)) {
4946 if (arg.length === 0) {
4947 throw new RuntimeError(900 /* RuntimeErrorCode.INVALID_DIFFER_INPUT */, ngDevMode && 'Arguments array must have arguments.');
4948 }
4949 let type = undefined;
4950 let flags = InjectFlags.Default;
4951 for (let j = 0; j < arg.length; j++) {
4952 const meta = arg[j];
4953 const flag = getInjectFlag(meta);
4954 if (typeof flag === 'number') {
4955 // Special case when we handle @Inject decorator.
4956 if (flag === -1 /* DecoratorFlags.Inject */) {
4957 type = meta.token;
4958 }
4959 else {
4960 flags |= flag;
4961 }
4962 }
4963 else {
4964 type = meta;
4965 }
4966 }
4967 args.push(ɵɵinject(type, flags));
4968 }
4969 else {
4970 args.push(ɵɵinject(arg));
4971 }
4972 }
4973 return args;
4974}
4975/**
4976 * Attaches a given InjectFlag to a given decorator using monkey-patching.
4977 * Since DI decorators can be used in providers `deps` array (when provider is configured using
4978 * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we
4979 * attach the flag to make it available both as a static property and as a field on decorator
4980 * instance.
4981 *
4982 * @param decorator Provided DI decorator.
4983 * @param flag InjectFlag that should be applied.
4984 */
4985function attachInjectFlag(decorator, flag) {
4986 decorator[DI_DECORATOR_FLAG] = flag;
4987 decorator.prototype[DI_DECORATOR_FLAG] = flag;
4988 return decorator;
4989}
4990/**
4991 * Reads monkey-patched property that contains InjectFlag attached to a decorator.
4992 *
4993 * @param token Token that may contain monkey-patched DI flags property.
4994 */
4995function getInjectFlag(token) {
4996 return token[DI_DECORATOR_FLAG];
4997}
4998function catchInjectorError(e, token, injectorErrorName, source) {
4999 const tokenPath = e[NG_TEMP_TOKEN_PATH];
5000 if (token[SOURCE]) {
5001 tokenPath.unshift(token[SOURCE]);
5002 }
5003 e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source);
5004 e[NG_TOKEN_PATH] = tokenPath;
5005 e[NG_TEMP_TOKEN_PATH] = null;
5006 throw e;
5007}
5008function formatError(text, obj, injectorErrorName, source = null) {
5009 text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.slice(2) : text;
5010 let context = stringify(obj);
5011 if (Array.isArray(obj)) {
5012 context = obj.map(stringify).join(' -> ');
5013 }
5014 else if (typeof obj === 'object') {
5015 let parts = [];
5016 for (let key in obj) {
5017 if (obj.hasOwnProperty(key)) {
5018 let value = obj[key];
5019 parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value)));
5020 }
5021 }
5022 context = `{${parts.join(', ')}}`;
5023 }
5024 return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
5025}
5026
5027/**
5028 * @license
5029 * Copyright Google LLC All Rights Reserved.
5030 *
5031 * Use of this source code is governed by an MIT-style license that can be
5032 * found in the LICENSE file at https://angular.io/license
5033 */
5034/**
5035 * Inject decorator and metadata.
5036 *
5037 * @Annotation
5038 * @publicApi
5039 */
5040const Inject = attachInjectFlag(
5041// Disable tslint because `DecoratorFlags` is a const enum which gets inlined.
5042// tslint:disable-next-line: no-toplevel-property-access
5043makeParamDecorator('Inject', (token) => ({ token })), -1 /* DecoratorFlags.Inject */);
5044/**
5045 * Optional decorator and metadata.
5046 *
5047 * @Annotation
5048 * @publicApi
5049 */
5050const Optional =
5051// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
5052// tslint:disable-next-line: no-toplevel-property-access
5053attachInjectFlag(makeParamDecorator('Optional'), 8 /* InternalInjectFlags.Optional */);
5054/**
5055 * Self decorator and metadata.
5056 *
5057 * @Annotation
5058 * @publicApi
5059 */
5060const Self =
5061// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
5062// tslint:disable-next-line: no-toplevel-property-access
5063attachInjectFlag(makeParamDecorator('Self'), 2 /* InternalInjectFlags.Self */);
5064/**
5065 * `SkipSelf` decorator and metadata.
5066 *
5067 * @Annotation
5068 * @publicApi
5069 */
5070const SkipSelf =
5071// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
5072// tslint:disable-next-line: no-toplevel-property-access
5073attachInjectFlag(makeParamDecorator('SkipSelf'), 4 /* InternalInjectFlags.SkipSelf */);
5074/**
5075 * Host decorator and metadata.
5076 *
5077 * @Annotation
5078 * @publicApi
5079 */
5080const Host =
5081// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
5082// tslint:disable-next-line: no-toplevel-property-access
5083attachInjectFlag(makeParamDecorator('Host'), 1 /* InternalInjectFlags.Host */);
5084
5085/**
5086 * @license
5087 * Copyright Google LLC All Rights Reserved.
5088 *
5089 * Use of this source code is governed by an MIT-style license that can be
5090 * found in the LICENSE file at https://angular.io/license
5091 */
5092let _reflect = null;
5093function getReflect() {
5094 return (_reflect = _reflect || new ReflectionCapabilities());
5095}
5096function reflectDependencies(type) {
5097 return convertDependencies(getReflect().parameters(type));
5098}
5099function convertDependencies(deps) {
5100 return deps.map(dep => reflectDependency(dep));
5101}
5102function reflectDependency(dep) {
5103 const meta = {
5104 token: null,
5105 attribute: null,
5106 host: false,
5107 optional: false,
5108 self: false,
5109 skipSelf: false,
5110 };
5111 if (Array.isArray(dep) && dep.length > 0) {
5112 for (let j = 0; j < dep.length; j++) {
5113 const param = dep[j];
5114 if (param === undefined) {
5115 // param may be undefined if type of dep is not set by ngtsc
5116 continue;
5117 }
5118 const proto = Object.getPrototypeOf(param);
5119 if (param instanceof Optional || proto.ngMetadataName === 'Optional') {
5120 meta.optional = true;
5121 }
5122 else if (param instanceof SkipSelf || proto.ngMetadataName === 'SkipSelf') {
5123 meta.skipSelf = true;
5124 }
5125 else if (param instanceof Self || proto.ngMetadataName === 'Self') {
5126 meta.self = true;
5127 }
5128 else if (param instanceof Host || proto.ngMetadataName === 'Host') {
5129 meta.host = true;
5130 }
5131 else if (param instanceof Inject) {
5132 meta.token = param.token;
5133 }
5134 else if (param instanceof Attribute) {
5135 if (param.attributeName === undefined) {
5136 throw new Error(`Attribute name must be defined.`);
5137 }
5138 meta.attribute = param.attributeName;
5139 }
5140 else {
5141 meta.token = param;
5142 }
5143 }
5144 }
5145 else if (dep === undefined || (Array.isArray(dep) && dep.length === 0)) {
5146 meta.token = null;
5147 }
5148 else {
5149 meta.token = dep;
5150 }
5151 return meta;
5152}
5153
5154/**
5155 * @license
5156 * Copyright Google LLC All Rights Reserved.
5157 *
5158 * Use of this source code is governed by an MIT-style license that can be
5159 * found in the LICENSE file at https://angular.io/license
5160 */
5161/**
5162 * Used to resolve resource URLs on `@Component` when used with JIT compilation.
5163 *
5164 * Example:
5165 * ```
5166 * @Component({
5167 * selector: 'my-comp',
5168 * templateUrl: 'my-comp.html', // This requires asynchronous resolution
5169 * })
5170 * class MyComponent{
5171 * }
5172 *
5173 * // Calling `renderComponent` will fail because `renderComponent` is a synchronous process
5174 * // and `MyComponent`'s `@Component.templateUrl` needs to be resolved asynchronously.
5175 *
5176 * // Calling `resolveComponentResources()` will resolve `@Component.templateUrl` into
5177 * // `@Component.template`, which allows `renderComponent` to proceed in a synchronous manner.
5178 *
5179 * // Use browser's `fetch()` function as the default resource resolution strategy.
5180 * resolveComponentResources(fetch).then(() => {
5181 * // After resolution all URLs have been converted into `template` strings.
5182 * renderComponent(MyComponent);
5183 * });
5184 *
5185 * ```
5186 *
5187 * NOTE: In AOT the resolution happens during compilation, and so there should be no need
5188 * to call this method outside JIT mode.
5189 *
5190 * @param resourceResolver a function which is responsible for returning a `Promise` to the
5191 * contents of the resolved URL. Browser's `fetch()` method is a good default implementation.
5192 */
5193function resolveComponentResources(resourceResolver) {
5194 // Store all promises which are fetching the resources.
5195 const componentResolved = [];
5196 // Cache so that we don't fetch the same resource more than once.
5197 const urlMap = new Map();
5198 function cachedResourceResolve(url) {
5199 let promise = urlMap.get(url);
5200 if (!promise) {
5201 const resp = resourceResolver(url);
5202 urlMap.set(url, promise = resp.then(unwrapResponse));
5203 }
5204 return promise;
5205 }
5206 componentResourceResolutionQueue.forEach((component, type) => {
5207 const promises = [];
5208 if (component.templateUrl) {
5209 promises.push(cachedResourceResolve(component.templateUrl).then((template) => {
5210 component.template = template;
5211 }));
5212 }
5213 const styleUrls = component.styleUrls;
5214 const styles = component.styles || (component.styles = []);
5215 const styleOffset = component.styles.length;
5216 styleUrls && styleUrls.forEach((styleUrl, index) => {
5217 styles.push(''); // pre-allocate array.
5218 promises.push(cachedResourceResolve(styleUrl).then((style) => {
5219 styles[styleOffset + index] = style;
5220 styleUrls.splice(styleUrls.indexOf(styleUrl), 1);
5221 if (styleUrls.length == 0) {
5222 component.styleUrls = undefined;
5223 }
5224 }));
5225 });
5226 const fullyResolved = Promise.all(promises).then(() => componentDefResolved(type));
5227 componentResolved.push(fullyResolved);
5228 });
5229 clearResolutionOfComponentResourcesQueue();
5230 return Promise.all(componentResolved).then(() => undefined);
5231}
5232let componentResourceResolutionQueue = new Map();
5233// Track when existing ɵcmp for a Type is waiting on resources.
5234const componentDefPendingResolution = new Set();
5235function maybeQueueResolutionOfComponentResources(type, metadata) {
5236 if (componentNeedsResolution(metadata)) {
5237 componentResourceResolutionQueue.set(type, metadata);
5238 componentDefPendingResolution.add(type);
5239 }
5240}
5241function isComponentDefPendingResolution(type) {
5242 return componentDefPendingResolution.has(type);
5243}
5244function componentNeedsResolution(component) {
5245 return !!((component.templateUrl && !component.hasOwnProperty('template')) ||
5246 component.styleUrls && component.styleUrls.length);
5247}
5248function clearResolutionOfComponentResourcesQueue() {
5249 const old = componentResourceResolutionQueue;
5250 componentResourceResolutionQueue = new Map();
5251 return old;
5252}
5253function restoreComponentResolutionQueue(queue) {
5254 componentDefPendingResolution.clear();
5255 queue.forEach((_, type) => componentDefPendingResolution.add(type));
5256 componentResourceResolutionQueue = queue;
5257}
5258function isComponentResourceResolutionQueueEmpty() {
5259 return componentResourceResolutionQueue.size === 0;
5260}
5261function unwrapResponse(response) {
5262 return typeof response == 'string' ? response : response.text();
5263}
5264function componentDefResolved(type) {
5265 componentDefPendingResolution.delete(type);
5266}
5267
5268/**
5269 * @license
5270 * Copyright Google LLC All Rights Reserved.
5271 *
5272 * Use of this source code is governed by an MIT-style license that can be
5273 * found in the LICENSE file at https://angular.io/license
5274 */
5275/**
5276 * Map of module-id to the corresponding NgModule.
5277 */
5278const modules = new Map();
5279/**
5280 * Whether to check for duplicate NgModule registrations.
5281 *
5282 * This can be disabled for testing.
5283 */
5284let checkForDuplicateNgModules = true;
5285function assertSameOrNotExisting(id, type, incoming) {
5286 if (type && type !== incoming && checkForDuplicateNgModules) {
5287 throw new Error(`Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`);
5288 }
5289}
5290/**
5291 * Adds the given NgModule type to Angular's NgModule registry.
5292 *
5293 * This is generated as a side-effect of NgModule compilation. Note that the `id` is passed in
5294 * explicitly and not read from the NgModule definition. This is for two reasons: it avoids a
5295 * megamorphic read, and in JIT there's a chicken-and-egg problem where the NgModule may not be
5296 * fully resolved when it's registered.
5297 *
5298 * @codeGenApi
5299 */
5300function registerNgModuleType(ngModuleType, id) {
5301 const existing = modules.get(id) || null;
5302 assertSameOrNotExisting(id, existing, ngModuleType);
5303 modules.set(id, ngModuleType);
5304}
5305function clearModulesForTest() {
5306 modules.clear();
5307}
5308function getRegisteredNgModuleType(id) {
5309 return modules.get(id);
5310}
5311/**
5312 * Control whether the NgModule registration system enforces that each NgModule type registered has
5313 * a unique id.
5314 *
5315 * This is useful for testing as the NgModule registry cannot be properly reset between tests with
5316 * Angular's current API.
5317 */
5318function setAllowDuplicateNgModuleIdsForTest(allowDuplicates) {
5319 checkForDuplicateNgModules = !allowDuplicates;
5320}
5321
5322/**
5323 * @license
5324 * Copyright Google LLC All Rights Reserved.
5325 *
5326 * Use of this source code is governed by an MIT-style license that can be
5327 * found in the LICENSE file at https://angular.io/license
5328 */
5329/**
5330 * The Trusted Types policy, or null if Trusted Types are not
5331 * enabled/supported, or undefined if the policy has not been created yet.
5332 */
5333let policy$1;
5334/**
5335 * Returns the Trusted Types policy, or null if Trusted Types are not
5336 * enabled/supported. The first call to this function will create the policy.
5337 */
5338function getPolicy$1() {
5339 if (policy$1 === undefined) {
5340 policy$1 = null;
5341 if (_global.trustedTypes) {
5342 try {
5343 policy$1 = _global.trustedTypes.createPolicy('angular', {
5344 createHTML: (s) => s,
5345 createScript: (s) => s,
5346 createScriptURL: (s) => s,
5347 });
5348 }
5349 catch (_a) {
5350 // trustedTypes.createPolicy throws if called with a name that is
5351 // already registered, even in report-only mode. Until the API changes,
5352 // catch the error not to break the applications functionally. In such
5353 // cases, the code will fall back to using strings.
5354 }
5355 }
5356 }
5357 return policy$1;
5358}
5359/**
5360 * Unsafely promote a string to a TrustedHTML, falling back to strings when
5361 * Trusted Types are not available.
5362 * @security This is a security-sensitive function; any use of this function
5363 * must go through security review. In particular, it must be assured that the
5364 * provided string will never cause an XSS vulnerability if used in a context
5365 * that will be interpreted as HTML by a browser, e.g. when assigning to
5366 * element.innerHTML.
5367 */
5368function trustedHTMLFromString(html) {
5369 var _a;
5370 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createHTML(html)) || html;
5371}
5372/**
5373 * Unsafely promote a string to a TrustedScript, falling back to strings when
5374 * Trusted Types are not available.
5375 * @security In particular, it must be assured that the provided string will
5376 * never cause an XSS vulnerability if used in a context that will be
5377 * interpreted and executed as a script by a browser, e.g. when calling eval.
5378 */
5379function trustedScriptFromString(script) {
5380 var _a;
5381 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
5382}
5383/**
5384 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
5385 * when Trusted Types are not available.
5386 * @security This is a security-sensitive function; any use of this function
5387 * must go through security review. In particular, it must be assured that the
5388 * provided string will never cause an XSS vulnerability if used in a context
5389 * that will cause a browser to load and execute a resource, e.g. when
5390 * assigning to script.src.
5391 */
5392function trustedScriptURLFromString(url) {
5393 var _a;
5394 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScriptURL(url)) || url;
5395}
5396/**
5397 * Unsafely call the Function constructor with the given string arguments. It
5398 * is only available in development mode, and should be stripped out of
5399 * production code.
5400 * @security This is a security-sensitive function; any use of this function
5401 * must go through security review. In particular, it must be assured that it
5402 * is only called from development code, as use in production code can lead to
5403 * XSS vulnerabilities.
5404 */
5405function newTrustedFunctionForDev(...args) {
5406 if (typeof ngDevMode === 'undefined') {
5407 throw new Error('newTrustedFunctionForDev should never be called in production');
5408 }
5409 if (!_global.trustedTypes) {
5410 // In environments that don't support Trusted Types, fall back to the most
5411 // straightforward implementation:
5412 return new Function(...args);
5413 }
5414 // Chrome currently does not support passing TrustedScript to the Function
5415 // constructor. The following implements the workaround proposed on the page
5416 // below, where the Chromium bug is also referenced:
5417 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
5418 const fnArgs = args.slice(0, -1).join(',');
5419 const fnBody = args[args.length - 1];
5420 const body = `(function anonymous(${fnArgs}
5421) { ${fnBody}
5422})`;
5423 // Using eval directly confuses the compiler and prevents this module from
5424 // being stripped out of JS binaries even if not used. The global['eval']
5425 // indirection fixes that.
5426 const fn = _global['eval'](trustedScriptFromString(body));
5427 if (fn.bind === undefined) {
5428 // Workaround for a browser bug that only exists in Chrome 83, where passing
5429 // a TrustedScript to eval just returns the TrustedScript back without
5430 // evaluating it. In that case, fall back to the most straightforward
5431 // implementation:
5432 return new Function(...args);
5433 }
5434 // To completely mimic the behavior of calling "new Function", two more
5435 // things need to happen:
5436 // 1. Stringifying the resulting function should return its source code
5437 fn.toString = () => body;
5438 // 2. When calling the resulting function, `this` should refer to `global`
5439 return fn.bind(_global);
5440 // When Trusted Types support in Function constructors is widely available,
5441 // the implementation of this function can be simplified to:
5442 // return new Function(...args.map(a => trustedScriptFromString(a)));
5443}
5444
5445/**
5446 * @license
5447 * Copyright Google LLC All Rights Reserved.
5448 *
5449 * Use of this source code is governed by an MIT-style license that can be
5450 * found in the LICENSE file at https://angular.io/license
5451 */
5452/**
5453 * The Trusted Types policy, or null if Trusted Types are not
5454 * enabled/supported, or undefined if the policy has not been created yet.
5455 */
5456let policy;
5457/**
5458 * Returns the Trusted Types policy, or null if Trusted Types are not
5459 * enabled/supported. The first call to this function will create the policy.
5460 */
5461function getPolicy() {
5462 if (policy === undefined) {
5463 policy = null;
5464 if (_global.trustedTypes) {
5465 try {
5466 policy = _global.trustedTypes
5467 .createPolicy('angular#unsafe-bypass', {
5468 createHTML: (s) => s,
5469 createScript: (s) => s,
5470 createScriptURL: (s) => s,
5471 });
5472 }
5473 catch (_a) {
5474 // trustedTypes.createPolicy throws if called with a name that is
5475 // already registered, even in report-only mode. Until the API changes,
5476 // catch the error not to break the applications functionally. In such
5477 // cases, the code will fall back to using strings.
5478 }
5479 }
5480 }
5481 return policy;
5482}
5483/**
5484 * Unsafely promote a string to a TrustedHTML, falling back to strings when
5485 * Trusted Types are not available.
5486 * @security This is a security-sensitive function; any use of this function
5487 * must go through security review. In particular, it must be assured that it
5488 * is only passed strings that come directly from custom sanitizers or the
5489 * bypassSecurityTrust* functions.
5490 */
5491function trustedHTMLFromStringBypass(html) {
5492 var _a;
5493 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createHTML(html)) || html;
5494}
5495/**
5496 * Unsafely promote a string to a TrustedScript, falling back to strings when
5497 * Trusted Types are not available.
5498 * @security This is a security-sensitive function; any use of this function
5499 * must go through security review. In particular, it must be assured that it
5500 * is only passed strings that come directly from custom sanitizers or the
5501 * bypassSecurityTrust* functions.
5502 */
5503function trustedScriptFromStringBypass(script) {
5504 var _a;
5505 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
5506}
5507/**
5508 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
5509 * when Trusted Types are not available.
5510 * @security This is a security-sensitive function; any use of this function
5511 * must go through security review. In particular, it must be assured that it
5512 * is only passed strings that come directly from custom sanitizers or the
5513 * bypassSecurityTrust* functions.
5514 */
5515function trustedScriptURLFromStringBypass(url) {
5516 var _a;
5517 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScriptURL(url)) || url;
5518}
5519
5520/**
5521 * @license
5522 * Copyright Google LLC All Rights Reserved.
5523 *
5524 * Use of this source code is governed by an MIT-style license that can be
5525 * found in the LICENSE file at https://angular.io/license
5526 */
5527class SafeValueImpl {
5528 constructor(changingThisBreaksApplicationSecurity) {
5529 this.changingThisBreaksApplicationSecurity = changingThisBreaksApplicationSecurity;
5530 }
5531 toString() {
5532 return `SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity}` +
5533 ` (see https://g.co/ng/security#xss)`;
5534 }
5535}
5536class SafeHtmlImpl extends SafeValueImpl {
5537 getTypeName() {
5538 return "HTML" /* BypassType.Html */;
5539 }
5540}
5541class SafeStyleImpl extends SafeValueImpl {
5542 getTypeName() {
5543 return "Style" /* BypassType.Style */;
5544 }
5545}
5546class SafeScriptImpl extends SafeValueImpl {
5547 getTypeName() {
5548 return "Script" /* BypassType.Script */;
5549 }
5550}
5551class SafeUrlImpl extends SafeValueImpl {
5552 getTypeName() {
5553 return "URL" /* BypassType.Url */;
5554 }
5555}
5556class SafeResourceUrlImpl extends SafeValueImpl {
5557 getTypeName() {
5558 return "ResourceURL" /* BypassType.ResourceUrl */;
5559 }
5560}
5561function unwrapSafeValue(value) {
5562 return value instanceof SafeValueImpl ? value.changingThisBreaksApplicationSecurity :
5563 value;
5564}
5565function allowSanitizationBypassAndThrow(value, type) {
5566 const actualType = getSanitizationBypassType(value);
5567 if (actualType != null && actualType !== type) {
5568 // Allow ResourceURLs in URL contexts, they are strictly more trusted.
5569 if (actualType === "ResourceURL" /* BypassType.ResourceUrl */ && type === "URL" /* BypassType.Url */)
5570 return true;
5571 throw new Error(`Required a safe ${type}, got a ${actualType} (see https://g.co/ng/security#xss)`);
5572 }
5573 return actualType === type;
5574}
5575function getSanitizationBypassType(value) {
5576 return value instanceof SafeValueImpl && value.getTypeName() || null;
5577}
5578/**
5579 * Mark `html` string as trusted.
5580 *
5581 * This function wraps the trusted string in `String` and brands it in a way which makes it
5582 * recognizable to {@link htmlSanitizer} to be trusted implicitly.
5583 *
5584 * @param trustedHtml `html` string which needs to be implicitly trusted.
5585 * @returns a `html` which has been branded to be implicitly trusted.
5586 */
5587function bypassSanitizationTrustHtml(trustedHtml) {
5588 return new SafeHtmlImpl(trustedHtml);
5589}
5590/**
5591 * Mark `style` string as trusted.
5592 *
5593 * This function wraps the trusted string in `String` and brands it in a way which makes it
5594 * recognizable to {@link styleSanitizer} to be trusted implicitly.
5595 *
5596 * @param trustedStyle `style` string which needs to be implicitly trusted.
5597 * @returns a `style` hich has been branded to be implicitly trusted.
5598 */
5599function bypassSanitizationTrustStyle(trustedStyle) {
5600 return new SafeStyleImpl(trustedStyle);
5601}
5602/**
5603 * Mark `script` string as trusted.
5604 *
5605 * This function wraps the trusted string in `String` and brands it in a way which makes it
5606 * recognizable to {@link scriptSanitizer} to be trusted implicitly.
5607 *
5608 * @param trustedScript `script` string which needs to be implicitly trusted.
5609 * @returns a `script` which has been branded to be implicitly trusted.
5610 */
5611function bypassSanitizationTrustScript(trustedScript) {
5612 return new SafeScriptImpl(trustedScript);
5613}
5614/**
5615 * Mark `url` string as trusted.
5616 *
5617 * This function wraps the trusted string in `String` and brands it in a way which makes it
5618 * recognizable to {@link urlSanitizer} to be trusted implicitly.
5619 *
5620 * @param trustedUrl `url` string which needs to be implicitly trusted.
5621 * @returns a `url` which has been branded to be implicitly trusted.
5622 */
5623function bypassSanitizationTrustUrl(trustedUrl) {
5624 return new SafeUrlImpl(trustedUrl);
5625}
5626/**
5627 * Mark `url` string as trusted.
5628 *
5629 * This function wraps the trusted string in `String` and brands it in a way which makes it
5630 * recognizable to {@link resourceUrlSanitizer} to be trusted implicitly.
5631 *
5632 * @param trustedResourceUrl `url` string which needs to be implicitly trusted.
5633 * @returns a `url` which has been branded to be implicitly trusted.
5634 */
5635function bypassSanitizationTrustResourceUrl(trustedResourceUrl) {
5636 return new SafeResourceUrlImpl(trustedResourceUrl);
5637}
5638
5639/**
5640 * @license
5641 * Copyright Google LLC All Rights Reserved.
5642 *
5643 * Use of this source code is governed by an MIT-style license that can be
5644 * found in the LICENSE file at https://angular.io/license
5645 */
5646/**
5647 * This helper is used to get hold of an inert tree of DOM elements containing dirty HTML
5648 * that needs sanitizing.
5649 * Depending upon browser support we use one of two strategies for doing this.
5650 * Default: DOMParser strategy
5651 * Fallback: InertDocument strategy
5652 */
5653function getInertBodyHelper(defaultDoc) {
5654 const inertDocumentHelper = new InertDocumentHelper(defaultDoc);
5655 return isDOMParserAvailable() ? new DOMParserHelper(inertDocumentHelper) : inertDocumentHelper;
5656}
5657/**
5658 * Uses DOMParser to create and fill an inert body element.
5659 * This is the default strategy used in browsers that support it.
5660 */
5661class DOMParserHelper {
5662 constructor(inertDocumentHelper) {
5663 this.inertDocumentHelper = inertDocumentHelper;
5664 }
5665 getInertBodyElement(html) {
5666 // We add these extra elements to ensure that the rest of the content is parsed as expected
5667 // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the
5668 // `<head>` tag. Note that the `<body>` tag is closed implicitly to prevent unclosed tags
5669 // in `html` from consuming the otherwise explicit `</body>` tag.
5670 html = '<body><remove></remove>' + html;
5671 try {
5672 const body = new window.DOMParser()
5673 .parseFromString(trustedHTMLFromString(html), 'text/html')
5674 .body;
5675 if (body === null) {
5676 // In some browsers (e.g. Mozilla/5.0 iPad AppleWebKit Mobile) the `body` property only
5677 // becomes available in the following tick of the JS engine. In that case we fall back to
5678 // the `inertDocumentHelper` instead.
5679 return this.inertDocumentHelper.getInertBodyElement(html);
5680 }
5681 body.removeChild(body.firstChild);
5682 return body;
5683 }
5684 catch (_a) {
5685 return null;
5686 }
5687 }
5688}
5689/**
5690 * Use an HTML5 `template` element, if supported, or an inert body element created via
5691 * `createHtmlDocument` to create and fill an inert DOM element.
5692 * This is the fallback strategy if the browser does not support DOMParser.
5693 */
5694class InertDocumentHelper {
5695 constructor(defaultDoc) {
5696 this.defaultDoc = defaultDoc;
5697 this.inertDocument = this.defaultDoc.implementation.createHTMLDocument('sanitization-inert');
5698 if (this.inertDocument.body == null) {
5699 // usually there should be only one body element in the document, but IE doesn't have any, so
5700 // we need to create one.
5701 const inertHtml = this.inertDocument.createElement('html');
5702 this.inertDocument.appendChild(inertHtml);
5703 const inertBodyElement = this.inertDocument.createElement('body');
5704 inertHtml.appendChild(inertBodyElement);
5705 }
5706 }
5707 getInertBodyElement(html) {
5708 // Prefer using <template> element if supported.
5709 const templateEl = this.inertDocument.createElement('template');
5710 if ('content' in templateEl) {
5711 templateEl.innerHTML = trustedHTMLFromString(html);
5712 return templateEl;
5713 }
5714 // Note that previously we used to do something like `this.inertDocument.body.innerHTML = html`
5715 // and we returned the inert `body` node. This was changed, because IE seems to treat setting
5716 // `innerHTML` on an inserted element differently, compared to one that hasn't been inserted
5717 // yet. In particular, IE appears to split some of the text into multiple text nodes rather
5718 // than keeping them in a single one which ends up messing with Ivy's i18n parsing further
5719 // down the line. This has been worked around by creating a new inert `body` and using it as
5720 // the root node in which we insert the HTML.
5721 const inertBody = this.inertDocument.createElement('body');
5722 inertBody.innerHTML = trustedHTMLFromString(html);
5723 // Support: IE 11 only
5724 // strip custom-namespaced attributes on IE<=11
5725 if (this.defaultDoc.documentMode) {
5726 this.stripCustomNsAttrs(inertBody);
5727 }
5728 return inertBody;
5729 }
5730 /**
5731 * When IE11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1'
5732 * attribute to declare ns1 namespace and prefixes the attribute with 'ns1' (e.g.
5733 * 'ns1:xlink:foo').
5734 *
5735 * This is undesirable since we don't want to allow any of these custom attributes. This method
5736 * strips them all.
5737 */
5738 stripCustomNsAttrs(el) {
5739 const elAttrs = el.attributes;
5740 // loop backwards so that we can support removals.
5741 for (let i = elAttrs.length - 1; 0 < i; i--) {
5742 const attrib = elAttrs.item(i);
5743 const attrName = attrib.name;
5744 if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) {
5745 el.removeAttribute(attrName);
5746 }
5747 }
5748 let childNode = el.firstChild;
5749 while (childNode) {
5750 if (childNode.nodeType === Node.ELEMENT_NODE)
5751 this.stripCustomNsAttrs(childNode);
5752 childNode = childNode.nextSibling;
5753 }
5754 }
5755}
5756/**
5757 * We need to determine whether the DOMParser exists in the global context and
5758 * supports parsing HTML; HTML parsing support is not as wide as other formats, see
5759 * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility.
5760 *
5761 * @suppress {uselessCode}
5762 */
5763function isDOMParserAvailable() {
5764 try {
5765 return !!new window.DOMParser().parseFromString(trustedHTMLFromString(''), 'text/html');
5766 }
5767 catch (_a) {
5768 return false;
5769 }
5770}
5771
5772/**
5773 * @license
5774 * Copyright Google LLC All Rights Reserved.
5775 *
5776 * Use of this source code is governed by an MIT-style license that can be
5777 * found in the LICENSE file at https://angular.io/license
5778 */
5779/**
5780 * A pattern that recognizes a commonly useful subset of URLs that are safe.
5781 *
5782 * This regular expression matches a subset of URLs that will not cause script
5783 * execution if used in URL context within a HTML document. Specifically, this
5784 * regular expression matches if (comment from here on and regex copied from
5785 * Soy's EscapingConventions):
5786 * (1) Either an allowed protocol (http, https, mailto or ftp).
5787 * (2) or no protocol. A protocol must be followed by a colon. The below
5788 * allows that by allowing colons only after one of the characters [/?#].
5789 * A colon after a hash (#) must be in the fragment.
5790 * Otherwise, a colon after a (?) must be in a query.
5791 * Otherwise, a colon after a single solidus (/) must be in a path.
5792 * Otherwise, a colon after a double solidus (//) must be in the authority
5793 * (before port).
5794 *
5795 * The pattern disallows &, used in HTML entity declarations before
5796 * one of the characters in [/?#]. This disallows HTML entities used in the
5797 * protocol name, which should never happen, e.g. "h&#116;tp" for "http".
5798 * It also disallows HTML entities in the first path part of a relative path,
5799 * e.g. "foo&lt;bar/baz". Our existing escaping functions should not produce
5800 * that. More importantly, it disallows masking of a colon,
5801 * e.g. "javascript&#58;...".
5802 *
5803 * This regular expression was taken from the Closure sanitization library.
5804 */
5805const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi;
5806/* A pattern that matches safe srcset values */
5807const SAFE_SRCSET_PATTERN = /^(?:(?:https?|file):|[^&:/?#]*(?:[/?#]|$))/gi;
5808/** A pattern that matches safe data URLs. Only matches image, video and audio types. */
5809const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+\/]+=*$/i;
5810function _sanitizeUrl(url) {
5811 url = String(url);
5812 if (url.match(SAFE_URL_PATTERN) || url.match(DATA_URL_PATTERN))
5813 return url;
5814 if (typeof ngDevMode === 'undefined' || ngDevMode) {
5815 console.warn(`WARNING: sanitizing unsafe URL value ${url} (see https://g.co/ng/security#xss)`);
5816 }
5817 return 'unsafe:' + url;
5818}
5819function sanitizeSrcset(srcset) {
5820 srcset = String(srcset);
5821 return srcset.split(',').map((srcset) => _sanitizeUrl(srcset.trim())).join(', ');
5822}
5823
5824/**
5825 * @license
5826 * Copyright Google LLC All Rights Reserved.
5827 *
5828 * Use of this source code is governed by an MIT-style license that can be
5829 * found in the LICENSE file at https://angular.io/license
5830 */
5831function tagSet(tags) {
5832 const res = {};
5833 for (const t of tags.split(','))
5834 res[t] = true;
5835 return res;
5836}
5837function merge(...sets) {
5838 const res = {};
5839 for (const s of sets) {
5840 for (const v in s) {
5841 if (s.hasOwnProperty(v))
5842 res[v] = true;
5843 }
5844 }
5845 return res;
5846}
5847// Good source of info about elements and attributes
5848// https://html.spec.whatwg.org/#semantics
5849// https://simon.html5.org/html-elements
5850// Safe Void Elements - HTML5
5851// https://html.spec.whatwg.org/#void-elements
5852const VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr');
5853// Elements that you can, intentionally, leave open (and which close themselves)
5854// https://html.spec.whatwg.org/#optional-tags
5855const OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr');
5856const OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt');
5857const OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS);
5858// Safe Block Elements - HTML5
5859const BLOCK_ELEMENTS = merge(OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet('address,article,' +
5860 'aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
5861 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul'));
5862// Inline Elements - HTML5
5863const INLINE_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet('a,abbr,acronym,audio,b,' +
5864 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' +
5865 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video'));
5866const VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS);
5867// Attributes that have href and hence need to be sanitized
5868const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
5869// Attributes that have special href set hence need to be sanitized
5870const SRCSET_ATTRS = tagSet('srcset');
5871const HTML_ATTRS = tagSet('abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' +
5872 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' +
5873 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' +
5874 'scope,scrolling,shape,size,sizes,span,srclang,start,summary,tabindex,target,title,translate,type,usemap,' +
5875 'valign,value,vspace,width');
5876// Accessibility attributes as per WAI-ARIA 1.1 (W3C Working Draft 14 December 2018)
5877const ARIA_ATTRS = tagSet('aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,' +
5878 'aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,' +
5879 'aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,' +
5880 'aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,' +
5881 'aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,' +
5882 'aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,' +
5883 'aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext');
5884// NB: This currently consciously doesn't support SVG. SVG sanitization has had several security
5885// issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via
5886// innerHTML is required, SVG attributes should be added here.
5887// NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those
5888// can be sanitized, but they increase security surface area without a legitimate use case, so they
5889// are left out here.
5890const VALID_ATTRS = merge(URI_ATTRS, SRCSET_ATTRS, HTML_ATTRS, ARIA_ATTRS);
5891// Elements whose content should not be traversed/preserved, if the elements themselves are invalid.
5892//
5893// Typically, `<invalid>Some content</invalid>` would traverse (and in this case preserve)
5894// `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we
5895// don't want to preserve the content, if the elements themselves are going to be removed.
5896const SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template');
5897/**
5898 * SanitizingHtmlSerializer serializes a DOM fragment, stripping out any unsafe elements and unsafe
5899 * attributes.
5900 */
5901class SanitizingHtmlSerializer {
5902 constructor() {
5903 // Explicitly track if something was stripped, to avoid accidentally warning of sanitization just
5904 // because characters were re-encoded.
5905 this.sanitizedSomething = false;
5906 this.buf = [];
5907 }
5908 sanitizeChildren(el) {
5909 // This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters.
5910 // However this code never accesses properties off of `document` before deleting its contents
5911 // again, so it shouldn't be vulnerable to DOM clobbering.
5912 let current = el.firstChild;
5913 let traverseContent = true;
5914 while (current) {
5915 if (current.nodeType === Node.ELEMENT_NODE) {
5916 traverseContent = this.startElement(current);
5917 }
5918 else if (current.nodeType === Node.TEXT_NODE) {
5919 this.chars(current.nodeValue);
5920 }
5921 else {
5922 // Strip non-element, non-text nodes.
5923 this.sanitizedSomething = true;
5924 }
5925 if (traverseContent && current.firstChild) {
5926 current = current.firstChild;
5927 continue;
5928 }
5929 while (current) {
5930 // Leaving the element. Walk up and to the right, closing tags as we go.
5931 if (current.nodeType === Node.ELEMENT_NODE) {
5932 this.endElement(current);
5933 }
5934 let next = this.checkClobberedElement(current, current.nextSibling);
5935 if (next) {
5936 current = next;
5937 break;
5938 }
5939 current = this.checkClobberedElement(current, current.parentNode);
5940 }
5941 }
5942 return this.buf.join('');
5943 }
5944 /**
5945 * Sanitizes an opening element tag (if valid) and returns whether the element's contents should
5946 * be traversed. Element content must always be traversed (even if the element itself is not
5947 * valid/safe), unless the element is one of `SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS`.
5948 *
5949 * @param element The element to sanitize.
5950 * @return True if the element's contents should be traversed.
5951 */
5952 startElement(element) {
5953 const tagName = element.nodeName.toLowerCase();
5954 if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
5955 this.sanitizedSomething = true;
5956 return !SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS.hasOwnProperty(tagName);
5957 }
5958 this.buf.push('<');
5959 this.buf.push(tagName);
5960 const elAttrs = element.attributes;
5961 for (let i = 0; i < elAttrs.length; i++) {
5962 const elAttr = elAttrs.item(i);
5963 const attrName = elAttr.name;
5964 const lower = attrName.toLowerCase();
5965 if (!VALID_ATTRS.hasOwnProperty(lower)) {
5966 this.sanitizedSomething = true;
5967 continue;
5968 }
5969 let value = elAttr.value;
5970 // TODO(martinprobst): Special case image URIs for data:image/...
5971 if (URI_ATTRS[lower])
5972 value = _sanitizeUrl(value);
5973 if (SRCSET_ATTRS[lower])
5974 value = sanitizeSrcset(value);
5975 this.buf.push(' ', attrName, '="', encodeEntities(value), '"');
5976 }
5977 this.buf.push('>');
5978 return true;
5979 }
5980 endElement(current) {
5981 const tagName = current.nodeName.toLowerCase();
5982 if (VALID_ELEMENTS.hasOwnProperty(tagName) && !VOID_ELEMENTS.hasOwnProperty(tagName)) {
5983 this.buf.push('</');
5984 this.buf.push(tagName);
5985 this.buf.push('>');
5986 }
5987 }
5988 chars(chars) {
5989 this.buf.push(encodeEntities(chars));
5990 }
5991 checkClobberedElement(node, nextNode) {
5992 if (nextNode &&
5993 (node.compareDocumentPosition(nextNode) &
5994 Node.DOCUMENT_POSITION_CONTAINED_BY) === Node.DOCUMENT_POSITION_CONTAINED_BY) {
5995 throw new Error(`Failed to sanitize html because the element is clobbered: ${node.outerHTML}`);
5996 }
5997 return nextNode;
5998 }
5999}
6000// Regular Expressions for parsing tags and attributes
6001const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
6002// ! to ~ is the ASCII range.
6003const NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
6004/**
6005 * Escapes all potentially dangerous characters, so that the
6006 * resulting string can be safely inserted into attribute or
6007 * element text.
6008 * @param value
6009 */
6010function encodeEntities(value) {
6011 return value.replace(/&/g, '&amp;')
6012 .replace(SURROGATE_PAIR_REGEXP, function (match) {
6013 const hi = match.charCodeAt(0);
6014 const low = match.charCodeAt(1);
6015 return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
6016 })
6017 .replace(NON_ALPHANUMERIC_REGEXP, function (match) {
6018 return '&#' + match.charCodeAt(0) + ';';
6019 })
6020 .replace(/</g, '&lt;')
6021 .replace(/>/g, '&gt;');
6022}
6023let inertBodyHelper;
6024/**
6025 * Sanitizes the given unsafe, untrusted HTML fragment, and returns HTML text that is safe to add to
6026 * the DOM in a browser environment.
6027 */
6028function _sanitizeHtml(defaultDoc, unsafeHtmlInput) {
6029 let inertBodyElement = null;
6030 try {
6031 inertBodyHelper = inertBodyHelper || getInertBodyHelper(defaultDoc);
6032 // Make sure unsafeHtml is actually a string (TypeScript types are not enforced at runtime).
6033 let unsafeHtml = unsafeHtmlInput ? String(unsafeHtmlInput) : '';
6034 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
6035 // mXSS protection. Repeatedly parse the document to make sure it stabilizes, so that a browser
6036 // trying to auto-correct incorrect HTML cannot cause formerly inert HTML to become dangerous.
6037 let mXSSAttempts = 5;
6038 let parsedHtml = unsafeHtml;
6039 do {
6040 if (mXSSAttempts === 0) {
6041 throw new Error('Failed to sanitize html because the input is unstable');
6042 }
6043 mXSSAttempts--;
6044 unsafeHtml = parsedHtml;
6045 parsedHtml = inertBodyElement.innerHTML;
6046 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
6047 } while (unsafeHtml !== parsedHtml);
6048 const sanitizer = new SanitizingHtmlSerializer();
6049 const safeHtml = sanitizer.sanitizeChildren(getTemplateContent(inertBodyElement) || inertBodyElement);
6050 if ((typeof ngDevMode === 'undefined' || ngDevMode) && sanitizer.sanitizedSomething) {
6051 console.warn('WARNING: sanitizing HTML stripped some content, see https://g.co/ng/security#xss');
6052 }
6053 return trustedHTMLFromString(safeHtml);
6054 }
6055 finally {
6056 // In case anything goes wrong, clear out inertElement to reset the entire DOM structure.
6057 if (inertBodyElement) {
6058 const parent = getTemplateContent(inertBodyElement) || inertBodyElement;
6059 while (parent.firstChild) {
6060 parent.removeChild(parent.firstChild);
6061 }
6062 }
6063 }
6064}
6065function getTemplateContent(el) {
6066 return 'content' in el /** Microsoft/TypeScript#21517 */ && isTemplateElement(el) ?
6067 el.content :
6068 null;
6069}
6070function isTemplateElement(el) {
6071 return el.nodeType === Node.ELEMENT_NODE && el.nodeName === 'TEMPLATE';
6072}
6073
6074/**
6075 * @license
6076 * Copyright Google LLC All Rights Reserved.
6077 *
6078 * Use of this source code is governed by an MIT-style license that can be
6079 * found in the LICENSE file at https://angular.io/license
6080 */
6081/**
6082 * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
6083 * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
6084 * handled.
6085 *
6086 * See DomSanitizer for more details on security in Angular applications.
6087 *
6088 * @publicApi
6089 */
6090var SecurityContext;
6091(function (SecurityContext) {
6092 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
6093 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
6094 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
6095 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
6096 SecurityContext[SecurityContext["URL"] = 4] = "URL";
6097 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
6098})(SecurityContext || (SecurityContext = {}));
6099
6100/**
6101 * @license
6102 * Copyright Google LLC All Rights Reserved.
6103 *
6104 * Use of this source code is governed by an MIT-style license that can be
6105 * found in the LICENSE file at https://angular.io/license
6106 */
6107/**
6108 * An `html` sanitizer which converts untrusted `html` **string** into trusted string by removing
6109 * dangerous content.
6110 *
6111 * This method parses the `html` and locates potentially dangerous content (such as urls and
6112 * javascript) and removes it.
6113 *
6114 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustHtml}.
6115 *
6116 * @param unsafeHtml untrusted `html`, typically from the user.
6117 * @returns `html` string which is safe to display to user, because all of the dangerous javascript
6118 * and urls have been removed.
6119 *
6120 * @codeGenApi
6121 */
6122function ɵɵsanitizeHtml(unsafeHtml) {
6123 const sanitizer = getSanitizer();
6124 if (sanitizer) {
6125 return trustedHTMLFromStringBypass(sanitizer.sanitize(SecurityContext.HTML, unsafeHtml) || '');
6126 }
6127 if (allowSanitizationBypassAndThrow(unsafeHtml, "HTML" /* BypassType.Html */)) {
6128 return trustedHTMLFromStringBypass(unwrapSafeValue(unsafeHtml));
6129 }
6130 return _sanitizeHtml(getDocument(), renderStringify(unsafeHtml));
6131}
6132/**
6133 * A `style` sanitizer which converts untrusted `style` **string** into trusted string by removing
6134 * dangerous content.
6135 *
6136 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustStyle}.
6137 *
6138 * @param unsafeStyle untrusted `style`, typically from the user.
6139 * @returns `style` string which is safe to bind to the `style` properties.
6140 *
6141 * @codeGenApi
6142 */
6143function ɵɵsanitizeStyle(unsafeStyle) {
6144 const sanitizer = getSanitizer();
6145 if (sanitizer) {
6146 return sanitizer.sanitize(SecurityContext.STYLE, unsafeStyle) || '';
6147 }
6148 if (allowSanitizationBypassAndThrow(unsafeStyle, "Style" /* BypassType.Style */)) {
6149 return unwrapSafeValue(unsafeStyle);
6150 }
6151 return renderStringify(unsafeStyle);
6152}
6153/**
6154 * A `url` sanitizer which converts untrusted `url` **string** into trusted string by removing
6155 * dangerous
6156 * content.
6157 *
6158 * This method parses the `url` and locates potentially dangerous content (such as javascript) and
6159 * removes it.
6160 *
6161 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustUrl}.
6162 *
6163 * @param unsafeUrl untrusted `url`, typically from the user.
6164 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
6165 * all of the dangerous javascript has been removed.
6166 *
6167 * @codeGenApi
6168 */
6169function ɵɵsanitizeUrl(unsafeUrl) {
6170 const sanitizer = getSanitizer();
6171 if (sanitizer) {
6172 return sanitizer.sanitize(SecurityContext.URL, unsafeUrl) || '';
6173 }
6174 if (allowSanitizationBypassAndThrow(unsafeUrl, "URL" /* BypassType.Url */)) {
6175 return unwrapSafeValue(unsafeUrl);
6176 }
6177 return _sanitizeUrl(renderStringify(unsafeUrl));
6178}
6179/**
6180 * A `url` sanitizer which only lets trusted `url`s through.
6181 *
6182 * This passes only `url`s marked trusted by calling {@link bypassSanitizationTrustResourceUrl}.
6183 *
6184 * @param unsafeResourceUrl untrusted `url`, typically from the user.
6185 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
6186 * only trusted `url`s have been allowed to pass.
6187 *
6188 * @codeGenApi
6189 */
6190function ɵɵsanitizeResourceUrl(unsafeResourceUrl) {
6191 const sanitizer = getSanitizer();
6192 if (sanitizer) {
6193 return trustedScriptURLFromStringBypass(sanitizer.sanitize(SecurityContext.RESOURCE_URL, unsafeResourceUrl) || '');
6194 }
6195 if (allowSanitizationBypassAndThrow(unsafeResourceUrl, "ResourceURL" /* BypassType.ResourceUrl */)) {
6196 return trustedScriptURLFromStringBypass(unwrapSafeValue(unsafeResourceUrl));
6197 }
6198 throw new RuntimeError(904 /* RuntimeErrorCode.UNSAFE_VALUE_IN_RESOURCE_URL */, ngDevMode &&
6199 'unsafe value used in a resource URL context (see https://g.co/ng/security#xss)');
6200}
6201/**
6202 * A `script` sanitizer which only lets trusted javascript through.
6203 *
6204 * This passes only `script`s marked trusted by calling {@link
6205 * bypassSanitizationTrustScript}.
6206 *
6207 * @param unsafeScript untrusted `script`, typically from the user.
6208 * @returns `url` string which is safe to bind to the `<script>` element such as `<img src>`,
6209 * because only trusted `scripts` have been allowed to pass.
6210 *
6211 * @codeGenApi
6212 */
6213function ɵɵsanitizeScript(unsafeScript) {
6214 const sanitizer = getSanitizer();
6215 if (sanitizer) {
6216 return trustedScriptFromStringBypass(sanitizer.sanitize(SecurityContext.SCRIPT, unsafeScript) || '');
6217 }
6218 if (allowSanitizationBypassAndThrow(unsafeScript, "Script" /* BypassType.Script */)) {
6219 return trustedScriptFromStringBypass(unwrapSafeValue(unsafeScript));
6220 }
6221 throw new RuntimeError(905 /* RuntimeErrorCode.UNSAFE_VALUE_IN_SCRIPT */, ngDevMode && 'unsafe value used in a script context');
6222}
6223/**
6224 * A template tag function for promoting the associated constant literal to a
6225 * TrustedHTML. Interpolation is explicitly not allowed.
6226 *
6227 * @param html constant template literal containing trusted HTML.
6228 * @returns TrustedHTML wrapping `html`.
6229 *
6230 * @security This is a security-sensitive function and should only be used to
6231 * convert constant values of attributes and properties found in
6232 * application-provided Angular templates to TrustedHTML.
6233 *
6234 * @codeGenApi
6235 */
6236function ɵɵtrustConstantHtml(html) {
6237 // The following runtime check ensures that the function was called as a
6238 // template tag (e.g. ɵɵtrustConstantHtml`content`), without any interpolation
6239 // (e.g. not ɵɵtrustConstantHtml`content ${variable}`). A TemplateStringsArray
6240 // is an array with a `raw` property that is also an array. The associated
6241 // template literal has no interpolation if and only if the length of the
6242 // TemplateStringsArray is 1.
6243 if (ngDevMode && (!Array.isArray(html) || !Array.isArray(html.raw) || html.length !== 1)) {
6244 throw new Error(`Unexpected interpolation in trusted HTML constant: ${html.join('?')}`);
6245 }
6246 return trustedHTMLFromString(html[0]);
6247}
6248/**
6249 * A template tag function for promoting the associated constant literal to a
6250 * TrustedScriptURL. Interpolation is explicitly not allowed.
6251 *
6252 * @param url constant template literal containing a trusted script URL.
6253 * @returns TrustedScriptURL wrapping `url`.
6254 *
6255 * @security This is a security-sensitive function and should only be used to
6256 * convert constant values of attributes and properties found in
6257 * application-provided Angular templates to TrustedScriptURL.
6258 *
6259 * @codeGenApi
6260 */
6261function ɵɵtrustConstantResourceUrl(url) {
6262 // The following runtime check ensures that the function was called as a
6263 // template tag (e.g. ɵɵtrustConstantResourceUrl`content`), without any
6264 // interpolation (e.g. not ɵɵtrustConstantResourceUrl`content ${variable}`). A
6265 // TemplateStringsArray is an array with a `raw` property that is also an
6266 // array. The associated template literal has no interpolation if and only if
6267 // the length of the TemplateStringsArray is 1.
6268 if (ngDevMode && (!Array.isArray(url) || !Array.isArray(url.raw) || url.length !== 1)) {
6269 throw new Error(`Unexpected interpolation in trusted URL constant: ${url.join('?')}`);
6270 }
6271 return trustedScriptURLFromString(url[0]);
6272}
6273/**
6274 * Detects which sanitizer to use for URL property, based on tag name and prop name.
6275 *
6276 * The rules are based on the RESOURCE_URL context config from
6277 * `packages/compiler/src/schema/dom_security_schema.ts`.
6278 * If tag and prop names don't match Resource URL schema, use URL sanitizer.
6279 */
6280function getUrlSanitizer(tag, prop) {
6281 if ((prop === 'src' &&
6282 (tag === 'embed' || tag === 'frame' || tag === 'iframe' || tag === 'media' ||
6283 tag === 'script')) ||
6284 (prop === 'href' && (tag === 'base' || tag === 'link'))) {
6285 return ɵɵsanitizeResourceUrl;
6286 }
6287 return ɵɵsanitizeUrl;
6288}
6289/**
6290 * Sanitizes URL, selecting sanitizer function based on tag and property names.
6291 *
6292 * This function is used in case we can't define security context at compile time, when only prop
6293 * name is available. This happens when we generate host bindings for Directives/Components. The
6294 * host element is unknown at compile time, so we defer calculation of specific sanitizer to
6295 * runtime.
6296 *
6297 * @param unsafeUrl untrusted `url`, typically from the user.
6298 * @param tag target element tag name.
6299 * @param prop name of the property that contains the value.
6300 * @returns `url` string which is safe to bind.
6301 *
6302 * @codeGenApi
6303 */
6304function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl, tag, prop) {
6305 return getUrlSanitizer(tag, prop)(unsafeUrl);
6306}
6307function validateAgainstEventProperties(name) {
6308 if (name.toLowerCase().startsWith('on')) {
6309 const errorMessage = `Binding to event property '${name}' is disallowed for security reasons, ` +
6310 `please use (${name.slice(2)})=...` +
6311 `\nIf '${name}' is a directive input, make sure the directive is imported by the` +
6312 ` current module.`;
6313 throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
6314 }
6315}
6316function validateAgainstEventAttributes(name) {
6317 if (name.toLowerCase().startsWith('on')) {
6318 const errorMessage = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
6319 `please use (${name.slice(2)})=...`;
6320 throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
6321 }
6322}
6323function getSanitizer() {
6324 const lView = getLView();
6325 return lView && lView[SANITIZER];
6326}
6327
6328/**
6329 * @license
6330 * Copyright Google LLC All Rights Reserved.
6331 *
6332 * Use of this source code is governed by an MIT-style license that can be
6333 * found in the LICENSE file at https://angular.io/license
6334 */
6335const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
6336function wrappedError(message, originalError) {
6337 const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
6338 const error = Error(msg);
6339 error[ERROR_ORIGINAL_ERROR] = originalError;
6340 return error;
6341}
6342function getOriginalError(error) {
6343 return error[ERROR_ORIGINAL_ERROR];
6344}
6345
6346/**
6347 * @license
6348 * Copyright Google LLC All Rights Reserved.
6349 *
6350 * Use of this source code is governed by an MIT-style license that can be
6351 * found in the LICENSE file at https://angular.io/license
6352 */
6353/**
6354 * Provides a hook for centralized exception handling.
6355 *
6356 * The default implementation of `ErrorHandler` prints error messages to the `console`. To
6357 * intercept error handling, write a custom exception handler that replaces this default as
6358 * appropriate for your app.
6359 *
6360 * @usageNotes
6361 * ### Example
6362 *
6363 * ```
6364 * class MyErrorHandler implements ErrorHandler {
6365 * handleError(error) {
6366 * // do something with the exception
6367 * }
6368 * }
6369 *
6370 * @NgModule({
6371 * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
6372 * })
6373 * class MyModule {}
6374 * ```
6375 *
6376 * @publicApi
6377 */
6378class ErrorHandler {
6379 constructor() {
6380 /**
6381 * @internal
6382 */
6383 this._console = console;
6384 }
6385 handleError(error) {
6386 const originalError = this._findOriginalError(error);
6387 this._console.error('ERROR', error);
6388 if (originalError) {
6389 this._console.error('ORIGINAL ERROR', originalError);
6390 }
6391 }
6392 /** @internal */
6393 _findOriginalError(error) {
6394 let e = error && getOriginalError(error);
6395 while (e && getOriginalError(e)) {
6396 e = getOriginalError(e);
6397 }
6398 return e || null;
6399 }
6400}
6401
6402/**
6403 * @license
6404 * Copyright Google LLC All Rights Reserved.
6405 *
6406 * Use of this source code is governed by an MIT-style license that can be
6407 * found in the LICENSE file at https://angular.io/license
6408 */
6409/**
6410 * Disallowed strings in the comment.
6411 *
6412 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
6413 */
6414const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
6415/**
6416 * Delimiter in the disallowed strings which needs to be wrapped with zero with character.
6417 */
6418const COMMENT_DELIMITER = /(<|>)/;
6419const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
6420/**
6421 * Escape the content of comment strings so that it can be safely inserted into a comment node.
6422 *
6423 * The issue is that HTML does not specify any way to escape comment end text inside the comment.
6424 * Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
6425 * "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
6426 * can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
6427 *
6428 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
6429 *
6430 * ```
6431 * div.innerHTML = div.innerHTML
6432 * ```
6433 *
6434 * One would expect that the above code would be safe to do, but it turns out that because comment
6435 * text is not escaped, the comment may contain text which will prematurely close the comment
6436 * opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
6437 * may contain such text and expect them to be safe.)
6438 *
6439 * This function escapes the comment text by looking for comment delimiters (`<` and `>`) and
6440 * surrounding them with `_>_` where the `_` is a zero width space `\u200B`. The result is that if a
6441 * comment contains any of the comment start/end delimiters (such as `<!--`, `-->` or `--!>`) the
6442 * text it will render normally but it will not cause the HTML parser to close/open the comment.
6443 *
6444 * @param value text to make safe for comment node by escaping the comment open/close character
6445 * sequence.
6446 */
6447function escapeCommentText(value) {
6448 return value.replace(COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED));
6449}
6450
6451/**
6452 * @license
6453 * Copyright Google LLC All Rights Reserved.
6454 *
6455 * Use of this source code is governed by an MIT-style license that can be
6456 * found in the LICENSE file at https://angular.io/license
6457 */
6458function normalizeDebugBindingName(name) {
6459 // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
6460 name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
6461 return `ng-reflect-${name}`;
6462}
6463const CAMEL_CASE_REGEXP = /([A-Z])/g;
6464function camelCaseToDashCase(input) {
6465 return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
6466}
6467function normalizeDebugBindingValue(value) {
6468 try {
6469 // Limit the size of the value as otherwise the DOM just gets polluted.
6470 return value != null ? value.toString().slice(0, 30) : value;
6471 }
6472 catch (e) {
6473 return '[ERROR] Exception while trying to serialize the value';
6474 }
6475}
6476
6477/**
6478 * @license
6479 * Copyright Google LLC All Rights Reserved.
6480 *
6481 * Use of this source code is governed by an MIT-style license that can be
6482 * found in the LICENSE file at https://angular.io/license
6483 */
6484// Keeps track of the currently-active LViews.
6485const TRACKED_LVIEWS = new Map();
6486// Used for generating unique IDs for LViews.
6487let uniqueIdCounter = 0;
6488/** Gets a unique ID that can be assigned to an LView. */
6489function getUniqueLViewId() {
6490 return uniqueIdCounter++;
6491}
6492/** Starts tracking an LView. */
6493function registerLView(lView) {
6494 ngDevMode && assertNumber(lView[ID], 'LView must have an ID in order to be registered');
6495 TRACKED_LVIEWS.set(lView[ID], lView);
6496}
6497/** Gets an LView by its unique ID. */
6498function getLViewById(id) {
6499 ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number');
6500 return TRACKED_LVIEWS.get(id) || null;
6501}
6502/** Stops tracking an LView. */
6503function unregisterLView(lView) {
6504 ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID');
6505 TRACKED_LVIEWS.delete(lView[ID]);
6506}
6507
6508/**
6509 * @license
6510 * Copyright Google LLC All Rights Reserved.
6511 *
6512 * Use of this source code is governed by an MIT-style license that can be
6513 * found in the LICENSE file at https://angular.io/license
6514 */
6515/**
6516 * The internal view context which is specific to a given DOM element, directive or
6517 * component instance. Each value in here (besides the LView and element node details)
6518 * can be present, null or undefined. If undefined then it implies the value has not been
6519 * looked up yet, otherwise, if null, then a lookup was executed and nothing was found.
6520 *
6521 * Each value will get filled when the respective value is examined within the getContext
6522 * function. The component, element and each directive instance will share the same instance
6523 * of the context.
6524 */
6525class LContext {
6526 constructor(
6527 /**
6528 * ID of the component's parent view data.
6529 */
6530 lViewId,
6531 /**
6532 * The index instance of the node.
6533 */
6534 nodeIndex,
6535 /**
6536 * The instance of the DOM node that is attached to the lNode.
6537 */
6538 native) {
6539 this.lViewId = lViewId;
6540 this.nodeIndex = nodeIndex;
6541 this.native = native;
6542 }
6543 /** Component's parent view data. */
6544 get lView() {
6545 return getLViewById(this.lViewId);
6546 }
6547}
6548
6549/**
6550 * @license
6551 * Copyright Google LLC All Rights Reserved.
6552 *
6553 * Use of this source code is governed by an MIT-style license that can be
6554 * found in the LICENSE file at https://angular.io/license
6555 */
6556/**
6557 * Returns the matching `LContext` data for a given DOM node, directive or component instance.
6558 *
6559 * This function will examine the provided DOM element, component, or directive instance\'s
6560 * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched
6561 * value will be that of the newly created `LContext`.
6562 *
6563 * If the monkey-patched value is the `LView` instance then the context value for that
6564 * target will be created and the monkey-patch reference will be updated. Therefore when this
6565 * function is called it may mutate the provided element\'s, component\'s or any of the associated
6566 * directive\'s monkey-patch values.
6567 *
6568 * If the monkey-patch value is not detected then the code will walk up the DOM until an element
6569 * is found which contains a monkey-patch reference. When that occurs then the provided element
6570 * will be updated with a new context (which is then returned). If the monkey-patch value is not
6571 * detected for a component/directive instance then it will throw an error (all components and
6572 * directives should be automatically monkey-patched by ivy).
6573 *
6574 * @param target Component, Directive or DOM Node.
6575 */
6576function getLContext(target) {
6577 let mpValue = readPatchedData(target);
6578 if (mpValue) {
6579 // only when it's an array is it considered an LView instance
6580 // ... otherwise it's an already constructed LContext instance
6581 if (isLView(mpValue)) {
6582 const lView = mpValue;
6583 let nodeIndex;
6584 let component = undefined;
6585 let directives = undefined;
6586 if (isComponentInstance(target)) {
6587 nodeIndex = findViaComponent(lView, target);
6588 if (nodeIndex == -1) {
6589 throw new Error('The provided component was not found in the application');
6590 }
6591 component = target;
6592 }
6593 else if (isDirectiveInstance(target)) {
6594 nodeIndex = findViaDirective(lView, target);
6595 if (nodeIndex == -1) {
6596 throw new Error('The provided directive was not found in the application');
6597 }
6598 directives = getDirectivesAtNodeIndex(nodeIndex, lView, false);
6599 }
6600 else {
6601 nodeIndex = findViaNativeElement(lView, target);
6602 if (nodeIndex == -1) {
6603 return null;
6604 }
6605 }
6606 // the goal is not to fill the entire context full of data because the lookups
6607 // are expensive. Instead, only the target data (the element, component, container, ICU
6608 // expression or directive details) are filled into the context. If called multiple times
6609 // with different target values then the missing target data will be filled in.
6610 const native = unwrapRNode(lView[nodeIndex]);
6611 const existingCtx = readPatchedData(native);
6612 const context = (existingCtx && !Array.isArray(existingCtx)) ?
6613 existingCtx :
6614 createLContext(lView, nodeIndex, native);
6615 // only when the component has been discovered then update the monkey-patch
6616 if (component && context.component === undefined) {
6617 context.component = component;
6618 attachPatchData(context.component, context);
6619 }
6620 // only when the directives have been discovered then update the monkey-patch
6621 if (directives && context.directives === undefined) {
6622 context.directives = directives;
6623 for (let i = 0; i < directives.length; i++) {
6624 attachPatchData(directives[i], context);
6625 }
6626 }
6627 attachPatchData(context.native, context);
6628 mpValue = context;
6629 }
6630 }
6631 else {
6632 const rElement = target;
6633 ngDevMode && assertDomNode(rElement);
6634 // if the context is not found then we need to traverse upwards up the DOM
6635 // to find the nearest element that has already been monkey patched with data
6636 let parent = rElement;
6637 while (parent = parent.parentNode) {
6638 const parentContext = readPatchedData(parent);
6639 if (parentContext) {
6640 const lView = Array.isArray(parentContext) ? parentContext : parentContext.lView;
6641 // the edge of the app was also reached here through another means
6642 // (maybe because the DOM was changed manually).
6643 if (!lView) {
6644 return null;
6645 }
6646 const index = findViaNativeElement(lView, rElement);
6647 if (index >= 0) {
6648 const native = unwrapRNode(lView[index]);
6649 const context = createLContext(lView, index, native);
6650 attachPatchData(native, context);
6651 mpValue = context;
6652 break;
6653 }
6654 }
6655 }
6656 }
6657 return mpValue || null;
6658}
6659/**
6660 * Creates an empty instance of a `LContext` context
6661 */
6662function createLContext(lView, nodeIndex, native) {
6663 return new LContext(lView[ID], nodeIndex, native);
6664}
6665/**
6666 * Takes a component instance and returns the view for that component.
6667 *
6668 * @param componentInstance
6669 * @returns The component's view
6670 */
6671function getComponentViewByInstance(componentInstance) {
6672 let patchedData = readPatchedData(componentInstance);
6673 let lView;
6674 if (isLView(patchedData)) {
6675 const contextLView = patchedData;
6676 const nodeIndex = findViaComponent(contextLView, componentInstance);
6677 lView = getComponentLViewByIndex(nodeIndex, contextLView);
6678 const context = createLContext(contextLView, nodeIndex, lView[HOST]);
6679 context.component = componentInstance;
6680 attachPatchData(componentInstance, context);
6681 attachPatchData(context.native, context);
6682 }
6683 else {
6684 const context = patchedData;
6685 const contextLView = context.lView;
6686 ngDevMode && assertLView(contextLView);
6687 lView = getComponentLViewByIndex(context.nodeIndex, contextLView);
6688 }
6689 return lView;
6690}
6691/**
6692 * This property will be monkey-patched on elements, components and directives.
6693 */
6694const MONKEY_PATCH_KEY_NAME = '__ngContext__';
6695/**
6696 * Assigns the given data to the given target (which could be a component,
6697 * directive or DOM node instance) using monkey-patching.
6698 */
6699function attachPatchData(target, data) {
6700 ngDevMode && assertDefined(target, 'Target expected');
6701 // Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this
6702 // for `LView`, because we have control over when an `LView` is created and destroyed, whereas
6703 // we can't know when to remove an `LContext`.
6704 if (isLView(data)) {
6705 target[MONKEY_PATCH_KEY_NAME] = data[ID];
6706 registerLView(data);
6707 }
6708 else {
6709 target[MONKEY_PATCH_KEY_NAME] = data;
6710 }
6711}
6712/**
6713 * Returns the monkey-patch value data present on the target (which could be
6714 * a component, directive or a DOM node).
6715 */
6716function readPatchedData(target) {
6717 ngDevMode && assertDefined(target, 'Target expected');
6718 const data = target[MONKEY_PATCH_KEY_NAME];
6719 return (typeof data === 'number') ? getLViewById(data) : data || null;
6720}
6721function readPatchedLView(target) {
6722 const value = readPatchedData(target);
6723 if (value) {
6724 return (isLView(value) ? value : value.lView);
6725 }
6726 return null;
6727}
6728function isComponentInstance(instance) {
6729 return instance && instance.constructor && instance.constructor.ɵcmp;
6730}
6731function isDirectiveInstance(instance) {
6732 return instance && instance.constructor && instance.constructor.ɵdir;
6733}
6734/**
6735 * Locates the element within the given LView and returns the matching index
6736 */
6737function findViaNativeElement(lView, target) {
6738 const tView = lView[TVIEW];
6739 for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
6740 if (unwrapRNode(lView[i]) === target) {
6741 return i;
6742 }
6743 }
6744 return -1;
6745}
6746/**
6747 * Locates the next tNode (child, sibling or parent).
6748 */
6749function traverseNextElement(tNode) {
6750 if (tNode.child) {
6751 return tNode.child;
6752 }
6753 else if (tNode.next) {
6754 return tNode.next;
6755 }
6756 else {
6757 // Let's take the following template: <div><span>text</span></div><component/>
6758 // After checking the text node, we need to find the next parent that has a "next" TNode,
6759 // in this case the parent `div`, so that we can find the component.
6760 while (tNode.parent && !tNode.parent.next) {
6761 tNode = tNode.parent;
6762 }
6763 return tNode.parent && tNode.parent.next;
6764 }
6765}
6766/**
6767 * Locates the component within the given LView and returns the matching index
6768 */
6769function findViaComponent(lView, componentInstance) {
6770 const componentIndices = lView[TVIEW].components;
6771 if (componentIndices) {
6772 for (let i = 0; i < componentIndices.length; i++) {
6773 const elementComponentIndex = componentIndices[i];
6774 const componentView = getComponentLViewByIndex(elementComponentIndex, lView);
6775 if (componentView[CONTEXT] === componentInstance) {
6776 return elementComponentIndex;
6777 }
6778 }
6779 }
6780 else {
6781 const rootComponentView = getComponentLViewByIndex(HEADER_OFFSET, lView);
6782 const rootComponent = rootComponentView[CONTEXT];
6783 if (rootComponent === componentInstance) {
6784 // we are dealing with the root element here therefore we know that the
6785 // element is the very first element after the HEADER data in the lView
6786 return HEADER_OFFSET;
6787 }
6788 }
6789 return -1;
6790}
6791/**
6792 * Locates the directive within the given LView and returns the matching index
6793 */
6794function findViaDirective(lView, directiveInstance) {
6795 // if a directive is monkey patched then it will (by default)
6796 // have a reference to the LView of the current view. The
6797 // element bound to the directive being search lives somewhere
6798 // in the view data. We loop through the nodes and check their
6799 // list of directives for the instance.
6800 let tNode = lView[TVIEW].firstChild;
6801 while (tNode) {
6802 const directiveIndexStart = tNode.directiveStart;
6803 const directiveIndexEnd = tNode.directiveEnd;
6804 for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
6805 if (lView[i] === directiveInstance) {
6806 return tNode.index;
6807 }
6808 }
6809 tNode = traverseNextElement(tNode);
6810 }
6811 return -1;
6812}
6813/**
6814 * Returns a list of directives extracted from the given view based on the
6815 * provided list of directive index values.
6816 *
6817 * @param nodeIndex The node index
6818 * @param lView The target view data
6819 * @param includeComponents Whether or not to include components in returned directives
6820 */
6821function getDirectivesAtNodeIndex(nodeIndex, lView, includeComponents) {
6822 const tNode = lView[TVIEW].data[nodeIndex];
6823 let directiveStartIndex = tNode.directiveStart;
6824 if (directiveStartIndex == 0)
6825 return EMPTY_ARRAY;
6826 const directiveEndIndex = tNode.directiveEnd;
6827 if (!includeComponents && tNode.flags & 2 /* TNodeFlags.isComponentHost */)
6828 directiveStartIndex++;
6829 return lView.slice(directiveStartIndex, directiveEndIndex);
6830}
6831function getComponentAtNodeIndex(nodeIndex, lView) {
6832 const tNode = lView[TVIEW].data[nodeIndex];
6833 let directiveStartIndex = tNode.directiveStart;
6834 return tNode.flags & 2 /* TNodeFlags.isComponentHost */ ? lView[directiveStartIndex] : null;
6835}
6836/**
6837 * Returns a map of local references (local reference name => element or directive instance) that
6838 * exist on a given element.
6839 */
6840function discoverLocalRefs(lView, nodeIndex) {
6841 const tNode = lView[TVIEW].data[nodeIndex];
6842 if (tNode && tNode.localNames) {
6843 const result = {};
6844 let localIndex = tNode.index + 1;
6845 for (let i = 0; i < tNode.localNames.length; i += 2) {
6846 result[tNode.localNames[i]] = lView[localIndex];
6847 localIndex++;
6848 }
6849 return result;
6850 }
6851 return null;
6852}
6853
6854/**
6855 * @license
6856 * Copyright Google LLC All Rights Reserved.
6857 *
6858 * Use of this source code is governed by an MIT-style license that can be
6859 * found in the LICENSE file at https://angular.io/license
6860 */
6861const defaultScheduler = (() => (typeof requestAnimationFrame !== 'undefined' &&
6862 requestAnimationFrame || // browser only
6863 setTimeout // everything else
6864)
6865 .bind(_global))();
6866/**
6867 *
6868 * @codeGenApi
6869 */
6870function ɵɵresolveWindow(element) {
6871 return element.ownerDocument.defaultView;
6872}
6873/**
6874 *
6875 * @codeGenApi
6876 */
6877function ɵɵresolveDocument(element) {
6878 return element.ownerDocument;
6879}
6880/**
6881 *
6882 * @codeGenApi
6883 */
6884function ɵɵresolveBody(element) {
6885 return element.ownerDocument.body;
6886}
6887/**
6888 * The special delimiter we use to separate property names, prefixes, and suffixes
6889 * in property binding metadata. See storeBindingMetadata().
6890 *
6891 * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter
6892 * because it is a very uncommon character that is unlikely to be part of a user's
6893 * property names or interpolation strings. If it is in fact used in a property
6894 * binding, DebugElement.properties will not return the correct value for that
6895 * binding. However, there should be no runtime effect for real applications.
6896 *
6897 * This character is typically rendered as a question mark inside of a diamond.
6898 * See https://en.wikipedia.org/wiki/Specials_(Unicode_block)
6899 *
6900 */
6901const INTERPOLATION_DELIMITER = `�`;
6902/**
6903 * Unwrap a value which might be behind a closure (for forward declaration reasons).
6904 */
6905function maybeUnwrapFn(value) {
6906 if (value instanceof Function) {
6907 return value();
6908 }
6909 else {
6910 return value;
6911 }
6912}
6913
6914/**
6915 * @license
6916 * Copyright Google LLC All Rights Reserved.
6917 *
6918 * Use of this source code is governed by an MIT-style license that can be
6919 * found in the LICENSE file at https://angular.io/license
6920 */
6921/** Verifies that a given type is a Standalone Component. */
6922function assertStandaloneComponentType(type) {
6923 const componentDef = getComponentDef(type);
6924 if (!componentDef) {
6925 throw new RuntimeError(906 /* RuntimeErrorCode.MISSING_GENERATED_DEF */, `The ${stringifyForError(type)} is not an Angular component, ` +
6926 `make sure it has the \`@Component\` decorator.`);
6927 }
6928 if (!componentDef.standalone) {
6929 throw new RuntimeError(907 /* RuntimeErrorCode.TYPE_IS_NOT_STANDALONE */, `The ${stringifyForError(type)} component is not marked as standalone, ` +
6930 `but Angular expects to have a standalone component here. ` +
6931 `Please make sure the ${stringifyForError(type)} component has ` +
6932 `the \`standalone: true\` flag in the decorator.`);
6933 }
6934}
6935/** Called when there are multiple component selectors that match a given node */
6936function throwMultipleComponentError(tNode, first, second) {
6937 throw new RuntimeError(-300 /* RuntimeErrorCode.MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
6938 `${stringifyForError(first)} and ` +
6939 `${stringifyForError(second)}`);
6940}
6941/** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
6942function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
6943 const field = propName ? ` for '${propName}'` : '';
6944 let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
6945 if (creationMode) {
6946 msg +=
6947 ` It seems like the view has been created after its parent and its children have been dirty checked.` +
6948 ` Has it been created in a change detection hook?`;
6949 }
6950 throw new RuntimeError(-100 /* RuntimeErrorCode.EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
6951}
6952function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
6953 const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
6954 let oldValue = prefix, newValue = prefix;
6955 for (let i = 0; i < chunks.length; i++) {
6956 const slotIdx = rootIndex + i;
6957 oldValue += `${lView[slotIdx]}${chunks[i]}`;
6958 newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
6959 }
6960 return { propName, oldValue, newValue };
6961}
6962/**
6963 * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
6964 * - property name (for property bindings or interpolations)
6965 * - old and new values, enriched using information from metadata
6966 *
6967 * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
6968 * function description.
6969 */
6970function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
6971 const tData = lView[TVIEW].data;
6972 const metadata = tData[bindingIndex];
6973 if (typeof metadata === 'string') {
6974 // metadata for property interpolation
6975 if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
6976 return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
6977 }
6978 // metadata for property binding
6979 return { propName: metadata, oldValue, newValue };
6980 }
6981 // metadata is not available for this expression, check if this expression is a part of the
6982 // property interpolation by going from the current binding index left and look for a string that
6983 // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
6984 // [..., 'id�Prefix � and � suffix', null, null, null, ...]
6985 if (metadata === null) {
6986 let idx = bindingIndex - 1;
6987 while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
6988 idx--;
6989 }
6990 const meta = tData[idx];
6991 if (typeof meta === 'string') {
6992 const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
6993 // first interpolation delimiter separates property name from interpolation parts (in case of
6994 // property interpolations), so we subtract one from total number of found delimiters
6995 if (matches && (matches.length - 1) > bindingIndex - idx) {
6996 return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
6997 }
6998 }
6999 }
7000 return { propName: undefined, oldValue, newValue };
7001}
7002
7003/**
7004 * @license
7005 * Copyright Google LLC All Rights Reserved.
7006 *
7007 * Use of this source code is governed by an MIT-style license that can be
7008 * found in the LICENSE file at https://angular.io/license
7009 */
7010/**
7011 * Flags for renderer-specific style modifiers.
7012 * @publicApi
7013 */
7014var RendererStyleFlags2;
7015(function (RendererStyleFlags2) {
7016 // TODO(misko): This needs to be refactored into a separate file so that it can be imported from
7017 // `node_manipulation.ts` Currently doing the import cause resolution order to change and fails
7018 // the tests. The work around is to have hard coded value in `node_manipulation.ts` for now.
7019 /**
7020 * Marks a style as important.
7021 */
7022 RendererStyleFlags2[RendererStyleFlags2["Important"] = 1] = "Important";
7023 /**
7024 * Marks a style as using dash case naming (this-is-dash-case).
7025 */
7026 RendererStyleFlags2[RendererStyleFlags2["DashCase"] = 2] = "DashCase";
7027})(RendererStyleFlags2 || (RendererStyleFlags2 = {}));
7028
7029/**
7030 * @license
7031 * Copyright Google LLC All Rights Reserved.
7032 *
7033 * Use of this source code is governed by an MIT-style license that can be
7034 * found in the LICENSE file at https://angular.io/license
7035 */
7036let _icuContainerIterate;
7037/**
7038 * Iterator which provides ability to visit all of the `TIcuContainerNode` root `RNode`s.
7039 */
7040function icuContainerIterate(tIcuContainerNode, lView) {
7041 return _icuContainerIterate(tIcuContainerNode, lView);
7042}
7043/**
7044 * Ensures that `IcuContainerVisitor`'s implementation is present.
7045 *
7046 * This function is invoked when i18n instruction comes across an ICU. The purpose is to allow the
7047 * bundler to tree shake ICU logic and only load it if ICU instruction is executed.
7048 */
7049function ensureIcuContainerVisitorLoaded(loader) {
7050 if (_icuContainerIterate === undefined) {
7051 // Do not inline this function. We want to keep `ensureIcuContainerVisitorLoaded` light, so it
7052 // can be inlined into call-site.
7053 _icuContainerIterate = loader();
7054 }
7055}
7056
7057/**
7058 * @license
7059 * Copyright Google LLC All Rights Reserved.
7060 *
7061 * Use of this source code is governed by an MIT-style license that can be
7062 * found in the LICENSE file at https://angular.io/license
7063 */
7064// Note: This hack is necessary so we don't erroneously get a circular dependency
7065// failure based on types.
7066const unusedValueExportToPlacateAjd$3 = 1;
7067
7068/**
7069 * @license
7070 * Copyright Google LLC All Rights Reserved.
7071 *
7072 * Use of this source code is governed by an MIT-style license that can be
7073 * found in the LICENSE file at https://angular.io/license
7074 */
7075/**
7076 * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of
7077 * that LContainer, which is an LView
7078 * @param lView the lView whose parent to get
7079 */
7080function getLViewParent(lView) {
7081 ngDevMode && assertLView(lView);
7082 const parent = lView[PARENT];
7083 return isLContainer(parent) ? parent[PARENT] : parent;
7084}
7085/**
7086 * Retrieve the root view from any component or `LView` by walking the parent `LView` until
7087 * reaching the root `LView`.
7088 *
7089 * @param componentOrLView any component or `LView`
7090 */
7091function getRootView(componentOrLView) {
7092 ngDevMode && assertDefined(componentOrLView, 'component');
7093 let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView);
7094 while (lView && !(lView[FLAGS] & 256 /* LViewFlags.IsRoot */)) {
7095 lView = getLViewParent(lView);
7096 }
7097 ngDevMode && assertLView(lView);
7098 return lView;
7099}
7100/**
7101 * Returns the `RootContext` instance that is associated with
7102 * the application where the target is situated. It does this by walking the parent views until it
7103 * gets to the root view, then getting the context off of that.
7104 *
7105 * @param viewOrComponent the `LView` or component to get the root context for.
7106 */
7107function getRootContext(viewOrComponent) {
7108 const rootView = getRootView(viewOrComponent);
7109 ngDevMode &&
7110 assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?');
7111 return rootView[CONTEXT];
7112}
7113/**
7114 * Gets the first `LContainer` in the LView or `null` if none exists.
7115 */
7116function getFirstLContainer(lView) {
7117 return getNearestLContainer(lView[CHILD_HEAD]);
7118}
7119/**
7120 * Gets the next `LContainer` that is a sibling of the given container.
7121 */
7122function getNextLContainer(container) {
7123 return getNearestLContainer(container[NEXT]);
7124}
7125function getNearestLContainer(viewOrContainer) {
7126 while (viewOrContainer !== null && !isLContainer(viewOrContainer)) {
7127 viewOrContainer = viewOrContainer[NEXT];
7128 }
7129 return viewOrContainer;
7130}
7131
7132/**
7133 * @license
7134 * Copyright Google LLC All Rights Reserved.
7135 *
7136 * Use of this source code is governed by an MIT-style license that can be
7137 * found in the LICENSE file at https://angular.io/license
7138 */
7139const unusedValueToPlacateAjd$2 = unusedValueExportToPlacateAjd$8 + unusedValueExportToPlacateAjd$4 + unusedValueExportToPlacateAjd$3 + unusedValueExportToPlacateAjd$6 + unusedValueExportToPlacateAjd$7;
7140/**
7141 * NOTE: for performance reasons, the possible actions are inlined within the function instead of
7142 * being passed as an argument.
7143 */
7144function applyToElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
7145 // If this slot was allocated for a text node dynamically created by i18n, the text node itself
7146 // won't be created until i18nApply() in the update block, so this node should be skipped.
7147 // For more info, see "ICU expressions should work inside an ngTemplateOutlet inside an ngFor"
7148 // in `i18n_spec.ts`.
7149 if (lNodeToHandle != null) {
7150 let lContainer;
7151 let isComponent = false;
7152 // We are expecting an RNode, but in the case of a component or LContainer the `RNode` is
7153 // wrapped in an array which needs to be unwrapped. We need to know if it is a component and if
7154 // it has LContainer so that we can process all of those cases appropriately.
7155 if (isLContainer(lNodeToHandle)) {
7156 lContainer = lNodeToHandle;
7157 }
7158 else if (isLView(lNodeToHandle)) {
7159 isComponent = true;
7160 ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView');
7161 lNodeToHandle = lNodeToHandle[HOST];
7162 }
7163 const rNode = unwrapRNode(lNodeToHandle);
7164 ngDevMode && !isProceduralRenderer(renderer) && assertDomNode(rNode);
7165 if (action === 0 /* WalkTNodeTreeAction.Create */ && parent !== null) {
7166 if (beforeNode == null) {
7167 nativeAppendChild(renderer, parent, rNode);
7168 }
7169 else {
7170 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
7171 }
7172 }
7173 else if (action === 1 /* WalkTNodeTreeAction.Insert */ && parent !== null) {
7174 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
7175 }
7176 else if (action === 2 /* WalkTNodeTreeAction.Detach */) {
7177 nativeRemoveNode(renderer, rNode, isComponent);
7178 }
7179 else if (action === 3 /* WalkTNodeTreeAction.Destroy */) {
7180 ngDevMode && ngDevMode.rendererDestroyNode++;
7181 renderer.destroyNode(rNode);
7182 }
7183 if (lContainer != null) {
7184 applyContainer(renderer, action, lContainer, parent, beforeNode);
7185 }
7186 }
7187}
7188function createTextNode(renderer, value) {
7189 ngDevMode && ngDevMode.rendererCreateTextNode++;
7190 ngDevMode && ngDevMode.rendererSetText++;
7191 return isProceduralRenderer(renderer) ? renderer.createText(value) :
7192 renderer.createTextNode(value);
7193}
7194function updateTextNode(renderer, rNode, value) {
7195 ngDevMode && ngDevMode.rendererSetText++;
7196 isProceduralRenderer(renderer) ? renderer.setValue(rNode, value) : rNode.textContent = value;
7197}
7198function createCommentNode(renderer, value) {
7199 ngDevMode && ngDevMode.rendererCreateComment++;
7200 // isProceduralRenderer check is not needed because both `Renderer2` and `Renderer3` have the same
7201 // method name.
7202 return renderer.createComment(escapeCommentText(value));
7203}
7204/**
7205 * Creates a native element from a tag name, using a renderer.
7206 * @param renderer A renderer to use
7207 * @param name the tag name
7208 * @param namespace Optional namespace for element.
7209 * @returns the element created
7210 */
7211function createElementNode(renderer, name, namespace) {
7212 ngDevMode && ngDevMode.rendererCreateElement++;
7213 if (isProceduralRenderer(renderer)) {
7214 return renderer.createElement(name, namespace);
7215 }
7216 else {
7217 const namespaceUri = namespace !== null ? getNamespaceUri(namespace) : null;
7218 return namespaceUri === null ? renderer.createElement(name) :
7219 renderer.createElementNS(namespaceUri, name);
7220 }
7221}
7222/**
7223 * Removes all DOM elements associated with a view.
7224 *
7225 * Because some root nodes of the view may be containers, we sometimes need
7226 * to propagate deeply into the nested containers to remove all elements in the
7227 * views beneath it.
7228 *
7229 * @param tView The `TView' of the `LView` from which elements should be added or removed
7230 * @param lView The view from which elements should be added or removed
7231 */
7232function removeViewFromContainer(tView, lView) {
7233 const renderer = lView[RENDERER];
7234 applyView(tView, lView, renderer, 2 /* WalkTNodeTreeAction.Detach */, null, null);
7235 lView[HOST] = null;
7236 lView[T_HOST] = null;
7237}
7238/**
7239 * Adds all DOM elements associated with a view.
7240 *
7241 * Because some root nodes of the view may be containers, we sometimes need
7242 * to propagate deeply into the nested containers to add all elements in the
7243 * views beneath it.
7244 *
7245 * @param tView The `TView' of the `LView` from which elements should be added or removed
7246 * @param parentTNode The `TNode` where the `LView` should be attached to.
7247 * @param renderer Current renderer to use for DOM manipulations.
7248 * @param lView The view from which elements should be added or removed
7249 * @param parentNativeNode The parent `RElement` where it should be inserted into.
7250 * @param beforeNode The node before which elements should be added, if insert mode
7251 */
7252function addViewToContainer(tView, parentTNode, renderer, lView, parentNativeNode, beforeNode) {
7253 lView[HOST] = parentNativeNode;
7254 lView[T_HOST] = parentTNode;
7255 applyView(tView, lView, renderer, 1 /* WalkTNodeTreeAction.Insert */, parentNativeNode, beforeNode);
7256}
7257/**
7258 * Detach a `LView` from the DOM by detaching its nodes.
7259 *
7260 * @param tView The `TView' of the `LView` to be detached
7261 * @param lView the `LView` to be detached.
7262 */
7263function renderDetachView(tView, lView) {
7264 applyView(tView, lView, lView[RENDERER], 2 /* WalkTNodeTreeAction.Detach */, null, null);
7265}
7266/**
7267 * Traverses down and up the tree of views and containers to remove listeners and
7268 * call onDestroy callbacks.
7269 *
7270 * Notes:
7271 * - Because it's used for onDestroy calls, it needs to be bottom-up.
7272 * - Must process containers instead of their views to avoid splicing
7273 * when views are destroyed and re-added.
7274 * - Using a while loop because it's faster than recursion
7275 * - Destroy only called on movement to sibling or movement to parent (laterally or up)
7276 *
7277 * @param rootView The view to destroy
7278 */
7279function destroyViewTree(rootView) {
7280 // If the view has no children, we can clean it up and return early.
7281 let lViewOrLContainer = rootView[CHILD_HEAD];
7282 if (!lViewOrLContainer) {
7283 return cleanUpView(rootView[TVIEW], rootView);
7284 }
7285 while (lViewOrLContainer) {
7286 let next = null;
7287 if (isLView(lViewOrLContainer)) {
7288 // If LView, traverse down to child.
7289 next = lViewOrLContainer[CHILD_HEAD];
7290 }
7291 else {
7292 ngDevMode && assertLContainer(lViewOrLContainer);
7293 // If container, traverse down to its first LView.
7294 const firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET];
7295 if (firstView)
7296 next = firstView;
7297 }
7298 if (!next) {
7299 // Only clean up view when moving to the side or up, as destroy hooks
7300 // should be called in order from the bottom up.
7301 while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) {
7302 if (isLView(lViewOrLContainer)) {
7303 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
7304 }
7305 lViewOrLContainer = lViewOrLContainer[PARENT];
7306 }
7307 if (lViewOrLContainer === null)
7308 lViewOrLContainer = rootView;
7309 if (isLView(lViewOrLContainer)) {
7310 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
7311 }
7312 next = lViewOrLContainer && lViewOrLContainer[NEXT];
7313 }
7314 lViewOrLContainer = next;
7315 }
7316}
7317/**
7318 * Inserts a view into a container.
7319 *
7320 * This adds the view to the container's array of active views in the correct
7321 * position. It also adds the view's elements to the DOM if the container isn't a
7322 * root node of another view (in that case, the view's elements will be added when
7323 * the container's parent view is added later).
7324 *
7325 * @param tView The `TView' of the `LView` to insert
7326 * @param lView The view to insert
7327 * @param lContainer The container into which the view should be inserted
7328 * @param index Which index in the container to insert the child view into
7329 */
7330function insertView(tView, lView, lContainer, index) {
7331 ngDevMode && assertLView(lView);
7332 ngDevMode && assertLContainer(lContainer);
7333 const indexInContainer = CONTAINER_HEADER_OFFSET + index;
7334 const containerLength = lContainer.length;
7335 if (index > 0) {
7336 // This is a new view, we need to add it to the children.
7337 lContainer[indexInContainer - 1][NEXT] = lView;
7338 }
7339 if (index < containerLength - CONTAINER_HEADER_OFFSET) {
7340 lView[NEXT] = lContainer[indexInContainer];
7341 addToArray(lContainer, CONTAINER_HEADER_OFFSET + index, lView);
7342 }
7343 else {
7344 lContainer.push(lView);
7345 lView[NEXT] = null;
7346 }
7347 lView[PARENT] = lContainer;
7348 // track views where declaration and insertion points are different
7349 const declarationLContainer = lView[DECLARATION_LCONTAINER];
7350 if (declarationLContainer !== null && lContainer !== declarationLContainer) {
7351 trackMovedView(declarationLContainer, lView);
7352 }
7353 // notify query that a new view has been added
7354 const lQueries = lView[QUERIES];
7355 if (lQueries !== null) {
7356 lQueries.insertView(tView);
7357 }
7358 // Sets the attached flag
7359 lView[FLAGS] |= 64 /* LViewFlags.Attached */;
7360}
7361/**
7362 * Track views created from the declaration container (TemplateRef) and inserted into a
7363 * different LContainer.
7364 */
7365function trackMovedView(declarationContainer, lView) {
7366 ngDevMode && assertDefined(lView, 'LView required');
7367 ngDevMode && assertLContainer(declarationContainer);
7368 const movedViews = declarationContainer[MOVED_VIEWS];
7369 const insertedLContainer = lView[PARENT];
7370 ngDevMode && assertLContainer(insertedLContainer);
7371 const insertedComponentLView = insertedLContainer[PARENT][DECLARATION_COMPONENT_VIEW];
7372 ngDevMode && assertDefined(insertedComponentLView, 'Missing insertedComponentLView');
7373 const declaredComponentLView = lView[DECLARATION_COMPONENT_VIEW];
7374 ngDevMode && assertDefined(declaredComponentLView, 'Missing declaredComponentLView');
7375 if (declaredComponentLView !== insertedComponentLView) {
7376 // At this point the declaration-component is not same as insertion-component; this means that
7377 // this is a transplanted view. Mark the declared lView as having transplanted views so that
7378 // those views can participate in CD.
7379 declarationContainer[HAS_TRANSPLANTED_VIEWS] = true;
7380 }
7381 if (movedViews === null) {
7382 declarationContainer[MOVED_VIEWS] = [lView];
7383 }
7384 else {
7385 movedViews.push(lView);
7386 }
7387}
7388function detachMovedView(declarationContainer, lView) {
7389 ngDevMode && assertLContainer(declarationContainer);
7390 ngDevMode &&
7391 assertDefined(declarationContainer[MOVED_VIEWS], 'A projected view should belong to a non-empty projected views collection');
7392 const movedViews = declarationContainer[MOVED_VIEWS];
7393 const declarationViewIndex = movedViews.indexOf(lView);
7394 const insertionLContainer = lView[PARENT];
7395 ngDevMode && assertLContainer(insertionLContainer);
7396 // If the view was marked for refresh but then detached before it was checked (where the flag
7397 // would be cleared and the counter decremented), we need to decrement the view counter here
7398 // instead.
7399 if (lView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
7400 lView[FLAGS] &= ~512 /* LViewFlags.RefreshTransplantedView */;
7401 updateTransplantedViewCount(insertionLContainer, -1);
7402 }
7403 movedViews.splice(declarationViewIndex, 1);
7404}
7405/**
7406 * Detaches a view from a container.
7407 *
7408 * This method removes the view from the container's array of active views. It also
7409 * removes the view's elements from the DOM.
7410 *
7411 * @param lContainer The container from which to detach a view
7412 * @param removeIndex The index of the view to detach
7413 * @returns Detached LView instance.
7414 */
7415function detachView(lContainer, removeIndex) {
7416 if (lContainer.length <= CONTAINER_HEADER_OFFSET)
7417 return;
7418 const indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
7419 const viewToDetach = lContainer[indexInContainer];
7420 if (viewToDetach) {
7421 const declarationLContainer = viewToDetach[DECLARATION_LCONTAINER];
7422 if (declarationLContainer !== null && declarationLContainer !== lContainer) {
7423 detachMovedView(declarationLContainer, viewToDetach);
7424 }
7425 if (removeIndex > 0) {
7426 lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT];
7427 }
7428 const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
7429 removeViewFromContainer(viewToDetach[TVIEW], viewToDetach);
7430 // notify query that a view has been removed
7431 const lQueries = removedLView[QUERIES];
7432 if (lQueries !== null) {
7433 lQueries.detachView(removedLView[TVIEW]);
7434 }
7435 viewToDetach[PARENT] = null;
7436 viewToDetach[NEXT] = null;
7437 // Unsets the attached flag
7438 viewToDetach[FLAGS] &= ~64 /* LViewFlags.Attached */;
7439 }
7440 return viewToDetach;
7441}
7442/**
7443 * A standalone function which destroys an LView,
7444 * conducting clean up (e.g. removing listeners, calling onDestroys).
7445 *
7446 * @param tView The `TView' of the `LView` to be destroyed
7447 * @param lView The view to be destroyed.
7448 */
7449function destroyLView(tView, lView) {
7450 if (!(lView[FLAGS] & 128 /* LViewFlags.Destroyed */)) {
7451 const renderer = lView[RENDERER];
7452 if (isProceduralRenderer(renderer) && renderer.destroyNode) {
7453 applyView(tView, lView, renderer, 3 /* WalkTNodeTreeAction.Destroy */, null, null);
7454 }
7455 destroyViewTree(lView);
7456 }
7457}
7458/**
7459 * Calls onDestroys hooks for all directives and pipes in a given view and then removes all
7460 * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks
7461 * can be propagated to @Output listeners.
7462 *
7463 * @param tView `TView` for the `LView` to clean up.
7464 * @param lView The LView to clean up
7465 */
7466function cleanUpView(tView, lView) {
7467 if (!(lView[FLAGS] & 128 /* LViewFlags.Destroyed */)) {
7468 // Usually the Attached flag is removed when the view is detached from its parent, however
7469 // if it's a root view, the flag won't be unset hence why we're also removing on destroy.
7470 lView[FLAGS] &= ~64 /* LViewFlags.Attached */;
7471 // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
7472 // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
7473 // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
7474 // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
7475 // really more of an "afterDestroy" hook if you think about it.
7476 lView[FLAGS] |= 128 /* LViewFlags.Destroyed */;
7477 executeOnDestroys(tView, lView);
7478 processCleanups(tView, lView);
7479 // For component views only, the local renderer is destroyed at clean up time.
7480 if (lView[TVIEW].type === 1 /* TViewType.Component */ && isProceduralRenderer(lView[RENDERER])) {
7481 ngDevMode && ngDevMode.rendererDestroy++;
7482 lView[RENDERER].destroy();
7483 }
7484 const declarationContainer = lView[DECLARATION_LCONTAINER];
7485 // we are dealing with an embedded view that is still inserted into a container
7486 if (declarationContainer !== null && isLContainer(lView[PARENT])) {
7487 // and this is a projected view
7488 if (declarationContainer !== lView[PARENT]) {
7489 detachMovedView(declarationContainer, lView);
7490 }
7491 // For embedded views still attached to a container: remove query result from this view.
7492 const lQueries = lView[QUERIES];
7493 if (lQueries !== null) {
7494 lQueries.detachView(tView);
7495 }
7496 }
7497 // Unregister the view once everything else has been cleaned up.
7498 unregisterLView(lView);
7499 }
7500}
7501/** Removes listeners and unsubscribes from output subscriptions */
7502function processCleanups(tView, lView) {
7503 const tCleanup = tView.cleanup;
7504 const lCleanup = lView[CLEANUP];
7505 // `LCleanup` contains both share information with `TCleanup` as well as instance specific
7506 // information appended at the end. We need to know where the end of the `TCleanup` information
7507 // is, and we track this with `lastLCleanupIndex`.
7508 let lastLCleanupIndex = -1;
7509 if (tCleanup !== null) {
7510 for (let i = 0; i < tCleanup.length - 1; i += 2) {
7511 if (typeof tCleanup[i] === 'string') {
7512 // This is a native DOM listener
7513 const idxOrTargetGetter = tCleanup[i + 1];
7514 const target = typeof idxOrTargetGetter === 'function' ?
7515 idxOrTargetGetter(lView) :
7516 unwrapRNode(lView[idxOrTargetGetter]);
7517 const listener = lCleanup[lastLCleanupIndex = tCleanup[i + 2]];
7518 const useCaptureOrSubIdx = tCleanup[i + 3];
7519 if (typeof useCaptureOrSubIdx === 'boolean') {
7520 // native DOM listener registered with Renderer3
7521 target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx);
7522 }
7523 else {
7524 if (useCaptureOrSubIdx >= 0) {
7525 // unregister
7526 lCleanup[lastLCleanupIndex = useCaptureOrSubIdx]();
7527 }
7528 else {
7529 // Subscription
7530 lCleanup[lastLCleanupIndex = -useCaptureOrSubIdx].unsubscribe();
7531 }
7532 }
7533 i += 2;
7534 }
7535 else {
7536 // This is a cleanup function that is grouped with the index of its context
7537 const context = lCleanup[lastLCleanupIndex = tCleanup[i + 1]];
7538 tCleanup[i].call(context);
7539 }
7540 }
7541 }
7542 if (lCleanup !== null) {
7543 for (let i = lastLCleanupIndex + 1; i < lCleanup.length; i++) {
7544 const instanceCleanupFn = lCleanup[i];
7545 ngDevMode && assertFunction(instanceCleanupFn, 'Expecting instance cleanup function.');
7546 instanceCleanupFn();
7547 }
7548 lView[CLEANUP] = null;
7549 }
7550}
7551/** Calls onDestroy hooks for this view */
7552function executeOnDestroys(tView, lView) {
7553 let destroyHooks;
7554 if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
7555 for (let i = 0; i < destroyHooks.length; i += 2) {
7556 const context = lView[destroyHooks[i]];
7557 // Only call the destroy hook if the context has been requested.
7558 if (!(context instanceof NodeInjectorFactory)) {
7559 const toCall = destroyHooks[i + 1];
7560 if (Array.isArray(toCall)) {
7561 for (let j = 0; j < toCall.length; j += 2) {
7562 const callContext = context[toCall[j]];
7563 const hook = toCall[j + 1];
7564 profiler(4 /* ProfilerEvent.LifecycleHookStart */, callContext, hook);
7565 try {
7566 hook.call(callContext);
7567 }
7568 finally {
7569 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, callContext, hook);
7570 }
7571 }
7572 }
7573 else {
7574 profiler(4 /* ProfilerEvent.LifecycleHookStart */, context, toCall);
7575 try {
7576 toCall.call(context);
7577 }
7578 finally {
7579 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, context, toCall);
7580 }
7581 }
7582 }
7583 }
7584 }
7585}
7586/**
7587 * Returns a native element if a node can be inserted into the given parent.
7588 *
7589 * There are two reasons why we may not be able to insert a element immediately.
7590 * - Projection: When creating a child content element of a component, we have to skip the
7591 * insertion because the content of a component will be projected.
7592 * `<component><content>delayed due to projection</content></component>`
7593 * - Parent container is disconnected: This can happen when we are inserting a view into
7594 * parent container, which itself is disconnected. For example the parent container is part
7595 * of a View which has not be inserted or is made for projection but has not been inserted
7596 * into destination.
7597 *
7598 * @param tView: Current `TView`.
7599 * @param tNode: `TNode` for which we wish to retrieve render parent.
7600 * @param lView: Current `LView`.
7601 */
7602function getParentRElement(tView, tNode, lView) {
7603 return getClosestRElement(tView, tNode.parent, lView);
7604}
7605/**
7606 * Get closest `RElement` or `null` if it can't be found.
7607 *
7608 * If `TNode` is `TNodeType.Element` => return `RElement` at `LView[tNode.index]` location.
7609 * If `TNode` is `TNodeType.ElementContainer|IcuContain` => return the parent (recursively).
7610 * If `TNode` is `null` then return host `RElement`:
7611 * - return `null` if projection
7612 * - return `null` if parent container is disconnected (we have no parent.)
7613 *
7614 * @param tView: Current `TView`.
7615 * @param tNode: `TNode` for which we wish to retrieve `RElement` (or `null` if host element is
7616 * needed).
7617 * @param lView: Current `LView`.
7618 * @returns `null` if the `RElement` can't be determined at this time (no parent / projection)
7619 */
7620function getClosestRElement(tView, tNode, lView) {
7621 let parentTNode = tNode;
7622 // Skip over element and ICU containers as those are represented by a comment node and
7623 // can't be used as a render parent.
7624 while (parentTNode !== null &&
7625 (parentTNode.type & (8 /* TNodeType.ElementContainer */ | 32 /* TNodeType.Icu */))) {
7626 tNode = parentTNode;
7627 parentTNode = tNode.parent;
7628 }
7629 // If the parent tNode is null, then we are inserting across views: either into an embedded view
7630 // or a component view.
7631 if (parentTNode === null) {
7632 // We are inserting a root element of the component view into the component host element and
7633 // it should always be eager.
7634 return lView[HOST];
7635 }
7636 else {
7637 ngDevMode && assertTNodeType(parentTNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
7638 if (parentTNode.flags & 2 /* TNodeFlags.isComponentHost */) {
7639 ngDevMode && assertTNodeForLView(parentTNode, lView);
7640 const encapsulation = tView.data[parentTNode.directiveStart].encapsulation;
7641 // We've got a parent which is an element in the current view. We just need to verify if the
7642 // parent element is not a component. Component's content nodes are not inserted immediately
7643 // because they will be projected, and so doing insert at this point would be wasteful.
7644 // Since the projection would then move it to its final destination. Note that we can't
7645 // make this assumption when using the Shadow DOM, because the native projection placeholders
7646 // (<content> or <slot>) have to be in place as elements are being inserted.
7647 if (encapsulation === ViewEncapsulation$1.None ||
7648 encapsulation === ViewEncapsulation$1.Emulated) {
7649 return null;
7650 }
7651 }
7652 return getNativeByTNode(parentTNode, lView);
7653 }
7654}
7655/**
7656 * Inserts a native node before another native node for a given parent using {@link Renderer3}.
7657 * This is a utility function that can be used when native nodes were determined - it abstracts an
7658 * actual renderer being used.
7659 */
7660function nativeInsertBefore(renderer, parent, child, beforeNode, isMove) {
7661 ngDevMode && ngDevMode.rendererInsertBefore++;
7662 if (isProceduralRenderer(renderer)) {
7663 renderer.insertBefore(parent, child, beforeNode, isMove);
7664 }
7665 else {
7666 const targetParent = isTemplateNode(parent) ? parent.content : parent;
7667 targetParent.insertBefore(child, beforeNode, isMove);
7668 }
7669}
7670function nativeAppendChild(renderer, parent, child) {
7671 ngDevMode && ngDevMode.rendererAppendChild++;
7672 ngDevMode && assertDefined(parent, 'parent node must be defined');
7673 if (isProceduralRenderer(renderer)) {
7674 renderer.appendChild(parent, child);
7675 }
7676 else {
7677 const targetParent = isTemplateNode(parent) ? parent.content : parent;
7678 targetParent.appendChild(child);
7679 }
7680}
7681function nativeAppendOrInsertBefore(renderer, parent, child, beforeNode, isMove) {
7682 if (beforeNode !== null) {
7683 nativeInsertBefore(renderer, parent, child, beforeNode, isMove);
7684 }
7685 else {
7686 nativeAppendChild(renderer, parent, child);
7687 }
7688}
7689/** Removes a node from the DOM given its native parent. */
7690function nativeRemoveChild(renderer, parent, child, isHostElement) {
7691 if (isProceduralRenderer(renderer)) {
7692 renderer.removeChild(parent, child, isHostElement);
7693 }
7694 else {
7695 parent.removeChild(child);
7696 }
7697}
7698/** Checks if an element is a `<template>` node. */
7699function isTemplateNode(node) {
7700 return node.tagName === 'TEMPLATE' && node.content !== undefined;
7701}
7702/**
7703 * Returns a native parent of a given native node.
7704 */
7705function nativeParentNode(renderer, node) {
7706 return (isProceduralRenderer(renderer) ? renderer.parentNode(node) : node.parentNode);
7707}
7708/**
7709 * Returns a native sibling of a given native node.
7710 */
7711function nativeNextSibling(renderer, node) {
7712 return isProceduralRenderer(renderer) ? renderer.nextSibling(node) : node.nextSibling;
7713}
7714/**
7715 * Find a node in front of which `currentTNode` should be inserted.
7716 *
7717 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
7718 * takes `TNode.insertBeforeIndex` into account if i18n code has been invoked.
7719 *
7720 * @param parentTNode parent `TNode`
7721 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
7722 * @param lView current `LView`
7723 */
7724function getInsertInFrontOfRNode(parentTNode, currentTNode, lView) {
7725 return _getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView);
7726}
7727/**
7728 * Find a node in front of which `currentTNode` should be inserted. (Does not take i18n into
7729 * account)
7730 *
7731 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
7732 * does not take `TNode.insertBeforeIndex` into account.
7733 *
7734 * @param parentTNode parent `TNode`
7735 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
7736 * @param lView current `LView`
7737 */
7738function getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView) {
7739 if (parentTNode.type & (8 /* TNodeType.ElementContainer */ | 32 /* TNodeType.Icu */)) {
7740 return getNativeByTNode(parentTNode, lView);
7741 }
7742 return null;
7743}
7744/**
7745 * Tree shakable boundary for `getInsertInFrontOfRNodeWithI18n` function.
7746 *
7747 * This function will only be set if i18n code runs.
7748 */
7749let _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithNoI18n;
7750/**
7751 * Tree shakable boundary for `processI18nInsertBefore` function.
7752 *
7753 * This function will only be set if i18n code runs.
7754 */
7755let _processI18nInsertBefore;
7756function setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore) {
7757 _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithI18n;
7758 _processI18nInsertBefore = processI18nInsertBefore;
7759}
7760/**
7761 * Appends the `child` native node (or a collection of nodes) to the `parent`.
7762 *
7763 * @param tView The `TView' to be appended
7764 * @param lView The current LView
7765 * @param childRNode The native child (or children) that should be appended
7766 * @param childTNode The TNode of the child element
7767 */
7768function appendChild(tView, lView, childRNode, childTNode) {
7769 const parentRNode = getParentRElement(tView, childTNode, lView);
7770 const renderer = lView[RENDERER];
7771 const parentTNode = childTNode.parent || lView[T_HOST];
7772 const anchorNode = getInsertInFrontOfRNode(parentTNode, childTNode, lView);
7773 if (parentRNode != null) {
7774 if (Array.isArray(childRNode)) {
7775 for (let i = 0; i < childRNode.length; i++) {
7776 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode[i], anchorNode, false);
7777 }
7778 }
7779 else {
7780 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode, anchorNode, false);
7781 }
7782 }
7783 _processI18nInsertBefore !== undefined &&
7784 _processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRNode);
7785}
7786/**
7787 * Returns the first native node for a given LView, starting from the provided TNode.
7788 *
7789 * Native nodes are returned in the order in which those appear in the native tree (DOM).
7790 */
7791function getFirstNativeNode(lView, tNode) {
7792 if (tNode !== null) {
7793 ngDevMode &&
7794 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 32 /* TNodeType.Icu */ | 16 /* TNodeType.Projection */);
7795 const tNodeType = tNode.type;
7796 if (tNodeType & 3 /* TNodeType.AnyRNode */) {
7797 return getNativeByTNode(tNode, lView);
7798 }
7799 else if (tNodeType & 4 /* TNodeType.Container */) {
7800 return getBeforeNodeForView(-1, lView[tNode.index]);
7801 }
7802 else if (tNodeType & 8 /* TNodeType.ElementContainer */) {
7803 const elIcuContainerChild = tNode.child;
7804 if (elIcuContainerChild !== null) {
7805 return getFirstNativeNode(lView, elIcuContainerChild);
7806 }
7807 else {
7808 const rNodeOrLContainer = lView[tNode.index];
7809 if (isLContainer(rNodeOrLContainer)) {
7810 return getBeforeNodeForView(-1, rNodeOrLContainer);
7811 }
7812 else {
7813 return unwrapRNode(rNodeOrLContainer);
7814 }
7815 }
7816 }
7817 else if (tNodeType & 32 /* TNodeType.Icu */) {
7818 let nextRNode = icuContainerIterate(tNode, lView);
7819 let rNode = nextRNode();
7820 // If the ICU container has no nodes, than we use the ICU anchor as the node.
7821 return rNode || unwrapRNode(lView[tNode.index]);
7822 }
7823 else {
7824 const projectionNodes = getProjectionNodes(lView, tNode);
7825 if (projectionNodes !== null) {
7826 if (Array.isArray(projectionNodes)) {
7827 return projectionNodes[0];
7828 }
7829 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
7830 ngDevMode && assertParentView(parentView);
7831 return getFirstNativeNode(parentView, projectionNodes);
7832 }
7833 else {
7834 return getFirstNativeNode(lView, tNode.next);
7835 }
7836 }
7837 }
7838 return null;
7839}
7840function getProjectionNodes(lView, tNode) {
7841 if (tNode !== null) {
7842 const componentView = lView[DECLARATION_COMPONENT_VIEW];
7843 const componentHost = componentView[T_HOST];
7844 const slotIdx = tNode.projection;
7845 ngDevMode && assertProjectionSlots(lView);
7846 return componentHost.projection[slotIdx];
7847 }
7848 return null;
7849}
7850function getBeforeNodeForView(viewIndexInContainer, lContainer) {
7851 const nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1;
7852 if (nextViewIndex < lContainer.length) {
7853 const lView = lContainer[nextViewIndex];
7854 const firstTNodeOfView = lView[TVIEW].firstChild;
7855 if (firstTNodeOfView !== null) {
7856 return getFirstNativeNode(lView, firstTNodeOfView);
7857 }
7858 }
7859 return lContainer[NATIVE];
7860}
7861/**
7862 * Removes a native node itself using a given renderer. To remove the node we are looking up its
7863 * parent from the native tree as not all platforms / browsers support the equivalent of
7864 * node.remove().
7865 *
7866 * @param renderer A renderer to be used
7867 * @param rNode The native node that should be removed
7868 * @param isHostElement A flag indicating if a node to be removed is a host of a component.
7869 */
7870function nativeRemoveNode(renderer, rNode, isHostElement) {
7871 ngDevMode && ngDevMode.rendererRemoveNode++;
7872 const nativeParent = nativeParentNode(renderer, rNode);
7873 if (nativeParent) {
7874 nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
7875 }
7876}
7877/**
7878 * Performs the operation of `action` on the node. Typically this involves inserting or removing
7879 * nodes on the LView or projection boundary.
7880 */
7881function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode, isProjection) {
7882 while (tNode != null) {
7883 ngDevMode && assertTNodeForLView(tNode, lView);
7884 ngDevMode &&
7885 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
7886 const rawSlotValue = lView[tNode.index];
7887 const tNodeType = tNode.type;
7888 if (isProjection) {
7889 if (action === 0 /* WalkTNodeTreeAction.Create */) {
7890 rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
7891 tNode.flags |= 4 /* TNodeFlags.isProjected */;
7892 }
7893 }
7894 if ((tNode.flags & 64 /* TNodeFlags.isDetached */) !== 64 /* TNodeFlags.isDetached */) {
7895 if (tNodeType & 8 /* TNodeType.ElementContainer */) {
7896 applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
7897 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
7898 }
7899 else if (tNodeType & 32 /* TNodeType.Icu */) {
7900 const nextRNode = icuContainerIterate(tNode, lView);
7901 let rNode;
7902 while (rNode = nextRNode()) {
7903 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
7904 }
7905 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
7906 }
7907 else if (tNodeType & 16 /* TNodeType.Projection */) {
7908 applyProjectionRecursive(renderer, action, lView, tNode, parentRElement, beforeNode);
7909 }
7910 else {
7911 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
7912 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
7913 }
7914 }
7915 tNode = isProjection ? tNode.projectionNext : tNode.next;
7916 }
7917}
7918function applyView(tView, lView, renderer, action, parentRElement, beforeNode) {
7919 applyNodes(renderer, action, tView.firstChild, lView, parentRElement, beforeNode, false);
7920}
7921/**
7922 * `applyProjection` performs operation on the projection.
7923 *
7924 * Inserting a projection requires us to locate the projected nodes from the parent component. The
7925 * complication is that those nodes themselves could be re-projected from their parent component.
7926 *
7927 * @param tView The `TView` of `LView` which needs to be inserted, detached, destroyed
7928 * @param lView The `LView` which needs to be inserted, detached, destroyed.
7929 * @param tProjectionNode node to project
7930 */
7931function applyProjection(tView, lView, tProjectionNode) {
7932 const renderer = lView[RENDERER];
7933 const parentRNode = getParentRElement(tView, tProjectionNode, lView);
7934 const parentTNode = tProjectionNode.parent || lView[T_HOST];
7935 let beforeNode = getInsertInFrontOfRNode(parentTNode, tProjectionNode, lView);
7936 applyProjectionRecursive(renderer, 0 /* WalkTNodeTreeAction.Create */, lView, tProjectionNode, parentRNode, beforeNode);
7937}
7938/**
7939 * `applyProjectionRecursive` performs operation on the projection specified by `action` (insert,
7940 * detach, destroy)
7941 *
7942 * Inserting a projection requires us to locate the projected nodes from the parent component. The
7943 * complication is that those nodes themselves could be re-projected from their parent component.
7944 *
7945 * @param renderer Render to use
7946 * @param action action to perform (insert, detach, destroy)
7947 * @param lView The LView which needs to be inserted, detached, destroyed.
7948 * @param tProjectionNode node to project
7949 * @param parentRElement parent DOM element for insertion/removal.
7950 * @param beforeNode Before which node the insertions should happen.
7951 */
7952function applyProjectionRecursive(renderer, action, lView, tProjectionNode, parentRElement, beforeNode) {
7953 const componentLView = lView[DECLARATION_COMPONENT_VIEW];
7954 const componentNode = componentLView[T_HOST];
7955 ngDevMode &&
7956 assertEqual(typeof tProjectionNode.projection, 'number', 'expecting projection index');
7957 const nodeToProjectOrRNodes = componentNode.projection[tProjectionNode.projection];
7958 if (Array.isArray(nodeToProjectOrRNodes)) {
7959 // This should not exist, it is a bit of a hack. When we bootstrap a top level node and we
7960 // need to support passing projectable nodes, so we cheat and put them in the TNode
7961 // of the Host TView. (Yes we put instance info at the T Level). We can get away with it
7962 // because we know that that TView is not shared and therefore it will not be a problem.
7963 // This should be refactored and cleaned up.
7964 for (let i = 0; i < nodeToProjectOrRNodes.length; i++) {
7965 const rNode = nodeToProjectOrRNodes[i];
7966 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
7967 }
7968 }
7969 else {
7970 let nodeToProject = nodeToProjectOrRNodes;
7971 const projectedComponentLView = componentLView[PARENT];
7972 applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
7973 }
7974}
7975/**
7976 * `applyContainer` performs an operation on the container and its views as specified by
7977 * `action` (insert, detach, destroy)
7978 *
7979 * Inserting a Container is complicated by the fact that the container may have Views which
7980 * themselves have containers or projections.
7981 *
7982 * @param renderer Renderer to use
7983 * @param action action to perform (insert, detach, destroy)
7984 * @param lContainer The LContainer which needs to be inserted, detached, destroyed.
7985 * @param parentRElement parent DOM element for insertion/removal.
7986 * @param beforeNode Before which node the insertions should happen.
7987 */
7988function applyContainer(renderer, action, lContainer, parentRElement, beforeNode) {
7989 ngDevMode && assertLContainer(lContainer);
7990 const anchor = lContainer[NATIVE]; // LContainer has its own before node.
7991 const native = unwrapRNode(lContainer);
7992 // An LContainer can be created dynamically on any node by injecting ViewContainerRef.
7993 // Asking for a ViewContainerRef on an element will result in a creation of a separate anchor
7994 // node (comment in the DOM) that will be different from the LContainer's host node. In this
7995 // particular case we need to execute action on 2 nodes:
7996 // - container's host node (this is done in the executeActionOnElementOrContainer)
7997 // - container's host node (this is done here)
7998 if (anchor !== native) {
7999 // This is very strange to me (Misko). I would expect that the native is same as anchor. I
8000 // don't see a reason why they should be different, but they are.
8001 //
8002 // If they are we need to process the second anchor as well.
8003 applyToElementOrContainer(action, renderer, parentRElement, anchor, beforeNode);
8004 }
8005 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
8006 const lView = lContainer[i];
8007 applyView(lView[TVIEW], lView, renderer, action, parentRElement, anchor);
8008 }
8009}
8010/**
8011 * Writes class/style to element.
8012 *
8013 * @param renderer Renderer to use.
8014 * @param isClassBased `true` if it should be written to `class` (`false` to write to `style`)
8015 * @param rNode The Node to write to.
8016 * @param prop Property to write to. This would be the class/style name.
8017 * @param value Value to write. If `null`/`undefined`/`false` this is considered a remove (set/add
8018 * otherwise).
8019 */
8020function applyStyling(renderer, isClassBased, rNode, prop, value) {
8021 const isProcedural = isProceduralRenderer(renderer);
8022 if (isClassBased) {
8023 // We actually want JS true/false here because any truthy value should add the class
8024 if (!value) {
8025 ngDevMode && ngDevMode.rendererRemoveClass++;
8026 if (isProcedural) {
8027 renderer.removeClass(rNode, prop);
8028 }
8029 else {
8030 rNode.classList.remove(prop);
8031 }
8032 }
8033 else {
8034 ngDevMode && ngDevMode.rendererAddClass++;
8035 if (isProcedural) {
8036 renderer.addClass(rNode, prop);
8037 }
8038 else {
8039 ngDevMode && assertDefined(rNode.classList, 'HTMLElement expected');
8040 rNode.classList.add(prop);
8041 }
8042 }
8043 }
8044 else {
8045 let flags = prop.indexOf('-') === -1 ? undefined : RendererStyleFlags2.DashCase;
8046 if (value == null /** || value === undefined */) {
8047 ngDevMode && ngDevMode.rendererRemoveStyle++;
8048 if (isProcedural) {
8049 renderer.removeStyle(rNode, prop, flags);
8050 }
8051 else {
8052 rNode.style.removeProperty(prop);
8053 }
8054 }
8055 else {
8056 // A value is important if it ends with `!important`. The style
8057 // parser strips any semicolons at the end of the value.
8058 const isImportant = typeof value === 'string' ? value.endsWith('!important') : false;
8059 if (isImportant) {
8060 // !important has to be stripped from the value for it to be valid.
8061 value = value.slice(0, -10);
8062 flags |= RendererStyleFlags2.Important;
8063 }
8064 ngDevMode && ngDevMode.rendererSetStyle++;
8065 if (isProcedural) {
8066 renderer.setStyle(rNode, prop, value, flags);
8067 }
8068 else {
8069 ngDevMode && assertDefined(rNode.style, 'HTMLElement expected');
8070 rNode.style.setProperty(prop, value, isImportant ? 'important' : '');
8071 }
8072 }
8073 }
8074}
8075/**
8076 * Write `cssText` to `RElement`.
8077 *
8078 * This function does direct write without any reconciliation. Used for writing initial values, so
8079 * that static styling values do not pull in the style parser.
8080 *
8081 * @param renderer Renderer to use
8082 * @param element The element which needs to be updated.
8083 * @param newValue The new class list to write.
8084 */
8085function writeDirectStyle(renderer, element, newValue) {
8086 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
8087 if (isProceduralRenderer(renderer)) {
8088 renderer.setAttribute(element, 'style', newValue);
8089 }
8090 else {
8091 element.style.cssText = newValue;
8092 }
8093 ngDevMode && ngDevMode.rendererSetStyle++;
8094}
8095/**
8096 * Write `className` to `RElement`.
8097 *
8098 * This function does direct write without any reconciliation. Used for writing initial values, so
8099 * that static styling values do not pull in the style parser.
8100 *
8101 * @param renderer Renderer to use
8102 * @param element The element which needs to be updated.
8103 * @param newValue The new class list to write.
8104 */
8105function writeDirectClass(renderer, element, newValue) {
8106 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
8107 if (isProceduralRenderer(renderer)) {
8108 if (newValue === '') {
8109 // There are tests in `google3` which expect `element.getAttribute('class')` to be `null`.
8110 renderer.removeAttribute(element, 'class');
8111 }
8112 else {
8113 renderer.setAttribute(element, 'class', newValue);
8114 }
8115 }
8116 else {
8117 element.className = newValue;
8118 }
8119 ngDevMode && ngDevMode.rendererSetClassName++;
8120}
8121
8122/**
8123 * @license
8124 * Copyright Google LLC All Rights Reserved.
8125 *
8126 * Use of this source code is governed by an MIT-style license that can be
8127 * found in the LICENSE file at https://angular.io/license
8128 */
8129/**
8130 * Returns an index of `classToSearch` in `className` taking token boundaries into account.
8131 *
8132 * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
8133 *
8134 * @param className A string containing classes (whitespace separated)
8135 * @param classToSearch A class name to locate
8136 * @param startingIndex Starting location of search
8137 * @returns an index of the located class (or -1 if not found)
8138 */
8139function classIndexOf(className, classToSearch, startingIndex) {
8140 ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
8141 let end = className.length;
8142 while (true) {
8143 const foundIndex = className.indexOf(classToSearch, startingIndex);
8144 if (foundIndex === -1)
8145 return foundIndex;
8146 if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* CharCode.SPACE */) {
8147 // Ensure that it has leading whitespace
8148 const length = classToSearch.length;
8149 if (foundIndex + length === end ||
8150 className.charCodeAt(foundIndex + length) <= 32 /* CharCode.SPACE */) {
8151 // Ensure that it has trailing whitespace
8152 return foundIndex;
8153 }
8154 }
8155 // False positive, keep searching from where we left off.
8156 startingIndex = foundIndex + 1;
8157 }
8158}
8159
8160/**
8161 * @license
8162 * Copyright Google LLC All Rights Reserved.
8163 *
8164 * Use of this source code is governed by an MIT-style license that can be
8165 * found in the LICENSE file at https://angular.io/license
8166 */
8167const unusedValueToPlacateAjd$1 = unusedValueExportToPlacateAjd$4 + unusedValueExportToPlacateAjd$3;
8168const NG_TEMPLATE_SELECTOR = 'ng-template';
8169/**
8170 * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
8171 *
8172 * @param attrs `TAttributes` to search through.
8173 * @param cssClassToMatch class to match (lowercase)
8174 * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
8175 * addition to the `AttributeMarker.Classes`.
8176 */
8177function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
8178 // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
8179 // It is strange to me that sometimes the class information comes in form of `class` attribute
8180 // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
8181 // if that is the right behavior.
8182 ngDevMode &&
8183 assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
8184 let i = 0;
8185 while (i < attrs.length) {
8186 let item = attrs[i++];
8187 if (isProjectionMode && item === 'class') {
8188 item = attrs[i];
8189 if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
8190 return true;
8191 }
8192 }
8193 else if (item === 1 /* AttributeMarker.Classes */) {
8194 // We found the classes section. Start searching for the class.
8195 while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
8196 // while we have strings
8197 if (item.toLowerCase() === cssClassToMatch)
8198 return true;
8199 }
8200 return false;
8201 }
8202 }
8203 return false;
8204}
8205/**
8206 * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
8207 *
8208 * @param tNode current TNode
8209 */
8210function isInlineTemplate(tNode) {
8211 return tNode.type === 4 /* TNodeType.Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
8212}
8213/**
8214 * Function that checks whether a given tNode matches tag-based selector and has a valid type.
8215 *
8216 * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
8217 * directive matching mode:
8218 * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
8219 * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
8220 * tag name was extracted from * syntax so we would match the same directive twice);
8221 * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
8222 * (applicable to TNodeType.Container only).
8223 */
8224function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
8225 const tagNameToCompare = tNode.type === 4 /* TNodeType.Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
8226 return currentSelector === tagNameToCompare;
8227}
8228/**
8229 * A utility function to match an Ivy node static data against a simple CSS selector
8230 *
8231 * @param node static data of the node to match
8232 * @param selector The selector to try matching against the node.
8233 * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
8234 * directive matching.
8235 * @returns true if node matches the selector.
8236 */
8237function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
8238 ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
8239 let mode = 4 /* SelectorFlags.ELEMENT */;
8240 const nodeAttrs = tNode.attrs || [];
8241 // Find the index of first attribute that has no value, only a name.
8242 const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
8243 // When processing ":not" selectors, we skip to the next ":not" if the
8244 // current one doesn't match
8245 let skipToNextSelector = false;
8246 for (let i = 0; i < selector.length; i++) {
8247 const current = selector[i];
8248 if (typeof current === 'number') {
8249 // If we finish processing a :not selector and it hasn't failed, return false
8250 if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
8251 return false;
8252 }
8253 // If we are skipping to the next :not() and this mode flag is positive,
8254 // it's a part of the current :not() selector, and we should keep skipping
8255 if (skipToNextSelector && isPositive(current))
8256 continue;
8257 skipToNextSelector = false;
8258 mode = current | (mode & 1 /* SelectorFlags.NOT */);
8259 continue;
8260 }
8261 if (skipToNextSelector)
8262 continue;
8263 if (mode & 4 /* SelectorFlags.ELEMENT */) {
8264 mode = 2 /* SelectorFlags.ATTRIBUTE */ | mode & 1 /* SelectorFlags.NOT */;
8265 if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
8266 current === '' && selector.length === 1) {
8267 if (isPositive(mode))
8268 return false;
8269 skipToNextSelector = true;
8270 }
8271 }
8272 else {
8273 const selectorAttrValue = mode & 8 /* SelectorFlags.CLASS */ ? current : selector[++i];
8274 // special case for matching against classes when a tNode has been instantiated with
8275 // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
8276 if ((mode & 8 /* SelectorFlags.CLASS */) && tNode.attrs !== null) {
8277 if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
8278 if (isPositive(mode))
8279 return false;
8280 skipToNextSelector = true;
8281 }
8282 continue;
8283 }
8284 const attrName = (mode & 8 /* SelectorFlags.CLASS */) ? 'class' : current;
8285 const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
8286 if (attrIndexInNode === -1) {
8287 if (isPositive(mode))
8288 return false;
8289 skipToNextSelector = true;
8290 continue;
8291 }
8292 if (selectorAttrValue !== '') {
8293 let nodeAttrValue;
8294 if (attrIndexInNode > nameOnlyMarkerIdx) {
8295 nodeAttrValue = '';
8296 }
8297 else {
8298 ngDevMode &&
8299 assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* AttributeMarker.NamespaceURI */, 'We do not match directives on namespaced attributes');
8300 // we lowercase the attribute value to be able to match
8301 // selectors without case-sensitivity
8302 // (selectors are already in lowercase when generated)
8303 nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
8304 }
8305 const compareAgainstClassName = mode & 8 /* SelectorFlags.CLASS */ ? nodeAttrValue : null;
8306 if (compareAgainstClassName &&
8307 classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
8308 mode & 2 /* SelectorFlags.ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
8309 if (isPositive(mode))
8310 return false;
8311 skipToNextSelector = true;
8312 }
8313 }
8314 }
8315 }
8316 return isPositive(mode) || skipToNextSelector;
8317}
8318function isPositive(mode) {
8319 return (mode & 1 /* SelectorFlags.NOT */) === 0;
8320}
8321/**
8322 * Examines the attribute's definition array for a node to find the index of the
8323 * attribute that matches the given `name`.
8324 *
8325 * NOTE: This will not match namespaced attributes.
8326 *
8327 * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
8328 * The following table summarizes which types of attributes we attempt to match:
8329 *
8330 * ===========================================================================================================
8331 * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
8332 * Attributes
8333 * ===========================================================================================================
8334 * Inline + Projection | YES | YES | NO | YES
8335 * -----------------------------------------------------------------------------------------------------------
8336 * Inline + Directive | NO | NO | YES | NO
8337 * -----------------------------------------------------------------------------------------------------------
8338 * Non-inline + Projection | YES | YES | NO | YES
8339 * -----------------------------------------------------------------------------------------------------------
8340 * Non-inline + Directive | YES | YES | NO | YES
8341 * ===========================================================================================================
8342 *
8343 * @param name the name of the attribute to find
8344 * @param attrs the attribute array to examine
8345 * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
8346 * rather than a manually expanded template node (e.g `<ng-template>`).
8347 * @param isProjectionMode true if we are matching against content projection otherwise we are
8348 * matching against directives.
8349 */
8350function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
8351 if (attrs === null)
8352 return -1;
8353 let i = 0;
8354 if (isProjectionMode || !isInlineTemplate) {
8355 let bindingsMode = false;
8356 while (i < attrs.length) {
8357 const maybeAttrName = attrs[i];
8358 if (maybeAttrName === name) {
8359 return i;
8360 }
8361 else if (maybeAttrName === 3 /* AttributeMarker.Bindings */ || maybeAttrName === 6 /* AttributeMarker.I18n */) {
8362 bindingsMode = true;
8363 }
8364 else if (maybeAttrName === 1 /* AttributeMarker.Classes */ || maybeAttrName === 2 /* AttributeMarker.Styles */) {
8365 let value = attrs[++i];
8366 // We should skip classes here because we have a separate mechanism for
8367 // matching classes in projection mode.
8368 while (typeof value === 'string') {
8369 value = attrs[++i];
8370 }
8371 continue;
8372 }
8373 else if (maybeAttrName === 4 /* AttributeMarker.Template */) {
8374 // We do not care about Template attributes in this scenario.
8375 break;
8376 }
8377 else if (maybeAttrName === 0 /* AttributeMarker.NamespaceURI */) {
8378 // Skip the whole namespaced attribute and value. This is by design.
8379 i += 4;
8380 continue;
8381 }
8382 // In binding mode there are only names, rather than name-value pairs.
8383 i += bindingsMode ? 1 : 2;
8384 }
8385 // We did not match the attribute
8386 return -1;
8387 }
8388 else {
8389 return matchTemplateAttribute(attrs, name);
8390 }
8391}
8392function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
8393 for (let i = 0; i < selector.length; i++) {
8394 if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
8395 return true;
8396 }
8397 }
8398 return false;
8399}
8400function getProjectAsAttrValue(tNode) {
8401 const nodeAttrs = tNode.attrs;
8402 if (nodeAttrs != null) {
8403 const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* AttributeMarker.ProjectAs */);
8404 // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
8405 // (attribute names are stored at even indexes)
8406 if ((ngProjectAsAttrIdx & 1) === 0) {
8407 return nodeAttrs[ngProjectAsAttrIdx + 1];
8408 }
8409 }
8410 return null;
8411}
8412function getNameOnlyMarkerIndex(nodeAttrs) {
8413 for (let i = 0; i < nodeAttrs.length; i++) {
8414 const nodeAttr = nodeAttrs[i];
8415 if (isNameOnlyAttributeMarker(nodeAttr)) {
8416 return i;
8417 }
8418 }
8419 return nodeAttrs.length;
8420}
8421function matchTemplateAttribute(attrs, name) {
8422 let i = attrs.indexOf(4 /* AttributeMarker.Template */);
8423 if (i > -1) {
8424 i++;
8425 while (i < attrs.length) {
8426 const attr = attrs[i];
8427 // Return in case we checked all template attrs and are switching to the next section in the
8428 // attrs array (that starts with a number that represents an attribute marker).
8429 if (typeof attr === 'number')
8430 return -1;
8431 if (attr === name)
8432 return i;
8433 i++;
8434 }
8435 }
8436 return -1;
8437}
8438/**
8439 * Checks whether a selector is inside a CssSelectorList
8440 * @param selector Selector to be checked.
8441 * @param list List in which to look for the selector.
8442 */
8443function isSelectorInSelectorList(selector, list) {
8444 selectorListLoop: for (let i = 0; i < list.length; i++) {
8445 const currentSelectorInList = list[i];
8446 if (selector.length !== currentSelectorInList.length) {
8447 continue;
8448 }
8449 for (let j = 0; j < selector.length; j++) {
8450 if (selector[j] !== currentSelectorInList[j]) {
8451 continue selectorListLoop;
8452 }
8453 }
8454 return true;
8455 }
8456 return false;
8457}
8458function maybeWrapInNotSelector(isNegativeMode, chunk) {
8459 return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
8460}
8461function stringifyCSSSelector(selector) {
8462 let result = selector[0];
8463 let i = 1;
8464 let mode = 2 /* SelectorFlags.ATTRIBUTE */;
8465 let currentChunk = '';
8466 let isNegativeMode = false;
8467 while (i < selector.length) {
8468 let valueOrMarker = selector[i];
8469 if (typeof valueOrMarker === 'string') {
8470 if (mode & 2 /* SelectorFlags.ATTRIBUTE */) {
8471 const attrValue = selector[++i];
8472 currentChunk +=
8473 '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
8474 }
8475 else if (mode & 8 /* SelectorFlags.CLASS */) {
8476 currentChunk += '.' + valueOrMarker;
8477 }
8478 else if (mode & 4 /* SelectorFlags.ELEMENT */) {
8479 currentChunk += ' ' + valueOrMarker;
8480 }
8481 }
8482 else {
8483 //
8484 // Append current chunk to the final result in case we come across SelectorFlag, which
8485 // indicates that the previous section of a selector is over. We need to accumulate content
8486 // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
8487 // ```
8488 // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
8489 // ```
8490 // should be transformed to `.classA :not(.classB .classC)`.
8491 //
8492 // Note: for negative selector part, we accumulate content between flags until we find the
8493 // next negative flag. This is needed to support a case where `:not()` rule contains more than
8494 // one chunk, e.g. the following selector:
8495 // ```
8496 // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
8497 // ```
8498 // should be stringified to `:not(p.foo) :not(.bar)`
8499 //
8500 if (currentChunk !== '' && !isPositive(valueOrMarker)) {
8501 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
8502 currentChunk = '';
8503 }
8504 mode = valueOrMarker;
8505 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
8506 // mode is maintained for remaining chunks of a selector.
8507 isNegativeMode = isNegativeMode || !isPositive(mode);
8508 }
8509 i++;
8510 }
8511 if (currentChunk !== '') {
8512 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
8513 }
8514 return result;
8515}
8516/**
8517 * Generates string representation of CSS selector in parsed form.
8518 *
8519 * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
8520 * additional parsing at runtime (for example, for directive matching). However in some cases (for
8521 * example, while bootstrapping a component), a string version of the selector is required to query
8522 * for the host element on the page. This function takes the parsed form of a selector and returns
8523 * its string representation.
8524 *
8525 * @param selectorList selector in parsed form
8526 * @returns string representation of a given selector
8527 */
8528function stringifyCSSSelectorList(selectorList) {
8529 return selectorList.map(stringifyCSSSelector).join(',');
8530}
8531/**
8532 * Extracts attributes and classes information from a given CSS selector.
8533 *
8534 * This function is used while creating a component dynamically. In this case, the host element
8535 * (that is created dynamically) should contain attributes and classes specified in component's CSS
8536 * selector.
8537 *
8538 * @param selector CSS selector in parsed form (in a form of array)
8539 * @returns object with `attrs` and `classes` fields that contain extracted information
8540 */
8541function extractAttrsAndClassesFromSelector(selector) {
8542 const attrs = [];
8543 const classes = [];
8544 let i = 1;
8545 let mode = 2 /* SelectorFlags.ATTRIBUTE */;
8546 while (i < selector.length) {
8547 let valueOrMarker = selector[i];
8548 if (typeof valueOrMarker === 'string') {
8549 if (mode === 2 /* SelectorFlags.ATTRIBUTE */) {
8550 if (valueOrMarker !== '') {
8551 attrs.push(valueOrMarker, selector[++i]);
8552 }
8553 }
8554 else if (mode === 8 /* SelectorFlags.CLASS */) {
8555 classes.push(valueOrMarker);
8556 }
8557 }
8558 else {
8559 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
8560 // mode is maintained for remaining chunks of a selector. Since attributes and classes are
8561 // extracted only for "positive" part of the selector, we can stop here.
8562 if (!isPositive(mode))
8563 break;
8564 mode = valueOrMarker;
8565 }
8566 i++;
8567 }
8568 return { attrs, classes };
8569}
8570
8571/**
8572 * @license
8573 * Copyright Google LLC All Rights Reserved.
8574 *
8575 * Use of this source code is governed by an MIT-style license that can be
8576 * found in the LICENSE file at https://angular.io/license
8577 */
8578/** A special value which designates that a value has not changed. */
8579const NO_CHANGE = (typeof ngDevMode === 'undefined' || ngDevMode) ? { __brand__: 'NO_CHANGE' } : {};
8580
8581/**
8582 * @license
8583 * Copyright Google LLC All Rights Reserved.
8584 *
8585 * Use of this source code is governed by an MIT-style license that can be
8586 * found in the LICENSE file at https://angular.io/license
8587 */
8588/**
8589 * Advances to an element for later binding instructions.
8590 *
8591 * Used in conjunction with instructions like {@link property} to act on elements with specified
8592 * indices, for example those created with {@link element} or {@link elementStart}.
8593 *
8594 * ```ts
8595 * (rf: RenderFlags, ctx: any) => {
8596 * if (rf & 1) {
8597 * text(0, 'Hello');
8598 * text(1, 'Goodbye')
8599 * element(2, 'div');
8600 * }
8601 * if (rf & 2) {
8602 * advance(2); // Advance twice to the <div>.
8603 * property('title', 'test');
8604 * }
8605 * }
8606 * ```
8607 * @param delta Number of elements to advance forwards by.
8608 *
8609 * @codeGenApi
8610 */
8611function ɵɵadvance(delta) {
8612 ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
8613 selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, !!ngDevMode && isInCheckNoChangesMode());
8614}
8615function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
8616 ngDevMode && assertIndexInDeclRange(lView, index);
8617 // Flush the initial hooks for elements in the view that have been added up to this point.
8618 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
8619 if (!checkNoChangesMode) {
8620 const hooksInitPhaseCompleted = (lView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
8621 if (hooksInitPhaseCompleted) {
8622 const preOrderCheckHooks = tView.preOrderCheckHooks;
8623 if (preOrderCheckHooks !== null) {
8624 executeCheckHooks(lView, preOrderCheckHooks, index);
8625 }
8626 }
8627 else {
8628 const preOrderHooks = tView.preOrderHooks;
8629 if (preOrderHooks !== null) {
8630 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, index);
8631 }
8632 }
8633 }
8634 // We must set the selected index *after* running the hooks, because hooks may have side-effects
8635 // that cause other template functions to run, thus updating the selected index, which is global
8636 // state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index
8637 // will be altered by the time we leave the `ɵɵadvance` instruction.
8638 setSelectedIndex(index);
8639}
8640
8641/**
8642 * @license
8643 * Copyright Google LLC All Rights Reserved.
8644 *
8645 * Use of this source code is governed by an MIT-style license that can be
8646 * found in the LICENSE file at https://angular.io/license
8647 */
8648/**
8649 * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
8650 *
8651 * This should be kept up to date with the public exports of @angular/core.
8652 */
8653const angularCoreDiEnv = {
8654 'ɵɵdefineInjectable': ɵɵdefineInjectable,
8655 'ɵɵdefineInjector': ɵɵdefineInjector,
8656 'ɵɵinject': ɵɵinject,
8657 'ɵɵinvalidFactoryDep': ɵɵinvalidFactoryDep,
8658 'resolveForwardRef': resolveForwardRef,
8659};
8660
8661/**
8662 * @license
8663 * Copyright Google LLC All Rights Reserved.
8664 *
8665 * Use of this source code is governed by an MIT-style license that can be
8666 * found in the LICENSE file at https://angular.io/license
8667 */
8668/**
8669 * Compile an Angular injectable according to its `Injectable` metadata, and patch the resulting
8670 * injectable def (`ɵprov`) onto the injectable type.
8671 */
8672function compileInjectable(type, meta) {
8673 let ngInjectableDef = null;
8674 let ngFactoryDef = null;
8675 // if NG_PROV_DEF is already defined on this class then don't overwrite it
8676 if (!type.hasOwnProperty(NG_PROV_DEF)) {
8677 Object.defineProperty(type, NG_PROV_DEF, {
8678 get: () => {
8679 if (ngInjectableDef === null) {
8680 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'injectable', type });
8681 ngInjectableDef = compiler.compileInjectable(angularCoreDiEnv, `ng:///${type.name}/ɵprov.js`, getInjectableMetadata(type, meta));
8682 }
8683 return ngInjectableDef;
8684 },
8685 });
8686 }
8687 // if NG_FACTORY_DEF is already defined on this class then don't overwrite it
8688 if (!type.hasOwnProperty(NG_FACTORY_DEF)) {
8689 Object.defineProperty(type, NG_FACTORY_DEF, {
8690 get: () => {
8691 if (ngFactoryDef === null) {
8692 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'injectable', type });
8693 ngFactoryDef = compiler.compileFactory(angularCoreDiEnv, `ng:///${type.name}/ɵfac.js`, {
8694 name: type.name,
8695 type,
8696 typeArgumentCount: 0,
8697 deps: reflectDependencies(type),
8698 target: compiler.FactoryTarget.Injectable
8699 });
8700 }
8701 return ngFactoryDef;
8702 },
8703 // Leave this configurable so that the factories from directives or pipes can take precedence.
8704 configurable: true
8705 });
8706 }
8707}
8708const USE_VALUE$1 = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
8709function isUseClassProvider(meta) {
8710 return meta.useClass !== undefined;
8711}
8712function isUseValueProvider(meta) {
8713 return USE_VALUE$1 in meta;
8714}
8715function isUseFactoryProvider(meta) {
8716 return meta.useFactory !== undefined;
8717}
8718function isUseExistingProvider(meta) {
8719 return meta.useExisting !== undefined;
8720}
8721function getInjectableMetadata(type, srcMeta) {
8722 // Allow the compilation of a class with a `@Injectable()` decorator without parameters
8723 const meta = srcMeta || { providedIn: null };
8724 const compilerMeta = {
8725 name: type.name,
8726 type: type,
8727 typeArgumentCount: 0,
8728 providedIn: meta.providedIn,
8729 };
8730 if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) {
8731 compilerMeta.deps = convertDependencies(meta.deps);
8732 }
8733 // Check to see if the user explicitly provided a `useXxxx` property.
8734 if (isUseClassProvider(meta)) {
8735 compilerMeta.useClass = meta.useClass;
8736 }
8737 else if (isUseValueProvider(meta)) {
8738 compilerMeta.useValue = meta.useValue;
8739 }
8740 else if (isUseFactoryProvider(meta)) {
8741 compilerMeta.useFactory = meta.useFactory;
8742 }
8743 else if (isUseExistingProvider(meta)) {
8744 compilerMeta.useExisting = meta.useExisting;
8745 }
8746 return compilerMeta;
8747}
8748
8749/**
8750 * @license
8751 * Copyright Google LLC All Rights Reserved.
8752 *
8753 * Use of this source code is governed by an MIT-style license that can be
8754 * found in the LICENSE file at https://angular.io/license
8755 */
8756/**
8757 * Injectable decorator and metadata.
8758 *
8759 * @Annotation
8760 * @publicApi
8761 */
8762const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, (type, meta) => compileInjectable(type, meta));
8763
8764/**
8765 * @license
8766 * Copyright Google LLC All Rights Reserved.
8767 *
8768 * Use of this source code is governed by an MIT-style license that can be
8769 * found in the LICENSE file at https://angular.io/license
8770 */
8771
8772/**
8773 * @license
8774 * Copyright Google LLC All Rights Reserved.
8775 *
8776 * Use of this source code is governed by an MIT-style license that can be
8777 * found in the LICENSE file at https://angular.io/license
8778 */
8779/**
8780 * A multi-provider token for initialization functions that will run upon construction of an
8781 * environment injector.
8782 *
8783 * @publicApi
8784 */
8785const ENVIRONMENT_INITIALIZER = new InjectionToken('ENVIRONMENT_INITIALIZER');
8786
8787/**
8788 * @license
8789 * Copyright Google LLC All Rights Reserved.
8790 *
8791 * Use of this source code is governed by an MIT-style license that can be
8792 * found in the LICENSE file at https://angular.io/license
8793 */
8794const INJECTOR_DEF_TYPES = new InjectionToken('INJECTOR_DEF_TYPES');
8795
8796/**
8797 * @license
8798 * Copyright Google LLC All Rights Reserved.
8799 *
8800 * Use of this source code is governed by an MIT-style license that can be
8801 * found in the LICENSE file at https://angular.io/license
8802 */
8803/**
8804 * Collects providers from all NgModules and standalone components, including transitively imported
8805 * ones.
8806 *
8807 * Providers extracted via `importProvidersFrom` are only usable in an application injector or
8808 * another environment injector (such as a route injector). They should not be used in component
8809 * providers.
8810 *
8811 * More information about standalone components can be found in [this
8812 * guide](guide/standalone-components).
8813 *
8814 * @usageNotes
8815 * The results of the `importProvidersFrom` call can be used in the `bootstrapApplication` call:
8816 *
8817 * ```typescript
8818 * await bootstrapApplication(RootComponent, {
8819 * providers: [
8820 * importProvidersFrom(NgModuleOne, NgModuleTwo)
8821 * ]
8822 * });
8823 * ```
8824 *
8825 * You can also use the `importProvidersFrom` results in the `providers` field of a route, when a
8826 * standalone component is used:
8827 *
8828 * ```typescript
8829 * export const ROUTES: Route[] = [
8830 * {
8831 * path: 'foo',
8832 * providers: [
8833 * importProvidersFrom(NgModuleOne, NgModuleTwo)
8834 * ],
8835 * component: YourStandaloneComponent
8836 * }
8837 * ];
8838 * ```
8839 *
8840 * @returns Collected providers from the specified list of types.
8841 * @publicApi
8842 * @developerPreview
8843 */
8844function importProvidersFrom(...sources) {
8845 return { ɵproviders: internalImportProvidersFrom(true, sources) };
8846}
8847function internalImportProvidersFrom(checkForStandaloneCmp, ...sources) {
8848 const providersOut = [];
8849 const dedup = new Set(); // already seen types
8850 let injectorTypesWithProviders;
8851 deepForEach(sources, source => {
8852 if ((typeof ngDevMode === 'undefined' || ngDevMode) && checkForStandaloneCmp) {
8853 const cmpDef = getComponentDef(source);
8854 if (cmpDef === null || cmpDef === void 0 ? void 0 : cmpDef.standalone) {
8855 throw new RuntimeError(800 /* RuntimeErrorCode.IMPORT_PROVIDERS_FROM_STANDALONE */, `Importing providers supports NgModule or ModuleWithProviders but got a standalone component "${stringifyForError(source)}"`);
8856 }
8857 }
8858 // Narrow `source` to access the internal type analogue for `ModuleWithProviders`.
8859 const internalSource = source;
8860 if (walkProviderTree(internalSource, providersOut, [], dedup)) {
8861 injectorTypesWithProviders || (injectorTypesWithProviders = []);
8862 injectorTypesWithProviders.push(internalSource);
8863 }
8864 });
8865 // Collect all providers from `ModuleWithProviders` types.
8866 if (injectorTypesWithProviders !== undefined) {
8867 processInjectorTypesWithProviders(injectorTypesWithProviders, providersOut);
8868 }
8869 return providersOut;
8870}
8871/**
8872 * Collects all providers from the list of `ModuleWithProviders` and appends them to the provided
8873 * array.
8874 */
8875function processInjectorTypesWithProviders(typesWithProviders, providersOut) {
8876 for (let i = 0; i < typesWithProviders.length; i++) {
8877 const { ngModule, providers } = typesWithProviders[i];
8878 deepForEach(providers, provider => {
8879 ngDevMode && validateProvider(provider, providers || EMPTY_ARRAY, ngModule);
8880 providersOut.push(provider);
8881 });
8882 }
8883}
8884/**
8885 * The logic visits an `InjectorType`, an `InjectorTypeWithProviders`, or a standalone
8886 * `ComponentType`, and all of its transitive providers and collects providers.
8887 *
8888 * If an `InjectorTypeWithProviders` that declares providers besides the type is specified,
8889 * the function will return "true" to indicate that the providers of the type definition need
8890 * to be processed. This allows us to process providers of injector types after all imports of
8891 * an injector definition are processed. (following View Engine semantics: see FW-1349)
8892 */
8893function walkProviderTree(container, providersOut, parents, dedup) {
8894 container = resolveForwardRef(container);
8895 if (!container)
8896 return false;
8897 // The actual type which had the definition. Usually `container`, but may be an unwrapped type
8898 // from `InjectorTypeWithProviders`.
8899 let defType = null;
8900 let injDef = getInjectorDef(container);
8901 const cmpDef = !injDef && getComponentDef(container);
8902 if (!injDef && !cmpDef) {
8903 // `container` is not an injector type or a component type. It might be:
8904 // * An `InjectorTypeWithProviders` that wraps an injector type.
8905 // * A standalone directive or pipe that got pulled in from a standalone component's
8906 // dependencies.
8907 // Try to unwrap it as an `InjectorTypeWithProviders` first.
8908 const ngModule = container.ngModule;
8909 injDef = getInjectorDef(ngModule);
8910 if (injDef) {
8911 defType = ngModule;
8912 }
8913 else {
8914 // Not a component or injector type, so ignore it.
8915 return false;
8916 }
8917 }
8918 else if (cmpDef && !cmpDef.standalone) {
8919 return false;
8920 }
8921 else {
8922 defType = container;
8923 }
8924 // Check for circular dependencies.
8925 if (ngDevMode && parents.indexOf(defType) !== -1) {
8926 const defName = stringify(defType);
8927 const path = parents.map(stringify);
8928 throwCyclicDependencyError(defName, path);
8929 }
8930 // Check for multiple imports of the same module
8931 const isDuplicate = dedup.has(defType);
8932 if (cmpDef) {
8933 if (isDuplicate) {
8934 // This component definition has already been processed.
8935 return false;
8936 }
8937 dedup.add(defType);
8938 if (cmpDef.dependencies) {
8939 const deps = typeof cmpDef.dependencies === 'function' ? cmpDef.dependencies() : cmpDef.dependencies;
8940 for (const dep of deps) {
8941 walkProviderTree(dep, providersOut, parents, dedup);
8942 }
8943 }
8944 }
8945 else if (injDef) {
8946 // First, include providers from any imports.
8947 if (injDef.imports != null && !isDuplicate) {
8948 // Before processing defType's imports, add it to the set of parents. This way, if it ends
8949 // up deeply importing itself, this can be detected.
8950 ngDevMode && parents.push(defType);
8951 // Add it to the set of dedups. This way we can detect multiple imports of the same module
8952 dedup.add(defType);
8953 let importTypesWithProviders;
8954 try {
8955 deepForEach(injDef.imports, imported => {
8956 if (walkProviderTree(imported, providersOut, parents, dedup)) {
8957 importTypesWithProviders || (importTypesWithProviders = []);
8958 // If the processed import is an injector type with providers, we store it in the
8959 // list of import types with providers, so that we can process those afterwards.
8960 importTypesWithProviders.push(imported);
8961 }
8962 });
8963 }
8964 finally {
8965 // Remove it from the parents set when finished.
8966 ngDevMode && parents.pop();
8967 }
8968 // Imports which are declared with providers (TypeWithProviders) need to be processed
8969 // after all imported modules are processed. This is similar to how View Engine
8970 // processes/merges module imports in the metadata resolver. See: FW-1349.
8971 if (importTypesWithProviders !== undefined) {
8972 processInjectorTypesWithProviders(importTypesWithProviders, providersOut);
8973 }
8974 }
8975 if (!isDuplicate) {
8976 // Track the InjectorType and add a provider for it.
8977 // It's important that this is done after the def's imports.
8978 const factory = getFactoryDef(defType) || (() => new defType());
8979 // Append extra providers to make more info available for consumers (to retrieve an injector
8980 // type), as well as internally (to calculate an injection scope correctly and eagerly
8981 // instantiate a `defType` when an injector is created).
8982 providersOut.push(
8983 // Provider to create `defType` using its factory.
8984 { provide: defType, useFactory: factory, deps: EMPTY_ARRAY },
8985 // Make this `defType` available to an internal logic that calculates injector scope.
8986 { provide: INJECTOR_DEF_TYPES, useValue: defType, multi: true },
8987 // Provider to eagerly instantiate `defType` via `ENVIRONMENT_INITIALIZER`.
8988 { provide: ENVIRONMENT_INITIALIZER, useValue: () => ɵɵinject(defType), multi: true } //
8989 );
8990 }
8991 // Next, include providers listed on the definition itself.
8992 const defProviders = injDef.providers;
8993 if (defProviders != null && !isDuplicate) {
8994 const injectorType = container;
8995 deepForEach(defProviders, provider => {
8996 ngDevMode && validateProvider(provider, defProviders, injectorType);
8997 providersOut.push(provider);
8998 });
8999 }
9000 }
9001 else {
9002 // Should not happen, but just in case.
9003 return false;
9004 }
9005 return (defType !== container &&
9006 container.providers !== undefined);
9007}
9008function validateProvider(provider, providers, containerType) {
9009 if (isTypeProvider(provider) || isValueProvider(provider) || isFactoryProvider(provider) ||
9010 isExistingProvider(provider)) {
9011 return;
9012 }
9013 // Here we expect the provider to be a `useClass` provider (by elimination).
9014 const classRef = resolveForwardRef(provider && (provider.useClass || provider.provide));
9015 if (!classRef) {
9016 throwInvalidProviderError(containerType, providers, provider);
9017 }
9018}
9019const USE_VALUE = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
9020function isValueProvider(value) {
9021 return value !== null && typeof value == 'object' && USE_VALUE in value;
9022}
9023function isExistingProvider(value) {
9024 return !!(value && value.useExisting);
9025}
9026function isFactoryProvider(value) {
9027 return !!(value && value.useFactory);
9028}
9029function isTypeProvider(value) {
9030 return typeof value === 'function';
9031}
9032function isClassProvider(value) {
9033 return !!value.useClass;
9034}
9035
9036/**
9037 * @license
9038 * Copyright Google LLC All Rights Reserved.
9039 *
9040 * Use of this source code is governed by an MIT-style license that can be
9041 * found in the LICENSE file at https://angular.io/license
9042 */
9043/**
9044 * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors.
9045 *
9046 * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a
9047 * project.
9048 *
9049 * @publicApi
9050 */
9051const INJECTOR = new InjectionToken('INJECTOR',
9052// Dissable tslint because this is const enum which gets inlined not top level prop access.
9053// tslint:disable-next-line: no-toplevel-property-access
9054-1 /* InjectorMarkers.Injector */);
9055
9056/**
9057 * @license
9058 * Copyright Google LLC All Rights Reserved.
9059 *
9060 * Use of this source code is governed by an MIT-style license that can be
9061 * found in the LICENSE file at https://angular.io/license
9062 */
9063class NullInjector {
9064 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
9065 if (notFoundValue === THROW_IF_NOT_FOUND) {
9066 const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`);
9067 error.name = 'NullInjectorError';
9068 throw error;
9069 }
9070 return notFoundValue;
9071 }
9072}
9073
9074/**
9075 * @license
9076 * Copyright Google LLC All Rights Reserved.
9077 *
9078 * Use of this source code is governed by an MIT-style license that can be
9079 * found in the LICENSE file at https://angular.io/license
9080 */
9081/**
9082 * An internal token whose presence in an injector indicates that the injector should treat itself
9083 * as a root scoped injector when processing requests for unknown tokens which may indicate
9084 * they are provided in the root scope.
9085 */
9086const INJECTOR_SCOPE = new InjectionToken('Set Injector scope.');
9087
9088/**
9089 * @license
9090 * Copyright Google LLC All Rights Reserved.
9091 *
9092 * Use of this source code is governed by an MIT-style license that can be
9093 * found in the LICENSE file at https://angular.io/license
9094 */
9095/**
9096 * Marker which indicates that a value has not yet been created from the factory function.
9097 */
9098const NOT_YET = {};
9099/**
9100 * Marker which indicates that the factory function for a token is in the process of being called.
9101 *
9102 * If the injector is asked to inject a token with its value set to CIRCULAR, that indicates
9103 * injection of a dependency has recursively attempted to inject the original token, and there is
9104 * a circular dependency among the providers.
9105 */
9106const CIRCULAR = {};
9107/**
9108 * A lazily initialized NullInjector.
9109 */
9110let NULL_INJECTOR$1 = undefined;
9111function getNullInjector() {
9112 if (NULL_INJECTOR$1 === undefined) {
9113 NULL_INJECTOR$1 = new NullInjector();
9114 }
9115 return NULL_INJECTOR$1;
9116}
9117/**
9118 * An `Injector` that's part of the environment injector hierarchy, which exists outside of the
9119 * component tree.
9120 *
9121 * @developerPreview
9122 */
9123class EnvironmentInjector {
9124}
9125class R3Injector extends EnvironmentInjector {
9126 constructor(providers, parent, source, scopes) {
9127 super();
9128 this.parent = parent;
9129 this.source = source;
9130 this.scopes = scopes;
9131 /**
9132 * Map of tokens to records which contain the instances of those tokens.
9133 * - `null` value implies that we don't have the record. Used by tree-shakable injectors
9134 * to prevent further searches.
9135 */
9136 this.records = new Map();
9137 /**
9138 * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks.
9139 */
9140 this._ngOnDestroyHooks = new Set();
9141 this._onDestroyHooks = [];
9142 this._destroyed = false;
9143 // Start off by creating Records for every provider.
9144 forEachSingleProvider(providers, provider => this.processProvider(provider));
9145 // Make sure the INJECTOR token provides this injector.
9146 this.records.set(INJECTOR, makeRecord(undefined, this));
9147 // And `EnvironmentInjector` if the current injector is supposed to be env-scoped.
9148 if (scopes.has('environment')) {
9149 this.records.set(EnvironmentInjector, makeRecord(undefined, this));
9150 }
9151 // Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide
9152 // any injectable scoped to APP_ROOT_SCOPE.
9153 const record = this.records.get(INJECTOR_SCOPE);
9154 if (record != null && typeof record.value === 'string') {
9155 this.scopes.add(record.value);
9156 }
9157 this.injectorDefTypes =
9158 new Set(this.get(INJECTOR_DEF_TYPES.multi, EMPTY_ARRAY, InjectFlags.Self));
9159 }
9160 /**
9161 * Flag indicating that this injector was previously destroyed.
9162 */
9163 get destroyed() {
9164 return this._destroyed;
9165 }
9166 /**
9167 * Destroy the injector and release references to every instance or provider associated with it.
9168 *
9169 * Also calls the `OnDestroy` lifecycle hooks of every instance that was created for which a
9170 * hook was found.
9171 */
9172 destroy() {
9173 this.assertNotDestroyed();
9174 // Set destroyed = true first, in case lifecycle hooks re-enter destroy().
9175 this._destroyed = true;
9176 try {
9177 // Call all the lifecycle hooks.
9178 for (const service of this._ngOnDestroyHooks) {
9179 service.ngOnDestroy();
9180 }
9181 for (const hook of this._onDestroyHooks) {
9182 hook();
9183 }
9184 }
9185 finally {
9186 // Release all references.
9187 this.records.clear();
9188 this._ngOnDestroyHooks.clear();
9189 this.injectorDefTypes.clear();
9190 this._onDestroyHooks.length = 0;
9191 }
9192 }
9193 onDestroy(callback) {
9194 this._onDestroyHooks.push(callback);
9195 }
9196 get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
9197 this.assertNotDestroyed();
9198 // Set the injection context.
9199 const previousInjector = setCurrentInjector(this);
9200 const previousInjectImplementation = setInjectImplementation(undefined);
9201 try {
9202 // Check for the SkipSelf flag.
9203 if (!(flags & InjectFlags.SkipSelf)) {
9204 // SkipSelf isn't set, check if the record belongs to this injector.
9205 let record = this.records.get(token);
9206 if (record === undefined) {
9207 // No record, but maybe the token is scoped to this injector. Look for an injectable
9208 // def with a scope matching this injector.
9209 const def = couldBeInjectableType(token) && getInjectableDef(token);
9210 if (def && this.injectableDefInScope(def)) {
9211 // Found an injectable def and it's scoped to this injector. Pretend as if it was here
9212 // all along.
9213 record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET);
9214 }
9215 else {
9216 record = null;
9217 }
9218 this.records.set(token, record);
9219 }
9220 // If a record was found, get the instance for it and return it.
9221 if (record != null /* NOT null || undefined */) {
9222 return this.hydrate(token, record);
9223 }
9224 }
9225 // Select the next injector based on the Self flag - if self is set, the next injector is
9226 // the NullInjector, otherwise it's the parent.
9227 const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector();
9228 // Set the notFoundValue based on the Optional flag - if optional is set and notFoundValue
9229 // is undefined, the value is null, otherwise it's the notFoundValue.
9230 notFoundValue = (flags & InjectFlags.Optional) && notFoundValue === THROW_IF_NOT_FOUND ?
9231 null :
9232 notFoundValue;
9233 return nextInjector.get(token, notFoundValue);
9234 }
9235 catch (e) {
9236 if (e.name === 'NullInjectorError') {
9237 const path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || [];
9238 path.unshift(stringify(token));
9239 if (previousInjector) {
9240 // We still have a parent injector, keep throwing
9241 throw e;
9242 }
9243 else {
9244 // Format & throw the final error message when we don't have any previous injector
9245 return catchInjectorError(e, token, 'R3InjectorError', this.source);
9246 }
9247 }
9248 else {
9249 throw e;
9250 }
9251 }
9252 finally {
9253 // Lastly, restore the previous injection context.
9254 setInjectImplementation(previousInjectImplementation);
9255 setCurrentInjector(previousInjector);
9256 }
9257 }
9258 /** @internal */
9259 resolveInjectorInitializers() {
9260 const previousInjector = setCurrentInjector(this);
9261 const previousInjectImplementation = setInjectImplementation(undefined);
9262 try {
9263 const initializers = this.get(ENVIRONMENT_INITIALIZER.multi, EMPTY_ARRAY, InjectFlags.Self);
9264 for (const initializer of initializers) {
9265 initializer();
9266 }
9267 }
9268 finally {
9269 setCurrentInjector(previousInjector);
9270 setInjectImplementation(previousInjectImplementation);
9271 }
9272 }
9273 toString() {
9274 const tokens = [];
9275 const records = this.records;
9276 for (const token of records.keys()) {
9277 tokens.push(stringify(token));
9278 }
9279 return `R3Injector[${tokens.join(', ')}]`;
9280 }
9281 assertNotDestroyed() {
9282 if (this._destroyed) {
9283 throw new RuntimeError(205 /* RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED */, ngDevMode && 'Injector has already been destroyed.');
9284 }
9285 }
9286 /**
9287 * Process a `SingleProvider` and add it.
9288 */
9289 processProvider(provider) {
9290 // Determine the token from the provider. Either it's its own token, or has a {provide: ...}
9291 // property.
9292 provider = resolveForwardRef(provider);
9293 let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider && provider.provide);
9294 // Construct a `Record` for the provider.
9295 const record = providerToRecord(provider);
9296 if (!isTypeProvider(provider) && provider.multi === true) {
9297 // If the provider indicates that it's a multi-provider, process it specially.
9298 // First check whether it's been defined already.
9299 let multiRecord = this.records.get(token);
9300 if (multiRecord) {
9301 // It has. Throw a nice error if
9302 if (ngDevMode && multiRecord.multi === undefined) {
9303 throwMixedMultiProviderError();
9304 }
9305 }
9306 else {
9307 multiRecord = makeRecord(undefined, NOT_YET, true);
9308 multiRecord.factory = () => injectArgs(multiRecord.multi);
9309 this.records.set(token, multiRecord);
9310 }
9311 token = provider;
9312 multiRecord.multi.push(provider);
9313 }
9314 else {
9315 const existing = this.records.get(token);
9316 if (ngDevMode && existing && existing.multi !== undefined) {
9317 throwMixedMultiProviderError();
9318 }
9319 }
9320 this.records.set(token, record);
9321 }
9322 hydrate(token, record) {
9323 if (ngDevMode && record.value === CIRCULAR) {
9324 throwCyclicDependencyError(stringify(token));
9325 }
9326 else if (record.value === NOT_YET) {
9327 record.value = CIRCULAR;
9328 record.value = record.factory();
9329 }
9330 if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) {
9331 this._ngOnDestroyHooks.add(record.value);
9332 }
9333 return record.value;
9334 }
9335 injectableDefInScope(def) {
9336 if (!def.providedIn) {
9337 return false;
9338 }
9339 const providedIn = resolveForwardRef(def.providedIn);
9340 if (typeof providedIn === 'string') {
9341 return providedIn === 'any' || (this.scopes.has(providedIn));
9342 }
9343 else {
9344 return this.injectorDefTypes.has(providedIn);
9345 }
9346 }
9347}
9348function injectableDefOrInjectorDefFactory(token) {
9349 // Most tokens will have an injectable def directly on them, which specifies a factory directly.
9350 const injectableDef = getInjectableDef(token);
9351 const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token);
9352 if (factory !== null) {
9353 return factory;
9354 }
9355 // InjectionTokens should have an injectable def (ɵprov) and thus should be handled above.
9356 // If it's missing that, it's an error.
9357 if (token instanceof InjectionToken) {
9358 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Token ${stringify(token)} is missing a ɵprov definition.`);
9359 }
9360 // Undecorated types can sometimes be created if they have no constructor arguments.
9361 if (token instanceof Function) {
9362 return getUndecoratedInjectableFactory(token);
9363 }
9364 // There was no way to resolve a factory for this token.
9365 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && 'unreachable');
9366}
9367function getUndecoratedInjectableFactory(token) {
9368 // If the token has parameters then it has dependencies that we cannot resolve implicitly.
9369 const paramLength = token.length;
9370 if (paramLength > 0) {
9371 const args = newArray(paramLength, '?');
9372 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Can't resolve all parameters for ${stringify(token)}: (${args.join(', ')}).`);
9373 }
9374 // The constructor function appears to have no parameters.
9375 // This might be because it inherits from a super-class. In which case, use an injectable
9376 // def from an ancestor if there is one.
9377 // Otherwise this really is a simple class with no dependencies, so return a factory that
9378 // just instantiates the zero-arg constructor.
9379 const inheritedInjectableDef = getInheritedInjectableDef(token);
9380 if (inheritedInjectableDef !== null) {
9381 return () => inheritedInjectableDef.factory(token);
9382 }
9383 else {
9384 return () => new token();
9385 }
9386}
9387function providerToRecord(provider) {
9388 if (isValueProvider(provider)) {
9389 return makeRecord(undefined, provider.useValue);
9390 }
9391 else {
9392 const factory = providerToFactory(provider);
9393 return makeRecord(factory, NOT_YET);
9394 }
9395}
9396/**
9397 * Converts a `SingleProvider` into a factory function.
9398 *
9399 * @param provider provider to convert to factory
9400 */
9401function providerToFactory(provider, ngModuleType, providers) {
9402 let factory = undefined;
9403 if (ngDevMode && isImportedNgModuleProviders(provider)) {
9404 throwInvalidProviderError(undefined, providers, provider);
9405 }
9406 if (isTypeProvider(provider)) {
9407 const unwrappedProvider = resolveForwardRef(provider);
9408 return getFactoryDef(unwrappedProvider) || injectableDefOrInjectorDefFactory(unwrappedProvider);
9409 }
9410 else {
9411 if (isValueProvider(provider)) {
9412 factory = () => resolveForwardRef(provider.useValue);
9413 }
9414 else if (isFactoryProvider(provider)) {
9415 factory = () => provider.useFactory(...injectArgs(provider.deps || []));
9416 }
9417 else if (isExistingProvider(provider)) {
9418 factory = () => ɵɵinject(resolveForwardRef(provider.useExisting));
9419 }
9420 else {
9421 const classRef = resolveForwardRef(provider &&
9422 (provider.useClass || provider.provide));
9423 if (ngDevMode && !classRef) {
9424 throwInvalidProviderError(ngModuleType, providers, provider);
9425 }
9426 if (hasDeps(provider)) {
9427 factory = () => new (classRef)(...injectArgs(provider.deps));
9428 }
9429 else {
9430 return getFactoryDef(classRef) || injectableDefOrInjectorDefFactory(classRef);
9431 }
9432 }
9433 }
9434 return factory;
9435}
9436function makeRecord(factory, value, multi = false) {
9437 return {
9438 factory: factory,
9439 value: value,
9440 multi: multi ? [] : undefined,
9441 };
9442}
9443function hasDeps(value) {
9444 return !!value.deps;
9445}
9446function hasOnDestroy(value) {
9447 return value !== null && typeof value === 'object' &&
9448 typeof value.ngOnDestroy === 'function';
9449}
9450function couldBeInjectableType(value) {
9451 return (typeof value === 'function') ||
9452 (typeof value === 'object' && value instanceof InjectionToken);
9453}
9454function isImportedNgModuleProviders(provider) {
9455 return !!provider.ɵproviders;
9456}
9457function forEachSingleProvider(providers, fn) {
9458 for (const provider of providers) {
9459 if (Array.isArray(provider)) {
9460 forEachSingleProvider(provider, fn);
9461 }
9462 else if (isImportedNgModuleProviders(provider)) {
9463 forEachSingleProvider(provider.ɵproviders, fn);
9464 }
9465 else {
9466 fn(provider);
9467 }
9468 }
9469}
9470
9471/**
9472 * @license
9473 * Copyright Google LLC All Rights Reserved.
9474 *
9475 * Use of this source code is governed by an MIT-style license that can be
9476 * found in the LICENSE file at https://angular.io/license
9477 */
9478/**
9479 * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s.
9480 *
9481 * @publicApi
9482 */
9483function createInjector(defType, parent = null, additionalProviders = null, name) {
9484 const injector = createInjectorWithoutInjectorInstances(defType, parent, additionalProviders, name);
9485 injector.resolveInjectorInitializers();
9486 return injector;
9487}
9488/**
9489 * Creates a new injector without eagerly resolving its injector types. Can be used in places
9490 * where resolving the injector types immediately can lead to an infinite loop. The injector types
9491 * should be resolved at a later point by calling `_resolveInjectorDefTypes`.
9492 */
9493function createInjectorWithoutInjectorInstances(defType, parent = null, additionalProviders = null, name, scopes = new Set()) {
9494 const providers = [
9495 additionalProviders || EMPTY_ARRAY,
9496 importProvidersFrom(defType),
9497 ];
9498 name = name || (typeof defType === 'object' ? undefined : stringify(defType));
9499 return new R3Injector(providers, parent || getNullInjector(), name || null, scopes);
9500}
9501
9502/**
9503 * @license
9504 * Copyright Google LLC All Rights Reserved.
9505 *
9506 * Use of this source code is governed by an MIT-style license that can be
9507 * found in the LICENSE file at https://angular.io/license
9508 */
9509/**
9510 * Concrete injectors implement this interface. Injectors are configured
9511 * with [providers](guide/glossary#provider) that associate
9512 * dependencies of various types with [injection tokens](guide/glossary#di-token).
9513 *
9514 * @see ["DI Providers"](guide/dependency-injection-providers).
9515 * @see `StaticProvider`
9516 *
9517 * @usageNotes
9518 *
9519 * The following example creates a service injector instance.
9520 *
9521 * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
9522 *
9523 * ### Usage example
9524 *
9525 * {@example core/di/ts/injector_spec.ts region='Injector'}
9526 *
9527 * `Injector` returns itself when given `Injector` as a token:
9528 *
9529 * {@example core/di/ts/injector_spec.ts region='injectInjector'}
9530 *
9531 * @publicApi
9532 */
9533class Injector {
9534 static create(options, parent) {
9535 var _a;
9536 if (Array.isArray(options)) {
9537 return createInjector({ name: '' }, parent, options, '');
9538 }
9539 else {
9540 const name = (_a = options.name) !== null && _a !== void 0 ? _a : '';
9541 return createInjector({ name }, options.parent, options.providers, name);
9542 }
9543 }
9544}
9545Injector.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
9546Injector.NULL = ( /* @__PURE__ */new NullInjector());
9547/** @nocollapse */
9548Injector.ɵprov = ɵɵdefineInjectable({
9549 token: Injector,
9550 providedIn: 'any',
9551 factory: () => ɵɵinject(INJECTOR),
9552});
9553/**
9554 * @internal
9555 * @nocollapse
9556 */
9557Injector.__NG_ELEMENT_ID__ = -1 /* InjectorMarkers.Injector */;
9558
9559/**
9560 * @license
9561 * Copyright Google LLC All Rights Reserved.
9562 *
9563 * Use of this source code is governed by an MIT-style license that can be
9564 * found in the LICENSE file at https://angular.io/license
9565 */
9566function findFirstClosedCycle(keys) {
9567 const res = [];
9568 for (let i = 0; i < keys.length; ++i) {
9569 if (res.indexOf(keys[i]) > -1) {
9570 res.push(keys[i]);
9571 return res;
9572 }
9573 res.push(keys[i]);
9574 }
9575 return res;
9576}
9577function constructResolvingPath(keys) {
9578 if (keys.length > 1) {
9579 const reversed = findFirstClosedCycle(keys.slice().reverse());
9580 const tokenStrs = reversed.map(k => stringify(k.token));
9581 return ' (' + tokenStrs.join(' -> ') + ')';
9582 }
9583 return '';
9584}
9585function injectionError(injector, key, constructResolvingMessage, originalError) {
9586 const keys = [key];
9587 const errMsg = constructResolvingMessage(keys);
9588 const error = (originalError ? wrappedError(errMsg, originalError) : Error(errMsg));
9589 error.addKey = addKey;
9590 error.keys = keys;
9591 error.injectors = [injector];
9592 error.constructResolvingMessage = constructResolvingMessage;
9593 error[ERROR_ORIGINAL_ERROR] = originalError;
9594 return error;
9595}
9596function addKey(injector, key) {
9597 this.injectors.push(injector);
9598 this.keys.push(key);
9599 // Note: This updated message won't be reflected in the `.stack` property
9600 this.message = this.constructResolvingMessage(this.keys);
9601}
9602/**
9603 * Thrown when trying to retrieve a dependency by key from {@link Injector}, but the
9604 * {@link Injector} does not have a {@link Provider} for the given key.
9605 *
9606 * @usageNotes
9607 * ### Example
9608 *
9609 * ```typescript
9610 * class A {
9611 * constructor(b:B) {}
9612 * }
9613 *
9614 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
9615 * ```
9616 */
9617function noProviderError(injector, key) {
9618 return injectionError(injector, key, function (keys) {
9619 const first = stringify(keys[0].token);
9620 return `No provider for ${first}!${constructResolvingPath(keys)}`;
9621 });
9622}
9623/**
9624 * Thrown when dependencies form a cycle.
9625 *
9626 * @usageNotes
9627 * ### Example
9628 *
9629 * ```typescript
9630 * var injector = Injector.resolveAndCreate([
9631 * {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]},
9632 * {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]}
9633 * ]);
9634 *
9635 * expect(() => injector.get("one")).toThrowError();
9636 * ```
9637 *
9638 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
9639 */
9640function cyclicDependencyError(injector, key) {
9641 return injectionError(injector, key, function (keys) {
9642 return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
9643 });
9644}
9645/**
9646 * Thrown when a constructing type returns with an Error.
9647 *
9648 * The `InstantiationError` class contains the original error plus the dependency graph which caused
9649 * this object to be instantiated.
9650 *
9651 * @usageNotes
9652 * ### Example
9653 *
9654 * ```typescript
9655 * class A {
9656 * constructor() {
9657 * throw new Error('message');
9658 * }
9659 * }
9660 *
9661 * var injector = Injector.resolveAndCreate([A]);
9662
9663 * try {
9664 * injector.get(A);
9665 * } catch (e) {
9666 * expect(e instanceof InstantiationError).toBe(true);
9667 * expect(e.originalException.message).toEqual("message");
9668 * expect(e.originalStack).toBeDefined();
9669 * }
9670 * ```
9671 */
9672function instantiationError(injector, originalException, originalStack, key) {
9673 return injectionError(injector, key, function (keys) {
9674 const first = stringify(keys[0].token);
9675 return `${originalException.message}: Error during instantiation of ${first}!${constructResolvingPath(keys)}.`;
9676 }, originalException);
9677}
9678/**
9679 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
9680 * creation.
9681 *
9682 * @usageNotes
9683 * ### Example
9684 *
9685 * ```typescript
9686 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
9687 * ```
9688 */
9689function invalidProviderError(provider) {
9690 return Error(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
9691}
9692/**
9693 * Thrown when the class has no annotation information.
9694 *
9695 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
9696 * need to be injected into the constructor.
9697 *
9698 * @usageNotes
9699 * ### Example
9700 *
9701 * ```typescript
9702 * class A {
9703 * constructor(b) {}
9704 * }
9705 *
9706 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
9707 * ```
9708 *
9709 * This error is also thrown when the class not marked with {@link Injectable} has parameter types.
9710 *
9711 * ```typescript
9712 * class B {}
9713 *
9714 * class A {
9715 * constructor(b:B) {} // no information about the parameter types of A is available at runtime.
9716 * }
9717 *
9718 * expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
9719 * ```
9720 *
9721 */
9722function noAnnotationError(typeOrFunc, params) {
9723 const signature = [];
9724 for (let i = 0, ii = params.length; i < ii; i++) {
9725 const parameter = params[i];
9726 if (!parameter || parameter.length == 0) {
9727 signature.push('?');
9728 }
9729 else {
9730 signature.push(parameter.map(stringify).join(' '));
9731 }
9732 }
9733 return Error('Cannot resolve all parameters for \'' + stringify(typeOrFunc) + '\'(' +
9734 signature.join(', ') + '). ' +
9735 'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
9736 stringify(typeOrFunc) + '\' is decorated with Injectable.');
9737}
9738/**
9739 * Thrown when getting an object by index.
9740 *
9741 * @usageNotes
9742 * ### Example
9743 *
9744 * ```typescript
9745 * class A {}
9746 *
9747 * var injector = Injector.resolveAndCreate([A]);
9748 *
9749 * expect(() => injector.getAt(100)).toThrowError();
9750 * ```
9751 *
9752 */
9753function outOfBoundsError(index) {
9754 return Error(`Index ${index} is out-of-bounds.`);
9755}
9756// TODO: add a working example after alpha38 is released
9757/**
9758 * Thrown when a multi provider and a regular provider are bound to the same token.
9759 *
9760 * @usageNotes
9761 * ### Example
9762 *
9763 * ```typescript
9764 * expect(() => Injector.resolveAndCreate([
9765 * { provide: "Strings", useValue: "string1", multi: true},
9766 * { provide: "Strings", useValue: "string2", multi: false}
9767 * ])).toThrowError();
9768 * ```
9769 */
9770function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) {
9771 return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
9772}
9773
9774/**
9775 * @license
9776 * Copyright Google LLC All Rights Reserved.
9777 *
9778 * Use of this source code is governed by an MIT-style license that can be
9779 * found in the LICENSE file at https://angular.io/license
9780 */
9781/**
9782 * A unique object used for retrieving items from the {@link ReflectiveInjector}.
9783 *
9784 * Keys have:
9785 * - a system-wide unique `id`.
9786 * - a `token`.
9787 *
9788 * `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
9789 * the
9790 * injector to store created objects in a more efficient way.
9791 *
9792 * `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
9793 * resolving
9794 * providers.
9795 *
9796 * @deprecated No replacement
9797 * @publicApi
9798 */
9799class ReflectiveKey {
9800 /**
9801 * Private
9802 */
9803 constructor(token, id) {
9804 this.token = token;
9805 this.id = id;
9806 if (!token) {
9807 throw new Error('Token must be defined!');
9808 }
9809 this.displayName = stringify(this.token);
9810 }
9811 /**
9812 * Retrieves a `Key` for a token.
9813 */
9814 static get(token) {
9815 return _globalKeyRegistry.get(resolveForwardRef(token));
9816 }
9817 /**
9818 * @returns the number of keys registered in the system.
9819 */
9820 static get numberOfKeys() {
9821 return _globalKeyRegistry.numberOfKeys;
9822 }
9823}
9824class KeyRegistry {
9825 constructor() {
9826 this._allKeys = new Map();
9827 }
9828 get(token) {
9829 if (token instanceof ReflectiveKey)
9830 return token;
9831 if (this._allKeys.has(token)) {
9832 return this._allKeys.get(token);
9833 }
9834 const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
9835 this._allKeys.set(token, newKey);
9836 return newKey;
9837 }
9838 get numberOfKeys() {
9839 return this._allKeys.size;
9840 }
9841}
9842const _globalKeyRegistry = new KeyRegistry();
9843
9844/**
9845 * @license
9846 * Copyright Google LLC All Rights Reserved.
9847 *
9848 * Use of this source code is governed by an MIT-style license that can be
9849 * found in the LICENSE file at https://angular.io/license
9850 */
9851/**
9852 * `Dependency` is used by the framework to extend DI.
9853 * This is internal to Angular and should not be used directly.
9854 */
9855class ReflectiveDependency {
9856 constructor(key, optional, visibility) {
9857 this.key = key;
9858 this.optional = optional;
9859 this.visibility = visibility;
9860 }
9861 static fromKey(key) {
9862 return new ReflectiveDependency(key, false, null);
9863 }
9864}
9865const _EMPTY_LIST = [];
9866class ResolvedReflectiveProvider_ {
9867 constructor(key, resolvedFactories, multiProvider) {
9868 this.key = key;
9869 this.resolvedFactories = resolvedFactories;
9870 this.multiProvider = multiProvider;
9871 this.resolvedFactory = this.resolvedFactories[0];
9872 }
9873}
9874/**
9875 * An internal resolved representation of a factory function created by resolving `Provider`.
9876 * @publicApi
9877 */
9878class ResolvedReflectiveFactory {
9879 constructor(
9880 /**
9881 * Factory function which can return an instance of an object represented by a key.
9882 */
9883 factory,
9884 /**
9885 * Arguments (dependencies) to the `factory` function.
9886 */
9887 dependencies) {
9888 this.factory = factory;
9889 this.dependencies = dependencies;
9890 }
9891}
9892/**
9893 * Resolve a single provider.
9894 */
9895function resolveReflectiveFactory(provider) {
9896 let factoryFn;
9897 let resolvedDeps;
9898 if (provider.useClass) {
9899 const useClass = resolveForwardRef(provider.useClass);
9900 factoryFn = getReflect().factory(useClass);
9901 resolvedDeps = _dependenciesFor(useClass);
9902 }
9903 else if (provider.useExisting) {
9904 factoryFn = (aliasInstance) => aliasInstance;
9905 resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
9906 }
9907 else if (provider.useFactory) {
9908 factoryFn = provider.useFactory;
9909 resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
9910 }
9911 else {
9912 factoryFn = () => provider.useValue;
9913 resolvedDeps = _EMPTY_LIST;
9914 }
9915 return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
9916}
9917/**
9918 * Converts the `Provider` into `ResolvedProvider`.
9919 *
9920 * `Injector` internally only uses `ResolvedProvider`, `Provider` contains convenience provider
9921 * syntax.
9922 */
9923function resolveReflectiveProvider(provider) {
9924 return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false);
9925}
9926/**
9927 * Resolve a list of Providers.
9928 */
9929function resolveReflectiveProviders(providers) {
9930 const normalized = _normalizeProviders(providers, []);
9931 const resolved = normalized.map(resolveReflectiveProvider);
9932 const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
9933 return Array.from(resolvedProviderMap.values());
9934}
9935/**
9936 * Merges a list of ResolvedProviders into a list where each key is contained exactly once and
9937 * multi providers have been merged.
9938 */
9939function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) {
9940 for (let i = 0; i < providers.length; i++) {
9941 const provider = providers[i];
9942 const existing = normalizedProvidersMap.get(provider.key.id);
9943 if (existing) {
9944 if (provider.multiProvider !== existing.multiProvider) {
9945 throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
9946 }
9947 if (provider.multiProvider) {
9948 for (let j = 0; j < provider.resolvedFactories.length; j++) {
9949 existing.resolvedFactories.push(provider.resolvedFactories[j]);
9950 }
9951 }
9952 else {
9953 normalizedProvidersMap.set(provider.key.id, provider);
9954 }
9955 }
9956 else {
9957 let resolvedProvider;
9958 if (provider.multiProvider) {
9959 resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider);
9960 }
9961 else {
9962 resolvedProvider = provider;
9963 }
9964 normalizedProvidersMap.set(provider.key.id, resolvedProvider);
9965 }
9966 }
9967 return normalizedProvidersMap;
9968}
9969function _normalizeProviders(providers, res) {
9970 providers.forEach(b => {
9971 if (b instanceof Type) {
9972 res.push({ provide: b, useClass: b });
9973 }
9974 else if (b && typeof b == 'object' && b.provide !== undefined) {
9975 res.push(b);
9976 }
9977 else if (Array.isArray(b)) {
9978 _normalizeProviders(b, res);
9979 }
9980 else {
9981 throw invalidProviderError(b);
9982 }
9983 });
9984 return res;
9985}
9986function constructDependencies(typeOrFunc, dependencies) {
9987 if (!dependencies) {
9988 return _dependenciesFor(typeOrFunc);
9989 }
9990 else {
9991 const params = dependencies.map(t => [t]);
9992 return dependencies.map(t => _extractToken(typeOrFunc, t, params));
9993 }
9994}
9995function _dependenciesFor(typeOrFunc) {
9996 const params = getReflect().parameters(typeOrFunc);
9997 if (!params)
9998 return [];
9999 if (params.some(p => p == null)) {
10000 throw noAnnotationError(typeOrFunc, params);
10001 }
10002 return params.map(p => _extractToken(typeOrFunc, p, params));
10003}
10004function _extractToken(typeOrFunc, metadata, params) {
10005 let token = null;
10006 let optional = false;
10007 if (!Array.isArray(metadata)) {
10008 if (metadata instanceof Inject) {
10009 return _createDependency(metadata.token, optional, null);
10010 }
10011 else {
10012 return _createDependency(metadata, optional, null);
10013 }
10014 }
10015 let visibility = null;
10016 for (let i = 0; i < metadata.length; ++i) {
10017 const paramMetadata = metadata[i];
10018 if (paramMetadata instanceof Type) {
10019 token = paramMetadata;
10020 }
10021 else if (paramMetadata instanceof Inject) {
10022 token = paramMetadata.token;
10023 }
10024 else if (paramMetadata instanceof Optional) {
10025 optional = true;
10026 }
10027 else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
10028 visibility = paramMetadata;
10029 }
10030 else if (paramMetadata instanceof InjectionToken) {
10031 token = paramMetadata;
10032 }
10033 }
10034 token = resolveForwardRef(token);
10035 if (token != null) {
10036 return _createDependency(token, optional, visibility);
10037 }
10038 else {
10039 throw noAnnotationError(typeOrFunc, params);
10040 }
10041}
10042function _createDependency(token, optional, visibility) {
10043 return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
10044}
10045
10046/**
10047 * @license
10048 * Copyright Google LLC All Rights Reserved.
10049 *
10050 * Use of this source code is governed by an MIT-style license that can be
10051 * found in the LICENSE file at https://angular.io/license
10052 */
10053// Threshold for the dynamic version
10054const UNDEFINED = {};
10055/**
10056 * A ReflectiveDependency injection container used for instantiating objects and resolving
10057 * dependencies.
10058 *
10059 * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
10060 * constructor dependencies.
10061 *
10062 * In typical use, application code asks for the dependencies in the constructor and they are
10063 * resolved by the `Injector`.
10064 *
10065 * @usageNotes
10066 * ### Example
10067 *
10068 * The following example creates an `Injector` configured to create `Engine` and `Car`.
10069 *
10070 * ```typescript
10071 * @Injectable()
10072 * class Engine {
10073 * }
10074 *
10075 * @Injectable()
10076 * class Car {
10077 * constructor(public engine:Engine) {}
10078 * }
10079 *
10080 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
10081 * var car = injector.get(Car);
10082 * expect(car instanceof Car).toBe(true);
10083 * expect(car.engine instanceof Engine).toBe(true);
10084 * ```
10085 *
10086 * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
10087 * resolve all of the object's dependencies automatically.
10088 *
10089 * TODO: delete in v14.
10090 *
10091 * @deprecated from v5 - slow and brings in a lot of code, Use `Injector.create` instead.
10092 * @publicApi
10093 */
10094class ReflectiveInjector {
10095 /**
10096 * Turns an array of provider definitions into an array of resolved providers.
10097 *
10098 * A resolution is a process of flattening multiple nested arrays and converting individual
10099 * providers into an array of `ResolvedReflectiveProvider`s.
10100 *
10101 * @usageNotes
10102 * ### Example
10103 *
10104 * ```typescript
10105 * @Injectable()
10106 * class Engine {
10107 * }
10108 *
10109 * @Injectable()
10110 * class Car {
10111 * constructor(public engine:Engine) {}
10112 * }
10113 *
10114 * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
10115 *
10116 * expect(providers.length).toEqual(2);
10117 *
10118 * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
10119 * expect(providers[0].key.displayName).toBe("Car");
10120 * expect(providers[0].dependencies.length).toEqual(1);
10121 * expect(providers[0].factory).toBeDefined();
10122 *
10123 * expect(providers[1].key.displayName).toBe("Engine");
10124 * });
10125 * ```
10126 *
10127 */
10128 static resolve(providers) {
10129 return resolveReflectiveProviders(providers);
10130 }
10131 /**
10132 * Resolves an array of providers and creates an injector from those providers.
10133 *
10134 * The passed-in providers can be an array of `Type`, `Provider`,
10135 * or a recursive array of more providers.
10136 *
10137 * @usageNotes
10138 * ### Example
10139 *
10140 * ```typescript
10141 * @Injectable()
10142 * class Engine {
10143 * }
10144 *
10145 * @Injectable()
10146 * class Car {
10147 * constructor(public engine:Engine) {}
10148 * }
10149 *
10150 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
10151 * expect(injector.get(Car) instanceof Car).toBe(true);
10152 * ```
10153 */
10154 static resolveAndCreate(providers, parent) {
10155 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
10156 return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
10157 }
10158 /**
10159 * Creates an injector from previously resolved providers.
10160 *
10161 * This API is the recommended way to construct injectors in performance-sensitive parts.
10162 *
10163 * @usageNotes
10164 * ### Example
10165 *
10166 * ```typescript
10167 * @Injectable()
10168 * class Engine {
10169 * }
10170 *
10171 * @Injectable()
10172 * class Car {
10173 * constructor(public engine:Engine) {}
10174 * }
10175 *
10176 * var providers = ReflectiveInjector.resolve([Car, Engine]);
10177 * var injector = ReflectiveInjector.fromResolvedProviders(providers);
10178 * expect(injector.get(Car) instanceof Car).toBe(true);
10179 * ```
10180 */
10181 static fromResolvedProviders(providers, parent) {
10182 return new ReflectiveInjector_(providers, parent);
10183 }
10184}
10185class ReflectiveInjector_ {
10186 /**
10187 * Private
10188 */
10189 constructor(_providers, _parent) {
10190 /** @internal */
10191 this._constructionCounter = 0;
10192 this._providers = _providers;
10193 this.parent = _parent || null;
10194 const len = _providers.length;
10195 this.keyIds = [];
10196 this.objs = [];
10197 for (let i = 0; i < len; i++) {
10198 this.keyIds[i] = _providers[i].key.id;
10199 this.objs[i] = UNDEFINED;
10200 }
10201 }
10202 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
10203 return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
10204 }
10205 resolveAndCreateChild(providers) {
10206 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
10207 return this.createChildFromResolved(ResolvedReflectiveProviders);
10208 }
10209 createChildFromResolved(providers) {
10210 const inj = new ReflectiveInjector_(providers);
10211 inj.parent = this;
10212 return inj;
10213 }
10214 resolveAndInstantiate(provider) {
10215 return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
10216 }
10217 instantiateResolved(provider) {
10218 return this._instantiateProvider(provider);
10219 }
10220 getProviderAtIndex(index) {
10221 if (index < 0 || index >= this._providers.length) {
10222 throw outOfBoundsError(index);
10223 }
10224 return this._providers[index];
10225 }
10226 /** @internal */
10227 _new(provider) {
10228 if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
10229 throw cyclicDependencyError(this, provider.key);
10230 }
10231 return this._instantiateProvider(provider);
10232 }
10233 _getMaxNumberOfObjects() {
10234 return this.objs.length;
10235 }
10236 _instantiateProvider(provider) {
10237 if (provider.multiProvider) {
10238 const res = [];
10239 for (let i = 0; i < provider.resolvedFactories.length; ++i) {
10240 res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
10241 }
10242 return res;
10243 }
10244 else {
10245 return this._instantiate(provider, provider.resolvedFactories[0]);
10246 }
10247 }
10248 _instantiate(provider, ResolvedReflectiveFactory) {
10249 const factory = ResolvedReflectiveFactory.factory;
10250 let deps;
10251 try {
10252 deps =
10253 ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
10254 }
10255 catch (e) {
10256 if (e.addKey) {
10257 e.addKey(this, provider.key);
10258 }
10259 throw e;
10260 }
10261 let obj;
10262 try {
10263 obj = factory(...deps);
10264 }
10265 catch (e) {
10266 throw instantiationError(this, e, e.stack, provider.key);
10267 }
10268 return obj;
10269 }
10270 _getByReflectiveDependency(dep) {
10271 return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
10272 }
10273 _getByKey(key, visibility, notFoundValue) {
10274 if (key === ReflectiveInjector_.INJECTOR_KEY) {
10275 return this;
10276 }
10277 if (visibility instanceof Self) {
10278 return this._getByKeySelf(key, notFoundValue);
10279 }
10280 else {
10281 return this._getByKeyDefault(key, notFoundValue, visibility);
10282 }
10283 }
10284 _getObjByKeyId(keyId) {
10285 for (let i = 0; i < this.keyIds.length; i++) {
10286 if (this.keyIds[i] === keyId) {
10287 if (this.objs[i] === UNDEFINED) {
10288 this.objs[i] = this._new(this._providers[i]);
10289 }
10290 return this.objs[i];
10291 }
10292 }
10293 return UNDEFINED;
10294 }
10295 /** @internal */
10296 _throwOrNull(key, notFoundValue) {
10297 if (notFoundValue !== THROW_IF_NOT_FOUND) {
10298 return notFoundValue;
10299 }
10300 else {
10301 throw noProviderError(this, key);
10302 }
10303 }
10304 /** @internal */
10305 _getByKeySelf(key, notFoundValue) {
10306 const obj = this._getObjByKeyId(key.id);
10307 return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
10308 }
10309 /** @internal */
10310 _getByKeyDefault(key, notFoundValue, visibility) {
10311 let inj;
10312 if (visibility instanceof SkipSelf) {
10313 inj = this.parent;
10314 }
10315 else {
10316 inj = this;
10317 }
10318 while (inj instanceof ReflectiveInjector_) {
10319 const inj_ = inj;
10320 const obj = inj_._getObjByKeyId(key.id);
10321 if (obj !== UNDEFINED)
10322 return obj;
10323 inj = inj_.parent;
10324 }
10325 if (inj !== null) {
10326 return inj.get(key.token, notFoundValue);
10327 }
10328 else {
10329 return this._throwOrNull(key, notFoundValue);
10330 }
10331 }
10332 get displayName() {
10333 const providers = _mapProviders(this, (b) => ' "' + b.key.displayName + '" ')
10334 .join(', ');
10335 return `ReflectiveInjector(providers: [${providers}])`;
10336 }
10337 toString() {
10338 return this.displayName;
10339 }
10340}
10341ReflectiveInjector_.INJECTOR_KEY = ( /* @__PURE__ */ReflectiveKey.get(Injector));
10342function _mapProviders(injector, fn) {
10343 const res = [];
10344 for (let i = 0; i < injector._providers.length; ++i) {
10345 res[i] = fn(injector.getProviderAtIndex(i));
10346 }
10347 return res;
10348}
10349
10350/**
10351 * @license
10352 * Copyright Google LLC All Rights Reserved.
10353 *
10354 * Use of this source code is governed by an MIT-style license that can be
10355 * found in the LICENSE file at https://angular.io/license
10356 */
10357
10358/**
10359 * @license
10360 * Copyright Google LLC All Rights Reserved.
10361 *
10362 * Use of this source code is governed by an MIT-style license that can be
10363 * found in the LICENSE file at https://angular.io/license
10364 */
10365
10366/**
10367 * @license
10368 * Copyright Google LLC All Rights Reserved.
10369 *
10370 * Use of this source code is governed by an MIT-style license that can be
10371 * found in the LICENSE file at https://angular.io/license
10372 */
10373function ɵɵdirectiveInject(token, flags = InjectFlags.Default) {
10374 const lView = getLView();
10375 // Fall back to inject() if view hasn't been created. This situation can happen in tests
10376 // if inject utilities are used before bootstrapping.
10377 if (lView === null) {
10378 // Verify that we will not get into infinite loop.
10379 ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject);
10380 return ɵɵinject(token, flags);
10381 }
10382 const tNode = getCurrentTNode();
10383 return getOrCreateInjectable(tNode, lView, resolveForwardRef(token), flags);
10384}
10385/**
10386 * Throws an error indicating that a factory function could not be generated by the compiler for a
10387 * particular class.
10388 *
10389 * This instruction allows the actual error message to be optimized away when ngDevMode is turned
10390 * off, saving bytes of generated code while still providing a good experience in dev mode.
10391 *
10392 * The name of the class is not mentioned here, but will be in the generated factory function name
10393 * and thus in the stack trace.
10394 *
10395 * @codeGenApi
10396 */
10397function ɵɵinvalidFactory() {
10398 const msg = ngDevMode ? `This constructor was not compatible with Dependency Injection.` : 'invalid';
10399 throw new Error(msg);
10400}
10401
10402/**
10403 * @license
10404 * Copyright Google LLC All Rights Reserved.
10405 *
10406 * Use of this source code is governed by an MIT-style license that can be
10407 * found in the LICENSE file at https://angular.io/license
10408 */
10409/**
10410 * Defines a schema that allows an NgModule to contain the following:
10411 * - Non-Angular elements named with dash case (`-`).
10412 * - Element properties named with dash case (`-`).
10413 * Dash case is the naming convention for custom elements.
10414 *
10415 * @publicApi
10416 */
10417const CUSTOM_ELEMENTS_SCHEMA = {
10418 name: 'custom-elements'
10419};
10420/**
10421 * Defines a schema that allows any property on any element.
10422 *
10423 * This schema allows you to ignore the errors related to any unknown elements or properties in a
10424 * template. The usage of this schema is generally discouraged because it prevents useful validation
10425 * and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
10426 *
10427 * @publicApi
10428 */
10429const NO_ERRORS_SCHEMA = {
10430 name: 'no-errors-schema'
10431};
10432
10433/**
10434 * @license
10435 * Copyright Google LLC All Rights Reserved.
10436 *
10437 * Use of this source code is governed by an MIT-style license that can be
10438 * found in the LICENSE file at https://angular.io/license
10439 */
10440let shouldThrowErrorOnUnknownElement = false;
10441/**
10442 * Sets a strict mode for JIT-compiled components to throw an error on unknown elements,
10443 * instead of just logging the error.
10444 * (for AOT-compiled ones this check happens at build time).
10445 */
10446function ɵsetUnknownElementStrictMode(shouldThrow) {
10447 shouldThrowErrorOnUnknownElement = shouldThrow;
10448}
10449/**
10450 * Gets the current value of the strict mode.
10451 */
10452function ɵgetUnknownElementStrictMode() {
10453 return shouldThrowErrorOnUnknownElement;
10454}
10455let shouldThrowErrorOnUnknownProperty = false;
10456/**
10457 * Sets a strict mode for JIT-compiled components to throw an error on unknown properties,
10458 * instead of just logging the error.
10459 * (for AOT-compiled ones this check happens at build time).
10460 */
10461function ɵsetUnknownPropertyStrictMode(shouldThrow) {
10462 shouldThrowErrorOnUnknownProperty = shouldThrow;
10463}
10464/**
10465 * Gets the current value of the strict mode.
10466 */
10467function ɵgetUnknownPropertyStrictMode() {
10468 return shouldThrowErrorOnUnknownProperty;
10469}
10470/**
10471 * Validates that the element is known at runtime and produces
10472 * an error if it's not the case.
10473 * This check is relevant for JIT-compiled components (for AOT-compiled
10474 * ones this check happens at build time).
10475 *
10476 * The element is considered known if either:
10477 * - it's a known HTML element
10478 * - it's a known custom element
10479 * - the element matches any directive
10480 * - the element is allowed by one of the schemas
10481 *
10482 * @param element Element to validate
10483 * @param lView An `LView` that represents a current component that is being rendered
10484 * @param tagName Name of the tag to check
10485 * @param schemas Array of schemas
10486 * @param hasDirectives Boolean indicating that the element matches any directive
10487 */
10488function validateElementIsKnown(element, lView, tagName, schemas, hasDirectives) {
10489 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
10490 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
10491 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
10492 // execute the check below.
10493 if (schemas === null)
10494 return;
10495 // If the element matches any directive, it's considered as valid.
10496 if (!hasDirectives && tagName !== null) {
10497 // The element is unknown if it's an instance of HTMLUnknownElement, or it isn't registered
10498 // as a custom element. Note that unknown elements with a dash in their name won't be instances
10499 // of HTMLUnknownElement in browsers that support web components.
10500 const isUnknown =
10501 // Note that we can't check for `typeof HTMLUnknownElement === 'function'`,
10502 // because while most browsers return 'function', IE returns 'object'.
10503 (typeof HTMLUnknownElement !== 'undefined' && HTMLUnknownElement &&
10504 element instanceof HTMLUnknownElement) ||
10505 (typeof customElements !== 'undefined' && tagName.indexOf('-') > -1 &&
10506 !customElements.get(tagName));
10507 if (isUnknown && !matchingSchemas(schemas, tagName)) {
10508 const isHostStandalone = isHostComponentStandalone(lView);
10509 const templateLocation = getTemplateLocationDetails(lView);
10510 const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
10511 let message = `'${tagName}' is not a known element${templateLocation}:\n`;
10512 message += `1. If '${tagName}' is an Angular component, then verify that it is ${isHostStandalone ? 'included in the \'@Component.imports\' of this component' :
10513 'a part of an @NgModule where this component is declared'}.\n`;
10514 if (tagName && tagName.indexOf('-') > -1) {
10515 message +=
10516 `2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${schemas} of this component to suppress this message.`;
10517 }
10518 else {
10519 message +=
10520 `2. To allow any element add 'NO_ERRORS_SCHEMA' to the ${schemas} of this component.`;
10521 }
10522 if (shouldThrowErrorOnUnknownElement) {
10523 throw new RuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message);
10524 }
10525 else {
10526 console.error(formatRuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message));
10527 }
10528 }
10529 }
10530}
10531/**
10532 * Validates that the property of the element is known at runtime and returns
10533 * false if it's not the case.
10534 * This check is relevant for JIT-compiled components (for AOT-compiled
10535 * ones this check happens at build time).
10536 *
10537 * The property is considered known if either:
10538 * - it's a known property of the element
10539 * - the element is allowed by one of the schemas
10540 * - the property is used for animations
10541 *
10542 * @param element Element to validate
10543 * @param propName Name of the property to check
10544 * @param tagName Name of the tag hosting the property
10545 * @param schemas Array of schemas
10546 */
10547function isPropertyValid(element, propName, tagName, schemas) {
10548 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
10549 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
10550 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
10551 // execute the check below.
10552 if (schemas === null)
10553 return true;
10554 // The property is considered valid if the element matches the schema, it exists on the element,
10555 // or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
10556 if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
10557 return true;
10558 }
10559 // Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
10560 // need to account for both here, while being careful with `typeof null` also returning 'object'.
10561 return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
10562}
10563/**
10564 * Logs or throws an error that a property is not supported on an element.
10565 *
10566 * @param propName Name of the invalid property
10567 * @param tagName Name of the tag hosting the property
10568 * @param nodeType Type of the node hosting the property
10569 * @param lView An `LView` that represents a current component
10570 */
10571function handleUnknownPropertyError(propName, tagName, nodeType, lView) {
10572 // Special-case a situation when a structural directive is applied to
10573 // an `<ng-template>` element, for example: `<ng-template *ngIf="true">`.
10574 // In this case the compiler generates the `ɵɵtemplate` instruction with
10575 // the `null` as the tagName. The directive matching logic at runtime relies
10576 // on this effect (see `isInlineTemplate`), thus using the 'ng-template' as
10577 // a default value of the `tNode.value` is not feasible at this moment.
10578 if (!tagName && nodeType === 4 /* TNodeType.Container */) {
10579 tagName = 'ng-template';
10580 }
10581 const isHostStandalone = isHostComponentStandalone(lView);
10582 const templateLocation = getTemplateLocationDetails(lView);
10583 let message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'${templateLocation}.`;
10584 const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
10585 const importLocation = isHostStandalone ?
10586 'included in the \'@Component.imports\' of this component' :
10587 'a part of an @NgModule where this component is declared';
10588 if (KNOWN_CONTROL_FLOW_DIRECTIVES.has(propName)) {
10589 // Most likely this is a control flow directive (such as `*ngIf`) used in
10590 // a template, but the `CommonModule` is not imported.
10591 message += `\nIf the '${propName}' is an Angular control flow directive, ` +
10592 `please make sure that the 'CommonModule' is ${importLocation}.`;
10593 }
10594 else {
10595 // May be an Angular component, which is not imported/declared?
10596 message += `\n1. If '${tagName}' is an Angular component and it has the ` +
10597 `'${propName}' input, then verify that it is ${importLocation}.`;
10598 // May be a Web Component?
10599 if (tagName && tagName.indexOf('-') > -1) {
10600 message += `\n2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' ` +
10601 `to the ${schemas} of this component to suppress this message.`;
10602 message += `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
10603 `the ${schemas} of this component.`;
10604 }
10605 else {
10606 // If it's expected, the error can be suppressed by the `NO_ERRORS_SCHEMA` schema.
10607 message += `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
10608 `the ${schemas} of this component.`;
10609 }
10610 }
10611 if (shouldThrowErrorOnUnknownProperty) {
10612 throw new RuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message);
10613 }
10614 else {
10615 console.error(formatRuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message));
10616 }
10617}
10618/**
10619 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
10620 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
10621 * be too slow for production mode and also it relies on the constructor function being available.
10622 *
10623 * Gets a reference to the host component def (where a current component is declared).
10624 *
10625 * @param lView An `LView` that represents a current component that is being rendered.
10626 */
10627function getDeclarationComponentDef(lView) {
10628 !ngDevMode && throwError('Must never be called in production mode');
10629 const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
10630 const context = declarationLView[CONTEXT];
10631 // Unable to obtain a context.
10632 if (!context)
10633 return null;
10634 return context.constructor ? getComponentDef(context.constructor) : null;
10635}
10636/**
10637 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
10638 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
10639 * be too slow for production mode.
10640 *
10641 * Checks if the current component is declared inside of a standalone component template.
10642 *
10643 * @param lView An `LView` that represents a current component that is being rendered.
10644 */
10645function isHostComponentStandalone(lView) {
10646 !ngDevMode && throwError('Must never be called in production mode');
10647 const componentDef = getDeclarationComponentDef(lView);
10648 // Treat host component as non-standalone if we can't obtain the def.
10649 return !!(componentDef === null || componentDef === void 0 ? void 0 : componentDef.standalone);
10650}
10651/**
10652 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
10653 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
10654 * be too slow for production mode.
10655 *
10656 * Constructs a string describing the location of the host component template. The function is used
10657 * in dev mode to produce error messages.
10658 *
10659 * @param lView An `LView` that represents a current component that is being rendered.
10660 */
10661function getTemplateLocationDetails(lView) {
10662 var _a;
10663 !ngDevMode && throwError('Must never be called in production mode');
10664 const hostComponentDef = getDeclarationComponentDef(lView);
10665 const componentClassName = (_a = hostComponentDef === null || hostComponentDef === void 0 ? void 0 : hostComponentDef.type) === null || _a === void 0 ? void 0 : _a.name;
10666 return componentClassName ? ` (used in the '${componentClassName}' component template)` : '';
10667}
10668/**
10669 * The set of known control flow directives.
10670 * We use this set to produce a more precises error message with a note
10671 * that the `CommonModule` should also be included.
10672 */
10673const KNOWN_CONTROL_FLOW_DIRECTIVES = new Set(['ngIf', 'ngFor', 'ngSwitch', 'ngSwitchCase', 'ngSwitchDefault']);
10674/**
10675 * Returns true if the tag name is allowed by specified schemas.
10676 * @param schemas Array of schemas
10677 * @param tagName Name of the tag
10678 */
10679function matchingSchemas(schemas, tagName) {
10680 if (schemas !== null) {
10681 for (let i = 0; i < schemas.length; i++) {
10682 const schema = schemas[i];
10683 if (schema === NO_ERRORS_SCHEMA ||
10684 schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
10685 return true;
10686 }
10687 }
10688 }
10689 return false;
10690}
10691
10692/**
10693 * @license
10694 * Copyright Google LLC All Rights Reserved.
10695 *
10696 * Use of this source code is governed by an MIT-style license that can be
10697 * found in the LICENSE file at https://angular.io/license
10698 */
10699/**
10700 * THIS FILE CONTAINS CODE WHICH SHOULD BE TREE SHAKEN AND NEVER CALLED FROM PRODUCTION CODE!!!
10701 */
10702/**
10703 * Creates an `Array` construction with a given name. This is useful when
10704 * looking for memory consumption to see what time of array it is.
10705 *
10706 *
10707 * @param name Name to give to the constructor
10708 * @returns A subclass of `Array` if possible. This can only be done in
10709 * environments which support `class` construct.
10710 */
10711function createNamedArrayType(name) {
10712 // This should never be called in prod mode, so let's verify that is the case.
10713 if (ngDevMode) {
10714 try {
10715 // If this function were compromised the following could lead to arbitrary
10716 // script execution. We bless it with Trusted Types anyway since this
10717 // function is stripped out of production binaries.
10718 return (newTrustedFunctionForDev('Array', `return class ${name} extends Array{}`))(Array);
10719 }
10720 catch (e) {
10721 // If it does not work just give up and fall back to regular Array.
10722 return Array;
10723 }
10724 }
10725 else {
10726 throw new Error('Looks like we are in \'prod mode\', but we are creating a named Array type, which is wrong! Check your code');
10727 }
10728}
10729
10730/**
10731 * @license
10732 * Copyright Google LLC All Rights Reserved.
10733 *
10734 * Use of this source code is governed by an MIT-style license that can be
10735 * found in the LICENSE file at https://angular.io/license
10736 */
10737function toTStylingRange(prev, next) {
10738 ngDevMode && assertNumberInRange(prev, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
10739 ngDevMode && assertNumberInRange(next, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
10740 return (prev << 17 /* StylingRange.PREV_SHIFT */ | next << 2 /* StylingRange.NEXT_SHIFT */);
10741}
10742function getTStylingRangePrev(tStylingRange) {
10743 ngDevMode && assertNumber(tStylingRange, 'expected number');
10744 return (tStylingRange >> 17 /* StylingRange.PREV_SHIFT */) & 32767 /* StylingRange.UNSIGNED_MASK */;
10745}
10746function getTStylingRangePrevDuplicate(tStylingRange) {
10747 ngDevMode && assertNumber(tStylingRange, 'expected number');
10748 return (tStylingRange & 2 /* StylingRange.PREV_DUPLICATE */) ==
10749 2 /* StylingRange.PREV_DUPLICATE */;
10750}
10751function setTStylingRangePrev(tStylingRange, previous) {
10752 ngDevMode && assertNumber(tStylingRange, 'expected number');
10753 ngDevMode && assertNumberInRange(previous, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
10754 return ((tStylingRange & ~4294836224 /* StylingRange.PREV_MASK */) |
10755 (previous << 17 /* StylingRange.PREV_SHIFT */));
10756}
10757function setTStylingRangePrevDuplicate(tStylingRange) {
10758 ngDevMode && assertNumber(tStylingRange, 'expected number');
10759 return (tStylingRange | 2 /* StylingRange.PREV_DUPLICATE */);
10760}
10761function getTStylingRangeNext(tStylingRange) {
10762 ngDevMode && assertNumber(tStylingRange, 'expected number');
10763 return (tStylingRange & 131068 /* StylingRange.NEXT_MASK */) >> 2 /* StylingRange.NEXT_SHIFT */;
10764}
10765function setTStylingRangeNext(tStylingRange, next) {
10766 ngDevMode && assertNumber(tStylingRange, 'expected number');
10767 ngDevMode && assertNumberInRange(next, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
10768 return ((tStylingRange & ~131068 /* StylingRange.NEXT_MASK */) | //
10769 next << 2 /* StylingRange.NEXT_SHIFT */);
10770}
10771function getTStylingRangeNextDuplicate(tStylingRange) {
10772 ngDevMode && assertNumber(tStylingRange, 'expected number');
10773 return (tStylingRange & 1 /* StylingRange.NEXT_DUPLICATE */) ===
10774 1 /* StylingRange.NEXT_DUPLICATE */;
10775}
10776function setTStylingRangeNextDuplicate(tStylingRange) {
10777 ngDevMode && assertNumber(tStylingRange, 'expected number');
10778 return (tStylingRange | 1 /* StylingRange.NEXT_DUPLICATE */);
10779}
10780function getTStylingRangeTail(tStylingRange) {
10781 ngDevMode && assertNumber(tStylingRange, 'expected number');
10782 const next = getTStylingRangeNext(tStylingRange);
10783 return next === 0 ? getTStylingRangePrev(tStylingRange) : next;
10784}
10785
10786/**
10787 * @license
10788 * Copyright Google LLC All Rights Reserved.
10789 *
10790 * Use of this source code is governed by an MIT-style license that can be
10791 * found in the LICENSE file at https://angular.io/license
10792 */
10793/**
10794 * Patch a `debug` property on top of the existing object.
10795 *
10796 * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
10797 *
10798 * @param obj Object to patch
10799 * @param debug Value to patch
10800 */
10801function attachDebugObject(obj, debug) {
10802 if (ngDevMode) {
10803 Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
10804 }
10805 else {
10806 throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
10807 }
10808}
10809/**
10810 * Patch a `debug` property getter on top of the existing object.
10811 *
10812 * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
10813 *
10814 * @param obj Object to patch
10815 * @param debugGetter Getter returning a value to patch
10816 */
10817function attachDebugGetter(obj, debugGetter) {
10818 if (ngDevMode) {
10819 Object.defineProperty(obj, 'debug', { get: debugGetter, enumerable: false });
10820 }
10821 else {
10822 throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
10823 }
10824}
10825
10826/**
10827 * @license
10828 * Copyright Google LLC All Rights Reserved.
10829 *
10830 * Use of this source code is governed by an MIT-style license that can be
10831 * found in the LICENSE file at https://angular.io/license
10832 */
10833/*
10834 * This file contains conditionally attached classes which provide human readable (debug) level
10835 * information for `LView`, `LContainer` and other internal data structures. These data structures
10836 * are stored internally as array which makes it very difficult during debugging to reason about the
10837 * current state of the system.
10838 *
10839 * Patching the array with extra property does change the array's hidden class' but it does not
10840 * change the cost of access, therefore this patching should not have significant if any impact in
10841 * `ngDevMode` mode. (see: https://jsperf.com/array-vs-monkey-patch-array)
10842 *
10843 * So instead of seeing:
10844 * ```
10845 * Array(30) [Object, 659, null, …]
10846 * ```
10847 *
10848 * You get to see:
10849 * ```
10850 * LViewDebug {
10851 * views: [...],
10852 * flags: {attached: true, ...}
10853 * nodes: [
10854 * {html: '<div id="123">', ..., nodes: [
10855 * {html: '<span>', ..., nodes: null}
10856 * ]}
10857 * ]
10858 * }
10859 * ```
10860 */
10861let LVIEW_COMPONENT_CACHE;
10862let LVIEW_EMBEDDED_CACHE;
10863let LVIEW_ROOT;
10864let LVIEW_COMPONENT;
10865let LVIEW_EMBEDDED;
10866/**
10867 * This function clones a blueprint and creates LView.
10868 *
10869 * Simple slice will keep the same type, and we need it to be LView
10870 */
10871function cloneToLViewFromTViewBlueprint(tView) {
10872 const debugTView = tView;
10873 const lView = getLViewToClone(debugTView.type, tView.template && tView.template.name);
10874 return lView.concat(tView.blueprint);
10875}
10876class LRootView extends Array {
10877}
10878class LComponentView extends Array {
10879}
10880class LEmbeddedView extends Array {
10881}
10882function getLViewToClone(type, name) {
10883 switch (type) {
10884 case 0 /* TViewType.Root */:
10885 if (LVIEW_ROOT === undefined)
10886 LVIEW_ROOT = new LRootView();
10887 return LVIEW_ROOT;
10888 case 1 /* TViewType.Component */:
10889 if (!ngDevMode || !ngDevMode.namedConstructors) {
10890 if (LVIEW_COMPONENT === undefined)
10891 LVIEW_COMPONENT = new LComponentView();
10892 return LVIEW_COMPONENT;
10893 }
10894 if (LVIEW_COMPONENT_CACHE === undefined)
10895 LVIEW_COMPONENT_CACHE = new Map();
10896 let componentArray = LVIEW_COMPONENT_CACHE.get(name);
10897 if (componentArray === undefined) {
10898 componentArray = new (createNamedArrayType('LComponentView' + nameSuffix(name)))();
10899 LVIEW_COMPONENT_CACHE.set(name, componentArray);
10900 }
10901 return componentArray;
10902 case 2 /* TViewType.Embedded */:
10903 if (!ngDevMode || !ngDevMode.namedConstructors) {
10904 if (LVIEW_EMBEDDED === undefined)
10905 LVIEW_EMBEDDED = new LEmbeddedView();
10906 return LVIEW_EMBEDDED;
10907 }
10908 if (LVIEW_EMBEDDED_CACHE === undefined)
10909 LVIEW_EMBEDDED_CACHE = new Map();
10910 let embeddedArray = LVIEW_EMBEDDED_CACHE.get(name);
10911 if (embeddedArray === undefined) {
10912 embeddedArray = new (createNamedArrayType('LEmbeddedView' + nameSuffix(name)))();
10913 LVIEW_EMBEDDED_CACHE.set(name, embeddedArray);
10914 }
10915 return embeddedArray;
10916 }
10917}
10918function nameSuffix(text) {
10919 if (text == null)
10920 return '';
10921 const index = text.lastIndexOf('_Template');
10922 return '_' + (index === -1 ? text : text.slice(0, index));
10923}
10924/**
10925 * This class is a debug version of Object literal so that we can have constructor name show up
10926 * in
10927 * debug tools in ngDevMode.
10928 */
10929const TViewConstructor = class TView {
10930 constructor(type, blueprint, template, queries, viewQuery, declTNode, data, bindingStartIndex, expandoStartIndex, hostBindingOpCodes, firstCreatePass, firstUpdatePass, staticViewQueries, staticContentQueries, preOrderHooks, preOrderCheckHooks, contentHooks, contentCheckHooks, viewHooks, viewCheckHooks, destroyHooks, cleanup, contentQueries, components, directiveRegistry, pipeRegistry, firstChild, schemas, consts, incompleteFirstPass, _decls, _vars) {
10931 this.type = type;
10932 this.blueprint = blueprint;
10933 this.template = template;
10934 this.queries = queries;
10935 this.viewQuery = viewQuery;
10936 this.declTNode = declTNode;
10937 this.data = data;
10938 this.bindingStartIndex = bindingStartIndex;
10939 this.expandoStartIndex = expandoStartIndex;
10940 this.hostBindingOpCodes = hostBindingOpCodes;
10941 this.firstCreatePass = firstCreatePass;
10942 this.firstUpdatePass = firstUpdatePass;
10943 this.staticViewQueries = staticViewQueries;
10944 this.staticContentQueries = staticContentQueries;
10945 this.preOrderHooks = preOrderHooks;
10946 this.preOrderCheckHooks = preOrderCheckHooks;
10947 this.contentHooks = contentHooks;
10948 this.contentCheckHooks = contentCheckHooks;
10949 this.viewHooks = viewHooks;
10950 this.viewCheckHooks = viewCheckHooks;
10951 this.destroyHooks = destroyHooks;
10952 this.cleanup = cleanup;
10953 this.contentQueries = contentQueries;
10954 this.components = components;
10955 this.directiveRegistry = directiveRegistry;
10956 this.pipeRegistry = pipeRegistry;
10957 this.firstChild = firstChild;
10958 this.schemas = schemas;
10959 this.consts = consts;
10960 this.incompleteFirstPass = incompleteFirstPass;
10961 this._decls = _decls;
10962 this._vars = _vars;
10963 }
10964 get template_() {
10965 const buf = [];
10966 processTNodeChildren(this.firstChild, buf);
10967 return buf.join('');
10968 }
10969 get type_() {
10970 return TViewTypeAsString[this.type] || `TViewType.?${this.type}?`;
10971 }
10972};
10973class TNode {
10974 constructor(tView_, //
10975 type, //
10976 index, //
10977 insertBeforeIndex, //
10978 injectorIndex, //
10979 directiveStart, //
10980 directiveEnd, //
10981 directiveStylingLast, //
10982 propertyBindings, //
10983 flags, //
10984 providerIndexes, //
10985 value, //
10986 attrs, //
10987 mergedAttrs, //
10988 localNames, //
10989 initialInputs, //
10990 inputs, //
10991 outputs, //
10992 tViews, //
10993 next, //
10994 projectionNext, //
10995 child, //
10996 parent, //
10997 projection, //
10998 styles, //
10999 stylesWithoutHost, //
11000 residualStyles, //
11001 classes, //
11002 classesWithoutHost, //
11003 residualClasses, //
11004 classBindings, //
11005 styleBindings) {
11006 this.tView_ = tView_;
11007 this.type = type;
11008 this.index = index;
11009 this.insertBeforeIndex = insertBeforeIndex;
11010 this.injectorIndex = injectorIndex;
11011 this.directiveStart = directiveStart;
11012 this.directiveEnd = directiveEnd;
11013 this.directiveStylingLast = directiveStylingLast;
11014 this.propertyBindings = propertyBindings;
11015 this.flags = flags;
11016 this.providerIndexes = providerIndexes;
11017 this.value = value;
11018 this.attrs = attrs;
11019 this.mergedAttrs = mergedAttrs;
11020 this.localNames = localNames;
11021 this.initialInputs = initialInputs;
11022 this.inputs = inputs;
11023 this.outputs = outputs;
11024 this.tViews = tViews;
11025 this.next = next;
11026 this.projectionNext = projectionNext;
11027 this.child = child;
11028 this.parent = parent;
11029 this.projection = projection;
11030 this.styles = styles;
11031 this.stylesWithoutHost = stylesWithoutHost;
11032 this.residualStyles = residualStyles;
11033 this.classes = classes;
11034 this.classesWithoutHost = classesWithoutHost;
11035 this.residualClasses = residualClasses;
11036 this.classBindings = classBindings;
11037 this.styleBindings = styleBindings;
11038 }
11039 /**
11040 * Return a human debug version of the set of `NodeInjector`s which will be consulted when
11041 * resolving tokens from this `TNode`.
11042 *
11043 * When debugging applications, it is often difficult to determine which `NodeInjector`s will be
11044 * consulted. This method shows a list of `DebugNode`s representing the `TNode`s which will be
11045 * consulted in order when resolving a token starting at this `TNode`.
11046 *
11047 * The original data is stored in `LView` and `TView` with a lot of offset indexes, and so it is
11048 * difficult to reason about.
11049 *
11050 * @param lView The `LView` instance for this `TNode`.
11051 */
11052 debugNodeInjectorPath(lView) {
11053 const path = [];
11054 let injectorIndex = getInjectorIndex(this, lView);
11055 if (injectorIndex === -1) {
11056 // Looks like the current `TNode` does not have `NodeInjector` associated with it => look for
11057 // parent NodeInjector.
11058 const parentLocation = getParentInjectorLocation(this, lView);
11059 if (parentLocation !== NO_PARENT_INJECTOR) {
11060 // We found a parent, so start searching from the parent location.
11061 injectorIndex = getParentInjectorIndex(parentLocation);
11062 lView = getParentInjectorView(parentLocation, lView);
11063 }
11064 else {
11065 // No parents have been found, so there are no `NodeInjector`s to consult.
11066 }
11067 }
11068 while (injectorIndex !== -1) {
11069 ngDevMode && assertNodeInjector(lView, injectorIndex);
11070 const tNode = lView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
11071 path.push(buildDebugNode(tNode, lView));
11072 const parentLocation = lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */];
11073 if (parentLocation === NO_PARENT_INJECTOR) {
11074 injectorIndex = -1;
11075 }
11076 else {
11077 injectorIndex = getParentInjectorIndex(parentLocation);
11078 lView = getParentInjectorView(parentLocation, lView);
11079 }
11080 }
11081 return path;
11082 }
11083 get type_() {
11084 return toTNodeTypeAsString(this.type) || `TNodeType.?${this.type}?`;
11085 }
11086 get flags_() {
11087 const flags = [];
11088 if (this.flags & 16 /* TNodeFlags.hasClassInput */)
11089 flags.push('TNodeFlags.hasClassInput');
11090 if (this.flags & 8 /* TNodeFlags.hasContentQuery */)
11091 flags.push('TNodeFlags.hasContentQuery');
11092 if (this.flags & 32 /* TNodeFlags.hasStyleInput */)
11093 flags.push('TNodeFlags.hasStyleInput');
11094 if (this.flags & 128 /* TNodeFlags.hasHostBindings */)
11095 flags.push('TNodeFlags.hasHostBindings');
11096 if (this.flags & 2 /* TNodeFlags.isComponentHost */)
11097 flags.push('TNodeFlags.isComponentHost');
11098 if (this.flags & 1 /* TNodeFlags.isDirectiveHost */)
11099 flags.push('TNodeFlags.isDirectiveHost');
11100 if (this.flags & 64 /* TNodeFlags.isDetached */)
11101 flags.push('TNodeFlags.isDetached');
11102 if (this.flags & 4 /* TNodeFlags.isProjected */)
11103 flags.push('TNodeFlags.isProjected');
11104 return flags.join('|');
11105 }
11106 get template_() {
11107 if (this.type & 1 /* TNodeType.Text */)
11108 return this.value;
11109 const buf = [];
11110 const tagName = typeof this.value === 'string' && this.value || this.type_;
11111 buf.push('<', tagName);
11112 if (this.flags) {
11113 buf.push(' ', this.flags_);
11114 }
11115 if (this.attrs) {
11116 for (let i = 0; i < this.attrs.length;) {
11117 const attrName = this.attrs[i++];
11118 if (typeof attrName == 'number') {
11119 break;
11120 }
11121 const attrValue = this.attrs[i++];
11122 buf.push(' ', attrName, '="', attrValue, '"');
11123 }
11124 }
11125 buf.push('>');
11126 processTNodeChildren(this.child, buf);
11127 buf.push('</', tagName, '>');
11128 return buf.join('');
11129 }
11130 get styleBindings_() {
11131 return toDebugStyleBinding(this, false);
11132 }
11133 get classBindings_() {
11134 return toDebugStyleBinding(this, true);
11135 }
11136 get providerIndexStart_() {
11137 return this.providerIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */;
11138 }
11139 get providerIndexEnd_() {
11140 return this.providerIndexStart_ +
11141 (this.providerIndexes >>> 20 /* TNodeProviderIndexes.CptViewProvidersCountShift */);
11142 }
11143}
11144const TNodeDebug = TNode;
11145function toDebugStyleBinding(tNode, isClassBased) {
11146 const tData = tNode.tView_.data;
11147 const bindings = [];
11148 const range = isClassBased ? tNode.classBindings : tNode.styleBindings;
11149 const prev = getTStylingRangePrev(range);
11150 const next = getTStylingRangeNext(range);
11151 let isTemplate = next !== 0;
11152 let cursor = isTemplate ? next : prev;
11153 while (cursor !== 0) {
11154 const itemKey = tData[cursor];
11155 const itemRange = tData[cursor + 1];
11156 bindings.unshift({
11157 key: itemKey,
11158 index: cursor,
11159 isTemplate: isTemplate,
11160 prevDuplicate: getTStylingRangePrevDuplicate(itemRange),
11161 nextDuplicate: getTStylingRangeNextDuplicate(itemRange),
11162 nextIndex: getTStylingRangeNext(itemRange),
11163 prevIndex: getTStylingRangePrev(itemRange),
11164 });
11165 if (cursor === prev)
11166 isTemplate = false;
11167 cursor = getTStylingRangePrev(itemRange);
11168 }
11169 bindings.push((isClassBased ? tNode.residualClasses : tNode.residualStyles) || null);
11170 return bindings;
11171}
11172function processTNodeChildren(tNode, buf) {
11173 while (tNode) {
11174 buf.push(tNode.template_);
11175 tNode = tNode.next;
11176 }
11177}
11178class TViewData extends Array {
11179}
11180let TVIEWDATA_EMPTY; // can't initialize here or it will not be tree shaken, because
11181// `LView` constructor could have side-effects.
11182/**
11183 * This function clones a blueprint and creates TData.
11184 *
11185 * Simple slice will keep the same type, and we need it to be TData
11186 */
11187function cloneToTViewData(list) {
11188 if (TVIEWDATA_EMPTY === undefined)
11189 TVIEWDATA_EMPTY = new TViewData();
11190 return TVIEWDATA_EMPTY.concat(list);
11191}
11192class LViewBlueprint extends Array {
11193}
11194class MatchesArray extends Array {
11195}
11196class TViewComponents extends Array {
11197}
11198class TNodeLocalNames extends Array {
11199}
11200class TNodeInitialInputs extends Array {
11201}
11202class LCleanup extends Array {
11203}
11204class TCleanup extends Array {
11205}
11206function attachLViewDebug(lView) {
11207 attachDebugObject(lView, new LViewDebug(lView));
11208}
11209function attachLContainerDebug(lContainer) {
11210 attachDebugObject(lContainer, new LContainerDebug(lContainer));
11211}
11212function toDebug(obj) {
11213 if (obj) {
11214 const debug = obj.debug;
11215 assertDefined(debug, 'Object does not have a debug representation.');
11216 return debug;
11217 }
11218 else {
11219 return obj;
11220 }
11221}
11222/**
11223 * Use this method to unwrap a native element in `LView` and convert it into HTML for easier
11224 * reading.
11225 *
11226 * @param value possibly wrapped native DOM node.
11227 * @param includeChildren If `true` then the serialized HTML form will include child elements
11228 * (same
11229 * as `outerHTML`). If `false` then the serialized HTML form will only contain the element
11230 * itself
11231 * (will not serialize child elements).
11232 */
11233function toHtml(value, includeChildren = false) {
11234 const node = unwrapRNode(value);
11235 if (node) {
11236 switch (node.nodeType) {
11237 case Node.TEXT_NODE:
11238 return node.textContent;
11239 case Node.COMMENT_NODE:
11240 return `<!--${node.textContent}-->`;
11241 case Node.ELEMENT_NODE:
11242 const outerHTML = node.outerHTML;
11243 if (includeChildren) {
11244 return outerHTML;
11245 }
11246 else {
11247 const innerHTML = '>' + node.innerHTML + '<';
11248 return (outerHTML.split(innerHTML)[0]) + '>';
11249 }
11250 }
11251 }
11252 return null;
11253}
11254class LViewDebug {
11255 constructor(_raw_lView) {
11256 this._raw_lView = _raw_lView;
11257 }
11258 /**
11259 * Flags associated with the `LView` unpacked into a more readable state.
11260 */
11261 get flags() {
11262 const flags = this._raw_lView[FLAGS];
11263 return {
11264 __raw__flags__: flags,
11265 initPhaseState: flags & 3 /* LViewFlags.InitPhaseStateMask */,
11266 creationMode: !!(flags & 4 /* LViewFlags.CreationMode */),
11267 firstViewPass: !!(flags & 8 /* LViewFlags.FirstLViewPass */),
11268 checkAlways: !!(flags & 16 /* LViewFlags.CheckAlways */),
11269 dirty: !!(flags & 32 /* LViewFlags.Dirty */),
11270 attached: !!(flags & 64 /* LViewFlags.Attached */),
11271 destroyed: !!(flags & 128 /* LViewFlags.Destroyed */),
11272 isRoot: !!(flags & 256 /* LViewFlags.IsRoot */),
11273 indexWithinInitPhase: flags >> 11 /* LViewFlags.IndexWithinInitPhaseShift */,
11274 };
11275 }
11276 get parent() {
11277 return toDebug(this._raw_lView[PARENT]);
11278 }
11279 get hostHTML() {
11280 return toHtml(this._raw_lView[HOST], true);
11281 }
11282 get html() {
11283 return (this.nodes || []).map(mapToHTML).join('');
11284 }
11285 get context() {
11286 return this._raw_lView[CONTEXT];
11287 }
11288 /**
11289 * The tree of nodes associated with the current `LView`. The nodes have been normalized into
11290 * a tree structure with relevant details pulled out for readability.
11291 */
11292 get nodes() {
11293 const lView = this._raw_lView;
11294 const tNode = lView[TVIEW].firstChild;
11295 return toDebugNodes(tNode, lView);
11296 }
11297 get template() {
11298 return this.tView.template_;
11299 }
11300 get tView() {
11301 return this._raw_lView[TVIEW];
11302 }
11303 get cleanup() {
11304 return this._raw_lView[CLEANUP];
11305 }
11306 get injector() {
11307 return this._raw_lView[INJECTOR$1];
11308 }
11309 get rendererFactory() {
11310 return this._raw_lView[RENDERER_FACTORY];
11311 }
11312 get renderer() {
11313 return this._raw_lView[RENDERER];
11314 }
11315 get sanitizer() {
11316 return this._raw_lView[SANITIZER];
11317 }
11318 get childHead() {
11319 return toDebug(this._raw_lView[CHILD_HEAD]);
11320 }
11321 get next() {
11322 return toDebug(this._raw_lView[NEXT]);
11323 }
11324 get childTail() {
11325 return toDebug(this._raw_lView[CHILD_TAIL]);
11326 }
11327 get declarationView() {
11328 return toDebug(this._raw_lView[DECLARATION_VIEW]);
11329 }
11330 get queries() {
11331 return this._raw_lView[QUERIES];
11332 }
11333 get tHost() {
11334 return this._raw_lView[T_HOST];
11335 }
11336 get id() {
11337 return this._raw_lView[ID];
11338 }
11339 get decls() {
11340 return toLViewRange(this.tView, this._raw_lView, HEADER_OFFSET, this.tView.bindingStartIndex);
11341 }
11342 get vars() {
11343 return toLViewRange(this.tView, this._raw_lView, this.tView.bindingStartIndex, this.tView.expandoStartIndex);
11344 }
11345 get expando() {
11346 return toLViewRange(this.tView, this._raw_lView, this.tView.expandoStartIndex, this._raw_lView.length);
11347 }
11348 /**
11349 * Normalized view of child views (and containers) attached at this location.
11350 */
11351 get childViews() {
11352 const childViews = [];
11353 let child = this.childHead;
11354 while (child) {
11355 childViews.push(child);
11356 child = child.next;
11357 }
11358 return childViews;
11359 }
11360}
11361function mapToHTML(node) {
11362 if (node.type === 'ElementContainer') {
11363 return (node.children || []).map(mapToHTML).join('');
11364 }
11365 else if (node.type === 'IcuContainer') {
11366 throw new Error('Not implemented');
11367 }
11368 else {
11369 return toHtml(node.native, true) || '';
11370 }
11371}
11372function toLViewRange(tView, lView, start, end) {
11373 let content = [];
11374 for (let index = start; index < end; index++) {
11375 content.push({ index: index, t: tView.data[index], l: lView[index] });
11376 }
11377 return { start: start, end: end, length: end - start, content: content };
11378}
11379/**
11380 * Turns a flat list of nodes into a tree by walking the associated `TNode` tree.
11381 *
11382 * @param tNode
11383 * @param lView
11384 */
11385function toDebugNodes(tNode, lView) {
11386 if (tNode) {
11387 const debugNodes = [];
11388 let tNodeCursor = tNode;
11389 while (tNodeCursor) {
11390 debugNodes.push(buildDebugNode(tNodeCursor, lView));
11391 tNodeCursor = tNodeCursor.next;
11392 }
11393 return debugNodes;
11394 }
11395 else {
11396 return [];
11397 }
11398}
11399function buildDebugNode(tNode, lView) {
11400 const rawValue = lView[tNode.index];
11401 const native = unwrapRNode(rawValue);
11402 const factories = [];
11403 const instances = [];
11404 const tView = lView[TVIEW];
11405 for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
11406 const def = tView.data[i];
11407 factories.push(def.type);
11408 instances.push(lView[i]);
11409 }
11410 return {
11411 html: toHtml(native),
11412 type: toTNodeTypeAsString(tNode.type),
11413 tNode,
11414 native: native,
11415 children: toDebugNodes(tNode.child, lView),
11416 factories,
11417 instances,
11418 injector: buildNodeInjectorDebug(tNode, tView, lView),
11419 get injectorResolutionPath() {
11420 return tNode.debugNodeInjectorPath(lView);
11421 },
11422 };
11423}
11424function buildNodeInjectorDebug(tNode, tView, lView) {
11425 const viewProviders = [];
11426 for (let i = tNode.providerIndexStart_; i < tNode.providerIndexEnd_; i++) {
11427 viewProviders.push(tView.data[i]);
11428 }
11429 const providers = [];
11430 for (let i = tNode.providerIndexEnd_; i < tNode.directiveEnd; i++) {
11431 providers.push(tView.data[i]);
11432 }
11433 const nodeInjectorDebug = {
11434 bloom: toBloom(lView, tNode.injectorIndex),
11435 cumulativeBloom: toBloom(tView.data, tNode.injectorIndex),
11436 providers,
11437 viewProviders,
11438 parentInjectorIndex: lView[tNode.providerIndexStart_ - 1],
11439 };
11440 return nodeInjectorDebug;
11441}
11442/**
11443 * Convert a number at `idx` location in `array` into binary representation.
11444 *
11445 * @param array
11446 * @param idx
11447 */
11448function binary(array, idx) {
11449 const value = array[idx];
11450 // If not a number we print 8 `?` to retain alignment but let user know that it was called on
11451 // wrong type.
11452 if (typeof value !== 'number')
11453 return '????????';
11454 // We prefix 0s so that we have constant length number
11455 const text = '00000000' + value.toString(2);
11456 return text.substring(text.length - 8);
11457}
11458/**
11459 * Convert a bloom filter at location `idx` in `array` into binary representation.
11460 *
11461 * @param array
11462 * @param idx
11463 */
11464function toBloom(array, idx) {
11465 if (idx < 0) {
11466 return 'NO_NODE_INJECTOR';
11467 }
11468 return `${binary(array, idx + 7)}_${binary(array, idx + 6)}_${binary(array, idx + 5)}_${binary(array, idx + 4)}_${binary(array, idx + 3)}_${binary(array, idx + 2)}_${binary(array, idx + 1)}_${binary(array, idx + 0)}`;
11469}
11470class LContainerDebug {
11471 constructor(_raw_lContainer) {
11472 this._raw_lContainer = _raw_lContainer;
11473 }
11474 get hasTransplantedViews() {
11475 return this._raw_lContainer[HAS_TRANSPLANTED_VIEWS];
11476 }
11477 get views() {
11478 return this._raw_lContainer.slice(CONTAINER_HEADER_OFFSET)
11479 .map(toDebug);
11480 }
11481 get parent() {
11482 return toDebug(this._raw_lContainer[PARENT]);
11483 }
11484 get movedViews() {
11485 return this._raw_lContainer[MOVED_VIEWS];
11486 }
11487 get host() {
11488 return this._raw_lContainer[HOST];
11489 }
11490 get native() {
11491 return this._raw_lContainer[NATIVE];
11492 }
11493 get next() {
11494 return toDebug(this._raw_lContainer[NEXT]);
11495 }
11496}
11497
11498/**
11499 * A permanent marker promise which signifies that the current CD tree is
11500 * clean.
11501 */
11502const _CLEAN_PROMISE = (() => Promise.resolve(null))();
11503/**
11504 * Invoke `HostBindingsFunction`s for view.
11505 *
11506 * This methods executes `TView.hostBindingOpCodes`. It is used to execute the
11507 * `HostBindingsFunction`s associated with the current `LView`.
11508 *
11509 * @param tView Current `TView`.
11510 * @param lView Current `LView`.
11511 */
11512function processHostBindingOpCodes(tView, lView) {
11513 const hostBindingOpCodes = tView.hostBindingOpCodes;
11514 if (hostBindingOpCodes === null)
11515 return;
11516 try {
11517 for (let i = 0; i < hostBindingOpCodes.length; i++) {
11518 const opCode = hostBindingOpCodes[i];
11519 if (opCode < 0) {
11520 // Negative numbers are element indexes.
11521 setSelectedIndex(~opCode);
11522 }
11523 else {
11524 // Positive numbers are NumberTuple which store bindingRootIndex and directiveIndex.
11525 const directiveIdx = opCode;
11526 const bindingRootIndx = hostBindingOpCodes[++i];
11527 const hostBindingFn = hostBindingOpCodes[++i];
11528 setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
11529 const context = lView[directiveIdx];
11530 hostBindingFn(2 /* RenderFlags.Update */, context);
11531 }
11532 }
11533 }
11534 finally {
11535 setSelectedIndex(-1);
11536 }
11537}
11538/** Refreshes all content queries declared by directives in a given view */
11539function refreshContentQueries(tView, lView) {
11540 const contentQueries = tView.contentQueries;
11541 if (contentQueries !== null) {
11542 for (let i = 0; i < contentQueries.length; i += 2) {
11543 const queryStartIdx = contentQueries[i];
11544 const directiveDefIdx = contentQueries[i + 1];
11545 if (directiveDefIdx !== -1) {
11546 const directiveDef = tView.data[directiveDefIdx];
11547 ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
11548 ngDevMode &&
11549 assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
11550 setCurrentQueryIndex(queryStartIdx);
11551 directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
11552 }
11553 }
11554 }
11555}
11556/** Refreshes child components in the current view (update mode). */
11557function refreshChildComponents(hostLView, components) {
11558 for (let i = 0; i < components.length; i++) {
11559 refreshComponent(hostLView, components[i]);
11560 }
11561}
11562/** Renders child components in the current view (creation mode). */
11563function renderChildComponents(hostLView, components) {
11564 for (let i = 0; i < components.length; i++) {
11565 renderComponent$1(hostLView, components[i]);
11566 }
11567}
11568function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector, embeddedViewInjector) {
11569 const lView = ngDevMode ? cloneToLViewFromTViewBlueprint(tView) : tView.blueprint.slice();
11570 lView[HOST] = host;
11571 lView[FLAGS] = flags | 4 /* LViewFlags.CreationMode */ | 64 /* LViewFlags.Attached */ | 8 /* LViewFlags.FirstLViewPass */;
11572 if (embeddedViewInjector !== null ||
11573 (parentLView && (parentLView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */))) {
11574 lView[FLAGS] |= 1024 /* LViewFlags.HasEmbeddedViewInjector */;
11575 }
11576 resetPreOrderHookFlags(lView);
11577 ngDevMode && tView.declTNode && parentLView && assertTNodeForLView(tView.declTNode, parentLView);
11578 lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
11579 lView[CONTEXT] = context;
11580 lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]);
11581 ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required');
11582 lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]);
11583 ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required');
11584 lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null;
11585 lView[INJECTOR$1] = injector || parentLView && parentLView[INJECTOR$1] || null;
11586 lView[T_HOST] = tHostNode;
11587 lView[ID] = getUniqueLViewId();
11588 lView[EMBEDDED_VIEW_INJECTOR] = embeddedViewInjector;
11589 ngDevMode &&
11590 assertEqual(tView.type == 2 /* TViewType.Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
11591 lView[DECLARATION_COMPONENT_VIEW] =
11592 tView.type == 2 /* TViewType.Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
11593 ngDevMode && attachLViewDebug(lView);
11594 return lView;
11595}
11596function getOrCreateTNode(tView, index, type, name, attrs) {
11597 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
11598 // `view_engine_compatibility` for additional context.
11599 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
11600 // Keep this function short, so that the VM will inline it.
11601 ngDevMode && assertPureTNodeType(type);
11602 let tNode = tView.data[index];
11603 if (tNode === null) {
11604 tNode = createTNodeAtIndex(tView, index, type, name, attrs);
11605 if (isInI18nBlock()) {
11606 // If we are in i18n block then all elements should be pre declared through `Placeholder`
11607 // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
11608 // If the `TNode` was not pre-declared than it means it was not mentioned which means it was
11609 // removed, so we mark it as detached.
11610 tNode.flags |= 64 /* TNodeFlags.isDetached */;
11611 }
11612 }
11613 else if (tNode.type & 64 /* TNodeType.Placeholder */) {
11614 tNode.type = type;
11615 tNode.value = name;
11616 tNode.attrs = attrs;
11617 const parent = getCurrentParentTNode();
11618 tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex;
11619 ngDevMode && assertTNodeForTView(tNode, tView);
11620 ngDevMode && assertEqual(index, tNode.index, 'Expecting same index');
11621 }
11622 setCurrentTNode(tNode, true);
11623 return tNode;
11624}
11625function createTNodeAtIndex(tView, index, type, name, attrs) {
11626 const currentTNode = getCurrentTNodePlaceholderOk();
11627 const isParent = isCurrentTNodeParent();
11628 const parent = isParent ? currentTNode : currentTNode && currentTNode.parent;
11629 // Parents cannot cross component boundaries because components will be used in multiple places.
11630 const tNode = tView.data[index] =
11631 createTNode(tView, parent, type, index, name, attrs);
11632 // Assign a pointer to the first child node of a given view. The first node is not always the one
11633 // at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
11634 // the index 1 or more, so we can't just check node index.
11635 if (tView.firstChild === null) {
11636 tView.firstChild = tNode;
11637 }
11638 if (currentTNode !== null) {
11639 if (isParent) {
11640 // FIXME(misko): This logic looks unnecessarily complicated. Could we simplify?
11641 if (currentTNode.child == null && tNode.parent !== null) {
11642 // We are in the same view, which means we are adding content node to the parent view.
11643 currentTNode.child = tNode;
11644 }
11645 }
11646 else {
11647 if (currentTNode.next === null) {
11648 // In the case of i18n the `currentTNode` may already be linked, in which case we don't want
11649 // to break the links which i18n created.
11650 currentTNode.next = tNode;
11651 }
11652 }
11653 }
11654 return tNode;
11655}
11656/**
11657 * When elements are created dynamically after a view blueprint is created (e.g. through
11658 * i18nApply()), we need to adjust the blueprint for future
11659 * template passes.
11660 *
11661 * @param tView `TView` associated with `LView`
11662 * @param lView The `LView` containing the blueprint to adjust
11663 * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
11664 * @param initialValue Initial value to store in blueprint
11665 */
11666function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
11667 if (numSlotsToAlloc === 0)
11668 return -1;
11669 if (ngDevMode) {
11670 assertFirstCreatePass(tView);
11671 assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
11672 assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
11673 assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
11674 assertFirstUpdatePass(tView);
11675 }
11676 const allocIdx = lView.length;
11677 for (let i = 0; i < numSlotsToAlloc; i++) {
11678 lView.push(initialValue);
11679 tView.blueprint.push(initialValue);
11680 tView.data.push(null);
11681 }
11682 return allocIdx;
11683}
11684//////////////////////////
11685//// Render
11686//////////////////////////
11687/**
11688 * Processes a view in the creation mode. This includes a number of steps in a specific order:
11689 * - creating view query functions (if any);
11690 * - executing a template function in the creation mode;
11691 * - updating static queries (if any);
11692 * - creating child components defined in a given view.
11693 */
11694function renderView(tView, lView, context) {
11695 ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
11696 enterView(lView);
11697 try {
11698 const viewQuery = tView.viewQuery;
11699 if (viewQuery !== null) {
11700 executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
11701 }
11702 // Execute a template associated with this view, if it exists. A template function might not be
11703 // defined for the root component views.
11704 const templateFn = tView.template;
11705 if (templateFn !== null) {
11706 executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
11707 }
11708 // This needs to be set before children are processed to support recursive components.
11709 // This must be set to false immediately after the first creation run because in an
11710 // ngFor loop, all the views will be created together before update mode runs and turns
11711 // off firstCreatePass. If we don't set it here, instances will perform directive
11712 // matching, etc again and again.
11713 if (tView.firstCreatePass) {
11714 tView.firstCreatePass = false;
11715 }
11716 // We resolve content queries specifically marked as `static` in creation mode. Dynamic
11717 // content queries are resolved during change detection (i.e. update mode), after embedded
11718 // views are refreshed (see block above).
11719 if (tView.staticContentQueries) {
11720 refreshContentQueries(tView, lView);
11721 }
11722 // We must materialize query results before child components are processed
11723 // in case a child component has projected a container. The LContainer needs
11724 // to exist so the embedded views are properly attached by the container.
11725 if (tView.staticViewQueries) {
11726 executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
11727 }
11728 // Render child component views.
11729 const components = tView.components;
11730 if (components !== null) {
11731 renderChildComponents(lView, components);
11732 }
11733 }
11734 catch (error) {
11735 // If we didn't manage to get past the first template pass due to
11736 // an error, mark the view as corrupted so we can try to recover.
11737 if (tView.firstCreatePass) {
11738 tView.incompleteFirstPass = true;
11739 tView.firstCreatePass = false;
11740 }
11741 throw error;
11742 }
11743 finally {
11744 lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
11745 leaveView();
11746 }
11747}
11748/**
11749 * Processes a view in update mode. This includes a number of steps in a specific order:
11750 * - executing a template function in update mode;
11751 * - executing hooks;
11752 * - refreshing queries;
11753 * - setting host bindings;
11754 * - refreshing child (embedded and component) views.
11755 */
11756function refreshView(tView, lView, templateFn, context) {
11757 ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
11758 const flags = lView[FLAGS];
11759 if ((flags & 128 /* LViewFlags.Destroyed */) === 128 /* LViewFlags.Destroyed */)
11760 return;
11761 enterView(lView);
11762 // Check no changes mode is a dev only mode used to verify that bindings have not changed
11763 // since they were assigned. We do not want to execute lifecycle hooks in that mode.
11764 const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
11765 try {
11766 resetPreOrderHookFlags(lView);
11767 setBindingIndex(tView.bindingStartIndex);
11768 if (templateFn !== null) {
11769 executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
11770 }
11771 const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
11772 // execute pre-order hooks (OnInit, OnChanges, DoCheck)
11773 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
11774 if (!isInCheckNoChangesPass) {
11775 if (hooksInitPhaseCompleted) {
11776 const preOrderCheckHooks = tView.preOrderCheckHooks;
11777 if (preOrderCheckHooks !== null) {
11778 executeCheckHooks(lView, preOrderCheckHooks, null);
11779 }
11780 }
11781 else {
11782 const preOrderHooks = tView.preOrderHooks;
11783 if (preOrderHooks !== null) {
11784 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
11785 }
11786 incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
11787 }
11788 }
11789 // First mark transplanted views that are declared in this lView as needing a refresh at their
11790 // insertion points. This is needed to avoid the situation where the template is defined in this
11791 // `LView` but its declaration appears after the insertion component.
11792 markTransplantedViewsForRefresh(lView);
11793 refreshEmbeddedViews(lView);
11794 // Content query results must be refreshed before content hooks are called.
11795 if (tView.contentQueries !== null) {
11796 refreshContentQueries(tView, lView);
11797 }
11798 // execute content hooks (AfterContentInit, AfterContentChecked)
11799 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
11800 if (!isInCheckNoChangesPass) {
11801 if (hooksInitPhaseCompleted) {
11802 const contentCheckHooks = tView.contentCheckHooks;
11803 if (contentCheckHooks !== null) {
11804 executeCheckHooks(lView, contentCheckHooks);
11805 }
11806 }
11807 else {
11808 const contentHooks = tView.contentHooks;
11809 if (contentHooks !== null) {
11810 executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
11811 }
11812 incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
11813 }
11814 }
11815 processHostBindingOpCodes(tView, lView);
11816 // Refresh child component views.
11817 const components = tView.components;
11818 if (components !== null) {
11819 refreshChildComponents(lView, components);
11820 }
11821 // View queries must execute after refreshing child components because a template in this view
11822 // could be inserted in a child component. If the view query executes before child component
11823 // refresh, the template might not yet be inserted.
11824 const viewQuery = tView.viewQuery;
11825 if (viewQuery !== null) {
11826 executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
11827 }
11828 // execute view hooks (AfterViewInit, AfterViewChecked)
11829 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
11830 if (!isInCheckNoChangesPass) {
11831 if (hooksInitPhaseCompleted) {
11832 const viewCheckHooks = tView.viewCheckHooks;
11833 if (viewCheckHooks !== null) {
11834 executeCheckHooks(lView, viewCheckHooks);
11835 }
11836 }
11837 else {
11838 const viewHooks = tView.viewHooks;
11839 if (viewHooks !== null) {
11840 executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
11841 }
11842 incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
11843 }
11844 }
11845 if (tView.firstUpdatePass === true) {
11846 // We need to make sure that we only flip the flag on successful `refreshView` only
11847 // Don't do this in `finally` block.
11848 // If we did this in `finally` block then an exception could block the execution of styling
11849 // instructions which in turn would be unable to insert themselves into the styling linked
11850 // list. The result of this would be that if the exception would not be throw on subsequent CD
11851 // the styling would be unable to process it data and reflect to the DOM.
11852 tView.firstUpdatePass = false;
11853 }
11854 // Do not reset the dirty state when running in check no changes mode. We don't want components
11855 // to behave differently depending on whether check no changes is enabled or not. For example:
11856 // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
11857 // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
11858 // no changes cycle, the component would be not be dirty for the next update pass. This would
11859 // be different in production mode where the component dirty state is not reset.
11860 if (!isInCheckNoChangesPass) {
11861 lView[FLAGS] &= ~(32 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
11862 }
11863 if (lView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
11864 lView[FLAGS] &= ~512 /* LViewFlags.RefreshTransplantedView */;
11865 updateTransplantedViewCount(lView[PARENT], -1);
11866 }
11867 }
11868 finally {
11869 leaveView();
11870 }
11871}
11872function renderComponentOrTemplate(tView, lView, templateFn, context) {
11873 const rendererFactory = lView[RENDERER_FACTORY];
11874 // Check no changes mode is a dev only mode used to verify that bindings have not changed
11875 // since they were assigned. We do not want to invoke renderer factory functions in that mode
11876 // to avoid any possible side-effects.
11877 const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
11878 const creationModeIsActive = isCreationMode(lView);
11879 try {
11880 if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.begin) {
11881 rendererFactory.begin();
11882 }
11883 if (creationModeIsActive) {
11884 renderView(tView, lView, context);
11885 }
11886 refreshView(tView, lView, templateFn, context);
11887 }
11888 finally {
11889 if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.end) {
11890 rendererFactory.end();
11891 }
11892 }
11893}
11894function executeTemplate(tView, lView, templateFn, rf, context) {
11895 const prevSelectedIndex = getSelectedIndex();
11896 const isUpdatePhase = rf & 2 /* RenderFlags.Update */;
11897 try {
11898 setSelectedIndex(-1);
11899 if (isUpdatePhase && lView.length > HEADER_OFFSET) {
11900 // When we're updating, inherently select 0 so we don't
11901 // have to generate that instruction for most update blocks.
11902 selectIndexInternal(tView, lView, HEADER_OFFSET, !!ngDevMode && isInCheckNoChangesMode());
11903 }
11904 const preHookType = isUpdatePhase ? 2 /* ProfilerEvent.TemplateUpdateStart */ : 0 /* ProfilerEvent.TemplateCreateStart */;
11905 profiler(preHookType, context);
11906 templateFn(rf, context);
11907 }
11908 finally {
11909 setSelectedIndex(prevSelectedIndex);
11910 const postHookType = isUpdatePhase ? 3 /* ProfilerEvent.TemplateUpdateEnd */ : 1 /* ProfilerEvent.TemplateCreateEnd */;
11911 profiler(postHookType, context);
11912 }
11913}
11914//////////////////////////
11915//// Element
11916//////////////////////////
11917function executeContentQueries(tView, tNode, lView) {
11918 if (isContentQueryHost(tNode)) {
11919 const start = tNode.directiveStart;
11920 const end = tNode.directiveEnd;
11921 for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
11922 const def = tView.data[directiveIndex];
11923 if (def.contentQueries) {
11924 def.contentQueries(1 /* RenderFlags.Create */, lView[directiveIndex], directiveIndex);
11925 }
11926 }
11927 }
11928}
11929/**
11930 * Creates directive instances.
11931 */
11932function createDirectivesInstances(tView, lView, tNode) {
11933 if (!getBindingsEnabled())
11934 return;
11935 instantiateAllDirectives(tView, lView, tNode, getNativeByTNode(tNode, lView));
11936 if ((tNode.flags & 128 /* TNodeFlags.hasHostBindings */) === 128 /* TNodeFlags.hasHostBindings */) {
11937 invokeDirectivesHostBindings(tView, lView, tNode);
11938 }
11939}
11940/**
11941 * Takes a list of local names and indices and pushes the resolved local variable values
11942 * to LView in the same order as they are loaded in the template with load().
11943 */
11944function saveResolvedLocalsInData(viewData, tNode, localRefExtractor = getNativeByTNode) {
11945 const localNames = tNode.localNames;
11946 if (localNames !== null) {
11947 let localIndex = tNode.index + 1;
11948 for (let i = 0; i < localNames.length; i += 2) {
11949 const index = localNames[i + 1];
11950 const value = index === -1 ?
11951 localRefExtractor(tNode, viewData) :
11952 viewData[index];
11953 viewData[localIndex++] = value;
11954 }
11955 }
11956}
11957/**
11958 * Gets TView from a template function or creates a new TView
11959 * if it doesn't already exist.
11960 *
11961 * @param def ComponentDef
11962 * @returns TView
11963 */
11964function getOrCreateTComponentView(def) {
11965 const tView = def.tView;
11966 // Create a TView if there isn't one, or recreate it if the first create pass didn't
11967 // complete successfully since we can't know for sure whether it's in a usable shape.
11968 if (tView === null || tView.incompleteFirstPass) {
11969 // Declaration node here is null since this function is called when we dynamically create a
11970 // component and hence there is no declaration.
11971 const declTNode = null;
11972 return def.tView = createTView(1 /* TViewType.Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
11973 }
11974 return tView;
11975}
11976/**
11977 * Creates a TView instance
11978 *
11979 * @param type Type of `TView`.
11980 * @param declTNode Declaration location of this `TView`.
11981 * @param templateFn Template function
11982 * @param decls The number of nodes, local refs, and pipes in this template
11983 * @param directives Registry of directives for this view
11984 * @param pipes Registry of pipes for this view
11985 * @param viewQuery View queries for this view
11986 * @param schemas Schemas for this view
11987 * @param consts Constants for this view
11988 */
11989function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
11990 ngDevMode && ngDevMode.tView++;
11991 const bindingStartIndex = HEADER_OFFSET + decls;
11992 // This length does not yet contain host bindings from child directives because at this point,
11993 // we don't know which directives are active on this template. As soon as a directive is matched
11994 // that has a host binding, we will update the blueprint with that def's hostVars count.
11995 const initialViewLength = bindingStartIndex + vars;
11996 const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
11997 const consts = typeof constsOrFactory === 'function' ? constsOrFactory() : constsOrFactory;
11998 const tView = blueprint[TVIEW] = ngDevMode ?
11999 new TViewConstructor(type, // type: TViewType,
12000 blueprint, // blueprint: LView,
12001 templateFn, // template: ComponentTemplate<{}>|null,
12002 null, // queries: TQueries|null
12003 viewQuery, // viewQuery: ViewQueriesFunction<{}>|null,
12004 declTNode, // declTNode: TNode|null,
12005 cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData,
12006 bindingStartIndex, // bindingStartIndex: number,
12007 initialViewLength, // expandoStartIndex: number,
12008 null, // hostBindingOpCodes: HostBindingOpCodes,
12009 true, // firstCreatePass: boolean,
12010 true, // firstUpdatePass: boolean,
12011 false, // staticViewQueries: boolean,
12012 false, // staticContentQueries: boolean,
12013 null, // preOrderHooks: HookData|null,
12014 null, // preOrderCheckHooks: HookData|null,
12015 null, // contentHooks: HookData|null,
12016 null, // contentCheckHooks: HookData|null,
12017 null, // viewHooks: HookData|null,
12018 null, // viewCheckHooks: HookData|null,
12019 null, // destroyHooks: DestroyHookData|null,
12020 null, // cleanup: any[]|null,
12021 null, // contentQueries: number[]|null,
12022 null, // components: number[]|null,
12023 typeof directives === 'function' ? //
12024 directives() : //
12025 directives, // directiveRegistry: DirectiveDefList|null,
12026 typeof pipes === 'function' ? pipes() : pipes, // pipeRegistry: PipeDefList|null,
12027 null, // firstChild: TNode|null,
12028 schemas, // schemas: SchemaMetadata[]|null,
12029 consts, // consts: TConstants|null
12030 false, // incompleteFirstPass: boolean
12031 decls, // ngDevMode only: decls
12032 vars) :
12033 {
12034 type: type,
12035 blueprint: blueprint,
12036 template: templateFn,
12037 queries: null,
12038 viewQuery: viewQuery,
12039 declTNode: declTNode,
12040 data: blueprint.slice().fill(null, bindingStartIndex),
12041 bindingStartIndex: bindingStartIndex,
12042 expandoStartIndex: initialViewLength,
12043 hostBindingOpCodes: null,
12044 firstCreatePass: true,
12045 firstUpdatePass: true,
12046 staticViewQueries: false,
12047 staticContentQueries: false,
12048 preOrderHooks: null,
12049 preOrderCheckHooks: null,
12050 contentHooks: null,
12051 contentCheckHooks: null,
12052 viewHooks: null,
12053 viewCheckHooks: null,
12054 destroyHooks: null,
12055 cleanup: null,
12056 contentQueries: null,
12057 components: null,
12058 directiveRegistry: typeof directives === 'function' ? directives() : directives,
12059 pipeRegistry: typeof pipes === 'function' ? pipes() : pipes,
12060 firstChild: null,
12061 schemas: schemas,
12062 consts: consts,
12063 incompleteFirstPass: false
12064 };
12065 if (ngDevMode) {
12066 // For performance reasons it is important that the tView retains the same shape during runtime.
12067 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
12068 // prevent class transitions.
12069 Object.seal(tView);
12070 }
12071 return tView;
12072}
12073function createViewBlueprint(bindingStartIndex, initialViewLength) {
12074 const blueprint = ngDevMode ? new LViewBlueprint() : [];
12075 for (let i = 0; i < initialViewLength; i++) {
12076 blueprint.push(i < bindingStartIndex ? null : NO_CHANGE);
12077 }
12078 return blueprint;
12079}
12080function createError(text, token) {
12081 return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
12082}
12083function assertHostNodeExists(rElement, elementOrSelector) {
12084 if (!rElement) {
12085 if (typeof elementOrSelector === 'string') {
12086 throw createError('Host node with selector not found:', elementOrSelector);
12087 }
12088 else {
12089 throw createError('Host node is required:', elementOrSelector);
12090 }
12091 }
12092}
12093/**
12094 * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
12095 *
12096 * @param rendererFactory Factory function to create renderer instance.
12097 * @param elementOrSelector Render element or CSS selector to locate the element.
12098 * @param encapsulation View Encapsulation defined for component that requests host element.
12099 */
12100function locateHostElement(renderer, elementOrSelector, encapsulation) {
12101 if (isProceduralRenderer(renderer)) {
12102 // When using native Shadow DOM, do not clear host element to allow native slot projection
12103 const preserveContent = encapsulation === ViewEncapsulation$1.ShadowDom;
12104 return renderer.selectRootElement(elementOrSelector, preserveContent);
12105 }
12106 let rElement = typeof elementOrSelector === 'string' ?
12107 renderer.querySelector(elementOrSelector) :
12108 elementOrSelector;
12109 ngDevMode && assertHostNodeExists(rElement, elementOrSelector);
12110 // Always clear host element's content when Renderer3 is in use. For procedural renderer case we
12111 // make it depend on whether ShadowDom encapsulation is used (in which case the content should be
12112 // preserved to allow native slot projection). ShadowDom encapsulation requires procedural
12113 // renderer, and procedural renderer case is handled above.
12114 rElement.textContent = '';
12115 return rElement;
12116}
12117/**
12118 * Saves context for this cleanup function in LView.cleanupInstances.
12119 *
12120 * On the first template pass, saves in TView:
12121 * - Cleanup function
12122 * - Index of context we just saved in LView.cleanupInstances
12123 *
12124 * This function can also be used to store instance specific cleanup fns. In that case the `context`
12125 * is `null` and the function is store in `LView` (rather than it `TView`).
12126 */
12127function storeCleanupWithContext(tView, lView, context, cleanupFn) {
12128 const lCleanup = getOrCreateLViewCleanup(lView);
12129 if (context === null) {
12130 // If context is null that this is instance specific callback. These callbacks can only be
12131 // inserted after template shared instances. For this reason in ngDevMode we freeze the TView.
12132 if (ngDevMode) {
12133 Object.freeze(getOrCreateTViewCleanup(tView));
12134 }
12135 lCleanup.push(cleanupFn);
12136 }
12137 else {
12138 lCleanup.push(context);
12139 if (tView.firstCreatePass) {
12140 getOrCreateTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1);
12141 }
12142 }
12143}
12144function createTNode(tView, tParent, type, index, value, attrs) {
12145 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
12146 // `view_engine_compatibility` for additional context.
12147 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
12148 ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\'');
12149 ngDevMode && ngDevMode.tNode++;
12150 ngDevMode && tParent && assertTNodeForTView(tParent, tView);
12151 let injectorIndex = tParent ? tParent.injectorIndex : -1;
12152 const tNode = ngDevMode ?
12153 new TNodeDebug(tView, // tView_: TView
12154 type, // type: TNodeType
12155 index, // index: number
12156 null, // insertBeforeIndex: null|-1|number|number[]
12157 injectorIndex, // injectorIndex: number
12158 -1, // directiveStart: number
12159 -1, // directiveEnd: number
12160 -1, // directiveStylingLast: number
12161 null, // propertyBindings: number[]|null
12162 0, // flags: TNodeFlags
12163 0, // providerIndexes: TNodeProviderIndexes
12164 value, // value: string|null
12165 attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
12166 null, // mergedAttrs
12167 null, // localNames: (string|number)[]|null
12168 undefined, // initialInputs: (string[]|null)[]|null|undefined
12169 null, // inputs: PropertyAliases|null
12170 null, // outputs: PropertyAliases|null
12171 null, // tViews: ITView|ITView[]|null
12172 null, // next: ITNode|null
12173 null, // projectionNext: ITNode|null
12174 null, // child: ITNode|null
12175 tParent, // parent: TElementNode|TContainerNode|null
12176 null, // projection: number|(ITNode|RNode[])[]|null
12177 null, // styles: string|null
12178 null, // stylesWithoutHost: string|null
12179 undefined, // residualStyles: string|null
12180 null, // classes: string|null
12181 null, // classesWithoutHost: string|null
12182 undefined, // residualClasses: string|null
12183 0, // classBindings: TStylingRange;
12184 0) :
12185 {
12186 type,
12187 index,
12188 insertBeforeIndex: null,
12189 injectorIndex,
12190 directiveStart: -1,
12191 directiveEnd: -1,
12192 directiveStylingLast: -1,
12193 propertyBindings: null,
12194 flags: 0,
12195 providerIndexes: 0,
12196 value: value,
12197 attrs: attrs,
12198 mergedAttrs: null,
12199 localNames: null,
12200 initialInputs: undefined,
12201 inputs: null,
12202 outputs: null,
12203 tViews: null,
12204 next: null,
12205 projectionNext: null,
12206 child: null,
12207 parent: tParent,
12208 projection: null,
12209 styles: null,
12210 stylesWithoutHost: null,
12211 residualStyles: undefined,
12212 classes: null,
12213 classesWithoutHost: null,
12214 residualClasses: undefined,
12215 classBindings: 0,
12216 styleBindings: 0,
12217 };
12218 if (ngDevMode) {
12219 // For performance reasons it is important that the tNode retains the same shape during runtime.
12220 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
12221 // prevent class transitions.
12222 Object.seal(tNode);
12223 }
12224 return tNode;
12225}
12226function generatePropertyAliases(inputAliasMap, directiveDefIdx, propStore) {
12227 for (let publicName in inputAliasMap) {
12228 if (inputAliasMap.hasOwnProperty(publicName)) {
12229 propStore = propStore === null ? {} : propStore;
12230 const internalName = inputAliasMap[publicName];
12231 if (propStore.hasOwnProperty(publicName)) {
12232 propStore[publicName].push(directiveDefIdx, internalName);
12233 }
12234 else {
12235 (propStore[publicName] = [directiveDefIdx, internalName]);
12236 }
12237 }
12238 }
12239 return propStore;
12240}
12241/**
12242 * Initializes data structures required to work with directive inputs and outputs.
12243 * Initialization is done for all directives matched on a given TNode.
12244 */
12245function initializeInputAndOutputAliases(tView, tNode) {
12246 ngDevMode && assertFirstCreatePass(tView);
12247 const start = tNode.directiveStart;
12248 const end = tNode.directiveEnd;
12249 const tViewData = tView.data;
12250 const tNodeAttrs = tNode.attrs;
12251 const inputsFromAttrs = ngDevMode ? new TNodeInitialInputs() : [];
12252 let inputsStore = null;
12253 let outputsStore = null;
12254 for (let i = start; i < end; i++) {
12255 const directiveDef = tViewData[i];
12256 const directiveInputs = directiveDef.inputs;
12257 // Do not use unbound attributes as inputs to structural directives, since structural
12258 // directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
12259 // TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
12260 // should be set for inline templates.
12261 const initialInputs = (tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
12262 generateInitialInputs(directiveInputs, tNodeAttrs) :
12263 null;
12264 inputsFromAttrs.push(initialInputs);
12265 inputsStore = generatePropertyAliases(directiveInputs, i, inputsStore);
12266 outputsStore = generatePropertyAliases(directiveDef.outputs, i, outputsStore);
12267 }
12268 if (inputsStore !== null) {
12269 if (inputsStore.hasOwnProperty('class')) {
12270 tNode.flags |= 16 /* TNodeFlags.hasClassInput */;
12271 }
12272 if (inputsStore.hasOwnProperty('style')) {
12273 tNode.flags |= 32 /* TNodeFlags.hasStyleInput */;
12274 }
12275 }
12276 tNode.initialInputs = inputsFromAttrs;
12277 tNode.inputs = inputsStore;
12278 tNode.outputs = outputsStore;
12279}
12280/**
12281 * Mapping between attributes names that don't correspond to their element property names.
12282 *
12283 * Performance note: this function is written as a series of if checks (instead of, say, a property
12284 * object lookup) for performance reasons - the series of `if` checks seems to be the fastest way of
12285 * mapping property names. Do NOT change without benchmarking.
12286 *
12287 * Note: this mapping has to be kept in sync with the equally named mapping in the template
12288 * type-checking machinery of ngtsc.
12289 */
12290function mapPropName(name) {
12291 if (name === 'class')
12292 return 'className';
12293 if (name === 'for')
12294 return 'htmlFor';
12295 if (name === 'formaction')
12296 return 'formAction';
12297 if (name === 'innerHtml')
12298 return 'innerHTML';
12299 if (name === 'readonly')
12300 return 'readOnly';
12301 if (name === 'tabindex')
12302 return 'tabIndex';
12303 return name;
12304}
12305function elementPropertyInternal(tView, tNode, lView, propName, value, renderer, sanitizer, nativeOnly) {
12306 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
12307 const element = getNativeByTNode(tNode, lView);
12308 let inputData = tNode.inputs;
12309 let dataValue;
12310 if (!nativeOnly && inputData != null && (dataValue = inputData[propName])) {
12311 setInputsForProperty(tView, lView, dataValue, propName, value);
12312 if (isComponentHost(tNode))
12313 markDirtyIfOnPush(lView, tNode.index);
12314 if (ngDevMode) {
12315 setNgReflectProperties(lView, element, tNode.type, dataValue, value);
12316 }
12317 }
12318 else if (tNode.type & 3 /* TNodeType.AnyRNode */) {
12319 propName = mapPropName(propName);
12320 if (ngDevMode) {
12321 validateAgainstEventProperties(propName);
12322 if (!isPropertyValid(element, propName, tNode.value, tView.schemas)) {
12323 handleUnknownPropertyError(propName, tNode.value, tNode.type, lView);
12324 }
12325 ngDevMode.rendererSetProperty++;
12326 }
12327 // It is assumed that the sanitizer is only added when the compiler determines that the
12328 // property is risky, so sanitization can be done without further checks.
12329 value = sanitizer != null ? sanitizer(value, tNode.value || '', propName) : value;
12330 if (isProceduralRenderer(renderer)) {
12331 renderer.setProperty(element, propName, value);
12332 }
12333 else if (!isAnimationProp(propName)) {
12334 element.setProperty ? element.setProperty(propName, value) :
12335 element[propName] = value;
12336 }
12337 }
12338 else if (tNode.type & 12 /* TNodeType.AnyContainer */) {
12339 // If the node is a container and the property didn't
12340 // match any of the inputs or schemas we should throw.
12341 if (ngDevMode && !matchingSchemas(tView.schemas, tNode.value)) {
12342 handleUnknownPropertyError(propName, tNode.value, tNode.type, lView);
12343 }
12344 }
12345}
12346/** If node is an OnPush component, marks its LView dirty. */
12347function markDirtyIfOnPush(lView, viewIndex) {
12348 ngDevMode && assertLView(lView);
12349 const childComponentLView = getComponentLViewByIndex(viewIndex, lView);
12350 if (!(childComponentLView[FLAGS] & 16 /* LViewFlags.CheckAlways */)) {
12351 childComponentLView[FLAGS] |= 32 /* LViewFlags.Dirty */;
12352 }
12353}
12354function setNgReflectProperty(lView, element, type, attrName, value) {
12355 const renderer = lView[RENDERER];
12356 attrName = normalizeDebugBindingName(attrName);
12357 const debugValue = normalizeDebugBindingValue(value);
12358 if (type & 3 /* TNodeType.AnyRNode */) {
12359 if (value == null) {
12360 isProceduralRenderer(renderer) ? renderer.removeAttribute(element, attrName) :
12361 element.removeAttribute(attrName);
12362 }
12363 else {
12364 isProceduralRenderer(renderer) ?
12365 renderer.setAttribute(element, attrName, debugValue) :
12366 element.setAttribute(attrName, debugValue);
12367 }
12368 }
12369 else {
12370 const textContent = escapeCommentText(`bindings=${JSON.stringify({ [attrName]: debugValue }, null, 2)}`);
12371 if (isProceduralRenderer(renderer)) {
12372 renderer.setValue(element, textContent);
12373 }
12374 else {
12375 element.textContent = textContent;
12376 }
12377 }
12378}
12379function setNgReflectProperties(lView, element, type, dataValue, value) {
12380 if (type & (3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */)) {
12381 /**
12382 * dataValue is an array containing runtime input or output names for the directives:
12383 * i+0: directive instance index
12384 * i+1: privateName
12385 *
12386 * e.g. [0, 'change', 'change-minified']
12387 * we want to set the reflected property with the privateName: dataValue[i+1]
12388 */
12389 for (let i = 0; i < dataValue.length; i += 2) {
12390 setNgReflectProperty(lView, element, type, dataValue[i + 1], value);
12391 }
12392 }
12393}
12394/**
12395 * Instantiate a root component.
12396 */
12397function instantiateRootComponent(tView, lView, def) {
12398 const rootTNode = getCurrentTNode();
12399 if (tView.firstCreatePass) {
12400 if (def.providersResolver)
12401 def.providersResolver(def);
12402 const directiveIndex = allocExpando(tView, lView, 1, null);
12403 ngDevMode &&
12404 assertEqual(directiveIndex, rootTNode.directiveStart, 'Because this is a root component the allocated expando should match the TNode component.');
12405 configureViewWithDirective(tView, rootTNode, lView, directiveIndex, def);
12406 }
12407 const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart, rootTNode);
12408 attachPatchData(directive, lView);
12409 const native = getNativeByTNode(rootTNode, lView);
12410 if (native) {
12411 attachPatchData(native, lView);
12412 }
12413 return directive;
12414}
12415/**
12416 * Resolve the matched directives on a node.
12417 */
12418function resolveDirectives(tView, lView, tNode, localRefs) {
12419 // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
12420 // tsickle.
12421 ngDevMode && assertFirstCreatePass(tView);
12422 let hasDirectives = false;
12423 if (getBindingsEnabled()) {
12424 const directiveDefs = findDirectiveDefMatches(tView, lView, tNode);
12425 const exportsMap = localRefs === null ? null : { '': -1 };
12426 if (directiveDefs !== null) {
12427 hasDirectives = true;
12428 initTNodeFlags(tNode, tView.data.length, directiveDefs.length);
12429 // When the same token is provided by several directives on the same node, some rules apply in
12430 // the viewEngine:
12431 // - viewProviders have priority over providers
12432 // - the last directive in NgModule.declarations has priority over the previous one
12433 // So to match these rules, the order in which providers are added in the arrays is very
12434 // important.
12435 for (let i = 0; i < directiveDefs.length; i++) {
12436 const def = directiveDefs[i];
12437 if (def.providersResolver)
12438 def.providersResolver(def);
12439 }
12440 let preOrderHooksFound = false;
12441 let preOrderCheckHooksFound = false;
12442 let directiveIdx = allocExpando(tView, lView, directiveDefs.length, null);
12443 ngDevMode &&
12444 assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
12445 for (let i = 0; i < directiveDefs.length; i++) {
12446 const def = directiveDefs[i];
12447 // Merge the attrs in the order of matches. This assumes that the first directive is the
12448 // component itself, so that the component has the least priority.
12449 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
12450 configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
12451 saveNameToExportMap(directiveIdx, def, exportsMap);
12452 if (def.contentQueries !== null)
12453 tNode.flags |= 8 /* TNodeFlags.hasContentQuery */;
12454 if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
12455 tNode.flags |= 128 /* TNodeFlags.hasHostBindings */;
12456 const lifeCycleHooks = def.type.prototype;
12457 // Only push a node index into the preOrderHooks array if this is the first
12458 // pre-order hook found on this node.
12459 if (!preOrderHooksFound &&
12460 (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
12461 // We will push the actual hook function into this array later during dir instantiation.
12462 // We cannot do it now because we must ensure hooks are registered in the same
12463 // order that directives are created (i.e. injection order).
12464 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
12465 preOrderHooksFound = true;
12466 }
12467 if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
12468 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
12469 preOrderCheckHooksFound = true;
12470 }
12471 directiveIdx++;
12472 }
12473 initializeInputAndOutputAliases(tView, tNode);
12474 }
12475 if (exportsMap)
12476 cacheMatchingLocalNames(tNode, localRefs, exportsMap);
12477 }
12478 // Merge the template attrs last so that they have the highest priority.
12479 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
12480 return hasDirectives;
12481}
12482/**
12483 * Add `hostBindings` to the `TView.hostBindingOpCodes`.
12484 *
12485 * @param tView `TView` to which the `hostBindings` should be added.
12486 * @param tNode `TNode` the element which contains the directive
12487 * @param lView `LView` current `LView`
12488 * @param directiveIdx Directive index in view.
12489 * @param directiveVarsIdx Where will the directive's vars be stored
12490 * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
12491 */
12492function registerHostBindingOpCodes(tView, tNode, lView, directiveIdx, directiveVarsIdx, def) {
12493 ngDevMode && assertFirstCreatePass(tView);
12494 const hostBindings = def.hostBindings;
12495 if (hostBindings) {
12496 let hostBindingOpCodes = tView.hostBindingOpCodes;
12497 if (hostBindingOpCodes === null) {
12498 hostBindingOpCodes = tView.hostBindingOpCodes = [];
12499 }
12500 const elementIndx = ~tNode.index;
12501 if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
12502 // Conditionally add select element so that we are more efficient in execution.
12503 // NOTE: this is strictly not necessary and it trades code size for runtime perf.
12504 // (We could just always add it.)
12505 hostBindingOpCodes.push(elementIndx);
12506 }
12507 hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
12508 }
12509}
12510/**
12511 * Returns the last selected element index in the `HostBindingOpCodes`
12512 *
12513 * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
12514 * if it changes. This method returns the last index (or '0' if not found.)
12515 *
12516 * Selected element index are only the ones which are negative.
12517 */
12518function lastSelectedElementIdx(hostBindingOpCodes) {
12519 let i = hostBindingOpCodes.length;
12520 while (i > 0) {
12521 const value = hostBindingOpCodes[--i];
12522 if (typeof value === 'number' && value < 0) {
12523 return value;
12524 }
12525 }
12526 return 0;
12527}
12528/**
12529 * Instantiate all the directives that were previously resolved on the current node.
12530 */
12531function instantiateAllDirectives(tView, lView, tNode, native) {
12532 const start = tNode.directiveStart;
12533 const end = tNode.directiveEnd;
12534 if (!tView.firstCreatePass) {
12535 getOrCreateNodeInjectorForNode(tNode, lView);
12536 }
12537 attachPatchData(native, lView);
12538 const initialInputs = tNode.initialInputs;
12539 for (let i = start; i < end; i++) {
12540 const def = tView.data[i];
12541 const isComponent = isComponentDef(def);
12542 if (isComponent) {
12543 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */);
12544 addComponentLogic(lView, tNode, def);
12545 }
12546 const directive = getNodeInjectable(lView, tView, i, tNode);
12547 attachPatchData(directive, lView);
12548 if (initialInputs !== null) {
12549 setInputsFromAttrs(lView, i - start, directive, def, tNode, initialInputs);
12550 }
12551 if (isComponent) {
12552 const componentView = getComponentLViewByIndex(tNode.index, lView);
12553 componentView[CONTEXT] = directive;
12554 }
12555 }
12556}
12557function invokeDirectivesHostBindings(tView, lView, tNode) {
12558 const start = tNode.directiveStart;
12559 const end = tNode.directiveEnd;
12560 const elementIndex = tNode.index;
12561 const currentDirectiveIndex = getCurrentDirectiveIndex();
12562 try {
12563 setSelectedIndex(elementIndex);
12564 for (let dirIndex = start; dirIndex < end; dirIndex++) {
12565 const def = tView.data[dirIndex];
12566 const directive = lView[dirIndex];
12567 setCurrentDirectiveIndex(dirIndex);
12568 if (def.hostBindings !== null || def.hostVars !== 0 || def.hostAttrs !== null) {
12569 invokeHostBindingsInCreationMode(def, directive);
12570 }
12571 }
12572 }
12573 finally {
12574 setSelectedIndex(-1);
12575 setCurrentDirectiveIndex(currentDirectiveIndex);
12576 }
12577}
12578/**
12579 * Invoke the host bindings in creation mode.
12580 *
12581 * @param def `DirectiveDef` which may contain the `hostBindings` function.
12582 * @param directive Instance of directive.
12583 */
12584function invokeHostBindingsInCreationMode(def, directive) {
12585 if (def.hostBindings !== null) {
12586 def.hostBindings(1 /* RenderFlags.Create */, directive);
12587 }
12588}
12589/**
12590 * Matches the current node against all available selectors.
12591 * If a component is matched (at most one), it is returned in first position in the array.
12592 */
12593function findDirectiveDefMatches(tView, viewData, tNode) {
12594 ngDevMode && assertFirstCreatePass(tView);
12595 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
12596 const registry = tView.directiveRegistry;
12597 let matches = null;
12598 if (registry) {
12599 for (let i = 0; i < registry.length; i++) {
12600 const def = registry[i];
12601 if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) {
12602 matches || (matches = ngDevMode ? new MatchesArray() : []);
12603 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, viewData), tView, def.type);
12604 if (isComponentDef(def)) {
12605 if (ngDevMode) {
12606 assertTNodeType(tNode, 2 /* TNodeType.Element */, `"${tNode.value}" tags cannot be used as component hosts. ` +
12607 `Please use a different tag to activate the ${stringify(def.type)} component.`);
12608 if (tNode.flags & 2 /* TNodeFlags.isComponentHost */) {
12609 // If another component has been matched previously, it's the first element in the
12610 // `matches` array, see how we store components/directives in `matches` below.
12611 throwMultipleComponentError(tNode, matches[0].type, def.type);
12612 }
12613 }
12614 markAsComponentHost(tView, tNode);
12615 // The component is always stored first with directives after.
12616 matches.unshift(def);
12617 }
12618 else {
12619 matches.push(def);
12620 }
12621 }
12622 }
12623 }
12624 return matches;
12625}
12626/**
12627 * Marks a given TNode as a component's host. This consists of:
12628 * - setting appropriate TNode flags;
12629 * - storing index of component's host element so it will be queued for view refresh during CD.
12630 */
12631function markAsComponentHost(tView, hostTNode) {
12632 ngDevMode && assertFirstCreatePass(tView);
12633 hostTNode.flags |= 2 /* TNodeFlags.isComponentHost */;
12634 (tView.components || (tView.components = ngDevMode ? new TViewComponents() : []))
12635 .push(hostTNode.index);
12636}
12637/** Caches local names and their matching directive indices for query and template lookups. */
12638function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
12639 if (localRefs) {
12640 const localNames = tNode.localNames = ngDevMode ? new TNodeLocalNames() : [];
12641 // Local names must be stored in tNode in the same order that localRefs are defined
12642 // in the template to ensure the data is loaded in the same slots as their refs
12643 // in the template (for template queries).
12644 for (let i = 0; i < localRefs.length; i += 2) {
12645 const index = exportsMap[localRefs[i + 1]];
12646 if (index == null)
12647 throw new RuntimeError(-301 /* RuntimeErrorCode.EXPORT_NOT_FOUND */, ngDevMode && `Export of name '${localRefs[i + 1]}' not found!`);
12648 localNames.push(localRefs[i], index);
12649 }
12650 }
12651}
12652/**
12653 * Builds up an export map as directives are created, so local refs can be quickly mapped
12654 * to their directive instances.
12655 */
12656function saveNameToExportMap(directiveIdx, def, exportsMap) {
12657 if (exportsMap) {
12658 if (def.exportAs) {
12659 for (let i = 0; i < def.exportAs.length; i++) {
12660 exportsMap[def.exportAs[i]] = directiveIdx;
12661 }
12662 }
12663 if (isComponentDef(def))
12664 exportsMap[''] = directiveIdx;
12665 }
12666}
12667/**
12668 * Initializes the flags on the current node, setting all indices to the initial index,
12669 * the directive count to 0, and adding the isComponent flag.
12670 * @param index the initial index
12671 */
12672function initTNodeFlags(tNode, index, numberOfDirectives) {
12673 ngDevMode &&
12674 assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
12675 tNode.flags |= 1 /* TNodeFlags.isDirectiveHost */;
12676 // When the first directive is created on a node, save the index
12677 tNode.directiveStart = index;
12678 tNode.directiveEnd = index + numberOfDirectives;
12679 tNode.providerIndexes = index;
12680}
12681/**
12682 * Setup directive for instantiation.
12683 *
12684 * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
12685 * as `LView`. `TView` gets the `DirectiveDef`.
12686 *
12687 * @param tView `TView`
12688 * @param tNode `TNode`
12689 * @param lView `LView`
12690 * @param directiveIndex Index where the directive will be stored in the Expando.
12691 * @param def `DirectiveDef`
12692 */
12693function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
12694 ngDevMode &&
12695 assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
12696 tView.data[directiveIndex] = def;
12697 const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
12698 // Even though `directiveFactory` will already be using `ɵɵdirectiveInject` in its generated code,
12699 // we also want to support `inject()` directly from the directive constructor context so we set
12700 // `ɵɵdirectiveInject` as the inject implementation here too.
12701 const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
12702 tView.blueprint[directiveIndex] = nodeInjectorFactory;
12703 lView[directiveIndex] = nodeInjectorFactory;
12704 registerHostBindingOpCodes(tView, tNode, lView, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
12705}
12706function addComponentLogic(lView, hostTNode, def) {
12707 const native = getNativeByTNode(hostTNode, lView);
12708 const tView = getOrCreateTComponentView(def);
12709 // Only component views should be added to the view tree directly. Embedded views are
12710 // accessed through their containers because they may be removed / re-added later.
12711 const rendererFactory = lView[RENDERER_FACTORY];
12712 const componentView = addToViewTree(lView, createLView(lView, tView, null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, native, hostTNode, rendererFactory, rendererFactory.createRenderer(native, def), null, null, null));
12713 // Component view will always be created before any injected LContainers,
12714 // so this is a regular element, wrap it with the component view
12715 lView[hostTNode.index] = componentView;
12716}
12717function elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace) {
12718 if (ngDevMode) {
12719 assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
12720 validateAgainstEventAttributes(name);
12721 assertTNodeType(tNode, 2 /* TNodeType.Element */, `Attempted to set attribute \`${name}\` on a container node. ` +
12722 `Host bindings are not valid on ng-container or ng-template.`);
12723 }
12724 const element = getNativeByTNode(tNode, lView);
12725 setElementAttribute(lView[RENDERER], element, namespace, tNode.value, name, value, sanitizer);
12726}
12727function setElementAttribute(renderer, element, namespace, tagName, name, value, sanitizer) {
12728 if (value == null) {
12729 ngDevMode && ngDevMode.rendererRemoveAttribute++;
12730 isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) :
12731 element.removeAttribute(name);
12732 }
12733 else {
12734 ngDevMode && ngDevMode.rendererSetAttribute++;
12735 const strValue = sanitizer == null ? renderStringify(value) : sanitizer(value, tagName || '', name);
12736 if (isProceduralRenderer(renderer)) {
12737 renderer.setAttribute(element, name, strValue, namespace);
12738 }
12739 else {
12740 namespace ? element.setAttributeNS(namespace, name, strValue) :
12741 element.setAttribute(name, strValue);
12742 }
12743 }
12744}
12745/**
12746 * Sets initial input properties on directive instances from attribute data
12747 *
12748 * @param lView Current LView that is being processed.
12749 * @param directiveIndex Index of the directive in directives array
12750 * @param instance Instance of the directive on which to set the initial inputs
12751 * @param def The directive def that contains the list of inputs
12752 * @param tNode The static data for this node
12753 */
12754function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initialInputData) {
12755 const initialInputs = initialInputData[directiveIndex];
12756 if (initialInputs !== null) {
12757 const setInput = def.setInput;
12758 for (let i = 0; i < initialInputs.length;) {
12759 const publicName = initialInputs[i++];
12760 const privateName = initialInputs[i++];
12761 const value = initialInputs[i++];
12762 if (setInput !== null) {
12763 def.setInput(instance, value, publicName, privateName);
12764 }
12765 else {
12766 instance[privateName] = value;
12767 }
12768 if (ngDevMode) {
12769 const nativeElement = getNativeByTNode(tNode, lView);
12770 setNgReflectProperty(lView, nativeElement, tNode.type, privateName, value);
12771 }
12772 }
12773 }
12774}
12775/**
12776 * Generates initialInputData for a node and stores it in the template's static storage
12777 * so subsequent template invocations don't have to recalculate it.
12778 *
12779 * initialInputData is an array containing values that need to be set as input properties
12780 * for directives on this node, but only once on creation. We need this array to support
12781 * the case where you set an @Input property of a directive using attribute-like syntax.
12782 * e.g. if you have a `name` @Input, you can set it once like this:
12783 *
12784 * <my-component name="Bess"></my-component>
12785 *
12786 * @param inputs The list of inputs from the directive def
12787 * @param attrs The static attrs on this node
12788 */
12789function generateInitialInputs(inputs, attrs) {
12790 let inputsToStore = null;
12791 let i = 0;
12792 while (i < attrs.length) {
12793 const attrName = attrs[i];
12794 if (attrName === 0 /* AttributeMarker.NamespaceURI */) {
12795 // We do not allow inputs on namespaced attributes.
12796 i += 4;
12797 continue;
12798 }
12799 else if (attrName === 5 /* AttributeMarker.ProjectAs */) {
12800 // Skip over the `ngProjectAs` value.
12801 i += 2;
12802 continue;
12803 }
12804 // If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
12805 if (typeof attrName === 'number')
12806 break;
12807 if (inputs.hasOwnProperty(attrName)) {
12808 if (inputsToStore === null)
12809 inputsToStore = [];
12810 inputsToStore.push(attrName, inputs[attrName], attrs[i + 1]);
12811 }
12812 i += 2;
12813 }
12814 return inputsToStore;
12815}
12816//////////////////////////
12817//// ViewContainer & View
12818//////////////////////////
12819// Not sure why I need to do `any` here but TS complains later.
12820const LContainerArray = class LContainer extends Array {
12821};
12822/**
12823 * Creates a LContainer, either from a container instruction, or for a ViewContainerRef.
12824 *
12825 * @param hostNative The host element for the LContainer
12826 * @param hostTNode The host TNode for the LContainer
12827 * @param currentView The parent view of the LContainer
12828 * @param native The native comment element
12829 * @param isForViewContainerRef Optional a flag indicating the ViewContainerRef case
12830 * @returns LContainer
12831 */
12832function createLContainer(hostNative, currentView, native, tNode) {
12833 ngDevMode && assertLView(currentView);
12834 ngDevMode && !isProceduralRenderer(currentView[RENDERER]) && assertDomNode(native);
12835 // https://jsperf.com/array-literal-vs-new-array-really
12836 const lContainer = new (ngDevMode ? LContainerArray : Array)(hostNative, // host native
12837 true, // Boolean `true` in this position signifies that this is an `LContainer`
12838 false, // has transplanted views
12839 currentView, // parent
12840 null, // next
12841 0, // transplanted views to refresh count
12842 tNode, // t_host
12843 native, // native,
12844 null, // view refs
12845 null);
12846 ngDevMode &&
12847 assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
12848 ngDevMode && attachLContainerDebug(lContainer);
12849 return lContainer;
12850}
12851/**
12852 * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
12853 * them by executing an associated template function.
12854 */
12855function refreshEmbeddedViews(lView) {
12856 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12857 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
12858 const embeddedLView = lContainer[i];
12859 const embeddedTView = embeddedLView[TVIEW];
12860 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
12861 if (viewAttachedToChangeDetector(embeddedLView)) {
12862 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
12863 }
12864 }
12865 }
12866}
12867/**
12868 * Mark transplanted views as needing to be refreshed at their insertion points.
12869 *
12870 * @param lView The `LView` that may have transplanted views.
12871 */
12872function markTransplantedViewsForRefresh(lView) {
12873 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12874 if (!lContainer[HAS_TRANSPLANTED_VIEWS])
12875 continue;
12876 const movedViews = lContainer[MOVED_VIEWS];
12877 ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
12878 for (let i = 0; i < movedViews.length; i++) {
12879 const movedLView = movedViews[i];
12880 const insertionLContainer = movedLView[PARENT];
12881 ngDevMode && assertLContainer(insertionLContainer);
12882 // We don't want to increment the counter if the moved LView was already marked for
12883 // refresh.
12884 if ((movedLView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) === 0) {
12885 updateTransplantedViewCount(insertionLContainer, 1);
12886 }
12887 // Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
12888 // those that aren't (declaration component === insertion component). In the latter case,
12889 // it's fine to add the flag, as we will clear it immediately in
12890 // `refreshEmbeddedViews` for the view currently being refreshed.
12891 movedLView[FLAGS] |= 512 /* LViewFlags.RefreshTransplantedView */;
12892 }
12893 }
12894}
12895/////////////
12896/**
12897 * Refreshes components by entering the component view and processing its bindings, queries, etc.
12898 *
12899 * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
12900 */
12901function refreshComponent(hostLView, componentHostIdx) {
12902 ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
12903 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
12904 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12905 if (viewAttachedToChangeDetector(componentView)) {
12906 const tView = componentView[TVIEW];
12907 if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 32 /* LViewFlags.Dirty */)) {
12908 refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
12909 }
12910 else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
12911 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12912 refreshContainsDirtyView(componentView);
12913 }
12914 }
12915}
12916/**
12917 * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
12918 * children or descendants of the given lView.
12919 *
12920 * @param lView The lView which contains descendant transplanted views that need to be refreshed.
12921 */
12922function refreshContainsDirtyView(lView) {
12923 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12924 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
12925 const embeddedLView = lContainer[i];
12926 if (embeddedLView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
12927 const embeddedTView = embeddedLView[TVIEW];
12928 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
12929 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
12930 }
12931 else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
12932 refreshContainsDirtyView(embeddedLView);
12933 }
12934 }
12935 }
12936 const tView = lView[TVIEW];
12937 // Refresh child component views.
12938 const components = tView.components;
12939 if (components !== null) {
12940 for (let i = 0; i < components.length; i++) {
12941 const componentView = getComponentLViewByIndex(components[i], lView);
12942 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12943 if (viewAttachedToChangeDetector(componentView) &&
12944 componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
12945 refreshContainsDirtyView(componentView);
12946 }
12947 }
12948 }
12949}
12950function renderComponent$1(hostLView, componentHostIdx) {
12951 ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
12952 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
12953 const componentTView = componentView[TVIEW];
12954 syncViewWithBlueprint(componentTView, componentView);
12955 renderView(componentTView, componentView, componentView[CONTEXT]);
12956}
12957/**
12958 * Syncs an LView instance with its blueprint if they have gotten out of sync.
12959 *
12960 * Typically, blueprints and their view instances should always be in sync, so the loop here
12961 * will be skipped. However, consider this case of two components side-by-side:
12962 *
12963 * App template:
12964 * ```
12965 * <comp></comp>
12966 * <comp></comp>
12967 * ```
12968 *
12969 * The following will happen:
12970 * 1. App template begins processing.
12971 * 2. First <comp> is matched as a component and its LView is created.
12972 * 3. Second <comp> is matched as a component and its LView is created.
12973 * 4. App template completes processing, so it's time to check child templates.
12974 * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
12975 * 6. Second <comp> template is checked. Its blueprint has been updated by the first
12976 * <comp> template, but its LView was created before this update, so it is out of sync.
12977 *
12978 * Note that embedded views inside ngFor loops will never be out of sync because these views
12979 * are processed as soon as they are created.
12980 *
12981 * @param tView The `TView` that contains the blueprint for syncing
12982 * @param lView The view to sync
12983 */
12984function syncViewWithBlueprint(tView, lView) {
12985 for (let i = lView.length; i < tView.blueprint.length; i++) {
12986 lView.push(tView.blueprint[i]);
12987 }
12988}
12989/**
12990 * Adds LView or LContainer to the end of the current view tree.
12991 *
12992 * This structure will be used to traverse through nested views to remove listeners
12993 * and call onDestroy callbacks.
12994 *
12995 * @param lView The view where LView or LContainer should be added
12996 * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header
12997 * @param lViewOrLContainer The LView or LContainer to add to the view tree
12998 * @returns The state passed in
12999 */
13000function addToViewTree(lView, lViewOrLContainer) {
13001 // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
13002 // to the end of the queue, which means if the developer retrieves the LContainers from RNodes out
13003 // of order, the change detection will run out of order, as the act of retrieving the the
13004 // LContainer from the RNode is what adds it to the queue.
13005 if (lView[CHILD_HEAD]) {
13006 lView[CHILD_TAIL][NEXT] = lViewOrLContainer;
13007 }
13008 else {
13009 lView[CHILD_HEAD] = lViewOrLContainer;
13010 }
13011 lView[CHILD_TAIL] = lViewOrLContainer;
13012 return lViewOrLContainer;
13013}
13014///////////////////////////////
13015//// Change detection
13016///////////////////////////////
13017/**
13018 * Marks current view and all ancestors dirty.
13019 *
13020 * Returns the root view because it is found as a byproduct of marking the view tree
13021 * dirty, and can be used by methods that consume markViewDirty() to easily schedule
13022 * change detection. Otherwise, such methods would need to traverse up the view tree
13023 * an additional time to get the root view and schedule a tick on it.
13024 *
13025 * @param lView The starting LView to mark dirty
13026 * @returns the root LView
13027 */
13028function markViewDirty(lView) {
13029 while (lView) {
13030 lView[FLAGS] |= 32 /* LViewFlags.Dirty */;
13031 const parent = getLViewParent(lView);
13032 // Stop traversing up as soon as you find a root view that wasn't attached to any container
13033 if (isRootView(lView) && !parent) {
13034 return lView;
13035 }
13036 // continue otherwise
13037 lView = parent;
13038 }
13039 return null;
13040}
13041/**
13042 * Used to schedule change detection on the whole application.
13043 *
13044 * Unlike `tick`, `scheduleTick` coalesces multiple calls into one change detection run.
13045 * It is usually called indirectly by calling `markDirty` when the view needs to be
13046 * re-rendered.
13047 *
13048 * Typically `scheduleTick` uses `requestAnimationFrame` to coalesce multiple
13049 * `scheduleTick` requests. The scheduling function can be overridden in
13050 * `renderComponent`'s `scheduler` option.
13051 */
13052function scheduleTick(rootContext, flags) {
13053 const nothingScheduled = rootContext.flags === 0 /* RootContextFlags.Empty */;
13054 if (nothingScheduled && rootContext.clean == _CLEAN_PROMISE) {
13055 // https://github.com/angular/angular/issues/39296
13056 // should only attach the flags when really scheduling a tick
13057 rootContext.flags |= flags;
13058 let res;
13059 rootContext.clean = new Promise((r) => res = r);
13060 rootContext.scheduler(() => {
13061 if (rootContext.flags & 1 /* RootContextFlags.DetectChanges */) {
13062 rootContext.flags &= ~1 /* RootContextFlags.DetectChanges */;
13063 tickRootContext(rootContext);
13064 }
13065 if (rootContext.flags & 2 /* RootContextFlags.FlushPlayers */) {
13066 rootContext.flags &= ~2 /* RootContextFlags.FlushPlayers */;
13067 const playerHandler = rootContext.playerHandler;
13068 if (playerHandler) {
13069 playerHandler.flushPlayers();
13070 }
13071 }
13072 rootContext.clean = _CLEAN_PROMISE;
13073 res(null);
13074 });
13075 }
13076}
13077function tickRootContext(rootContext) {
13078 for (let i = 0; i < rootContext.components.length; i++) {
13079 const rootComponent = rootContext.components[i];
13080 const lView = readPatchedLView(rootComponent);
13081 // We might not have an `LView` if the component was destroyed.
13082 if (lView !== null) {
13083 const tView = lView[TVIEW];
13084 renderComponentOrTemplate(tView, lView, tView.template, rootComponent);
13085 }
13086 }
13087}
13088function detectChangesInternal(tView, lView, context) {
13089 const rendererFactory = lView[RENDERER_FACTORY];
13090 if (rendererFactory.begin)
13091 rendererFactory.begin();
13092 try {
13093 refreshView(tView, lView, tView.template, context);
13094 }
13095 catch (error) {
13096 handleError(lView, error);
13097 throw error;
13098 }
13099 finally {
13100 if (rendererFactory.end)
13101 rendererFactory.end();
13102 }
13103}
13104/**
13105 * Synchronously perform change detection on a root view and its components.
13106 *
13107 * @param lView The view which the change detection should be performed on.
13108 */
13109function detectChangesInRootView(lView) {
13110 tickRootContext(lView[CONTEXT]);
13111}
13112function checkNoChangesInternal(tView, view, context) {
13113 setIsInCheckNoChangesMode(true);
13114 try {
13115 detectChangesInternal(tView, view, context);
13116 }
13117 finally {
13118 setIsInCheckNoChangesMode(false);
13119 }
13120}
13121/**
13122 * Checks the change detector on a root view and its components, and throws if any changes are
13123 * detected.
13124 *
13125 * This is used in development mode to verify that running change detection doesn't
13126 * introduce other changes.
13127 *
13128 * @param lView The view which the change detection should be checked on.
13129 */
13130function checkNoChangesInRootView(lView) {
13131 setIsInCheckNoChangesMode(true);
13132 try {
13133 detectChangesInRootView(lView);
13134 }
13135 finally {
13136 setIsInCheckNoChangesMode(false);
13137 }
13138}
13139function executeViewQueryFn(flags, viewQueryFn, component) {
13140 ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
13141 setCurrentQueryIndex(0);
13142 viewQueryFn(flags, component);
13143}
13144///////////////////////////////
13145//// Bindings & interpolations
13146///////////////////////////////
13147/**
13148 * Stores meta-data for a property binding to be used by TestBed's `DebugElement.properties`.
13149 *
13150 * In order to support TestBed's `DebugElement.properties` we need to save, for each binding:
13151 * - a bound property name;
13152 * - a static parts of interpolated strings;
13153 *
13154 * A given property metadata is saved at the binding's index in the `TView.data` (in other words, a
13155 * property binding metadata will be stored in `TView.data` at the same index as a bound value in
13156 * `LView`). Metadata are represented as `INTERPOLATION_DELIMITER`-delimited string with the
13157 * following format:
13158 * - `propertyName` for bound properties;
13159 * - `propertyName�prefix�interpolation_static_part1�..interpolation_static_partN�suffix` for
13160 * interpolated properties.
13161 *
13162 * @param tData `TData` where meta-data will be saved;
13163 * @param tNode `TNode` that is a target of the binding;
13164 * @param propertyName bound property name;
13165 * @param bindingIndex binding index in `LView`
13166 * @param interpolationParts static interpolation parts (for property interpolations)
13167 */
13168function storePropertyBindingMetadata(tData, tNode, propertyName, bindingIndex, ...interpolationParts) {
13169 // Binding meta-data are stored only the first time a given property instruction is processed.
13170 // Since we don't have a concept of the "first update pass" we need to check for presence of the
13171 // binding meta-data to decide if one should be stored (or if was stored already).
13172 if (tData[bindingIndex] === null) {
13173 if (tNode.inputs == null || !tNode.inputs[propertyName]) {
13174 const propBindingIdxs = tNode.propertyBindings || (tNode.propertyBindings = []);
13175 propBindingIdxs.push(bindingIndex);
13176 let bindingMetadata = propertyName;
13177 if (interpolationParts.length > 0) {
13178 bindingMetadata +=
13179 INTERPOLATION_DELIMITER + interpolationParts.join(INTERPOLATION_DELIMITER);
13180 }
13181 tData[bindingIndex] = bindingMetadata;
13182 }
13183 }
13184}
13185const CLEAN_PROMISE = _CLEAN_PROMISE;
13186function getOrCreateLViewCleanup(view) {
13187 // top level variables should not be exported for performance reasons (PERF_NOTES.md)
13188 return view[CLEANUP] || (view[CLEANUP] = ngDevMode ? new LCleanup() : []);
13189}
13190function getOrCreateTViewCleanup(tView) {
13191 return tView.cleanup || (tView.cleanup = ngDevMode ? new TCleanup() : []);
13192}
13193/**
13194 * There are cases where the sub component's renderer needs to be included
13195 * instead of the current renderer (see the componentSyntheticHost* instructions).
13196 */
13197function loadComponentRenderer(currentDef, tNode, lView) {
13198 // TODO(FW-2043): the `currentDef` is null when host bindings are invoked while creating root
13199 // component (see packages/core/src/render3/component.ts). This is not consistent with the process
13200 // of creating inner components, when current directive index is available in the state. In order
13201 // to avoid relying on current def being `null` (thus special-casing root component creation), the
13202 // process of creating root component should be unified with the process of creating inner
13203 // components.
13204 if (currentDef === null || isComponentDef(currentDef)) {
13205 lView = unwrapLView(lView[tNode.index]);
13206 }
13207 return lView[RENDERER];
13208}
13209/** Handles an error thrown in an LView. */
13210function handleError(lView, error) {
13211 const injector = lView[INJECTOR$1];
13212 const errorHandler = injector ? injector.get(ErrorHandler, null) : null;
13213 errorHandler && errorHandler.handleError(error);
13214}
13215/**
13216 * Set the inputs of directives at the current node to corresponding value.
13217 *
13218 * @param tView The current TView
13219 * @param lView the `LView` which contains the directives.
13220 * @param inputs mapping between the public "input" name and privately-known,
13221 * possibly minified, property names to write to.
13222 * @param value Value to set.
13223 */
13224function setInputsForProperty(tView, lView, inputs, publicName, value) {
13225 for (let i = 0; i < inputs.length;) {
13226 const index = inputs[i++];
13227 const privateName = inputs[i++];
13228 const instance = lView[index];
13229 ngDevMode && assertIndexInRange(lView, index);
13230 const def = tView.data[index];
13231 if (def.setInput !== null) {
13232 def.setInput(instance, value, publicName, privateName);
13233 }
13234 else {
13235 instance[privateName] = value;
13236 }
13237 }
13238}
13239/**
13240 * Updates a text binding at a given index in a given LView.
13241 */
13242function textBindingInternal(lView, index, value) {
13243 ngDevMode && assertString(value, 'Value should be a string');
13244 ngDevMode && assertNotSame(value, NO_CHANGE, 'value should not be NO_CHANGE');
13245 ngDevMode && assertIndexInRange(lView, index);
13246 const element = getNativeByIndex(index, lView);
13247 ngDevMode && assertDefined(element, 'native element should exist');
13248 updateTextNode(lView[RENDERER], element, value);
13249}
13250
13251/**
13252 * @license
13253 * Copyright Google LLC All Rights Reserved.
13254 *
13255 * Use of this source code is governed by an MIT-style license that can be
13256 * found in the LICENSE file at https://angular.io/license
13257 */
13258/**
13259 * Compute the static styling (class/style) from `TAttributes`.
13260 *
13261 * This function should be called during `firstCreatePass` only.
13262 *
13263 * @param tNode The `TNode` into which the styling information should be loaded.
13264 * @param attrs `TAttributes` containing the styling information.
13265 * @param writeToHost Where should the resulting static styles be written?
13266 * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
13267 * - `true` Write to `TNode.styles` / `TNode.classes`
13268 */
13269function computeStaticStyling(tNode, attrs, writeToHost) {
13270 ngDevMode &&
13271 assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
13272 let styles = writeToHost ? tNode.styles : null;
13273 let classes = writeToHost ? tNode.classes : null;
13274 let mode = 0;
13275 if (attrs !== null) {
13276 for (let i = 0; i < attrs.length; i++) {
13277 const value = attrs[i];
13278 if (typeof value === 'number') {
13279 mode = value;
13280 }
13281 else if (mode == 1 /* AttributeMarker.Classes */) {
13282 classes = concatStringsWithSpace(classes, value);
13283 }
13284 else if (mode == 2 /* AttributeMarker.Styles */) {
13285 const style = value;
13286 const styleValue = attrs[++i];
13287 styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
13288 }
13289 }
13290 }
13291 writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
13292 writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
13293}
13294
13295/**
13296 * @license
13297 * Copyright Google LLC All Rights Reserved.
13298 *
13299 * Use of this source code is governed by an MIT-style license that can be
13300 * found in the LICENSE file at https://angular.io/license
13301 */
13302/**
13303 * Synchronously perform change detection on a component (and possibly its sub-components).
13304 *
13305 * This function triggers change detection in a synchronous way on a component.
13306 *
13307 * @param component The component which the change detection should be performed on.
13308 */
13309function detectChanges(component) {
13310 const view = getComponentViewByInstance(component);
13311 detectChangesInternal(view[TVIEW], view, component);
13312}
13313/**
13314 * Marks the component as dirty (needing change detection). Marking a component dirty will
13315 * schedule a change detection on it at some point in the future.
13316 *
13317 * Marking an already dirty component as dirty won't do anything. Only one outstanding change
13318 * detection can be scheduled per component tree.
13319 *
13320 * @param component Component to mark as dirty.
13321 */
13322function markDirty(component) {
13323 ngDevMode && assertDefined(component, 'component');
13324 const rootView = markViewDirty(getComponentViewByInstance(component));
13325 ngDevMode && assertDefined(rootView[CONTEXT], 'rootContext should be defined');
13326 scheduleTick(rootView[CONTEXT], 1 /* RootContextFlags.DetectChanges */);
13327}
13328/**
13329 * Used to perform change detection on the whole application.
13330 *
13331 * This is equivalent to `detectChanges`, but invoked on root component. Additionally, `tick`
13332 * executes lifecycle hooks and conditionally checks components based on their
13333 * `ChangeDetectionStrategy` and dirtiness.
13334 *
13335 * The preferred way to trigger change detection is to call `markDirty`. `markDirty` internally
13336 * schedules `tick` using a scheduler in order to coalesce multiple `markDirty` calls into a
13337 * single change detection run. By default, the scheduler is `requestAnimationFrame`, but can
13338 * be changed when calling `renderComponent` and providing the `scheduler` option.
13339 */
13340function tick(component) {
13341 const rootView = getRootView(component);
13342 const rootContext = rootView[CONTEXT];
13343 tickRootContext(rootContext);
13344}
13345
13346/**
13347 * @license
13348 * Copyright Google LLC All Rights Reserved.
13349 *
13350 * Use of this source code is governed by an MIT-style license that can be
13351 * found in the LICENSE file at https://angular.io/license
13352 */
13353/**
13354 * Retrieves the component instance associated with a given DOM element.
13355 *
13356 * @usageNotes
13357 * Given the following DOM structure:
13358 *
13359 * ```html
13360 * <app-root>
13361 * <div>
13362 * <child-comp></child-comp>
13363 * </div>
13364 * </app-root>
13365 * ```
13366 *
13367 * Calling `getComponent` on `<child-comp>` will return the instance of `ChildComponent`
13368 * associated with this DOM element.
13369 *
13370 * Calling the function on `<app-root>` will return the `MyApp` instance.
13371 *
13372 *
13373 * @param element DOM element from which the component should be retrieved.
13374 * @returns Component instance associated with the element or `null` if there
13375 * is no component associated with it.
13376 *
13377 * @publicApi
13378 * @globalApi ng
13379 */
13380function getComponent$1(element) {
13381 ngDevMode && assertDomElement(element);
13382 const context = getLContext(element);
13383 if (context === null)
13384 return null;
13385 if (context.component === undefined) {
13386 const lView = context.lView;
13387 if (lView === null) {
13388 return null;
13389 }
13390 context.component = getComponentAtNodeIndex(context.nodeIndex, lView);
13391 }
13392 return context.component;
13393}
13394/**
13395 * If inside an embedded view (e.g. `*ngIf` or `*ngFor`), retrieves the context of the embedded
13396 * view that the element is part of. Otherwise retrieves the instance of the component whose view
13397 * owns the element (in this case, the result is the same as calling `getOwningComponent`).
13398 *
13399 * @param element Element for which to get the surrounding component instance.
13400 * @returns Instance of the component that is around the element or null if the element isn't
13401 * inside any component.
13402 *
13403 * @publicApi
13404 * @globalApi ng
13405 */
13406function getContext(element) {
13407 assertDomElement(element);
13408 const context = getLContext(element);
13409 const lView = context ? context.lView : null;
13410 return lView === null ? null : lView[CONTEXT];
13411}
13412/**
13413 * Retrieves the component instance whose view contains the DOM element.
13414 *
13415 * For example, if `<child-comp>` is used in the template of `<app-comp>`
13416 * (i.e. a `ViewChild` of `<app-comp>`), calling `getOwningComponent` on `<child-comp>`
13417 * would return `<app-comp>`.
13418 *
13419 * @param elementOrDir DOM element, component or directive instance
13420 * for which to retrieve the root components.
13421 * @returns Component instance whose view owns the DOM element or null if the element is not
13422 * part of a component view.
13423 *
13424 * @publicApi
13425 * @globalApi ng
13426 */
13427function getOwningComponent(elementOrDir) {
13428 const context = getLContext(elementOrDir);
13429 let lView = context ? context.lView : null;
13430 if (lView === null)
13431 return null;
13432 let parent;
13433 while (lView[TVIEW].type === 2 /* TViewType.Embedded */ && (parent = getLViewParent(lView))) {
13434 lView = parent;
13435 }
13436 return lView[FLAGS] & 256 /* LViewFlags.IsRoot */ ? null : lView[CONTEXT];
13437}
13438/**
13439 * Retrieves all root components associated with a DOM element, directive or component instance.
13440 * Root components are those which have been bootstrapped by Angular.
13441 *
13442 * @param elementOrDir DOM element, component or directive instance
13443 * for which to retrieve the root components.
13444 * @returns Root components associated with the target object.
13445 *
13446 * @publicApi
13447 * @globalApi ng
13448 */
13449function getRootComponents(elementOrDir) {
13450 const lView = readPatchedLView(elementOrDir);
13451 return lView !== null ? [...getRootContext(lView).components] : [];
13452}
13453/**
13454 * Retrieves an `Injector` associated with an element, component or directive instance.
13455 *
13456 * @param elementOrDir DOM element, component or directive instance for which to
13457 * retrieve the injector.
13458 * @returns Injector associated with the element, component or directive instance.
13459 *
13460 * @publicApi
13461 * @globalApi ng
13462 */
13463function getInjector(elementOrDir) {
13464 const context = getLContext(elementOrDir);
13465 const lView = context ? context.lView : null;
13466 if (lView === null)
13467 return Injector.NULL;
13468 const tNode = lView[TVIEW].data[context.nodeIndex];
13469 return new NodeInjector(tNode, lView);
13470}
13471/**
13472 * Retrieve a set of injection tokens at a given DOM node.
13473 *
13474 * @param element Element for which the injection tokens should be retrieved.
13475 */
13476function getInjectionTokens(element) {
13477 const context = getLContext(element);
13478 const lView = context ? context.lView : null;
13479 if (lView === null)
13480 return [];
13481 const tView = lView[TVIEW];
13482 const tNode = tView.data[context.nodeIndex];
13483 const providerTokens = [];
13484 const startIndex = tNode.providerIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */;
13485 const endIndex = tNode.directiveEnd;
13486 for (let i = startIndex; i < endIndex; i++) {
13487 let value = tView.data[i];
13488 if (isDirectiveDefHack(value)) {
13489 // The fact that we sometimes store Type and sometimes DirectiveDef in this location is a
13490 // design flaw. We should always store same type so that we can be monomorphic. The issue
13491 // is that for Components/Directives we store the def instead the type. The correct behavior
13492 // is that we should always be storing injectable type in this location.
13493 value = value.type;
13494 }
13495 providerTokens.push(value);
13496 }
13497 return providerTokens;
13498}
13499/**
13500 * Retrieves directive instances associated with a given DOM node. Does not include
13501 * component instances.
13502 *
13503 * @usageNotes
13504 * Given the following DOM structure:
13505 *
13506 * ```html
13507 * <app-root>
13508 * <button my-button></button>
13509 * <my-comp></my-comp>
13510 * </app-root>
13511 * ```
13512 *
13513 * Calling `getDirectives` on `<button>` will return an array with an instance of the `MyButton`
13514 * directive that is associated with the DOM node.
13515 *
13516 * Calling `getDirectives` on `<my-comp>` will return an empty array.
13517 *
13518 * @param node DOM node for which to get the directives.
13519 * @returns Array of directives associated with the node.
13520 *
13521 * @publicApi
13522 * @globalApi ng
13523 */
13524function getDirectives(node) {
13525 // Skip text nodes because we can't have directives associated with them.
13526 if (node instanceof Text) {
13527 return [];
13528 }
13529 const context = getLContext(node);
13530 const lView = context ? context.lView : null;
13531 if (lView === null) {
13532 return [];
13533 }
13534 const tView = lView[TVIEW];
13535 const nodeIndex = context.nodeIndex;
13536 if (!(tView === null || tView === void 0 ? void 0 : tView.data[nodeIndex])) {
13537 return [];
13538 }
13539 if (context.directives === undefined) {
13540 context.directives = getDirectivesAtNodeIndex(nodeIndex, lView, false);
13541 }
13542 // The `directives` in this case are a named array called `LComponentView`. Clone the
13543 // result so we don't expose an internal data structure in the user's console.
13544 return context.directives === null ? [] : [...context.directives];
13545}
13546/**
13547 * Returns the debug (partial) metadata for a particular directive or component instance.
13548 * The function accepts an instance of a directive or component and returns the corresponding
13549 * metadata.
13550 *
13551 * @param directiveOrComponentInstance Instance of a directive or component
13552 * @returns metadata of the passed directive or component
13553 *
13554 * @publicApi
13555 * @globalApi ng
13556 */
13557function getDirectiveMetadata$1(directiveOrComponentInstance) {
13558 const { constructor } = directiveOrComponentInstance;
13559 if (!constructor) {
13560 throw new Error('Unable to find the instance constructor');
13561 }
13562 // In case a component inherits from a directive, we may have component and directive metadata
13563 // To ensure we don't get the metadata of the directive, we want to call `getComponentDef` first.
13564 const componentDef = getComponentDef(constructor);
13565 if (componentDef) {
13566 return {
13567 inputs: componentDef.inputs,
13568 outputs: componentDef.outputs,
13569 encapsulation: componentDef.encapsulation,
13570 changeDetection: componentDef.onPush ? ChangeDetectionStrategy.OnPush :
13571 ChangeDetectionStrategy.Default
13572 };
13573 }
13574 const directiveDef = getDirectiveDef(constructor);
13575 if (directiveDef) {
13576 return { inputs: directiveDef.inputs, outputs: directiveDef.outputs };
13577 }
13578 return null;
13579}
13580/**
13581 * Retrieve map of local references.
13582 *
13583 * The references are retrieved as a map of local reference name to element or directive instance.
13584 *
13585 * @param target DOM element, component or directive instance for which to retrieve
13586 * the local references.
13587 */
13588function getLocalRefs(target) {
13589 const context = getLContext(target);
13590 if (context === null)
13591 return {};
13592 if (context.localRefs === undefined) {
13593 const lView = context.lView;
13594 if (lView === null) {
13595 return {};
13596 }
13597 context.localRefs = discoverLocalRefs(lView, context.nodeIndex);
13598 }
13599 return context.localRefs || {};
13600}
13601/**
13602 * Retrieves the host element of a component or directive instance.
13603 * The host element is the DOM element that matched the selector of the directive.
13604 *
13605 * @param componentOrDirective Component or directive instance for which the host
13606 * element should be retrieved.
13607 * @returns Host element of the target.
13608 *
13609 * @publicApi
13610 * @globalApi ng
13611 */
13612function getHostElement(componentOrDirective) {
13613 return getLContext(componentOrDirective).native;
13614}
13615/**
13616 * Retrieves the rendered text for a given component.
13617 *
13618 * This function retrieves the host element of a component and
13619 * and then returns the `textContent` for that element. This implies
13620 * that the text returned will include re-projected content of
13621 * the component as well.
13622 *
13623 * @param component The component to return the content text for.
13624 */
13625function getRenderedText(component) {
13626 const hostElement = getHostElement(component);
13627 return hostElement.textContent || '';
13628}
13629/**
13630 * Retrieves a list of event listeners associated with a DOM element. The list does include host
13631 * listeners, but it does not include event listeners defined outside of the Angular context
13632 * (e.g. through `addEventListener`).
13633 *
13634 * @usageNotes
13635 * Given the following DOM structure:
13636 *
13637 * ```html
13638 * <app-root>
13639 * <div (click)="doSomething()"></div>
13640 * </app-root>
13641 * ```
13642 *
13643 * Calling `getListeners` on `<div>` will return an object that looks as follows:
13644 *
13645 * ```ts
13646 * {
13647 * name: 'click',
13648 * element: <div>,
13649 * callback: () => doSomething(),
13650 * useCapture: false
13651 * }
13652 * ```
13653 *
13654 * @param element Element for which the DOM listeners should be retrieved.
13655 * @returns Array of event listeners on the DOM element.
13656 *
13657 * @publicApi
13658 * @globalApi ng
13659 */
13660function getListeners(element) {
13661 ngDevMode && assertDomElement(element);
13662 const lContext = getLContext(element);
13663 const lView = lContext === null ? null : lContext.lView;
13664 if (lView === null)
13665 return [];
13666 const tView = lView[TVIEW];
13667 const lCleanup = lView[CLEANUP];
13668 const tCleanup = tView.cleanup;
13669 const listeners = [];
13670 if (tCleanup && lCleanup) {
13671 for (let i = 0; i < tCleanup.length;) {
13672 const firstParam = tCleanup[i++];
13673 const secondParam = tCleanup[i++];
13674 if (typeof firstParam === 'string') {
13675 const name = firstParam;
13676 const listenerElement = unwrapRNode(lView[secondParam]);
13677 const callback = lCleanup[tCleanup[i++]];
13678 const useCaptureOrIndx = tCleanup[i++];
13679 // if useCaptureOrIndx is boolean then report it as is.
13680 // if useCaptureOrIndx is positive number then it in unsubscribe method
13681 // if useCaptureOrIndx is negative number then it is a Subscription
13682 const type = (typeof useCaptureOrIndx === 'boolean' || useCaptureOrIndx >= 0) ? 'dom' : 'output';
13683 const useCapture = typeof useCaptureOrIndx === 'boolean' ? useCaptureOrIndx : false;
13684 if (element == listenerElement) {
13685 listeners.push({ element, name, callback, useCapture, type });
13686 }
13687 }
13688 }
13689 }
13690 listeners.sort(sortListeners);
13691 return listeners;
13692}
13693function sortListeners(a, b) {
13694 if (a.name == b.name)
13695 return 0;
13696 return a.name < b.name ? -1 : 1;
13697}
13698/**
13699 * This function should not exist because it is megamorphic and only mostly correct.
13700 *
13701 * See call site for more info.
13702 */
13703function isDirectiveDefHack(obj) {
13704 return obj.type !== undefined && obj.template !== undefined && obj.declaredInputs !== undefined;
13705}
13706/**
13707 * Returns the attached `DebugNode` instance for an element in the DOM.
13708 *
13709 * @param element DOM element which is owned by an existing component's view.
13710 */
13711function getDebugNode$1(element) {
13712 if (ngDevMode && !(element instanceof Node)) {
13713 throw new Error('Expecting instance of DOM Element');
13714 }
13715 const lContext = getLContext(element);
13716 const lView = lContext ? lContext.lView : null;
13717 if (lView === null) {
13718 return null;
13719 }
13720 const nodeIndex = lContext.nodeIndex;
13721 if (nodeIndex !== -1) {
13722 const valueInLView = lView[nodeIndex];
13723 // this means that value in the lView is a component with its own
13724 // data. In this situation the TNode is not accessed at the same spot.
13725 const tNode = isLView(valueInLView) ? valueInLView[T_HOST] : getTNode(lView[TVIEW], nodeIndex);
13726 ngDevMode &&
13727 assertEqual(tNode.index, nodeIndex, 'Expecting that TNode at index is same as index');
13728 return buildDebugNode(tNode, lView);
13729 }
13730 return null;
13731}
13732/**
13733 * Retrieve the component `LView` from component/element.
13734 *
13735 * NOTE: `LView` is a private and should not be leaked outside.
13736 * Don't export this method to `ng.*` on window.
13737 *
13738 * @param target DOM element or component instance for which to retrieve the LView.
13739 */
13740function getComponentLView(target) {
13741 const lContext = getLContext(target);
13742 const nodeIndx = lContext.nodeIndex;
13743 const lView = lContext.lView;
13744 ngDevMode && assertLView(lView);
13745 const componentLView = lView[nodeIndx];
13746 ngDevMode && assertLView(componentLView);
13747 return componentLView;
13748}
13749/** Asserts that a value is a DOM Element. */
13750function assertDomElement(value) {
13751 if (typeof Element !== 'undefined' && !(value instanceof Element)) {
13752 throw new Error('Expecting instance of DOM Element');
13753 }
13754}
13755
13756/**
13757 * @license
13758 * Copyright Google LLC All Rights Reserved.
13759 *
13760 * Use of this source code is governed by an MIT-style license that can be
13761 * found in the LICENSE file at https://angular.io/license
13762 */
13763/**
13764 * Marks a component for check (in case of OnPush components) and synchronously
13765 * performs change detection on the application this component belongs to.
13766 *
13767 * @param component Component to {@link ChangeDetectorRef#markForCheck mark for check}.
13768 *
13769 * @publicApi
13770 * @globalApi ng
13771 */
13772function applyChanges(component) {
13773 markDirty(component);
13774 getRootComponents(component).forEach(rootComponent => detectChanges(rootComponent));
13775}
13776
13777/**
13778 * @license
13779 * Copyright Google LLC All Rights Reserved.
13780 *
13781 * Use of this source code is governed by an MIT-style license that can be
13782 * found in the LICENSE file at https://angular.io/license
13783 */
13784/**
13785 * This file introduces series of globally accessible debug tools
13786 * to allow for the Angular debugging story to function.
13787 *
13788 * To see this in action run the following command:
13789 *
13790 * bazel run //packages/core/test/bundling/todo:devserver
13791 *
13792 * Then load `localhost:5432` and start using the console tools.
13793 */
13794/**
13795 * This value reflects the property on the window where the dev
13796 * tools are patched (window.ng).
13797 * */
13798const GLOBAL_PUBLISH_EXPANDO_KEY = 'ng';
13799let _published = false;
13800/**
13801 * Publishes a collection of default debug tools onto`window.ng`.
13802 *
13803 * These functions are available globally when Angular is in development
13804 * mode and are automatically stripped away from prod mode is on.
13805 */
13806function publishDefaultGlobalUtils$1() {
13807 if (!_published) {
13808 _published = true;
13809 /**
13810 * Warning: this function is *INTERNAL* and should not be relied upon in application's code.
13811 * The contract of the function might be changed in any release and/or the function can be
13812 * removed completely.
13813 */
13814 publishGlobalUtil('ɵsetProfiler', setProfiler);
13815 publishGlobalUtil('getDirectiveMetadata', getDirectiveMetadata$1);
13816 publishGlobalUtil('getComponent', getComponent$1);
13817 publishGlobalUtil('getContext', getContext);
13818 publishGlobalUtil('getListeners', getListeners);
13819 publishGlobalUtil('getOwningComponent', getOwningComponent);
13820 publishGlobalUtil('getHostElement', getHostElement);
13821 publishGlobalUtil('getInjector', getInjector);
13822 publishGlobalUtil('getRootComponents', getRootComponents);
13823 publishGlobalUtil('getDirectives', getDirectives);
13824 publishGlobalUtil('applyChanges', applyChanges);
13825 }
13826}
13827/**
13828 * Publishes the given function to `window.ng` so that it can be
13829 * used from the browser console when an application is not in production.
13830 */
13831function publishGlobalUtil(name, fn) {
13832 if (typeof COMPILED === 'undefined' || !COMPILED) {
13833 // Note: we can't export `ng` when using closure enhanced optimization as:
13834 // - closure declares globals itself for minified names, which sometimes clobber our `ng` global
13835 // - we can't declare a closure extern as the namespace `ng` is already used within Google
13836 // for typings for AngularJS (via `goog.provide('ng....')`).
13837 const w = _global;
13838 ngDevMode && assertDefined(fn, 'function not defined');
13839 if (w) {
13840 let container = w[GLOBAL_PUBLISH_EXPANDO_KEY];
13841 if (!container) {
13842 container = w[GLOBAL_PUBLISH_EXPANDO_KEY] = {};
13843 }
13844 container[name] = fn;
13845 }
13846 }
13847}
13848
13849/**
13850 * @license
13851 * Copyright Google LLC All Rights Reserved.
13852 *
13853 * Use of this source code is governed by an MIT-style license that can be
13854 * found in the LICENSE file at https://angular.io/license
13855 */
13856// TODO: A hack to not pull in the NullInjector from @angular/core.
13857const NULL_INJECTOR = {
13858 get: (token, notFoundValue) => {
13859 throwProviderNotFoundError(token, 'NullInjector');
13860 }
13861};
13862/**
13863 * Bootstraps a Component into an existing host element and returns an instance
13864 * of the component.
13865 *
13866 * Use this function to bootstrap a component into the DOM tree. Each invocation
13867 * of this function will create a separate tree of components, injectors and
13868 * change detection cycles and lifetimes. To dynamically insert a new component
13869 * into an existing tree such that it shares the same injection, change detection
13870 * and object lifetime, use {@link ViewContainer#createComponent}.
13871 *
13872 * @param componentType Component to bootstrap
13873 * @param options Optional parameters which control bootstrapping
13874 */
13875function renderComponent(componentType /* Type as workaround for: Microsoft/TypeScript/issues/4881 */, opts = {}) {
13876 ngDevMode && publishDefaultGlobalUtils$1();
13877 ngDevMode && assertComponentType(componentType);
13878 const rendererFactory = opts.rendererFactory || domRendererFactory3;
13879 const sanitizer = opts.sanitizer || null;
13880 const componentDef = getComponentDef(componentType);
13881 if (componentDef.type != componentType)
13882 componentDef.type = componentType;
13883 // The first index of the first selector is the tag name.
13884 const componentTag = componentDef.selectors[0][0];
13885 const hostRenderer = rendererFactory.createRenderer(null, null);
13886 const hostRNode = locateHostElement(hostRenderer, opts.host || componentTag, componentDef.encapsulation);
13887 const rootFlags = componentDef.onPush ? 32 /* LViewFlags.Dirty */ | 256 /* LViewFlags.IsRoot */ :
13888 16 /* LViewFlags.CheckAlways */ | 256 /* LViewFlags.IsRoot */;
13889 const rootContext = createRootContext(opts.scheduler, opts.playerHandler);
13890 const renderer = rendererFactory.createRenderer(hostRNode, componentDef);
13891 const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null);
13892 const rootView = createLView(null, rootTView, rootContext, rootFlags, null, null, rendererFactory, renderer, null, opts.injector || null, null);
13893 enterView(rootView);
13894 let component;
13895 try {
13896 if (rendererFactory.begin)
13897 rendererFactory.begin();
13898 const componentView = createRootComponentView(hostRNode, componentDef, rootView, rendererFactory, renderer, sanitizer);
13899 component = createRootComponent(componentView, componentDef, rootView, rootContext, opts.hostFeatures || null);
13900 // create mode pass
13901 renderView(rootTView, rootView, null);
13902 // update mode pass
13903 refreshView(rootTView, rootView, null, null);
13904 }
13905 finally {
13906 leaveView();
13907 if (rendererFactory.end)
13908 rendererFactory.end();
13909 }
13910 return component;
13911}
13912/**
13913 * Creates the root component view and the root component node.
13914 *
13915 * @param rNode Render host element.
13916 * @param def ComponentDef
13917 * @param rootView The parent view where the host node is stored
13918 * @param rendererFactory Factory to be used for creating child renderers.
13919 * @param hostRenderer The current renderer
13920 * @param sanitizer The sanitizer, if provided
13921 *
13922 * @returns Component view created
13923 */
13924function createRootComponentView(rNode, def, rootView, rendererFactory, hostRenderer, sanitizer) {
13925 const tView = rootView[TVIEW];
13926 const index = HEADER_OFFSET;
13927 ngDevMode && assertIndexInRange(rootView, index);
13928 rootView[index] = rNode;
13929 // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
13930 // the same time we want to communicate the debug `TNode` that this is a special `TNode`
13931 // representing a host element.
13932 const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null);
13933 const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
13934 if (mergedAttrs !== null) {
13935 computeStaticStyling(tNode, mergedAttrs, true);
13936 if (rNode !== null) {
13937 setUpAttributes(hostRenderer, rNode, mergedAttrs);
13938 if (tNode.classes !== null) {
13939 writeDirectClass(hostRenderer, rNode, tNode.classes);
13940 }
13941 if (tNode.styles !== null) {
13942 writeDirectStyle(hostRenderer, rNode, tNode.styles);
13943 }
13944 }
13945 }
13946 const viewRenderer = rendererFactory.createRenderer(rNode, def);
13947 const componentView = createLView(rootView, getOrCreateTComponentView(def), null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
13948 if (tView.firstCreatePass) {
13949 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, def.type);
13950 markAsComponentHost(tView, tNode);
13951 initTNodeFlags(tNode, rootView.length, 1);
13952 }
13953 addToViewTree(rootView, componentView);
13954 // Store component view at node index, with node as the HOST
13955 return rootView[index] = componentView;
13956}
13957/**
13958 * Creates a root component and sets it up with features and host bindings. Shared by
13959 * renderComponent() and ViewContainerRef.createComponent().
13960 */
13961function createRootComponent(componentView, componentDef, rootLView, rootContext, hostFeatures) {
13962 const tView = rootLView[TVIEW];
13963 // Create directive instance with factory() and store at next index in viewData
13964 const component = instantiateRootComponent(tView, rootLView, componentDef);
13965 rootContext.components.push(component);
13966 componentView[CONTEXT] = component;
13967 if (hostFeatures !== null) {
13968 for (const feature of hostFeatures) {
13969 feature(component, componentDef);
13970 }
13971 }
13972 // We want to generate an empty QueryList for root content queries for backwards
13973 // compatibility with ViewEngine.
13974 if (componentDef.contentQueries) {
13975 const tNode = getCurrentTNode();
13976 ngDevMode && assertDefined(tNode, 'TNode expected');
13977 componentDef.contentQueries(1 /* RenderFlags.Create */, component, tNode.directiveStart);
13978 }
13979 const rootTNode = getCurrentTNode();
13980 ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
13981 if (tView.firstCreatePass &&
13982 (componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) {
13983 setSelectedIndex(rootTNode.index);
13984 const rootTView = rootLView[TVIEW];
13985 registerHostBindingOpCodes(rootTView, rootTNode, rootLView, rootTNode.directiveStart, rootTNode.directiveEnd, componentDef);
13986 invokeHostBindingsInCreationMode(componentDef, component);
13987 }
13988 return component;
13989}
13990function createRootContext(scheduler, playerHandler) {
13991 return {
13992 components: [],
13993 scheduler: scheduler || defaultScheduler,
13994 clean: CLEAN_PROMISE,
13995 playerHandler: playerHandler || null,
13996 flags: 0 /* RootContextFlags.Empty */
13997 };
13998}
13999/**
14000 * Used to enable lifecycle hooks on the root component.
14001 *
14002 * Include this feature when calling `renderComponent` if the root component
14003 * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't
14004 * be called properly.
14005 *
14006 * Example:
14007 *
14008 * ```
14009 * renderComponent(AppComponent, {hostFeatures: [LifecycleHooksFeature]});
14010 * ```
14011 */
14012function LifecycleHooksFeature() {
14013 const tNode = getCurrentTNode();
14014 ngDevMode && assertDefined(tNode, 'TNode is required');
14015 registerPostOrderHooks(getLView()[TVIEW], tNode);
14016}
14017/**
14018 * Wait on component until it is rendered.
14019 *
14020 * This function returns a `Promise` which is resolved when the component's
14021 * change detection is executed. This is determined by finding the scheduler
14022 * associated with the `component`'s render tree and waiting until the scheduler
14023 * flushes. If nothing is scheduled, the function returns a resolved promise.
14024 *
14025 * Example:
14026 * ```
14027 * await whenRendered(myComponent);
14028 * ```
14029 *
14030 * @param component Component to wait upon
14031 * @returns Promise which resolves when the component is rendered.
14032 */
14033function whenRendered(component) {
14034 return getRootContext(component).clean;
14035}
14036
14037/**
14038 * @license
14039 * Copyright Google LLC All Rights Reserved.
14040 *
14041 * Use of this source code is governed by an MIT-style license that can be
14042 * found in the LICENSE file at https://angular.io/license
14043 */
14044function getSuperType(type) {
14045 return Object.getPrototypeOf(type.prototype).constructor;
14046}
14047/**
14048 * Merges the definition from a super class to a sub class.
14049 * @param definition The definition that is a SubClass of another directive of component
14050 *
14051 * @codeGenApi
14052 */
14053function ɵɵInheritDefinitionFeature(definition) {
14054 let superType = getSuperType(definition.type);
14055 let shouldInheritFields = true;
14056 const inheritanceChain = [definition];
14057 while (superType) {
14058 let superDef = undefined;
14059 if (isComponentDef(definition)) {
14060 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
14061 superDef = superType.ɵcmp || superType.ɵdir;
14062 }
14063 else {
14064 if (superType.ɵcmp) {
14065 throw new RuntimeError(903 /* RuntimeErrorCode.INVALID_INHERITANCE */, ngDevMode &&
14066 `Directives cannot inherit Components. Directive ${stringifyForError(definition.type)} is attempting to extend component ${stringifyForError(superType)}`);
14067 }
14068 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
14069 superDef = superType.ɵdir;
14070 }
14071 if (superDef) {
14072 if (shouldInheritFields) {
14073 inheritanceChain.push(superDef);
14074 // Some fields in the definition may be empty, if there were no values to put in them that
14075 // would've justified object creation. Unwrap them if necessary.
14076 const writeableDef = definition;
14077 writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
14078 writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
14079 writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
14080 // Merge hostBindings
14081 const superHostBindings = superDef.hostBindings;
14082 superHostBindings && inheritHostBindings(definition, superHostBindings);
14083 // Merge queries
14084 const superViewQuery = superDef.viewQuery;
14085 const superContentQueries = superDef.contentQueries;
14086 superViewQuery && inheritViewQuery(definition, superViewQuery);
14087 superContentQueries && inheritContentQueries(definition, superContentQueries);
14088 // Merge inputs and outputs
14089 fillProperties(definition.inputs, superDef.inputs);
14090 fillProperties(definition.declaredInputs, superDef.declaredInputs);
14091 fillProperties(definition.outputs, superDef.outputs);
14092 // Merge animations metadata.
14093 // If `superDef` is a Component, the `data` field is present (defaults to an empty object).
14094 if (isComponentDef(superDef) && superDef.data.animation) {
14095 // If super def is a Component, the `definition` is also a Component, since Directives can
14096 // not inherit Components (we throw an error above and cannot reach this code).
14097 const defData = definition.data;
14098 defData.animation = (defData.animation || []).concat(superDef.data.animation);
14099 }
14100 }
14101 // Run parent features
14102 const features = superDef.features;
14103 if (features) {
14104 for (let i = 0; i < features.length; i++) {
14105 const feature = features[i];
14106 if (feature && feature.ngInherit) {
14107 feature(definition);
14108 }
14109 // If `InheritDefinitionFeature` is a part of the current `superDef`, it means that this
14110 // def already has all the necessary information inherited from its super class(es), so we
14111 // can stop merging fields from super classes. However we need to iterate through the
14112 // prototype chain to look for classes that might contain other "features" (like
14113 // NgOnChanges), which we should invoke for the original `definition`. We set the
14114 // `shouldInheritFields` flag to indicate that, essentially skipping fields inheritance
14115 // logic and only invoking functions from the "features" list.
14116 if (feature === ɵɵInheritDefinitionFeature) {
14117 shouldInheritFields = false;
14118 }
14119 }
14120 }
14121 }
14122 superType = Object.getPrototypeOf(superType);
14123 }
14124 mergeHostAttrsAcrossInheritance(inheritanceChain);
14125}
14126/**
14127 * Merge the `hostAttrs` and `hostVars` from the inherited parent to the base class.
14128 *
14129 * @param inheritanceChain A list of `WritableDefs` starting at the top most type and listing
14130 * sub-types in order. For each type take the `hostAttrs` and `hostVars` and merge it with the child
14131 * type.
14132 */
14133function mergeHostAttrsAcrossInheritance(inheritanceChain) {
14134 let hostVars = 0;
14135 let hostAttrs = null;
14136 // We process the inheritance order from the base to the leaves here.
14137 for (let i = inheritanceChain.length - 1; i >= 0; i--) {
14138 const def = inheritanceChain[i];
14139 // For each `hostVars`, we need to add the superclass amount.
14140 def.hostVars = (hostVars += def.hostVars);
14141 // for each `hostAttrs` we need to merge it with superclass.
14142 def.hostAttrs =
14143 mergeHostAttrs(def.hostAttrs, hostAttrs = mergeHostAttrs(hostAttrs, def.hostAttrs));
14144 }
14145}
14146function maybeUnwrapEmpty(value) {
14147 if (value === EMPTY_OBJ) {
14148 return {};
14149 }
14150 else if (value === EMPTY_ARRAY) {
14151 return [];
14152 }
14153 else {
14154 return value;
14155 }
14156}
14157function inheritViewQuery(definition, superViewQuery) {
14158 const prevViewQuery = definition.viewQuery;
14159 if (prevViewQuery) {
14160 definition.viewQuery = (rf, ctx) => {
14161 superViewQuery(rf, ctx);
14162 prevViewQuery(rf, ctx);
14163 };
14164 }
14165 else {
14166 definition.viewQuery = superViewQuery;
14167 }
14168}
14169function inheritContentQueries(definition, superContentQueries) {
14170 const prevContentQueries = definition.contentQueries;
14171 if (prevContentQueries) {
14172 definition.contentQueries = (rf, ctx, directiveIndex) => {
14173 superContentQueries(rf, ctx, directiveIndex);
14174 prevContentQueries(rf, ctx, directiveIndex);
14175 };
14176 }
14177 else {
14178 definition.contentQueries = superContentQueries;
14179 }
14180}
14181function inheritHostBindings(definition, superHostBindings) {
14182 const prevHostBindings = definition.hostBindings;
14183 if (prevHostBindings) {
14184 definition.hostBindings = (rf, ctx) => {
14185 superHostBindings(rf, ctx);
14186 prevHostBindings(rf, ctx);
14187 };
14188 }
14189 else {
14190 definition.hostBindings = superHostBindings;
14191 }
14192}
14193
14194/**
14195 * @license
14196 * Copyright Google LLC All Rights Reserved.
14197 *
14198 * Use of this source code is governed by an MIT-style license that can be
14199 * found in the LICENSE file at https://angular.io/license
14200 */
14201/**
14202 * Fields which exist on either directive or component definitions, and need to be copied from
14203 * parent to child classes by the `ɵɵCopyDefinitionFeature`.
14204 */
14205const COPY_DIRECTIVE_FIELDS = [
14206 // The child class should use the providers of its parent.
14207 'providersResolver',
14208 // Not listed here are any fields which are handled by the `ɵɵInheritDefinitionFeature`, such
14209 // as inputs, outputs, and host binding functions.
14210];
14211/**
14212 * Fields which exist only on component definitions, and need to be copied from parent to child
14213 * classes by the `ɵɵCopyDefinitionFeature`.
14214 *
14215 * The type here allows any field of `ComponentDef` which is not also a property of `DirectiveDef`,
14216 * since those should go in `COPY_DIRECTIVE_FIELDS` above.
14217 */
14218const COPY_COMPONENT_FIELDS = [
14219 // The child class should use the template function of its parent, including all template
14220 // semantics.
14221 'template',
14222 'decls',
14223 'consts',
14224 'vars',
14225 'onPush',
14226 'ngContentSelectors',
14227 // The child class should use the CSS styles of its parent, including all styling semantics.
14228 'styles',
14229 'encapsulation',
14230 // The child class should be checked by the runtime in the same way as its parent.
14231 'schemas',
14232];
14233/**
14234 * Copies the fields not handled by the `ɵɵInheritDefinitionFeature` from the supertype of a
14235 * definition.
14236 *
14237 * This exists primarily to support ngcc migration of an existing View Engine pattern, where an
14238 * entire decorator is inherited from a parent to a child class. When ngcc detects this case, it
14239 * generates a skeleton definition on the child class, and applies this feature.
14240 *
14241 * The `ɵɵCopyDefinitionFeature` then copies any needed fields from the parent class' definition,
14242 * including things like the component template function.
14243 *
14244 * @param definition The definition of a child class which inherits from a parent class with its
14245 * own definition.
14246 *
14247 * @codeGenApi
14248 */
14249function ɵɵCopyDefinitionFeature(definition) {
14250 let superType = getSuperType(definition.type);
14251 let superDef = undefined;
14252 if (isComponentDef(definition)) {
14253 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
14254 superDef = superType.ɵcmp;
14255 }
14256 else {
14257 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
14258 superDef = superType.ɵdir;
14259 }
14260 // Needed because `definition` fields are readonly.
14261 const defAny = definition;
14262 // Copy over any fields that apply to either directives or components.
14263 for (const field of COPY_DIRECTIVE_FIELDS) {
14264 defAny[field] = superDef[field];
14265 }
14266 if (isComponentDef(superDef)) {
14267 // Copy over any component-specific fields.
14268 for (const field of COPY_COMPONENT_FIELDS) {
14269 defAny[field] = superDef[field];
14270 }
14271 }
14272}
14273
14274/**
14275 * @license
14276 * Copyright Google LLC All Rights Reserved.
14277 *
14278 * Use of this source code is governed by an MIT-style license that can be
14279 * found in the LICENSE file at https://angular.io/license
14280 */
14281let _symbolIterator = null;
14282function getSymbolIterator() {
14283 if (!_symbolIterator) {
14284 const Symbol = _global['Symbol'];
14285 if (Symbol && Symbol.iterator) {
14286 _symbolIterator = Symbol.iterator;
14287 }
14288 else {
14289 // es6-shim specific logic
14290 const keys = Object.getOwnPropertyNames(Map.prototype);
14291 for (let i = 0; i < keys.length; ++i) {
14292 const key = keys[i];
14293 if (key !== 'entries' && key !== 'size' &&
14294 Map.prototype[key] === Map.prototype['entries']) {
14295 _symbolIterator = key;
14296 }
14297 }
14298 }
14299 }
14300 return _symbolIterator;
14301}
14302
14303/**
14304 * @license
14305 * Copyright Google LLC All Rights Reserved.
14306 *
14307 * Use of this source code is governed by an MIT-style license that can be
14308 * found in the LICENSE file at https://angular.io/license
14309 */
14310function isIterable(obj) {
14311 return obj !== null && typeof obj === 'object' && obj[getSymbolIterator()] !== undefined;
14312}
14313function isListLikeIterable(obj) {
14314 if (!isJsObject(obj))
14315 return false;
14316 return Array.isArray(obj) ||
14317 (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
14318 getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop
14319}
14320function areIterablesEqual(a, b, comparator) {
14321 const iterator1 = a[getSymbolIterator()]();
14322 const iterator2 = b[getSymbolIterator()]();
14323 while (true) {
14324 const item1 = iterator1.next();
14325 const item2 = iterator2.next();
14326 if (item1.done && item2.done)
14327 return true;
14328 if (item1.done || item2.done)
14329 return false;
14330 if (!comparator(item1.value, item2.value))
14331 return false;
14332 }
14333}
14334function iterateListLike(obj, fn) {
14335 if (Array.isArray(obj)) {
14336 for (let i = 0; i < obj.length; i++) {
14337 fn(obj[i]);
14338 }
14339 }
14340 else {
14341 const iterator = obj[getSymbolIterator()]();
14342 let item;
14343 while (!((item = iterator.next()).done)) {
14344 fn(item.value);
14345 }
14346 }
14347}
14348function isJsObject(o) {
14349 return o !== null && (typeof o === 'function' || typeof o === 'object');
14350}
14351
14352/**
14353 * @license
14354 * Copyright Google LLC All Rights Reserved.
14355 *
14356 * Use of this source code is governed by an MIT-style license that can be
14357 * found in the LICENSE file at https://angular.io/license
14358 */
14359function devModeEqual(a, b) {
14360 const isListLikeIterableA = isListLikeIterable(a);
14361 const isListLikeIterableB = isListLikeIterable(b);
14362 if (isListLikeIterableA && isListLikeIterableB) {
14363 return areIterablesEqual(a, b, devModeEqual);
14364 }
14365 else {
14366 const isAObject = a && (typeof a === 'object' || typeof a === 'function');
14367 const isBObject = b && (typeof b === 'object' || typeof b === 'function');
14368 if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
14369 return true;
14370 }
14371 else {
14372 return Object.is(a, b);
14373 }
14374 }
14375}
14376
14377/**
14378 * @license
14379 * Copyright Google LLC All Rights Reserved.
14380 *
14381 * Use of this source code is governed by an MIT-style license that can be
14382 * found in the LICENSE file at https://angular.io/license
14383 */
14384// TODO(misko): consider inlining
14385/** Updates binding and returns the value. */
14386function updateBinding(lView, bindingIndex, value) {
14387 return lView[bindingIndex] = value;
14388}
14389/** Gets the current binding value. */
14390function getBinding(lView, bindingIndex) {
14391 ngDevMode && assertIndexInRange(lView, bindingIndex);
14392 ngDevMode &&
14393 assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
14394 return lView[bindingIndex];
14395}
14396/**
14397 * Updates binding if changed, then returns whether it was updated.
14398 *
14399 * This function also checks the `CheckNoChangesMode` and throws if changes are made.
14400 * Some changes (Objects/iterables) during `CheckNoChangesMode` are exempt to comply with VE
14401 * behavior.
14402 *
14403 * @param lView current `LView`
14404 * @param bindingIndex The binding in the `LView` to check
14405 * @param value New value to check against `lView[bindingIndex]`
14406 * @returns `true` if the bindings has changed. (Throws if binding has changed during
14407 * `CheckNoChangesMode`)
14408 */
14409function bindingUpdated(lView, bindingIndex, value) {
14410 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
14411 ngDevMode &&
14412 assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`);
14413 const oldValue = lView[bindingIndex];
14414 if (Object.is(oldValue, value)) {
14415 return false;
14416 }
14417 else {
14418 if (ngDevMode && isInCheckNoChangesMode()) {
14419 // View engine didn't report undefined values as changed on the first checkNoChanges pass
14420 // (before the change detection was run).
14421 const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
14422 if (!devModeEqual(oldValueToCompare, value)) {
14423 const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
14424 throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName);
14425 }
14426 // There was a change, but the `devModeEqual` decided that the change is exempt from an error.
14427 // For this reason we exit as if no change. The early exit is needed to prevent the changed
14428 // value to be written into `LView` (If we would write the new value that we would not see it
14429 // as change on next CD.)
14430 return false;
14431 }
14432 lView[bindingIndex] = value;
14433 return true;
14434 }
14435}
14436/** Updates 2 bindings if changed, then returns whether either was updated. */
14437function bindingUpdated2(lView, bindingIndex, exp1, exp2) {
14438 const different = bindingUpdated(lView, bindingIndex, exp1);
14439 return bindingUpdated(lView, bindingIndex + 1, exp2) || different;
14440}
14441/** Updates 3 bindings if changed, then returns whether any was updated. */
14442function bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) {
14443 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
14444 return bindingUpdated(lView, bindingIndex + 2, exp3) || different;
14445}
14446/** Updates 4 bindings if changed, then returns whether any was updated. */
14447function bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) {
14448 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
14449 return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different;
14450}
14451
14452/**
14453 * @license
14454 * Copyright Google LLC All Rights Reserved.
14455 *
14456 * Use of this source code is governed by an MIT-style license that can be
14457 * found in the LICENSE file at https://angular.io/license
14458 */
14459/**
14460 * Updates the value of or removes a bound attribute on an Element.
14461 *
14462 * Used in the case of `[attr.title]="value"`
14463 *
14464 * @param name name The name of the attribute.
14465 * @param value value The attribute is removed when value is `null` or `undefined`.
14466 * Otherwise the attribute value is set to the stringified value.
14467 * @param sanitizer An optional function used to sanitize the value.
14468 * @param namespace Optional namespace to use when setting the attribute.
14469 *
14470 * @codeGenApi
14471 */
14472function ɵɵattribute(name, value, sanitizer, namespace) {
14473 const lView = getLView();
14474 const bindingIndex = nextBindingIndex();
14475 if (bindingUpdated(lView, bindingIndex, value)) {
14476 const tView = getTView();
14477 const tNode = getSelectedTNode();
14478 elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace);
14479 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, 'attr.' + name, bindingIndex);
14480 }
14481 return ɵɵattribute;
14482}
14483
14484/**
14485 * @license
14486 * Copyright Google LLC All Rights Reserved.
14487 *
14488 * Use of this source code is governed by an MIT-style license that can be
14489 * found in the LICENSE file at https://angular.io/license
14490 */
14491/**
14492 * Create interpolation bindings with a variable number of expressions.
14493 *
14494 * If there are 1 to 8 expressions `interpolation1()` to `interpolation8()` should be used instead.
14495 * Those are faster because there is no need to create an array of expressions and iterate over it.
14496 *
14497 * `values`:
14498 * - has static text at even indexes,
14499 * - has evaluated expressions at odd indexes.
14500 *
14501 * Returns the concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
14502 */
14503function interpolationV(lView, values) {
14504 ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
14505 ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
14506 let isBindingUpdated = false;
14507 let bindingIndex = getBindingIndex();
14508 for (let i = 1; i < values.length; i += 2) {
14509 // Check if bindings (odd indexes) have changed
14510 isBindingUpdated = bindingUpdated(lView, bindingIndex++, values[i]) || isBindingUpdated;
14511 }
14512 setBindingIndex(bindingIndex);
14513 if (!isBindingUpdated) {
14514 return NO_CHANGE;
14515 }
14516 // Build the updated content
14517 let content = values[0];
14518 for (let i = 1; i < values.length; i += 2) {
14519 content += renderStringify(values[i]) + values[i + 1];
14520 }
14521 return content;
14522}
14523/**
14524 * Creates an interpolation binding with 1 expression.
14525 *
14526 * @param prefix static value used for concatenation only.
14527 * @param v0 value checked for change.
14528 * @param suffix static value used for concatenation only.
14529 */
14530function interpolation1(lView, prefix, v0, suffix) {
14531 const different = bindingUpdated(lView, nextBindingIndex(), v0);
14532 return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE;
14533}
14534/**
14535 * Creates an interpolation binding with 2 expressions.
14536 */
14537function interpolation2(lView, prefix, v0, i0, v1, suffix) {
14538 const bindingIndex = getBindingIndex();
14539 const different = bindingUpdated2(lView, bindingIndex, v0, v1);
14540 incrementBindingIndex(2);
14541 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE;
14542}
14543/**
14544 * Creates an interpolation binding with 3 expressions.
14545 */
14546function interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix) {
14547 const bindingIndex = getBindingIndex();
14548 const different = bindingUpdated3(lView, bindingIndex, v0, v1, v2);
14549 incrementBindingIndex(3);
14550 return different ?
14551 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix :
14552 NO_CHANGE;
14553}
14554/**
14555 * Create an interpolation binding with 4 expressions.
14556 */
14557function interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
14558 const bindingIndex = getBindingIndex();
14559 const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
14560 incrementBindingIndex(4);
14561 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
14562 renderStringify(v2) + i2 + renderStringify(v3) + suffix :
14563 NO_CHANGE;
14564}
14565/**
14566 * Creates an interpolation binding with 5 expressions.
14567 */
14568function interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
14569 const bindingIndex = getBindingIndex();
14570 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
14571 different = bindingUpdated(lView, bindingIndex + 4, v4) || different;
14572 incrementBindingIndex(5);
14573 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
14574 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + suffix :
14575 NO_CHANGE;
14576}
14577/**
14578 * Creates an interpolation binding with 6 expressions.
14579 */
14580function interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
14581 const bindingIndex = getBindingIndex();
14582 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
14583 different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different;
14584 incrementBindingIndex(6);
14585 return different ?
14586 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
14587 renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix :
14588 NO_CHANGE;
14589}
14590/**
14591 * Creates an interpolation binding with 7 expressions.
14592 */
14593function interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
14594 const bindingIndex = getBindingIndex();
14595 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
14596 different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different;
14597 incrementBindingIndex(7);
14598 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
14599 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
14600 renderStringify(v5) + i5 + renderStringify(v6) + suffix :
14601 NO_CHANGE;
14602}
14603/**
14604 * Creates an interpolation binding with 8 expressions.
14605 */
14606function interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
14607 const bindingIndex = getBindingIndex();
14608 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
14609 different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different;
14610 incrementBindingIndex(8);
14611 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
14612 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
14613 renderStringify(v5) + i5 + renderStringify(v6) + i6 + renderStringify(v7) + suffix :
14614 NO_CHANGE;
14615}
14616
14617/**
14618 *
14619 * Update an interpolated attribute on an element with single bound value surrounded by text.
14620 *
14621 * Used when the value passed to a property has 1 interpolated value in it:
14622 *
14623 * ```html
14624 * <div attr.title="prefix{{v0}}suffix"></div>
14625 * ```
14626 *
14627 * Its compiled representation is::
14628 *
14629 * ```ts
14630 * ɵɵattributeInterpolate1('title', 'prefix', v0, 'suffix');
14631 * ```
14632 *
14633 * @param attrName The name of the attribute to update
14634 * @param prefix Static value used for concatenation only.
14635 * @param v0 Value checked for change.
14636 * @param suffix Static value used for concatenation only.
14637 * @param sanitizer An optional sanitizer function
14638 * @returns itself, so that it may be chained.
14639 * @codeGenApi
14640 */
14641function ɵɵattributeInterpolate1(attrName, prefix, v0, suffix, sanitizer, namespace) {
14642 const lView = getLView();
14643 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
14644 if (interpolatedValue !== NO_CHANGE) {
14645 const tNode = getSelectedTNode();
14646 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14647 ngDevMode &&
14648 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 1, prefix, suffix);
14649 }
14650 return ɵɵattributeInterpolate1;
14651}
14652/**
14653 *
14654 * Update an interpolated attribute on an element with 2 bound values surrounded by text.
14655 *
14656 * Used when the value passed to a property has 2 interpolated values in it:
14657 *
14658 * ```html
14659 * <div attr.title="prefix{{v0}}-{{v1}}suffix"></div>
14660 * ```
14661 *
14662 * Its compiled representation is::
14663 *
14664 * ```ts
14665 * ɵɵattributeInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
14666 * ```
14667 *
14668 * @param attrName The name of the attribute to update
14669 * @param prefix Static value used for concatenation only.
14670 * @param v0 Value checked for change.
14671 * @param i0 Static value used for concatenation only.
14672 * @param v1 Value checked for change.
14673 * @param suffix Static value used for concatenation only.
14674 * @param sanitizer An optional sanitizer function
14675 * @returns itself, so that it may be chained.
14676 * @codeGenApi
14677 */
14678function ɵɵattributeInterpolate2(attrName, prefix, v0, i0, v1, suffix, sanitizer, namespace) {
14679 const lView = getLView();
14680 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
14681 if (interpolatedValue !== NO_CHANGE) {
14682 const tNode = getSelectedTNode();
14683 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14684 ngDevMode &&
14685 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 2, prefix, i0, suffix);
14686 }
14687 return ɵɵattributeInterpolate2;
14688}
14689/**
14690 *
14691 * Update an interpolated attribute on an element with 3 bound values surrounded by text.
14692 *
14693 * Used when the value passed to a property has 3 interpolated values in it:
14694 *
14695 * ```html
14696 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
14697 * ```
14698 *
14699 * Its compiled representation is::
14700 *
14701 * ```ts
14702 * ɵɵattributeInterpolate3(
14703 * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
14704 * ```
14705 *
14706 * @param attrName The name of the attribute to update
14707 * @param prefix Static value used for concatenation only.
14708 * @param v0 Value checked for change.
14709 * @param i0 Static value used for concatenation only.
14710 * @param v1 Value checked for change.
14711 * @param i1 Static value used for concatenation only.
14712 * @param v2 Value checked for change.
14713 * @param suffix Static value used for concatenation only.
14714 * @param sanitizer An optional sanitizer function
14715 * @returns itself, so that it may be chained.
14716 * @codeGenApi
14717 */
14718function ɵɵattributeInterpolate3(attrName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer, namespace) {
14719 const lView = getLView();
14720 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
14721 if (interpolatedValue !== NO_CHANGE) {
14722 const tNode = getSelectedTNode();
14723 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14724 ngDevMode &&
14725 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 3, prefix, i0, i1, suffix);
14726 }
14727 return ɵɵattributeInterpolate3;
14728}
14729/**
14730 *
14731 * Update an interpolated attribute on an element with 4 bound values surrounded by text.
14732 *
14733 * Used when the value passed to a property has 4 interpolated values in it:
14734 *
14735 * ```html
14736 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
14737 * ```
14738 *
14739 * Its compiled representation is::
14740 *
14741 * ```ts
14742 * ɵɵattributeInterpolate4(
14743 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
14744 * ```
14745 *
14746 * @param attrName The name of the attribute to update
14747 * @param prefix Static value used for concatenation only.
14748 * @param v0 Value checked for change.
14749 * @param i0 Static value used for concatenation only.
14750 * @param v1 Value checked for change.
14751 * @param i1 Static value used for concatenation only.
14752 * @param v2 Value checked for change.
14753 * @param i2 Static value used for concatenation only.
14754 * @param v3 Value checked for change.
14755 * @param suffix Static value used for concatenation only.
14756 * @param sanitizer An optional sanitizer function
14757 * @returns itself, so that it may be chained.
14758 * @codeGenApi
14759 */
14760function ɵɵattributeInterpolate4(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer, namespace) {
14761 const lView = getLView();
14762 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
14763 if (interpolatedValue !== NO_CHANGE) {
14764 const tNode = getSelectedTNode();
14765 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14766 ngDevMode &&
14767 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix);
14768 }
14769 return ɵɵattributeInterpolate4;
14770}
14771/**
14772 *
14773 * Update an interpolated attribute on an element with 5 bound values surrounded by text.
14774 *
14775 * Used when the value passed to a property has 5 interpolated values in it:
14776 *
14777 * ```html
14778 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
14779 * ```
14780 *
14781 * Its compiled representation is::
14782 *
14783 * ```ts
14784 * ɵɵattributeInterpolate5(
14785 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
14786 * ```
14787 *
14788 * @param attrName The name of the attribute to update
14789 * @param prefix Static value used for concatenation only.
14790 * @param v0 Value checked for change.
14791 * @param i0 Static value used for concatenation only.
14792 * @param v1 Value checked for change.
14793 * @param i1 Static value used for concatenation only.
14794 * @param v2 Value checked for change.
14795 * @param i2 Static value used for concatenation only.
14796 * @param v3 Value checked for change.
14797 * @param i3 Static value used for concatenation only.
14798 * @param v4 Value checked for change.
14799 * @param suffix Static value used for concatenation only.
14800 * @param sanitizer An optional sanitizer function
14801 * @returns itself, so that it may be chained.
14802 * @codeGenApi
14803 */
14804function ɵɵattributeInterpolate5(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer, namespace) {
14805 const lView = getLView();
14806 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
14807 if (interpolatedValue !== NO_CHANGE) {
14808 const tNode = getSelectedTNode();
14809 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14810 ngDevMode &&
14811 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix);
14812 }
14813 return ɵɵattributeInterpolate5;
14814}
14815/**
14816 *
14817 * Update an interpolated attribute on an element with 6 bound values surrounded by text.
14818 *
14819 * Used when the value passed to a property has 6 interpolated values in it:
14820 *
14821 * ```html
14822 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
14823 * ```
14824 *
14825 * Its compiled representation is::
14826 *
14827 * ```ts
14828 * ɵɵattributeInterpolate6(
14829 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
14830 * ```
14831 *
14832 * @param attrName The name of the attribute to update
14833 * @param prefix Static value used for concatenation only.
14834 * @param v0 Value checked for change.
14835 * @param i0 Static value used for concatenation only.
14836 * @param v1 Value checked for change.
14837 * @param i1 Static value used for concatenation only.
14838 * @param v2 Value checked for change.
14839 * @param i2 Static value used for concatenation only.
14840 * @param v3 Value checked for change.
14841 * @param i3 Static value used for concatenation only.
14842 * @param v4 Value checked for change.
14843 * @param i4 Static value used for concatenation only.
14844 * @param v5 Value checked for change.
14845 * @param suffix Static value used for concatenation only.
14846 * @param sanitizer An optional sanitizer function
14847 * @returns itself, so that it may be chained.
14848 * @codeGenApi
14849 */
14850function ɵɵattributeInterpolate6(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer, namespace) {
14851 const lView = getLView();
14852 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
14853 if (interpolatedValue !== NO_CHANGE) {
14854 const tNode = getSelectedTNode();
14855 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14856 ngDevMode &&
14857 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, i4, suffix);
14858 }
14859 return ɵɵattributeInterpolate6;
14860}
14861/**
14862 *
14863 * Update an interpolated attribute on an element with 7 bound values surrounded by text.
14864 *
14865 * Used when the value passed to a property has 7 interpolated values in it:
14866 *
14867 * ```html
14868 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
14869 * ```
14870 *
14871 * Its compiled representation is::
14872 *
14873 * ```ts
14874 * ɵɵattributeInterpolate7(
14875 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
14876 * ```
14877 *
14878 * @param attrName The name of the attribute to update
14879 * @param prefix Static value used for concatenation only.
14880 * @param v0 Value checked for change.
14881 * @param i0 Static value used for concatenation only.
14882 * @param v1 Value checked for change.
14883 * @param i1 Static value used for concatenation only.
14884 * @param v2 Value checked for change.
14885 * @param i2 Static value used for concatenation only.
14886 * @param v3 Value checked for change.
14887 * @param i3 Static value used for concatenation only.
14888 * @param v4 Value checked for change.
14889 * @param i4 Static value used for concatenation only.
14890 * @param v5 Value checked for change.
14891 * @param i5 Static value used for concatenation only.
14892 * @param v6 Value checked for change.
14893 * @param suffix Static value used for concatenation only.
14894 * @param sanitizer An optional sanitizer function
14895 * @returns itself, so that it may be chained.
14896 * @codeGenApi
14897 */
14898function ɵɵattributeInterpolate7(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer, namespace) {
14899 const lView = getLView();
14900 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
14901 if (interpolatedValue !== NO_CHANGE) {
14902 const tNode = getSelectedTNode();
14903 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14904 ngDevMode &&
14905 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, suffix);
14906 }
14907 return ɵɵattributeInterpolate7;
14908}
14909/**
14910 *
14911 * Update an interpolated attribute on an element with 8 bound values surrounded by text.
14912 *
14913 * Used when the value passed to a property has 8 interpolated values in it:
14914 *
14915 * ```html
14916 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
14917 * ```
14918 *
14919 * Its compiled representation is::
14920 *
14921 * ```ts
14922 * ɵɵattributeInterpolate8(
14923 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
14924 * ```
14925 *
14926 * @param attrName The name of the attribute to update
14927 * @param prefix Static value used for concatenation only.
14928 * @param v0 Value checked for change.
14929 * @param i0 Static value used for concatenation only.
14930 * @param v1 Value checked for change.
14931 * @param i1 Static value used for concatenation only.
14932 * @param v2 Value checked for change.
14933 * @param i2 Static value used for concatenation only.
14934 * @param v3 Value checked for change.
14935 * @param i3 Static value used for concatenation only.
14936 * @param v4 Value checked for change.
14937 * @param i4 Static value used for concatenation only.
14938 * @param v5 Value checked for change.
14939 * @param i5 Static value used for concatenation only.
14940 * @param v6 Value checked for change.
14941 * @param i6 Static value used for concatenation only.
14942 * @param v7 Value checked for change.
14943 * @param suffix Static value used for concatenation only.
14944 * @param sanitizer An optional sanitizer function
14945 * @returns itself, so that it may be chained.
14946 * @codeGenApi
14947 */
14948function ɵɵattributeInterpolate8(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer, namespace) {
14949 const lView = getLView();
14950 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
14951 if (interpolatedValue !== NO_CHANGE) {
14952 const tNode = getSelectedTNode();
14953 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
14954 ngDevMode &&
14955 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, suffix);
14956 }
14957 return ɵɵattributeInterpolate8;
14958}
14959/**
14960 * Update an interpolated attribute on an element with 9 or more bound values surrounded by text.
14961 *
14962 * Used when the number of interpolated values exceeds 8.
14963 *
14964 * ```html
14965 * <div
14966 * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
14967 * ```
14968 *
14969 * Its compiled representation is::
14970 *
14971 * ```ts
14972 * ɵɵattributeInterpolateV(
14973 * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
14974 * 'suffix']);
14975 * ```
14976 *
14977 * @param attrName The name of the attribute to update.
14978 * @param values The collection of values and the strings in-between those values, beginning with
14979 * a string prefix and ending with a string suffix.
14980 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
14981 * @param sanitizer An optional sanitizer function
14982 * @returns itself, so that it may be chained.
14983 * @codeGenApi
14984 */
14985function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
14986 const lView = getLView();
14987 const interpolated = interpolationV(lView, values);
14988 if (interpolated !== NO_CHANGE) {
14989 const tNode = getSelectedTNode();
14990 elementAttributeInternal(tNode, lView, attrName, interpolated, sanitizer, namespace);
14991 if (ngDevMode) {
14992 const interpolationInBetween = [values[0]]; // prefix
14993 for (let i = 2; i < values.length; i += 2) {
14994 interpolationInBetween.push(values[i]);
14995 }
14996 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
14997 }
14998 }
14999 return ɵɵattributeInterpolateV;
15000}
15001
15002/**
15003 * @license
15004 * Copyright Google LLC All Rights Reserved.
15005 *
15006 * Use of this source code is governed by an MIT-style license that can be
15007 * found in the LICENSE file at https://angular.io/license
15008 */
15009function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
15010 ngDevMode && assertFirstCreatePass(tView);
15011 ngDevMode && ngDevMode.firstCreatePass++;
15012 const tViewConsts = tView.consts;
15013 // TODO(pk): refactor getOrCreateTNode to have the "create" only version
15014 const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
15015 resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
15016 registerPostOrderHooks(tView, tNode);
15017 const embeddedTView = tNode.tViews = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
15018 if (tView.queries !== null) {
15019 tView.queries.template(tView, tNode);
15020 embeddedTView.queries = tView.queries.embeddedTView(tNode);
15021 }
15022 return tNode;
15023}
15024/**
15025 * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
15026 *
15027 * <ng-template #foo>
15028 * <div></div>
15029 * </ng-template>
15030 *
15031 * @param index The index of the container in the data array
15032 * @param templateFn Inline template
15033 * @param decls The number of nodes, local refs, and pipes for this template
15034 * @param vars The number of bindings for this template
15035 * @param tagName The name of the container element, if applicable
15036 * @param attrsIndex Index of template attributes in the `consts` array.
15037 * @param localRefs Index of the local references in the `consts` array.
15038 * @param localRefExtractor A function which extracts local-refs values from the template.
15039 * Defaults to the current element associated with the local-ref.
15040 *
15041 * @codeGenApi
15042 */
15043function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
15044 const lView = getLView();
15045 const tView = getTView();
15046 const adjustedIndex = index + HEADER_OFFSET;
15047 const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
15048 tView.data[adjustedIndex];
15049 setCurrentTNode(tNode, false);
15050 const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : '');
15051 appendChild(tView, lView, comment, tNode);
15052 attachPatchData(comment, lView);
15053 addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
15054 if (isDirectiveHost(tNode)) {
15055 createDirectivesInstances(tView, lView, tNode);
15056 }
15057 if (localRefsIndex != null) {
15058 saveResolvedLocalsInData(lView, tNode, localRefExtractor);
15059 }
15060}
15061
15062/**
15063 * @license
15064 * Copyright Google LLC All Rights Reserved.
15065 *
15066 * Use of this source code is governed by an MIT-style license that can be
15067 * found in the LICENSE file at https://angular.io/license
15068 */
15069/** Store a value in the `data` at a given `index`. */
15070function store(tView, lView, index, value) {
15071 // We don't store any static data for local variables, so the first time
15072 // we see the template, we should store as null to avoid a sparse array
15073 if (index >= tView.data.length) {
15074 tView.data[index] = null;
15075 tView.blueprint[index] = null;
15076 }
15077 lView[index] = value;
15078}
15079/**
15080 * Retrieves a local reference from the current contextViewData.
15081 *
15082 * If the reference to retrieve is in a parent view, this instruction is used in conjunction
15083 * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
15084 *
15085 * @param index The index of the local ref in contextViewData.
15086 *
15087 * @codeGenApi
15088 */
15089function ɵɵreference(index) {
15090 const contextLView = getContextLView();
15091 return load(contextLView, HEADER_OFFSET + index);
15092}
15093
15094/**
15095 * @license
15096 * Copyright Google LLC All Rights Reserved.
15097 *
15098 * Use of this source code is governed by an MIT-style license that can be
15099 * found in the LICENSE file at https://angular.io/license
15100 */
15101/**
15102 * Update a property on a selected element.
15103 *
15104 * Operates on the element selected by index via the {@link select} instruction.
15105 *
15106 * If the property name also exists as an input property on one of the element's directives,
15107 * the component property will be set instead of the element property. This check must
15108 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled
15109 *
15110 * @param propName Name of property. Because it is going to DOM, this is not subject to
15111 * renaming as part of minification.
15112 * @param value New value to write.
15113 * @param sanitizer An optional function used to sanitize the value.
15114 * @returns This function returns itself so that it may be chained
15115 * (e.g. `property('name', ctx.name)('title', ctx.title)`)
15116 *
15117 * @codeGenApi
15118 */
15119function ɵɵproperty(propName, value, sanitizer) {
15120 const lView = getLView();
15121 const bindingIndex = nextBindingIndex();
15122 if (bindingUpdated(lView, bindingIndex, value)) {
15123 const tView = getTView();
15124 const tNode = getSelectedTNode();
15125 elementPropertyInternal(tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, false);
15126 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
15127 }
15128 return ɵɵproperty;
15129}
15130/**
15131 * Given `<div style="..." my-dir>` and `MyDir` with `@Input('style')` we need to write to
15132 * directive input.
15133 */
15134function setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased) {
15135 const inputs = tNode.inputs;
15136 const property = isClassBased ? 'class' : 'style';
15137 // We support both 'class' and `className` hence the fallback.
15138 setInputsForProperty(tView, lView, inputs[property], property, value);
15139}
15140
15141/**
15142 * @license
15143 * Copyright Google LLC All Rights Reserved.
15144 *
15145 * Use of this source code is governed by an MIT-style license that can be
15146 * found in the LICENSE file at https://angular.io/license
15147 */
15148function elementStartFirstCreatePass(index, tView, lView, native, name, attrsIndex, localRefsIndex) {
15149 ngDevMode && assertFirstCreatePass(tView);
15150 ngDevMode && ngDevMode.firstCreatePass++;
15151 const tViewConsts = tView.consts;
15152 const attrs = getConstant(tViewConsts, attrsIndex);
15153 const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, name, attrs);
15154 const hasDirectives = resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
15155 if (ngDevMode) {
15156 validateElementIsKnown(native, lView, tNode.value, tView.schemas, hasDirectives);
15157 }
15158 if (tNode.attrs !== null) {
15159 computeStaticStyling(tNode, tNode.attrs, false);
15160 }
15161 if (tNode.mergedAttrs !== null) {
15162 computeStaticStyling(tNode, tNode.mergedAttrs, true);
15163 }
15164 if (tView.queries !== null) {
15165 tView.queries.elementStart(tView, tNode);
15166 }
15167 return tNode;
15168}
15169/**
15170 * Create DOM element. The instruction must later be followed by `elementEnd()` call.
15171 *
15172 * @param index Index of the element in the LView array
15173 * @param name Name of the DOM Node
15174 * @param attrsIndex Index of the element's attributes in the `consts` array.
15175 * @param localRefsIndex Index of the element's local references in the `consts` array.
15176 * @returns This function returns itself so that it may be chained.
15177 *
15178 * Attributes and localRefs are passed as an array of strings where elements with an even index
15179 * hold an attribute name and elements with an odd index hold an attribute value, ex.:
15180 * ['id', 'warning5', 'class', 'alert']
15181 *
15182 * @codeGenApi
15183 */
15184function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
15185 const lView = getLView();
15186 const tView = getTView();
15187 const adjustedIndex = HEADER_OFFSET + index;
15188 ngDevMode &&
15189 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'elements should be created before any bindings');
15190 ngDevMode && assertIndexInRange(lView, adjustedIndex);
15191 const renderer = lView[RENDERER];
15192 const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1());
15193 const tNode = tView.firstCreatePass ?
15194 elementStartFirstCreatePass(adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
15195 tView.data[adjustedIndex];
15196 setCurrentTNode(tNode, true);
15197 const mergedAttrs = tNode.mergedAttrs;
15198 if (mergedAttrs !== null) {
15199 setUpAttributes(renderer, native, mergedAttrs);
15200 }
15201 const classes = tNode.classes;
15202 if (classes !== null) {
15203 writeDirectClass(renderer, native, classes);
15204 }
15205 const styles = tNode.styles;
15206 if (styles !== null) {
15207 writeDirectStyle(renderer, native, styles);
15208 }
15209 if ((tNode.flags & 64 /* TNodeFlags.isDetached */) !== 64 /* TNodeFlags.isDetached */) {
15210 // In the i18n case, the translation may have removed this element, so only add it if it is not
15211 // detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
15212 appendChild(tView, lView, native, tNode);
15213 }
15214 // any immediate children of a component or template container must be pre-emptively
15215 // monkey-patched with the component view data so that the element can be inspected
15216 // later on using any element discovery utility methods (see `element_discovery.ts`)
15217 if (getElementDepthCount() === 0) {
15218 attachPatchData(native, lView);
15219 }
15220 increaseElementDepthCount();
15221 if (isDirectiveHost(tNode)) {
15222 createDirectivesInstances(tView, lView, tNode);
15223 executeContentQueries(tView, tNode, lView);
15224 }
15225 if (localRefsIndex !== null) {
15226 saveResolvedLocalsInData(lView, tNode);
15227 }
15228 return ɵɵelementStart;
15229}
15230/**
15231 * Mark the end of the element.
15232 * @returns This function returns itself so that it may be chained.
15233 *
15234 * @codeGenApi
15235 */
15236function ɵɵelementEnd() {
15237 let currentTNode = getCurrentTNode();
15238 ngDevMode && assertDefined(currentTNode, 'No parent node to close.');
15239 if (isCurrentTNodeParent()) {
15240 setCurrentTNodeAsNotParent();
15241 }
15242 else {
15243 ngDevMode && assertHasParent(getCurrentTNode());
15244 currentTNode = currentTNode.parent;
15245 setCurrentTNode(currentTNode, false);
15246 }
15247 const tNode = currentTNode;
15248 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */);
15249 decreaseElementDepthCount();
15250 const tView = getTView();
15251 if (tView.firstCreatePass) {
15252 registerPostOrderHooks(tView, currentTNode);
15253 if (isContentQueryHost(currentTNode)) {
15254 tView.queries.elementEnd(currentTNode);
15255 }
15256 }
15257 if (tNode.classesWithoutHost != null && hasClassInput(tNode)) {
15258 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.classesWithoutHost, true);
15259 }
15260 if (tNode.stylesWithoutHost != null && hasStyleInput(tNode)) {
15261 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.stylesWithoutHost, false);
15262 }
15263 return ɵɵelementEnd;
15264}
15265/**
15266 * Creates an empty element using {@link elementStart} and {@link elementEnd}
15267 *
15268 * @param index Index of the element in the data array
15269 * @param name Name of the DOM Node
15270 * @param attrsIndex Index of the element's attributes in the `consts` array.
15271 * @param localRefsIndex Index of the element's local references in the `consts` array.
15272 * @returns This function returns itself so that it may be chained.
15273 *
15274 * @codeGenApi
15275 */
15276function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
15277 ɵɵelementStart(index, name, attrsIndex, localRefsIndex);
15278 ɵɵelementEnd();
15279 return ɵɵelement;
15280}
15281
15282/**
15283 * @license
15284 * Copyright Google LLC All Rights Reserved.
15285 *
15286 * Use of this source code is governed by an MIT-style license that can be
15287 * found in the LICENSE file at https://angular.io/license
15288 */
15289function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) {
15290 ngDevMode && ngDevMode.firstCreatePass++;
15291 const tViewConsts = tView.consts;
15292 const attrs = getConstant(tViewConsts, attrsIndex);
15293 const tNode = getOrCreateTNode(tView, index, 8 /* TNodeType.ElementContainer */, 'ng-container', attrs);
15294 // While ng-container doesn't necessarily support styling, we use the style context to identify
15295 // and execute directives on the ng-container.
15296 if (attrs !== null) {
15297 computeStaticStyling(tNode, attrs, true);
15298 }
15299 const localRefs = getConstant(tViewConsts, localRefsIndex);
15300 resolveDirectives(tView, lView, tNode, localRefs);
15301 if (tView.queries !== null) {
15302 tView.queries.elementStart(tView, tNode);
15303 }
15304 return tNode;
15305}
15306/**
15307 * Creates a logical container for other nodes (<ng-container>) backed by a comment node in the DOM.
15308 * The instruction must later be followed by `elementContainerEnd()` call.
15309 *
15310 * @param index Index of the element in the LView array
15311 * @param attrsIndex Index of the container attributes in the `consts` array.
15312 * @param localRefsIndex Index of the container's local references in the `consts` array.
15313 * @returns This function returns itself so that it may be chained.
15314 *
15315 * Even if this instruction accepts a set of attributes no actual attribute values are propagated to
15316 * the DOM (as a comment node can't have attributes). Attributes are here only for directive
15317 * matching purposes and setting initial inputs of directives.
15318 *
15319 * @codeGenApi
15320 */
15321function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
15322 const lView = getLView();
15323 const tView = getTView();
15324 const adjustedIndex = index + HEADER_OFFSET;
15325 ngDevMode && assertIndexInRange(lView, adjustedIndex);
15326 ngDevMode &&
15327 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings');
15328 const tNode = tView.firstCreatePass ?
15329 elementContainerStartFirstCreatePass(adjustedIndex, tView, lView, attrsIndex, localRefsIndex) :
15330 tView.data[adjustedIndex];
15331 setCurrentTNode(tNode, true);
15332 ngDevMode && ngDevMode.rendererCreateComment++;
15333 const native = lView[adjustedIndex] =
15334 lView[RENDERER].createComment(ngDevMode ? 'ng-container' : '');
15335 appendChild(tView, lView, native, tNode);
15336 attachPatchData(native, lView);
15337 if (isDirectiveHost(tNode)) {
15338 createDirectivesInstances(tView, lView, tNode);
15339 executeContentQueries(tView, tNode, lView);
15340 }
15341 if (localRefsIndex != null) {
15342 saveResolvedLocalsInData(lView, tNode);
15343 }
15344 return ɵɵelementContainerStart;
15345}
15346/**
15347 * Mark the end of the <ng-container>.
15348 * @returns This function returns itself so that it may be chained.
15349 *
15350 * @codeGenApi
15351 */
15352function ɵɵelementContainerEnd() {
15353 let currentTNode = getCurrentTNode();
15354 const tView = getTView();
15355 if (isCurrentTNodeParent()) {
15356 setCurrentTNodeAsNotParent();
15357 }
15358 else {
15359 ngDevMode && assertHasParent(currentTNode);
15360 currentTNode = currentTNode.parent;
15361 setCurrentTNode(currentTNode, false);
15362 }
15363 ngDevMode && assertTNodeType(currentTNode, 8 /* TNodeType.ElementContainer */);
15364 if (tView.firstCreatePass) {
15365 registerPostOrderHooks(tView, currentTNode);
15366 if (isContentQueryHost(currentTNode)) {
15367 tView.queries.elementEnd(currentTNode);
15368 }
15369 }
15370 return ɵɵelementContainerEnd;
15371}
15372/**
15373 * Creates an empty logical container using {@link elementContainerStart}
15374 * and {@link elementContainerEnd}
15375 *
15376 * @param index Index of the element in the LView array
15377 * @param attrsIndex Index of the container attributes in the `consts` array.
15378 * @param localRefsIndex Index of the container's local references in the `consts` array.
15379 * @returns This function returns itself so that it may be chained.
15380 *
15381 * @codeGenApi
15382 */
15383function ɵɵelementContainer(index, attrsIndex, localRefsIndex) {
15384 ɵɵelementContainerStart(index, attrsIndex, localRefsIndex);
15385 ɵɵelementContainerEnd();
15386 return ɵɵelementContainer;
15387}
15388
15389/**
15390 * Returns the current OpaqueViewState instance.
15391 *
15392 * Used in conjunction with the restoreView() instruction to save a snapshot
15393 * of the current view and restore it when listeners are invoked. This allows
15394 * walking the declaration view tree in listeners to get vars from parent views.
15395 *
15396 * @codeGenApi
15397 */
15398function ɵɵgetCurrentView() {
15399 return getLView();
15400}
15401
15402/**
15403 * @license
15404 * Copyright Google LLC All Rights Reserved.
15405 *
15406 * Use of this source code is governed by an MIT-style license that can be
15407 * found in the LICENSE file at https://angular.io/license
15408 */
15409/**
15410 * Determine if the argument is shaped like a Promise
15411 */
15412function isPromise(obj) {
15413 // allow any Promise/A+ compliant thenable.
15414 // It's up to the caller to ensure that obj.then conforms to the spec
15415 return !!obj && typeof obj.then === 'function';
15416}
15417/**
15418 * Determine if the argument is a Subscribable
15419 */
15420function isSubscribable(obj) {
15421 return !!obj && typeof obj.subscribe === 'function';
15422}
15423/**
15424 * Determine if the argument is an Observable
15425 *
15426 * Strictly this tests that the `obj` is `Subscribable`, since `Observable`
15427 * types need additional methods, such as `lift()`. But it is adequate for our
15428 * needs since within the Angular framework code we only ever need to use the
15429 * `subscribe()` method, and RxJS has mechanisms to wrap `Subscribable` objects
15430 * into `Observable` as needed.
15431 */
15432const isObservable = isSubscribable;
15433
15434/**
15435 * @license
15436 * Copyright Google LLC All Rights Reserved.
15437 *
15438 * Use of this source code is governed by an MIT-style license that can be
15439 * found in the LICENSE file at https://angular.io/license
15440 */
15441/**
15442 * Adds an event listener to the current node.
15443 *
15444 * If an output exists on one of the node's directives, it also subscribes to the output
15445 * and saves the subscription for later cleanup.
15446 *
15447 * @param eventName Name of the event
15448 * @param listenerFn The function to be called when event emits
15449 * @param useCapture Whether or not to use capture in event listener
15450 * @param eventTargetResolver Function that returns global target information in case this listener
15451 * should be attached to a global object like window, document or body
15452 *
15453 * @codeGenApi
15454 */
15455function ɵɵlistener(eventName, listenerFn, useCapture, eventTargetResolver) {
15456 const lView = getLView();
15457 const tView = getTView();
15458 const tNode = getCurrentTNode();
15459 listenerInternal(tView, lView, lView[RENDERER], tNode, eventName, listenerFn, !!useCapture, eventTargetResolver);
15460 return ɵɵlistener;
15461}
15462/**
15463 * Registers a synthetic host listener (e.g. `(@foo.start)`) on a component or directive.
15464 *
15465 * This instruction is for compatibility purposes and is designed to ensure that a
15466 * synthetic host listener (e.g. `@HostListener('@foo.start')`) properly gets rendered
15467 * in the component's renderer. Normally all host listeners are evaluated with the
15468 * parent component's renderer, but, in the case of animation @triggers, they need
15469 * to be evaluated with the sub component's renderer (because that's where the
15470 * animation triggers are defined).
15471 *
15472 * Do not use this instruction as a replacement for `listener`. This instruction
15473 * only exists to ensure compatibility with the ViewEngine's host binding behavior.
15474 *
15475 * @param eventName Name of the event
15476 * @param listenerFn The function to be called when event emits
15477 * @param useCapture Whether or not to use capture in event listener
15478 * @param eventTargetResolver Function that returns global target information in case this listener
15479 * should be attached to a global object like window, document or body
15480 *
15481 * @codeGenApi
15482 */
15483function ɵɵsyntheticHostListener(eventName, listenerFn) {
15484 const tNode = getCurrentTNode();
15485 const lView = getLView();
15486 const tView = getTView();
15487 const currentDef = getCurrentDirectiveDef(tView.data);
15488 const renderer = loadComponentRenderer(currentDef, tNode, lView);
15489 listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn, false);
15490 return ɵɵsyntheticHostListener;
15491}
15492/**
15493 * A utility function that checks if a given element has already an event handler registered for an
15494 * event with a specified name. The TView.cleanup data structure is used to find out which events
15495 * are registered for a given element.
15496 */
15497function findExistingListener(tView, lView, eventName, tNodeIdx) {
15498 const tCleanup = tView.cleanup;
15499 if (tCleanup != null) {
15500 for (let i = 0; i < tCleanup.length - 1; i += 2) {
15501 const cleanupEventName = tCleanup[i];
15502 if (cleanupEventName === eventName && tCleanup[i + 1] === tNodeIdx) {
15503 // We have found a matching event name on the same node but it might not have been
15504 // registered yet, so we must explicitly verify entries in the LView cleanup data
15505 // structures.
15506 const lCleanup = lView[CLEANUP];
15507 const listenerIdxInLCleanup = tCleanup[i + 2];
15508 return lCleanup.length > listenerIdxInLCleanup ? lCleanup[listenerIdxInLCleanup] : null;
15509 }
15510 // TView.cleanup can have a mix of 4-elements entries (for event handler cleanups) or
15511 // 2-element entries (for directive and queries destroy hooks). As such we can encounter
15512 // blocks of 4 or 2 items in the tView.cleanup and this is why we iterate over 2 elements
15513 // first and jump another 2 elements if we detect listeners cleanup (4 elements). Also check
15514 // documentation of TView.cleanup for more details of this data structure layout.
15515 if (typeof cleanupEventName === 'string') {
15516 i += 2;
15517 }
15518 }
15519 }
15520 return null;
15521}
15522function listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn, useCapture, eventTargetResolver) {
15523 const isTNodeDirectiveHost = isDirectiveHost(tNode);
15524 const firstCreatePass = tView.firstCreatePass;
15525 const tCleanup = firstCreatePass && getOrCreateTViewCleanup(tView);
15526 const context = lView[CONTEXT];
15527 // When the ɵɵlistener instruction was generated and is executed we know that there is either a
15528 // native listener or a directive output on this element. As such we we know that we will have to
15529 // register a listener and store its cleanup function on LView.
15530 const lCleanup = getOrCreateLViewCleanup(lView);
15531 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
15532 let processOutputs = true;
15533 // Adding a native event listener is applicable when:
15534 // - The corresponding TNode represents a DOM element.
15535 // - The event target has a resolver (usually resulting in a global object,
15536 // such as `window` or `document`).
15537 if ((tNode.type & 3 /* TNodeType.AnyRNode */) || eventTargetResolver) {
15538 const native = getNativeByTNode(tNode, lView);
15539 const target = eventTargetResolver ? eventTargetResolver(native) : native;
15540 const lCleanupIndex = lCleanup.length;
15541 const idxOrTargetGetter = eventTargetResolver ?
15542 (_lView) => eventTargetResolver(unwrapRNode(_lView[tNode.index])) :
15543 tNode.index;
15544 // In order to match current behavior, native DOM event listeners must be added for all
15545 // events (including outputs).
15546 if (isProceduralRenderer(renderer)) {
15547 // There might be cases where multiple directives on the same element try to register an event
15548 // handler function for the same event. In this situation we want to avoid registration of
15549 // several native listeners as each registration would be intercepted by NgZone and
15550 // trigger change detection. This would mean that a single user action would result in several
15551 // change detections being invoked. To avoid this situation we want to have only one call to
15552 // native handler registration (for the same element and same type of event).
15553 //
15554 // In order to have just one native event handler in presence of multiple handler functions,
15555 // we just register a first handler function as a native event listener and then chain
15556 // (coalesce) other handler functions on top of the first native handler function.
15557 let existingListener = null;
15558 // Please note that the coalescing described here doesn't happen for events specifying an
15559 // alternative target (ex. (document:click)) - this is to keep backward compatibility with the
15560 // view engine.
15561 // Also, we don't have to search for existing listeners is there are no directives
15562 // matching on a given node as we can't register multiple event handlers for the same event in
15563 // a template (this would mean having duplicate attributes).
15564 if (!eventTargetResolver && isTNodeDirectiveHost) {
15565 existingListener = findExistingListener(tView, lView, eventName, tNode.index);
15566 }
15567 if (existingListener !== null) {
15568 // Attach a new listener to coalesced listeners list, maintaining the order in which
15569 // listeners are registered. For performance reasons, we keep a reference to the last
15570 // listener in that list (in `__ngLastListenerFn__` field), so we can avoid going through
15571 // the entire set each time we need to add a new listener.
15572 const lastListenerFn = existingListener.__ngLastListenerFn__ || existingListener;
15573 lastListenerFn.__ngNextListenerFn__ = listenerFn;
15574 existingListener.__ngLastListenerFn__ = listenerFn;
15575 processOutputs = false;
15576 }
15577 else {
15578 listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
15579 const cleanupFn = renderer.listen(target, eventName, listenerFn);
15580 ngDevMode && ngDevMode.rendererAddEventListener++;
15581 lCleanup.push(listenerFn, cleanupFn);
15582 tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1);
15583 }
15584 }
15585 else {
15586 listenerFn = wrapListener(tNode, lView, context, listenerFn, true /** preventDefault */);
15587 target.addEventListener(eventName, listenerFn, useCapture);
15588 ngDevMode && ngDevMode.rendererAddEventListener++;
15589 lCleanup.push(listenerFn);
15590 tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCapture);
15591 }
15592 }
15593 else {
15594 // Even if there is no native listener to add, we still need to wrap the listener so that OnPush
15595 // ancestors are marked dirty when an event occurs.
15596 listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
15597 }
15598 // subscribe to directive outputs
15599 const outputs = tNode.outputs;
15600 let props;
15601 if (processOutputs && outputs !== null && (props = outputs[eventName])) {
15602 const propsLength = props.length;
15603 if (propsLength) {
15604 for (let i = 0; i < propsLength; i += 2) {
15605 const index = props[i];
15606 ngDevMode && assertIndexInRange(lView, index);
15607 const minifiedName = props[i + 1];
15608 const directiveInstance = lView[index];
15609 const output = directiveInstance[minifiedName];
15610 if (ngDevMode && !isObservable(output)) {
15611 throw new Error(`@Output ${minifiedName} not initialized in '${directiveInstance.constructor.name}'.`);
15612 }
15613 const subscription = output.subscribe(listenerFn);
15614 const idx = lCleanup.length;
15615 lCleanup.push(listenerFn, subscription);
15616 tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
15617 }
15618 }
15619 }
15620}
15621function executeListenerWithErrorHandling(lView, context, listenerFn, e) {
15622 try {
15623 profiler(6 /* ProfilerEvent.OutputStart */, context, listenerFn);
15624 // Only explicitly returning false from a listener should preventDefault
15625 return listenerFn(e) !== false;
15626 }
15627 catch (error) {
15628 handleError(lView, error);
15629 return false;
15630 }
15631 finally {
15632 profiler(7 /* ProfilerEvent.OutputEnd */, context, listenerFn);
15633 }
15634}
15635/**
15636 * Wraps an event listener with a function that marks ancestors dirty and prevents default behavior,
15637 * if applicable.
15638 *
15639 * @param tNode The TNode associated with this listener
15640 * @param lView The LView that contains this listener
15641 * @param listenerFn The listener function to call
15642 * @param wrapWithPreventDefault Whether or not to prevent default behavior
15643 * (the procedural renderer does this already, so in those cases, we should skip)
15644 */
15645function wrapListener(tNode, lView, context, listenerFn, wrapWithPreventDefault) {
15646 // Note: we are performing most of the work in the listener function itself
15647 // to optimize listener registration.
15648 return function wrapListenerIn_markDirtyAndPreventDefault(e) {
15649 // Ivy uses `Function` as a special token that allows us to unwrap the function
15650 // so that it can be invoked programmatically by `DebugNode.triggerEventHandler`.
15651 if (e === Function) {
15652 return listenerFn;
15653 }
15654 // In order to be backwards compatible with View Engine, events on component host nodes
15655 // must also mark the component view itself dirty (i.e. the view that it owns).
15656 const startView = tNode.flags & 2 /* TNodeFlags.isComponentHost */ ?
15657 getComponentLViewByIndex(tNode.index, lView) :
15658 lView;
15659 markViewDirty(startView);
15660 let result = executeListenerWithErrorHandling(lView, context, listenerFn, e);
15661 // A just-invoked listener function might have coalesced listeners so we need to check for
15662 // their presence and invoke as needed.
15663 let nextListenerFn = wrapListenerIn_markDirtyAndPreventDefault.__ngNextListenerFn__;
15664 while (nextListenerFn) {
15665 // We should prevent default if any of the listeners explicitly return false
15666 result = executeListenerWithErrorHandling(lView, context, nextListenerFn, e) && result;
15667 nextListenerFn = nextListenerFn.__ngNextListenerFn__;
15668 }
15669 if (wrapWithPreventDefault && result === false) {
15670 e.preventDefault();
15671 // Necessary for legacy browsers that don't support preventDefault (e.g. IE)
15672 e.returnValue = false;
15673 }
15674 return result;
15675 };
15676}
15677
15678/**
15679 * @license
15680 * Copyright Google LLC All Rights Reserved.
15681 *
15682 * Use of this source code is governed by an MIT-style license that can be
15683 * found in the LICENSE file at https://angular.io/license
15684 */
15685
15686/**
15687 * @license
15688 * Copyright Google LLC All Rights Reserved.
15689 *
15690 * Use of this source code is governed by an MIT-style license that can be
15691 * found in the LICENSE file at https://angular.io/license
15692 */
15693/**
15694 * Retrieves a context at the level specified and saves it as the global, contextViewData.
15695 * Will get the next level up if level is not specified.
15696 *
15697 * This is used to save contexts of parent views so they can be bound in embedded views, or
15698 * in conjunction with reference() to bind a ref from a parent view.
15699 *
15700 * @param level The relative level of the view from which to grab context compared to contextVewData
15701 * @returns context
15702 *
15703 * @codeGenApi
15704 */
15705function ɵɵnextContext(level = 1) {
15706 return nextContextImpl(level);
15707}
15708
15709/**
15710 * @license
15711 * Copyright Google LLC All Rights Reserved.
15712 *
15713 * Use of this source code is governed by an MIT-style license that can be
15714 * found in the LICENSE file at https://angular.io/license
15715 */
15716/**
15717 * Checks a given node against matching projection slots and returns the
15718 * determined slot index. Returns "null" if no slot matched the given node.
15719 *
15720 * This function takes into account the parsed ngProjectAs selector from the
15721 * node's attributes. If present, it will check whether the ngProjectAs selector
15722 * matches any of the projection slot selectors.
15723 */
15724function matchingProjectionSlotIndex(tNode, projectionSlots) {
15725 let wildcardNgContentIndex = null;
15726 const ngProjectAsAttrVal = getProjectAsAttrValue(tNode);
15727 for (let i = 0; i < projectionSlots.length; i++) {
15728 const slotValue = projectionSlots[i];
15729 // The last wildcard projection slot should match all nodes which aren't matching
15730 // any selector. This is necessary to be backwards compatible with view engine.
15731 if (slotValue === '*') {
15732 wildcardNgContentIndex = i;
15733 continue;
15734 }
15735 // If we ran into an `ngProjectAs` attribute, we should match its parsed selector
15736 // to the list of selectors, otherwise we fall back to matching against the node.
15737 if (ngProjectAsAttrVal === null ?
15738 isNodeMatchingSelectorList(tNode, slotValue, /* isProjectionMode */ true) :
15739 isSelectorInSelectorList(ngProjectAsAttrVal, slotValue)) {
15740 return i; // first matching selector "captures" a given node
15741 }
15742 }
15743 return wildcardNgContentIndex;
15744}
15745/**
15746 * Instruction to distribute projectable nodes among <ng-content> occurrences in a given template.
15747 * It takes all the selectors from the entire component's template and decides where
15748 * each projected node belongs (it re-distributes nodes among "buckets" where each "bucket" is
15749 * backed by a selector).
15750 *
15751 * This function requires CSS selectors to be provided in 2 forms: parsed (by a compiler) and text,
15752 * un-parsed form.
15753 *
15754 * The parsed form is needed for efficient matching of a node against a given CSS selector.
15755 * The un-parsed, textual form is needed for support of the ngProjectAs attribute.
15756 *
15757 * Having a CSS selector in 2 different formats is not ideal, but alternatives have even more
15758 * drawbacks:
15759 * - having only a textual form would require runtime parsing of CSS selectors;
15760 * - we can't have only a parsed as we can't re-construct textual form from it (as entered by a
15761 * template author).
15762 *
15763 * @param projectionSlots? A collection of projection slots. A projection slot can be based
15764 * on a parsed CSS selectors or set to the wildcard selector ("*") in order to match
15765 * all nodes which do not match any selector. If not specified, a single wildcard
15766 * selector projection slot will be defined.
15767 *
15768 * @codeGenApi
15769 */
15770function ɵɵprojectionDef(projectionSlots) {
15771 const componentNode = getLView()[DECLARATION_COMPONENT_VIEW][T_HOST];
15772 if (!componentNode.projection) {
15773 // If no explicit projection slots are defined, fall back to a single
15774 // projection slot with the wildcard selector.
15775 const numProjectionSlots = projectionSlots ? projectionSlots.length : 1;
15776 const projectionHeads = componentNode.projection =
15777 newArray(numProjectionSlots, null);
15778 const tails = projectionHeads.slice();
15779 let componentChild = componentNode.child;
15780 while (componentChild !== null) {
15781 const slotIndex = projectionSlots ? matchingProjectionSlotIndex(componentChild, projectionSlots) : 0;
15782 if (slotIndex !== null) {
15783 if (tails[slotIndex]) {
15784 tails[slotIndex].projectionNext = componentChild;
15785 }
15786 else {
15787 projectionHeads[slotIndex] = componentChild;
15788 }
15789 tails[slotIndex] = componentChild;
15790 }
15791 componentChild = componentChild.next;
15792 }
15793 }
15794}
15795/**
15796 * Inserts previously re-distributed projected nodes. This instruction must be preceded by a call
15797 * to the projectionDef instruction.
15798 *
15799 * @param nodeIndex
15800 * @param selectorIndex:
15801 * - 0 when the selector is `*` (or unspecified as this is the default value),
15802 * - 1 based index of the selector from the {@link projectionDef}
15803 *
15804 * @codeGenApi
15805 */
15806function ɵɵprojection(nodeIndex, selectorIndex = 0, attrs) {
15807 const lView = getLView();
15808 const tView = getTView();
15809 const tProjectionNode = getOrCreateTNode(tView, HEADER_OFFSET + nodeIndex, 16 /* TNodeType.Projection */, null, attrs || null);
15810 // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views.
15811 if (tProjectionNode.projection === null)
15812 tProjectionNode.projection = selectorIndex;
15813 // `<ng-content>` has no content
15814 setCurrentTNodeAsNotParent();
15815 if ((tProjectionNode.flags & 64 /* TNodeFlags.isDetached */) !== 64 /* TNodeFlags.isDetached */) {
15816 // re-distribution of projectable nodes is stored on a component's view level
15817 applyProjection(tView, lView, tProjectionNode);
15818 }
15819}
15820
15821/**
15822 *
15823 * Update an interpolated property on an element with a lone bound value
15824 *
15825 * Used when the value passed to a property has 1 interpolated value in it, an no additional text
15826 * surrounds that interpolated value:
15827 *
15828 * ```html
15829 * <div title="{{v0}}"></div>
15830 * ```
15831 *
15832 * Its compiled representation is::
15833 *
15834 * ```ts
15835 * ɵɵpropertyInterpolate('title', v0);
15836 * ```
15837 *
15838 * If the property name also exists as an input property on one of the element's directives,
15839 * the component property will be set instead of the element property. This check must
15840 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15841 *
15842 * @param propName The name of the property to update
15843 * @param prefix Static value used for concatenation only.
15844 * @param v0 Value checked for change.
15845 * @param suffix Static value used for concatenation only.
15846 * @param sanitizer An optional sanitizer function
15847 * @returns itself, so that it may be chained.
15848 * @codeGenApi
15849 */
15850function ɵɵpropertyInterpolate(propName, v0, sanitizer) {
15851 ɵɵpropertyInterpolate1(propName, '', v0, '', sanitizer);
15852 return ɵɵpropertyInterpolate;
15853}
15854/**
15855 *
15856 * Update an interpolated property on an element with single bound value surrounded by text.
15857 *
15858 * Used when the value passed to a property has 1 interpolated value in it:
15859 *
15860 * ```html
15861 * <div title="prefix{{v0}}suffix"></div>
15862 * ```
15863 *
15864 * Its compiled representation is::
15865 *
15866 * ```ts
15867 * ɵɵpropertyInterpolate1('title', 'prefix', v0, 'suffix');
15868 * ```
15869 *
15870 * If the property name also exists as an input property on one of the element's directives,
15871 * the component property will be set instead of the element property. This check must
15872 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15873 *
15874 * @param propName The name of the property to update
15875 * @param prefix Static value used for concatenation only.
15876 * @param v0 Value checked for change.
15877 * @param suffix Static value used for concatenation only.
15878 * @param sanitizer An optional sanitizer function
15879 * @returns itself, so that it may be chained.
15880 * @codeGenApi
15881 */
15882function ɵɵpropertyInterpolate1(propName, prefix, v0, suffix, sanitizer) {
15883 const lView = getLView();
15884 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
15885 if (interpolatedValue !== NO_CHANGE) {
15886 const tView = getTView();
15887 const tNode = getSelectedTNode();
15888 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15889 ngDevMode &&
15890 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 1, prefix, suffix);
15891 }
15892 return ɵɵpropertyInterpolate1;
15893}
15894/**
15895 *
15896 * Update an interpolated property on an element with 2 bound values surrounded by text.
15897 *
15898 * Used when the value passed to a property has 2 interpolated values in it:
15899 *
15900 * ```html
15901 * <div title="prefix{{v0}}-{{v1}}suffix"></div>
15902 * ```
15903 *
15904 * Its compiled representation is::
15905 *
15906 * ```ts
15907 * ɵɵpropertyInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
15908 * ```
15909 *
15910 * If the property name also exists as an input property on one of the element's directives,
15911 * the component property will be set instead of the element property. This check must
15912 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15913 *
15914 * @param propName The name of the property to update
15915 * @param prefix Static value used for concatenation only.
15916 * @param v0 Value checked for change.
15917 * @param i0 Static value used for concatenation only.
15918 * @param v1 Value checked for change.
15919 * @param suffix Static value used for concatenation only.
15920 * @param sanitizer An optional sanitizer function
15921 * @returns itself, so that it may be chained.
15922 * @codeGenApi
15923 */
15924function ɵɵpropertyInterpolate2(propName, prefix, v0, i0, v1, suffix, sanitizer) {
15925 const lView = getLView();
15926 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
15927 if (interpolatedValue !== NO_CHANGE) {
15928 const tView = getTView();
15929 const tNode = getSelectedTNode();
15930 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15931 ngDevMode &&
15932 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 2, prefix, i0, suffix);
15933 }
15934 return ɵɵpropertyInterpolate2;
15935}
15936/**
15937 *
15938 * Update an interpolated property on an element with 3 bound values surrounded by text.
15939 *
15940 * Used when the value passed to a property has 3 interpolated values in it:
15941 *
15942 * ```html
15943 * <div title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
15944 * ```
15945 *
15946 * Its compiled representation is::
15947 *
15948 * ```ts
15949 * ɵɵpropertyInterpolate3(
15950 * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
15951 * ```
15952 *
15953 * If the property name also exists as an input property on one of the element's directives,
15954 * the component property will be set instead of the element property. This check must
15955 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15956 *
15957 * @param propName The name of the property to update
15958 * @param prefix Static value used for concatenation only.
15959 * @param v0 Value checked for change.
15960 * @param i0 Static value used for concatenation only.
15961 * @param v1 Value checked for change.
15962 * @param i1 Static value used for concatenation only.
15963 * @param v2 Value checked for change.
15964 * @param suffix Static value used for concatenation only.
15965 * @param sanitizer An optional sanitizer function
15966 * @returns itself, so that it may be chained.
15967 * @codeGenApi
15968 */
15969function ɵɵpropertyInterpolate3(propName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer) {
15970 const lView = getLView();
15971 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
15972 if (interpolatedValue !== NO_CHANGE) {
15973 const tView = getTView();
15974 const tNode = getSelectedTNode();
15975 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15976 ngDevMode &&
15977 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 3, prefix, i0, i1, suffix);
15978 }
15979 return ɵɵpropertyInterpolate3;
15980}
15981/**
15982 *
15983 * Update an interpolated property on an element with 4 bound values surrounded by text.
15984 *
15985 * Used when the value passed to a property has 4 interpolated values in it:
15986 *
15987 * ```html
15988 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
15989 * ```
15990 *
15991 * Its compiled representation is::
15992 *
15993 * ```ts
15994 * ɵɵpropertyInterpolate4(
15995 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
15996 * ```
15997 *
15998 * If the property name also exists as an input property on one of the element's directives,
15999 * the component property will be set instead of the element property. This check must
16000 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
16001 *
16002 * @param propName The name of the property to update
16003 * @param prefix Static value used for concatenation only.
16004 * @param v0 Value checked for change.
16005 * @param i0 Static value used for concatenation only.
16006 * @param v1 Value checked for change.
16007 * @param i1 Static value used for concatenation only.
16008 * @param v2 Value checked for change.
16009 * @param i2 Static value used for concatenation only.
16010 * @param v3 Value checked for change.
16011 * @param suffix Static value used for concatenation only.
16012 * @param sanitizer An optional sanitizer function
16013 * @returns itself, so that it may be chained.
16014 * @codeGenApi
16015 */
16016function ɵɵpropertyInterpolate4(propName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer) {
16017 const lView = getLView();
16018 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
16019 if (interpolatedValue !== NO_CHANGE) {
16020 const tView = getTView();
16021 const tNode = getSelectedTNode();
16022 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
16023 ngDevMode &&
16024 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix);
16025 }
16026 return ɵɵpropertyInterpolate4;
16027}
16028/**
16029 *
16030 * Update an interpolated property on an element with 5 bound values surrounded by text.
16031 *
16032 * Used when the value passed to a property has 5 interpolated values in it:
16033 *
16034 * ```html
16035 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
16036 * ```
16037 *
16038 * Its compiled representation is::
16039 *
16040 * ```ts
16041 * ɵɵpropertyInterpolate5(
16042 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
16043 * ```
16044 *
16045 * If the property name also exists as an input property on one of the element's directives,
16046 * the component property will be set instead of the element property. This check must
16047 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
16048 *
16049 * @param propName The name of the property to update
16050 * @param prefix Static value used for concatenation only.
16051 * @param v0 Value checked for change.
16052 * @param i0 Static value used for concatenation only.
16053 * @param v1 Value checked for change.
16054 * @param i1 Static value used for concatenation only.
16055 * @param v2 Value checked for change.
16056 * @param i2 Static value used for concatenation only.
16057 * @param v3 Value checked for change.
16058 * @param i3 Static value used for concatenation only.
16059 * @param v4 Value checked for change.
16060 * @param suffix Static value used for concatenation only.
16061 * @param sanitizer An optional sanitizer function
16062 * @returns itself, so that it may be chained.
16063 * @codeGenApi
16064 */
16065function ɵɵpropertyInterpolate5(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer) {
16066 const lView = getLView();
16067 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
16068 if (interpolatedValue !== NO_CHANGE) {
16069 const tView = getTView();
16070 const tNode = getSelectedTNode();
16071 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
16072 ngDevMode &&
16073 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix);
16074 }
16075 return ɵɵpropertyInterpolate5;
16076}
16077/**
16078 *
16079 * Update an interpolated property on an element with 6 bound values surrounded by text.
16080 *
16081 * Used when the value passed to a property has 6 interpolated values in it:
16082 *
16083 * ```html
16084 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
16085 * ```
16086 *
16087 * Its compiled representation is::
16088 *
16089 * ```ts
16090 * ɵɵpropertyInterpolate6(
16091 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
16092 * ```
16093 *
16094 * If the property name also exists as an input property on one of the element's directives,
16095 * the component property will be set instead of the element property. This check must
16096 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
16097 *
16098 * @param propName The name of the property to update
16099 * @param prefix Static value used for concatenation only.
16100 * @param v0 Value checked for change.
16101 * @param i0 Static value used for concatenation only.
16102 * @param v1 Value checked for change.
16103 * @param i1 Static value used for concatenation only.
16104 * @param v2 Value checked for change.
16105 * @param i2 Static value used for concatenation only.
16106 * @param v3 Value checked for change.
16107 * @param i3 Static value used for concatenation only.
16108 * @param v4 Value checked for change.
16109 * @param i4 Static value used for concatenation only.
16110 * @param v5 Value checked for change.
16111 * @param suffix Static value used for concatenation only.
16112 * @param sanitizer An optional sanitizer function
16113 * @returns itself, so that it may be chained.
16114 * @codeGenApi
16115 */
16116function ɵɵpropertyInterpolate6(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer) {
16117 const lView = getLView();
16118 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
16119 if (interpolatedValue !== NO_CHANGE) {
16120 const tView = getTView();
16121 const tNode = getSelectedTNode();
16122 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
16123 ngDevMode &&
16124 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, i4, suffix);
16125 }
16126 return ɵɵpropertyInterpolate6;
16127}
16128/**
16129 *
16130 * Update an interpolated property on an element with 7 bound values surrounded by text.
16131 *
16132 * Used when the value passed to a property has 7 interpolated values in it:
16133 *
16134 * ```html
16135 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
16136 * ```
16137 *
16138 * Its compiled representation is::
16139 *
16140 * ```ts
16141 * ɵɵpropertyInterpolate7(
16142 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
16143 * ```
16144 *
16145 * If the property name also exists as an input property on one of the element's directives,
16146 * the component property will be set instead of the element property. This check must
16147 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
16148 *
16149 * @param propName The name of the property to update
16150 * @param prefix Static value used for concatenation only.
16151 * @param v0 Value checked for change.
16152 * @param i0 Static value used for concatenation only.
16153 * @param v1 Value checked for change.
16154 * @param i1 Static value used for concatenation only.
16155 * @param v2 Value checked for change.
16156 * @param i2 Static value used for concatenation only.
16157 * @param v3 Value checked for change.
16158 * @param i3 Static value used for concatenation only.
16159 * @param v4 Value checked for change.
16160 * @param i4 Static value used for concatenation only.
16161 * @param v5 Value checked for change.
16162 * @param i5 Static value used for concatenation only.
16163 * @param v6 Value checked for change.
16164 * @param suffix Static value used for concatenation only.
16165 * @param sanitizer An optional sanitizer function
16166 * @returns itself, so that it may be chained.
16167 * @codeGenApi
16168 */
16169function ɵɵpropertyInterpolate7(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer) {
16170 const lView = getLView();
16171 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
16172 if (interpolatedValue !== NO_CHANGE) {
16173 const tView = getTView();
16174 const tNode = getSelectedTNode();
16175 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
16176 ngDevMode &&
16177 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, suffix);
16178 }
16179 return ɵɵpropertyInterpolate7;
16180}
16181/**
16182 *
16183 * Update an interpolated property on an element with 8 bound values surrounded by text.
16184 *
16185 * Used when the value passed to a property has 8 interpolated values in it:
16186 *
16187 * ```html
16188 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
16189 * ```
16190 *
16191 * Its compiled representation is::
16192 *
16193 * ```ts
16194 * ɵɵpropertyInterpolate8(
16195 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
16196 * ```
16197 *
16198 * If the property name also exists as an input property on one of the element's directives,
16199 * the component property will be set instead of the element property. This check must
16200 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
16201 *
16202 * @param propName The name of the property to update
16203 * @param prefix Static value used for concatenation only.
16204 * @param v0 Value checked for change.
16205 * @param i0 Static value used for concatenation only.
16206 * @param v1 Value checked for change.
16207 * @param i1 Static value used for concatenation only.
16208 * @param v2 Value checked for change.
16209 * @param i2 Static value used for concatenation only.
16210 * @param v3 Value checked for change.
16211 * @param i3 Static value used for concatenation only.
16212 * @param v4 Value checked for change.
16213 * @param i4 Static value used for concatenation only.
16214 * @param v5 Value checked for change.
16215 * @param i5 Static value used for concatenation only.
16216 * @param v6 Value checked for change.
16217 * @param i6 Static value used for concatenation only.
16218 * @param v7 Value checked for change.
16219 * @param suffix Static value used for concatenation only.
16220 * @param sanitizer An optional sanitizer function
16221 * @returns itself, so that it may be chained.
16222 * @codeGenApi
16223 */
16224function ɵɵpropertyInterpolate8(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer) {
16225 const lView = getLView();
16226 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
16227 if (interpolatedValue !== NO_CHANGE) {
16228 const tView = getTView();
16229 const tNode = getSelectedTNode();
16230 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
16231 ngDevMode &&
16232 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, suffix);
16233 }
16234 return ɵɵpropertyInterpolate8;
16235}
16236/**
16237 * Update an interpolated property on an element with 9 or more bound values surrounded by text.
16238 *
16239 * Used when the number of interpolated values exceeds 8.
16240 *
16241 * ```html
16242 * <div
16243 * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
16244 * ```
16245 *
16246 * Its compiled representation is::
16247 *
16248 * ```ts
16249 * ɵɵpropertyInterpolateV(
16250 * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
16251 * 'suffix']);
16252 * ```
16253 *
16254 * If the property name also exists as an input property on one of the element's directives,
16255 * the component property will be set instead of the element property. This check must
16256 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
16257 *
16258 * @param propName The name of the property to update.
16259 * @param values The collection of values and the strings inbetween those values, beginning with a
16260 * string prefix and ending with a string suffix.
16261 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
16262 * @param sanitizer An optional sanitizer function
16263 * @returns itself, so that it may be chained.
16264 * @codeGenApi
16265 */
16266function ɵɵpropertyInterpolateV(propName, values, sanitizer) {
16267 const lView = getLView();
16268 const interpolatedValue = interpolationV(lView, values);
16269 if (interpolatedValue !== NO_CHANGE) {
16270 const tView = getTView();
16271 const tNode = getSelectedTNode();
16272 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
16273 if (ngDevMode) {
16274 const interpolationInBetween = [values[0]]; // prefix
16275 for (let i = 2; i < values.length; i += 2) {
16276 interpolationInBetween.push(values[i]);
16277 }
16278 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
16279 }
16280 }
16281 return ɵɵpropertyInterpolateV;
16282}
16283
16284/**
16285 * @license
16286 * Copyright Google LLC All Rights Reserved.
16287 *
16288 * Use of this source code is governed by an MIT-style license that can be
16289 * found in the LICENSE file at https://angular.io/license
16290 */
16291/**
16292 * NOTE: The word `styling` is used interchangeably as style or class styling.
16293 *
16294 * This file contains code to link styling instructions together so that they can be replayed in
16295 * priority order. The file exists because Ivy styling instruction execution order does not match
16296 * that of the priority order. The purpose of this code is to create a linked list so that the
16297 * instructions can be traversed in priority order when computing the styles.
16298 *
16299 * Assume we are dealing with the following code:
16300 * ```
16301 * @Component({
16302 * template: `
16303 * <my-cmp [style]=" {color: '#001'} "
16304 * [style.color]=" #002 "
16305 * dir-style-color-1
16306 * dir-style-color-2> `
16307 * })
16308 * class ExampleComponent {
16309 * static ngComp = ... {
16310 * ...
16311 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
16312 * ɵɵstyleMap({color: '#001'});
16313 * ɵɵstyleProp('color', '#002');
16314 * ...
16315 * }
16316 * }
16317 *
16318 * @Directive({
16319 * selector: `[dir-style-color-1]',
16320 * })
16321 * class Style1Directive {
16322 * @HostBinding('style') style = {color: '#005'};
16323 * @HostBinding('style.color') color = '#006';
16324 *
16325 * static ngDir = ... {
16326 * ...
16327 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
16328 * ɵɵstyleMap({color: '#005'});
16329 * ɵɵstyleProp('color', '#006');
16330 * ...
16331 * }
16332 * }
16333 *
16334 * @Directive({
16335 * selector: `[dir-style-color-2]',
16336 * })
16337 * class Style2Directive {
16338 * @HostBinding('style') style = {color: '#007'};
16339 * @HostBinding('style.color') color = '#008';
16340 *
16341 * static ngDir = ... {
16342 * ...
16343 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
16344 * ɵɵstyleMap({color: '#007'});
16345 * ɵɵstyleProp('color', '#008');
16346 * ...
16347 * }
16348 * }
16349 *
16350 * @Directive({
16351 * selector: `my-cmp',
16352 * })
16353 * class MyComponent {
16354 * @HostBinding('style') style = {color: '#003'};
16355 * @HostBinding('style.color') color = '#004';
16356 *
16357 * static ngComp = ... {
16358 * ...
16359 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
16360 * ɵɵstyleMap({color: '#003'});
16361 * ɵɵstyleProp('color', '#004');
16362 * ...
16363 * }
16364 * }
16365 * ```
16366 *
16367 * The Order of instruction execution is:
16368 *
16369 * NOTE: the comment binding location is for illustrative purposes only.
16370 *
16371 * ```
16372 * // Template: (ExampleComponent)
16373 * ɵɵstyleMap({color: '#001'}); // Binding index: 10
16374 * ɵɵstyleProp('color', '#002'); // Binding index: 12
16375 * // MyComponent
16376 * ɵɵstyleMap({color: '#003'}); // Binding index: 20
16377 * ɵɵstyleProp('color', '#004'); // Binding index: 22
16378 * // Style1Directive
16379 * ɵɵstyleMap({color: '#005'}); // Binding index: 24
16380 * ɵɵstyleProp('color', '#006'); // Binding index: 26
16381 * // Style2Directive
16382 * ɵɵstyleMap({color: '#007'}); // Binding index: 28
16383 * ɵɵstyleProp('color', '#008'); // Binding index: 30
16384 * ```
16385 *
16386 * The correct priority order of concatenation is:
16387 *
16388 * ```
16389 * // MyComponent
16390 * ɵɵstyleMap({color: '#003'}); // Binding index: 20
16391 * ɵɵstyleProp('color', '#004'); // Binding index: 22
16392 * // Style1Directive
16393 * ɵɵstyleMap({color: '#005'}); // Binding index: 24
16394 * ɵɵstyleProp('color', '#006'); // Binding index: 26
16395 * // Style2Directive
16396 * ɵɵstyleMap({color: '#007'}); // Binding index: 28
16397 * ɵɵstyleProp('color', '#008'); // Binding index: 30
16398 * // Template: (ExampleComponent)
16399 * ɵɵstyleMap({color: '#001'}); // Binding index: 10
16400 * ɵɵstyleProp('color', '#002'); // Binding index: 12
16401 * ```
16402 *
16403 * What color should be rendered?
16404 *
16405 * Once the items are correctly sorted in the list, the answer is simply the last item in the
16406 * concatenation list which is `#002`.
16407 *
16408 * To do so we keep a linked list of all of the bindings which pertain to this element.
16409 * Notice that the bindings are inserted in the order of execution, but the `TView.data` allows
16410 * us to traverse them in the order of priority.
16411 *
16412 * |Idx|`TView.data`|`LView` | Notes
16413 * |---|------------|-----------------|--------------
16414 * |...| | |
16415 * |10 |`null` |`{color: '#001'}`| `ɵɵstyleMap('color', {color: '#001'})`
16416 * |11 |`30 | 12` | ... |
16417 * |12 |`color` |`'#002'` | `ɵɵstyleProp('color', '#002')`
16418 * |13 |`10 | 0` | ... |
16419 * |...| | |
16420 * |20 |`null` |`{color: '#003'}`| `ɵɵstyleMap('color', {color: '#003'})`
16421 * |21 |`0 | 22` | ... |
16422 * |22 |`color` |`'#004'` | `ɵɵstyleProp('color', '#004')`
16423 * |23 |`20 | 24` | ... |
16424 * |24 |`null` |`{color: '#005'}`| `ɵɵstyleMap('color', {color: '#005'})`
16425 * |25 |`22 | 26` | ... |
16426 * |26 |`color` |`'#006'` | `ɵɵstyleProp('color', '#006')`
16427 * |27 |`24 | 28` | ... |
16428 * |28 |`null` |`{color: '#007'}`| `ɵɵstyleMap('color', {color: '#007'})`
16429 * |29 |`26 | 30` | ... |
16430 * |30 |`color` |`'#008'` | `ɵɵstyleProp('color', '#008')`
16431 * |31 |`28 | 10` | ... |
16432 *
16433 * The above data structure allows us to re-concatenate the styling no matter which data binding
16434 * changes.
16435 *
16436 * NOTE: in addition to keeping track of next/previous index the `TView.data` also stores prev/next
16437 * duplicate bit. The duplicate bit if true says there either is a binding with the same name or
16438 * there is a map (which may contain the name). This information is useful in knowing if other
16439 * styles with higher priority need to be searched for overwrites.
16440 *
16441 * NOTE: See `should support example in 'tnode_linked_list.ts' documentation` in
16442 * `tnode_linked_list_spec.ts` for working example.
16443 */
16444let __unused_const_as_closure_does_not_like_standalone_comment_blocks__;
16445/**
16446 * Insert new `tStyleValue` at `TData` and link existing style bindings such that we maintain linked
16447 * list of styles and compute the duplicate flag.
16448 *
16449 * Note: this function is executed during `firstUpdatePass` only to populate the `TView.data`.
16450 *
16451 * The function works by keeping track of `tStylingRange` which contains two pointers pointing to
16452 * the head/tail of the template portion of the styles.
16453 * - if `isHost === false` (we are template) then insertion is at tail of `TStylingRange`
16454 * - if `isHost === true` (we are host binding) then insertion is at head of `TStylingRange`
16455 *
16456 * @param tData The `TData` to insert into.
16457 * @param tNode `TNode` associated with the styling element.
16458 * @param tStylingKey See `TStylingKey`.
16459 * @param index location of where `tStyleValue` should be stored (and linked into list.)
16460 * @param isHostBinding `true` if the insertion is for a `hostBinding`. (insertion is in front of
16461 * template.)
16462 * @param isClassBinding True if the associated `tStylingKey` as a `class` styling.
16463 * `tNode.classBindings` should be used (or `tNode.styleBindings` otherwise.)
16464 */
16465function insertTStylingBinding(tData, tNode, tStylingKeyWithStatic, index, isHostBinding, isClassBinding) {
16466 ngDevMode && assertFirstUpdatePass(getTView());
16467 let tBindings = isClassBinding ? tNode.classBindings : tNode.styleBindings;
16468 let tmplHead = getTStylingRangePrev(tBindings);
16469 let tmplTail = getTStylingRangeNext(tBindings);
16470 tData[index] = tStylingKeyWithStatic;
16471 let isKeyDuplicateOfStatic = false;
16472 let tStylingKey;
16473 if (Array.isArray(tStylingKeyWithStatic)) {
16474 // We are case when the `TStylingKey` contains static fields as well.
16475 const staticKeyValueArray = tStylingKeyWithStatic;
16476 tStylingKey = staticKeyValueArray[1]; // unwrap.
16477 // We need to check if our key is present in the static so that we can mark it as duplicate.
16478 if (tStylingKey === null ||
16479 keyValueArrayIndexOf(staticKeyValueArray, tStylingKey) > 0) {
16480 // tStylingKey is present in the statics, need to mark it as duplicate.
16481 isKeyDuplicateOfStatic = true;
16482 }
16483 }
16484 else {
16485 tStylingKey = tStylingKeyWithStatic;
16486 }
16487 if (isHostBinding) {
16488 // We are inserting host bindings
16489 // If we don't have template bindings then `tail` is 0.
16490 const hasTemplateBindings = tmplTail !== 0;
16491 // This is important to know because that means that the `head` can't point to the first
16492 // template bindings (there are none.) Instead the head points to the tail of the template.
16493 if (hasTemplateBindings) {
16494 // template head's "prev" will point to last host binding or to 0 if no host bindings yet
16495 const previousNode = getTStylingRangePrev(tData[tmplHead + 1]);
16496 tData[index + 1] = toTStylingRange(previousNode, tmplHead);
16497 // if a host binding has already been registered, we need to update the next of that host
16498 // binding to point to this one
16499 if (previousNode !== 0) {
16500 // We need to update the template-tail value to point to us.
16501 tData[previousNode + 1] =
16502 setTStylingRangeNext(tData[previousNode + 1], index);
16503 }
16504 // The "previous" of the template binding head should point to this host binding
16505 tData[tmplHead + 1] = setTStylingRangePrev(tData[tmplHead + 1], index);
16506 }
16507 else {
16508 tData[index + 1] = toTStylingRange(tmplHead, 0);
16509 // if a host binding has already been registered, we need to update the next of that host
16510 // binding to point to this one
16511 if (tmplHead !== 0) {
16512 // We need to update the template-tail value to point to us.
16513 tData[tmplHead + 1] = setTStylingRangeNext(tData[tmplHead + 1], index);
16514 }
16515 // if we don't have template, the head points to template-tail, and needs to be advanced.
16516 tmplHead = index;
16517 }
16518 }
16519 else {
16520 // We are inserting in template section.
16521 // We need to set this binding's "previous" to the current template tail
16522 tData[index + 1] = toTStylingRange(tmplTail, 0);
16523 ngDevMode &&
16524 assertEqual(tmplHead !== 0 && tmplTail === 0, false, 'Adding template bindings after hostBindings is not allowed.');
16525 if (tmplHead === 0) {
16526 tmplHead = index;
16527 }
16528 else {
16529 // We need to update the previous value "next" to point to this binding
16530 tData[tmplTail + 1] = setTStylingRangeNext(tData[tmplTail + 1], index);
16531 }
16532 tmplTail = index;
16533 }
16534 // Now we need to update / compute the duplicates.
16535 // Starting with our location search towards head (least priority)
16536 if (isKeyDuplicateOfStatic) {
16537 tData[index + 1] = setTStylingRangePrevDuplicate(tData[index + 1]);
16538 }
16539 markDuplicates(tData, tStylingKey, index, true, isClassBinding);
16540 markDuplicates(tData, tStylingKey, index, false, isClassBinding);
16541 markDuplicateOfResidualStyling(tNode, tStylingKey, tData, index, isClassBinding);
16542 tBindings = toTStylingRange(tmplHead, tmplTail);
16543 if (isClassBinding) {
16544 tNode.classBindings = tBindings;
16545 }
16546 else {
16547 tNode.styleBindings = tBindings;
16548 }
16549}
16550/**
16551 * Look into the residual styling to see if the current `tStylingKey` is duplicate of residual.
16552 *
16553 * @param tNode `TNode` where the residual is stored.
16554 * @param tStylingKey `TStylingKey` to store.
16555 * @param tData `TData` associated with the current `LView`.
16556 * @param index location of where `tStyleValue` should be stored (and linked into list.)
16557 * @param isClassBinding True if the associated `tStylingKey` as a `class` styling.
16558 * `tNode.classBindings` should be used (or `tNode.styleBindings` otherwise.)
16559 */
16560function markDuplicateOfResidualStyling(tNode, tStylingKey, tData, index, isClassBinding) {
16561 const residual = isClassBinding ? tNode.residualClasses : tNode.residualStyles;
16562 if (residual != null /* or undefined */ && typeof tStylingKey == 'string' &&
16563 keyValueArrayIndexOf(residual, tStylingKey) >= 0) {
16564 // We have duplicate in the residual so mark ourselves as duplicate.
16565 tData[index + 1] = setTStylingRangeNextDuplicate(tData[index + 1]);
16566 }
16567}
16568/**
16569 * Marks `TStyleValue`s as duplicates if another style binding in the list has the same
16570 * `TStyleValue`.
16571 *
16572 * NOTE: this function is intended to be called twice once with `isPrevDir` set to `true` and once
16573 * with it set to `false` to search both the previous as well as next items in the list.
16574 *
16575 * No duplicate case
16576 * ```
16577 * [style.color]
16578 * [style.width.px] <<- index
16579 * [style.height.px]
16580 * ```
16581 *
16582 * In the above case adding `[style.width.px]` to the existing `[style.color]` produces no
16583 * duplicates because `width` is not found in any other part of the linked list.
16584 *
16585 * Duplicate case
16586 * ```
16587 * [style.color]
16588 * [style.width.em]
16589 * [style.width.px] <<- index
16590 * ```
16591 * In the above case adding `[style.width.px]` will produce a duplicate with `[style.width.em]`
16592 * because `width` is found in the chain.
16593 *
16594 * Map case 1
16595 * ```
16596 * [style.width.px]
16597 * [style.color]
16598 * [style] <<- index
16599 * ```
16600 * In the above case adding `[style]` will produce a duplicate with any other bindings because
16601 * `[style]` is a Map and as such is fully dynamic and could produce `color` or `width`.
16602 *
16603 * Map case 2
16604 * ```
16605 * [style]
16606 * [style.width.px]
16607 * [style.color] <<- index
16608 * ```
16609 * In the above case adding `[style.color]` will produce a duplicate because there is already a
16610 * `[style]` binding which is a Map and as such is fully dynamic and could produce `color` or
16611 * `width`.
16612 *
16613 * NOTE: Once `[style]` (Map) is added into the system all things are mapped as duplicates.
16614 * NOTE: We use `style` as example, but same logic is applied to `class`es as well.
16615 *
16616 * @param tData `TData` where the linked list is stored.
16617 * @param tStylingKey `TStylingKeyPrimitive` which contains the value to compare to other keys in
16618 * the linked list.
16619 * @param index Starting location in the linked list to search from
16620 * @param isPrevDir Direction.
16621 * - `true` for previous (lower priority);
16622 * - `false` for next (higher priority).
16623 */
16624function markDuplicates(tData, tStylingKey, index, isPrevDir, isClassBinding) {
16625 const tStylingAtIndex = tData[index + 1];
16626 const isMap = tStylingKey === null;
16627 let cursor = isPrevDir ? getTStylingRangePrev(tStylingAtIndex) : getTStylingRangeNext(tStylingAtIndex);
16628 let foundDuplicate = false;
16629 // We keep iterating as long as we have a cursor
16630 // AND either:
16631 // - we found what we are looking for, OR
16632 // - we are a map in which case we have to continue searching even after we find what we were
16633 // looking for since we are a wild card and everything needs to be flipped to duplicate.
16634 while (cursor !== 0 && (foundDuplicate === false || isMap)) {
16635 ngDevMode && assertIndexInRange(tData, cursor);
16636 const tStylingValueAtCursor = tData[cursor];
16637 const tStyleRangeAtCursor = tData[cursor + 1];
16638 if (isStylingMatch(tStylingValueAtCursor, tStylingKey)) {
16639 foundDuplicate = true;
16640 tData[cursor + 1] = isPrevDir ? setTStylingRangeNextDuplicate(tStyleRangeAtCursor) :
16641 setTStylingRangePrevDuplicate(tStyleRangeAtCursor);
16642 }
16643 cursor = isPrevDir ? getTStylingRangePrev(tStyleRangeAtCursor) :
16644 getTStylingRangeNext(tStyleRangeAtCursor);
16645 }
16646 if (foundDuplicate) {
16647 // if we found a duplicate, than mark ourselves.
16648 tData[index + 1] = isPrevDir ? setTStylingRangePrevDuplicate(tStylingAtIndex) :
16649 setTStylingRangeNextDuplicate(tStylingAtIndex);
16650 }
16651}
16652/**
16653 * Determines if two `TStylingKey`s are a match.
16654 *
16655 * When computing whether a binding contains a duplicate, we need to compare if the instruction
16656 * `TStylingKey` has a match.
16657 *
16658 * Here are examples of `TStylingKey`s which match given `tStylingKeyCursor` is:
16659 * - `color`
16660 * - `color` // Match another color
16661 * - `null` // That means that `tStylingKey` is a `classMap`/`styleMap` instruction
16662 * - `['', 'color', 'other', true]` // wrapped `color` so match
16663 * - `['', null, 'other', true]` // wrapped `null` so match
16664 * - `['', 'width', 'color', 'value']` // wrapped static value contains a match on `'color'`
16665 * - `null` // `tStylingKeyCursor` always match as it is `classMap`/`styleMap` instruction
16666 *
16667 * @param tStylingKeyCursor
16668 * @param tStylingKey
16669 */
16670function isStylingMatch(tStylingKeyCursor, tStylingKey) {
16671 ngDevMode &&
16672 assertNotEqual(Array.isArray(tStylingKey), true, 'Expected that \'tStylingKey\' has been unwrapped');
16673 if (tStylingKeyCursor === null || // If the cursor is `null` it means that we have map at that
16674 // location so we must assume that we have a match.
16675 tStylingKey == null || // If `tStylingKey` is `null` then it is a map therefor assume that it
16676 // contains a match.
16677 (Array.isArray(tStylingKeyCursor) ? tStylingKeyCursor[1] : tStylingKeyCursor) ===
16678 tStylingKey // If the keys match explicitly than we are a match.
16679 ) {
16680 return true;
16681 }
16682 else if (Array.isArray(tStylingKeyCursor) && typeof tStylingKey === 'string') {
16683 // if we did not find a match, but `tStylingKeyCursor` is `KeyValueArray` that means cursor has
16684 // statics and we need to check those as well.
16685 return keyValueArrayIndexOf(tStylingKeyCursor, tStylingKey) >=
16686 0; // see if we are matching the key
16687 }
16688 return false;
16689}
16690
16691/**
16692 * @license
16693 * Copyright Google LLC All Rights Reserved.
16694 *
16695 * Use of this source code is governed by an MIT-style license that can be
16696 * found in the LICENSE file at https://angular.io/license
16697 */
16698// Global state of the parser. (This makes parser non-reentrant, but that is not an issue)
16699const parserState = {
16700 textEnd: 0,
16701 key: 0,
16702 keyEnd: 0,
16703 value: 0,
16704 valueEnd: 0,
16705};
16706/**
16707 * Retrieves the last parsed `key` of style.
16708 * @param text the text to substring the key from.
16709 */
16710function getLastParsedKey(text) {
16711 return text.substring(parserState.key, parserState.keyEnd);
16712}
16713/**
16714 * Retrieves the last parsed `value` of style.
16715 * @param text the text to substring the key from.
16716 */
16717function getLastParsedValue(text) {
16718 return text.substring(parserState.value, parserState.valueEnd);
16719}
16720/**
16721 * Initializes `className` string for parsing and parses the first token.
16722 *
16723 * This function is intended to be used in this format:
16724 * ```
16725 * for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) {
16726 * const key = getLastParsedKey();
16727 * ...
16728 * }
16729 * ```
16730 * @param text `className` to parse
16731 * @returns index where the next invocation of `parseClassNameNext` should resume.
16732 */
16733function parseClassName(text) {
16734 resetParserState(text);
16735 return parseClassNameNext(text, consumeWhitespace(text, 0, parserState.textEnd));
16736}
16737/**
16738 * Parses next `className` token.
16739 *
16740 * This function is intended to be used in this format:
16741 * ```
16742 * for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) {
16743 * const key = getLastParsedKey();
16744 * ...
16745 * }
16746 * ```
16747 *
16748 * @param text `className` to parse
16749 * @param index where the parsing should resume.
16750 * @returns index where the next invocation of `parseClassNameNext` should resume.
16751 */
16752function parseClassNameNext(text, index) {
16753 const end = parserState.textEnd;
16754 if (end === index) {
16755 return -1;
16756 }
16757 index = parserState.keyEnd = consumeClassToken(text, parserState.key = index, end);
16758 return consumeWhitespace(text, index, end);
16759}
16760/**
16761 * Initializes `cssText` string for parsing and parses the first key/values.
16762 *
16763 * This function is intended to be used in this format:
16764 * ```
16765 * for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i))) {
16766 * const key = getLastParsedKey();
16767 * const value = getLastParsedValue();
16768 * ...
16769 * }
16770 * ```
16771 * @param text `cssText` to parse
16772 * @returns index where the next invocation of `parseStyleNext` should resume.
16773 */
16774function parseStyle(text) {
16775 resetParserState(text);
16776 return parseStyleNext(text, consumeWhitespace(text, 0, parserState.textEnd));
16777}
16778/**
16779 * Parses the next `cssText` key/values.
16780 *
16781 * This function is intended to be used in this format:
16782 * ```
16783 * for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i))) {
16784 * const key = getLastParsedKey();
16785 * const value = getLastParsedValue();
16786 * ...
16787 * }
16788 *
16789 * @param text `cssText` to parse
16790 * @param index where the parsing should resume.
16791 * @returns index where the next invocation of `parseStyleNext` should resume.
16792 */
16793function parseStyleNext(text, startIndex) {
16794 const end = parserState.textEnd;
16795 let index = parserState.key = consumeWhitespace(text, startIndex, end);
16796 if (end === index) {
16797 // we reached an end so just quit
16798 return -1;
16799 }
16800 index = parserState.keyEnd = consumeStyleKey(text, index, end);
16801 index = consumeSeparator(text, index, end, 58 /* CharCode.COLON */);
16802 index = parserState.value = consumeWhitespace(text, index, end);
16803 index = parserState.valueEnd = consumeStyleValue(text, index, end);
16804 return consumeSeparator(text, index, end, 59 /* CharCode.SEMI_COLON */);
16805}
16806/**
16807 * Reset the global state of the styling parser.
16808 * @param text The styling text to parse.
16809 */
16810function resetParserState(text) {
16811 parserState.key = 0;
16812 parserState.keyEnd = 0;
16813 parserState.value = 0;
16814 parserState.valueEnd = 0;
16815 parserState.textEnd = text.length;
16816}
16817/**
16818 * Returns index of next non-whitespace character.
16819 *
16820 * @param text Text to scan
16821 * @param startIndex Starting index of character where the scan should start.
16822 * @param endIndex Ending index of character where the scan should end.
16823 * @returns Index of next non-whitespace character (May be the same as `start` if no whitespace at
16824 * that location.)
16825 */
16826function consumeWhitespace(text, startIndex, endIndex) {
16827 while (startIndex < endIndex && text.charCodeAt(startIndex) <= 32 /* CharCode.SPACE */) {
16828 startIndex++;
16829 }
16830 return startIndex;
16831}
16832/**
16833 * Returns index of last char in class token.
16834 *
16835 * @param text Text to scan
16836 * @param startIndex Starting index of character where the scan should start.
16837 * @param endIndex Ending index of character where the scan should end.
16838 * @returns Index after last char in class token.
16839 */
16840function consumeClassToken(text, startIndex, endIndex) {
16841 while (startIndex < endIndex && text.charCodeAt(startIndex) > 32 /* CharCode.SPACE */) {
16842 startIndex++;
16843 }
16844 return startIndex;
16845}
16846/**
16847 * Consumes all of the characters belonging to style key and token.
16848 *
16849 * @param text Text to scan
16850 * @param startIndex Starting index of character where the scan should start.
16851 * @param endIndex Ending index of character where the scan should end.
16852 * @returns Index after last style key character.
16853 */
16854function consumeStyleKey(text, startIndex, endIndex) {
16855 let ch;
16856 while (startIndex < endIndex &&
16857 ((ch = text.charCodeAt(startIndex)) === 45 /* CharCode.DASH */ || ch === 95 /* CharCode.UNDERSCORE */ ||
16858 ((ch & -33 /* CharCode.UPPER_CASE */) >= 65 /* CharCode.A */ && (ch & -33 /* CharCode.UPPER_CASE */) <= 90 /* CharCode.Z */) ||
16859 (ch >= 48 /* CharCode.ZERO */ && ch <= 57 /* CharCode.NINE */))) {
16860 startIndex++;
16861 }
16862 return startIndex;
16863}
16864/**
16865 * Consumes all whitespace and the separator `:` after the style key.
16866 *
16867 * @param text Text to scan
16868 * @param startIndex Starting index of character where the scan should start.
16869 * @param endIndex Ending index of character where the scan should end.
16870 * @returns Index after separator and surrounding whitespace.
16871 */
16872function consumeSeparator(text, startIndex, endIndex, separator) {
16873 startIndex = consumeWhitespace(text, startIndex, endIndex);
16874 if (startIndex < endIndex) {
16875 if (ngDevMode && text.charCodeAt(startIndex) !== separator) {
16876 malformedStyleError(text, String.fromCharCode(separator), startIndex);
16877 }
16878 startIndex++;
16879 }
16880 return startIndex;
16881}
16882/**
16883 * Consumes style value honoring `url()` and `""` text.
16884 *
16885 * @param text Text to scan
16886 * @param startIndex Starting index of character where the scan should start.
16887 * @param endIndex Ending index of character where the scan should end.
16888 * @returns Index after last style value character.
16889 */
16890function consumeStyleValue(text, startIndex, endIndex) {
16891 let ch1 = -1; // 1st previous character
16892 let ch2 = -1; // 2nd previous character
16893 let ch3 = -1; // 3rd previous character
16894 let i = startIndex;
16895 let lastChIndex = i;
16896 while (i < endIndex) {
16897 const ch = text.charCodeAt(i++);
16898 if (ch === 59 /* CharCode.SEMI_COLON */) {
16899 return lastChIndex;
16900 }
16901 else if (ch === 34 /* CharCode.DOUBLE_QUOTE */ || ch === 39 /* CharCode.SINGLE_QUOTE */) {
16902 lastChIndex = i = consumeQuotedText(text, ch, i, endIndex);
16903 }
16904 else if (startIndex ===
16905 i - 4 && // We have seen only 4 characters so far "URL(" (Ignore "foo_URL()")
16906 ch3 === 85 /* CharCode.U */ &&
16907 ch2 === 82 /* CharCode.R */ && ch1 === 76 /* CharCode.L */ && ch === 40 /* CharCode.OPEN_PAREN */) {
16908 lastChIndex = i = consumeQuotedText(text, 41 /* CharCode.CLOSE_PAREN */, i, endIndex);
16909 }
16910 else if (ch > 32 /* CharCode.SPACE */) {
16911 // if we have a non-whitespace character then capture its location
16912 lastChIndex = i;
16913 }
16914 ch3 = ch2;
16915 ch2 = ch1;
16916 ch1 = ch & -33 /* CharCode.UPPER_CASE */;
16917 }
16918 return lastChIndex;
16919}
16920/**
16921 * Consumes all of the quoted characters.
16922 *
16923 * @param text Text to scan
16924 * @param quoteCharCode CharCode of either `"` or `'` quote or `)` for `url(...)`.
16925 * @param startIndex Starting index of character where the scan should start.
16926 * @param endIndex Ending index of character where the scan should end.
16927 * @returns Index after quoted characters.
16928 */
16929function consumeQuotedText(text, quoteCharCode, startIndex, endIndex) {
16930 let ch1 = -1; // 1st previous character
16931 let index = startIndex;
16932 while (index < endIndex) {
16933 const ch = text.charCodeAt(index++);
16934 if (ch == quoteCharCode && ch1 !== 92 /* CharCode.BACK_SLASH */) {
16935 return index;
16936 }
16937 if (ch == 92 /* CharCode.BACK_SLASH */ && ch1 === 92 /* CharCode.BACK_SLASH */) {
16938 // two back slashes cancel each other out. For example `"\\"` should properly end the
16939 // quotation. (It should not assume that the last `"` is escaped.)
16940 ch1 = 0;
16941 }
16942 else {
16943 ch1 = ch;
16944 }
16945 }
16946 throw ngDevMode ? malformedStyleError(text, String.fromCharCode(quoteCharCode), endIndex) :
16947 new Error();
16948}
16949function malformedStyleError(text, expecting, index) {
16950 ngDevMode && assertEqual(typeof text === 'string', true, 'String expected here');
16951 throw throwError(`Malformed style at location ${index} in string '` + text.substring(0, index) + '[>>' +
16952 text.substring(index, index + 1) + '<<]' + text.slice(index + 1) +
16953 `'. Expecting '${expecting}'.`);
16954}
16955
16956/**
16957 * @license
16958 * Copyright Google LLC All Rights Reserved.
16959 *
16960 * Use of this source code is governed by an MIT-style license that can be
16961 * found in the LICENSE file at https://angular.io/license
16962 */
16963/**
16964 * Update a style binding on an element with the provided value.
16965 *
16966 * If the style value is falsy then it will be removed from the element
16967 * (or assigned a different value depending if there are any styles placed
16968 * on the element with `styleMap` or any static styles that are
16969 * present from when the element was created with `styling`).
16970 *
16971 * Note that the styling element is updated as part of `stylingApply`.
16972 *
16973 * @param prop A valid CSS property.
16974 * @param value New value to write (`null` or an empty string to remove).
16975 * @param suffix Optional suffix. Used with scalar values to add unit such as `px`.
16976 *
16977 * Note that this will apply the provided style value to the host element if this function is called
16978 * within a host binding function.
16979 *
16980 * @codeGenApi
16981 */
16982function ɵɵstyleProp(prop, value, suffix) {
16983 checkStylingProperty(prop, value, suffix, false);
16984 return ɵɵstyleProp;
16985}
16986/**
16987 * Update a class binding on an element with the provided value.
16988 *
16989 * This instruction is meant to handle the `[class.foo]="exp"` case and,
16990 * therefore, the class binding itself must already be allocated using
16991 * `styling` within the creation block.
16992 *
16993 * @param prop A valid CSS class (only one).
16994 * @param value A true/false value which will turn the class on or off.
16995 *
16996 * Note that this will apply the provided class value to the host element if this function
16997 * is called within a host binding function.
16998 *
16999 * @codeGenApi
17000 */
17001function ɵɵclassProp(className, value) {
17002 checkStylingProperty(className, value, null, true);
17003 return ɵɵclassProp;
17004}
17005/**
17006 * Update style bindings using an object literal on an element.
17007 *
17008 * This instruction is meant to apply styling via the `[style]="exp"` template bindings.
17009 * When styles are applied to the element they will then be updated with respect to
17010 * any styles/classes set via `styleProp`. If any styles are set to falsy
17011 * then they will be removed from the element.
17012 *
17013 * Note that the styling instruction will not be applied until `stylingApply` is called.
17014 *
17015 * @param styles A key/value style map of the styles that will be applied to the given element.
17016 * Any missing styles (that have already been applied to the element beforehand) will be
17017 * removed (unset) from the element's styling.
17018 *
17019 * Note that this will apply the provided styleMap value to the host element if this function
17020 * is called within a host binding.
17021 *
17022 * @codeGenApi
17023 */
17024function ɵɵstyleMap(styles) {
17025 checkStylingMap(styleKeyValueArraySet, styleStringParser, styles, false);
17026}
17027/**
17028 * Parse text as style and add values to KeyValueArray.
17029 *
17030 * This code is pulled out to a separate function so that it can be tree shaken away if it is not
17031 * needed. It is only referenced from `ɵɵstyleMap`.
17032 *
17033 * @param keyValueArray KeyValueArray to add parsed values to.
17034 * @param text text to parse.
17035 */
17036function styleStringParser(keyValueArray, text) {
17037 for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i)) {
17038 styleKeyValueArraySet(keyValueArray, getLastParsedKey(text), getLastParsedValue(text));
17039 }
17040}
17041/**
17042 * Update class bindings using an object literal or class-string on an element.
17043 *
17044 * This instruction is meant to apply styling via the `[class]="exp"` template bindings.
17045 * When classes are applied to the element they will then be updated with
17046 * respect to any styles/classes set via `classProp`. If any
17047 * classes are set to falsy then they will be removed from the element.
17048 *
17049 * Note that the styling instruction will not be applied until `stylingApply` is called.
17050 * Note that this will the provided classMap value to the host element if this function is called
17051 * within a host binding.
17052 *
17053 * @param classes A key/value map or string of CSS classes that will be added to the
17054 * given element. Any missing classes (that have already been applied to the element
17055 * beforehand) will be removed (unset) from the element's list of CSS classes.
17056 *
17057 * @codeGenApi
17058 */
17059function ɵɵclassMap(classes) {
17060 checkStylingMap(keyValueArraySet, classStringParser, classes, true);
17061}
17062/**
17063 * Parse text as class and add values to KeyValueArray.
17064 *
17065 * This code is pulled out to a separate function so that it can be tree shaken away if it is not
17066 * needed. It is only referenced from `ɵɵclassMap`.
17067 *
17068 * @param keyValueArray KeyValueArray to add parsed values to.
17069 * @param text text to parse.
17070 */
17071function classStringParser(keyValueArray, text) {
17072 for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) {
17073 keyValueArraySet(keyValueArray, getLastParsedKey(text), true);
17074 }
17075}
17076/**
17077 * Common code between `ɵɵclassProp` and `ɵɵstyleProp`.
17078 *
17079 * @param prop property name.
17080 * @param value binding value.
17081 * @param suffix suffix for the property (e.g. `em` or `px`)
17082 * @param isClassBased `true` if `class` change (`false` if `style`)
17083 */
17084function checkStylingProperty(prop, value, suffix, isClassBased) {
17085 const lView = getLView();
17086 const tView = getTView();
17087 // Styling instructions use 2 slots per binding.
17088 // 1. one for the value / TStylingKey
17089 // 2. one for the intermittent-value / TStylingRange
17090 const bindingIndex = incrementBindingIndex(2);
17091 if (tView.firstUpdatePass) {
17092 stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased);
17093 }
17094 if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
17095 const tNode = tView.data[getSelectedIndex()];
17096 updateStyling(tView, tNode, lView, lView[RENDERER], prop, lView[bindingIndex + 1] = normalizeSuffix(value, suffix), isClassBased, bindingIndex);
17097 }
17098}
17099/**
17100 * Common code between `ɵɵclassMap` and `ɵɵstyleMap`.
17101 *
17102 * @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
17103 * function so that `style` can be processed. This is done for tree shaking purposes.
17104 * @param stringParser Parser used to parse `value` if `string`. (Passed in as `style` and `class`
17105 * have different parsers.)
17106 * @param value bound value from application
17107 * @param isClassBased `true` if `class` change (`false` if `style`)
17108 */
17109function checkStylingMap(keyValueArraySet, stringParser, value, isClassBased) {
17110 const tView = getTView();
17111 const bindingIndex = incrementBindingIndex(2);
17112 if (tView.firstUpdatePass) {
17113 stylingFirstUpdatePass(tView, null, bindingIndex, isClassBased);
17114 }
17115 const lView = getLView();
17116 if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
17117 // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the
17118 // if so as not to read unnecessarily.
17119 const tNode = tView.data[getSelectedIndex()];
17120 if (hasStylingInputShadow(tNode, isClassBased) && !isInHostBindings(tView, bindingIndex)) {
17121 if (ngDevMode) {
17122 // verify that if we are shadowing then `TData` is appropriately marked so that we skip
17123 // processing this binding in styling resolution.
17124 const tStylingKey = tView.data[bindingIndex];
17125 assertEqual(Array.isArray(tStylingKey) ? tStylingKey[1] : tStylingKey, false, 'Styling linked list shadow input should be marked as \'false\'');
17126 }
17127 // VE does not concatenate the static portion like we are doing here.
17128 // Instead VE just ignores the static completely if dynamic binding is present.
17129 // Because of locality we have already set the static portion because we don't know if there
17130 // is a dynamic portion until later. If we would ignore the static portion it would look like
17131 // the binding has removed it. This would confuse `[ngStyle]`/`[ngClass]` to do the wrong
17132 // thing as it would think that the static portion was removed. For this reason we
17133 // concatenate it so that `[ngStyle]`/`[ngClass]` can continue to work on changed.
17134 let staticPrefix = isClassBased ? tNode.classesWithoutHost : tNode.stylesWithoutHost;
17135 ngDevMode && isClassBased === false && staticPrefix !== null &&
17136 assertEqual(staticPrefix.endsWith(';'), true, 'Expecting static portion to end with \';\'');
17137 if (staticPrefix !== null) {
17138 // We want to make sure that falsy values of `value` become empty strings.
17139 value = concatStringsWithSpace(staticPrefix, value ? value : '');
17140 }
17141 // Given `<div [style] my-dir>` such that `my-dir` has `@Input('style')`.
17142 // This takes over the `[style]` binding. (Same for `[class]`)
17143 setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased);
17144 }
17145 else {
17146 updateStylingMap(tView, tNode, lView, lView[RENDERER], lView[bindingIndex + 1], lView[bindingIndex + 1] = toStylingKeyValueArray(keyValueArraySet, stringParser, value), isClassBased, bindingIndex);
17147 }
17148 }
17149}
17150/**
17151 * Determines when the binding is in `hostBindings` section
17152 *
17153 * @param tView Current `TView`
17154 * @param bindingIndex index of binding which we would like if it is in `hostBindings`
17155 */
17156function isInHostBindings(tView, bindingIndex) {
17157 // All host bindings are placed after the expando section.
17158 return bindingIndex >= tView.expandoStartIndex;
17159}
17160/**
17161 * Collects the necessary information to insert the binding into a linked list of style bindings
17162 * using `insertTStylingBinding`.
17163 *
17164 * @param tView `TView` where the binding linked list will be stored.
17165 * @param tStylingKey Property/key of the binding.
17166 * @param bindingIndex Index of binding associated with the `prop`
17167 * @param isClassBased `true` if `class` change (`false` if `style`)
17168 */
17169function stylingFirstUpdatePass(tView, tStylingKey, bindingIndex, isClassBased) {
17170 ngDevMode && assertFirstUpdatePass(tView);
17171 const tData = tView.data;
17172 if (tData[bindingIndex + 1] === null) {
17173 // The above check is necessary because we don't clear first update pass until first successful
17174 // (no exception) template execution. This prevents the styling instruction from double adding
17175 // itself to the list.
17176 // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the
17177 // if so as not to read unnecessarily.
17178 const tNode = tData[getSelectedIndex()];
17179 ngDevMode && assertDefined(tNode, 'TNode expected');
17180 const isHostBindings = isInHostBindings(tView, bindingIndex);
17181 if (hasStylingInputShadow(tNode, isClassBased) && tStylingKey === null && !isHostBindings) {
17182 // `tStylingKey === null` implies that we are either `[style]` or `[class]` binding.
17183 // If there is a directive which uses `@Input('style')` or `@Input('class')` than
17184 // we need to neutralize this binding since that directive is shadowing it.
17185 // We turn this into a noop by setting the key to `false`
17186 tStylingKey = false;
17187 }
17188 tStylingKey = wrapInStaticStylingKey(tData, tNode, tStylingKey, isClassBased);
17189 insertTStylingBinding(tData, tNode, tStylingKey, bindingIndex, isHostBindings, isClassBased);
17190 }
17191}
17192/**
17193 * Adds static styling information to the binding if applicable.
17194 *
17195 * The linked list of styles not only stores the list and keys, but also stores static styling
17196 * information on some of the keys. This function determines if the key should contain the styling
17197 * information and computes it.
17198 *
17199 * See `TStylingStatic` for more details.
17200 *
17201 * @param tData `TData` where the linked list is stored.
17202 * @param tNode `TNode` for which the styling is being computed.
17203 * @param stylingKey `TStylingKeyPrimitive` which may need to be wrapped into `TStylingKey`
17204 * @param isClassBased `true` if `class` (`false` if `style`)
17205 */
17206function wrapInStaticStylingKey(tData, tNode, stylingKey, isClassBased) {
17207 const hostDirectiveDef = getCurrentDirectiveDef(tData);
17208 let residual = isClassBased ? tNode.residualClasses : tNode.residualStyles;
17209 if (hostDirectiveDef === null) {
17210 // We are in template node.
17211 // If template node already had styling instruction then it has already collected the static
17212 // styling and there is no need to collect them again. We know that we are the first styling
17213 // instruction because the `TNode.*Bindings` points to 0 (nothing has been inserted yet).
17214 const isFirstStylingInstructionInTemplate = (isClassBased ? tNode.classBindings : tNode.styleBindings) === 0;
17215 if (isFirstStylingInstructionInTemplate) {
17216 // It would be nice to be able to get the statics from `mergeAttrs`, however, at this point
17217 // they are already merged and it would not be possible to figure which property belongs where
17218 // in the priority.
17219 stylingKey = collectStylingFromDirectives(null, tData, tNode, stylingKey, isClassBased);
17220 stylingKey = collectStylingFromTAttrs(stylingKey, tNode.attrs, isClassBased);
17221 // We know that if we have styling binding in template we can't have residual.
17222 residual = null;
17223 }
17224 }
17225 else {
17226 // We are in host binding node and there was no binding instruction in template node.
17227 // This means that we need to compute the residual.
17228 const directiveStylingLast = tNode.directiveStylingLast;
17229 const isFirstStylingInstructionInHostBinding = directiveStylingLast === -1 || tData[directiveStylingLast] !== hostDirectiveDef;
17230 if (isFirstStylingInstructionInHostBinding) {
17231 stylingKey =
17232 collectStylingFromDirectives(hostDirectiveDef, tData, tNode, stylingKey, isClassBased);
17233 if (residual === null) {
17234 // - If `null` than either:
17235 // - Template styling instruction already ran and it has consumed the static
17236 // styling into its `TStylingKey` and so there is no need to update residual. Instead
17237 // we need to update the `TStylingKey` associated with the first template node
17238 // instruction. OR
17239 // - Some other styling instruction ran and determined that there are no residuals
17240 let templateStylingKey = getTemplateHeadTStylingKey(tData, tNode, isClassBased);
17241 if (templateStylingKey !== undefined && Array.isArray(templateStylingKey)) {
17242 // Only recompute if `templateStylingKey` had static values. (If no static value found
17243 // then there is nothing to do since this operation can only produce less static keys, not
17244 // more.)
17245 templateStylingKey = collectStylingFromDirectives(null, tData, tNode, templateStylingKey[1] /* unwrap previous statics */, isClassBased);
17246 templateStylingKey =
17247 collectStylingFromTAttrs(templateStylingKey, tNode.attrs, isClassBased);
17248 setTemplateHeadTStylingKey(tData, tNode, isClassBased, templateStylingKey);
17249 }
17250 }
17251 else {
17252 // We only need to recompute residual if it is not `null`.
17253 // - If existing residual (implies there was no template styling). This means that some of
17254 // the statics may have moved from the residual to the `stylingKey` and so we have to
17255 // recompute.
17256 // - If `undefined` this is the first time we are running.
17257 residual = collectResidual(tData, tNode, isClassBased);
17258 }
17259 }
17260 }
17261 if (residual !== undefined) {
17262 isClassBased ? (tNode.residualClasses = residual) : (tNode.residualStyles = residual);
17263 }
17264 return stylingKey;
17265}
17266/**
17267 * Retrieve the `TStylingKey` for the template styling instruction.
17268 *
17269 * This is needed since `hostBinding` styling instructions are inserted after the template
17270 * instruction. While the template instruction needs to update the residual in `TNode` the
17271 * `hostBinding` instructions need to update the `TStylingKey` of the template instruction because
17272 * the template instruction is downstream from the `hostBindings` instructions.
17273 *
17274 * @param tData `TData` where the linked list is stored.
17275 * @param tNode `TNode` for which the styling is being computed.
17276 * @param isClassBased `true` if `class` (`false` if `style`)
17277 * @return `TStylingKey` if found or `undefined` if not found.
17278 */
17279function getTemplateHeadTStylingKey(tData, tNode, isClassBased) {
17280 const bindings = isClassBased ? tNode.classBindings : tNode.styleBindings;
17281 if (getTStylingRangeNext(bindings) === 0) {
17282 // There does not seem to be a styling instruction in the `template`.
17283 return undefined;
17284 }
17285 return tData[getTStylingRangePrev(bindings)];
17286}
17287/**
17288 * Update the `TStylingKey` of the first template instruction in `TNode`.
17289 *
17290 * Logically `hostBindings` styling instructions are of lower priority than that of the template.
17291 * However, they execute after the template styling instructions. This means that they get inserted
17292 * in front of the template styling instructions.
17293 *
17294 * If we have a template styling instruction and a new `hostBindings` styling instruction is
17295 * executed it means that it may need to steal static fields from the template instruction. This
17296 * method allows us to update the first template instruction `TStylingKey` with a new value.
17297 *
17298 * Assume:
17299 * ```
17300 * <div my-dir style="color: red" [style.color]="tmplExp"></div>
17301 *
17302 * @Directive({
17303 * host: {
17304 * 'style': 'width: 100px',
17305 * '[style.color]': 'dirExp',
17306 * }
17307 * })
17308 * class MyDir {}
17309 * ```
17310 *
17311 * when `[style.color]="tmplExp"` executes it creates this data structure.
17312 * ```
17313 * ['', 'color', 'color', 'red', 'width', '100px'],
17314 * ```
17315 *
17316 * The reason for this is that the template instruction does not know if there are styling
17317 * instructions and must assume that there are none and must collect all of the static styling.
17318 * (both
17319 * `color' and 'width`)
17320 *
17321 * When `'[style.color]': 'dirExp',` executes we need to insert a new data into the linked list.
17322 * ```
17323 * ['', 'color', 'width', '100px'], // newly inserted
17324 * ['', 'color', 'color', 'red', 'width', '100px'], // this is wrong
17325 * ```
17326 *
17327 * Notice that the template statics is now wrong as it incorrectly contains `width` so we need to
17328 * update it like so:
17329 * ```
17330 * ['', 'color', 'width', '100px'],
17331 * ['', 'color', 'color', 'red'], // UPDATE
17332 * ```
17333 *
17334 * @param tData `TData` where the linked list is stored.
17335 * @param tNode `TNode` for which the styling is being computed.
17336 * @param isClassBased `true` if `class` (`false` if `style`)
17337 * @param tStylingKey New `TStylingKey` which is replacing the old one.
17338 */
17339function setTemplateHeadTStylingKey(tData, tNode, isClassBased, tStylingKey) {
17340 const bindings = isClassBased ? tNode.classBindings : tNode.styleBindings;
17341 ngDevMode &&
17342 assertNotEqual(getTStylingRangeNext(bindings), 0, 'Expecting to have at least one template styling binding.');
17343 tData[getTStylingRangePrev(bindings)] = tStylingKey;
17344}
17345/**
17346 * Collect all static values after the current `TNode.directiveStylingLast` index.
17347 *
17348 * Collect the remaining styling information which has not yet been collected by an existing
17349 * styling instruction.
17350 *
17351 * @param tData `TData` where the `DirectiveDefs` are stored.
17352 * @param tNode `TNode` which contains the directive range.
17353 * @param isClassBased `true` if `class` (`false` if `style`)
17354 */
17355function collectResidual(tData, tNode, isClassBased) {
17356 let residual = undefined;
17357 const directiveEnd = tNode.directiveEnd;
17358 ngDevMode &&
17359 assertNotEqual(tNode.directiveStylingLast, -1, 'By the time this function gets called at least one hostBindings-node styling instruction must have executed.');
17360 // We add `1 + tNode.directiveStart` because we need to skip the current directive (as we are
17361 // collecting things after the last `hostBindings` directive which had a styling instruction.)
17362 for (let i = 1 + tNode.directiveStylingLast; i < directiveEnd; i++) {
17363 const attrs = tData[i].hostAttrs;
17364 residual = collectStylingFromTAttrs(residual, attrs, isClassBased);
17365 }
17366 return collectStylingFromTAttrs(residual, tNode.attrs, isClassBased);
17367}
17368/**
17369 * Collect the static styling information with lower priority than `hostDirectiveDef`.
17370 *
17371 * (This is opposite of residual styling.)
17372 *
17373 * @param hostDirectiveDef `DirectiveDef` for which we want to collect lower priority static
17374 * styling. (Or `null` if template styling)
17375 * @param tData `TData` where the linked list is stored.
17376 * @param tNode `TNode` for which the styling is being computed.
17377 * @param stylingKey Existing `TStylingKey` to update or wrap.
17378 * @param isClassBased `true` if `class` (`false` if `style`)
17379 */
17380function collectStylingFromDirectives(hostDirectiveDef, tData, tNode, stylingKey, isClassBased) {
17381 // We need to loop because there can be directives which have `hostAttrs` but don't have
17382 // `hostBindings` so this loop catches up to the current directive..
17383 let currentDirective = null;
17384 const directiveEnd = tNode.directiveEnd;
17385 let directiveStylingLast = tNode.directiveStylingLast;
17386 if (directiveStylingLast === -1) {
17387 directiveStylingLast = tNode.directiveStart;
17388 }
17389 else {
17390 directiveStylingLast++;
17391 }
17392 while (directiveStylingLast < directiveEnd) {
17393 currentDirective = tData[directiveStylingLast];
17394 ngDevMode && assertDefined(currentDirective, 'expected to be defined');
17395 stylingKey = collectStylingFromTAttrs(stylingKey, currentDirective.hostAttrs, isClassBased);
17396 if (currentDirective === hostDirectiveDef)
17397 break;
17398 directiveStylingLast++;
17399 }
17400 if (hostDirectiveDef !== null) {
17401 // we only advance the styling cursor if we are collecting data from host bindings.
17402 // Template executes before host bindings and so if we would update the index,
17403 // host bindings would not get their statics.
17404 tNode.directiveStylingLast = directiveStylingLast;
17405 }
17406 return stylingKey;
17407}
17408/**
17409 * Convert `TAttrs` into `TStylingStatic`.
17410 *
17411 * @param stylingKey existing `TStylingKey` to update or wrap.
17412 * @param attrs `TAttributes` to process.
17413 * @param isClassBased `true` if `class` (`false` if `style`)
17414 */
17415function collectStylingFromTAttrs(stylingKey, attrs, isClassBased) {
17416 const desiredMarker = isClassBased ? 1 /* AttributeMarker.Classes */ : 2 /* AttributeMarker.Styles */;
17417 let currentMarker = -1 /* AttributeMarker.ImplicitAttributes */;
17418 if (attrs !== null) {
17419 for (let i = 0; i < attrs.length; i++) {
17420 const item = attrs[i];
17421 if (typeof item === 'number') {
17422 currentMarker = item;
17423 }
17424 else {
17425 if (currentMarker === desiredMarker) {
17426 if (!Array.isArray(stylingKey)) {
17427 stylingKey = stylingKey === undefined ? [] : ['', stylingKey];
17428 }
17429 keyValueArraySet(stylingKey, item, isClassBased ? true : attrs[++i]);
17430 }
17431 }
17432 }
17433 }
17434 return stylingKey === undefined ? null : stylingKey;
17435}
17436/**
17437 * Convert user input to `KeyValueArray`.
17438 *
17439 * This function takes user input which could be `string`, Object literal, or iterable and converts
17440 * it into a consistent representation. The output of this is `KeyValueArray` (which is an array
17441 * where
17442 * even indexes contain keys and odd indexes contain values for those keys).
17443 *
17444 * The advantage of converting to `KeyValueArray` is that we can perform diff in an input
17445 * independent
17446 * way.
17447 * (ie we can compare `foo bar` to `['bar', 'baz'] and determine a set of changes which need to be
17448 * applied)
17449 *
17450 * The fact that `KeyValueArray` is sorted is very important because it allows us to compute the
17451 * difference in linear fashion without the need to allocate any additional data.
17452 *
17453 * For example if we kept this as a `Map` we would have to iterate over previous `Map` to determine
17454 * which values need to be deleted, over the new `Map` to determine additions, and we would have to
17455 * keep additional `Map` to keep track of duplicates or items which have not yet been visited.
17456 *
17457 * @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
17458 * function so that `style` can be processed. This is done
17459 * for tree shaking purposes.
17460 * @param stringParser The parser is passed in so that it will be tree shakable. See
17461 * `styleStringParser` and `classStringParser`
17462 * @param value The value to parse/convert to `KeyValueArray`
17463 */
17464function toStylingKeyValueArray(keyValueArraySet, stringParser, value) {
17465 if (value == null /*|| value === undefined */ || value === '')
17466 return EMPTY_ARRAY;
17467 const styleKeyValueArray = [];
17468 const unwrappedValue = unwrapSafeValue(value);
17469 if (Array.isArray(unwrappedValue)) {
17470 for (let i = 0; i < unwrappedValue.length; i++) {
17471 keyValueArraySet(styleKeyValueArray, unwrappedValue[i], true);
17472 }
17473 }
17474 else if (typeof unwrappedValue === 'object') {
17475 for (const key in unwrappedValue) {
17476 if (unwrappedValue.hasOwnProperty(key)) {
17477 keyValueArraySet(styleKeyValueArray, key, unwrappedValue[key]);
17478 }
17479 }
17480 }
17481 else if (typeof unwrappedValue === 'string') {
17482 stringParser(styleKeyValueArray, unwrappedValue);
17483 }
17484 else {
17485 ngDevMode &&
17486 throwError('Unsupported styling type ' + typeof unwrappedValue + ': ' + unwrappedValue);
17487 }
17488 return styleKeyValueArray;
17489}
17490/**
17491 * Set a `value` for a `key`.
17492 *
17493 * See: `keyValueArraySet` for details
17494 *
17495 * @param keyValueArray KeyValueArray to add to.
17496 * @param key Style key to add.
17497 * @param value The value to set.
17498 */
17499function styleKeyValueArraySet(keyValueArray, key, value) {
17500 keyValueArraySet(keyValueArray, key, unwrapSafeValue(value));
17501}
17502/**
17503 * Update map based styling.
17504 *
17505 * Map based styling could be anything which contains more than one binding. For example `string`,
17506 * or object literal. Dealing with all of these types would complicate the logic so
17507 * instead this function expects that the complex input is first converted into normalized
17508 * `KeyValueArray`. The advantage of normalization is that we get the values sorted, which makes it
17509 * very cheap to compute deltas between the previous and current value.
17510 *
17511 * @param tView Associated `TView.data` contains the linked list of binding priorities.
17512 * @param tNode `TNode` where the binding is located.
17513 * @param lView `LView` contains the values associated with other styling binding at this `TNode`.
17514 * @param renderer Renderer to use if any updates.
17515 * @param oldKeyValueArray Previous value represented as `KeyValueArray`
17516 * @param newKeyValueArray Current value represented as `KeyValueArray`
17517 * @param isClassBased `true` if `class` (`false` if `style`)
17518 * @param bindingIndex Binding index of the binding.
17519 */
17520function updateStylingMap(tView, tNode, lView, renderer, oldKeyValueArray, newKeyValueArray, isClassBased, bindingIndex) {
17521 if (oldKeyValueArray === NO_CHANGE) {
17522 // On first execution the oldKeyValueArray is NO_CHANGE => treat it as empty KeyValueArray.
17523 oldKeyValueArray = EMPTY_ARRAY;
17524 }
17525 let oldIndex = 0;
17526 let newIndex = 0;
17527 let oldKey = 0 < oldKeyValueArray.length ? oldKeyValueArray[0] : null;
17528 let newKey = 0 < newKeyValueArray.length ? newKeyValueArray[0] : null;
17529 while (oldKey !== null || newKey !== null) {
17530 ngDevMode && assertLessThan(oldIndex, 999, 'Are we stuck in infinite loop?');
17531 ngDevMode && assertLessThan(newIndex, 999, 'Are we stuck in infinite loop?');
17532 const oldValue = oldIndex < oldKeyValueArray.length ? oldKeyValueArray[oldIndex + 1] : undefined;
17533 const newValue = newIndex < newKeyValueArray.length ? newKeyValueArray[newIndex + 1] : undefined;
17534 let setKey = null;
17535 let setValue = undefined;
17536 if (oldKey === newKey) {
17537 // UPDATE: Keys are equal => new value is overwriting old value.
17538 oldIndex += 2;
17539 newIndex += 2;
17540 if (oldValue !== newValue) {
17541 setKey = newKey;
17542 setValue = newValue;
17543 }
17544 }
17545 else if (newKey === null || oldKey !== null && oldKey < newKey) {
17546 // DELETE: oldKey key is missing or we did not find the oldKey in the newValue
17547 // (because the keyValueArray is sorted and `newKey` is found later alphabetically).
17548 // `"background" < "color"` so we need to delete `"background"` because it is not found in the
17549 // new array.
17550 oldIndex += 2;
17551 setKey = oldKey;
17552 }
17553 else {
17554 // CREATE: newKey's is earlier alphabetically than oldKey's (or no oldKey) => we have new key.
17555 // `"color" > "background"` so we need to add `color` because it is in new array but not in
17556 // old array.
17557 ngDevMode && assertDefined(newKey, 'Expecting to have a valid key');
17558 newIndex += 2;
17559 setKey = newKey;
17560 setValue = newValue;
17561 }
17562 if (setKey !== null) {
17563 updateStyling(tView, tNode, lView, renderer, setKey, setValue, isClassBased, bindingIndex);
17564 }
17565 oldKey = oldIndex < oldKeyValueArray.length ? oldKeyValueArray[oldIndex] : null;
17566 newKey = newIndex < newKeyValueArray.length ? newKeyValueArray[newIndex] : null;
17567 }
17568}
17569/**
17570 * Update a simple (property name) styling.
17571 *
17572 * This function takes `prop` and updates the DOM to that value. The function takes the binding
17573 * value as well as binding priority into consideration to determine which value should be written
17574 * to DOM. (For example it may be determined that there is a higher priority overwrite which blocks
17575 * the DOM write, or if the value goes to `undefined` a lower priority overwrite may be consulted.)
17576 *
17577 * @param tView Associated `TView.data` contains the linked list of binding priorities.
17578 * @param tNode `TNode` where the binding is located.
17579 * @param lView `LView` contains the values associated with other styling binding at this `TNode`.
17580 * @param renderer Renderer to use if any updates.
17581 * @param prop Either style property name or a class name.
17582 * @param value Either style value for `prop` or `true`/`false` if `prop` is class.
17583 * @param isClassBased `true` if `class` (`false` if `style`)
17584 * @param bindingIndex Binding index of the binding.
17585 */
17586function updateStyling(tView, tNode, lView, renderer, prop, value, isClassBased, bindingIndex) {
17587 if (!(tNode.type & 3 /* TNodeType.AnyRNode */)) {
17588 // It is possible to have styling on non-elements (such as ng-container).
17589 // This is rare, but it does happen. In such a case, just ignore the binding.
17590 return;
17591 }
17592 const tData = tView.data;
17593 const tRange = tData[bindingIndex + 1];
17594 const higherPriorityValue = getTStylingRangeNextDuplicate(tRange) ?
17595 findStylingValue(tData, tNode, lView, prop, getTStylingRangeNext(tRange), isClassBased) :
17596 undefined;
17597 if (!isStylingValuePresent(higherPriorityValue)) {
17598 // We don't have a next duplicate, or we did not find a duplicate value.
17599 if (!isStylingValuePresent(value)) {
17600 // We should delete current value or restore to lower priority value.
17601 if (getTStylingRangePrevDuplicate(tRange)) {
17602 // We have a possible prev duplicate, let's retrieve it.
17603 value = findStylingValue(tData, null, lView, prop, bindingIndex, isClassBased);
17604 }
17605 }
17606 const rNode = getNativeByIndex(getSelectedIndex(), lView);
17607 applyStyling(renderer, isClassBased, rNode, prop, value);
17608 }
17609}
17610/**
17611 * Search for styling value with higher priority which is overwriting current value, or a
17612 * value of lower priority to which we should fall back if the value is `undefined`.
17613 *
17614 * When value is being applied at a location, related values need to be consulted.
17615 * - If there is a higher priority binding, we should be using that one instead.
17616 * For example `<div [style]="{color:exp1}" [style.color]="exp2">` change to `exp1`
17617 * requires that we check `exp2` to see if it is set to value other than `undefined`.
17618 * - If there is a lower priority binding and we are changing to `undefined`
17619 * For example `<div [style]="{color:exp1}" [style.color]="exp2">` change to `exp2` to
17620 * `undefined` requires that we check `exp1` (and static values) and use that as new value.
17621 *
17622 * NOTE: The styling stores two values.
17623 * 1. The raw value which came from the application is stored at `index + 0` location. (This value
17624 * is used for dirty checking).
17625 * 2. The normalized value is stored at `index + 1`.
17626 *
17627 * @param tData `TData` used for traversing the priority.
17628 * @param tNode `TNode` to use for resolving static styling. Also controls search direction.
17629 * - `TNode` search next and quit as soon as `isStylingValuePresent(value)` is true.
17630 * If no value found consult `tNode.residualStyle`/`tNode.residualClass` for default value.
17631 * - `null` search prev and go all the way to end. Return last value where
17632 * `isStylingValuePresent(value)` is true.
17633 * @param lView `LView` used for retrieving the actual values.
17634 * @param prop Property which we are interested in.
17635 * @param index Starting index in the linked list of styling bindings where the search should start.
17636 * @param isClassBased `true` if `class` (`false` if `style`)
17637 */
17638function findStylingValue(tData, tNode, lView, prop, index, isClassBased) {
17639 // `TNode` to use for resolving static styling. Also controls search direction.
17640 // - `TNode` search next and quit as soon as `isStylingValuePresent(value)` is true.
17641 // If no value found consult `tNode.residualStyle`/`tNode.residualClass` for default value.
17642 // - `null` search prev and go all the way to end. Return last value where
17643 // `isStylingValuePresent(value)` is true.
17644 const isPrevDirection = tNode === null;
17645 let value = undefined;
17646 while (index > 0) {
17647 const rawKey = tData[index];
17648 const containsStatics = Array.isArray(rawKey);
17649 // Unwrap the key if we contain static values.
17650 const key = containsStatics ? rawKey[1] : rawKey;
17651 const isStylingMap = key === null;
17652 let valueAtLViewIndex = lView[index + 1];
17653 if (valueAtLViewIndex === NO_CHANGE) {
17654 // In firstUpdatePass the styling instructions create a linked list of styling.
17655 // On subsequent passes it is possible for a styling instruction to try to read a binding
17656 // which
17657 // has not yet executed. In that case we will find `NO_CHANGE` and we should assume that
17658 // we have `undefined` (or empty array in case of styling-map instruction) instead. This
17659 // allows the resolution to apply the value (which may later be overwritten when the
17660 // binding actually executes.)
17661 valueAtLViewIndex = isStylingMap ? EMPTY_ARRAY : undefined;
17662 }
17663 let currentValue = isStylingMap ? keyValueArrayGet(valueAtLViewIndex, prop) :
17664 key === prop ? valueAtLViewIndex : undefined;
17665 if (containsStatics && !isStylingValuePresent(currentValue)) {
17666 currentValue = keyValueArrayGet(rawKey, prop);
17667 }
17668 if (isStylingValuePresent(currentValue)) {
17669 value = currentValue;
17670 if (isPrevDirection) {
17671 return value;
17672 }
17673 }
17674 const tRange = tData[index + 1];
17675 index = isPrevDirection ? getTStylingRangePrev(tRange) : getTStylingRangeNext(tRange);
17676 }
17677 if (tNode !== null) {
17678 // in case where we are going in next direction AND we did not find anything, we need to
17679 // consult residual styling
17680 let residual = isClassBased ? tNode.residualClasses : tNode.residualStyles;
17681 if (residual != null /** OR residual !=== undefined */) {
17682 value = keyValueArrayGet(residual, prop);
17683 }
17684 }
17685 return value;
17686}
17687/**
17688 * Determines if the binding value should be used (or if the value is 'undefined' and hence priority
17689 * resolution should be used.)
17690 *
17691 * @param value Binding style value.
17692 */
17693function isStylingValuePresent(value) {
17694 // Currently only `undefined` value is considered non-binding. That is `undefined` says I don't
17695 // have an opinion as to what this binding should be and you should consult other bindings by
17696 // priority to determine the valid value.
17697 // This is extracted into a single function so that we have a single place to control this.
17698 return value !== undefined;
17699}
17700/**
17701 * Normalizes and/or adds a suffix to the value.
17702 *
17703 * If value is `null`/`undefined` no suffix is added
17704 * @param value
17705 * @param suffix
17706 */
17707function normalizeSuffix(value, suffix) {
17708 if (value == null /** || value === undefined */) {
17709 // do nothing
17710 }
17711 else if (typeof suffix === 'string') {
17712 value = value + suffix;
17713 }
17714 else if (typeof value === 'object') {
17715 value = stringify(unwrapSafeValue(value));
17716 }
17717 return value;
17718}
17719/**
17720 * Tests if the `TNode` has input shadow.
17721 *
17722 * An input shadow is when a directive steals (shadows) the input by using `@Input('style')` or
17723 * `@Input('class')` as input.
17724 *
17725 * @param tNode `TNode` which we would like to see if it has shadow.
17726 * @param isClassBased `true` if `class` (`false` if `style`)
17727 */
17728function hasStylingInputShadow(tNode, isClassBased) {
17729 return (tNode.flags & (isClassBased ? 16 /* TNodeFlags.hasClassInput */ : 32 /* TNodeFlags.hasStyleInput */)) !== 0;
17730}
17731
17732/**
17733 * @license
17734 * Copyright Google LLC All Rights Reserved.
17735 *
17736 * Use of this source code is governed by an MIT-style license that can be
17737 * found in the LICENSE file at https://angular.io/license
17738 */
17739/**
17740 * Create static text node
17741 *
17742 * @param index Index of the node in the data array
17743 * @param value Static string value to write.
17744 *
17745 * @codeGenApi
17746 */
17747function ɵɵtext(index, value = '') {
17748 const lView = getLView();
17749 const tView = getTView();
17750 const adjustedIndex = index + HEADER_OFFSET;
17751 ngDevMode &&
17752 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'text nodes should be created before any bindings');
17753 ngDevMode && assertIndexInRange(lView, adjustedIndex);
17754 const tNode = tView.firstCreatePass ?
17755 getOrCreateTNode(tView, adjustedIndex, 1 /* TNodeType.Text */, value, null) :
17756 tView.data[adjustedIndex];
17757 const textNative = lView[adjustedIndex] = createTextNode(lView[RENDERER], value);
17758 appendChild(tView, lView, textNative, tNode);
17759 // Text nodes are self closing.
17760 setCurrentTNode(tNode, false);
17761}
17762
17763/**
17764 * @license
17765 * Copyright Google LLC All Rights Reserved.
17766 *
17767 * Use of this source code is governed by an MIT-style license that can be
17768 * found in the LICENSE file at https://angular.io/license
17769 */
17770/**
17771 *
17772 * Update text content with a lone bound value
17773 *
17774 * Used when a text node has 1 interpolated value in it, an no additional text
17775 * surrounds that interpolated value:
17776 *
17777 * ```html
17778 * <div>{{v0}}</div>
17779 * ```
17780 *
17781 * Its compiled representation is:
17782 *
17783 * ```ts
17784 * ɵɵtextInterpolate(v0);
17785 * ```
17786 * @returns itself, so that it may be chained.
17787 * @see textInterpolateV
17788 * @codeGenApi
17789 */
17790function ɵɵtextInterpolate(v0) {
17791 ɵɵtextInterpolate1('', v0, '');
17792 return ɵɵtextInterpolate;
17793}
17794/**
17795 *
17796 * Update text content with single bound value surrounded by other text.
17797 *
17798 * Used when a text node has 1 interpolated value in it:
17799 *
17800 * ```html
17801 * <div>prefix{{v0}}suffix</div>
17802 * ```
17803 *
17804 * Its compiled representation is:
17805 *
17806 * ```ts
17807 * ɵɵtextInterpolate1('prefix', v0, 'suffix');
17808 * ```
17809 * @returns itself, so that it may be chained.
17810 * @see textInterpolateV
17811 * @codeGenApi
17812 */
17813function ɵɵtextInterpolate1(prefix, v0, suffix) {
17814 const lView = getLView();
17815 const interpolated = interpolation1(lView, prefix, v0, suffix);
17816 if (interpolated !== NO_CHANGE) {
17817 textBindingInternal(lView, getSelectedIndex(), interpolated);
17818 }
17819 return ɵɵtextInterpolate1;
17820}
17821/**
17822 *
17823 * Update text content with 2 bound values surrounded by other text.
17824 *
17825 * Used when a text node has 2 interpolated values in it:
17826 *
17827 * ```html
17828 * <div>prefix{{v0}}-{{v1}}suffix</div>
17829 * ```
17830 *
17831 * Its compiled representation is:
17832 *
17833 * ```ts
17834 * ɵɵtextInterpolate2('prefix', v0, '-', v1, 'suffix');
17835 * ```
17836 * @returns itself, so that it may be chained.
17837 * @see textInterpolateV
17838 * @codeGenApi
17839 */
17840function ɵɵtextInterpolate2(prefix, v0, i0, v1, suffix) {
17841 const lView = getLView();
17842 const interpolated = interpolation2(lView, prefix, v0, i0, v1, suffix);
17843 if (interpolated !== NO_CHANGE) {
17844 textBindingInternal(lView, getSelectedIndex(), interpolated);
17845 }
17846 return ɵɵtextInterpolate2;
17847}
17848/**
17849 *
17850 * Update text content with 3 bound values surrounded by other text.
17851 *
17852 * Used when a text node has 3 interpolated values in it:
17853 *
17854 * ```html
17855 * <div>prefix{{v0}}-{{v1}}-{{v2}}suffix</div>
17856 * ```
17857 *
17858 * Its compiled representation is:
17859 *
17860 * ```ts
17861 * ɵɵtextInterpolate3(
17862 * 'prefix', v0, '-', v1, '-', v2, 'suffix');
17863 * ```
17864 * @returns itself, so that it may be chained.
17865 * @see textInterpolateV
17866 * @codeGenApi
17867 */
17868function ɵɵtextInterpolate3(prefix, v0, i0, v1, i1, v2, suffix) {
17869 const lView = getLView();
17870 const interpolated = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
17871 if (interpolated !== NO_CHANGE) {
17872 textBindingInternal(lView, getSelectedIndex(), interpolated);
17873 }
17874 return ɵɵtextInterpolate3;
17875}
17876/**
17877 *
17878 * Update text content with 4 bound values surrounded by other text.
17879 *
17880 * Used when a text node has 4 interpolated values in it:
17881 *
17882 * ```html
17883 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix</div>
17884 * ```
17885 *
17886 * Its compiled representation is:
17887 *
17888 * ```ts
17889 * ɵɵtextInterpolate4(
17890 * 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
17891 * ```
17892 * @returns itself, so that it may be chained.
17893 * @see ɵɵtextInterpolateV
17894 * @codeGenApi
17895 */
17896function ɵɵtextInterpolate4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
17897 const lView = getLView();
17898 const interpolated = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
17899 if (interpolated !== NO_CHANGE) {
17900 textBindingInternal(lView, getSelectedIndex(), interpolated);
17901 }
17902 return ɵɵtextInterpolate4;
17903}
17904/**
17905 *
17906 * Update text content with 5 bound values surrounded by other text.
17907 *
17908 * Used when a text node has 5 interpolated values in it:
17909 *
17910 * ```html
17911 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix</div>
17912 * ```
17913 *
17914 * Its compiled representation is:
17915 *
17916 * ```ts
17917 * ɵɵtextInterpolate5(
17918 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
17919 * ```
17920 * @returns itself, so that it may be chained.
17921 * @see textInterpolateV
17922 * @codeGenApi
17923 */
17924function ɵɵtextInterpolate5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
17925 const lView = getLView();
17926 const interpolated = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
17927 if (interpolated !== NO_CHANGE) {
17928 textBindingInternal(lView, getSelectedIndex(), interpolated);
17929 }
17930 return ɵɵtextInterpolate5;
17931}
17932/**
17933 *
17934 * Update text content with 6 bound values surrounded by other text.
17935 *
17936 * Used when a text node has 6 interpolated values in it:
17937 *
17938 * ```html
17939 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix</div>
17940 * ```
17941 *
17942 * Its compiled representation is:
17943 *
17944 * ```ts
17945 * ɵɵtextInterpolate6(
17946 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
17947 * ```
17948 *
17949 * @param i4 Static value used for concatenation only.
17950 * @param v5 Value checked for change. @returns itself, so that it may be chained.
17951 * @see textInterpolateV
17952 * @codeGenApi
17953 */
17954function ɵɵtextInterpolate6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
17955 const lView = getLView();
17956 const interpolated = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
17957 if (interpolated !== NO_CHANGE) {
17958 textBindingInternal(lView, getSelectedIndex(), interpolated);
17959 }
17960 return ɵɵtextInterpolate6;
17961}
17962/**
17963 *
17964 * Update text content with 7 bound values surrounded by other text.
17965 *
17966 * Used when a text node has 7 interpolated values in it:
17967 *
17968 * ```html
17969 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix</div>
17970 * ```
17971 *
17972 * Its compiled representation is:
17973 *
17974 * ```ts
17975 * ɵɵtextInterpolate7(
17976 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
17977 * ```
17978 * @returns itself, so that it may be chained.
17979 * @see textInterpolateV
17980 * @codeGenApi
17981 */
17982function ɵɵtextInterpolate7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
17983 const lView = getLView();
17984 const interpolated = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
17985 if (interpolated !== NO_CHANGE) {
17986 textBindingInternal(lView, getSelectedIndex(), interpolated);
17987 }
17988 return ɵɵtextInterpolate7;
17989}
17990/**
17991 *
17992 * Update text content with 8 bound values surrounded by other text.
17993 *
17994 * Used when a text node has 8 interpolated values in it:
17995 *
17996 * ```html
17997 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix</div>
17998 * ```
17999 *
18000 * Its compiled representation is:
18001 *
18002 * ```ts
18003 * ɵɵtextInterpolate8(
18004 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
18005 * ```
18006 * @returns itself, so that it may be chained.
18007 * @see textInterpolateV
18008 * @codeGenApi
18009 */
18010function ɵɵtextInterpolate8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
18011 const lView = getLView();
18012 const interpolated = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
18013 if (interpolated !== NO_CHANGE) {
18014 textBindingInternal(lView, getSelectedIndex(), interpolated);
18015 }
18016 return ɵɵtextInterpolate8;
18017}
18018/**
18019 * Update text content with 9 or more bound values other surrounded by text.
18020 *
18021 * Used when the number of interpolated values exceeds 8.
18022 *
18023 * ```html
18024 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix</div>
18025 * ```
18026 *
18027 * Its compiled representation is:
18028 *
18029 * ```ts
18030 * ɵɵtextInterpolateV(
18031 * ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
18032 * 'suffix']);
18033 * ```
18034 *.
18035 * @param values The collection of values and the strings in between those values, beginning with
18036 * a string prefix and ending with a string suffix.
18037 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
18038 *
18039 * @returns itself, so that it may be chained.
18040 * @codeGenApi
18041 */
18042function ɵɵtextInterpolateV(values) {
18043 const lView = getLView();
18044 const interpolated = interpolationV(lView, values);
18045 if (interpolated !== NO_CHANGE) {
18046 textBindingInternal(lView, getSelectedIndex(), interpolated);
18047 }
18048 return ɵɵtextInterpolateV;
18049}
18050
18051/**
18052 * @license
18053 * Copyright Google LLC All Rights Reserved.
18054 *
18055 * Use of this source code is governed by an MIT-style license that can be
18056 * found in the LICENSE file at https://angular.io/license
18057 */
18058/**
18059 *
18060 * Update an interpolated class on an element with single bound value surrounded by text.
18061 *
18062 * Used when the value passed to a property has 1 interpolated value in it:
18063 *
18064 * ```html
18065 * <div class="prefix{{v0}}suffix"></div>
18066 * ```
18067 *
18068 * Its compiled representation is:
18069 *
18070 * ```ts
18071 * ɵɵclassMapInterpolate1('prefix', v0, 'suffix');
18072 * ```
18073 *
18074 * @param prefix Static value used for concatenation only.
18075 * @param v0 Value checked for change.
18076 * @param suffix Static value used for concatenation only.
18077 * @codeGenApi
18078 */
18079function ɵɵclassMapInterpolate1(prefix, v0, suffix) {
18080 const lView = getLView();
18081 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
18082 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18083}
18084/**
18085 *
18086 * Update an interpolated class on an element with 2 bound values surrounded by text.
18087 *
18088 * Used when the value passed to a property has 2 interpolated values in it:
18089 *
18090 * ```html
18091 * <div class="prefix{{v0}}-{{v1}}suffix"></div>
18092 * ```
18093 *
18094 * Its compiled representation is:
18095 *
18096 * ```ts
18097 * ɵɵclassMapInterpolate2('prefix', v0, '-', v1, 'suffix');
18098 * ```
18099 *
18100 * @param prefix Static value used for concatenation only.
18101 * @param v0 Value checked for change.
18102 * @param i0 Static value used for concatenation only.
18103 * @param v1 Value checked for change.
18104 * @param suffix Static value used for concatenation only.
18105 * @codeGenApi
18106 */
18107function ɵɵclassMapInterpolate2(prefix, v0, i0, v1, suffix) {
18108 const lView = getLView();
18109 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
18110 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18111}
18112/**
18113 *
18114 * Update an interpolated class on an element with 3 bound values surrounded by text.
18115 *
18116 * Used when the value passed to a property has 3 interpolated values in it:
18117 *
18118 * ```html
18119 * <div class="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
18120 * ```
18121 *
18122 * Its compiled representation is:
18123 *
18124 * ```ts
18125 * ɵɵclassMapInterpolate3(
18126 * 'prefix', v0, '-', v1, '-', v2, 'suffix');
18127 * ```
18128 *
18129 * @param prefix Static value used for concatenation only.
18130 * @param v0 Value checked for change.
18131 * @param i0 Static value used for concatenation only.
18132 * @param v1 Value checked for change.
18133 * @param i1 Static value used for concatenation only.
18134 * @param v2 Value checked for change.
18135 * @param suffix Static value used for concatenation only.
18136 * @codeGenApi
18137 */
18138function ɵɵclassMapInterpolate3(prefix, v0, i0, v1, i1, v2, suffix) {
18139 const lView = getLView();
18140 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
18141 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18142}
18143/**
18144 *
18145 * Update an interpolated class on an element with 4 bound values surrounded by text.
18146 *
18147 * Used when the value passed to a property has 4 interpolated values in it:
18148 *
18149 * ```html
18150 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
18151 * ```
18152 *
18153 * Its compiled representation is:
18154 *
18155 * ```ts
18156 * ɵɵclassMapInterpolate4(
18157 * 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
18158 * ```
18159 *
18160 * @param prefix Static value used for concatenation only.
18161 * @param v0 Value checked for change.
18162 * @param i0 Static value used for concatenation only.
18163 * @param v1 Value checked for change.
18164 * @param i1 Static value used for concatenation only.
18165 * @param v2 Value checked for change.
18166 * @param i2 Static value used for concatenation only.
18167 * @param v3 Value checked for change.
18168 * @param suffix Static value used for concatenation only.
18169 * @codeGenApi
18170 */
18171function ɵɵclassMapInterpolate4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
18172 const lView = getLView();
18173 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
18174 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18175}
18176/**
18177 *
18178 * Update an interpolated class on an element with 5 bound values surrounded by text.
18179 *
18180 * Used when the value passed to a property has 5 interpolated values in it:
18181 *
18182 * ```html
18183 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
18184 * ```
18185 *
18186 * Its compiled representation is:
18187 *
18188 * ```ts
18189 * ɵɵclassMapInterpolate5(
18190 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
18191 * ```
18192 *
18193 * @param prefix Static value used for concatenation only.
18194 * @param v0 Value checked for change.
18195 * @param i0 Static value used for concatenation only.
18196 * @param v1 Value checked for change.
18197 * @param i1 Static value used for concatenation only.
18198 * @param v2 Value checked for change.
18199 * @param i2 Static value used for concatenation only.
18200 * @param v3 Value checked for change.
18201 * @param i3 Static value used for concatenation only.
18202 * @param v4 Value checked for change.
18203 * @param suffix Static value used for concatenation only.
18204 * @codeGenApi
18205 */
18206function ɵɵclassMapInterpolate5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
18207 const lView = getLView();
18208 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
18209 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18210}
18211/**
18212 *
18213 * Update an interpolated class on an element with 6 bound values surrounded by text.
18214 *
18215 * Used when the value passed to a property has 6 interpolated values in it:
18216 *
18217 * ```html
18218 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
18219 * ```
18220 *
18221 * Its compiled representation is:
18222 *
18223 * ```ts
18224 * ɵɵclassMapInterpolate6(
18225 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
18226 * ```
18227 *
18228 * @param prefix Static value used for concatenation only.
18229 * @param v0 Value checked for change.
18230 * @param i0 Static value used for concatenation only.
18231 * @param v1 Value checked for change.
18232 * @param i1 Static value used for concatenation only.
18233 * @param v2 Value checked for change.
18234 * @param i2 Static value used for concatenation only.
18235 * @param v3 Value checked for change.
18236 * @param i3 Static value used for concatenation only.
18237 * @param v4 Value checked for change.
18238 * @param i4 Static value used for concatenation only.
18239 * @param v5 Value checked for change.
18240 * @param suffix Static value used for concatenation only.
18241 * @codeGenApi
18242 */
18243function ɵɵclassMapInterpolate6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
18244 const lView = getLView();
18245 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
18246 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18247}
18248/**
18249 *
18250 * Update an interpolated class on an element with 7 bound values surrounded by text.
18251 *
18252 * Used when the value passed to a property has 7 interpolated values in it:
18253 *
18254 * ```html
18255 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
18256 * ```
18257 *
18258 * Its compiled representation is:
18259 *
18260 * ```ts
18261 * ɵɵclassMapInterpolate7(
18262 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
18263 * ```
18264 *
18265 * @param prefix Static value used for concatenation only.
18266 * @param v0 Value checked for change.
18267 * @param i0 Static value used for concatenation only.
18268 * @param v1 Value checked for change.
18269 * @param i1 Static value used for concatenation only.
18270 * @param v2 Value checked for change.
18271 * @param i2 Static value used for concatenation only.
18272 * @param v3 Value checked for change.
18273 * @param i3 Static value used for concatenation only.
18274 * @param v4 Value checked for change.
18275 * @param i4 Static value used for concatenation only.
18276 * @param v5 Value checked for change.
18277 * @param i5 Static value used for concatenation only.
18278 * @param v6 Value checked for change.
18279 * @param suffix Static value used for concatenation only.
18280 * @codeGenApi
18281 */
18282function ɵɵclassMapInterpolate7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
18283 const lView = getLView();
18284 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
18285 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18286}
18287/**
18288 *
18289 * Update an interpolated class on an element with 8 bound values surrounded by text.
18290 *
18291 * Used when the value passed to a property has 8 interpolated values in it:
18292 *
18293 * ```html
18294 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
18295 * ```
18296 *
18297 * Its compiled representation is:
18298 *
18299 * ```ts
18300 * ɵɵclassMapInterpolate8(
18301 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
18302 * ```
18303 *
18304 * @param prefix Static value used for concatenation only.
18305 * @param v0 Value checked for change.
18306 * @param i0 Static value used for concatenation only.
18307 * @param v1 Value checked for change.
18308 * @param i1 Static value used for concatenation only.
18309 * @param v2 Value checked for change.
18310 * @param i2 Static value used for concatenation only.
18311 * @param v3 Value checked for change.
18312 * @param i3 Static value used for concatenation only.
18313 * @param v4 Value checked for change.
18314 * @param i4 Static value used for concatenation only.
18315 * @param v5 Value checked for change.
18316 * @param i5 Static value used for concatenation only.
18317 * @param v6 Value checked for change.
18318 * @param i6 Static value used for concatenation only.
18319 * @param v7 Value checked for change.
18320 * @param suffix Static value used for concatenation only.
18321 * @codeGenApi
18322 */
18323function ɵɵclassMapInterpolate8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
18324 const lView = getLView();
18325 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
18326 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18327}
18328/**
18329 * Update an interpolated class on an element with 9 or more bound values surrounded by text.
18330 *
18331 * Used when the number of interpolated values exceeds 8.
18332 *
18333 * ```html
18334 * <div
18335 * class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
18336 * ```
18337 *
18338 * Its compiled representation is:
18339 *
18340 * ```ts
18341 * ɵɵclassMapInterpolateV(
18342 * ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
18343 * 'suffix']);
18344 * ```
18345 *.
18346 * @param values The collection of values and the strings in-between those values, beginning with
18347 * a string prefix and ending with a string suffix.
18348 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
18349 * @codeGenApi
18350 */
18351function ɵɵclassMapInterpolateV(values) {
18352 const lView = getLView();
18353 const interpolatedValue = interpolationV(lView, values);
18354 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
18355}
18356
18357/**
18358 * @license
18359 * Copyright Google LLC All Rights Reserved.
18360 *
18361 * Use of this source code is governed by an MIT-style license that can be
18362 * found in the LICENSE file at https://angular.io/license
18363 */
18364/**
18365 *
18366 * Update an interpolated style on an element with single bound value surrounded by text.
18367 *
18368 * Used when the value passed to a property has 1 interpolated value in it:
18369 *
18370 * ```html
18371 * <div style="key: {{v0}}suffix"></div>
18372 * ```
18373 *
18374 * Its compiled representation is:
18375 *
18376 * ```ts
18377 * ɵɵstyleMapInterpolate1('key: ', v0, 'suffix');
18378 * ```
18379 *
18380 * @param prefix Static value used for concatenation only.
18381 * @param v0 Value checked for change.
18382 * @param suffix Static value used for concatenation only.
18383 * @codeGenApi
18384 */
18385function ɵɵstyleMapInterpolate1(prefix, v0, suffix) {
18386 const lView = getLView();
18387 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
18388 ɵɵstyleMap(interpolatedValue);
18389}
18390/**
18391 *
18392 * Update an interpolated style on an element with 2 bound values surrounded by text.
18393 *
18394 * Used when the value passed to a property has 2 interpolated values in it:
18395 *
18396 * ```html
18397 * <div style="key: {{v0}}; key1: {{v1}}suffix"></div>
18398 * ```
18399 *
18400 * Its compiled representation is:
18401 *
18402 * ```ts
18403 * ɵɵstyleMapInterpolate2('key: ', v0, '; key1: ', v1, 'suffix');
18404 * ```
18405 *
18406 * @param prefix Static value used for concatenation only.
18407 * @param v0 Value checked for change.
18408 * @param i0 Static value used for concatenation only.
18409 * @param v1 Value checked for change.
18410 * @param suffix Static value used for concatenation only.
18411 * @codeGenApi
18412 */
18413function ɵɵstyleMapInterpolate2(prefix, v0, i0, v1, suffix) {
18414 const lView = getLView();
18415 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
18416 ɵɵstyleMap(interpolatedValue);
18417}
18418/**
18419 *
18420 * Update an interpolated style on an element with 3 bound values surrounded by text.
18421 *
18422 * Used when the value passed to a property has 3 interpolated values in it:
18423 *
18424 * ```html
18425 * <div style="key: {{v0}}; key2: {{v1}}; key2: {{v2}}suffix"></div>
18426 * ```
18427 *
18428 * Its compiled representation is:
18429 *
18430 * ```ts
18431 * ɵɵstyleMapInterpolate3(
18432 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, 'suffix');
18433 * ```
18434 *
18435 * @param prefix Static value used for concatenation only.
18436 * @param v0 Value checked for change.
18437 * @param i0 Static value used for concatenation only.
18438 * @param v1 Value checked for change.
18439 * @param i1 Static value used for concatenation only.
18440 * @param v2 Value checked for change.
18441 * @param suffix Static value used for concatenation only.
18442 * @codeGenApi
18443 */
18444function ɵɵstyleMapInterpolate3(prefix, v0, i0, v1, i1, v2, suffix) {
18445 const lView = getLView();
18446 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
18447 ɵɵstyleMap(interpolatedValue);
18448}
18449/**
18450 *
18451 * Update an interpolated style on an element with 4 bound values surrounded by text.
18452 *
18453 * Used when the value passed to a property has 4 interpolated values in it:
18454 *
18455 * ```html
18456 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}suffix"></div>
18457 * ```
18458 *
18459 * Its compiled representation is:
18460 *
18461 * ```ts
18462 * ɵɵstyleMapInterpolate4(
18463 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, 'suffix');
18464 * ```
18465 *
18466 * @param prefix Static value used for concatenation only.
18467 * @param v0 Value checked for change.
18468 * @param i0 Static value used for concatenation only.
18469 * @param v1 Value checked for change.
18470 * @param i1 Static value used for concatenation only.
18471 * @param v2 Value checked for change.
18472 * @param i2 Static value used for concatenation only.
18473 * @param v3 Value checked for change.
18474 * @param suffix Static value used for concatenation only.
18475 * @codeGenApi
18476 */
18477function ɵɵstyleMapInterpolate4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
18478 const lView = getLView();
18479 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
18480 ɵɵstyleMap(interpolatedValue);
18481}
18482/**
18483 *
18484 * Update an interpolated style on an element with 5 bound values surrounded by text.
18485 *
18486 * Used when the value passed to a property has 5 interpolated values in it:
18487 *
18488 * ```html
18489 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}suffix"></div>
18490 * ```
18491 *
18492 * Its compiled representation is:
18493 *
18494 * ```ts
18495 * ɵɵstyleMapInterpolate5(
18496 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, 'suffix');
18497 * ```
18498 *
18499 * @param prefix Static value used for concatenation only.
18500 * @param v0 Value checked for change.
18501 * @param i0 Static value used for concatenation only.
18502 * @param v1 Value checked for change.
18503 * @param i1 Static value used for concatenation only.
18504 * @param v2 Value checked for change.
18505 * @param i2 Static value used for concatenation only.
18506 * @param v3 Value checked for change.
18507 * @param i3 Static value used for concatenation only.
18508 * @param v4 Value checked for change.
18509 * @param suffix Static value used for concatenation only.
18510 * @codeGenApi
18511 */
18512function ɵɵstyleMapInterpolate5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
18513 const lView = getLView();
18514 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
18515 ɵɵstyleMap(interpolatedValue);
18516}
18517/**
18518 *
18519 * Update an interpolated style on an element with 6 bound values surrounded by text.
18520 *
18521 * Used when the value passed to a property has 6 interpolated values in it:
18522 *
18523 * ```html
18524 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}};
18525 * key5: {{v5}}suffix"></div>
18526 * ```
18527 *
18528 * Its compiled representation is:
18529 *
18530 * ```ts
18531 * ɵɵstyleMapInterpolate6(
18532 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
18533 * 'suffix');
18534 * ```
18535 *
18536 * @param prefix Static value used for concatenation only.
18537 * @param v0 Value checked for change.
18538 * @param i0 Static value used for concatenation only.
18539 * @param v1 Value checked for change.
18540 * @param i1 Static value used for concatenation only.
18541 * @param v2 Value checked for change.
18542 * @param i2 Static value used for concatenation only.
18543 * @param v3 Value checked for change.
18544 * @param i3 Static value used for concatenation only.
18545 * @param v4 Value checked for change.
18546 * @param i4 Static value used for concatenation only.
18547 * @param v5 Value checked for change.
18548 * @param suffix Static value used for concatenation only.
18549 * @codeGenApi
18550 */
18551function ɵɵstyleMapInterpolate6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
18552 const lView = getLView();
18553 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
18554 ɵɵstyleMap(interpolatedValue);
18555}
18556/**
18557 *
18558 * Update an interpolated style on an element with 7 bound values surrounded by text.
18559 *
18560 * Used when the value passed to a property has 7 interpolated values in it:
18561 *
18562 * ```html
18563 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}; key5: {{v5}};
18564 * key6: {{v6}}suffix"></div>
18565 * ```
18566 *
18567 * Its compiled representation is:
18568 *
18569 * ```ts
18570 * ɵɵstyleMapInterpolate7(
18571 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
18572 * '; key6: ', v6, 'suffix');
18573 * ```
18574 *
18575 * @param prefix Static value used for concatenation only.
18576 * @param v0 Value checked for change.
18577 * @param i0 Static value used for concatenation only.
18578 * @param v1 Value checked for change.
18579 * @param i1 Static value used for concatenation only.
18580 * @param v2 Value checked for change.
18581 * @param i2 Static value used for concatenation only.
18582 * @param v3 Value checked for change.
18583 * @param i3 Static value used for concatenation only.
18584 * @param v4 Value checked for change.
18585 * @param i4 Static value used for concatenation only.
18586 * @param v5 Value checked for change.
18587 * @param i5 Static value used for concatenation only.
18588 * @param v6 Value checked for change.
18589 * @param suffix Static value used for concatenation only.
18590 * @codeGenApi
18591 */
18592function ɵɵstyleMapInterpolate7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
18593 const lView = getLView();
18594 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
18595 ɵɵstyleMap(interpolatedValue);
18596}
18597/**
18598 *
18599 * Update an interpolated style on an element with 8 bound values surrounded by text.
18600 *
18601 * Used when the value passed to a property has 8 interpolated values in it:
18602 *
18603 * ```html
18604 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}; key5: {{v5}};
18605 * key6: {{v6}}; key7: {{v7}}suffix"></div>
18606 * ```
18607 *
18608 * Its compiled representation is:
18609 *
18610 * ```ts
18611 * ɵɵstyleMapInterpolate8(
18612 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
18613 * '; key6: ', v6, '; key7: ', v7, 'suffix');
18614 * ```
18615 *
18616 * @param prefix Static value used for concatenation only.
18617 * @param v0 Value checked for change.
18618 * @param i0 Static value used for concatenation only.
18619 * @param v1 Value checked for change.
18620 * @param i1 Static value used for concatenation only.
18621 * @param v2 Value checked for change.
18622 * @param i2 Static value used for concatenation only.
18623 * @param v3 Value checked for change.
18624 * @param i3 Static value used for concatenation only.
18625 * @param v4 Value checked for change.
18626 * @param i4 Static value used for concatenation only.
18627 * @param v5 Value checked for change.
18628 * @param i5 Static value used for concatenation only.
18629 * @param v6 Value checked for change.
18630 * @param i6 Static value used for concatenation only.
18631 * @param v7 Value checked for change.
18632 * @param suffix Static value used for concatenation only.
18633 * @codeGenApi
18634 */
18635function ɵɵstyleMapInterpolate8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
18636 const lView = getLView();
18637 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
18638 ɵɵstyleMap(interpolatedValue);
18639}
18640/**
18641 * Update an interpolated style on an element with 9 or more bound values surrounded by text.
18642 *
18643 * Used when the number of interpolated values exceeds 8.
18644 *
18645 * ```html
18646 * <div
18647 * class="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}; key5: {{v5}};
18648 * key6: {{v6}}; key7: {{v7}}; key8: {{v8}}; key9: {{v9}}suffix"></div>
18649 * ```
18650 *
18651 * Its compiled representation is:
18652 *
18653 * ```ts
18654 * ɵɵstyleMapInterpolateV(
18655 * ['key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
18656 * '; key6: ', v6, '; key7: ', v7, '; key8: ', v8, '; key9: ', v9, 'suffix']);
18657 * ```
18658 *.
18659 * @param values The collection of values and the strings in-between those values, beginning with
18660 * a string prefix and ending with a string suffix.
18661 * (e.g. `['prefix', value0, '; key2: ', value1, '; key2: ', value2, ..., value99, 'suffix']`)
18662 * @codeGenApi
18663 */
18664function ɵɵstyleMapInterpolateV(values) {
18665 const lView = getLView();
18666 const interpolatedValue = interpolationV(lView, values);
18667 ɵɵstyleMap(interpolatedValue);
18668}
18669
18670/**
18671 * @license
18672 * Copyright Google LLC All Rights Reserved.
18673 *
18674 * Use of this source code is governed by an MIT-style license that can be
18675 * found in the LICENSE file at https://angular.io/license
18676 */
18677/**
18678 *
18679 * Update an interpolated style property on an element with single bound value surrounded by text.
18680 *
18681 * Used when the value passed to a property has 1 interpolated value in it:
18682 *
18683 * ```html
18684 * <div style.color="prefix{{v0}}suffix"></div>
18685 * ```
18686 *
18687 * Its compiled representation is:
18688 *
18689 * ```ts
18690 * ɵɵstylePropInterpolate1(0, 'prefix', v0, 'suffix');
18691 * ```
18692 *
18693 * @param styleIndex Index of style to update. This index value refers to the
18694 * index of the style in the style bindings array that was passed into
18695 * `styling`.
18696 * @param prefix Static value used for concatenation only.
18697 * @param v0 Value checked for change.
18698 * @param suffix Static value used for concatenation only.
18699 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18700 * @returns itself, so that it may be chained.
18701 * @codeGenApi
18702 */
18703function ɵɵstylePropInterpolate1(prop, prefix, v0, suffix, valueSuffix) {
18704 const lView = getLView();
18705 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
18706 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18707 return ɵɵstylePropInterpolate1;
18708}
18709/**
18710 *
18711 * Update an interpolated style property on an element with 2 bound values surrounded by text.
18712 *
18713 * Used when the value passed to a property has 2 interpolated values in it:
18714 *
18715 * ```html
18716 * <div style.color="prefix{{v0}}-{{v1}}suffix"></div>
18717 * ```
18718 *
18719 * Its compiled representation is:
18720 *
18721 * ```ts
18722 * ɵɵstylePropInterpolate2(0, 'prefix', v0, '-', v1, 'suffix');
18723 * ```
18724 *
18725 * @param styleIndex Index of style to update. This index value refers to the
18726 * index of the style in the style bindings array that was passed into
18727 * `styling`.
18728 * @param prefix Static value used for concatenation only.
18729 * @param v0 Value checked for change.
18730 * @param i0 Static value used for concatenation only.
18731 * @param v1 Value checked for change.
18732 * @param suffix Static value used for concatenation only.
18733 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18734 * @returns itself, so that it may be chained.
18735 * @codeGenApi
18736 */
18737function ɵɵstylePropInterpolate2(prop, prefix, v0, i0, v1, suffix, valueSuffix) {
18738 const lView = getLView();
18739 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
18740 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18741 return ɵɵstylePropInterpolate2;
18742}
18743/**
18744 *
18745 * Update an interpolated style property on an element with 3 bound values surrounded by text.
18746 *
18747 * Used when the value passed to a property has 3 interpolated values in it:
18748 *
18749 * ```html
18750 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
18751 * ```
18752 *
18753 * Its compiled representation is:
18754 *
18755 * ```ts
18756 * ɵɵstylePropInterpolate3(0, 'prefix', v0, '-', v1, '-', v2, 'suffix');
18757 * ```
18758 *
18759 * @param styleIndex Index of style to update. This index value refers to the
18760 * index of the style in the style bindings array that was passed into
18761 * `styling`.
18762 * @param prefix Static value used for concatenation only.
18763 * @param v0 Value checked for change.
18764 * @param i0 Static value used for concatenation only.
18765 * @param v1 Value checked for change.
18766 * @param i1 Static value used for concatenation only.
18767 * @param v2 Value checked for change.
18768 * @param suffix Static value used for concatenation only.
18769 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18770 * @returns itself, so that it may be chained.
18771 * @codeGenApi
18772 */
18773function ɵɵstylePropInterpolate3(prop, prefix, v0, i0, v1, i1, v2, suffix, valueSuffix) {
18774 const lView = getLView();
18775 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
18776 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18777 return ɵɵstylePropInterpolate3;
18778}
18779/**
18780 *
18781 * Update an interpolated style property on an element with 4 bound values surrounded by text.
18782 *
18783 * Used when the value passed to a property has 4 interpolated values in it:
18784 *
18785 * ```html
18786 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
18787 * ```
18788 *
18789 * Its compiled representation is:
18790 *
18791 * ```ts
18792 * ɵɵstylePropInterpolate4(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
18793 * ```
18794 *
18795 * @param styleIndex Index of style to update. This index value refers to the
18796 * index of the style in the style bindings array that was passed into
18797 * `styling`.
18798 * @param prefix Static value used for concatenation only.
18799 * @param v0 Value checked for change.
18800 * @param i0 Static value used for concatenation only.
18801 * @param v1 Value checked for change.
18802 * @param i1 Static value used for concatenation only.
18803 * @param v2 Value checked for change.
18804 * @param i2 Static value used for concatenation only.
18805 * @param v3 Value checked for change.
18806 * @param suffix Static value used for concatenation only.
18807 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18808 * @returns itself, so that it may be chained.
18809 * @codeGenApi
18810 */
18811function ɵɵstylePropInterpolate4(prop, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, valueSuffix) {
18812 const lView = getLView();
18813 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
18814 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18815 return ɵɵstylePropInterpolate4;
18816}
18817/**
18818 *
18819 * Update an interpolated style property on an element with 5 bound values surrounded by text.
18820 *
18821 * Used when the value passed to a property has 5 interpolated values in it:
18822 *
18823 * ```html
18824 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
18825 * ```
18826 *
18827 * Its compiled representation is:
18828 *
18829 * ```ts
18830 * ɵɵstylePropInterpolate5(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
18831 * ```
18832 *
18833 * @param styleIndex Index of style to update. This index value refers to the
18834 * index of the style in the style bindings array that was passed into
18835 * `styling`.
18836 * @param prefix Static value used for concatenation only.
18837 * @param v0 Value checked for change.
18838 * @param i0 Static value used for concatenation only.
18839 * @param v1 Value checked for change.
18840 * @param i1 Static value used for concatenation only.
18841 * @param v2 Value checked for change.
18842 * @param i2 Static value used for concatenation only.
18843 * @param v3 Value checked for change.
18844 * @param i3 Static value used for concatenation only.
18845 * @param v4 Value checked for change.
18846 * @param suffix Static value used for concatenation only.
18847 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18848 * @returns itself, so that it may be chained.
18849 * @codeGenApi
18850 */
18851function ɵɵstylePropInterpolate5(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, valueSuffix) {
18852 const lView = getLView();
18853 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
18854 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18855 return ɵɵstylePropInterpolate5;
18856}
18857/**
18858 *
18859 * Update an interpolated style property on an element with 6 bound values surrounded by text.
18860 *
18861 * Used when the value passed to a property has 6 interpolated values in it:
18862 *
18863 * ```html
18864 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
18865 * ```
18866 *
18867 * Its compiled representation is:
18868 *
18869 * ```ts
18870 * ɵɵstylePropInterpolate6(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
18871 * ```
18872 *
18873 * @param styleIndex Index of style to update. This index value refers to the
18874 * index of the style in the style bindings array that was passed into
18875 * `styling`.
18876 * @param prefix Static value used for concatenation only.
18877 * @param v0 Value checked for change.
18878 * @param i0 Static value used for concatenation only.
18879 * @param v1 Value checked for change.
18880 * @param i1 Static value used for concatenation only.
18881 * @param v2 Value checked for change.
18882 * @param i2 Static value used for concatenation only.
18883 * @param v3 Value checked for change.
18884 * @param i3 Static value used for concatenation only.
18885 * @param v4 Value checked for change.
18886 * @param i4 Static value used for concatenation only.
18887 * @param v5 Value checked for change.
18888 * @param suffix Static value used for concatenation only.
18889 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18890 * @returns itself, so that it may be chained.
18891 * @codeGenApi
18892 */
18893function ɵɵstylePropInterpolate6(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, valueSuffix) {
18894 const lView = getLView();
18895 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
18896 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18897 return ɵɵstylePropInterpolate6;
18898}
18899/**
18900 *
18901 * Update an interpolated style property on an element with 7 bound values surrounded by text.
18902 *
18903 * Used when the value passed to a property has 7 interpolated values in it:
18904 *
18905 * ```html
18906 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
18907 * ```
18908 *
18909 * Its compiled representation is:
18910 *
18911 * ```ts
18912 * ɵɵstylePropInterpolate7(
18913 * 0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
18914 * ```
18915 *
18916 * @param styleIndex Index of style to update. This index value refers to the
18917 * index of the style in the style bindings array that was passed into
18918 * `styling`.
18919 * @param prefix Static value used for concatenation only.
18920 * @param v0 Value checked for change.
18921 * @param i0 Static value used for concatenation only.
18922 * @param v1 Value checked for change.
18923 * @param i1 Static value used for concatenation only.
18924 * @param v2 Value checked for change.
18925 * @param i2 Static value used for concatenation only.
18926 * @param v3 Value checked for change.
18927 * @param i3 Static value used for concatenation only.
18928 * @param v4 Value checked for change.
18929 * @param i4 Static value used for concatenation only.
18930 * @param v5 Value checked for change.
18931 * @param i5 Static value used for concatenation only.
18932 * @param v6 Value checked for change.
18933 * @param suffix Static value used for concatenation only.
18934 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18935 * @returns itself, so that it may be chained.
18936 * @codeGenApi
18937 */
18938function ɵɵstylePropInterpolate7(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, valueSuffix) {
18939 const lView = getLView();
18940 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
18941 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18942 return ɵɵstylePropInterpolate7;
18943}
18944/**
18945 *
18946 * Update an interpolated style property on an element with 8 bound values surrounded by text.
18947 *
18948 * Used when the value passed to a property has 8 interpolated values in it:
18949 *
18950 * ```html
18951 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
18952 * ```
18953 *
18954 * Its compiled representation is:
18955 *
18956 * ```ts
18957 * ɵɵstylePropInterpolate8(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6,
18958 * '-', v7, 'suffix');
18959 * ```
18960 *
18961 * @param styleIndex Index of style to update. This index value refers to the
18962 * index of the style in the style bindings array that was passed into
18963 * `styling`.
18964 * @param prefix Static value used for concatenation only.
18965 * @param v0 Value checked for change.
18966 * @param i0 Static value used for concatenation only.
18967 * @param v1 Value checked for change.
18968 * @param i1 Static value used for concatenation only.
18969 * @param v2 Value checked for change.
18970 * @param i2 Static value used for concatenation only.
18971 * @param v3 Value checked for change.
18972 * @param i3 Static value used for concatenation only.
18973 * @param v4 Value checked for change.
18974 * @param i4 Static value used for concatenation only.
18975 * @param v5 Value checked for change.
18976 * @param i5 Static value used for concatenation only.
18977 * @param v6 Value checked for change.
18978 * @param i6 Static value used for concatenation only.
18979 * @param v7 Value checked for change.
18980 * @param suffix Static value used for concatenation only.
18981 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18982 * @returns itself, so that it may be chained.
18983 * @codeGenApi
18984 */
18985function ɵɵstylePropInterpolate8(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, valueSuffix) {
18986 const lView = getLView();
18987 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
18988 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18989 return ɵɵstylePropInterpolate8;
18990}
18991/**
18992 * Update an interpolated style property on an element with 9 or more bound values surrounded by
18993 * text.
18994 *
18995 * Used when the number of interpolated values exceeds 8.
18996 *
18997 * ```html
18998 * <div
18999 * style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix">
19000 * </div>
19001 * ```
19002 *
19003 * Its compiled representation is:
19004 *
19005 * ```ts
19006 * ɵɵstylePropInterpolateV(
19007 * 0, ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
19008 * 'suffix']);
19009 * ```
19010 *
19011 * @param styleIndex Index of style to update. This index value refers to the
19012 * index of the style in the style bindings array that was passed into
19013 * `styling`..
19014 * @param values The collection of values and the strings in-between those values, beginning with
19015 * a string prefix and ending with a string suffix.
19016 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
19017 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
19018 * @returns itself, so that it may be chained.
19019 * @codeGenApi
19020 */
19021function ɵɵstylePropInterpolateV(prop, values, valueSuffix) {
19022 const lView = getLView();
19023 const interpolatedValue = interpolationV(lView, values);
19024 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
19025 return ɵɵstylePropInterpolateV;
19026}
19027
19028/**
19029 * @license
19030 * Copyright Google LLC All Rights Reserved.
19031 *
19032 * Use of this source code is governed by an MIT-style license that can be
19033 * found in the LICENSE file at https://angular.io/license
19034 */
19035/**
19036 * Update a property on a host element. Only applies to native node properties, not inputs.
19037 *
19038 * Operates on the element selected by index via the {@link select} instruction.
19039 *
19040 * @param propName Name of property. Because it is going to DOM, this is not subject to
19041 * renaming as part of minification.
19042 * @param value New value to write.
19043 * @param sanitizer An optional function used to sanitize the value.
19044 * @returns This function returns itself so that it may be chained
19045 * (e.g. `property('name', ctx.name)('title', ctx.title)`)
19046 *
19047 * @codeGenApi
19048 */
19049function ɵɵhostProperty(propName, value, sanitizer) {
19050 const lView = getLView();
19051 const bindingIndex = nextBindingIndex();
19052 if (bindingUpdated(lView, bindingIndex, value)) {
19053 const tView = getTView();
19054 const tNode = getSelectedTNode();
19055 elementPropertyInternal(tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, true);
19056 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
19057 }
19058 return ɵɵhostProperty;
19059}
19060/**
19061 * Updates a synthetic host binding (e.g. `[@foo]`) on a component or directive.
19062 *
19063 * This instruction is for compatibility purposes and is designed to ensure that a
19064 * synthetic host binding (e.g. `@HostBinding('@foo')`) properly gets rendered in
19065 * the component's renderer. Normally all host bindings are evaluated with the parent
19066 * component's renderer, but, in the case of animation @triggers, they need to be
19067 * evaluated with the sub component's renderer (because that's where the animation
19068 * triggers are defined).
19069 *
19070 * Do not use this instruction as a replacement for `elementProperty`. This instruction
19071 * only exists to ensure compatibility with the ViewEngine's host binding behavior.
19072 *
19073 * @param index The index of the element to update in the data array
19074 * @param propName Name of property. Because it is going to DOM, this is not subject to
19075 * renaming as part of minification.
19076 * @param value New value to write.
19077 * @param sanitizer An optional function used to sanitize the value.
19078 *
19079 * @codeGenApi
19080 */
19081function ɵɵsyntheticHostProperty(propName, value, sanitizer) {
19082 const lView = getLView();
19083 const bindingIndex = nextBindingIndex();
19084 if (bindingUpdated(lView, bindingIndex, value)) {
19085 const tView = getTView();
19086 const tNode = getSelectedTNode();
19087 const currentDef = getCurrentDirectiveDef(tView.data);
19088 const renderer = loadComponentRenderer(currentDef, tNode, lView);
19089 elementPropertyInternal(tView, tNode, lView, propName, value, renderer, sanitizer, true);
19090 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
19091 }
19092 return ɵɵsyntheticHostProperty;
19093}
19094
19095/**
19096 * @license
19097 * Copyright Google LLC All Rights Reserved.
19098 *
19099 * Use of this source code is governed by an MIT-style license that can be
19100 * found in the LICENSE file at https://angular.io/license
19101 */
19102/**
19103 * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
19104 */
19105if (typeof ngI18nClosureMode === 'undefined') {
19106 // These property accesses can be ignored because ngI18nClosureMode will be set to false
19107 // when optimizing code and the whole if statement will be dropped.
19108 // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
19109 // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
19110 (function () {
19111 // tslint:disable-next-line:no-toplevel-property-access
19112 _global['ngI18nClosureMode'] =
19113 // TODO(FW-1250): validate that this actually, you know, works.
19114 // tslint:disable-next-line:no-toplevel-property-access
19115 typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
19116 })();
19117}
19118
19119/**
19120 * @license
19121 * Copyright Google LLC All Rights Reserved.
19122 *
19123 * Use of this source code is governed by an MIT-style license that can be
19124 * found in the LICENSE file at https://angular.io/license
19125 */
19126// THIS CODE IS GENERATED - DO NOT MODIFY.
19127const u = undefined;
19128function plural(val) {
19129 const n = val, i = Math.floor(Math.abs(val)), v = val.toString().replace(/^[^.]*\.?/, '').length;
19130 if (i === 1 && v === 0)
19131 return 1;
19132 return 5;
19133}
19134var localeEn = ["en", [["a", "p"], ["AM", "PM"], u], [["AM", "PM"], u, u], [["S", "M", "T", "W", "T", "F", "S"], ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]], u, [["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"], ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]], u, [["B", "A"], ["BC", "AD"], ["Before Christ", "Anno Domini"]], 0, [6, 0], ["M/d/yy", "MMM d, y", "MMMM d, y", "EEEE, MMMM d, y"], ["h:mm a", "h:mm:ss a", "h:mm:ss a z", "h:mm:ss a zzzz"], ["{1}, {0}", u, "{1} 'at' {0}", u], [".", ",", ";", "%", "+", "-", "E", "×", "‰", "∞", "NaN", ":"], ["#,##0.###", "#,##0%", "¤#,##0.00", "#E0"], "USD", "$", "US Dollar", {}, "ltr", plural];
19135
19136/**
19137 * @license
19138 * Copyright Google LLC All Rights Reserved.
19139 *
19140 * Use of this source code is governed by an MIT-style license that can be
19141 * found in the LICENSE file at https://angular.io/license
19142 */
19143/**
19144 * This const is used to store the locale data registered with `registerLocaleData`
19145 */
19146let LOCALE_DATA = {};
19147/**
19148 * Register locale data to be used internally by Angular. See the
19149 * ["I18n guide"](guide/i18n-common-format-data-locale) to know how to import additional locale
19150 * data.
19151 *
19152 * The signature `registerLocaleData(data: any, extraData?: any)` is deprecated since v5.1
19153 */
19154function registerLocaleData(data, localeId, extraData) {
19155 if (typeof localeId !== 'string') {
19156 extraData = localeId;
19157 localeId = data[LocaleDataIndex.LocaleId];
19158 }
19159 localeId = localeId.toLowerCase().replace(/_/g, '-');
19160 LOCALE_DATA[localeId] = data;
19161 if (extraData) {
19162 LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData;
19163 }
19164}
19165/**
19166 * Finds the locale data for a given locale.
19167 *
19168 * @param locale The locale code.
19169 * @returns The locale data.
19170 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
19171 */
19172function findLocaleData(locale) {
19173 const normalizedLocale = normalizeLocale(locale);
19174 let match = getLocaleData(normalizedLocale);
19175 if (match) {
19176 return match;
19177 }
19178 // let's try to find a parent locale
19179 const parentLocale = normalizedLocale.split('-')[0];
19180 match = getLocaleData(parentLocale);
19181 if (match) {
19182 return match;
19183 }
19184 if (parentLocale === 'en') {
19185 return localeEn;
19186 }
19187 throw new Error(`Missing locale data for the locale "${locale}".`);
19188}
19189/**
19190 * Retrieves the default currency code for the given locale.
19191 *
19192 * The default is defined as the first currency which is still in use.
19193 *
19194 * @param locale The code of the locale whose currency code we want.
19195 * @returns The code of the default currency for the given locale.
19196 *
19197 */
19198function getLocaleCurrencyCode(locale) {
19199 const data = findLocaleData(locale);
19200 return data[LocaleDataIndex.CurrencyCode] || null;
19201}
19202/**
19203 * Retrieves the plural function used by ICU expressions to determine the plural case to use
19204 * for a given locale.
19205 * @param locale A locale code for the locale format rules to use.
19206 * @returns The plural function for the locale.
19207 * @see `NgPlural`
19208 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
19209 */
19210function getLocalePluralCase(locale) {
19211 const data = findLocaleData(locale);
19212 return data[LocaleDataIndex.PluralCase];
19213}
19214/**
19215 * Helper function to get the given `normalizedLocale` from `LOCALE_DATA`
19216 * or from the global `ng.common.locale`.
19217 */
19218function getLocaleData(normalizedLocale) {
19219 if (!(normalizedLocale in LOCALE_DATA)) {
19220 LOCALE_DATA[normalizedLocale] = _global.ng && _global.ng.common && _global.ng.common.locales &&
19221 _global.ng.common.locales[normalizedLocale];
19222 }
19223 return LOCALE_DATA[normalizedLocale];
19224}
19225/**
19226 * Helper function to remove all the locale data from `LOCALE_DATA`.
19227 */
19228function unregisterAllLocaleData() {
19229 LOCALE_DATA = {};
19230}
19231/**
19232 * Index of each type of locale data from the locale data array
19233 */
19234var LocaleDataIndex;
19235(function (LocaleDataIndex) {
19236 LocaleDataIndex[LocaleDataIndex["LocaleId"] = 0] = "LocaleId";
19237 LocaleDataIndex[LocaleDataIndex["DayPeriodsFormat"] = 1] = "DayPeriodsFormat";
19238 LocaleDataIndex[LocaleDataIndex["DayPeriodsStandalone"] = 2] = "DayPeriodsStandalone";
19239 LocaleDataIndex[LocaleDataIndex["DaysFormat"] = 3] = "DaysFormat";
19240 LocaleDataIndex[LocaleDataIndex["DaysStandalone"] = 4] = "DaysStandalone";
19241 LocaleDataIndex[LocaleDataIndex["MonthsFormat"] = 5] = "MonthsFormat";
19242 LocaleDataIndex[LocaleDataIndex["MonthsStandalone"] = 6] = "MonthsStandalone";
19243 LocaleDataIndex[LocaleDataIndex["Eras"] = 7] = "Eras";
19244 LocaleDataIndex[LocaleDataIndex["FirstDayOfWeek"] = 8] = "FirstDayOfWeek";
19245 LocaleDataIndex[LocaleDataIndex["WeekendRange"] = 9] = "WeekendRange";
19246 LocaleDataIndex[LocaleDataIndex["DateFormat"] = 10] = "DateFormat";
19247 LocaleDataIndex[LocaleDataIndex["TimeFormat"] = 11] = "TimeFormat";
19248 LocaleDataIndex[LocaleDataIndex["DateTimeFormat"] = 12] = "DateTimeFormat";
19249 LocaleDataIndex[LocaleDataIndex["NumberSymbols"] = 13] = "NumberSymbols";
19250 LocaleDataIndex[LocaleDataIndex["NumberFormats"] = 14] = "NumberFormats";
19251 LocaleDataIndex[LocaleDataIndex["CurrencyCode"] = 15] = "CurrencyCode";
19252 LocaleDataIndex[LocaleDataIndex["CurrencySymbol"] = 16] = "CurrencySymbol";
19253 LocaleDataIndex[LocaleDataIndex["CurrencyName"] = 17] = "CurrencyName";
19254 LocaleDataIndex[LocaleDataIndex["Currencies"] = 18] = "Currencies";
19255 LocaleDataIndex[LocaleDataIndex["Directionality"] = 19] = "Directionality";
19256 LocaleDataIndex[LocaleDataIndex["PluralCase"] = 20] = "PluralCase";
19257 LocaleDataIndex[LocaleDataIndex["ExtraData"] = 21] = "ExtraData";
19258})(LocaleDataIndex || (LocaleDataIndex = {}));
19259/**
19260 * Returns the canonical form of a locale name - lowercase with `_` replaced with `-`.
19261 */
19262function normalizeLocale(locale) {
19263 return locale.toLowerCase().replace(/_/g, '-');
19264}
19265
19266/**
19267 * @license
19268 * Copyright Google LLC All Rights Reserved.
19269 *
19270 * Use of this source code is governed by an MIT-style license that can be
19271 * found in the LICENSE file at https://angular.io/license
19272 */
19273const pluralMapping = ['zero', 'one', 'two', 'few', 'many'];
19274/**
19275 * Returns the plural case based on the locale
19276 */
19277function getPluralCase(value, locale) {
19278 const plural = getLocalePluralCase(locale)(parseInt(value, 10));
19279 const result = pluralMapping[plural];
19280 return (result !== undefined) ? result : 'other';
19281}
19282/**
19283 * The locale id that the application is using by default (for translations and ICU expressions).
19284 */
19285const DEFAULT_LOCALE_ID = 'en-US';
19286/**
19287 * USD currency code that the application uses by default for CurrencyPipe when no
19288 * DEFAULT_CURRENCY_CODE is provided.
19289 */
19290const USD_CURRENCY_CODE = 'USD';
19291
19292/**
19293 * @license
19294 * Copyright Google LLC All Rights Reserved.
19295 *
19296 * Use of this source code is governed by an MIT-style license that can be
19297 * found in the LICENSE file at https://angular.io/license
19298 */
19299/**
19300 * Marks that the next string is an element name.
19301 *
19302 * See `I18nMutateOpCodes` documentation.
19303 */
19304const ELEMENT_MARKER = {
19305 marker: 'element'
19306};
19307/**
19308 * Marks that the next string is comment text need for ICU.
19309 *
19310 * See `I18nMutateOpCodes` documentation.
19311 */
19312const ICU_MARKER = {
19313 marker: 'ICU'
19314};
19315/**
19316 * See `I18nCreateOpCodes`
19317 */
19318var I18nCreateOpCode;
19319(function (I18nCreateOpCode) {
19320 /**
19321 * Number of bits to shift index so that it can be combined with the `APPEND_EAGERLY` and
19322 * `COMMENT`.
19323 */
19324 I18nCreateOpCode[I18nCreateOpCode["SHIFT"] = 2] = "SHIFT";
19325 /**
19326 * Should the node be appended to parent imedditatly after creation.
19327 */
19328 I18nCreateOpCode[I18nCreateOpCode["APPEND_EAGERLY"] = 1] = "APPEND_EAGERLY";
19329 /**
19330 * If set the node should be comment (rather than a text) node.
19331 */
19332 I18nCreateOpCode[I18nCreateOpCode["COMMENT"] = 2] = "COMMENT";
19333})(I18nCreateOpCode || (I18nCreateOpCode = {}));
19334// Note: This hack is necessary so we don't erroneously get a circular dependency
19335// failure based on types.
19336const unusedValueExportToPlacateAjd$2 = 1;
19337
19338/**
19339 * @license
19340 * Copyright Google LLC All Rights Reserved.
19341 *
19342 * Use of this source code is governed by an MIT-style license that can be
19343 * found in the LICENSE file at https://angular.io/license
19344 */
19345/**
19346 * The locale id that the application is currently using (for translations and ICU expressions).
19347 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
19348 * but is now defined as a global value.
19349 */
19350let LOCALE_ID$1 = DEFAULT_LOCALE_ID;
19351/**
19352 * Sets the locale id that will be used for translations and ICU expressions.
19353 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
19354 * but is now defined as a global value.
19355 *
19356 * @param localeId
19357 */
19358function setLocaleId(localeId) {
19359 assertDefined(localeId, `Expected localeId to be defined`);
19360 if (typeof localeId === 'string') {
19361 LOCALE_ID$1 = localeId.toLowerCase().replace(/_/g, '-');
19362 }
19363}
19364/**
19365 * Gets the locale id that will be used for translations and ICU expressions.
19366 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
19367 * but is now defined as a global value.
19368 */
19369function getLocaleId() {
19370 return LOCALE_ID$1;
19371}
19372
19373/**
19374 * @license
19375 * Copyright Google LLC All Rights Reserved.
19376 *
19377 * Use of this source code is governed by an MIT-style license that can be
19378 * found in the LICENSE file at https://angular.io/license
19379 */
19380/**
19381 * Find a node in front of which `currentTNode` should be inserted (takes i18n into account).
19382 *
19383 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
19384 * takes `TNode.insertBeforeIndex` into account.
19385 *
19386 * @param parentTNode parent `TNode`
19387 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
19388 * @param lView current `LView`
19389 */
19390function getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView) {
19391 const tNodeInsertBeforeIndex = currentTNode.insertBeforeIndex;
19392 const insertBeforeIndex = Array.isArray(tNodeInsertBeforeIndex) ? tNodeInsertBeforeIndex[0] : tNodeInsertBeforeIndex;
19393 if (insertBeforeIndex === null) {
19394 return getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView);
19395 }
19396 else {
19397 ngDevMode && assertIndexInRange(lView, insertBeforeIndex);
19398 return unwrapRNode(lView[insertBeforeIndex]);
19399 }
19400}
19401/**
19402 * Process `TNode.insertBeforeIndex` by adding i18n text nodes.
19403 *
19404 * See `TNode.insertBeforeIndex`
19405 */
19406function processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRElement) {
19407 const tNodeInsertBeforeIndex = childTNode.insertBeforeIndex;
19408 if (Array.isArray(tNodeInsertBeforeIndex)) {
19409 // An array indicates that there are i18n nodes that need to be added as children of this
19410 // `childRNode`. These i18n nodes were created before this `childRNode` was available and so
19411 // only now can be added. The first element of the array is the normal index where we should
19412 // insert the `childRNode`. Additional elements are the extra nodes to be added as children of
19413 // `childRNode`.
19414 ngDevMode && assertDomNode(childRNode);
19415 let i18nParent = childRNode;
19416 let anchorRNode = null;
19417 if (!(childTNode.type & 3 /* TNodeType.AnyRNode */)) {
19418 anchorRNode = i18nParent;
19419 i18nParent = parentRElement;
19420 }
19421 if (i18nParent !== null && (childTNode.flags & 2 /* TNodeFlags.isComponentHost */) === 0) {
19422 for (let i = 1; i < tNodeInsertBeforeIndex.length; i++) {
19423 // No need to `unwrapRNode` because all of the indexes point to i18n text nodes.
19424 // see `assertDomNode` below.
19425 const i18nChild = lView[tNodeInsertBeforeIndex[i]];
19426 nativeInsertBefore(renderer, i18nParent, i18nChild, anchorRNode, false);
19427 }
19428 }
19429 }
19430}
19431
19432/**
19433 * @license
19434 * Copyright Google LLC All Rights Reserved.
19435 *
19436 * Use of this source code is governed by an MIT-style license that can be
19437 * found in the LICENSE file at https://angular.io/license
19438 */
19439/**
19440 * Add `tNode` to `previousTNodes` list and update relevant `TNode`s in `previousTNodes` list
19441 * `tNode.insertBeforeIndex`.
19442 *
19443 * Things to keep in mind:
19444 * 1. All i18n text nodes are encoded as `TNodeType.Element` and are created eagerly by the
19445 * `ɵɵi18nStart` instruction.
19446 * 2. All `TNodeType.Placeholder` `TNodes` are elements which will be created later by
19447 * `ɵɵelementStart` instruction.
19448 * 3. `ɵɵelementStart` instruction will create `TNode`s in the ascending `TNode.index` order. (So a
19449 * smaller index `TNode` is guaranteed to be created before a larger one)
19450 *
19451 * We use the above three invariants to determine `TNode.insertBeforeIndex`.
19452 *
19453 * In an ideal world `TNode.insertBeforeIndex` would always be `TNode.next.index`. However,
19454 * this will not work because `TNode.next.index` may be larger than `TNode.index` which means that
19455 * the next node is not yet created and therefore we can't insert in front of it.
19456 *
19457 * Rule1: `TNode.insertBeforeIndex = null` if `TNode.next === null` (Initial condition, as we don't
19458 * know if there will be further `TNode`s inserted after.)
19459 * Rule2: If `previousTNode` is created after the `tNode` being inserted, then
19460 * `previousTNode.insertBeforeNode = tNode.index` (So when a new `tNode` is added we check
19461 * previous to see if we can update its `insertBeforeTNode`)
19462 *
19463 * See `TNode.insertBeforeIndex` for more context.
19464 *
19465 * @param previousTNodes A list of previous TNodes so that we can easily traverse `TNode`s in
19466 * reverse order. (If `TNode` would have `previous` this would not be necessary.)
19467 * @param newTNode A TNode to add to the `previousTNodes` list.
19468 */
19469function addTNodeAndUpdateInsertBeforeIndex(previousTNodes, newTNode) {
19470 // Start with Rule1
19471 ngDevMode &&
19472 assertEqual(newTNode.insertBeforeIndex, null, 'We expect that insertBeforeIndex is not set');
19473 previousTNodes.push(newTNode);
19474 if (previousTNodes.length > 1) {
19475 for (let i = previousTNodes.length - 2; i >= 0; i--) {
19476 const existingTNode = previousTNodes[i];
19477 // Text nodes are created eagerly and so they don't need their `indexBeforeIndex` updated.
19478 // It is safe to ignore them.
19479 if (!isI18nText(existingTNode)) {
19480 if (isNewTNodeCreatedBefore(existingTNode, newTNode) &&
19481 getInsertBeforeIndex(existingTNode) === null) {
19482 // If it was created before us in time, (and it does not yet have `insertBeforeIndex`)
19483 // then add the `insertBeforeIndex`.
19484 setInsertBeforeIndex(existingTNode, newTNode.index);
19485 }
19486 }
19487 }
19488 }
19489}
19490function isI18nText(tNode) {
19491 return !(tNode.type & 64 /* TNodeType.Placeholder */);
19492}
19493function isNewTNodeCreatedBefore(existingTNode, newTNode) {
19494 return isI18nText(newTNode) || existingTNode.index > newTNode.index;
19495}
19496function getInsertBeforeIndex(tNode) {
19497 const index = tNode.insertBeforeIndex;
19498 return Array.isArray(index) ? index[0] : index;
19499}
19500function setInsertBeforeIndex(tNode, value) {
19501 const index = tNode.insertBeforeIndex;
19502 if (Array.isArray(index)) {
19503 // Array is stored if we have to insert child nodes. See `TNode.insertBeforeIndex`
19504 index[0] = value;
19505 }
19506 else {
19507 setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
19508 tNode.insertBeforeIndex = value;
19509 }
19510}
19511
19512/**
19513 * @license
19514 * Copyright Google LLC All Rights Reserved.
19515 *
19516 * Use of this source code is governed by an MIT-style license that can be
19517 * found in the LICENSE file at https://angular.io/license
19518 */
19519/**
19520 * Retrieve `TIcu` at a given `index`.
19521 *
19522 * The `TIcu` can be stored either directly (if it is nested ICU) OR
19523 * it is stored inside tho `TIcuContainer` if it is top level ICU.
19524 *
19525 * The reason for this is that the top level ICU need a `TNode` so that they are part of the render
19526 * tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
19527 * expressed (parent ICU may have selected a case which does not contain it.)
19528 *
19529 * @param tView Current `TView`.
19530 * @param index Index where the value should be read from.
19531 */
19532function getTIcu(tView, index) {
19533 const value = tView.data[index];
19534 if (value === null || typeof value === 'string')
19535 return null;
19536 if (ngDevMode &&
19537 !(value.hasOwnProperty('tViews') || value.hasOwnProperty('currentCaseLViewIndex'))) {
19538 throwError('We expect to get \'null\'|\'TIcu\'|\'TIcuContainer\', but got: ' + value);
19539 }
19540 // Here the `value.hasOwnProperty('currentCaseLViewIndex')` is a polymorphic read as it can be
19541 // either TIcu or TIcuContainerNode. This is not ideal, but we still think it is OK because it
19542 // will be just two cases which fits into the browser inline cache (inline cache can take up to
19543 // 4)
19544 const tIcu = value.hasOwnProperty('currentCaseLViewIndex') ? value :
19545 value.value;
19546 ngDevMode && assertTIcu(tIcu);
19547 return tIcu;
19548}
19549/**
19550 * Store `TIcu` at a give `index`.
19551 *
19552 * The `TIcu` can be stored either directly (if it is nested ICU) OR
19553 * it is stored inside tho `TIcuContainer` if it is top level ICU.
19554 *
19555 * The reason for this is that the top level ICU need a `TNode` so that they are part of the render
19556 * tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
19557 * expressed (parent ICU may have selected a case which does not contain it.)
19558 *
19559 * @param tView Current `TView`.
19560 * @param index Index where the value should be stored at in `Tview.data`
19561 * @param tIcu The TIcu to store.
19562 */
19563function setTIcu(tView, index, tIcu) {
19564 const tNode = tView.data[index];
19565 ngDevMode &&
19566 assertEqual(tNode === null || tNode.hasOwnProperty('tViews'), true, 'We expect to get \'null\'|\'TIcuContainer\'');
19567 if (tNode === null) {
19568 tView.data[index] = tIcu;
19569 }
19570 else {
19571 ngDevMode && assertTNodeType(tNode, 32 /* TNodeType.Icu */);
19572 tNode.value = tIcu;
19573 }
19574}
19575/**
19576 * Set `TNode.insertBeforeIndex` taking the `Array` into account.
19577 *
19578 * See `TNode.insertBeforeIndex`
19579 */
19580function setTNodeInsertBeforeIndex(tNode, index) {
19581 ngDevMode && assertTNode(tNode);
19582 let insertBeforeIndex = tNode.insertBeforeIndex;
19583 if (insertBeforeIndex === null) {
19584 setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
19585 insertBeforeIndex = tNode.insertBeforeIndex =
19586 [null /* may be updated to number later */, index];
19587 }
19588 else {
19589 assertEqual(Array.isArray(insertBeforeIndex), true, 'Expecting array here');
19590 insertBeforeIndex.push(index);
19591 }
19592}
19593/**
19594 * Create `TNode.type=TNodeType.Placeholder` node.
19595 *
19596 * See `TNodeType.Placeholder` for more information.
19597 */
19598function createTNodePlaceholder(tView, previousTNodes, index) {
19599 const tNode = createTNodeAtIndex(tView, index, 64 /* TNodeType.Placeholder */, null, null);
19600 addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tNode);
19601 return tNode;
19602}
19603/**
19604 * Returns current ICU case.
19605 *
19606 * ICU cases are stored as index into the `TIcu.cases`.
19607 * At times it is necessary to communicate that the ICU case just switched and that next ICU update
19608 * should update all bindings regardless of the mask. In such a case the we store negative numbers
19609 * for cases which have just been switched. This function removes the negative flag.
19610 */
19611function getCurrentICUCaseIndex(tIcu, lView) {
19612 const currentCase = lView[tIcu.currentCaseLViewIndex];
19613 return currentCase === null ? currentCase : (currentCase < 0 ? ~currentCase : currentCase);
19614}
19615function getParentFromIcuCreateOpCode(mergedCode) {
19616 return mergedCode >>> 17 /* IcuCreateOpCode.SHIFT_PARENT */;
19617}
19618function getRefFromIcuCreateOpCode(mergedCode) {
19619 return (mergedCode & 131070 /* IcuCreateOpCode.MASK_REF */) >>> 1 /* IcuCreateOpCode.SHIFT_REF */;
19620}
19621function getInstructionFromIcuCreateOpCode(mergedCode) {
19622 return mergedCode & 1 /* IcuCreateOpCode.MASK_INSTRUCTION */;
19623}
19624function icuCreateOpCode(opCode, parentIdx, refIdx) {
19625 ngDevMode && assertGreaterThanOrEqual(parentIdx, 0, 'Missing parent index');
19626 ngDevMode && assertGreaterThan(refIdx, 0, 'Missing ref index');
19627 return opCode | parentIdx << 17 /* IcuCreateOpCode.SHIFT_PARENT */ | refIdx << 1 /* IcuCreateOpCode.SHIFT_REF */;
19628}
19629
19630/**
19631 * @license
19632 * Copyright Google LLC All Rights Reserved.
19633 *
19634 * Use of this source code is governed by an MIT-style license that can be
19635 * found in the LICENSE file at https://angular.io/license
19636 */
19637/**
19638 * Keep track of which input bindings in `ɵɵi18nExp` have changed.
19639 *
19640 * This is used to efficiently update expressions in i18n only when the corresponding input has
19641 * changed.
19642 *
19643 * 1) Each bit represents which of the `ɵɵi18nExp` has changed.
19644 * 2) There are 32 bits allowed in JS.
19645 * 3) Bit 32 is special as it is shared for all changes past 32. (In other words if you have more
19646 * than 32 `ɵɵi18nExp` then all changes past 32nd `ɵɵi18nExp` will be mapped to same bit. This means
19647 * that we may end up changing more than we need to. But i18n expressions with 32 bindings is rare
19648 * so in practice it should not be an issue.)
19649 */
19650let changeMask = 0b0;
19651/**
19652 * Keeps track of which bit needs to be updated in `changeMask`
19653 *
19654 * This value gets incremented on every call to `ɵɵi18nExp`
19655 */
19656let changeMaskCounter = 0;
19657/**
19658 * Keep track of which input bindings in `ɵɵi18nExp` have changed.
19659 *
19660 * `setMaskBit` gets invoked by each call to `ɵɵi18nExp`.
19661 *
19662 * @param hasChange did `ɵɵi18nExp` detect a change.
19663 */
19664function setMaskBit(hasChange) {
19665 if (hasChange) {
19666 changeMask = changeMask | (1 << Math.min(changeMaskCounter, 31));
19667 }
19668 changeMaskCounter++;
19669}
19670function applyI18n(tView, lView, index) {
19671 if (changeMaskCounter > 0) {
19672 ngDevMode && assertDefined(tView, `tView should be defined`);
19673 const tI18n = tView.data[index];
19674 // When `index` points to an `ɵɵi18nAttributes` then we have an array otherwise `TI18n`
19675 const updateOpCodes = Array.isArray(tI18n) ? tI18n : tI18n.update;
19676 const bindingsStartIndex = getBindingIndex() - changeMaskCounter - 1;
19677 applyUpdateOpCodes(tView, lView, updateOpCodes, bindingsStartIndex, changeMask);
19678 }
19679 // Reset changeMask & maskBit to default for the next update cycle
19680 changeMask = 0b0;
19681 changeMaskCounter = 0;
19682}
19683/**
19684 * Apply `I18nCreateOpCodes` op-codes as stored in `TI18n.create`.
19685 *
19686 * Creates text (and comment) nodes which are internationalized.
19687 *
19688 * @param lView Current lView
19689 * @param createOpCodes Set of op-codes to apply
19690 * @param parentRNode Parent node (so that direct children can be added eagerly) or `null` if it is
19691 * a root node.
19692 * @param insertInFrontOf DOM node that should be used as an anchor.
19693 */
19694function applyCreateOpCodes(lView, createOpCodes, parentRNode, insertInFrontOf) {
19695 const renderer = lView[RENDERER];
19696 for (let i = 0; i < createOpCodes.length; i++) {
19697 const opCode = createOpCodes[i++];
19698 const text = createOpCodes[i];
19699 const isComment = (opCode & I18nCreateOpCode.COMMENT) === I18nCreateOpCode.COMMENT;
19700 const appendNow = (opCode & I18nCreateOpCode.APPEND_EAGERLY) === I18nCreateOpCode.APPEND_EAGERLY;
19701 const index = opCode >>> I18nCreateOpCode.SHIFT;
19702 let rNode = lView[index];
19703 if (rNode === null) {
19704 // We only create new DOM nodes if they don't already exist: If ICU switches case back to a
19705 // case which was already instantiated, no need to create new DOM nodes.
19706 rNode = lView[index] =
19707 isComment ? renderer.createComment(text) : createTextNode(renderer, text);
19708 }
19709 if (appendNow && parentRNode !== null) {
19710 nativeInsertBefore(renderer, parentRNode, rNode, insertInFrontOf, false);
19711 }
19712 }
19713}
19714/**
19715 * Apply `I18nMutateOpCodes` OpCodes.
19716 *
19717 * @param tView Current `TView`
19718 * @param mutableOpCodes Mutable OpCodes to process
19719 * @param lView Current `LView`
19720 * @param anchorRNode place where the i18n node should be inserted.
19721 */
19722function applyMutableOpCodes(tView, mutableOpCodes, lView, anchorRNode) {
19723 ngDevMode && assertDomNode(anchorRNode);
19724 const renderer = lView[RENDERER];
19725 // `rootIdx` represents the node into which all inserts happen.
19726 let rootIdx = null;
19727 // `rootRNode` represents the real node into which we insert. This can be different from
19728 // `lView[rootIdx]` if we have projection.
19729 // - null we don't have a parent (as can be the case in when we are inserting into a root of
19730 // LView which has no parent.)
19731 // - `RElement` The element representing the root after taking projection into account.
19732 let rootRNode;
19733 for (let i = 0; i < mutableOpCodes.length; i++) {
19734 const opCode = mutableOpCodes[i];
19735 if (typeof opCode == 'string') {
19736 const textNodeIndex = mutableOpCodes[++i];
19737 if (lView[textNodeIndex] === null) {
19738 ngDevMode && ngDevMode.rendererCreateTextNode++;
19739 ngDevMode && assertIndexInRange(lView, textNodeIndex);
19740 lView[textNodeIndex] = createTextNode(renderer, opCode);
19741 }
19742 }
19743 else if (typeof opCode == 'number') {
19744 switch (opCode & 1 /* IcuCreateOpCode.MASK_INSTRUCTION */) {
19745 case 0 /* IcuCreateOpCode.AppendChild */:
19746 const parentIdx = getParentFromIcuCreateOpCode(opCode);
19747 if (rootIdx === null) {
19748 // The first operation should save the `rootIdx` because the first operation
19749 // must insert into the root. (Only subsequent operations can insert into a dynamic
19750 // parent)
19751 rootIdx = parentIdx;
19752 rootRNode = nativeParentNode(renderer, anchorRNode);
19753 }
19754 let insertInFrontOf;
19755 let parentRNode;
19756 if (parentIdx === rootIdx) {
19757 insertInFrontOf = anchorRNode;
19758 parentRNode = rootRNode;
19759 }
19760 else {
19761 insertInFrontOf = null;
19762 parentRNode = unwrapRNode(lView[parentIdx]);
19763 }
19764 // FIXME(misko): Refactor with `processI18nText`
19765 if (parentRNode !== null) {
19766 // This can happen if the `LView` we are adding to is not attached to a parent `LView`.
19767 // In such a case there is no "root" we can attach to. This is fine, as we still need to
19768 // create the elements. When the `LView` gets later added to a parent these "root" nodes
19769 // get picked up and added.
19770 ngDevMode && assertDomNode(parentRNode);
19771 const refIdx = getRefFromIcuCreateOpCode(opCode);
19772 ngDevMode && assertGreaterThan(refIdx, HEADER_OFFSET, 'Missing ref');
19773 // `unwrapRNode` is not needed here as all of these point to RNodes as part of the i18n
19774 // which can't have components.
19775 const child = lView[refIdx];
19776 ngDevMode && assertDomNode(child);
19777 nativeInsertBefore(renderer, parentRNode, child, insertInFrontOf, false);
19778 const tIcu = getTIcu(tView, refIdx);
19779 if (tIcu !== null && typeof tIcu === 'object') {
19780 // If we just added a comment node which has ICU then that ICU may have already been
19781 // rendered and therefore we need to re-add it here.
19782 ngDevMode && assertTIcu(tIcu);
19783 const caseIndex = getCurrentICUCaseIndex(tIcu, lView);
19784 if (caseIndex !== null) {
19785 applyMutableOpCodes(tView, tIcu.create[caseIndex], lView, lView[tIcu.anchorIdx]);
19786 }
19787 }
19788 }
19789 break;
19790 case 1 /* IcuCreateOpCode.Attr */:
19791 const elementNodeIndex = opCode >>> 1 /* IcuCreateOpCode.SHIFT_REF */;
19792 const attrName = mutableOpCodes[++i];
19793 const attrValue = mutableOpCodes[++i];
19794 // This code is used for ICU expressions only, since we don't support
19795 // directives/components in ICUs, we don't need to worry about inputs here
19796 setElementAttribute(renderer, getNativeByIndex(elementNodeIndex, lView), null, null, attrName, attrValue, null);
19797 break;
19798 default:
19799 if (ngDevMode) {
19800 throw new RuntimeError(700 /* RuntimeErrorCode.INVALID_I18N_STRUCTURE */, `Unable to determine the type of mutate operation for "${opCode}"`);
19801 }
19802 }
19803 }
19804 else {
19805 switch (opCode) {
19806 case ICU_MARKER:
19807 const commentValue = mutableOpCodes[++i];
19808 const commentNodeIndex = mutableOpCodes[++i];
19809 if (lView[commentNodeIndex] === null) {
19810 ngDevMode &&
19811 assertEqual(typeof commentValue, 'string', `Expected "${commentValue}" to be a comment node value`);
19812 ngDevMode && ngDevMode.rendererCreateComment++;
19813 ngDevMode && assertIndexInExpandoRange(lView, commentNodeIndex);
19814 const commentRNode = lView[commentNodeIndex] =
19815 createCommentNode(renderer, commentValue);
19816 // FIXME(misko): Attaching patch data is only needed for the root (Also add tests)
19817 attachPatchData(commentRNode, lView);
19818 }
19819 break;
19820 case ELEMENT_MARKER:
19821 const tagName = mutableOpCodes[++i];
19822 const elementNodeIndex = mutableOpCodes[++i];
19823 if (lView[elementNodeIndex] === null) {
19824 ngDevMode &&
19825 assertEqual(typeof tagName, 'string', `Expected "${tagName}" to be an element node tag name`);
19826 ngDevMode && ngDevMode.rendererCreateElement++;
19827 ngDevMode && assertIndexInExpandoRange(lView, elementNodeIndex);
19828 const elementRNode = lView[elementNodeIndex] =
19829 createElementNode(renderer, tagName, null);
19830 // FIXME(misko): Attaching patch data is only needed for the root (Also add tests)
19831 attachPatchData(elementRNode, lView);
19832 }
19833 break;
19834 default:
19835 ngDevMode &&
19836 throwError(`Unable to determine the type of mutate operation for "${opCode}"`);
19837 }
19838 }
19839 }
19840}
19841/**
19842 * Apply `I18nUpdateOpCodes` OpCodes
19843 *
19844 * @param tView Current `TView`
19845 * @param lView Current `LView`
19846 * @param updateOpCodes OpCodes to process
19847 * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
19848 * @param changeMask Each bit corresponds to a `ɵɵi18nExp` (Counting backwards from
19849 * `bindingsStartIndex`)
19850 */
19851function applyUpdateOpCodes(tView, lView, updateOpCodes, bindingsStartIndex, changeMask) {
19852 for (let i = 0; i < updateOpCodes.length; i++) {
19853 // bit code to check if we should apply the next update
19854 const checkBit = updateOpCodes[i];
19855 // Number of opCodes to skip until next set of update codes
19856 const skipCodes = updateOpCodes[++i];
19857 if (checkBit & changeMask) {
19858 // The value has been updated since last checked
19859 let value = '';
19860 for (let j = i + 1; j <= (i + skipCodes); j++) {
19861 const opCode = updateOpCodes[j];
19862 if (typeof opCode == 'string') {
19863 value += opCode;
19864 }
19865 else if (typeof opCode == 'number') {
19866 if (opCode < 0) {
19867 // Negative opCode represent `i18nExp` values offset.
19868 value += renderStringify(lView[bindingsStartIndex - opCode]);
19869 }
19870 else {
19871 const nodeIndex = (opCode >>> 2 /* I18nUpdateOpCode.SHIFT_REF */);
19872 switch (opCode & 3 /* I18nUpdateOpCode.MASK_OPCODE */) {
19873 case 1 /* I18nUpdateOpCode.Attr */:
19874 const propName = updateOpCodes[++j];
19875 const sanitizeFn = updateOpCodes[++j];
19876 const tNodeOrTagName = tView.data[nodeIndex];
19877 ngDevMode && assertDefined(tNodeOrTagName, 'Experting TNode or string');
19878 if (typeof tNodeOrTagName === 'string') {
19879 // IF we don't have a `TNode`, then we are an element in ICU (as ICU content does
19880 // not have TNode), in which case we know that there are no directives, and hence
19881 // we use attribute setting.
19882 setElementAttribute(lView[RENDERER], lView[nodeIndex], null, tNodeOrTagName, propName, value, sanitizeFn);
19883 }
19884 else {
19885 elementPropertyInternal(tView, tNodeOrTagName, lView, propName, value, lView[RENDERER], sanitizeFn, false);
19886 }
19887 break;
19888 case 0 /* I18nUpdateOpCode.Text */:
19889 const rText = lView[nodeIndex];
19890 rText !== null && updateTextNode(lView[RENDERER], rText, value);
19891 break;
19892 case 2 /* I18nUpdateOpCode.IcuSwitch */:
19893 applyIcuSwitchCase(tView, getTIcu(tView, nodeIndex), lView, value);
19894 break;
19895 case 3 /* I18nUpdateOpCode.IcuUpdate */:
19896 applyIcuUpdateCase(tView, getTIcu(tView, nodeIndex), bindingsStartIndex, lView);
19897 break;
19898 }
19899 }
19900 }
19901 }
19902 }
19903 else {
19904 const opCode = updateOpCodes[i + 1];
19905 if (opCode > 0 && (opCode & 3 /* I18nUpdateOpCode.MASK_OPCODE */) === 3 /* I18nUpdateOpCode.IcuUpdate */) {
19906 // Special case for the `icuUpdateCase`. It could be that the mask did not match, but
19907 // we still need to execute `icuUpdateCase` because the case has changed recently due to
19908 // previous `icuSwitchCase` instruction. (`icuSwitchCase` and `icuUpdateCase` always come in
19909 // pairs.)
19910 const nodeIndex = (opCode >>> 2 /* I18nUpdateOpCode.SHIFT_REF */);
19911 const tIcu = getTIcu(tView, nodeIndex);
19912 const currentIndex = lView[tIcu.currentCaseLViewIndex];
19913 if (currentIndex < 0) {
19914 applyIcuUpdateCase(tView, tIcu, bindingsStartIndex, lView);
19915 }
19916 }
19917 }
19918 i += skipCodes;
19919 }
19920}
19921/**
19922 * Apply OpCodes associated with updating an existing ICU.
19923 *
19924 * @param tView Current `TView`
19925 * @param tIcu Current `TIcu`
19926 * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
19927 * @param lView Current `LView`
19928 */
19929function applyIcuUpdateCase(tView, tIcu, bindingsStartIndex, lView) {
19930 ngDevMode && assertIndexInRange(lView, tIcu.currentCaseLViewIndex);
19931 let activeCaseIndex = lView[tIcu.currentCaseLViewIndex];
19932 if (activeCaseIndex !== null) {
19933 let mask = changeMask;
19934 if (activeCaseIndex < 0) {
19935 // Clear the flag.
19936 // Negative number means that the ICU was freshly created and we need to force the update.
19937 activeCaseIndex = lView[tIcu.currentCaseLViewIndex] = ~activeCaseIndex;
19938 // -1 is same as all bits on, which simulates creation since it marks all bits dirty
19939 mask = -1;
19940 }
19941 applyUpdateOpCodes(tView, lView, tIcu.update[activeCaseIndex], bindingsStartIndex, mask);
19942 }
19943}
19944/**
19945 * Apply OpCodes associated with switching a case on ICU.
19946 *
19947 * This involves tearing down existing case and than building up a new case.
19948 *
19949 * @param tView Current `TView`
19950 * @param tIcu Current `TIcu`
19951 * @param lView Current `LView`
19952 * @param value Value of the case to update to.
19953 */
19954function applyIcuSwitchCase(tView, tIcu, lView, value) {
19955 // Rebuild a new case for this ICU
19956 const caseIndex = getCaseIndex(tIcu, value);
19957 let activeCaseIndex = getCurrentICUCaseIndex(tIcu, lView);
19958 if (activeCaseIndex !== caseIndex) {
19959 applyIcuSwitchCaseRemove(tView, tIcu, lView);
19960 lView[tIcu.currentCaseLViewIndex] = caseIndex === null ? null : ~caseIndex;
19961 if (caseIndex !== null) {
19962 // Add the nodes for the new case
19963 const anchorRNode = lView[tIcu.anchorIdx];
19964 if (anchorRNode) {
19965 ngDevMode && assertDomNode(anchorRNode);
19966 applyMutableOpCodes(tView, tIcu.create[caseIndex], lView, anchorRNode);
19967 }
19968 }
19969 }
19970}
19971/**
19972 * Apply OpCodes associated with tearing ICU case.
19973 *
19974 * This involves tearing down existing case and than building up a new case.
19975 *
19976 * @param tView Current `TView`
19977 * @param tIcu Current `TIcu`
19978 * @param lView Current `LView`
19979 */
19980function applyIcuSwitchCaseRemove(tView, tIcu, lView) {
19981 let activeCaseIndex = getCurrentICUCaseIndex(tIcu, lView);
19982 if (activeCaseIndex !== null) {
19983 const removeCodes = tIcu.remove[activeCaseIndex];
19984 for (let i = 0; i < removeCodes.length; i++) {
19985 const nodeOrIcuIndex = removeCodes[i];
19986 if (nodeOrIcuIndex > 0) {
19987 // Positive numbers are `RNode`s.
19988 const rNode = getNativeByIndex(nodeOrIcuIndex, lView);
19989 rNode !== null && nativeRemoveNode(lView[RENDERER], rNode);
19990 }
19991 else {
19992 // Negative numbers are ICUs
19993 applyIcuSwitchCaseRemove(tView, getTIcu(tView, ~nodeOrIcuIndex), lView);
19994 }
19995 }
19996 }
19997}
19998/**
19999 * Returns the index of the current case of an ICU expression depending on the main binding value
20000 *
20001 * @param icuExpression
20002 * @param bindingValue The value of the main binding used by this ICU expression
20003 */
20004function getCaseIndex(icuExpression, bindingValue) {
20005 let index = icuExpression.cases.indexOf(bindingValue);
20006 if (index === -1) {
20007 switch (icuExpression.type) {
20008 case 1 /* IcuType.plural */: {
20009 const resolvedCase = getPluralCase(bindingValue, getLocaleId());
20010 index = icuExpression.cases.indexOf(resolvedCase);
20011 if (index === -1 && resolvedCase !== 'other') {
20012 index = icuExpression.cases.indexOf('other');
20013 }
20014 break;
20015 }
20016 case 0 /* IcuType.select */: {
20017 index = icuExpression.cases.indexOf('other');
20018 break;
20019 }
20020 }
20021 }
20022 return index === -1 ? null : index;
20023}
20024
20025/**
20026 * @license
20027 * Copyright Google LLC All Rights Reserved.
20028 *
20029 * Use of this source code is governed by an MIT-style license that can be
20030 * found in the LICENSE file at https://angular.io/license
20031 */
20032function loadIcuContainerVisitor() {
20033 const _stack = [];
20034 let _index = -1;
20035 let _lView;
20036 let _removes;
20037 /**
20038 * Retrieves a set of root nodes from `TIcu.remove`. Used by `TNodeType.ICUContainer`
20039 * to determine which root belong to the ICU.
20040 *
20041 * Example of usage.
20042 * ```
20043 * const nextRNode = icuContainerIteratorStart(tIcuContainerNode, lView);
20044 * let rNode: RNode|null;
20045 * while(rNode = nextRNode()) {
20046 * console.log(rNode);
20047 * }
20048 * ```
20049 *
20050 * @param tIcuContainerNode Current `TIcuContainerNode`
20051 * @param lView `LView` where the `RNode`s should be looked up.
20052 */
20053 function icuContainerIteratorStart(tIcuContainerNode, lView) {
20054 _lView = lView;
20055 while (_stack.length)
20056 _stack.pop();
20057 ngDevMode && assertTNodeForLView(tIcuContainerNode, lView);
20058 enterIcu(tIcuContainerNode.value, lView);
20059 return icuContainerIteratorNext;
20060 }
20061 function enterIcu(tIcu, lView) {
20062 _index = 0;
20063 const currentCase = getCurrentICUCaseIndex(tIcu, lView);
20064 if (currentCase !== null) {
20065 ngDevMode && assertNumberInRange(currentCase, 0, tIcu.cases.length - 1);
20066 _removes = tIcu.remove[currentCase];
20067 }
20068 else {
20069 _removes = EMPTY_ARRAY;
20070 }
20071 }
20072 function icuContainerIteratorNext() {
20073 if (_index < _removes.length) {
20074 const removeOpCode = _removes[_index++];
20075 ngDevMode && assertNumber(removeOpCode, 'Expecting OpCode number');
20076 if (removeOpCode > 0) {
20077 const rNode = _lView[removeOpCode];
20078 ngDevMode && assertDomNode(rNode);
20079 return rNode;
20080 }
20081 else {
20082 _stack.push(_index, _removes);
20083 // ICUs are represented by negative indices
20084 const tIcuIndex = ~removeOpCode;
20085 const tIcu = _lView[TVIEW].data[tIcuIndex];
20086 ngDevMode && assertTIcu(tIcu);
20087 enterIcu(tIcu, _lView);
20088 return icuContainerIteratorNext();
20089 }
20090 }
20091 else {
20092 if (_stack.length === 0) {
20093 return null;
20094 }
20095 else {
20096 _removes = _stack.pop();
20097 _index = _stack.pop();
20098 return icuContainerIteratorNext();
20099 }
20100 }
20101 }
20102 return icuContainerIteratorStart;
20103}
20104
20105/**
20106 * @license
20107 * Copyright Google LLC All Rights Reserved.
20108 *
20109 * Use of this source code is governed by an MIT-style license that can be
20110 * found in the LICENSE file at https://angular.io/license
20111 */
20112/**
20113 * Converts `I18nCreateOpCodes` array into a human readable format.
20114 *
20115 * This function is attached to the `I18nCreateOpCodes.debug` property if `ngDevMode` is enabled.
20116 * This function provides a human readable view of the opcodes. This is useful when debugging the
20117 * application as well as writing more readable tests.
20118 *
20119 * @param this `I18nCreateOpCodes` if attached as a method.
20120 * @param opcodes `I18nCreateOpCodes` if invoked as a function.
20121 */
20122function i18nCreateOpCodesToString(opcodes) {
20123 const createOpCodes = opcodes || (Array.isArray(this) ? this : []);
20124 let lines = [];
20125 for (let i = 0; i < createOpCodes.length; i++) {
20126 const opCode = createOpCodes[i++];
20127 const text = createOpCodes[i];
20128 const isComment = (opCode & I18nCreateOpCode.COMMENT) === I18nCreateOpCode.COMMENT;
20129 const appendNow = (opCode & I18nCreateOpCode.APPEND_EAGERLY) === I18nCreateOpCode.APPEND_EAGERLY;
20130 const index = opCode >>> I18nCreateOpCode.SHIFT;
20131 lines.push(`lView[${index}] = document.${isComment ? 'createComment' : 'createText'}(${JSON.stringify(text)});`);
20132 if (appendNow) {
20133 lines.push(`parent.appendChild(lView[${index}]);`);
20134 }
20135 }
20136 return lines;
20137}
20138/**
20139 * Converts `I18nUpdateOpCodes` array into a human readable format.
20140 *
20141 * This function is attached to the `I18nUpdateOpCodes.debug` property if `ngDevMode` is enabled.
20142 * This function provides a human readable view of the opcodes. This is useful when debugging the
20143 * application as well as writing more readable tests.
20144 *
20145 * @param this `I18nUpdateOpCodes` if attached as a method.
20146 * @param opcodes `I18nUpdateOpCodes` if invoked as a function.
20147 */
20148function i18nUpdateOpCodesToString(opcodes) {
20149 const parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
20150 let lines = [];
20151 function consumeOpCode(value) {
20152 const ref = value >>> 2 /* I18nUpdateOpCode.SHIFT_REF */;
20153 const opCode = value & 3 /* I18nUpdateOpCode.MASK_OPCODE */;
20154 switch (opCode) {
20155 case 0 /* I18nUpdateOpCode.Text */:
20156 return `(lView[${ref}] as Text).textContent = $$$`;
20157 case 1 /* I18nUpdateOpCode.Attr */:
20158 const attrName = parser.consumeString();
20159 const sanitizationFn = parser.consumeFunction();
20160 const value = sanitizationFn ? `(${sanitizationFn})($$$)` : '$$$';
20161 return `(lView[${ref}] as Element).setAttribute('${attrName}', ${value})`;
20162 case 2 /* I18nUpdateOpCode.IcuSwitch */:
20163 return `icuSwitchCase(${ref}, $$$)`;
20164 case 3 /* I18nUpdateOpCode.IcuUpdate */:
20165 return `icuUpdateCase(${ref})`;
20166 }
20167 throw new Error('unexpected OpCode');
20168 }
20169 while (parser.hasMore()) {
20170 let mask = parser.consumeNumber();
20171 let size = parser.consumeNumber();
20172 const end = parser.i + size;
20173 const statements = [];
20174 let statement = '';
20175 while (parser.i < end) {
20176 let value = parser.consumeNumberOrString();
20177 if (typeof value === 'string') {
20178 statement += value;
20179 }
20180 else if (value < 0) {
20181 // Negative numbers are ref indexes
20182 // Here `i` refers to current binding index. It is to signify that the value is relative,
20183 // rather than absolute.
20184 statement += '${lView[i' + value + ']}';
20185 }
20186 else {
20187 // Positive numbers are operations.
20188 const opCodeText = consumeOpCode(value);
20189 statements.push(opCodeText.replace('$$$', '`' + statement + '`') + ';');
20190 statement = '';
20191 }
20192 }
20193 lines.push(`if (mask & 0b${mask.toString(2)}) { ${statements.join(' ')} }`);
20194 }
20195 return lines;
20196}
20197/**
20198 * Converts `I18nCreateOpCodes` array into a human readable format.
20199 *
20200 * This function is attached to the `I18nCreateOpCodes.debug` if `ngDevMode` is enabled. This
20201 * function provides a human readable view of the opcodes. This is useful when debugging the
20202 * application as well as writing more readable tests.
20203 *
20204 * @param this `I18nCreateOpCodes` if attached as a method.
20205 * @param opcodes `I18nCreateOpCodes` if invoked as a function.
20206 */
20207function icuCreateOpCodesToString(opcodes) {
20208 const parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
20209 let lines = [];
20210 function consumeOpCode(opCode) {
20211 const parent = getParentFromIcuCreateOpCode(opCode);
20212 const ref = getRefFromIcuCreateOpCode(opCode);
20213 switch (getInstructionFromIcuCreateOpCode(opCode)) {
20214 case 0 /* IcuCreateOpCode.AppendChild */:
20215 return `(lView[${parent}] as Element).appendChild(lView[${lastRef}])`;
20216 case 1 /* IcuCreateOpCode.Attr */:
20217 return `(lView[${ref}] as Element).setAttribute("${parser.consumeString()}", "${parser.consumeString()}")`;
20218 }
20219 throw new Error('Unexpected OpCode: ' + getInstructionFromIcuCreateOpCode(opCode));
20220 }
20221 let lastRef = -1;
20222 while (parser.hasMore()) {
20223 let value = parser.consumeNumberStringOrMarker();
20224 if (value === ICU_MARKER) {
20225 const text = parser.consumeString();
20226 lastRef = parser.consumeNumber();
20227 lines.push(`lView[${lastRef}] = document.createComment("${text}")`);
20228 }
20229 else if (value === ELEMENT_MARKER) {
20230 const text = parser.consumeString();
20231 lastRef = parser.consumeNumber();
20232 lines.push(`lView[${lastRef}] = document.createElement("${text}")`);
20233 }
20234 else if (typeof value === 'string') {
20235 lastRef = parser.consumeNumber();
20236 lines.push(`lView[${lastRef}] = document.createTextNode("${value}")`);
20237 }
20238 else if (typeof value === 'number') {
20239 const line = consumeOpCode(value);
20240 line && lines.push(line);
20241 }
20242 else {
20243 throw new Error('Unexpected value');
20244 }
20245 }
20246 return lines;
20247}
20248/**
20249 * Converts `I18nRemoveOpCodes` array into a human readable format.
20250 *
20251 * This function is attached to the `I18nRemoveOpCodes.debug` if `ngDevMode` is enabled. This
20252 * function provides a human readable view of the opcodes. This is useful when debugging the
20253 * application as well as writing more readable tests.
20254 *
20255 * @param this `I18nRemoveOpCodes` if attached as a method.
20256 * @param opcodes `I18nRemoveOpCodes` if invoked as a function.
20257 */
20258function i18nRemoveOpCodesToString(opcodes) {
20259 const removeCodes = opcodes || (Array.isArray(this) ? this : []);
20260 let lines = [];
20261 for (let i = 0; i < removeCodes.length; i++) {
20262 const nodeOrIcuIndex = removeCodes[i];
20263 if (nodeOrIcuIndex > 0) {
20264 // Positive numbers are `RNode`s.
20265 lines.push(`remove(lView[${nodeOrIcuIndex}])`);
20266 }
20267 else {
20268 // Negative numbers are ICUs
20269 lines.push(`removeNestedICU(${~nodeOrIcuIndex})`);
20270 }
20271 }
20272 return lines;
20273}
20274class OpCodeParser {
20275 constructor(codes) {
20276 this.i = 0;
20277 this.codes = codes;
20278 }
20279 hasMore() {
20280 return this.i < this.codes.length;
20281 }
20282 consumeNumber() {
20283 let value = this.codes[this.i++];
20284 assertNumber(value, 'expecting number in OpCode');
20285 return value;
20286 }
20287 consumeString() {
20288 let value = this.codes[this.i++];
20289 assertString(value, 'expecting string in OpCode');
20290 return value;
20291 }
20292 consumeFunction() {
20293 let value = this.codes[this.i++];
20294 if (value === null || typeof value === 'function') {
20295 return value;
20296 }
20297 throw new Error('expecting function in OpCode');
20298 }
20299 consumeNumberOrString() {
20300 let value = this.codes[this.i++];
20301 if (typeof value === 'string') {
20302 return value;
20303 }
20304 assertNumber(value, 'expecting number or string in OpCode');
20305 return value;
20306 }
20307 consumeNumberStringOrMarker() {
20308 let value = this.codes[this.i++];
20309 if (typeof value === 'string' || typeof value === 'number' || value == ICU_MARKER ||
20310 value == ELEMENT_MARKER) {
20311 return value;
20312 }
20313 assertNumber(value, 'expecting number, string, ICU_MARKER or ELEMENT_MARKER in OpCode');
20314 return value;
20315 }
20316}
20317
20318/**
20319 * @license
20320 * Copyright Google LLC All Rights Reserved.
20321 *
20322 * Use of this source code is governed by an MIT-style license that can be
20323 * found in the LICENSE file at https://angular.io/license
20324 */
20325const BINDING_REGEXP = /�(\d+):?\d*�/gi;
20326const ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi;
20327const NESTED_ICU = /�(\d+)�/;
20328const ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/;
20329const MARKER = `�`;
20330const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
20331const PH_REGEXP = /�(\/?[#*]\d+):?\d*�/gi;
20332/**
20333 * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
20334 * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
20335 * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
20336 * and later on replaced by a space. We are re-implementing the same idea here, since translations
20337 * might contain this special character.
20338 */
20339const NGSP_UNICODE_REGEXP = /\uE500/g;
20340function replaceNgsp(value) {
20341 return value.replace(NGSP_UNICODE_REGEXP, ' ');
20342}
20343/**
20344 * Create dynamic nodes from i18n translation block.
20345 *
20346 * - Text nodes are created synchronously
20347 * - TNodes are linked into tree lazily
20348 *
20349 * @param tView Current `TView`
20350 * @parentTNodeIndex index to the parent TNode of this i18n block
20351 * @param lView Current `LView`
20352 * @param index Index of `ɵɵi18nStart` instruction.
20353 * @param message Message to translate.
20354 * @param subTemplateIndex Index into the sub template of message translation. (ie in case of
20355 * `ngIf`) (-1 otherwise)
20356 */
20357function i18nStartFirstCreatePass(tView, parentTNodeIndex, lView, index, message, subTemplateIndex) {
20358 const rootTNode = getCurrentParentTNode();
20359 const createOpCodes = [];
20360 const updateOpCodes = [];
20361 const existingTNodeStack = [[]];
20362 if (ngDevMode) {
20363 attachDebugGetter(createOpCodes, i18nCreateOpCodesToString);
20364 attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
20365 }
20366 message = getTranslationForTemplate(message, subTemplateIndex);
20367 const msgParts = replaceNgsp(message).split(PH_REGEXP);
20368 for (let i = 0; i < msgParts.length; i++) {
20369 let value = msgParts[i];
20370 if ((i & 1) === 0) {
20371 // Even indexes are text (including bindings & ICU expressions)
20372 const parts = i18nParseTextIntoPartsAndICU(value);
20373 for (let j = 0; j < parts.length; j++) {
20374 let part = parts[j];
20375 if ((j & 1) === 0) {
20376 // `j` is odd therefore `part` is string
20377 const text = part;
20378 ngDevMode && assertString(text, 'Parsed ICU part should be string');
20379 if (text !== '') {
20380 i18nStartFirstCreatePassProcessTextNode(tView, rootTNode, existingTNodeStack[0], createOpCodes, updateOpCodes, lView, text);
20381 }
20382 }
20383 else {
20384 // `j` is Even therefor `part` is an `ICUExpression`
20385 const icuExpression = part;
20386 // Verify that ICU expression has the right shape. Translations might contain invalid
20387 // constructions (while original messages were correct), so ICU parsing at runtime may
20388 // not succeed (thus `icuExpression` remains a string).
20389 // Note: we intentionally retain the error here by not using `ngDevMode`, because
20390 // the value can change based on the locale and users aren't guaranteed to hit
20391 // an invalid string while they're developing.
20392 if (typeof icuExpression !== 'object') {
20393 throw new Error(`Unable to parse ICU expression in "${message}" message.`);
20394 }
20395 const icuContainerTNode = createTNodeAndAddOpCode(tView, rootTNode, existingTNodeStack[0], lView, createOpCodes, ngDevMode ? `ICU ${index}:${icuExpression.mainBinding}` : '', true);
20396 const icuNodeIndex = icuContainerTNode.index;
20397 ngDevMode &&
20398 assertGreaterThanOrEqual(icuNodeIndex, HEADER_OFFSET, 'Index must be in absolute LView offset');
20399 icuStart(tView, lView, updateOpCodes, parentTNodeIndex, icuExpression, icuNodeIndex);
20400 }
20401 }
20402 }
20403 else {
20404 // Odd indexes are placeholders (elements and sub-templates)
20405 // At this point value is something like: '/#1:2' (originally coming from '�/#1:2�')
20406 const isClosing = value.charCodeAt(0) === 47 /* CharCode.SLASH */;
20407 const type = value.charCodeAt(isClosing ? 1 : 0);
20408 ngDevMode && assertOneOf(type, 42 /* CharCode.STAR */, 35 /* CharCode.HASH */);
20409 const index = HEADER_OFFSET + Number.parseInt(value.substring((isClosing ? 2 : 1)));
20410 if (isClosing) {
20411 existingTNodeStack.shift();
20412 setCurrentTNode(getCurrentParentTNode(), false);
20413 }
20414 else {
20415 const tNode = createTNodePlaceholder(tView, existingTNodeStack[0], index);
20416 existingTNodeStack.unshift([]);
20417 setCurrentTNode(tNode, true);
20418 }
20419 }
20420 }
20421 tView.data[index] = {
20422 create: createOpCodes,
20423 update: updateOpCodes,
20424 };
20425}
20426/**
20427 * Allocate space in i18n Range add create OpCode instruction to create a text or comment node.
20428 *
20429 * @param tView Current `TView` needed to allocate space in i18n range.
20430 * @param rootTNode Root `TNode` of the i18n block. This node determines if the new TNode will be
20431 * added as part of the `i18nStart` instruction or as part of the `TNode.insertBeforeIndex`.
20432 * @param existingTNodes internal state for `addTNodeAndUpdateInsertBeforeIndex`.
20433 * @param lView Current `LView` needed to allocate space in i18n range.
20434 * @param createOpCodes Array storing `I18nCreateOpCodes` where new opCodes will be added.
20435 * @param text Text to be added when the `Text` or `Comment` node will be created.
20436 * @param isICU true if a `Comment` node for ICU (instead of `Text`) node should be created.
20437 */
20438function createTNodeAndAddOpCode(tView, rootTNode, existingTNodes, lView, createOpCodes, text, isICU) {
20439 const i18nNodeIdx = allocExpando(tView, lView, 1, null);
20440 let opCode = i18nNodeIdx << I18nCreateOpCode.SHIFT;
20441 let parentTNode = getCurrentParentTNode();
20442 if (rootTNode === parentTNode) {
20443 // FIXME(misko): A null `parentTNode` should represent when we fall of the `LView` boundary.
20444 // (there is no parent), but in some circumstances (because we are inconsistent about how we set
20445 // `previousOrParentTNode`) it could point to `rootTNode` So this is a work around.
20446 parentTNode = null;
20447 }
20448 if (parentTNode === null) {
20449 // If we don't have a parent that means that we can eagerly add nodes.
20450 // If we have a parent than these nodes can't be added now (as the parent has not been created
20451 // yet) and instead the `parentTNode` is responsible for adding it. See
20452 // `TNode.insertBeforeIndex`
20453 opCode |= I18nCreateOpCode.APPEND_EAGERLY;
20454 }
20455 if (isICU) {
20456 opCode |= I18nCreateOpCode.COMMENT;
20457 ensureIcuContainerVisitorLoaded(loadIcuContainerVisitor);
20458 }
20459 createOpCodes.push(opCode, text === null ? '' : text);
20460 // We store `{{?}}` so that when looking at debug `TNodeType.template` we can see where the
20461 // bindings are.
20462 const tNode = createTNodeAtIndex(tView, i18nNodeIdx, isICU ? 32 /* TNodeType.Icu */ : 1 /* TNodeType.Text */, text === null ? (ngDevMode ? '{{?}}' : '') : text, null);
20463 addTNodeAndUpdateInsertBeforeIndex(existingTNodes, tNode);
20464 const tNodeIdx = tNode.index;
20465 setCurrentTNode(tNode, false /* Text nodes are self closing */);
20466 if (parentTNode !== null && rootTNode !== parentTNode) {
20467 // We are a child of deeper node (rather than a direct child of `i18nStart` instruction.)
20468 // We have to make sure to add ourselves to the parent.
20469 setTNodeInsertBeforeIndex(parentTNode, tNodeIdx);
20470 }
20471 return tNode;
20472}
20473/**
20474 * Processes text node in i18n block.
20475 *
20476 * Text nodes can have:
20477 * - Create instruction in `createOpCodes` for creating the text node.
20478 * - Allocate spec for text node in i18n range of `LView`
20479 * - If contains binding:
20480 * - bindings => allocate space in i18n range of `LView` to store the binding value.
20481 * - populate `updateOpCodes` with update instructions.
20482 *
20483 * @param tView Current `TView`
20484 * @param rootTNode Root `TNode` of the i18n block. This node determines if the new TNode will
20485 * be added as part of the `i18nStart` instruction or as part of the
20486 * `TNode.insertBeforeIndex`.
20487 * @param existingTNodes internal state for `addTNodeAndUpdateInsertBeforeIndex`.
20488 * @param createOpCodes Location where the creation OpCodes will be stored.
20489 * @param lView Current `LView`
20490 * @param text The translated text (which may contain binding)
20491 */
20492function i18nStartFirstCreatePassProcessTextNode(tView, rootTNode, existingTNodes, createOpCodes, updateOpCodes, lView, text) {
20493 const hasBinding = text.match(BINDING_REGEXP);
20494 const tNode = createTNodeAndAddOpCode(tView, rootTNode, existingTNodes, lView, createOpCodes, hasBinding ? null : text, false);
20495 if (hasBinding) {
20496 generateBindingUpdateOpCodes(updateOpCodes, text, tNode.index, null, 0, null);
20497 }
20498}
20499/**
20500 * See `i18nAttributes` above.
20501 */
20502function i18nAttributesFirstPass(tView, index, values) {
20503 const previousElement = getCurrentTNode();
20504 const previousElementIndex = previousElement.index;
20505 const updateOpCodes = [];
20506 if (ngDevMode) {
20507 attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
20508 }
20509 if (tView.firstCreatePass && tView.data[index] === null) {
20510 for (let i = 0; i < values.length; i += 2) {
20511 const attrName = values[i];
20512 const message = values[i + 1];
20513 if (message !== '') {
20514 // Check if attribute value contains an ICU and throw an error if that's the case.
20515 // ICUs in element attributes are not supported.
20516 // Note: we intentionally retain the error here by not using `ngDevMode`, because
20517 // the `value` can change based on the locale and users aren't guaranteed to hit
20518 // an invalid string while they're developing.
20519 if (ICU_REGEXP.test(message)) {
20520 throw new Error(`ICU expressions are not supported in attributes. Message: "${message}".`);
20521 }
20522 // i18n attributes that hit this code path are guaranteed to have bindings, because
20523 // the compiler treats static i18n attributes as regular attribute bindings.
20524 // Since this may not be the first i18n attribute on this element we need to pass in how
20525 // many previous bindings there have already been.
20526 generateBindingUpdateOpCodes(updateOpCodes, message, previousElementIndex, attrName, countBindings(updateOpCodes), null);
20527 }
20528 }
20529 tView.data[index] = updateOpCodes;
20530 }
20531}
20532/**
20533 * Generate the OpCodes to update the bindings of a string.
20534 *
20535 * @param updateOpCodes Place where the update opcodes will be stored.
20536 * @param str The string containing the bindings.
20537 * @param destinationNode Index of the destination node which will receive the binding.
20538 * @param attrName Name of the attribute, if the string belongs to an attribute.
20539 * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary.
20540 * @param bindingStart The lView index of the next expression that can be bound via an opCode.
20541 * @returns The mask value for these bindings
20542 */
20543function generateBindingUpdateOpCodes(updateOpCodes, str, destinationNode, attrName, bindingStart, sanitizeFn) {
20544 ngDevMode &&
20545 assertGreaterThanOrEqual(destinationNode, HEADER_OFFSET, 'Index must be in absolute LView offset');
20546 const maskIndex = updateOpCodes.length; // Location of mask
20547 const sizeIndex = maskIndex + 1; // location of size for skipping
20548 updateOpCodes.push(null, null); // Alloc space for mask and size
20549 const startIndex = maskIndex + 2; // location of first allocation.
20550 if (ngDevMode) {
20551 attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
20552 }
20553 const textParts = str.split(BINDING_REGEXP);
20554 let mask = 0;
20555 for (let j = 0; j < textParts.length; j++) {
20556 const textValue = textParts[j];
20557 if (j & 1) {
20558 // Odd indexes are bindings
20559 const bindingIndex = bindingStart + parseInt(textValue, 10);
20560 updateOpCodes.push(-1 - bindingIndex);
20561 mask = mask | toMaskBit(bindingIndex);
20562 }
20563 else if (textValue !== '') {
20564 // Even indexes are text
20565 updateOpCodes.push(textValue);
20566 }
20567 }
20568 updateOpCodes.push(destinationNode << 2 /* I18nUpdateOpCode.SHIFT_REF */ |
20569 (attrName ? 1 /* I18nUpdateOpCode.Attr */ : 0 /* I18nUpdateOpCode.Text */));
20570 if (attrName) {
20571 updateOpCodes.push(attrName, sanitizeFn);
20572 }
20573 updateOpCodes[maskIndex] = mask;
20574 updateOpCodes[sizeIndex] = updateOpCodes.length - startIndex;
20575 return mask;
20576}
20577/**
20578 * Count the number of bindings in the given `opCodes`.
20579 *
20580 * It could be possible to speed this up, by passing the number of bindings found back from
20581 * `generateBindingUpdateOpCodes()` to `i18nAttributesFirstPass()` but this would then require more
20582 * complexity in the code and/or transient objects to be created.
20583 *
20584 * Since this function is only called once when the template is instantiated, is trivial in the
20585 * first instance (since `opCodes` will be an empty array), and it is not common for elements to
20586 * contain multiple i18n bound attributes, it seems like this is a reasonable compromise.
20587 */
20588function countBindings(opCodes) {
20589 let count = 0;
20590 for (let i = 0; i < opCodes.length; i++) {
20591 const opCode = opCodes[i];
20592 // Bindings are negative numbers.
20593 if (typeof opCode === 'number' && opCode < 0) {
20594 count++;
20595 }
20596 }
20597 return count;
20598}
20599/**
20600 * Convert binding index to mask bit.
20601 *
20602 * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make
20603 * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to
20604 * have more than 32 bindings this will be hit very rarely. The downside of hitting this corner
20605 * case is that we will execute binding code more often than necessary. (penalty of performance)
20606 */
20607function toMaskBit(bindingIndex) {
20608 return 1 << Math.min(bindingIndex, 31);
20609}
20610function isRootTemplateMessage(subTemplateIndex) {
20611 return subTemplateIndex === -1;
20612}
20613/**
20614 * Removes everything inside the sub-templates of a message.
20615 */
20616function removeInnerTemplateTranslation(message) {
20617 let match;
20618 let res = '';
20619 let index = 0;
20620 let inTemplate = false;
20621 let tagMatched;
20622 while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) {
20623 if (!inTemplate) {
20624 res += message.substring(index, match.index + match[0].length);
20625 tagMatched = match[1];
20626 inTemplate = true;
20627 }
20628 else {
20629 if (match[0] === `${MARKER}/*${tagMatched}${MARKER}`) {
20630 index = match.index;
20631 inTemplate = false;
20632 }
20633 }
20634 }
20635 ngDevMode &&
20636 assertEqual(inTemplate, false, `Tag mismatch: unable to find the end of the sub-template in the translation "${message}"`);
20637 res += message.slice(index);
20638 return res;
20639}
20640/**
20641 * Extracts a part of a message and removes the rest.
20642 *
20643 * This method is used for extracting a part of the message associated with a template. A
20644 * translated message can span multiple templates.
20645 *
20646 * Example:
20647 * ```
20648 * <div i18n>Translate <span *ngIf>me</span>!</div>
20649 * ```
20650 *
20651 * @param message The message to crop
20652 * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the
20653 * external template and removes all sub-templates.
20654 */
20655function getTranslationForTemplate(message, subTemplateIndex) {
20656 if (isRootTemplateMessage(subTemplateIndex)) {
20657 // We want the root template message, ignore all sub-templates
20658 return removeInnerTemplateTranslation(message);
20659 }
20660 else {
20661 // We want a specific sub-template
20662 const start = message.indexOf(`:${subTemplateIndex}${MARKER}`) + 2 + subTemplateIndex.toString().length;
20663 const end = message.search(new RegExp(`${MARKER}\\/\\*\\d+:${subTemplateIndex}${MARKER}`));
20664 return removeInnerTemplateTranslation(message.substring(start, end));
20665 }
20666}
20667/**
20668 * Generate the OpCodes for ICU expressions.
20669 *
20670 * @param icuExpression
20671 * @param index Index where the anchor is stored and an optional `TIcuContainerNode`
20672 * - `lView[anchorIdx]` points to a `Comment` node representing the anchor for the ICU.
20673 * - `tView.data[anchorIdx]` points to the `TIcuContainerNode` if ICU is root (`null` otherwise)
20674 */
20675function icuStart(tView, lView, updateOpCodes, parentIdx, icuExpression, anchorIdx) {
20676 ngDevMode && assertDefined(icuExpression, 'ICU expression must be defined');
20677 let bindingMask = 0;
20678 const tIcu = {
20679 type: icuExpression.type,
20680 currentCaseLViewIndex: allocExpando(tView, lView, 1, null),
20681 anchorIdx,
20682 cases: [],
20683 create: [],
20684 remove: [],
20685 update: []
20686 };
20687 addUpdateIcuSwitch(updateOpCodes, icuExpression, anchorIdx);
20688 setTIcu(tView, anchorIdx, tIcu);
20689 const values = icuExpression.values;
20690 for (let i = 0; i < values.length; i++) {
20691 // Each value is an array of strings & other ICU expressions
20692 const valueArr = values[i];
20693 const nestedIcus = [];
20694 for (let j = 0; j < valueArr.length; j++) {
20695 const value = valueArr[j];
20696 if (typeof value !== 'string') {
20697 // It is an nested ICU expression
20698 const icuIndex = nestedIcus.push(value) - 1;
20699 // Replace nested ICU expression by a comment node
20700 valueArr[j] = `<!--�${icuIndex}�-->`;
20701 }
20702 }
20703 bindingMask = parseIcuCase(tView, tIcu, lView, updateOpCodes, parentIdx, icuExpression.cases[i], valueArr.join(''), nestedIcus) |
20704 bindingMask;
20705 }
20706 if (bindingMask) {
20707 addUpdateIcuUpdate(updateOpCodes, bindingMask, anchorIdx);
20708 }
20709}
20710/**
20711 * Parses text containing an ICU expression and produces a JSON object for it.
20712 * Original code from closure library, modified for Angular.
20713 *
20714 * @param pattern Text containing an ICU expression that needs to be parsed.
20715 *
20716 */
20717function parseICUBlock(pattern) {
20718 const cases = [];
20719 const values = [];
20720 let icuType = 1 /* IcuType.plural */;
20721 let mainBinding = 0;
20722 pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) {
20723 if (type === 'select') {
20724 icuType = 0 /* IcuType.select */;
20725 }
20726 else {
20727 icuType = 1 /* IcuType.plural */;
20728 }
20729 mainBinding = parseInt(binding.slice(1), 10);
20730 return '';
20731 });
20732 const parts = i18nParseTextIntoPartsAndICU(pattern);
20733 // Looking for (key block)+ sequence. One of the keys has to be "other".
20734 for (let pos = 0; pos < parts.length;) {
20735 let key = parts[pos++].trim();
20736 if (icuType === 1 /* IcuType.plural */) {
20737 // Key can be "=x", we just want "x"
20738 key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1');
20739 }
20740 if (key.length) {
20741 cases.push(key);
20742 }
20743 const blocks = i18nParseTextIntoPartsAndICU(parts[pos++]);
20744 if (cases.length > values.length) {
20745 values.push(blocks);
20746 }
20747 }
20748 // TODO(ocombe): support ICU expressions in attributes, see #21615
20749 return { type: icuType, mainBinding: mainBinding, cases, values };
20750}
20751/**
20752 * Breaks pattern into strings and top level {...} blocks.
20753 * Can be used to break a message into text and ICU expressions, or to break an ICU expression
20754 * into keys and cases. Original code from closure library, modified for Angular.
20755 *
20756 * @param pattern (sub)Pattern to be broken.
20757 * @returns An `Array<string|IcuExpression>` where:
20758 * - odd positions: `string` => text between ICU expressions
20759 * - even positions: `ICUExpression` => ICU expression parsed into `ICUExpression` record.
20760 */
20761function i18nParseTextIntoPartsAndICU(pattern) {
20762 if (!pattern) {
20763 return [];
20764 }
20765 let prevPos = 0;
20766 const braceStack = [];
20767 const results = [];
20768 const braces = /[{}]/g;
20769 // lastIndex doesn't get set to 0 so we have to.
20770 braces.lastIndex = 0;
20771 let match;
20772 while (match = braces.exec(pattern)) {
20773 const pos = match.index;
20774 if (match[0] == '}') {
20775 braceStack.pop();
20776 if (braceStack.length == 0) {
20777 // End of the block.
20778 const block = pattern.substring(prevPos, pos);
20779 if (ICU_BLOCK_REGEXP.test(block)) {
20780 results.push(parseICUBlock(block));
20781 }
20782 else {
20783 results.push(block);
20784 }
20785 prevPos = pos + 1;
20786 }
20787 }
20788 else {
20789 if (braceStack.length == 0) {
20790 const substring = pattern.substring(prevPos, pos);
20791 results.push(substring);
20792 prevPos = pos + 1;
20793 }
20794 braceStack.push('{');
20795 }
20796 }
20797 const substring = pattern.substring(prevPos);
20798 results.push(substring);
20799 return results;
20800}
20801/**
20802 * Parses a node, its children and its siblings, and generates the mutate & update OpCodes.
20803 *
20804 */
20805function parseIcuCase(tView, tIcu, lView, updateOpCodes, parentIdx, caseName, unsafeCaseHtml, nestedIcus) {
20806 const create = [];
20807 const remove = [];
20808 const update = [];
20809 if (ngDevMode) {
20810 attachDebugGetter(create, icuCreateOpCodesToString);
20811 attachDebugGetter(remove, i18nRemoveOpCodesToString);
20812 attachDebugGetter(update, i18nUpdateOpCodesToString);
20813 }
20814 tIcu.cases.push(caseName);
20815 tIcu.create.push(create);
20816 tIcu.remove.push(remove);
20817 tIcu.update.push(update);
20818 const inertBodyHelper = getInertBodyHelper(getDocument());
20819 const inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeCaseHtml);
20820 ngDevMode && assertDefined(inertBodyElement, 'Unable to generate inert body element');
20821 const inertRootNode = getTemplateContent(inertBodyElement) || inertBodyElement;
20822 if (inertRootNode) {
20823 return walkIcuTree(tView, tIcu, lView, updateOpCodes, create, remove, update, inertRootNode, parentIdx, nestedIcus, 0);
20824 }
20825 else {
20826 return 0;
20827 }
20828}
20829function walkIcuTree(tView, tIcu, lView, sharedUpdateOpCodes, create, remove, update, parentNode, parentIdx, nestedIcus, depth) {
20830 let bindingMask = 0;
20831 let currentNode = parentNode.firstChild;
20832 while (currentNode) {
20833 const newIndex = allocExpando(tView, lView, 1, null);
20834 switch (currentNode.nodeType) {
20835 case Node.ELEMENT_NODE:
20836 const element = currentNode;
20837 const tagName = element.tagName.toLowerCase();
20838 if (VALID_ELEMENTS.hasOwnProperty(tagName)) {
20839 addCreateNodeAndAppend(create, ELEMENT_MARKER, tagName, parentIdx, newIndex);
20840 tView.data[newIndex] = tagName;
20841 const elAttrs = element.attributes;
20842 for (let i = 0; i < elAttrs.length; i++) {
20843 const attr = elAttrs.item(i);
20844 const lowerAttrName = attr.name.toLowerCase();
20845 const hasBinding = !!attr.value.match(BINDING_REGEXP);
20846 // we assume the input string is safe, unless it's using a binding
20847 if (hasBinding) {
20848 if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
20849 if (URI_ATTRS[lowerAttrName]) {
20850 generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, _sanitizeUrl);
20851 }
20852 else if (SRCSET_ATTRS[lowerAttrName]) {
20853 generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, sanitizeSrcset);
20854 }
20855 else {
20856 generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, null);
20857 }
20858 }
20859 else {
20860 ngDevMode &&
20861 console.warn(`WARNING: ignoring unsafe attribute value ` +
20862 `${lowerAttrName} on element ${tagName} ` +
20863 `(see https://g.co/ng/security#xss)`);
20864 }
20865 }
20866 else {
20867 addCreateAttribute(create, newIndex, attr);
20868 }
20869 }
20870 // Parse the children of this node (if any)
20871 bindingMask = walkIcuTree(tView, tIcu, lView, sharedUpdateOpCodes, create, remove, update, currentNode, newIndex, nestedIcus, depth + 1) |
20872 bindingMask;
20873 addRemoveNode(remove, newIndex, depth);
20874 }
20875 break;
20876 case Node.TEXT_NODE:
20877 const value = currentNode.textContent || '';
20878 const hasBinding = value.match(BINDING_REGEXP);
20879 addCreateNodeAndAppend(create, null, hasBinding ? '' : value, parentIdx, newIndex);
20880 addRemoveNode(remove, newIndex, depth);
20881 if (hasBinding) {
20882 bindingMask =
20883 generateBindingUpdateOpCodes(update, value, newIndex, null, 0, null) | bindingMask;
20884 }
20885 break;
20886 case Node.COMMENT_NODE:
20887 // Check if the comment node is a placeholder for a nested ICU
20888 const isNestedIcu = NESTED_ICU.exec(currentNode.textContent || '');
20889 if (isNestedIcu) {
20890 const nestedIcuIndex = parseInt(isNestedIcu[1], 10);
20891 const icuExpression = nestedIcus[nestedIcuIndex];
20892 // Create the comment node that will anchor the ICU expression
20893 addCreateNodeAndAppend(create, ICU_MARKER, ngDevMode ? `nested ICU ${nestedIcuIndex}` : '', parentIdx, newIndex);
20894 icuStart(tView, lView, sharedUpdateOpCodes, parentIdx, icuExpression, newIndex);
20895 addRemoveNestedIcu(remove, newIndex, depth);
20896 }
20897 break;
20898 }
20899 currentNode = currentNode.nextSibling;
20900 }
20901 return bindingMask;
20902}
20903function addRemoveNode(remove, index, depth) {
20904 if (depth === 0) {
20905 remove.push(index);
20906 }
20907}
20908function addRemoveNestedIcu(remove, index, depth) {
20909 if (depth === 0) {
20910 remove.push(~index); // remove ICU at `index`
20911 remove.push(index); // remove ICU comment at `index`
20912 }
20913}
20914function addUpdateIcuSwitch(update, icuExpression, index) {
20915 update.push(toMaskBit(icuExpression.mainBinding), 2, -1 - icuExpression.mainBinding, index << 2 /* I18nUpdateOpCode.SHIFT_REF */ | 2 /* I18nUpdateOpCode.IcuSwitch */);
20916}
20917function addUpdateIcuUpdate(update, bindingMask, index) {
20918 update.push(bindingMask, 1, index << 2 /* I18nUpdateOpCode.SHIFT_REF */ | 3 /* I18nUpdateOpCode.IcuUpdate */);
20919}
20920function addCreateNodeAndAppend(create, marker, text, appendToParentIdx, createAtIdx) {
20921 if (marker !== null) {
20922 create.push(marker);
20923 }
20924 create.push(text, createAtIdx, icuCreateOpCode(0 /* IcuCreateOpCode.AppendChild */, appendToParentIdx, createAtIdx));
20925}
20926function addCreateAttribute(create, newIndex, attr) {
20927 create.push(newIndex << 1 /* IcuCreateOpCode.SHIFT_REF */ | 1 /* IcuCreateOpCode.Attr */, attr.name, attr.value);
20928}
20929
20930/**
20931 * @license
20932 * Copyright Google LLC All Rights Reserved.
20933 *
20934 * Use of this source code is governed by an MIT-style license that can be
20935 * found in the LICENSE file at https://angular.io/license
20936 */
20937// i18nPostprocess consts
20938const ROOT_TEMPLATE_ID = 0;
20939const PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/;
20940const PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g;
20941const PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g;
20942const PP_ICU_PLACEHOLDERS_REGEXP = /{([A-Z0-9_]+)}/g;
20943const PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g;
20944const PP_CLOSE_TEMPLATE_REGEXP = /\/\*/;
20945const PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/;
20946/**
20947 * Handles message string post-processing for internationalization.
20948 *
20949 * Handles message string post-processing by transforming it from intermediate
20950 * format (that might contain some markers that we need to replace) to the final
20951 * form, consumable by i18nStart instruction. Post processing steps include:
20952 *
20953 * 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�])
20954 * 2. Replace all ICU vars (like "VAR_PLURAL")
20955 * 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
20956 * 4. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�)
20957 * in case multiple ICUs have the same placeholder name
20958 *
20959 * @param message Raw translation string for post processing
20960 * @param replacements Set of replacements that should be applied
20961 *
20962 * @returns Transformed string that can be consumed by i18nStart instruction
20963 *
20964 * @codeGenApi
20965 */
20966function i18nPostprocess(message, replacements = {}) {
20967 /**
20968 * Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�]
20969 *
20970 * Note: due to the way we process nested templates (BFS), multi-value placeholders are typically
20971 * grouped by templates, for example: [�#5�|�#6�|�#1:1�|�#3:2�] where �#5� and �#6� belong to root
20972 * template, �#1:1� belong to nested template with index 1 and �#1:2� - nested template with index
20973 * 3. However in real templates the order might be different: i.e. �#1:1� and/or �#3:2� may go in
20974 * front of �#6�. The post processing step restores the right order by keeping track of the
20975 * template id stack and looks for placeholders that belong to the currently active template.
20976 */
20977 let result = message;
20978 if (PP_MULTI_VALUE_PLACEHOLDERS_REGEXP.test(message)) {
20979 const matches = {};
20980 const templateIdsStack = [ROOT_TEMPLATE_ID];
20981 result = result.replace(PP_PLACEHOLDERS_REGEXP, (m, phs, tmpl) => {
20982 const content = phs || tmpl;
20983 const placeholders = matches[content] || [];
20984 if (!placeholders.length) {
20985 content.split('|').forEach((placeholder) => {
20986 const match = placeholder.match(PP_TEMPLATE_ID_REGEXP);
20987 const templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID;
20988 const isCloseTemplateTag = PP_CLOSE_TEMPLATE_REGEXP.test(placeholder);
20989 placeholders.push([templateId, isCloseTemplateTag, placeholder]);
20990 });
20991 matches[content] = placeholders;
20992 }
20993 if (!placeholders.length) {
20994 throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
20995 }
20996 const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
20997 let idx = 0;
20998 // find placeholder index that matches current template id
20999 for (let i = 0; i < placeholders.length; i++) {
21000 if (placeholders[i][0] === currentTemplateId) {
21001 idx = i;
21002 break;
21003 }
21004 }
21005 // update template id stack based on the current tag extracted
21006 const [templateId, isCloseTemplateTag, placeholder] = placeholders[idx];
21007 if (isCloseTemplateTag) {
21008 templateIdsStack.pop();
21009 }
21010 else if (currentTemplateId !== templateId) {
21011 templateIdsStack.push(templateId);
21012 }
21013 // remove processed tag from the list
21014 placeholders.splice(idx, 1);
21015 return placeholder;
21016 });
21017 }
21018 // return current result if no replacements specified
21019 if (!Object.keys(replacements).length) {
21020 return result;
21021 }
21022 /**
21023 * Step 2: replace all ICU vars (like "VAR_PLURAL")
21024 */
21025 result = result.replace(PP_ICU_VARS_REGEXP, (match, start, key, _type, _idx, end) => {
21026 return replacements.hasOwnProperty(key) ? `${start}${replacements[key]}${end}` : match;
21027 });
21028 /**
21029 * Step 3: replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
21030 */
21031 result = result.replace(PP_ICU_PLACEHOLDERS_REGEXP, (match, key) => {
21032 return replacements.hasOwnProperty(key) ? replacements[key] : match;
21033 });
21034 /**
21035 * Step 4: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case
21036 * multiple ICUs have the same placeholder name
21037 */
21038 result = result.replace(PP_ICUS_REGEXP, (match, key) => {
21039 if (replacements.hasOwnProperty(key)) {
21040 const list = replacements[key];
21041 if (!list.length) {
21042 throw new Error(`i18n postprocess: unmatched ICU - ${match} with key: ${key}`);
21043 }
21044 return list.shift();
21045 }
21046 return match;
21047 });
21048 return result;
21049}
21050
21051/**
21052 * @license
21053 * Copyright Google LLC All Rights Reserved.
21054 *
21055 * Use of this source code is governed by an MIT-style license that can be
21056 * found in the LICENSE file at https://angular.io/license
21057 */
21058/**
21059 * Marks a block of text as translatable.
21060 *
21061 * The instructions `i18nStart` and `i18nEnd` mark the translation block in the template.
21062 * The translation `message` is the value which is locale specific. The translation string may
21063 * contain placeholders which associate inner elements and sub-templates within the translation.
21064 *
21065 * The translation `message` placeholders are:
21066 * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
21067 * interpolated into. The placeholder `index` points to the expression binding index. An optional
21068 * `block` that matches the sub-template in which it was declared.
21069 * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
21070 * and end of DOM element that were embedded in the original translation block. The placeholder
21071 * `index` points to the element index in the template instructions set. An optional `block` that
21072 * matches the sub-template in which it was declared.
21073 * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
21074 * split up and translated separately in each angular template function. The `index` points to the
21075 * `template` instruction index. A `block` that matches the sub-template in which it was declared.
21076 *
21077 * @param index A unique index of the translation in the static block.
21078 * @param messageIndex An index of the translation message from the `def.consts` array.
21079 * @param subTemplateIndex Optional sub-template index in the `message`.
21080 *
21081 * @codeGenApi
21082 */
21083function ɵɵi18nStart(index, messageIndex, subTemplateIndex = -1) {
21084 const tView = getTView();
21085 const lView = getLView();
21086 const adjustedIndex = HEADER_OFFSET + index;
21087 ngDevMode && assertDefined(tView, `tView should be defined`);
21088 const message = getConstant(tView.consts, messageIndex);
21089 const parentTNode = getCurrentParentTNode();
21090 if (tView.firstCreatePass) {
21091 i18nStartFirstCreatePass(tView, parentTNode === null ? 0 : parentTNode.index, lView, adjustedIndex, message, subTemplateIndex);
21092 }
21093 const tI18n = tView.data[adjustedIndex];
21094 const sameViewParentTNode = parentTNode === lView[T_HOST] ? null : parentTNode;
21095 const parentRNode = getClosestRElement(tView, sameViewParentTNode, lView);
21096 // If `parentTNode` is an `ElementContainer` than it has `<!--ng-container--->`.
21097 // When we do inserts we have to make sure to insert in front of `<!--ng-container--->`.
21098 const insertInFrontOf = parentTNode && (parentTNode.type & 8 /* TNodeType.ElementContainer */) ?
21099 lView[parentTNode.index] :
21100 null;
21101 applyCreateOpCodes(lView, tI18n.create, parentRNode, insertInFrontOf);
21102 setInI18nBlock(true);
21103}
21104/**
21105 * Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes
21106 * into the render tree, moves the placeholder nodes and removes the deleted nodes.
21107 *
21108 * @codeGenApi
21109 */
21110function ɵɵi18nEnd() {
21111 setInI18nBlock(false);
21112}
21113/**
21114 *
21115 * Use this instruction to create a translation block that doesn't contain any placeholder.
21116 * It calls both {@link i18nStart} and {@link i18nEnd} in one instruction.
21117 *
21118 * The translation `message` is the value which is locale specific. The translation string may
21119 * contain placeholders which associate inner elements and sub-templates within the translation.
21120 *
21121 * The translation `message` placeholders are:
21122 * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
21123 * interpolated into. The placeholder `index` points to the expression binding index. An optional
21124 * `block` that matches the sub-template in which it was declared.
21125 * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
21126 * and end of DOM element that were embedded in the original translation block. The placeholder
21127 * `index` points to the element index in the template instructions set. An optional `block` that
21128 * matches the sub-template in which it was declared.
21129 * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
21130 * split up and translated separately in each angular template function. The `index` points to the
21131 * `template` instruction index. A `block` that matches the sub-template in which it was declared.
21132 *
21133 * @param index A unique index of the translation in the static block.
21134 * @param messageIndex An index of the translation message from the `def.consts` array.
21135 * @param subTemplateIndex Optional sub-template index in the `message`.
21136 *
21137 * @codeGenApi
21138 */
21139function ɵɵi18n(index, messageIndex, subTemplateIndex) {
21140 ɵɵi18nStart(index, messageIndex, subTemplateIndex);
21141 ɵɵi18nEnd();
21142}
21143/**
21144 * Marks a list of attributes as translatable.
21145 *
21146 * @param index A unique index in the static block
21147 * @param values
21148 *
21149 * @codeGenApi
21150 */
21151function ɵɵi18nAttributes(index, attrsIndex) {
21152 const tView = getTView();
21153 ngDevMode && assertDefined(tView, `tView should be defined`);
21154 const attrs = getConstant(tView.consts, attrsIndex);
21155 i18nAttributesFirstPass(tView, index + HEADER_OFFSET, attrs);
21156}
21157/**
21158 * Stores the values of the bindings during each update cycle in order to determine if we need to
21159 * update the translated nodes.
21160 *
21161 * @param value The binding's value
21162 * @returns This function returns itself so that it may be chained
21163 * (e.g. `i18nExp(ctx.name)(ctx.title)`)
21164 *
21165 * @codeGenApi
21166 */
21167function ɵɵi18nExp(value) {
21168 const lView = getLView();
21169 setMaskBit(bindingUpdated(lView, nextBindingIndex(), value));
21170 return ɵɵi18nExp;
21171}
21172/**
21173 * Updates a translation block or an i18n attribute when the bindings have changed.
21174 *
21175 * @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes}
21176 * (i18n attribute) on which it should update the content.
21177 *
21178 * @codeGenApi
21179 */
21180function ɵɵi18nApply(index) {
21181 applyI18n(getTView(), getLView(), index + HEADER_OFFSET);
21182}
21183/**
21184 * Handles message string post-processing for internationalization.
21185 *
21186 * Handles message string post-processing by transforming it from intermediate
21187 * format (that might contain some markers that we need to replace) to the final
21188 * form, consumable by i18nStart instruction. Post processing steps include:
21189 *
21190 * 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�])
21191 * 2. Replace all ICU vars (like "VAR_PLURAL")
21192 * 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
21193 * 4. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�)
21194 * in case multiple ICUs have the same placeholder name
21195 *
21196 * @param message Raw translation string for post processing
21197 * @param replacements Set of replacements that should be applied
21198 *
21199 * @returns Transformed string that can be consumed by i18nStart instruction
21200 *
21201 * @codeGenApi
21202 */
21203function ɵɵi18nPostprocess(message, replacements = {}) {
21204 return i18nPostprocess(message, replacements);
21205}
21206
21207/**
21208 * @license
21209 * Copyright Google LLC All Rights Reserved.
21210 *
21211 * Use of this source code is governed by an MIT-style license that can be
21212 * found in the LICENSE file at https://angular.io/license
21213 */
21214
21215/**
21216 * @license
21217 * Copyright Google LLC All Rights Reserved.
21218 *
21219 * Use of this source code is governed by an MIT-style license that can be
21220 * found in the LICENSE file at https://angular.io/license
21221 */
21222/**
21223 * Resolves the providers which are defined in the DirectiveDef.
21224 *
21225 * When inserting the tokens and the factories in their respective arrays, we can assume that
21226 * this method is called first for the component (if any), and then for other directives on the same
21227 * node.
21228 * As a consequence,the providers are always processed in that order:
21229 * 1) The view providers of the component
21230 * 2) The providers of the component
21231 * 3) The providers of the other directives
21232 * This matches the structure of the injectables arrays of a view (for each node).
21233 * So the tokens and the factories can be pushed at the end of the arrays, except
21234 * in one case for multi providers.
21235 *
21236 * @param def the directive definition
21237 * @param providers: Array of `providers`.
21238 * @param viewProviders: Array of `viewProviders`.
21239 */
21240function providersResolver(def, providers, viewProviders) {
21241 const tView = getTView();
21242 if (tView.firstCreatePass) {
21243 const isComponent = isComponentDef(def);
21244 // The list of view providers is processed first, and the flags are updated
21245 resolveProvider(viewProviders, tView.data, tView.blueprint, isComponent, true);
21246 // Then, the list of providers is processed, and the flags are updated
21247 resolveProvider(providers, tView.data, tView.blueprint, isComponent, false);
21248 }
21249}
21250/**
21251 * Resolves a provider and publishes it to the DI system.
21252 */
21253function resolveProvider(provider, tInjectables, lInjectablesBlueprint, isComponent, isViewProvider) {
21254 provider = resolveForwardRef(provider);
21255 if (Array.isArray(provider)) {
21256 // Recursively call `resolveProvider`
21257 // Recursion is OK in this case because this code will not be in hot-path once we implement
21258 // cloning of the initial state.
21259 for (let i = 0; i < provider.length; i++) {
21260 resolveProvider(provider[i], tInjectables, lInjectablesBlueprint, isComponent, isViewProvider);
21261 }
21262 }
21263 else {
21264 const tView = getTView();
21265 const lView = getLView();
21266 let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider.provide);
21267 let providerFactory = providerToFactory(provider);
21268 const tNode = getCurrentTNode();
21269 const beginIndex = tNode.providerIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */;
21270 const endIndex = tNode.directiveStart;
21271 const cptViewProvidersCount = tNode.providerIndexes >> 20 /* TNodeProviderIndexes.CptViewProvidersCountShift */;
21272 if (isTypeProvider(provider) || !provider.multi) {
21273 // Single provider case: the factory is created and pushed immediately
21274 const factory = new NodeInjectorFactory(providerFactory, isViewProvider, ɵɵdirectiveInject);
21275 const existingFactoryIndex = indexOf(token, tInjectables, isViewProvider ? beginIndex : beginIndex + cptViewProvidersCount, endIndex);
21276 if (existingFactoryIndex === -1) {
21277 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, token);
21278 registerDestroyHooksIfSupported(tView, provider, tInjectables.length);
21279 tInjectables.push(token);
21280 tNode.directiveStart++;
21281 tNode.directiveEnd++;
21282 if (isViewProvider) {
21283 tNode.providerIndexes += 1048576 /* TNodeProviderIndexes.CptViewProvidersCountShifter */;
21284 }
21285 lInjectablesBlueprint.push(factory);
21286 lView.push(factory);
21287 }
21288 else {
21289 lInjectablesBlueprint[existingFactoryIndex] = factory;
21290 lView[existingFactoryIndex] = factory;
21291 }
21292 }
21293 else {
21294 // Multi provider case:
21295 // We create a multi factory which is going to aggregate all the values.
21296 // Since the output of such a factory depends on content or view injection,
21297 // we create two of them, which are linked together.
21298 //
21299 // The first one (for view providers) is always in the first block of the injectables array,
21300 // and the second one (for providers) is always in the second block.
21301 // This is important because view providers have higher priority. When a multi token
21302 // is being looked up, the view providers should be found first.
21303 // Note that it is not possible to have a multi factory in the third block (directive block).
21304 //
21305 // The algorithm to process multi providers is as follows:
21306 // 1) If the multi provider comes from the `viewProviders` of the component:
21307 // a) If the special view providers factory doesn't exist, it is created and pushed.
21308 // b) Else, the multi provider is added to the existing multi factory.
21309 // 2) If the multi provider comes from the `providers` of the component or of another
21310 // directive:
21311 // a) If the multi factory doesn't exist, it is created and provider pushed into it.
21312 // It is also linked to the multi factory for view providers, if it exists.
21313 // b) Else, the multi provider is added to the existing multi factory.
21314 const existingProvidersFactoryIndex = indexOf(token, tInjectables, beginIndex + cptViewProvidersCount, endIndex);
21315 const existingViewProvidersFactoryIndex = indexOf(token, tInjectables, beginIndex, beginIndex + cptViewProvidersCount);
21316 const doesProvidersFactoryExist = existingProvidersFactoryIndex >= 0 &&
21317 lInjectablesBlueprint[existingProvidersFactoryIndex];
21318 const doesViewProvidersFactoryExist = existingViewProvidersFactoryIndex >= 0 &&
21319 lInjectablesBlueprint[existingViewProvidersFactoryIndex];
21320 if (isViewProvider && !doesViewProvidersFactoryExist ||
21321 !isViewProvider && !doesProvidersFactoryExist) {
21322 // Cases 1.a and 2.a
21323 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, token);
21324 const factory = multiFactory(isViewProvider ? multiViewProvidersFactoryResolver : multiProvidersFactoryResolver, lInjectablesBlueprint.length, isViewProvider, isComponent, providerFactory);
21325 if (!isViewProvider && doesViewProvidersFactoryExist) {
21326 lInjectablesBlueprint[existingViewProvidersFactoryIndex].providerFactory = factory;
21327 }
21328 registerDestroyHooksIfSupported(tView, provider, tInjectables.length, 0);
21329 tInjectables.push(token);
21330 tNode.directiveStart++;
21331 tNode.directiveEnd++;
21332 if (isViewProvider) {
21333 tNode.providerIndexes += 1048576 /* TNodeProviderIndexes.CptViewProvidersCountShifter */;
21334 }
21335 lInjectablesBlueprint.push(factory);
21336 lView.push(factory);
21337 }
21338 else {
21339 // Cases 1.b and 2.b
21340 const indexInFactory = multiFactoryAdd(lInjectablesBlueprint[isViewProvider ? existingViewProvidersFactoryIndex :
21341 existingProvidersFactoryIndex], providerFactory, !isViewProvider && isComponent);
21342 registerDestroyHooksIfSupported(tView, provider, existingProvidersFactoryIndex > -1 ? existingProvidersFactoryIndex :
21343 existingViewProvidersFactoryIndex, indexInFactory);
21344 }
21345 if (!isViewProvider && isComponent && doesViewProvidersFactoryExist) {
21346 lInjectablesBlueprint[existingViewProvidersFactoryIndex].componentProviders++;
21347 }
21348 }
21349 }
21350}
21351/**
21352 * Registers the `ngOnDestroy` hook of a provider, if the provider supports destroy hooks.
21353 * @param tView `TView` in which to register the hook.
21354 * @param provider Provider whose hook should be registered.
21355 * @param contextIndex Index under which to find the context for the hook when it's being invoked.
21356 * @param indexInFactory Only required for `multi` providers. Index of the provider in the multi
21357 * provider factory.
21358 */
21359function registerDestroyHooksIfSupported(tView, provider, contextIndex, indexInFactory) {
21360 const providerIsTypeProvider = isTypeProvider(provider);
21361 const providerIsClassProvider = isClassProvider(provider);
21362 if (providerIsTypeProvider || providerIsClassProvider) {
21363 // Resolve forward references as `useClass` can hold a forward reference.
21364 const classToken = providerIsClassProvider ? resolveForwardRef(provider.useClass) : provider;
21365 const prototype = classToken.prototype;
21366 const ngOnDestroy = prototype.ngOnDestroy;
21367 if (ngOnDestroy) {
21368 const hooks = tView.destroyHooks || (tView.destroyHooks = []);
21369 if (!providerIsTypeProvider && provider.multi) {
21370 ngDevMode &&
21371 assertDefined(indexInFactory, 'indexInFactory when registering multi factory destroy hook');
21372 const existingCallbacksIndex = hooks.indexOf(contextIndex);
21373 if (existingCallbacksIndex === -1) {
21374 hooks.push(contextIndex, [indexInFactory, ngOnDestroy]);
21375 }
21376 else {
21377 hooks[existingCallbacksIndex + 1].push(indexInFactory, ngOnDestroy);
21378 }
21379 }
21380 else {
21381 hooks.push(contextIndex, ngOnDestroy);
21382 }
21383 }
21384 }
21385}
21386/**
21387 * Add a factory in a multi factory.
21388 * @returns Index at which the factory was inserted.
21389 */
21390function multiFactoryAdd(multiFactory, factory, isComponentProvider) {
21391 if (isComponentProvider) {
21392 multiFactory.componentProviders++;
21393 }
21394 return multiFactory.multi.push(factory) - 1;
21395}
21396/**
21397 * Returns the index of item in the array, but only in the begin to end range.
21398 */
21399function indexOf(item, arr, begin, end) {
21400 for (let i = begin; i < end; i++) {
21401 if (arr[i] === item)
21402 return i;
21403 }
21404 return -1;
21405}
21406/**
21407 * Use this with `multi` `providers`.
21408 */
21409function multiProvidersFactoryResolver(_, tData, lData, tNode) {
21410 return multiResolve(this.multi, []);
21411}
21412/**
21413 * Use this with `multi` `viewProviders`.
21414 *
21415 * This factory knows how to concatenate itself with the existing `multi` `providers`.
21416 */
21417function multiViewProvidersFactoryResolver(_, tData, lView, tNode) {
21418 const factories = this.multi;
21419 let result;
21420 if (this.providerFactory) {
21421 const componentCount = this.providerFactory.componentProviders;
21422 const multiProviders = getNodeInjectable(lView, lView[TVIEW], this.providerFactory.index, tNode);
21423 // Copy the section of the array which contains `multi` `providers` from the component
21424 result = multiProviders.slice(0, componentCount);
21425 // Insert the `viewProvider` instances.
21426 multiResolve(factories, result);
21427 // Copy the section of the array which contains `multi` `providers` from other directives
21428 for (let i = componentCount; i < multiProviders.length; i++) {
21429 result.push(multiProviders[i]);
21430 }
21431 }
21432 else {
21433 result = [];
21434 // Insert the `viewProvider` instances.
21435 multiResolve(factories, result);
21436 }
21437 return result;
21438}
21439/**
21440 * Maps an array of factories into an array of values.
21441 */
21442function multiResolve(factories, result) {
21443 for (let i = 0; i < factories.length; i++) {
21444 const factory = factories[i];
21445 result.push(factory());
21446 }
21447 return result;
21448}
21449/**
21450 * Creates a multi factory.
21451 */
21452function multiFactory(factoryFn, index, isViewProvider, isComponent, f) {
21453 const factory = new NodeInjectorFactory(factoryFn, isViewProvider, ɵɵdirectiveInject);
21454 factory.multi = [];
21455 factory.index = index;
21456 factory.componentProviders = 0;
21457 multiFactoryAdd(factory, f, isComponent && !isViewProvider);
21458 return factory;
21459}
21460
21461/**
21462 * This feature resolves the providers of a directive (or component),
21463 * and publish them into the DI system, making it visible to others for injection.
21464 *
21465 * For example:
21466 * ```ts
21467 * class ComponentWithProviders {
21468 * constructor(private greeter: GreeterDE) {}
21469 *
21470 * static ɵcmp = defineComponent({
21471 * type: ComponentWithProviders,
21472 * selectors: [['component-with-providers']],
21473 * factory: () => new ComponentWithProviders(directiveInject(GreeterDE as any)),
21474 * decls: 1,
21475 * vars: 1,
21476 * template: function(fs: RenderFlags, ctx: ComponentWithProviders) {
21477 * if (fs & RenderFlags.Create) {
21478 * ɵɵtext(0);
21479 * }
21480 * if (fs & RenderFlags.Update) {
21481 * ɵɵtextInterpolate(ctx.greeter.greet());
21482 * }
21483 * },
21484 * features: [ɵɵProvidersFeature([GreeterDE])]
21485 * });
21486 * }
21487 * ```
21488 *
21489 * @param definition
21490 *
21491 * @codeGenApi
21492 */
21493function ɵɵProvidersFeature(providers, viewProviders = []) {
21494 return (definition) => {
21495 definition.providersResolver =
21496 (def, processProvidersFn) => {
21497 return providersResolver(def, //
21498 processProvidersFn ? processProvidersFn(providers) : providers, //
21499 viewProviders);
21500 };
21501 };
21502}
21503
21504/**
21505 * @license
21506 * Copyright Google LLC All Rights Reserved.
21507 *
21508 * Use of this source code is governed by an MIT-style license that can be
21509 * found in the LICENSE file at https://angular.io/license
21510 */
21511function noComponentFactoryError(component) {
21512 const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
21513 error[ERROR_COMPONENT] = component;
21514 return error;
21515}
21516const ERROR_COMPONENT = 'ngComponent';
21517function getComponent(error) {
21518 return error[ERROR_COMPONENT];
21519}
21520class _NullComponentFactoryResolver {
21521 resolveComponentFactory(component) {
21522 throw noComponentFactoryError(component);
21523 }
21524}
21525/**
21526 * A simple registry that maps `Components` to generated `ComponentFactory` classes
21527 * that can be used to create instances of components.
21528 * Use to obtain the factory for a given component type,
21529 * then use the factory's `create()` method to create a component of that type.
21530 *
21531 * Note: since v13, dynamic component creation via
21532 * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
21533 * does **not** require resolving component factory: component class can be used directly.
21534 *
21535 * @publicApi
21536 *
21537 * @deprecated Angular no longer requires Component factories. Please use other APIs where
21538 * Component class can be used directly.
21539 */
21540class ComponentFactoryResolver$1 {
21541}
21542ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
21543
21544/**
21545 * @license
21546 * Copyright Google LLC All Rights Reserved.
21547 *
21548 * Use of this source code is governed by an MIT-style license that can be
21549 * found in the LICENSE file at https://angular.io/license
21550 */
21551/**
21552 * Represents an instance of an `NgModule` created by an `NgModuleFactory`.
21553 * Provides access to the `NgModule` instance and related objects.
21554 *
21555 * @publicApi
21556 */
21557class NgModuleRef$1 {
21558}
21559/**
21560 * @publicApi
21561 *
21562 * @deprecated
21563 * This class was mostly used as a part of ViewEngine-based JIT API and is no longer needed in Ivy
21564 * JIT mode. See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes)
21565 * for additional context. Angular provides APIs that accept NgModule classes directly (such as
21566 * [PlatformRef.bootstrapModule](api/core/PlatformRef#bootstrapModule) and
21567 * [createNgModuleRef](api/core/createNgModuleRef)), consider switching to those APIs instead of
21568 * using factory-based ones.
21569 */
21570class NgModuleFactory$1 {
21571}
21572
21573/**
21574 * @license
21575 * Copyright Google LLC All Rights Reserved.
21576 *
21577 * Use of this source code is governed by an MIT-style license that can be
21578 * found in the LICENSE file at https://angular.io/license
21579 */
21580/**
21581 * Represents a component created by a `ComponentFactory`.
21582 * Provides access to the component instance and related objects,
21583 * and provides the means of destroying the instance.
21584 *
21585 * @publicApi
21586 */
21587class ComponentRef$1 {
21588}
21589/**
21590 * Base class for a factory that can create a component dynamically.
21591 * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
21592 * Use the resulting `ComponentFactory.create()` method to create a component of that type.
21593 *
21594 * @see [Dynamic Components](guide/dynamic-component-loader)
21595 *
21596 * @publicApi
21597 *
21598 * @deprecated Angular no longer requires Component factories. Please use other APIs where
21599 * Component class can be used directly.
21600 */
21601class ComponentFactory$1 {
21602}
21603
21604/**
21605 * @license
21606 * Copyright Google LLC All Rights Reserved.
21607 *
21608 * Use of this source code is governed by an MIT-style license that can be
21609 * found in the LICENSE file at https://angular.io/license
21610 */
21611/**
21612 * Creates an ElementRef from the most recent node.
21613 *
21614 * @returns The ElementRef instance to use
21615 */
21616function injectElementRef() {
21617 return createElementRef(getCurrentTNode(), getLView());
21618}
21619/**
21620 * Creates an ElementRef given a node.
21621 *
21622 * @param tNode The node for which you'd like an ElementRef
21623 * @param lView The view to which the node belongs
21624 * @returns The ElementRef instance to use
21625 */
21626function createElementRef(tNode, lView) {
21627 return new ElementRef(getNativeByTNode(tNode, lView));
21628}
21629/**
21630 * A wrapper around a native element inside of a View.
21631 *
21632 * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
21633 * element.
21634 *
21635 * @security Permitting direct access to the DOM can make your application more vulnerable to
21636 * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
21637 * [Security Guide](https://g.co/ng/security).
21638 *
21639 * @publicApi
21640 */
21641// Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
21642// i.e. users have to ask for what they need. With that, we can build better analysis tools
21643// and could do better codegen in the future.
21644class ElementRef {
21645 constructor(nativeElement) {
21646 this.nativeElement = nativeElement;
21647 }
21648}
21649/**
21650 * @internal
21651 * @nocollapse
21652 */
21653ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
21654/**
21655 * Unwraps `ElementRef` and return the `nativeElement`.
21656 *
21657 * @param value value to unwrap
21658 * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
21659 */
21660function unwrapElementRef(value) {
21661 return value instanceof ElementRef ? value.nativeElement : value;
21662}
21663
21664/**
21665 * @license
21666 * Copyright Google LLC All Rights Reserved.
21667 *
21668 * Use of this source code is governed by an MIT-style license that can be
21669 * found in the LICENSE file at https://angular.io/license
21670 */
21671const Renderer2Interceptor = new InjectionToken('Renderer2Interceptor');
21672/**
21673 * Creates and initializes a custom renderer that implements the `Renderer2` base class.
21674 *
21675 * @publicApi
21676 */
21677class RendererFactory2 {
21678}
21679/**
21680 * Extend this base class to implement custom rendering. By default, Angular
21681 * renders a template into DOM. You can use custom rendering to intercept
21682 * rendering calls, or to render to something other than DOM.
21683 *
21684 * Create your custom renderer using `RendererFactory2`.
21685 *
21686 * Use a custom renderer to bypass Angular's templating and
21687 * make custom UI changes that can't be expressed declaratively.
21688 * For example if you need to set a property or an attribute whose name is
21689 * not statically known, use the `setProperty()` or
21690 * `setAttribute()` method.
21691 *
21692 * @publicApi
21693 */
21694class Renderer2 {
21695}
21696/**
21697 * @internal
21698 * @nocollapse
21699 */
21700Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
21701/** Returns a Renderer2 (or throws when application was bootstrapped with Renderer3) */
21702function getOrCreateRenderer2(lView) {
21703 const renderer = lView[RENDERER];
21704 if (ngDevMode && !isProceduralRenderer(renderer)) {
21705 throw new Error('Cannot inject Renderer2 when the application uses Renderer3!');
21706 }
21707 return renderer;
21708}
21709/** Injects a Renderer2 for the current component. */
21710function injectRenderer2() {
21711 // We need the Renderer to be based on the component that it's being injected into, however since
21712 // DI happens before we've entered its view, `getLView` will return the parent view instead.
21713 const lView = getLView();
21714 const tNode = getCurrentTNode();
21715 const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
21716 return getOrCreateRenderer2(isLView(nodeAtIndex) ? nodeAtIndex : lView);
21717}
21718
21719/**
21720 * @license
21721 * Copyright Google LLC All Rights Reserved.
21722 *
21723 * Use of this source code is governed by an MIT-style license that can be
21724 * found in the LICENSE file at https://angular.io/license
21725 */
21726/**
21727 * Sanitizer is used by the views to sanitize potentially dangerous values.
21728 *
21729 * @publicApi
21730 */
21731class Sanitizer {
21732}
21733/** @nocollapse */
21734Sanitizer.ɵprov = ɵɵdefineInjectable({
21735 token: Sanitizer,
21736 providedIn: 'root',
21737 factory: () => null,
21738});
21739
21740/**
21741 * @license
21742 * Copyright Google LLC All Rights Reserved.
21743 *
21744 * Use of this source code is governed by an MIT-style license that can be
21745 * found in the LICENSE file at https://angular.io/license
21746 */
21747/**
21748 * @description Represents the version of Angular
21749 *
21750 * @publicApi
21751 */
21752class Version {
21753 constructor(full) {
21754 this.full = full;
21755 this.major = full.split('.')[0];
21756 this.minor = full.split('.')[1];
21757 this.patch = full.split('.').slice(2).join('.');
21758 }
21759}
21760/**
21761 * @publicApi
21762 */
21763const VERSION = new Version('14.0.3');
21764
21765/**
21766 * @license
21767 * Copyright Google LLC All Rights Reserved.
21768 *
21769 * Use of this source code is governed by an MIT-style license that can be
21770 * found in the LICENSE file at https://angular.io/license
21771 */
21772// This default value is when checking the hierarchy for a token.
21773//
21774// It means both:
21775// - the token is not provided by the current injector,
21776// - only the element injectors should be checked (ie do not check module injectors
21777//
21778// mod1
21779// /
21780// el1 mod2
21781// \ /
21782// el2
21783//
21784// When requesting el2.injector.get(token), we should check in the following order and return the
21785// first found value:
21786// - el2.injector.get(token, default)
21787// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
21788// - mod2.injector.get(token, default)
21789const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
21790
21791/**
21792 * @license
21793 * Copyright Google LLC All Rights Reserved.
21794 *
21795 * Use of this source code is governed by an MIT-style license that can be
21796 * found in the LICENSE file at https://angular.io/license
21797 */
21798function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
21799 while (tNode !== null) {
21800 ngDevMode &&
21801 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
21802 const lNode = lView[tNode.index];
21803 if (lNode !== null) {
21804 result.push(unwrapRNode(lNode));
21805 }
21806 // A given lNode can represent either a native node or a LContainer (when it is a host of a
21807 // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
21808 // from the views in this container.
21809 if (isLContainer(lNode)) {
21810 for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
21811 const lViewInAContainer = lNode[i];
21812 const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
21813 if (lViewFirstChildTNode !== null) {
21814 collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
21815 }
21816 }
21817 }
21818 const tNodeType = tNode.type;
21819 if (tNodeType & 8 /* TNodeType.ElementContainer */) {
21820 collectNativeNodes(tView, lView, tNode.child, result);
21821 }
21822 else if (tNodeType & 32 /* TNodeType.Icu */) {
21823 const nextRNode = icuContainerIterate(tNode, lView);
21824 let rNode;
21825 while (rNode = nextRNode()) {
21826 result.push(rNode);
21827 }
21828 }
21829 else if (tNodeType & 16 /* TNodeType.Projection */) {
21830 const nodesInSlot = getProjectionNodes(lView, tNode);
21831 if (Array.isArray(nodesInSlot)) {
21832 result.push(...nodesInSlot);
21833 }
21834 else {
21835 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
21836 ngDevMode && assertParentView(parentView);
21837 collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
21838 }
21839 }
21840 tNode = isProjection ? tNode.projectionNext : tNode.next;
21841 }
21842 return result;
21843}
21844
21845/**
21846 * @license
21847 * Copyright Google LLC All Rights Reserved.
21848 *
21849 * Use of this source code is governed by an MIT-style license that can be
21850 * found in the LICENSE file at https://angular.io/license
21851 */
21852class ViewRef$1 {
21853 constructor(
21854 /**
21855 * This represents `LView` associated with the component when ViewRef is a ChangeDetectorRef.
21856 *
21857 * When ViewRef is created for a dynamic component, this also represents the `LView` for the
21858 * component.
21859 *
21860 * For a "regular" ViewRef created for an embedded view, this is the `LView` for the embedded
21861 * view.
21862 *
21863 * @internal
21864 */
21865 _lView,
21866 /**
21867 * This represents the `LView` associated with the point where `ChangeDetectorRef` was
21868 * requested.
21869 *
21870 * This may be different from `_lView` if the `_cdRefInjectingView` is an embedded view.
21871 */
21872 _cdRefInjectingView) {
21873 this._lView = _lView;
21874 this._cdRefInjectingView = _cdRefInjectingView;
21875 this._appRef = null;
21876 this._attachedToViewContainer = false;
21877 }
21878 get rootNodes() {
21879 const lView = this._lView;
21880 const tView = lView[TVIEW];
21881 return collectNativeNodes(tView, lView, tView.firstChild, []);
21882 }
21883 get context() {
21884 return this._lView[CONTEXT];
21885 }
21886 set context(value) {
21887 this._lView[CONTEXT] = value;
21888 }
21889 get destroyed() {
21890 return (this._lView[FLAGS] & 128 /* LViewFlags.Destroyed */) === 128 /* LViewFlags.Destroyed */;
21891 }
21892 destroy() {
21893 if (this._appRef) {
21894 this._appRef.detachView(this);
21895 }
21896 else if (this._attachedToViewContainer) {
21897 const parent = this._lView[PARENT];
21898 if (isLContainer(parent)) {
21899 const viewRefs = parent[VIEW_REFS];
21900 const index = viewRefs ? viewRefs.indexOf(this) : -1;
21901 if (index > -1) {
21902 ngDevMode &&
21903 assertEqual(index, parent.indexOf(this._lView) - CONTAINER_HEADER_OFFSET, 'An attached view should be in the same position within its container as its ViewRef in the VIEW_REFS array.');
21904 detachView(parent, index);
21905 removeFromArray(viewRefs, index);
21906 }
21907 }
21908 this._attachedToViewContainer = false;
21909 }
21910 destroyLView(this._lView[TVIEW], this._lView);
21911 }
21912 onDestroy(callback) {
21913 storeCleanupWithContext(this._lView[TVIEW], this._lView, null, callback);
21914 }
21915 /**
21916 * Marks a view and all of its ancestors dirty.
21917 *
21918 * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is
21919 * checked when it needs to be re-rendered but the two normal triggers haven't marked it
21920 * dirty (i.e. inputs haven't changed and events haven't fired in the view).
21921 *
21922 * <!-- TODO: Add a link to a chapter on OnPush components -->
21923 *
21924 * @usageNotes
21925 * ### Example
21926 *
21927 * ```typescript
21928 * @Component({
21929 * selector: 'app-root',
21930 * template: `Number of ticks: {{numberOfTicks}}`
21931 * changeDetection: ChangeDetectionStrategy.OnPush,
21932 * })
21933 * class AppComponent {
21934 * numberOfTicks = 0;
21935 *
21936 * constructor(private ref: ChangeDetectorRef) {
21937 * setInterval(() => {
21938 * this.numberOfTicks++;
21939 * // the following is required, otherwise the view will not be updated
21940 * this.ref.markForCheck();
21941 * }, 1000);
21942 * }
21943 * }
21944 * ```
21945 */
21946 markForCheck() {
21947 markViewDirty(this._cdRefInjectingView || this._lView);
21948 }
21949 /**
21950 * Detaches the view from the change detection tree.
21951 *
21952 * Detached views will not be checked during change detection runs until they are
21953 * re-attached, even if they are dirty. `detach` can be used in combination with
21954 * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change
21955 * detection checks.
21956 *
21957 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
21958 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
21959 *
21960 * @usageNotes
21961 * ### Example
21962 *
21963 * The following example defines a component with a large list of readonly data.
21964 * Imagine the data changes constantly, many times per second. For performance reasons,
21965 * we want to check and update the list every five seconds. We can do that by detaching
21966 * the component's change detector and doing a local check every five seconds.
21967 *
21968 * ```typescript
21969 * class DataProvider {
21970 * // in a real application the returned data will be different every time
21971 * get data() {
21972 * return [1,2,3,4,5];
21973 * }
21974 * }
21975 *
21976 * @Component({
21977 * selector: 'giant-list',
21978 * template: `
21979 * <li *ngFor="let d of dataProvider.data">Data {{d}}</li>
21980 * `,
21981 * })
21982 * class GiantList {
21983 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {
21984 * ref.detach();
21985 * setInterval(() => {
21986 * this.ref.detectChanges();
21987 * }, 5000);
21988 * }
21989 * }
21990 *
21991 * @Component({
21992 * selector: 'app',
21993 * providers: [DataProvider],
21994 * template: `
21995 * <giant-list><giant-list>
21996 * `,
21997 * })
21998 * class App {
21999 * }
22000 * ```
22001 */
22002 detach() {
22003 this._lView[FLAGS] &= ~64 /* LViewFlags.Attached */;
22004 }
22005 /**
22006 * Re-attaches a view to the change detection tree.
22007 *
22008 * This can be used to re-attach views that were previously detached from the tree
22009 * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default.
22010 *
22011 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
22012 *
22013 * @usageNotes
22014 * ### Example
22015 *
22016 * The following example creates a component displaying `live` data. The component will detach
22017 * its change detector from the main change detector tree when the component's live property
22018 * is set to false.
22019 *
22020 * ```typescript
22021 * class DataProvider {
22022 * data = 1;
22023 *
22024 * constructor() {
22025 * setInterval(() => {
22026 * this.data = this.data * 2;
22027 * }, 500);
22028 * }
22029 * }
22030 *
22031 * @Component({
22032 * selector: 'live-data',
22033 * inputs: ['live'],
22034 * template: 'Data: {{dataProvider.data}}'
22035 * })
22036 * class LiveData {
22037 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {}
22038 *
22039 * set live(value) {
22040 * if (value) {
22041 * this.ref.reattach();
22042 * } else {
22043 * this.ref.detach();
22044 * }
22045 * }
22046 * }
22047 *
22048 * @Component({
22049 * selector: 'app-root',
22050 * providers: [DataProvider],
22051 * template: `
22052 * Live Update: <input type="checkbox" [(ngModel)]="live">
22053 * <live-data [live]="live"><live-data>
22054 * `,
22055 * })
22056 * class AppComponent {
22057 * live = true;
22058 * }
22059 * ```
22060 */
22061 reattach() {
22062 this._lView[FLAGS] |= 64 /* LViewFlags.Attached */;
22063 }
22064 /**
22065 * Checks the view and its children.
22066 *
22067 * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement
22068 * local change detection checks.
22069 *
22070 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
22071 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
22072 *
22073 * @usageNotes
22074 * ### Example
22075 *
22076 * The following example defines a component with a large list of readonly data.
22077 * Imagine, the data changes constantly, many times per second. For performance reasons,
22078 * we want to check and update the list every five seconds.
22079 *
22080 * We can do that by detaching the component's change detector and doing a local change detection
22081 * check every five seconds.
22082 *
22083 * See {@link ChangeDetectorRef#detach detach} for more information.
22084 */
22085 detectChanges() {
22086 detectChangesInternal(this._lView[TVIEW], this._lView, this.context);
22087 }
22088 /**
22089 * Checks the change detector and its children, and throws if any changes are detected.
22090 *
22091 * This is used in development mode to verify that running change detection doesn't
22092 * introduce other changes.
22093 */
22094 checkNoChanges() {
22095 if (ngDevMode) {
22096 checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
22097 }
22098 }
22099 attachToViewContainerRef() {
22100 if (this._appRef) {
22101 throw new RuntimeError(902 /* RuntimeErrorCode.VIEW_ALREADY_ATTACHED */, ngDevMode && 'This view is already attached directly to the ApplicationRef!');
22102 }
22103 this._attachedToViewContainer = true;
22104 }
22105 detachFromAppRef() {
22106 this._appRef = null;
22107 renderDetachView(this._lView[TVIEW], this._lView);
22108 }
22109 attachToAppRef(appRef) {
22110 if (this._attachedToViewContainer) {
22111 throw new RuntimeError(902 /* RuntimeErrorCode.VIEW_ALREADY_ATTACHED */, ngDevMode && 'This view is already attached to a ViewContainer!');
22112 }
22113 this._appRef = appRef;
22114 }
22115}
22116/** @internal */
22117class RootViewRef extends ViewRef$1 {
22118 constructor(_view) {
22119 super(_view);
22120 this._view = _view;
22121 }
22122 detectChanges() {
22123 detectChangesInRootView(this._view);
22124 }
22125 checkNoChanges() {
22126 if (ngDevMode) {
22127 checkNoChangesInRootView(this._view);
22128 }
22129 }
22130 get context() {
22131 return null;
22132 }
22133}
22134
22135/**
22136 * @license
22137 * Copyright Google LLC All Rights Reserved.
22138 *
22139 * Use of this source code is governed by an MIT-style license that can be
22140 * found in the LICENSE file at https://angular.io/license
22141 */
22142class ComponentFactoryResolver extends ComponentFactoryResolver$1 {
22143 /**
22144 * @param ngModule The NgModuleRef to which all resolved factories are bound.
22145 */
22146 constructor(ngModule) {
22147 super();
22148 this.ngModule = ngModule;
22149 }
22150 resolveComponentFactory(component) {
22151 ngDevMode && assertComponentType(component);
22152 const componentDef = getComponentDef(component);
22153 return new ComponentFactory(componentDef, this.ngModule);
22154 }
22155}
22156function toRefArray(map) {
22157 const array = [];
22158 for (let nonMinified in map) {
22159 if (map.hasOwnProperty(nonMinified)) {
22160 const minified = map[nonMinified];
22161 array.push({ propName: minified, templateName: nonMinified });
22162 }
22163 }
22164 return array;
22165}
22166function getNamespace(elementName) {
22167 const name = elementName.toLowerCase();
22168 return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null);
22169}
22170/**
22171 * Injector that looks up a value using a specific injector, before falling back to the module
22172 * injector. Used primarily when creating components or embedded views dynamically.
22173 */
22174class ChainedInjector {
22175 constructor(injector, parentInjector) {
22176 this.injector = injector;
22177 this.parentInjector = parentInjector;
22178 }
22179 get(token, notFoundValue, flags) {
22180 const value = this.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
22181 if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
22182 notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
22183 // Return the value from the root element injector when
22184 // - it provides it
22185 // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
22186 // - the module injector should not be checked
22187 // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
22188 return value;
22189 }
22190 return this.parentInjector.get(token, notFoundValue, flags);
22191 }
22192}
22193/**
22194 * Render3 implementation of {@link viewEngine_ComponentFactory}.
22195 */
22196class ComponentFactory extends ComponentFactory$1 {
22197 /**
22198 * @param componentDef The component definition.
22199 * @param ngModule The NgModuleRef to which the factory is bound.
22200 */
22201 constructor(componentDef, ngModule) {
22202 super();
22203 this.componentDef = componentDef;
22204 this.ngModule = ngModule;
22205 this.componentType = componentDef.type;
22206 this.selector = stringifyCSSSelectorList(componentDef.selectors);
22207 this.ngContentSelectors =
22208 componentDef.ngContentSelectors ? componentDef.ngContentSelectors : [];
22209 this.isBoundToModule = !!ngModule;
22210 }
22211 get inputs() {
22212 return toRefArray(this.componentDef.inputs);
22213 }
22214 get outputs() {
22215 return toRefArray(this.componentDef.outputs);
22216 }
22217 create(injector, projectableNodes, rootSelectorOrNode, environmentInjector) {
22218 environmentInjector = environmentInjector || this.ngModule;
22219 let realEnvironmentInjector = environmentInjector instanceof EnvironmentInjector ?
22220 environmentInjector :
22221 environmentInjector === null || environmentInjector === void 0 ? void 0 : environmentInjector.injector;
22222 if (realEnvironmentInjector && this.componentDef.getStandaloneInjector !== null) {
22223 realEnvironmentInjector = this.componentDef.getStandaloneInjector(realEnvironmentInjector) ||
22224 realEnvironmentInjector;
22225 }
22226 const rootViewInjector = realEnvironmentInjector ? new ChainedInjector(injector, realEnvironmentInjector) : injector;
22227 const rendererFactory = rootViewInjector.get(RendererFactory2, domRendererFactory3);
22228 const sanitizer = rootViewInjector.get(Sanitizer, null);
22229 const hostRenderer = rendererFactory.createRenderer(null, this.componentDef);
22230 // Determine a tag name used for creating host elements when this component is created
22231 // dynamically. Default to 'div' if this component did not specify any tag name in its selector.
22232 const elementName = this.componentDef.selectors[0][0] || 'div';
22233 const hostRNode = rootSelectorOrNode ?
22234 locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) :
22235 createElementNode(rendererFactory.createRenderer(null, this.componentDef), elementName, getNamespace(elementName));
22236 const rootFlags = this.componentDef.onPush ? 32 /* LViewFlags.Dirty */ | 256 /* LViewFlags.IsRoot */ :
22237 16 /* LViewFlags.CheckAlways */ | 256 /* LViewFlags.IsRoot */;
22238 const rootContext = createRootContext();
22239 // Create the root view. Uses empty TView and ContentTemplate.
22240 const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null);
22241 const rootLView = createLView(null, rootTView, rootContext, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector, null);
22242 // rootView is the parent when bootstrapping
22243 // TODO(misko): it looks like we are entering view here but we don't really need to as
22244 // `renderView` does that. However as the code is written it is needed because
22245 // `createRootComponentView` and `createRootComponent` both read global state. Fixing those
22246 // issues would allow us to drop this.
22247 enterView(rootLView);
22248 let component;
22249 let tElementNode;
22250 try {
22251 const componentView = createRootComponentView(hostRNode, this.componentDef, rootLView, rendererFactory, hostRenderer);
22252 if (hostRNode) {
22253 if (rootSelectorOrNode) {
22254 setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]);
22255 }
22256 else {
22257 // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
22258 // is not defined), also apply attributes and classes extracted from component selector.
22259 // Extract attributes and classes from the first selector only to match VE behavior.
22260 const { attrs, classes } = extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
22261 if (attrs) {
22262 setUpAttributes(hostRenderer, hostRNode, attrs);
22263 }
22264 if (classes && classes.length > 0) {
22265 writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
22266 }
22267 }
22268 }
22269 tElementNode = getTNode(rootTView, HEADER_OFFSET);
22270 if (projectableNodes !== undefined) {
22271 const projection = tElementNode.projection = [];
22272 for (let i = 0; i < this.ngContentSelectors.length; i++) {
22273 const nodesforSlot = projectableNodes[i];
22274 // Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
22275 // case). Here we do normalize passed data structure to be an array of arrays to avoid
22276 // complex checks down the line.
22277 // We also normalize the length of the passed in projectable nodes (to match the number of
22278 // <ng-container> slots defined by a component).
22279 projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
22280 }
22281 }
22282 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
22283 // executed here?
22284 // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
22285 component = createRootComponent(componentView, this.componentDef, rootLView, rootContext, [LifecycleHooksFeature]);
22286 renderView(rootTView, rootLView, null);
22287 }
22288 finally {
22289 leaveView();
22290 }
22291 return new ComponentRef(this.componentType, component, createElementRef(tElementNode, rootLView), rootLView, tElementNode);
22292 }
22293}
22294const componentFactoryResolver = new ComponentFactoryResolver();
22295/**
22296 * Creates a ComponentFactoryResolver and stores it on the injector. Or, if the
22297 * ComponentFactoryResolver
22298 * already exists, retrieves the existing ComponentFactoryResolver.
22299 *
22300 * @returns The ComponentFactoryResolver instance to use
22301 */
22302function injectComponentFactoryResolver() {
22303 return componentFactoryResolver;
22304}
22305/**
22306 * Represents an instance of a Component created via a {@link ComponentFactory}.
22307 *
22308 * `ComponentRef` provides access to the Component Instance as well other objects related to this
22309 * Component Instance and allows you to destroy the Component Instance via the {@link #destroy}
22310 * method.
22311 *
22312 */
22313class ComponentRef extends ComponentRef$1 {
22314 constructor(componentType, instance, location, _rootLView, _tNode) {
22315 super();
22316 this.location = location;
22317 this._rootLView = _rootLView;
22318 this._tNode = _tNode;
22319 this.instance = instance;
22320 this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView);
22321 this.componentType = componentType;
22322 }
22323 get injector() {
22324 return new NodeInjector(this._tNode, this._rootLView);
22325 }
22326 destroy() {
22327 this.hostView.destroy();
22328 }
22329 onDestroy(callback) {
22330 this.hostView.onDestroy(callback);
22331 }
22332}
22333
22334/**
22335 * @license
22336 * Copyright Google LLC All Rights Reserved.
22337 *
22338 * Use of this source code is governed by an MIT-style license that can be
22339 * found in the LICENSE file at https://angular.io/license
22340 */
22341/**
22342 * Returns a new NgModuleRef instance based on the NgModule class and parent injector provided.
22343 * @param ngModule NgModule class.
22344 * @param parentInjector Optional injector instance to use as a parent for the module injector. If
22345 * not provided, `NullInjector` will be used instead.
22346 * @publicApi
22347 */
22348function createNgModuleRef(ngModule, parentInjector) {
22349 return new NgModuleRef(ngModule, parentInjector !== null && parentInjector !== void 0 ? parentInjector : null);
22350}
22351class NgModuleRef extends NgModuleRef$1 {
22352 constructor(ngModuleType, _parent) {
22353 super();
22354 this._parent = _parent;
22355 // tslint:disable-next-line:require-internal-with-underscore
22356 this._bootstrapComponents = [];
22357 this.injector = this;
22358 this.destroyCbs = [];
22359 // When bootstrapping a module we have a dependency graph that looks like this:
22360 // ApplicationRef -> ComponentFactoryResolver -> NgModuleRef. The problem is that if the
22361 // module being resolved tries to inject the ComponentFactoryResolver, it'll create a
22362 // circular dependency which will result in a runtime error, because the injector doesn't
22363 // exist yet. We work around the issue by creating the ComponentFactoryResolver ourselves
22364 // and providing it, rather than letting the injector resolve it.
22365 this.componentFactoryResolver = new ComponentFactoryResolver(this);
22366 const ngModuleDef = getNgModuleDef(ngModuleType);
22367 ngDevMode &&
22368 assertDefined(ngModuleDef, `NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`);
22369 this._bootstrapComponents = maybeUnwrapFn(ngModuleDef.bootstrap);
22370 this._r3Injector = createInjectorWithoutInjectorInstances(ngModuleType, _parent, [
22371 { provide: NgModuleRef$1, useValue: this }, {
22372 provide: ComponentFactoryResolver$1,
22373 useValue: this.componentFactoryResolver
22374 }
22375 ], stringify(ngModuleType), new Set(['environment']));
22376 // We need to resolve the injector types separately from the injector creation, because
22377 // the module might be trying to use this ref in its constructor for DI which will cause a
22378 // circular error that will eventually error out, because the injector isn't created yet.
22379 this._r3Injector.resolveInjectorInitializers();
22380 this.instance = this.get(ngModuleType);
22381 }
22382 get(token, notFoundValue = Injector.THROW_IF_NOT_FOUND, injectFlags = InjectFlags.Default) {
22383 if (token === Injector || token === NgModuleRef$1 || token === INJECTOR) {
22384 return this;
22385 }
22386 return this._r3Injector.get(token, notFoundValue, injectFlags);
22387 }
22388 destroy() {
22389 ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
22390 const injector = this._r3Injector;
22391 !injector.destroyed && injector.destroy();
22392 this.destroyCbs.forEach(fn => fn());
22393 this.destroyCbs = null;
22394 }
22395 onDestroy(callback) {
22396 ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
22397 this.destroyCbs.push(callback);
22398 }
22399}
22400class NgModuleFactory extends NgModuleFactory$1 {
22401 constructor(moduleType) {
22402 super();
22403 this.moduleType = moduleType;
22404 }
22405 create(parentInjector) {
22406 return new NgModuleRef(this.moduleType, parentInjector);
22407 }
22408}
22409class EnvironmentNgModuleRefAdapter extends NgModuleRef$1 {
22410 constructor(providers, parent, source) {
22411 super();
22412 this.componentFactoryResolver = new ComponentFactoryResolver(this);
22413 this.instance = null;
22414 const injector = new R3Injector([
22415 ...providers,
22416 { provide: NgModuleRef$1, useValue: this },
22417 { provide: ComponentFactoryResolver$1, useValue: this.componentFactoryResolver },
22418 ], parent || getNullInjector(), source, new Set(['environment']));
22419 this.injector = injector;
22420 injector.resolveInjectorInitializers();
22421 }
22422 destroy() {
22423 this.injector.destroy();
22424 }
22425 onDestroy(callback) {
22426 this.injector.onDestroy(callback);
22427 }
22428}
22429/**
22430 * Create a new environment injector.
22431 *
22432 * @publicApi
22433 * @developerPreview
22434 */
22435function createEnvironmentInjector(providers, parent = null, debugName = null) {
22436 const adapter = new EnvironmentNgModuleRefAdapter(providers, parent, debugName);
22437 return adapter.injector;
22438}
22439
22440/**
22441 * @license
22442 * Copyright Google LLC All Rights Reserved.
22443 *
22444 * Use of this source code is governed by an MIT-style license that can be
22445 * found in the LICENSE file at https://angular.io/license
22446 */
22447/**
22448 * A service used by the framework to create instances of standalone injectors. Those injectors are
22449 * created on demand in case of dynamic component instantiation and contain ambient providers
22450 * collected from the imports graph rooted at a given standalone component.
22451 */
22452class StandaloneService {
22453 constructor(_injector) {
22454 this._injector = _injector;
22455 this.cachedInjectors = new Map();
22456 }
22457 getOrCreateStandaloneInjector(componentDef) {
22458 if (!componentDef.standalone) {
22459 return null;
22460 }
22461 if (!this.cachedInjectors.has(componentDef.id)) {
22462 const providers = internalImportProvidersFrom(false, componentDef.type);
22463 const standaloneInjector = providers.length > 0 ?
22464 createEnvironmentInjector([providers], this._injector, `Standalone[${componentDef.type.name}]`) :
22465 null;
22466 this.cachedInjectors.set(componentDef.id, standaloneInjector);
22467 }
22468 return this.cachedInjectors.get(componentDef.id);
22469 }
22470 ngOnDestroy() {
22471 try {
22472 for (const injector of this.cachedInjectors.values()) {
22473 if (injector !== null) {
22474 injector.destroy();
22475 }
22476 }
22477 }
22478 finally {
22479 this.cachedInjectors.clear();
22480 }
22481 }
22482}
22483/** @nocollapse */
22484StandaloneService.ɵprov = ɵɵdefineInjectable({
22485 token: StandaloneService,
22486 providedIn: 'environment',
22487 factory: () => new StandaloneService(ɵɵinject(EnvironmentInjector)),
22488});
22489/**
22490 * A feature that acts as a setup code for the {@link StandaloneService}.
22491 *
22492 * The most important responsaibility of this feature is to expose the "getStandaloneInjector"
22493 * function (an entry points to a standalone injector creation) on a component definition object. We
22494 * go through the features infrastructure to make sure that the standalone injector creation logic
22495 * is tree-shakable and not included in applications that don't use standalone components.
22496 *
22497 * @codeGenApi
22498 */
22499function ɵɵStandaloneFeature(definition) {
22500 definition.getStandaloneInjector = (parentInjector) => {
22501 return parentInjector.get(StandaloneService).getOrCreateStandaloneInjector(definition);
22502 };
22503}
22504
22505/**
22506 * @license
22507 * Copyright Google LLC All Rights Reserved.
22508 *
22509 * Use of this source code is governed by an MIT-style license that can be
22510 * found in the LICENSE file at https://angular.io/license
22511 */
22512/**
22513 * Adds decorator, constructor, and property metadata to a given type via static metadata fields
22514 * on the type.
22515 *
22516 * These metadata fields can later be read with Angular's `ReflectionCapabilities` API.
22517 *
22518 * Calls to `setClassMetadata` can be guarded by ngDevMode, resulting in the metadata assignments
22519 * being tree-shaken away during production builds.
22520 */
22521function setClassMetadata(type, decorators, ctorParameters, propDecorators) {
22522 return noSideEffects(() => {
22523 const clazz = type;
22524 if (decorators !== null) {
22525 if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) {
22526 clazz.decorators.push(...decorators);
22527 }
22528 else {
22529 clazz.decorators = decorators;
22530 }
22531 }
22532 if (ctorParameters !== null) {
22533 // Rather than merging, clobber the existing parameters. If other projects exist which
22534 // use tsickle-style annotations and reflect over them in the same way, this could
22535 // cause issues, but that is vanishingly unlikely.
22536 clazz.ctorParameters = ctorParameters;
22537 }
22538 if (propDecorators !== null) {
22539 // The property decorator objects are merged as it is possible different fields have
22540 // different decorator types. Decorators on individual fields are not merged, as it's
22541 // also incredibly unlikely that a field will be decorated both with an Angular
22542 // decorator and a non-Angular decorator that's also been downleveled.
22543 if (clazz.hasOwnProperty('propDecorators') && clazz.propDecorators !== undefined) {
22544 clazz.propDecorators = Object.assign(Object.assign({}, clazz.propDecorators), propDecorators);
22545 }
22546 else {
22547 clazz.propDecorators = propDecorators;
22548 }
22549 }
22550 });
22551}
22552
22553/**
22554 * @license
22555 * Copyright Google LLC All Rights Reserved.
22556 *
22557 * Use of this source code is governed by an MIT-style license that can be
22558 * found in the LICENSE file at https://angular.io/license
22559 */
22560/**
22561 * Bindings for pure functions are stored after regular bindings.
22562 *
22563 * |-------decls------|---------vars---------| |----- hostVars (dir1) ------|
22564 * ------------------------------------------------------------------------------------------
22565 * | nodes/refs/pipes | bindings | fn slots | injector | dir1 | host bindings | host slots |
22566 * ------------------------------------------------------------------------------------------
22567 * ^ ^
22568 * TView.bindingStartIndex TView.expandoStartIndex
22569 *
22570 * Pure function instructions are given an offset from the binding root. Adding the offset to the
22571 * binding root gives the first index where the bindings are stored. In component views, the binding
22572 * root is the bindingStartIndex. In host bindings, the binding root is the expandoStartIndex +
22573 * any directive instances + any hostVars in directives evaluated before it.
22574 *
22575 * See VIEW_DATA.md for more information about host binding resolution.
22576 */
22577/**
22578 * If the value hasn't been saved, calls the pure function to store and return the
22579 * value. If it has been saved, returns the saved value.
22580 *
22581 * @param slotOffset the offset from binding root to the reserved slot
22582 * @param pureFn Function that returns a value
22583 * @param thisArg Optional calling context of pureFn
22584 * @returns value
22585 *
22586 * @codeGenApi
22587 */
22588function ɵɵpureFunction0(slotOffset, pureFn, thisArg) {
22589 const bindingIndex = getBindingRoot() + slotOffset;
22590 const lView = getLView();
22591 return lView[bindingIndex] === NO_CHANGE ?
22592 updateBinding(lView, bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) :
22593 getBinding(lView, bindingIndex);
22594}
22595/**
22596 * If the value of the provided exp has changed, calls the pure function to return
22597 * an updated value. Or if the value has not changed, returns cached value.
22598 *
22599 * @param slotOffset the offset from binding root to the reserved slot
22600 * @param pureFn Function that returns an updated value
22601 * @param exp Updated expression value
22602 * @param thisArg Optional calling context of pureFn
22603 * @returns Updated or cached value
22604 *
22605 * @codeGenApi
22606 */
22607function ɵɵpureFunction1(slotOffset, pureFn, exp, thisArg) {
22608 return pureFunction1Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp, thisArg);
22609}
22610/**
22611 * If the value of any provided exp has changed, calls the pure function to return
22612 * an updated value. Or if no values have changed, returns cached value.
22613 *
22614 * @param slotOffset the offset from binding root to the reserved slot
22615 * @param pureFn
22616 * @param exp1
22617 * @param exp2
22618 * @param thisArg Optional calling context of pureFn
22619 * @returns Updated or cached value
22620 *
22621 * @codeGenApi
22622 */
22623function ɵɵpureFunction2(slotOffset, pureFn, exp1, exp2, thisArg) {
22624 return pureFunction2Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, thisArg);
22625}
22626/**
22627 * If the value of any provided exp has changed, calls the pure function to return
22628 * an updated value. Or if no values have changed, returns cached value.
22629 *
22630 * @param slotOffset the offset from binding root to the reserved slot
22631 * @param pureFn
22632 * @param exp1
22633 * @param exp2
22634 * @param exp3
22635 * @param thisArg Optional calling context of pureFn
22636 * @returns Updated or cached value
22637 *
22638 * @codeGenApi
22639 */
22640function ɵɵpureFunction3(slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
22641 return pureFunction3Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, thisArg);
22642}
22643/**
22644 * If the value of any provided exp has changed, calls the pure function to return
22645 * an updated value. Or if no values have changed, returns cached value.
22646 *
22647 * @param slotOffset the offset from binding root to the reserved slot
22648 * @param pureFn
22649 * @param exp1
22650 * @param exp2
22651 * @param exp3
22652 * @param exp4
22653 * @param thisArg Optional calling context of pureFn
22654 * @returns Updated or cached value
22655 *
22656 * @codeGenApi
22657 */
22658function ɵɵpureFunction4(slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
22659 return pureFunction4Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg);
22660}
22661/**
22662 * If the value of any provided exp has changed, calls the pure function to return
22663 * an updated value. Or if no values have changed, returns cached value.
22664 *
22665 * @param slotOffset the offset from binding root to the reserved slot
22666 * @param pureFn
22667 * @param exp1
22668 * @param exp2
22669 * @param exp3
22670 * @param exp4
22671 * @param exp5
22672 * @param thisArg Optional calling context of pureFn
22673 * @returns Updated or cached value
22674 *
22675 * @codeGenApi
22676 */
22677function ɵɵpureFunction5(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, thisArg) {
22678 const bindingIndex = getBindingRoot() + slotOffset;
22679 const lView = getLView();
22680 const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22681 return bindingUpdated(lView, bindingIndex + 4, exp5) || different ?
22682 updateBinding(lView, bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
22683 pureFn(exp1, exp2, exp3, exp4, exp5)) :
22684 getBinding(lView, bindingIndex + 5);
22685}
22686/**
22687 * If the value of any provided exp has changed, calls the pure function to return
22688 * an updated value. Or if no values have changed, returns cached value.
22689 *
22690 * @param slotOffset the offset from binding root to the reserved slot
22691 * @param pureFn
22692 * @param exp1
22693 * @param exp2
22694 * @param exp3
22695 * @param exp4
22696 * @param exp5
22697 * @param exp6
22698 * @param thisArg Optional calling context of pureFn
22699 * @returns Updated or cached value
22700 *
22701 * @codeGenApi
22702 */
22703function ɵɵpureFunction6(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, thisArg) {
22704 const bindingIndex = getBindingRoot() + slotOffset;
22705 const lView = getLView();
22706 const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22707 return bindingUpdated2(lView, bindingIndex + 4, exp5, exp6) || different ?
22708 updateBinding(lView, bindingIndex + 6, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
22709 pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
22710 getBinding(lView, bindingIndex + 6);
22711}
22712/**
22713 * If the value of any provided exp has changed, calls the pure function to return
22714 * an updated value. Or if no values have changed, returns cached value.
22715 *
22716 * @param slotOffset the offset from binding root to the reserved slot
22717 * @param pureFn
22718 * @param exp1
22719 * @param exp2
22720 * @param exp3
22721 * @param exp4
22722 * @param exp5
22723 * @param exp6
22724 * @param exp7
22725 * @param thisArg Optional calling context of pureFn
22726 * @returns Updated or cached value
22727 *
22728 * @codeGenApi
22729 */
22730function ɵɵpureFunction7(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, thisArg) {
22731 const bindingIndex = getBindingRoot() + slotOffset;
22732 const lView = getLView();
22733 let different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22734 return bindingUpdated3(lView, bindingIndex + 4, exp5, exp6, exp7) || different ?
22735 updateBinding(lView, bindingIndex + 7, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
22736 pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
22737 getBinding(lView, bindingIndex + 7);
22738}
22739/**
22740 * If the value of any provided exp has changed, calls the pure function to return
22741 * an updated value. Or if no values have changed, returns cached value.
22742 *
22743 * @param slotOffset the offset from binding root to the reserved slot
22744 * @param pureFn
22745 * @param exp1
22746 * @param exp2
22747 * @param exp3
22748 * @param exp4
22749 * @param exp5
22750 * @param exp6
22751 * @param exp7
22752 * @param exp8
22753 * @param thisArg Optional calling context of pureFn
22754 * @returns Updated or cached value
22755 *
22756 * @codeGenApi
22757 */
22758function ɵɵpureFunction8(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8, thisArg) {
22759 const bindingIndex = getBindingRoot() + slotOffset;
22760 const lView = getLView();
22761 const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22762 return bindingUpdated4(lView, bindingIndex + 4, exp5, exp6, exp7, exp8) || different ?
22763 updateBinding(lView, bindingIndex + 8, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
22764 pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
22765 getBinding(lView, bindingIndex + 8);
22766}
22767/**
22768 * pureFunction instruction that can support any number of bindings.
22769 *
22770 * If the value of any provided exp has changed, calls the pure function to return
22771 * an updated value. Or if no values have changed, returns cached value.
22772 *
22773 * @param slotOffset the offset from binding root to the reserved slot
22774 * @param pureFn A pure function that takes binding values and builds an object or array
22775 * containing those values.
22776 * @param exps An array of binding values
22777 * @param thisArg Optional calling context of pureFn
22778 * @returns Updated or cached value
22779 *
22780 * @codeGenApi
22781 */
22782function ɵɵpureFunctionV(slotOffset, pureFn, exps, thisArg) {
22783 return pureFunctionVInternal(getLView(), getBindingRoot(), slotOffset, pureFn, exps, thisArg);
22784}
22785/**
22786 * Results of a pure function invocation are stored in LView in a dedicated slot that is initialized
22787 * to NO_CHANGE. In rare situations a pure pipe might throw an exception on the very first
22788 * invocation and not produce any valid results. In this case LView would keep holding the NO_CHANGE
22789 * value. The NO_CHANGE is not something that we can use in expressions / bindings thus we convert
22790 * it to `undefined`.
22791 */
22792function getPureFunctionReturnValue(lView, returnValueIndex) {
22793 ngDevMode && assertIndexInRange(lView, returnValueIndex);
22794 const lastReturnValue = lView[returnValueIndex];
22795 return lastReturnValue === NO_CHANGE ? undefined : lastReturnValue;
22796}
22797/**
22798 * If the value of the provided exp has changed, calls the pure function to return
22799 * an updated value. Or if the value has not changed, returns cached value.
22800 *
22801 * @param lView LView in which the function is being executed.
22802 * @param bindingRoot Binding root index.
22803 * @param slotOffset the offset from binding root to the reserved slot
22804 * @param pureFn Function that returns an updated value
22805 * @param exp Updated expression value
22806 * @param thisArg Optional calling context of pureFn
22807 * @returns Updated or cached value
22808 */
22809function pureFunction1Internal(lView, bindingRoot, slotOffset, pureFn, exp, thisArg) {
22810 const bindingIndex = bindingRoot + slotOffset;
22811 return bindingUpdated(lView, bindingIndex, exp) ?
22812 updateBinding(lView, bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
22813 getPureFunctionReturnValue(lView, bindingIndex + 1);
22814}
22815/**
22816 * If the value of any provided exp has changed, calls the pure function to return
22817 * an updated value. Or if no values have changed, returns cached value.
22818 *
22819 * @param lView LView in which the function is being executed.
22820 * @param bindingRoot Binding root index.
22821 * @param slotOffset the offset from binding root to the reserved slot
22822 * @param pureFn
22823 * @param exp1
22824 * @param exp2
22825 * @param thisArg Optional calling context of pureFn
22826 * @returns Updated or cached value
22827 */
22828function pureFunction2Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, thisArg) {
22829 const bindingIndex = bindingRoot + slotOffset;
22830 return bindingUpdated2(lView, bindingIndex, exp1, exp2) ?
22831 updateBinding(lView, bindingIndex + 2, thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) :
22832 getPureFunctionReturnValue(lView, bindingIndex + 2);
22833}
22834/**
22835 * If the value of any provided exp has changed, calls the pure function to return
22836 * an updated value. Or if no values have changed, returns cached value.
22837 *
22838 * @param lView LView in which the function is being executed.
22839 * @param bindingRoot Binding root index.
22840 * @param slotOffset the offset from binding root to the reserved slot
22841 * @param pureFn
22842 * @param exp1
22843 * @param exp2
22844 * @param exp3
22845 * @param thisArg Optional calling context of pureFn
22846 * @returns Updated or cached value
22847 */
22848function pureFunction3Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
22849 const bindingIndex = bindingRoot + slotOffset;
22850 return bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) ?
22851 updateBinding(lView, bindingIndex + 3, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) :
22852 getPureFunctionReturnValue(lView, bindingIndex + 3);
22853}
22854/**
22855 * If the value of any provided exp has changed, calls the pure function to return
22856 * an updated value. Or if no values have changed, returns cached value.
22857 *
22858 * @param lView LView in which the function is being executed.
22859 * @param bindingRoot Binding root index.
22860 * @param slotOffset the offset from binding root to the reserved slot
22861 * @param pureFn
22862 * @param exp1
22863 * @param exp2
22864 * @param exp3
22865 * @param exp4
22866 * @param thisArg Optional calling context of pureFn
22867 * @returns Updated or cached value
22868 *
22869 */
22870function pureFunction4Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
22871 const bindingIndex = bindingRoot + slotOffset;
22872 return bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) ?
22873 updateBinding(lView, bindingIndex + 4, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) :
22874 getPureFunctionReturnValue(lView, bindingIndex + 4);
22875}
22876/**
22877 * pureFunction instruction that can support any number of bindings.
22878 *
22879 * If the value of any provided exp has changed, calls the pure function to return
22880 * an updated value. Or if no values have changed, returns cached value.
22881 *
22882 * @param lView LView in which the function is being executed.
22883 * @param bindingRoot Binding root index.
22884 * @param slotOffset the offset from binding root to the reserved slot
22885 * @param pureFn A pure function that takes binding values and builds an object or array
22886 * containing those values.
22887 * @param exps An array of binding values
22888 * @param thisArg Optional calling context of pureFn
22889 * @returns Updated or cached value
22890 */
22891function pureFunctionVInternal(lView, bindingRoot, slotOffset, pureFn, exps, thisArg) {
22892 let bindingIndex = bindingRoot + slotOffset;
22893 let different = false;
22894 for (let i = 0; i < exps.length; i++) {
22895 bindingUpdated(lView, bindingIndex++, exps[i]) && (different = true);
22896 }
22897 return different ? updateBinding(lView, bindingIndex, pureFn.apply(thisArg, exps)) :
22898 getPureFunctionReturnValue(lView, bindingIndex);
22899}
22900
22901/**
22902 * @license
22903 * Copyright Google LLC All Rights Reserved.
22904 *
22905 * Use of this source code is governed by an MIT-style license that can be
22906 * found in the LICENSE file at https://angular.io/license
22907 */
22908/**
22909 * Create a pipe.
22910 *
22911 * @param index Pipe index where the pipe will be stored.
22912 * @param pipeName The name of the pipe
22913 * @returns T the instance of the pipe.
22914 *
22915 * @codeGenApi
22916 */
22917function ɵɵpipe(index, pipeName) {
22918 const tView = getTView();
22919 let pipeDef;
22920 const adjustedIndex = index + HEADER_OFFSET;
22921 if (tView.firstCreatePass) {
22922 // The `getPipeDef` throws if a pipe with a given name is not found
22923 // (so we use non-null assertion below).
22924 pipeDef = getPipeDef(pipeName, tView.pipeRegistry);
22925 tView.data[adjustedIndex] = pipeDef;
22926 if (pipeDef.onDestroy) {
22927 (tView.destroyHooks || (tView.destroyHooks = [])).push(adjustedIndex, pipeDef.onDestroy);
22928 }
22929 }
22930 else {
22931 pipeDef = tView.data[adjustedIndex];
22932 }
22933 const pipeFactory = pipeDef.factory || (pipeDef.factory = getFactoryDef(pipeDef.type, true));
22934 const previousInjectImplementation = setInjectImplementation(ɵɵdirectiveInject);
22935 try {
22936 // DI for pipes is supposed to behave like directives when placed on a component
22937 // host node, which means that we have to disable access to `viewProviders`.
22938 const previousIncludeViewProviders = setIncludeViewProviders(false);
22939 const pipeInstance = pipeFactory();
22940 setIncludeViewProviders(previousIncludeViewProviders);
22941 store(tView, getLView(), adjustedIndex, pipeInstance);
22942 return pipeInstance;
22943 }
22944 finally {
22945 // we have to restore the injector implementation in finally, just in case the creation of the
22946 // pipe throws an error.
22947 setInjectImplementation(previousInjectImplementation);
22948 }
22949}
22950/**
22951 * Searches the pipe registry for a pipe with the given name. If one is found,
22952 * returns the pipe. Otherwise, an error is thrown because the pipe cannot be resolved.
22953 *
22954 * @param name Name of pipe to resolve
22955 * @param registry Full list of available pipes
22956 * @returns Matching PipeDef
22957 */
22958function getPipeDef(name, registry) {
22959 if (registry) {
22960 for (let i = registry.length - 1; i >= 0; i--) {
22961 const pipeDef = registry[i];
22962 if (name === pipeDef.name) {
22963 return pipeDef;
22964 }
22965 }
22966 }
22967 if (ngDevMode) {
22968 throw new RuntimeError(-302 /* RuntimeErrorCode.PIPE_NOT_FOUND */, getPipeNotFoundErrorMessage(name));
22969 }
22970}
22971/**
22972 * Generates a helpful error message for the user when a pipe is not found.
22973 *
22974 * @param name Name of the missing pipe
22975 * @returns The error message
22976 */
22977function getPipeNotFoundErrorMessage(name) {
22978 const lView = getLView();
22979 const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
22980 const context = declarationLView[CONTEXT];
22981 const hostIsStandalone = isHostComponentStandalone(lView);
22982 const componentInfoMessage = context ? ` in the '${context.constructor.name}' component` : '';
22983 const verifyMessage = `Verify that it is ${hostIsStandalone ? 'included in the \'@Component.imports\' of this component' :
22984 'declared or imported in this module'}`;
22985 const errorMessage = `The pipe '${name}' could not be found${componentInfoMessage}. ${verifyMessage}`;
22986 return errorMessage;
22987}
22988/**
22989 * Invokes a pipe with 1 arguments.
22990 *
22991 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
22992 * the pipe only when an input to the pipe changes.
22993 *
22994 * @param index Pipe index where the pipe was stored on creation.
22995 * @param slotOffset the offset in the reserved slot space
22996 * @param v1 1st argument to {@link PipeTransform#transform}.
22997 *
22998 * @codeGenApi
22999 */
23000function ɵɵpipeBind1(index, slotOffset, v1) {
23001 const adjustedIndex = index + HEADER_OFFSET;
23002 const lView = getLView();
23003 const pipeInstance = load(lView, adjustedIndex);
23004 return isPure(lView, adjustedIndex) ?
23005 pureFunction1Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) :
23006 pipeInstance.transform(v1);
23007}
23008/**
23009 * Invokes a pipe with 2 arguments.
23010 *
23011 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
23012 * the pipe only when an input to the pipe changes.
23013 *
23014 * @param index Pipe index where the pipe was stored on creation.
23015 * @param slotOffset the offset in the reserved slot space
23016 * @param v1 1st argument to {@link PipeTransform#transform}.
23017 * @param v2 2nd argument to {@link PipeTransform#transform}.
23018 *
23019 * @codeGenApi
23020 */
23021function ɵɵpipeBind2(index, slotOffset, v1, v2) {
23022 const adjustedIndex = index + HEADER_OFFSET;
23023 const lView = getLView();
23024 const pipeInstance = load(lView, adjustedIndex);
23025 return isPure(lView, adjustedIndex) ?
23026 pureFunction2Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, pipeInstance) :
23027 pipeInstance.transform(v1, v2);
23028}
23029/**
23030 * Invokes a pipe with 3 arguments.
23031 *
23032 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
23033 * the pipe only when an input to the pipe changes.
23034 *
23035 * @param index Pipe index where the pipe was stored on creation.
23036 * @param slotOffset the offset in the reserved slot space
23037 * @param v1 1st argument to {@link PipeTransform#transform}.
23038 * @param v2 2nd argument to {@link PipeTransform#transform}.
23039 * @param v3 4rd argument to {@link PipeTransform#transform}.
23040 *
23041 * @codeGenApi
23042 */
23043function ɵɵpipeBind3(index, slotOffset, v1, v2, v3) {
23044 const adjustedIndex = index + HEADER_OFFSET;
23045 const lView = getLView();
23046 const pipeInstance = load(lView, adjustedIndex);
23047 return isPure(lView, adjustedIndex) ?
23048 pureFunction3Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, pipeInstance) :
23049 pipeInstance.transform(v1, v2, v3);
23050}
23051/**
23052 * Invokes a pipe with 4 arguments.
23053 *
23054 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
23055 * the pipe only when an input to the pipe changes.
23056 *
23057 * @param index Pipe index where the pipe was stored on creation.
23058 * @param slotOffset the offset in the reserved slot space
23059 * @param v1 1st argument to {@link PipeTransform#transform}.
23060 * @param v2 2nd argument to {@link PipeTransform#transform}.
23061 * @param v3 3rd argument to {@link PipeTransform#transform}.
23062 * @param v4 4th argument to {@link PipeTransform#transform}.
23063 *
23064 * @codeGenApi
23065 */
23066function ɵɵpipeBind4(index, slotOffset, v1, v2, v3, v4) {
23067 const adjustedIndex = index + HEADER_OFFSET;
23068 const lView = getLView();
23069 const pipeInstance = load(lView, adjustedIndex);
23070 return isPure(lView, adjustedIndex) ? pureFunction4Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, v4, pipeInstance) :
23071 pipeInstance.transform(v1, v2, v3, v4);
23072}
23073/**
23074 * Invokes a pipe with variable number of arguments.
23075 *
23076 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
23077 * the pipe only when an input to the pipe changes.
23078 *
23079 * @param index Pipe index where the pipe was stored on creation.
23080 * @param slotOffset the offset in the reserved slot space
23081 * @param values Array of arguments to pass to {@link PipeTransform#transform} method.
23082 *
23083 * @codeGenApi
23084 */
23085function ɵɵpipeBindV(index, slotOffset, values) {
23086 const adjustedIndex = index + HEADER_OFFSET;
23087 const lView = getLView();
23088 const pipeInstance = load(lView, adjustedIndex);
23089 return isPure(lView, adjustedIndex) ?
23090 pureFunctionVInternal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, values, pipeInstance) :
23091 pipeInstance.transform.apply(pipeInstance, values);
23092}
23093function isPure(lView, index) {
23094 return lView[TVIEW].data[index].pure;
23095}
23096
23097/**
23098 * @license
23099 * Copyright Google LLC All Rights Reserved.
23100 *
23101 * Use of this source code is governed by an MIT-style license that can be
23102 * found in the LICENSE file at https://angular.io/license
23103 */
23104class EventEmitter_ extends Subject {
23105 constructor(isAsync = false) {
23106 super();
23107 this.__isAsync = isAsync;
23108 }
23109 emit(value) {
23110 super.next(value);
23111 }
23112 subscribe(observerOrNext, error, complete) {
23113 var _a, _b, _c;
23114 let nextFn = observerOrNext;
23115 let errorFn = error || (() => null);
23116 let completeFn = complete;
23117 if (observerOrNext && typeof observerOrNext === 'object') {
23118 const observer = observerOrNext;
23119 nextFn = (_a = observer.next) === null || _a === void 0 ? void 0 : _a.bind(observer);
23120 errorFn = (_b = observer.error) === null || _b === void 0 ? void 0 : _b.bind(observer);
23121 completeFn = (_c = observer.complete) === null || _c === void 0 ? void 0 : _c.bind(observer);
23122 }
23123 if (this.__isAsync) {
23124 errorFn = _wrapInTimeout(errorFn);
23125 if (nextFn) {
23126 nextFn = _wrapInTimeout(nextFn);
23127 }
23128 if (completeFn) {
23129 completeFn = _wrapInTimeout(completeFn);
23130 }
23131 }
23132 const sink = super.subscribe({ next: nextFn, error: errorFn, complete: completeFn });
23133 if (observerOrNext instanceof Subscription) {
23134 observerOrNext.add(sink);
23135 }
23136 return sink;
23137 }
23138}
23139function _wrapInTimeout(fn) {
23140 return (value) => {
23141 setTimeout(fn, undefined, value);
23142 };
23143}
23144/**
23145 * @publicApi
23146 */
23147const EventEmitter = EventEmitter_;
23148
23149/**
23150 * @license
23151 * Copyright Google LLC All Rights Reserved.
23152 *
23153 * Use of this source code is governed by an MIT-style license that can be
23154 * found in the LICENSE file at https://angular.io/license
23155 */
23156function symbolIterator() {
23157 return this._results[getSymbolIterator()]();
23158}
23159/**
23160 * An unmodifiable list of items that Angular keeps up to date when the state
23161 * of the application changes.
23162 *
23163 * The type of object that {@link ViewChildren}, {@link ContentChildren}, and {@link QueryList}
23164 * provide.
23165 *
23166 * Implements an iterable interface, therefore it can be used in both ES6
23167 * javascript `for (var i of items)` loops as well as in Angular templates with
23168 * `*ngFor="let i of myList"`.
23169 *
23170 * Changes can be observed by subscribing to the changes `Observable`.
23171 *
23172 * NOTE: In the future this class will implement an `Observable` interface.
23173 *
23174 * @usageNotes
23175 * ### Example
23176 * ```typescript
23177 * @Component({...})
23178 * class Container {
23179 * @ViewChildren(Item) items:QueryList<Item>;
23180 * }
23181 * ```
23182 *
23183 * @publicApi
23184 */
23185class QueryList {
23186 /**
23187 * @param emitDistinctChangesOnly Whether `QueryList.changes` should fire only when actual change
23188 * has occurred. Or if it should fire when query is recomputed. (recomputing could resolve in
23189 * the same result)
23190 */
23191 constructor(_emitDistinctChangesOnly = false) {
23192 this._emitDistinctChangesOnly = _emitDistinctChangesOnly;
23193 this.dirty = true;
23194 this._results = [];
23195 this._changesDetected = false;
23196 this._changes = null;
23197 this.length = 0;
23198 this.first = undefined;
23199 this.last = undefined;
23200 // This function should be declared on the prototype, but doing so there will cause the class
23201 // declaration to have side-effects and become not tree-shakable. For this reason we do it in
23202 // the constructor.
23203 // [getSymbolIterator()](): Iterator<T> { ... }
23204 const symbol = getSymbolIterator();
23205 const proto = QueryList.prototype;
23206 if (!proto[symbol])
23207 proto[symbol] = symbolIterator;
23208 }
23209 /**
23210 * Returns `Observable` of `QueryList` notifying the subscriber of changes.
23211 */
23212 get changes() {
23213 return this._changes || (this._changes = new EventEmitter());
23214 }
23215 /**
23216 * Returns the QueryList entry at `index`.
23217 */
23218 get(index) {
23219 return this._results[index];
23220 }
23221 /**
23222 * See
23223 * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
23224 */
23225 map(fn) {
23226 return this._results.map(fn);
23227 }
23228 /**
23229 * See
23230 * [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
23231 */
23232 filter(fn) {
23233 return this._results.filter(fn);
23234 }
23235 /**
23236 * See
23237 * [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
23238 */
23239 find(fn) {
23240 return this._results.find(fn);
23241 }
23242 /**
23243 * See
23244 * [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
23245 */
23246 reduce(fn, init) {
23247 return this._results.reduce(fn, init);
23248 }
23249 /**
23250 * See
23251 * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
23252 */
23253 forEach(fn) {
23254 this._results.forEach(fn);
23255 }
23256 /**
23257 * See
23258 * [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
23259 */
23260 some(fn) {
23261 return this._results.some(fn);
23262 }
23263 /**
23264 * Returns a copy of the internal results list as an Array.
23265 */
23266 toArray() {
23267 return this._results.slice();
23268 }
23269 toString() {
23270 return this._results.toString();
23271 }
23272 /**
23273 * Updates the stored data of the query list, and resets the `dirty` flag to `false`, so that
23274 * on change detection, it will not notify of changes to the queries, unless a new change
23275 * occurs.
23276 *
23277 * @param resultsTree The query results to store
23278 * @param identityAccessor Optional function for extracting stable object identity from a value
23279 * in the array. This function is executed for each element of the query result list while
23280 * comparing current query list with the new one (provided as a first argument of the `reset`
23281 * function) to detect if the lists are different. If the function is not provided, elements
23282 * are compared as is (without any pre-processing).
23283 */
23284 reset(resultsTree, identityAccessor) {
23285 // Cast to `QueryListInternal` so that we can mutate fields which are readonly for the usage of
23286 // QueryList (but not for QueryList itself.)
23287 const self = this;
23288 self.dirty = false;
23289 const newResultFlat = flatten(resultsTree);
23290 if (this._changesDetected = !arrayEquals(self._results, newResultFlat, identityAccessor)) {
23291 self._results = newResultFlat;
23292 self.length = newResultFlat.length;
23293 self.last = newResultFlat[this.length - 1];
23294 self.first = newResultFlat[0];
23295 }
23296 }
23297 /**
23298 * Triggers a change event by emitting on the `changes` {@link EventEmitter}.
23299 */
23300 notifyOnChanges() {
23301 if (this._changes && (this._changesDetected || !this._emitDistinctChangesOnly))
23302 this._changes.emit(this);
23303 }
23304 /** internal */
23305 setDirty() {
23306 this.dirty = true;
23307 }
23308 /** internal */
23309 destroy() {
23310 this.changes.complete();
23311 this.changes.unsubscribe();
23312 }
23313}
23314Symbol.iterator;
23315
23316/**
23317 * @license
23318 * Copyright Google LLC All Rights Reserved.
23319 *
23320 * Use of this source code is governed by an MIT-style license that can be
23321 * found in the LICENSE file at https://angular.io/license
23322 */
23323/**
23324 * Represents an embedded template that can be used to instantiate embedded views.
23325 * To instantiate embedded views based on a template, use the `ViewContainerRef`
23326 * method `createEmbeddedView()`.
23327 *
23328 * Access a `TemplateRef` instance by placing a directive on an `<ng-template>`
23329 * element (or directive prefixed with `*`). The `TemplateRef` for the embedded view
23330 * is injected into the constructor of the directive,
23331 * using the `TemplateRef` token.
23332 *
23333 * You can also use a `Query` to find a `TemplateRef` associated with
23334 * a component or a directive.
23335 *
23336 * @see `ViewContainerRef`
23337 * @see [Navigate the Component Tree with DI](guide/dependency-injection-navtree)
23338 *
23339 * @publicApi
23340 */
23341class TemplateRef {
23342}
23343/**
23344 * @internal
23345 * @nocollapse
23346 */
23347TemplateRef.__NG_ELEMENT_ID__ = injectTemplateRef;
23348const ViewEngineTemplateRef = TemplateRef;
23349// TODO(alxhub): combine interface and implementation. Currently this is challenging since something
23350// in g3 depends on them being separate.
23351const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
23352 constructor(_declarationLView, _declarationTContainer, elementRef) {
23353 super();
23354 this._declarationLView = _declarationLView;
23355 this._declarationTContainer = _declarationTContainer;
23356 this.elementRef = elementRef;
23357 }
23358 createEmbeddedView(context, injector) {
23359 const embeddedTView = this._declarationTContainer.tViews;
23360 const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* LViewFlags.CheckAlways */, null, embeddedTView.declTNode, null, null, null, null, injector || null);
23361 const declarationLContainer = this._declarationLView[this._declarationTContainer.index];
23362 ngDevMode && assertLContainer(declarationLContainer);
23363 embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
23364 const declarationViewLQueries = this._declarationLView[QUERIES];
23365 if (declarationViewLQueries !== null) {
23366 embeddedLView[QUERIES] = declarationViewLQueries.createEmbeddedView(embeddedTView);
23367 }
23368 renderView(embeddedTView, embeddedLView, context);
23369 return new ViewRef$1(embeddedLView);
23370 }
23371};
23372/**
23373 * Creates a TemplateRef given a node.
23374 *
23375 * @returns The TemplateRef instance to use
23376 */
23377function injectTemplateRef() {
23378 return createTemplateRef(getCurrentTNode(), getLView());
23379}
23380/**
23381 * Creates a TemplateRef and stores it on the injector.
23382 *
23383 * @param hostTNode The node on which a TemplateRef is requested
23384 * @param hostLView The `LView` to which the node belongs
23385 * @returns The TemplateRef instance or null if we can't create a TemplateRef on a given node type
23386 */
23387function createTemplateRef(hostTNode, hostLView) {
23388 if (hostTNode.type & 4 /* TNodeType.Container */) {
23389 ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
23390 return new R3TemplateRef(hostLView, hostTNode, createElementRef(hostTNode, hostLView));
23391 }
23392 return null;
23393}
23394
23395/**
23396 * @license
23397 * Copyright Google LLC All Rights Reserved.
23398 *
23399 * Use of this source code is governed by an MIT-style license that can be
23400 * found in the LICENSE file at https://angular.io/license
23401 */
23402/**
23403 * Represents a container where one or more views can be attached to a component.
23404 *
23405 * Can contain *host views* (created by instantiating a
23406 * component with the `createComponent()` method), and *embedded views*
23407 * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
23408 *
23409 * A view container instance can contain other view containers,
23410 * creating a [view hierarchy](guide/glossary#view-tree).
23411 *
23412 * @see `ComponentRef`
23413 * @see `EmbeddedViewRef`
23414 *
23415 * @publicApi
23416 */
23417class ViewContainerRef {
23418}
23419/**
23420 * @internal
23421 * @nocollapse
23422 */
23423ViewContainerRef.__NG_ELEMENT_ID__ = injectViewContainerRef;
23424/**
23425 * Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
23426 * already exists, retrieves the existing ViewContainerRef.
23427 *
23428 * @returns The ViewContainerRef instance to use
23429 */
23430function injectViewContainerRef() {
23431 const previousTNode = getCurrentTNode();
23432 return createContainerRef(previousTNode, getLView());
23433}
23434const VE_ViewContainerRef = ViewContainerRef;
23435// TODO(alxhub): cleaning up this indirection triggers a subtle bug in Closure in g3. Once the fix
23436// for that lands, this can be cleaned up.
23437const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
23438 constructor(_lContainer, _hostTNode, _hostLView) {
23439 super();
23440 this._lContainer = _lContainer;
23441 this._hostTNode = _hostTNode;
23442 this._hostLView = _hostLView;
23443 }
23444 get element() {
23445 return createElementRef(this._hostTNode, this._hostLView);
23446 }
23447 get injector() {
23448 return new NodeInjector(this._hostTNode, this._hostLView);
23449 }
23450 /** @deprecated No replacement */
23451 get parentInjector() {
23452 const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostLView);
23453 if (hasParentInjector(parentLocation)) {
23454 const parentView = getParentInjectorView(parentLocation, this._hostLView);
23455 const injectorIndex = getParentInjectorIndex(parentLocation);
23456 ngDevMode && assertNodeInjector(parentView, injectorIndex);
23457 const parentTNode = parentView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
23458 return new NodeInjector(parentTNode, parentView);
23459 }
23460 else {
23461 return new NodeInjector(null, this._hostLView);
23462 }
23463 }
23464 clear() {
23465 while (this.length > 0) {
23466 this.remove(this.length - 1);
23467 }
23468 }
23469 get(index) {
23470 const viewRefs = getViewRefs(this._lContainer);
23471 return viewRefs !== null && viewRefs[index] || null;
23472 }
23473 get length() {
23474 return this._lContainer.length - CONTAINER_HEADER_OFFSET;
23475 }
23476 createEmbeddedView(templateRef, context, indexOrOptions) {
23477 let index;
23478 let injector;
23479 if (typeof indexOrOptions === 'number') {
23480 index = indexOrOptions;
23481 }
23482 else if (indexOrOptions != null) {
23483 index = indexOrOptions.index;
23484 injector = indexOrOptions.injector;
23485 }
23486 const viewRef = templateRef.createEmbeddedView(context || {}, injector);
23487 this.insert(viewRef, index);
23488 return viewRef;
23489 }
23490 createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
23491 const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
23492 let index;
23493 // This function supports 2 signatures and we need to handle options correctly for both:
23494 // 1. When first argument is a Component type. This signature also requires extra
23495 // options to be provided as as object (more ergonomic option).
23496 // 2. First argument is a Component factory. In this case extra options are represented as
23497 // positional arguments. This signature is less ergonomic and will be deprecated.
23498 if (isComponentFactory) {
23499 if (ngDevMode) {
23500 assertEqual(typeof indexOrOptions !== 'object', true, 'It looks like Component factory was provided as the first argument ' +
23501 'and an options object as the second argument. This combination of arguments ' +
23502 'is incompatible. You can either change the first argument to provide Component ' +
23503 'type or change the second argument to be a number (representing an index at ' +
23504 'which to insert the new component\'s host view into this container)');
23505 }
23506 index = indexOrOptions;
23507 }
23508 else {
23509 if (ngDevMode) {
23510 assertDefined(getComponentDef(componentFactoryOrType), `Provided Component class doesn't contain Component definition. ` +
23511 `Please check whether provided class has @Component decorator.`);
23512 assertEqual(typeof indexOrOptions !== 'number', true, 'It looks like Component type was provided as the first argument ' +
23513 'and a number (representing an index at which to insert the new component\'s ' +
23514 'host view into this container as the second argument. This combination of arguments ' +
23515 'is incompatible. Please use an object as the second argument instead.');
23516 }
23517 const options = (indexOrOptions || {});
23518 if (ngDevMode && options.environmentInjector && options.ngModuleRef) {
23519 throwError(`Cannot pass both environmentInjector and ngModuleRef options to createComponent().`);
23520 }
23521 index = options.index;
23522 injector = options.injector;
23523 projectableNodes = options.projectableNodes;
23524 environmentInjector = options.environmentInjector || options.ngModuleRef;
23525 }
23526 const componentFactory = isComponentFactory ?
23527 componentFactoryOrType :
23528 new ComponentFactory(getComponentDef(componentFactoryOrType));
23529 const contextInjector = injector || this.parentInjector;
23530 // If an `NgModuleRef` is not provided explicitly, try retrieving it from the DI tree.
23531 if (!environmentInjector && componentFactory.ngModule == null) {
23532 // For the `ComponentFactory` case, entering this logic is very unlikely, since we expect that
23533 // an instance of a `ComponentFactory`, resolved via `ComponentFactoryResolver` would have an
23534 // `ngModule` field. This is possible in some test scenarios and potentially in some JIT-based
23535 // use-cases. For the `ComponentFactory` case we preserve backwards-compatibility and try
23536 // using a provided injector first, then fall back to the parent injector of this
23537 // `ViewContainerRef` instance.
23538 //
23539 // For the factory-less case, it's critical to establish a connection with the module
23540 // injector tree (by retrieving an instance of an `NgModuleRef` and accessing its injector),
23541 // so that a component can use DI tokens provided in MgModules. For this reason, we can not
23542 // rely on the provided injector, since it might be detached from the DI tree (for example, if
23543 // it was created via `Injector.create` without specifying a parent injector, or if an
23544 // injector is retrieved from an `NgModuleRef` created via `createNgModuleRef` using an
23545 // NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent
23546 // injector, which is normally connected to the DI tree, which includes module injector
23547 // subtree.
23548 const _injector = isComponentFactory ? contextInjector : this.parentInjector;
23549 // DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) ||
23550 // undefined` expression which seems to cause internal google apps to fail. This is documented
23551 // in the following internal bug issue: go/b/142967802
23552 const result = _injector.get(EnvironmentInjector, null);
23553 if (result) {
23554 environmentInjector = result;
23555 }
23556 }
23557 const componentRef = componentFactory.create(contextInjector, projectableNodes, undefined, environmentInjector);
23558 this.insert(componentRef.hostView, index);
23559 return componentRef;
23560 }
23561 insert(viewRef, index) {
23562 const lView = viewRef._lView;
23563 const tView = lView[TVIEW];
23564 if (ngDevMode && viewRef.destroyed) {
23565 throw new Error('Cannot insert a destroyed View in a ViewContainer!');
23566 }
23567 if (viewAttachedToContainer(lView)) {
23568 // If view is already attached, detach it first so we clean up references appropriately.
23569 const prevIdx = this.indexOf(viewRef);
23570 // A view might be attached either to this or a different container. The `prevIdx` for
23571 // those cases will be:
23572 // equal to -1 for views attached to this ViewContainerRef
23573 // >= 0 for views attached to a different ViewContainerRef
23574 if (prevIdx !== -1) {
23575 this.detach(prevIdx);
23576 }
23577 else {
23578 const prevLContainer = lView[PARENT];
23579 ngDevMode &&
23580 assertEqual(isLContainer(prevLContainer), true, 'An attached view should have its PARENT point to a container.');
23581 // We need to re-create a R3ViewContainerRef instance since those are not stored on
23582 // LView (nor anywhere else).
23583 const prevVCRef = new R3ViewContainerRef(prevLContainer, prevLContainer[T_HOST], prevLContainer[PARENT]);
23584 prevVCRef.detach(prevVCRef.indexOf(viewRef));
23585 }
23586 }
23587 // Logical operation of adding `LView` to `LContainer`
23588 const adjustedIdx = this._adjustIndex(index);
23589 const lContainer = this._lContainer;
23590 insertView(tView, lView, lContainer, adjustedIdx);
23591 // Physical operation of adding the DOM nodes.
23592 const beforeNode = getBeforeNodeForView(adjustedIdx, lContainer);
23593 const renderer = lView[RENDERER];
23594 const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
23595 if (parentRNode !== null) {
23596 addViewToContainer(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
23597 }
23598 viewRef.attachToViewContainerRef();
23599 addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
23600 return viewRef;
23601 }
23602 move(viewRef, newIndex) {
23603 if (ngDevMode && viewRef.destroyed) {
23604 throw new Error('Cannot move a destroyed View in a ViewContainer!');
23605 }
23606 return this.insert(viewRef, newIndex);
23607 }
23608 indexOf(viewRef) {
23609 const viewRefsArr = getViewRefs(this._lContainer);
23610 return viewRefsArr !== null ? viewRefsArr.indexOf(viewRef) : -1;
23611 }
23612 remove(index) {
23613 const adjustedIdx = this._adjustIndex(index, -1);
23614 const detachedView = detachView(this._lContainer, adjustedIdx);
23615 if (detachedView) {
23616 // Before destroying the view, remove it from the container's array of `ViewRef`s.
23617 // This ensures the view container length is updated before calling
23618 // `destroyLView`, which could recursively call view container methods that
23619 // rely on an accurate container length.
23620 // (e.g. a method on this view container being called by a child directive's OnDestroy
23621 // lifecycle hook)
23622 removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx);
23623 destroyLView(detachedView[TVIEW], detachedView);
23624 }
23625 }
23626 detach(index) {
23627 const adjustedIdx = this._adjustIndex(index, -1);
23628 const view = detachView(this._lContainer, adjustedIdx);
23629 const wasDetached = view && removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx) != null;
23630 return wasDetached ? new ViewRef$1(view) : null;
23631 }
23632 _adjustIndex(index, shift = 0) {
23633 if (index == null) {
23634 return this.length + shift;
23635 }
23636 if (ngDevMode) {
23637 assertGreaterThan(index, -1, `ViewRef index must be positive, got ${index}`);
23638 // +1 because it's legal to insert at the end.
23639 assertLessThan(index, this.length + 1 + shift, 'index');
23640 }
23641 return index;
23642 }
23643};
23644function getViewRefs(lContainer) {
23645 return lContainer[VIEW_REFS];
23646}
23647function getOrCreateViewRefs(lContainer) {
23648 return (lContainer[VIEW_REFS] || (lContainer[VIEW_REFS] = []));
23649}
23650/**
23651 * Creates a ViewContainerRef and stores it on the injector.
23652 *
23653 * @param ViewContainerRefToken The ViewContainerRef type
23654 * @param ElementRefToken The ElementRef type
23655 * @param hostTNode The node that is requesting a ViewContainerRef
23656 * @param hostLView The view to which the node belongs
23657 * @returns The ViewContainerRef instance to use
23658 */
23659function createContainerRef(hostTNode, hostLView) {
23660 ngDevMode && assertTNodeType(hostTNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */);
23661 let lContainer;
23662 const slotValue = hostLView[hostTNode.index];
23663 if (isLContainer(slotValue)) {
23664 // If the host is a container, we don't need to create a new LContainer
23665 lContainer = slotValue;
23666 }
23667 else {
23668 let commentNode;
23669 // If the host is an element container, the native host element is guaranteed to be a
23670 // comment and we can reuse that comment as anchor element for the new LContainer.
23671 // The comment node in question is already part of the DOM structure so we don't need to append
23672 // it again.
23673 if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
23674 commentNode = unwrapRNode(slotValue);
23675 }
23676 else {
23677 // If the host is a regular element, we have to insert a comment node manually which will
23678 // be used as an anchor when inserting elements. In this specific case we use low-level DOM
23679 // manipulation to insert it.
23680 const renderer = hostLView[RENDERER];
23681 ngDevMode && ngDevMode.rendererCreateComment++;
23682 commentNode = renderer.createComment(ngDevMode ? 'container' : '');
23683 const hostNative = getNativeByTNode(hostTNode, hostLView);
23684 const parentOfHostNative = nativeParentNode(renderer, hostNative);
23685 nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
23686 }
23687 hostLView[hostTNode.index] = lContainer =
23688 createLContainer(slotValue, hostLView, commentNode, hostTNode);
23689 addToViewTree(hostLView, lContainer);
23690 }
23691 return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
23692}
23693
23694/**
23695 * @license
23696 * Copyright Google LLC All Rights Reserved.
23697 *
23698 * Use of this source code is governed by an MIT-style license that can be
23699 * found in the LICENSE file at https://angular.io/license
23700 */
23701// Note: This hack is necessary so we don't erroneously get a circular dependency
23702// failure based on types.
23703const unusedValueExportToPlacateAjd$1 = 1;
23704
23705/**
23706 * @license
23707 * Copyright Google LLC All Rights Reserved.
23708 *
23709 * Use of this source code is governed by an MIT-style license that can be
23710 * found in the LICENSE file at https://angular.io/license
23711 */
23712// Note: This hack is necessary so we don't erroneously get a circular dependency
23713// failure based on types.
23714const unusedValueExportToPlacateAjd = 1;
23715
23716/**
23717 * @license
23718 * Copyright Google LLC All Rights Reserved.
23719 *
23720 * Use of this source code is governed by an MIT-style license that can be
23721 * found in the LICENSE file at https://angular.io/license
23722 */
23723const unusedValueToPlacateAjd = unusedValueExportToPlacateAjd$1 + unusedValueExportToPlacateAjd$5 + unusedValueExportToPlacateAjd$4 + unusedValueExportToPlacateAjd;
23724class LQuery_ {
23725 constructor(queryList) {
23726 this.queryList = queryList;
23727 this.matches = null;
23728 }
23729 clone() {
23730 return new LQuery_(this.queryList);
23731 }
23732 setDirty() {
23733 this.queryList.setDirty();
23734 }
23735}
23736class LQueries_ {
23737 constructor(queries = []) {
23738 this.queries = queries;
23739 }
23740 createEmbeddedView(tView) {
23741 const tQueries = tView.queries;
23742 if (tQueries !== null) {
23743 const noOfInheritedQueries = tView.contentQueries !== null ? tView.contentQueries[0] : tQueries.length;
23744 const viewLQueries = [];
23745 // An embedded view has queries propagated from a declaration view at the beginning of the
23746 // TQueries collection and up until a first content query declared in the embedded view. Only
23747 // propagated LQueries are created at this point (LQuery corresponding to declared content
23748 // queries will be instantiated from the content query instructions for each directive).
23749 for (let i = 0; i < noOfInheritedQueries; i++) {
23750 const tQuery = tQueries.getByIndex(i);
23751 const parentLQuery = this.queries[tQuery.indexInDeclarationView];
23752 viewLQueries.push(parentLQuery.clone());
23753 }
23754 return new LQueries_(viewLQueries);
23755 }
23756 return null;
23757 }
23758 insertView(tView) {
23759 this.dirtyQueriesWithMatches(tView);
23760 }
23761 detachView(tView) {
23762 this.dirtyQueriesWithMatches(tView);
23763 }
23764 dirtyQueriesWithMatches(tView) {
23765 for (let i = 0; i < this.queries.length; i++) {
23766 if (getTQuery(tView, i).matches !== null) {
23767 this.queries[i].setDirty();
23768 }
23769 }
23770 }
23771}
23772class TQueryMetadata_ {
23773 constructor(predicate, flags, read = null) {
23774 this.predicate = predicate;
23775 this.flags = flags;
23776 this.read = read;
23777 }
23778}
23779class TQueries_ {
23780 constructor(queries = []) {
23781 this.queries = queries;
23782 }
23783 elementStart(tView, tNode) {
23784 ngDevMode &&
23785 assertFirstCreatePass(tView, 'Queries should collect results on the first template pass only');
23786 for (let i = 0; i < this.queries.length; i++) {
23787 this.queries[i].elementStart(tView, tNode);
23788 }
23789 }
23790 elementEnd(tNode) {
23791 for (let i = 0; i < this.queries.length; i++) {
23792 this.queries[i].elementEnd(tNode);
23793 }
23794 }
23795 embeddedTView(tNode) {
23796 let queriesForTemplateRef = null;
23797 for (let i = 0; i < this.length; i++) {
23798 const childQueryIndex = queriesForTemplateRef !== null ? queriesForTemplateRef.length : 0;
23799 const tqueryClone = this.getByIndex(i).embeddedTView(tNode, childQueryIndex);
23800 if (tqueryClone) {
23801 tqueryClone.indexInDeclarationView = i;
23802 if (queriesForTemplateRef !== null) {
23803 queriesForTemplateRef.push(tqueryClone);
23804 }
23805 else {
23806 queriesForTemplateRef = [tqueryClone];
23807 }
23808 }
23809 }
23810 return queriesForTemplateRef !== null ? new TQueries_(queriesForTemplateRef) : null;
23811 }
23812 template(tView, tNode) {
23813 ngDevMode &&
23814 assertFirstCreatePass(tView, 'Queries should collect results on the first template pass only');
23815 for (let i = 0; i < this.queries.length; i++) {
23816 this.queries[i].template(tView, tNode);
23817 }
23818 }
23819 getByIndex(index) {
23820 ngDevMode && assertIndexInRange(this.queries, index);
23821 return this.queries[index];
23822 }
23823 get length() {
23824 return this.queries.length;
23825 }
23826 track(tquery) {
23827 this.queries.push(tquery);
23828 }
23829}
23830class TQuery_ {
23831 constructor(metadata, nodeIndex = -1) {
23832 this.metadata = metadata;
23833 this.matches = null;
23834 this.indexInDeclarationView = -1;
23835 this.crossesNgTemplate = false;
23836 /**
23837 * A flag indicating if a given query still applies to nodes it is crossing. We use this flag
23838 * (alongside with _declarationNodeIndex) to know when to stop applying content queries to
23839 * elements in a template.
23840 */
23841 this._appliesToNextNode = true;
23842 this._declarationNodeIndex = nodeIndex;
23843 }
23844 elementStart(tView, tNode) {
23845 if (this.isApplyingToNode(tNode)) {
23846 this.matchTNode(tView, tNode);
23847 }
23848 }
23849 elementEnd(tNode) {
23850 if (this._declarationNodeIndex === tNode.index) {
23851 this._appliesToNextNode = false;
23852 }
23853 }
23854 template(tView, tNode) {
23855 this.elementStart(tView, tNode);
23856 }
23857 embeddedTView(tNode, childQueryIndex) {
23858 if (this.isApplyingToNode(tNode)) {
23859 this.crossesNgTemplate = true;
23860 // A marker indicating a `<ng-template>` element (a placeholder for query results from
23861 // embedded views created based on this `<ng-template>`).
23862 this.addMatch(-tNode.index, childQueryIndex);
23863 return new TQuery_(this.metadata);
23864 }
23865 return null;
23866 }
23867 isApplyingToNode(tNode) {
23868 if (this._appliesToNextNode &&
23869 (this.metadata.flags & 1 /* QueryFlags.descendants */) !== 1 /* QueryFlags.descendants */) {
23870 const declarationNodeIdx = this._declarationNodeIndex;
23871 let parent = tNode.parent;
23872 // Determine if a given TNode is a "direct" child of a node on which a content query was
23873 // declared (only direct children of query's host node can match with the descendants: false
23874 // option). There are 3 main use-case / conditions to consider here:
23875 // - <needs-target><i #target></i></needs-target>: here <i #target> parent node is a query
23876 // host node;
23877 // - <needs-target><ng-template [ngIf]="true"><i #target></i></ng-template></needs-target>:
23878 // here <i #target> parent node is null;
23879 // - <needs-target><ng-container><i #target></i></ng-container></needs-target>: here we need
23880 // to go past `<ng-container>` to determine <i #target> parent node (but we shouldn't traverse
23881 // up past the query's host node!).
23882 while (parent !== null && (parent.type & 8 /* TNodeType.ElementContainer */) &&
23883 parent.index !== declarationNodeIdx) {
23884 parent = parent.parent;
23885 }
23886 return declarationNodeIdx === (parent !== null ? parent.index : -1);
23887 }
23888 return this._appliesToNextNode;
23889 }
23890 matchTNode(tView, tNode) {
23891 const predicate = this.metadata.predicate;
23892 if (Array.isArray(predicate)) {
23893 for (let i = 0; i < predicate.length; i++) {
23894 const name = predicate[i];
23895 this.matchTNodeWithReadOption(tView, tNode, getIdxOfMatchingSelector(tNode, name));
23896 // Also try matching the name to a provider since strings can be used as DI tokens too.
23897 this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, name, false, false));
23898 }
23899 }
23900 else {
23901 if (predicate === TemplateRef) {
23902 if (tNode.type & 4 /* TNodeType.Container */) {
23903 this.matchTNodeWithReadOption(tView, tNode, -1);
23904 }
23905 }
23906 else {
23907 this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, predicate, false, false));
23908 }
23909 }
23910 }
23911 matchTNodeWithReadOption(tView, tNode, nodeMatchIdx) {
23912 if (nodeMatchIdx !== null) {
23913 const read = this.metadata.read;
23914 if (read !== null) {
23915 if (read === ElementRef || read === ViewContainerRef ||
23916 read === TemplateRef && (tNode.type & 4 /* TNodeType.Container */)) {
23917 this.addMatch(tNode.index, -2);
23918 }
23919 else {
23920 const directiveOrProviderIdx = locateDirectiveOrProvider(tNode, tView, read, false, false);
23921 if (directiveOrProviderIdx !== null) {
23922 this.addMatch(tNode.index, directiveOrProviderIdx);
23923 }
23924 }
23925 }
23926 else {
23927 this.addMatch(tNode.index, nodeMatchIdx);
23928 }
23929 }
23930 }
23931 addMatch(tNodeIdx, matchIdx) {
23932 if (this.matches === null) {
23933 this.matches = [tNodeIdx, matchIdx];
23934 }
23935 else {
23936 this.matches.push(tNodeIdx, matchIdx);
23937 }
23938 }
23939}
23940/**
23941 * Iterates over local names for a given node and returns directive index
23942 * (or -1 if a local name points to an element).
23943 *
23944 * @param tNode static data of a node to check
23945 * @param selector selector to match
23946 * @returns directive index, -1 or null if a selector didn't match any of the local names
23947 */
23948function getIdxOfMatchingSelector(tNode, selector) {
23949 const localNames = tNode.localNames;
23950 if (localNames !== null) {
23951 for (let i = 0; i < localNames.length; i += 2) {
23952 if (localNames[i] === selector) {
23953 return localNames[i + 1];
23954 }
23955 }
23956 }
23957 return null;
23958}
23959function createResultByTNodeType(tNode, currentView) {
23960 if (tNode.type & (3 /* TNodeType.AnyRNode */ | 8 /* TNodeType.ElementContainer */)) {
23961 return createElementRef(tNode, currentView);
23962 }
23963 else if (tNode.type & 4 /* TNodeType.Container */) {
23964 return createTemplateRef(tNode, currentView);
23965 }
23966 return null;
23967}
23968function createResultForNode(lView, tNode, matchingIdx, read) {
23969 if (matchingIdx === -1) {
23970 // if read token and / or strategy is not specified, detect it using appropriate tNode type
23971 return createResultByTNodeType(tNode, lView);
23972 }
23973 else if (matchingIdx === -2) {
23974 // read a special token from a node injector
23975 return createSpecialToken(lView, tNode, read);
23976 }
23977 else {
23978 // read a token
23979 return getNodeInjectable(lView, lView[TVIEW], matchingIdx, tNode);
23980 }
23981}
23982function createSpecialToken(lView, tNode, read) {
23983 if (read === ElementRef) {
23984 return createElementRef(tNode, lView);
23985 }
23986 else if (read === TemplateRef) {
23987 return createTemplateRef(tNode, lView);
23988 }
23989 else if (read === ViewContainerRef) {
23990 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
23991 return createContainerRef(tNode, lView);
23992 }
23993 else {
23994 ngDevMode &&
23995 throwError(`Special token to read should be one of ElementRef, TemplateRef or ViewContainerRef but got ${stringify(read)}.`);
23996 }
23997}
23998/**
23999 * A helper function that creates query results for a given view. This function is meant to do the
24000 * processing once and only once for a given view instance (a set of results for a given view
24001 * doesn't change).
24002 */
24003function materializeViewResults(tView, lView, tQuery, queryIndex) {
24004 const lQuery = lView[QUERIES].queries[queryIndex];
24005 if (lQuery.matches === null) {
24006 const tViewData = tView.data;
24007 const tQueryMatches = tQuery.matches;
24008 const result = [];
24009 for (let i = 0; i < tQueryMatches.length; i += 2) {
24010 const matchedNodeIdx = tQueryMatches[i];
24011 if (matchedNodeIdx < 0) {
24012 // we at the <ng-template> marker which might have results in views created based on this
24013 // <ng-template> - those results will be in separate views though, so here we just leave
24014 // null as a placeholder
24015 result.push(null);
24016 }
24017 else {
24018 ngDevMode && assertIndexInRange(tViewData, matchedNodeIdx);
24019 const tNode = tViewData[matchedNodeIdx];
24020 result.push(createResultForNode(lView, tNode, tQueryMatches[i + 1], tQuery.metadata.read));
24021 }
24022 }
24023 lQuery.matches = result;
24024 }
24025 return lQuery.matches;
24026}
24027/**
24028 * A helper function that collects (already materialized) query results from a tree of views,
24029 * starting with a provided LView.
24030 */
24031function collectQueryResults(tView, lView, queryIndex, result) {
24032 const tQuery = tView.queries.getByIndex(queryIndex);
24033 const tQueryMatches = tQuery.matches;
24034 if (tQueryMatches !== null) {
24035 const lViewResults = materializeViewResults(tView, lView, tQuery, queryIndex);
24036 for (let i = 0; i < tQueryMatches.length; i += 2) {
24037 const tNodeIdx = tQueryMatches[i];
24038 if (tNodeIdx > 0) {
24039 result.push(lViewResults[i / 2]);
24040 }
24041 else {
24042 const childQueryIndex = tQueryMatches[i + 1];
24043 const declarationLContainer = lView[-tNodeIdx];
24044 ngDevMode && assertLContainer(declarationLContainer);
24045 // collect matches for views inserted in this container
24046 for (let i = CONTAINER_HEADER_OFFSET; i < declarationLContainer.length; i++) {
24047 const embeddedLView = declarationLContainer[i];
24048 if (embeddedLView[DECLARATION_LCONTAINER] === embeddedLView[PARENT]) {
24049 collectQueryResults(embeddedLView[TVIEW], embeddedLView, childQueryIndex, result);
24050 }
24051 }
24052 // collect matches for views created from this declaration container and inserted into
24053 // different containers
24054 if (declarationLContainer[MOVED_VIEWS] !== null) {
24055 const embeddedLViews = declarationLContainer[MOVED_VIEWS];
24056 for (let i = 0; i < embeddedLViews.length; i++) {
24057 const embeddedLView = embeddedLViews[i];
24058 collectQueryResults(embeddedLView[TVIEW], embeddedLView, childQueryIndex, result);
24059 }
24060 }
24061 }
24062 }
24063 }
24064 return result;
24065}
24066/**
24067 * Refreshes a query by combining matches from all active views and removing matches from deleted
24068 * views.
24069 *
24070 * @returns `true` if a query got dirty during change detection or if this is a static query
24071 * resolving in creation mode, `false` otherwise.
24072 *
24073 * @codeGenApi
24074 */
24075function ɵɵqueryRefresh(queryList) {
24076 const lView = getLView();
24077 const tView = getTView();
24078 const queryIndex = getCurrentQueryIndex();
24079 setCurrentQueryIndex(queryIndex + 1);
24080 const tQuery = getTQuery(tView, queryIndex);
24081 if (queryList.dirty &&
24082 (isCreationMode(lView) ===
24083 ((tQuery.metadata.flags & 2 /* QueryFlags.isStatic */) === 2 /* QueryFlags.isStatic */))) {
24084 if (tQuery.matches === null) {
24085 queryList.reset([]);
24086 }
24087 else {
24088 const result = tQuery.crossesNgTemplate ?
24089 collectQueryResults(tView, lView, queryIndex, []) :
24090 materializeViewResults(tView, lView, tQuery, queryIndex);
24091 queryList.reset(result, unwrapElementRef);
24092 queryList.notifyOnChanges();
24093 }
24094 return true;
24095 }
24096 return false;
24097}
24098/**
24099 * Creates new QueryList, stores the reference in LView and returns QueryList.
24100 *
24101 * @param predicate The type for which the query will search
24102 * @param flags Flags associated with the query
24103 * @param read What to save in the query
24104 *
24105 * @codeGenApi
24106 */
24107function ɵɵviewQuery(predicate, flags, read) {
24108 ngDevMode && assertNumber(flags, 'Expecting flags');
24109 const tView = getTView();
24110 if (tView.firstCreatePass) {
24111 createTQuery(tView, new TQueryMetadata_(predicate, flags, read), -1);
24112 if ((flags & 2 /* QueryFlags.isStatic */) === 2 /* QueryFlags.isStatic */) {
24113 tView.staticViewQueries = true;
24114 }
24115 }
24116 createLQuery(tView, getLView(), flags);
24117}
24118/**
24119 * Registers a QueryList, associated with a content query, for later refresh (part of a view
24120 * refresh).
24121 *
24122 * @param directiveIndex Current directive index
24123 * @param predicate The type for which the query will search
24124 * @param flags Flags associated with the query
24125 * @param read What to save in the query
24126 * @returns QueryList<T>
24127 *
24128 * @codeGenApi
24129 */
24130function ɵɵcontentQuery(directiveIndex, predicate, flags, read) {
24131 ngDevMode && assertNumber(flags, 'Expecting flags');
24132 const tView = getTView();
24133 if (tView.firstCreatePass) {
24134 const tNode = getCurrentTNode();
24135 createTQuery(tView, new TQueryMetadata_(predicate, flags, read), tNode.index);
24136 saveContentQueryAndDirectiveIndex(tView, directiveIndex);
24137 if ((flags & 2 /* QueryFlags.isStatic */) === 2 /* QueryFlags.isStatic */) {
24138 tView.staticContentQueries = true;
24139 }
24140 }
24141 createLQuery(tView, getLView(), flags);
24142}
24143/**
24144 * Loads a QueryList corresponding to the current view or content query.
24145 *
24146 * @codeGenApi
24147 */
24148function ɵɵloadQuery() {
24149 return loadQueryInternal(getLView(), getCurrentQueryIndex());
24150}
24151function loadQueryInternal(lView, queryIndex) {
24152 ngDevMode &&
24153 assertDefined(lView[QUERIES], 'LQueries should be defined when trying to load a query');
24154 ngDevMode && assertIndexInRange(lView[QUERIES].queries, queryIndex);
24155 return lView[QUERIES].queries[queryIndex].queryList;
24156}
24157function createLQuery(tView, lView, flags) {
24158 const queryList = new QueryList((flags & 4 /* QueryFlags.emitDistinctChangesOnly */) === 4 /* QueryFlags.emitDistinctChangesOnly */);
24159 storeCleanupWithContext(tView, lView, queryList, queryList.destroy);
24160 if (lView[QUERIES] === null)
24161 lView[QUERIES] = new LQueries_();
24162 lView[QUERIES].queries.push(new LQuery_(queryList));
24163}
24164function createTQuery(tView, metadata, nodeIndex) {
24165 if (tView.queries === null)
24166 tView.queries = new TQueries_();
24167 tView.queries.track(new TQuery_(metadata, nodeIndex));
24168}
24169function saveContentQueryAndDirectiveIndex(tView, directiveIndex) {
24170 const tViewContentQueries = tView.contentQueries || (tView.contentQueries = []);
24171 const lastSavedDirectiveIndex = tViewContentQueries.length ? tViewContentQueries[tViewContentQueries.length - 1] : -1;
24172 if (directiveIndex !== lastSavedDirectiveIndex) {
24173 tViewContentQueries.push(tView.queries.length - 1, directiveIndex);
24174 }
24175}
24176function getTQuery(tView, index) {
24177 ngDevMode && assertDefined(tView.queries, 'TQueries must be defined to retrieve a TQuery');
24178 return tView.queries.getByIndex(index);
24179}
24180
24181/**
24182 * @license
24183 * Copyright Google LLC All Rights Reserved.
24184 *
24185 * Use of this source code is governed by an MIT-style license that can be
24186 * found in the LICENSE file at https://angular.io/license
24187 */
24188/**
24189 * Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the
24190 * `<ng-template>` element.
24191 *
24192 * @codeGenApi
24193 */
24194function ɵɵtemplateRefExtractor(tNode, lView) {
24195 return createTemplateRef(tNode, lView);
24196}
24197
24198/**
24199 * @license
24200 * Copyright Google LLC All Rights Reserved.
24201 *
24202 * Use of this source code is governed by an MIT-style license that can be
24203 * found in the LICENSE file at https://angular.io/license
24204 */
24205
24206/**
24207 * @license
24208 * Copyright Google LLC All Rights Reserved.
24209 *
24210 * Use of this source code is governed by an MIT-style license that can be
24211 * found in the LICENSE file at https://angular.io/license
24212 */
24213/**
24214 * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
24215 *
24216 * This should be kept up to date with the public exports of @angular/core.
24217 */
24218const angularCoreEnv = (() => ({
24219 'ɵɵattribute': ɵɵattribute,
24220 'ɵɵattributeInterpolate1': ɵɵattributeInterpolate1,
24221 'ɵɵattributeInterpolate2': ɵɵattributeInterpolate2,
24222 'ɵɵattributeInterpolate3': ɵɵattributeInterpolate3,
24223 'ɵɵattributeInterpolate4': ɵɵattributeInterpolate4,
24224 'ɵɵattributeInterpolate5': ɵɵattributeInterpolate5,
24225 'ɵɵattributeInterpolate6': ɵɵattributeInterpolate6,
24226 'ɵɵattributeInterpolate7': ɵɵattributeInterpolate7,
24227 'ɵɵattributeInterpolate8': ɵɵattributeInterpolate8,
24228 'ɵɵattributeInterpolateV': ɵɵattributeInterpolateV,
24229 'ɵɵdefineComponent': ɵɵdefineComponent,
24230 'ɵɵdefineDirective': ɵɵdefineDirective,
24231 'ɵɵdefineInjectable': ɵɵdefineInjectable,
24232 'ɵɵdefineInjector': ɵɵdefineInjector,
24233 'ɵɵdefineNgModule': ɵɵdefineNgModule,
24234 'ɵɵdefinePipe': ɵɵdefinePipe,
24235 'ɵɵdirectiveInject': ɵɵdirectiveInject,
24236 'ɵɵgetInheritedFactory': ɵɵgetInheritedFactory,
24237 'ɵɵinject': ɵɵinject,
24238 'ɵɵinjectAttribute': ɵɵinjectAttribute,
24239 'ɵɵinvalidFactory': ɵɵinvalidFactory,
24240 'ɵɵinvalidFactoryDep': ɵɵinvalidFactoryDep,
24241 'ɵɵtemplateRefExtractor': ɵɵtemplateRefExtractor,
24242 'ɵɵresetView': ɵɵresetView,
24243 'ɵɵNgOnChangesFeature': ɵɵNgOnChangesFeature,
24244 'ɵɵProvidersFeature': ɵɵProvidersFeature,
24245 'ɵɵCopyDefinitionFeature': ɵɵCopyDefinitionFeature,
24246 'ɵɵInheritDefinitionFeature': ɵɵInheritDefinitionFeature,
24247 'ɵɵStandaloneFeature': ɵɵStandaloneFeature,
24248 'ɵɵnextContext': ɵɵnextContext,
24249 'ɵɵnamespaceHTML': ɵɵnamespaceHTML,
24250 'ɵɵnamespaceMathML': ɵɵnamespaceMathML,
24251 'ɵɵnamespaceSVG': ɵɵnamespaceSVG,
24252 'ɵɵenableBindings': ɵɵenableBindings,
24253 'ɵɵdisableBindings': ɵɵdisableBindings,
24254 'ɵɵelementStart': ɵɵelementStart,
24255 'ɵɵelementEnd': ɵɵelementEnd,
24256 'ɵɵelement': ɵɵelement,
24257 'ɵɵelementContainerStart': ɵɵelementContainerStart,
24258 'ɵɵelementContainerEnd': ɵɵelementContainerEnd,
24259 'ɵɵelementContainer': ɵɵelementContainer,
24260 'ɵɵpureFunction0': ɵɵpureFunction0,
24261 'ɵɵpureFunction1': ɵɵpureFunction1,
24262 'ɵɵpureFunction2': ɵɵpureFunction2,
24263 'ɵɵpureFunction3': ɵɵpureFunction3,
24264 'ɵɵpureFunction4': ɵɵpureFunction4,
24265 'ɵɵpureFunction5': ɵɵpureFunction5,
24266 'ɵɵpureFunction6': ɵɵpureFunction6,
24267 'ɵɵpureFunction7': ɵɵpureFunction7,
24268 'ɵɵpureFunction8': ɵɵpureFunction8,
24269 'ɵɵpureFunctionV': ɵɵpureFunctionV,
24270 'ɵɵgetCurrentView': ɵɵgetCurrentView,
24271 'ɵɵrestoreView': ɵɵrestoreView,
24272 'ɵɵlistener': ɵɵlistener,
24273 'ɵɵprojection': ɵɵprojection,
24274 'ɵɵsyntheticHostProperty': ɵɵsyntheticHostProperty,
24275 'ɵɵsyntheticHostListener': ɵɵsyntheticHostListener,
24276 'ɵɵpipeBind1': ɵɵpipeBind1,
24277 'ɵɵpipeBind2': ɵɵpipeBind2,
24278 'ɵɵpipeBind3': ɵɵpipeBind3,
24279 'ɵɵpipeBind4': ɵɵpipeBind4,
24280 'ɵɵpipeBindV': ɵɵpipeBindV,
24281 'ɵɵprojectionDef': ɵɵprojectionDef,
24282 'ɵɵhostProperty': ɵɵhostProperty,
24283 'ɵɵproperty': ɵɵproperty,
24284 'ɵɵpropertyInterpolate': ɵɵpropertyInterpolate,
24285 'ɵɵpropertyInterpolate1': ɵɵpropertyInterpolate1,
24286 'ɵɵpropertyInterpolate2': ɵɵpropertyInterpolate2,
24287 'ɵɵpropertyInterpolate3': ɵɵpropertyInterpolate3,
24288 'ɵɵpropertyInterpolate4': ɵɵpropertyInterpolate4,
24289 'ɵɵpropertyInterpolate5': ɵɵpropertyInterpolate5,
24290 'ɵɵpropertyInterpolate6': ɵɵpropertyInterpolate6,
24291 'ɵɵpropertyInterpolate7': ɵɵpropertyInterpolate7,
24292 'ɵɵpropertyInterpolate8': ɵɵpropertyInterpolate8,
24293 'ɵɵpropertyInterpolateV': ɵɵpropertyInterpolateV,
24294 'ɵɵpipe': ɵɵpipe,
24295 'ɵɵqueryRefresh': ɵɵqueryRefresh,
24296 'ɵɵviewQuery': ɵɵviewQuery,
24297 'ɵɵloadQuery': ɵɵloadQuery,
24298 'ɵɵcontentQuery': ɵɵcontentQuery,
24299 'ɵɵreference': ɵɵreference,
24300 'ɵɵclassMap': ɵɵclassMap,
24301 'ɵɵclassMapInterpolate1': ɵɵclassMapInterpolate1,
24302 'ɵɵclassMapInterpolate2': ɵɵclassMapInterpolate2,
24303 'ɵɵclassMapInterpolate3': ɵɵclassMapInterpolate3,
24304 'ɵɵclassMapInterpolate4': ɵɵclassMapInterpolate4,
24305 'ɵɵclassMapInterpolate5': ɵɵclassMapInterpolate5,
24306 'ɵɵclassMapInterpolate6': ɵɵclassMapInterpolate6,
24307 'ɵɵclassMapInterpolate7': ɵɵclassMapInterpolate7,
24308 'ɵɵclassMapInterpolate8': ɵɵclassMapInterpolate8,
24309 'ɵɵclassMapInterpolateV': ɵɵclassMapInterpolateV,
24310 'ɵɵstyleMap': ɵɵstyleMap,
24311 'ɵɵstyleMapInterpolate1': ɵɵstyleMapInterpolate1,
24312 'ɵɵstyleMapInterpolate2': ɵɵstyleMapInterpolate2,
24313 'ɵɵstyleMapInterpolate3': ɵɵstyleMapInterpolate3,
24314 'ɵɵstyleMapInterpolate4': ɵɵstyleMapInterpolate4,
24315 'ɵɵstyleMapInterpolate5': ɵɵstyleMapInterpolate5,
24316 'ɵɵstyleMapInterpolate6': ɵɵstyleMapInterpolate6,
24317 'ɵɵstyleMapInterpolate7': ɵɵstyleMapInterpolate7,
24318 'ɵɵstyleMapInterpolate8': ɵɵstyleMapInterpolate8,
24319 'ɵɵstyleMapInterpolateV': ɵɵstyleMapInterpolateV,
24320 'ɵɵstyleProp': ɵɵstyleProp,
24321 'ɵɵstylePropInterpolate1': ɵɵstylePropInterpolate1,
24322 'ɵɵstylePropInterpolate2': ɵɵstylePropInterpolate2,
24323 'ɵɵstylePropInterpolate3': ɵɵstylePropInterpolate3,
24324 'ɵɵstylePropInterpolate4': ɵɵstylePropInterpolate4,
24325 'ɵɵstylePropInterpolate5': ɵɵstylePropInterpolate5,
24326 'ɵɵstylePropInterpolate6': ɵɵstylePropInterpolate6,
24327 'ɵɵstylePropInterpolate7': ɵɵstylePropInterpolate7,
24328 'ɵɵstylePropInterpolate8': ɵɵstylePropInterpolate8,
24329 'ɵɵstylePropInterpolateV': ɵɵstylePropInterpolateV,
24330 'ɵɵclassProp': ɵɵclassProp,
24331 'ɵɵadvance': ɵɵadvance,
24332 'ɵɵtemplate': ɵɵtemplate,
24333 'ɵɵtext': ɵɵtext,
24334 'ɵɵtextInterpolate': ɵɵtextInterpolate,
24335 'ɵɵtextInterpolate1': ɵɵtextInterpolate1,
24336 'ɵɵtextInterpolate2': ɵɵtextInterpolate2,
24337 'ɵɵtextInterpolate3': ɵɵtextInterpolate3,
24338 'ɵɵtextInterpolate4': ɵɵtextInterpolate4,
24339 'ɵɵtextInterpolate5': ɵɵtextInterpolate5,
24340 'ɵɵtextInterpolate6': ɵɵtextInterpolate6,
24341 'ɵɵtextInterpolate7': ɵɵtextInterpolate7,
24342 'ɵɵtextInterpolate8': ɵɵtextInterpolate8,
24343 'ɵɵtextInterpolateV': ɵɵtextInterpolateV,
24344 'ɵɵi18n': ɵɵi18n,
24345 'ɵɵi18nAttributes': ɵɵi18nAttributes,
24346 'ɵɵi18nExp': ɵɵi18nExp,
24347 'ɵɵi18nStart': ɵɵi18nStart,
24348 'ɵɵi18nEnd': ɵɵi18nEnd,
24349 'ɵɵi18nApply': ɵɵi18nApply,
24350 'ɵɵi18nPostprocess': ɵɵi18nPostprocess,
24351 'ɵɵresolveWindow': ɵɵresolveWindow,
24352 'ɵɵresolveDocument': ɵɵresolveDocument,
24353 'ɵɵresolveBody': ɵɵresolveBody,
24354 'ɵɵsetComponentScope': ɵɵsetComponentScope,
24355 'ɵɵsetNgModuleScope': ɵɵsetNgModuleScope,
24356 'ɵɵregisterNgModuleType': registerNgModuleType,
24357 'ɵɵsanitizeHtml': ɵɵsanitizeHtml,
24358 'ɵɵsanitizeStyle': ɵɵsanitizeStyle,
24359 'ɵɵsanitizeResourceUrl': ɵɵsanitizeResourceUrl,
24360 'ɵɵsanitizeScript': ɵɵsanitizeScript,
24361 'ɵɵsanitizeUrl': ɵɵsanitizeUrl,
24362 'ɵɵsanitizeUrlOrResourceUrl': ɵɵsanitizeUrlOrResourceUrl,
24363 'ɵɵtrustConstantHtml': ɵɵtrustConstantHtml,
24364 'ɵɵtrustConstantResourceUrl': ɵɵtrustConstantResourceUrl,
24365 'forwardRef': forwardRef,
24366 'resolveForwardRef': resolveForwardRef,
24367}))();
24368
24369let jitOptions = null;
24370function setJitOptions(options) {
24371 if (jitOptions !== null) {
24372 if (options.defaultEncapsulation !== jitOptions.defaultEncapsulation) {
24373 ngDevMode &&
24374 console.error('Provided value for `defaultEncapsulation` can not be changed once it has been set.');
24375 return;
24376 }
24377 if (options.preserveWhitespaces !== jitOptions.preserveWhitespaces) {
24378 ngDevMode &&
24379 console.error('Provided value for `preserveWhitespaces` can not be changed once it has been set.');
24380 return;
24381 }
24382 }
24383 jitOptions = options;
24384}
24385function getJitOptions() {
24386 return jitOptions;
24387}
24388function resetJitOptions() {
24389 jitOptions = null;
24390}
24391
24392/**
24393 * @license
24394 * Copyright Google LLC All Rights Reserved.
24395 *
24396 * Use of this source code is governed by an MIT-style license that can be
24397 * found in the LICENSE file at https://angular.io/license
24398 */
24399function patchModuleCompilation() {
24400 // Does nothing, but exists as a target for patching.
24401}
24402
24403/**
24404 * @license
24405 * Copyright Google LLC All Rights Reserved.
24406 *
24407 * Use of this source code is governed by an MIT-style license that can be
24408 * found in the LICENSE file at https://angular.io/license
24409 */
24410function isModuleWithProviders(value) {
24411 return value.ngModule !== undefined;
24412}
24413function isNgModule(value) {
24414 return !!getNgModuleDef(value);
24415}
24416
24417/**
24418 * @license
24419 * Copyright Google LLC All Rights Reserved.
24420 *
24421 * Use of this source code is governed by an MIT-style license that can be
24422 * found in the LICENSE file at https://angular.io/license
24423 */
24424const moduleQueue = [];
24425/**
24426 * Enqueues moduleDef to be checked later to see if scope can be set on its
24427 * component declarations.
24428 */
24429function enqueueModuleForDelayedScoping(moduleType, ngModule) {
24430 moduleQueue.push({ moduleType, ngModule });
24431}
24432let flushingModuleQueue = false;
24433/**
24434 * Loops over queued module definitions, if a given module definition has all of its
24435 * declarations resolved, it dequeues that module definition and sets the scope on
24436 * its declarations.
24437 */
24438function flushModuleScopingQueueAsMuchAsPossible() {
24439 if (!flushingModuleQueue) {
24440 flushingModuleQueue = true;
24441 try {
24442 for (let i = moduleQueue.length - 1; i >= 0; i--) {
24443 const { moduleType, ngModule } = moduleQueue[i];
24444 if (ngModule.declarations && ngModule.declarations.every(isResolvedDeclaration)) {
24445 // dequeue
24446 moduleQueue.splice(i, 1);
24447 setScopeOnDeclaredComponents(moduleType, ngModule);
24448 }
24449 }
24450 }
24451 finally {
24452 flushingModuleQueue = false;
24453 }
24454 }
24455}
24456/**
24457 * Returns truthy if a declaration has resolved. If the declaration happens to be
24458 * an array of declarations, it will recurse to check each declaration in that array
24459 * (which may also be arrays).
24460 */
24461function isResolvedDeclaration(declaration) {
24462 if (Array.isArray(declaration)) {
24463 return declaration.every(isResolvedDeclaration);
24464 }
24465 return !!resolveForwardRef(declaration);
24466}
24467/**
24468 * Compiles a module in JIT mode.
24469 *
24470 * This function automatically gets called when a class has a `@NgModule` decorator.
24471 */
24472function compileNgModule(moduleType, ngModule = {}) {
24473 patchModuleCompilation();
24474 compileNgModuleDefs(moduleType, ngModule);
24475 if (ngModule.id !== undefined) {
24476 registerNgModuleType(moduleType, ngModule.id);
24477 }
24478 // Because we don't know if all declarations have resolved yet at the moment the
24479 // NgModule decorator is executing, we're enqueueing the setting of module scope
24480 // on its declarations to be run at a later time when all declarations for the module,
24481 // including forward refs, have resolved.
24482 enqueueModuleForDelayedScoping(moduleType, ngModule);
24483}
24484/**
24485 * Compiles and adds the `ɵmod`, `ɵfac` and `ɵinj` properties to the module class.
24486 *
24487 * It's possible to compile a module via this API which will allow duplicate declarations in its
24488 * root.
24489 */
24490function compileNgModuleDefs(moduleType, ngModule, allowDuplicateDeclarationsInRoot = false) {
24491 ngDevMode && assertDefined(moduleType, 'Required value moduleType');
24492 ngDevMode && assertDefined(ngModule, 'Required value ngModule');
24493 const declarations = flatten(ngModule.declarations || EMPTY_ARRAY);
24494 let ngModuleDef = null;
24495 Object.defineProperty(moduleType, NG_MOD_DEF, {
24496 configurable: true,
24497 get: () => {
24498 if (ngModuleDef === null) {
24499 if (ngDevMode && ngModule.imports && ngModule.imports.indexOf(moduleType) > -1) {
24500 // We need to assert this immediately, because allowing it to continue will cause it to
24501 // go into an infinite loop before we've reached the point where we throw all the errors.
24502 throw new Error(`'${stringifyForError(moduleType)}' module can't import itself`);
24503 }
24504 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'NgModule', type: moduleType });
24505 ngModuleDef = compiler.compileNgModule(angularCoreEnv, `ng:///${moduleType.name}/ɵmod.js`, {
24506 type: moduleType,
24507 bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(resolveForwardRef),
24508 declarations: declarations.map(resolveForwardRef),
24509 imports: flatten(ngModule.imports || EMPTY_ARRAY)
24510 .map(resolveForwardRef)
24511 .map(expandModuleWithProviders),
24512 exports: flatten(ngModule.exports || EMPTY_ARRAY)
24513 .map(resolveForwardRef)
24514 .map(expandModuleWithProviders),
24515 schemas: ngModule.schemas ? flatten(ngModule.schemas) : null,
24516 id: ngModule.id || null,
24517 });
24518 // Set `schemas` on ngModuleDef to an empty array in JIT mode to indicate that runtime
24519 // should verify that there are no unknown elements in a template. In AOT mode, that check
24520 // happens at compile time and `schemas` information is not present on Component and Module
24521 // defs after compilation (so the check doesn't happen the second time at runtime).
24522 if (!ngModuleDef.schemas) {
24523 ngModuleDef.schemas = [];
24524 }
24525 }
24526 return ngModuleDef;
24527 }
24528 });
24529 let ngFactoryDef = null;
24530 Object.defineProperty(moduleType, NG_FACTORY_DEF, {
24531 get: () => {
24532 if (ngFactoryDef === null) {
24533 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'NgModule', type: moduleType });
24534 ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${moduleType.name}/ɵfac.js`, {
24535 name: moduleType.name,
24536 type: moduleType,
24537 deps: reflectDependencies(moduleType),
24538 target: compiler.FactoryTarget.NgModule,
24539 typeArgumentCount: 0,
24540 });
24541 }
24542 return ngFactoryDef;
24543 },
24544 // Make the property configurable in dev mode to allow overriding in tests
24545 configurable: !!ngDevMode,
24546 });
24547 let ngInjectorDef = null;
24548 Object.defineProperty(moduleType, NG_INJ_DEF, {
24549 get: () => {
24550 if (ngInjectorDef === null) {
24551 ngDevMode &&
24552 verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot);
24553 const meta = {
24554 name: moduleType.name,
24555 type: moduleType,
24556 providers: ngModule.providers || EMPTY_ARRAY,
24557 imports: [
24558 (ngModule.imports || EMPTY_ARRAY).map(resolveForwardRef),
24559 (ngModule.exports || EMPTY_ARRAY).map(resolveForwardRef),
24560 ],
24561 };
24562 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'NgModule', type: moduleType });
24563 ngInjectorDef =
24564 compiler.compileInjector(angularCoreEnv, `ng:///${moduleType.name}/ɵinj.js`, meta);
24565 }
24566 return ngInjectorDef;
24567 },
24568 // Make the property configurable in dev mode to allow overriding in tests
24569 configurable: !!ngDevMode,
24570 });
24571}
24572function isStandalone(type) {
24573 const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef$1(type);
24574 return def !== null ? def.standalone : false;
24575}
24576function generateStandaloneInDeclarationsError(type, location) {
24577 const prefix = `Unexpected "${stringifyForError(type)}" found in the "declarations" array of the`;
24578 const suffix = `"${stringifyForError(type)}" is marked as standalone and can't be declared ` +
24579 'in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?';
24580 return `${prefix} ${location}, ${suffix}`;
24581}
24582function verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot, importingModule) {
24583 if (verifiedNgModule.get(moduleType))
24584 return;
24585 // skip verifications of standalone components, directives and pipes
24586 if (isStandalone(moduleType))
24587 return;
24588 verifiedNgModule.set(moduleType, true);
24589 moduleType = resolveForwardRef(moduleType);
24590 let ngModuleDef;
24591 if (importingModule) {
24592 ngModuleDef = getNgModuleDef(moduleType);
24593 if (!ngModuleDef) {
24594 throw new Error(`Unexpected value '${moduleType.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`);
24595 }
24596 }
24597 else {
24598 ngModuleDef = getNgModuleDef(moduleType, true);
24599 }
24600 const errors = [];
24601 const declarations = maybeUnwrapFn(ngModuleDef.declarations);
24602 const imports = maybeUnwrapFn(ngModuleDef.imports);
24603 flatten(imports).map(unwrapModuleWithProvidersImports).forEach(modOrStandaloneCmpt => {
24604 verifySemanticsOfNgModuleImport(modOrStandaloneCmpt, moduleType);
24605 verifySemanticsOfNgModuleDef(modOrStandaloneCmpt, false, moduleType);
24606 });
24607 const exports = maybeUnwrapFn(ngModuleDef.exports);
24608 declarations.forEach(verifyDeclarationsHaveDefinitions);
24609 declarations.forEach(verifyDirectivesHaveSelector);
24610 declarations.forEach((declarationType) => verifyNotStandalone(declarationType, moduleType));
24611 const combinedDeclarations = [
24612 ...declarations.map(resolveForwardRef),
24613 ...flatten(imports.map(computeCombinedExports)).map(resolveForwardRef),
24614 ];
24615 exports.forEach(verifyExportsAreDeclaredOrReExported);
24616 declarations.forEach(decl => verifyDeclarationIsUnique(decl, allowDuplicateDeclarationsInRoot));
24617 declarations.forEach(verifyComponentEntryComponentsIsPartOfNgModule);
24618 const ngModule = getAnnotation(moduleType, 'NgModule');
24619 if (ngModule) {
24620 ngModule.imports &&
24621 flatten(ngModule.imports).map(unwrapModuleWithProvidersImports).forEach(mod => {
24622 verifySemanticsOfNgModuleImport(mod, moduleType);
24623 verifySemanticsOfNgModuleDef(mod, false, moduleType);
24624 });
24625 ngModule.bootstrap && deepForEach(ngModule.bootstrap, verifyCorrectBootstrapType);
24626 ngModule.bootstrap && deepForEach(ngModule.bootstrap, verifyComponentIsPartOfNgModule);
24627 ngModule.entryComponents &&
24628 deepForEach(ngModule.entryComponents, verifyComponentIsPartOfNgModule);
24629 }
24630 // Throw Error if any errors were detected.
24631 if (errors.length) {
24632 throw new Error(errors.join('\n'));
24633 }
24634 ////////////////////////////////////////////////////////////////////////////////////////////////
24635 function verifyDeclarationsHaveDefinitions(type) {
24636 type = resolveForwardRef(type);
24637 const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef$1(type);
24638 if (!def) {
24639 errors.push(`Unexpected value '${stringifyForError(type)}' declared by the module '${stringifyForError(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`);
24640 }
24641 }
24642 function verifyDirectivesHaveSelector(type) {
24643 type = resolveForwardRef(type);
24644 const def = getDirectiveDef(type);
24645 if (!getComponentDef(type) && def && def.selectors.length == 0) {
24646 errors.push(`Directive ${stringifyForError(type)} has no selector, please add it!`);
24647 }
24648 }
24649 function verifyNotStandalone(type, moduleType) {
24650 type = resolveForwardRef(type);
24651 const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef$1(type);
24652 if (def === null || def === void 0 ? void 0 : def.standalone) {
24653 const location = `"${stringifyForError(moduleType)}" NgModule`;
24654 errors.push(generateStandaloneInDeclarationsError(type, location));
24655 }
24656 }
24657 function verifyExportsAreDeclaredOrReExported(type) {
24658 type = resolveForwardRef(type);
24659 const kind = getComponentDef(type) && 'component' || getDirectiveDef(type) && 'directive' ||
24660 getPipeDef$1(type) && 'pipe';
24661 if (kind) {
24662 // only checked if we are declared as Component, Directive, or Pipe
24663 // Modules don't need to be declared or imported.
24664 if (combinedDeclarations.lastIndexOf(type) === -1) {
24665 // We are exporting something which we don't explicitly declare or import.
24666 errors.push(`Can't export ${kind} ${stringifyForError(type)} from ${stringifyForError(moduleType)} as it was neither declared nor imported!`);
24667 }
24668 }
24669 }
24670 function verifyDeclarationIsUnique(type, suppressErrors) {
24671 type = resolveForwardRef(type);
24672 const existingModule = ownerNgModule.get(type);
24673 if (existingModule && existingModule !== moduleType) {
24674 if (!suppressErrors) {
24675 const modules = [existingModule, moduleType].map(stringifyForError).sort();
24676 errors.push(`Type ${stringifyForError(type)} is part of the declarations of 2 modules: ${modules[0]} and ${modules[1]}! ` +
24677 `Please consider moving ${stringifyForError(type)} to a higher module that imports ${modules[0]} and ${modules[1]}. ` +
24678 `You can also create a new NgModule that exports and includes ${stringifyForError(type)} then import that NgModule in ${modules[0]} and ${modules[1]}.`);
24679 }
24680 }
24681 else {
24682 // Mark type as having owner.
24683 ownerNgModule.set(type, moduleType);
24684 }
24685 }
24686 function verifyComponentIsPartOfNgModule(type) {
24687 type = resolveForwardRef(type);
24688 const existingModule = ownerNgModule.get(type);
24689 if (!existingModule && !isStandalone(type)) {
24690 errors.push(`Component ${stringifyForError(type)} is not part of any NgModule or the module has not been imported into your module.`);
24691 }
24692 }
24693 function verifyCorrectBootstrapType(type) {
24694 type = resolveForwardRef(type);
24695 if (!getComponentDef(type)) {
24696 errors.push(`${stringifyForError(type)} cannot be used as an entry component.`);
24697 }
24698 if (isStandalone(type)) {
24699 // Note: this error should be the same as the
24700 // `NGMODULE_BOOTSTRAP_IS_STANDALONE` one in AOT compiler.
24701 errors.push(`The \`${stringifyForError(type)}\` class is a standalone component, which can ` +
24702 `not be used in the \`@NgModule.bootstrap\` array. Use the \`bootstrapApplication\` ` +
24703 `function for bootstrap instead.`);
24704 }
24705 }
24706 function verifyComponentEntryComponentsIsPartOfNgModule(type) {
24707 type = resolveForwardRef(type);
24708 if (getComponentDef(type)) {
24709 // We know we are component
24710 const component = getAnnotation(type, 'Component');
24711 if (component && component.entryComponents) {
24712 deepForEach(component.entryComponents, verifyComponentIsPartOfNgModule);
24713 }
24714 }
24715 }
24716 function verifySemanticsOfNgModuleImport(type, importingModule) {
24717 type = resolveForwardRef(type);
24718 const directiveDef = getComponentDef(type) || getDirectiveDef(type);
24719 if (directiveDef !== null && !directiveDef.standalone) {
24720 throw new Error(`Unexpected directive '${type.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`);
24721 }
24722 const pipeDef = getPipeDef$1(type);
24723 if (pipeDef !== null && !pipeDef.standalone) {
24724 throw new Error(`Unexpected pipe '${type.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`);
24725 }
24726 }
24727}
24728function unwrapModuleWithProvidersImports(typeOrWithProviders) {
24729 typeOrWithProviders = resolveForwardRef(typeOrWithProviders);
24730 return typeOrWithProviders.ngModule || typeOrWithProviders;
24731}
24732function getAnnotation(type, name) {
24733 let annotation = null;
24734 collect(type.__annotations__);
24735 collect(type.decorators);
24736 return annotation;
24737 function collect(annotations) {
24738 if (annotations) {
24739 annotations.forEach(readAnnotation);
24740 }
24741 }
24742 function readAnnotation(decorator) {
24743 if (!annotation) {
24744 const proto = Object.getPrototypeOf(decorator);
24745 if (proto.ngMetadataName == name) {
24746 annotation = decorator;
24747 }
24748 else if (decorator.type) {
24749 const proto = Object.getPrototypeOf(decorator.type);
24750 if (proto.ngMetadataName == name) {
24751 annotation = decorator.args[0];
24752 }
24753 }
24754 }
24755 }
24756}
24757/**
24758 * Keep track of compiled components. This is needed because in tests we often want to compile the
24759 * same component with more than one NgModule. This would cause an error unless we reset which
24760 * NgModule the component belongs to. We keep the list of compiled components here so that the
24761 * TestBed can reset it later.
24762 */
24763let ownerNgModule = new WeakMap();
24764let verifiedNgModule = new WeakMap();
24765function resetCompiledComponents() {
24766 ownerNgModule = new WeakMap();
24767 verifiedNgModule = new WeakMap();
24768 moduleQueue.length = 0;
24769}
24770/**
24771 * Computes the combined declarations of explicit declarations, as well as declarations inherited by
24772 * traversing the exports of imported modules.
24773 * @param type
24774 */
24775function computeCombinedExports(type) {
24776 type = resolveForwardRef(type);
24777 const ngModuleDef = getNgModuleDef(type);
24778 // a standalone component, directive or pipe
24779 if (ngModuleDef === null) {
24780 return [type];
24781 }
24782 return [...flatten(maybeUnwrapFn(ngModuleDef.exports).map((type) => {
24783 const ngModuleDef = getNgModuleDef(type);
24784 if (ngModuleDef) {
24785 verifySemanticsOfNgModuleDef(type, false);
24786 return computeCombinedExports(type);
24787 }
24788 else {
24789 return type;
24790 }
24791 }))];
24792}
24793/**
24794 * Some declared components may be compiled asynchronously, and thus may not have their
24795 * ɵcmp set yet. If this is the case, then a reference to the module is written into
24796 * the `ngSelectorScope` property of the declared type.
24797 */
24798function setScopeOnDeclaredComponents(moduleType, ngModule) {
24799 const declarations = flatten(ngModule.declarations || EMPTY_ARRAY);
24800 const transitiveScopes = transitiveScopesFor(moduleType);
24801 declarations.forEach(declaration => {
24802 declaration = resolveForwardRef(declaration);
24803 if (declaration.hasOwnProperty(NG_COMP_DEF)) {
24804 // A `ɵcmp` field exists - go ahead and patch the component directly.
24805 const component = declaration;
24806 const componentDef = getComponentDef(component);
24807 patchComponentDefWithScope(componentDef, transitiveScopes);
24808 }
24809 else if (!declaration.hasOwnProperty(NG_DIR_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) {
24810 // Set `ngSelectorScope` for future reference when the component compilation finishes.
24811 declaration.ngSelectorScope = moduleType;
24812 }
24813 });
24814}
24815/**
24816 * Patch the definition of a component with directives and pipes from the compilation scope of
24817 * a given module.
24818 */
24819function patchComponentDefWithScope(componentDef, transitiveScopes) {
24820 componentDef.directiveDefs = () => Array.from(transitiveScopes.compilation.directives)
24821 .map(dir => dir.hasOwnProperty(NG_COMP_DEF) ? getComponentDef(dir) : getDirectiveDef(dir))
24822 .filter(def => !!def);
24823 componentDef.pipeDefs = () => Array.from(transitiveScopes.compilation.pipes).map(pipe => getPipeDef$1(pipe));
24824 componentDef.schemas = transitiveScopes.schemas;
24825 // Since we avoid Components/Directives/Pipes recompiling in case there are no overrides, we
24826 // may face a problem where previously compiled defs available to a given Component/Directive
24827 // are cached in TView and may become stale (in case any of these defs gets recompiled). In
24828 // order to avoid this problem, we force fresh TView to be created.
24829 componentDef.tView = null;
24830}
24831/**
24832 * Compute the pair of transitive scopes (compilation scope and exported scope) for a given type
24833 * (either a NgModule or a standalone component / directive / pipe).
24834 */
24835function transitiveScopesFor(type) {
24836 if (isNgModule(type)) {
24837 return transitiveScopesForNgModule(type);
24838 }
24839 else if (isStandalone(type)) {
24840 const directiveDef = getComponentDef(type) || getDirectiveDef(type);
24841 if (directiveDef !== null) {
24842 return {
24843 schemas: null,
24844 compilation: {
24845 directives: new Set(),
24846 pipes: new Set(),
24847 },
24848 exported: {
24849 directives: new Set([type]),
24850 pipes: new Set(),
24851 },
24852 };
24853 }
24854 const pipeDef = getPipeDef$1(type);
24855 if (pipeDef !== null) {
24856 return {
24857 schemas: null,
24858 compilation: {
24859 directives: new Set(),
24860 pipes: new Set(),
24861 },
24862 exported: {
24863 directives: new Set(),
24864 pipes: new Set([type]),
24865 },
24866 };
24867 }
24868 }
24869 // TODO: change the error message to be more user-facing and take standalone into account
24870 throw new Error(`${type.name} does not have a module def (ɵmod property)`);
24871}
24872/**
24873 * Compute the pair of transitive scopes (compilation scope and exported scope) for a given module.
24874 *
24875 * This operation is memoized and the result is cached on the module's definition. This function can
24876 * be called on modules with components that have not fully compiled yet, but the result should not
24877 * be used until they have.
24878 *
24879 * @param moduleType module that transitive scope should be calculated for.
24880 */
24881function transitiveScopesForNgModule(moduleType) {
24882 const def = getNgModuleDef(moduleType, true);
24883 if (def.transitiveCompileScopes !== null) {
24884 return def.transitiveCompileScopes;
24885 }
24886 const scopes = {
24887 schemas: def.schemas || null,
24888 compilation: {
24889 directives: new Set(),
24890 pipes: new Set(),
24891 },
24892 exported: {
24893 directives: new Set(),
24894 pipes: new Set(),
24895 },
24896 };
24897 maybeUnwrapFn(def.imports).forEach((imported) => {
24898 // When this module imports another, the imported module's exported directives and pipes are
24899 // added to the compilation scope of this module.
24900 const importedScope = transitiveScopesFor(imported);
24901 importedScope.exported.directives.forEach(entry => scopes.compilation.directives.add(entry));
24902 importedScope.exported.pipes.forEach(entry => scopes.compilation.pipes.add(entry));
24903 });
24904 maybeUnwrapFn(def.declarations).forEach(declared => {
24905 const declaredWithDefs = declared;
24906 if (getPipeDef$1(declaredWithDefs)) {
24907 scopes.compilation.pipes.add(declared);
24908 }
24909 else {
24910 // Either declared has a ɵcmp or ɵdir, or it's a component which hasn't
24911 // had its template compiled yet. In either case, it gets added to the compilation's
24912 // directives.
24913 scopes.compilation.directives.add(declared);
24914 }
24915 });
24916 maybeUnwrapFn(def.exports).forEach((exported) => {
24917 const exportedType = exported;
24918 // Either the type is a module, a pipe, or a component/directive (which may not have a
24919 // ɵcmp as it might be compiled asynchronously).
24920 if (isNgModule(exportedType)) {
24921 // When this module exports another, the exported module's exported directives and pipes are
24922 // added to both the compilation and exported scopes of this module.
24923 const exportedScope = transitiveScopesFor(exportedType);
24924 exportedScope.exported.directives.forEach(entry => {
24925 scopes.compilation.directives.add(entry);
24926 scopes.exported.directives.add(entry);
24927 });
24928 exportedScope.exported.pipes.forEach(entry => {
24929 scopes.compilation.pipes.add(entry);
24930 scopes.exported.pipes.add(entry);
24931 });
24932 }
24933 else if (getPipeDef$1(exportedType)) {
24934 scopes.exported.pipes.add(exportedType);
24935 }
24936 else {
24937 scopes.exported.directives.add(exportedType);
24938 }
24939 });
24940 def.transitiveCompileScopes = scopes;
24941 return scopes;
24942}
24943function expandModuleWithProviders(value) {
24944 if (isModuleWithProviders(value)) {
24945 return value.ngModule;
24946 }
24947 return value;
24948}
24949
24950/**
24951 * @license
24952 * Copyright Google LLC All Rights Reserved.
24953 *
24954 * Use of this source code is governed by an MIT-style license that can be
24955 * found in the LICENSE file at https://angular.io/license
24956 */
24957/**
24958 * Keep track of the compilation depth to avoid reentrancy issues during JIT compilation. This
24959 * matters in the following scenario:
24960 *
24961 * Consider a component 'A' that extends component 'B', both declared in module 'M'. During
24962 * the compilation of 'A' the definition of 'B' is requested to capture the inheritance chain,
24963 * potentially triggering compilation of 'B'. If this nested compilation were to trigger
24964 * `flushModuleScopingQueueAsMuchAsPossible` it may happen that module 'M' is still pending in the
24965 * queue, resulting in 'A' and 'B' to be patched with the NgModule scope. As the compilation of
24966 * 'A' is still in progress, this would introduce a circular dependency on its compilation. To avoid
24967 * this issue, the module scope queue is only flushed for compilations at the depth 0, to ensure
24968 * all compilations have finished.
24969 */
24970let compilationDepth = 0;
24971/**
24972 * Compile an Angular component according to its decorator metadata, and patch the resulting
24973 * component def (ɵcmp) onto the component type.
24974 *
24975 * Compilation may be asynchronous (due to the need to resolve URLs for the component template or
24976 * other resources, for example). In the event that compilation is not immediate, `compileComponent`
24977 * will enqueue resource resolution into a global queue and will fail to return the `ɵcmp`
24978 * until the global queue has been resolved with a call to `resolveComponentResources`.
24979 */
24980function compileComponent(type, metadata) {
24981 // Initialize ngDevMode. This must be the first statement in compileComponent.
24982 // See the `initNgDevMode` docstring for more information.
24983 (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
24984 let ngComponentDef = null;
24985 // Metadata may have resources which need to be resolved.
24986 maybeQueueResolutionOfComponentResources(type, metadata);
24987 // Note that we're using the same function as `Directive`, because that's only subset of metadata
24988 // that we need to create the ngFactoryDef. We're avoiding using the component metadata
24989 // because we'd have to resolve the asynchronous templates.
24990 addDirectiveFactoryDef(type, metadata);
24991 Object.defineProperty(type, NG_COMP_DEF, {
24992 get: () => {
24993 if (ngComponentDef === null) {
24994 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'component', type: type });
24995 if (componentNeedsResolution(metadata)) {
24996 const error = [`Component '${type.name}' is not resolved:`];
24997 if (metadata.templateUrl) {
24998 error.push(` - templateUrl: ${metadata.templateUrl}`);
24999 }
25000 if (metadata.styleUrls && metadata.styleUrls.length) {
25001 error.push(` - styleUrls: ${JSON.stringify(metadata.styleUrls)}`);
25002 }
25003 error.push(`Did you run and wait for 'resolveComponentResources()'?`);
25004 throw new Error(error.join('\n'));
25005 }
25006 // This const was called `jitOptions` previously but had to be renamed to `options` because
25007 // of a bug with Terser that caused optimized JIT builds to throw a `ReferenceError`.
25008 // This bug was investigated in https://github.com/angular/angular-cli/issues/17264.
25009 // We should not rename it back until https://github.com/terser/terser/issues/615 is fixed.
25010 const options = getJitOptions();
25011 let preserveWhitespaces = metadata.preserveWhitespaces;
25012 if (preserveWhitespaces === undefined) {
25013 if (options !== null && options.preserveWhitespaces !== undefined) {
25014 preserveWhitespaces = options.preserveWhitespaces;
25015 }
25016 else {
25017 preserveWhitespaces = false;
25018 }
25019 }
25020 let encapsulation = metadata.encapsulation;
25021 if (encapsulation === undefined) {
25022 if (options !== null && options.defaultEncapsulation !== undefined) {
25023 encapsulation = options.defaultEncapsulation;
25024 }
25025 else {
25026 encapsulation = ViewEncapsulation$1.Emulated;
25027 }
25028 }
25029 const templateUrl = metadata.templateUrl || `ng:///${type.name}/template.html`;
25030 const meta = Object.assign(Object.assign({}, directiveMetadata(type, metadata)), { typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl), template: metadata.template || '', preserveWhitespaces, styles: metadata.styles || EMPTY_ARRAY, animations: metadata.animations,
25031 // JIT components are always compiled against an empty set of `declarations`. Instead, the
25032 // `directiveDefs` and `pipeDefs` are updated at a later point:
25033 // * for NgModule-based components, they're set when the NgModule which declares the
25034 // component resolves in the module scoping queue
25035 // * for standalone components, they're set just below, after `compileComponent`.
25036 declarations: [], changeDetection: metadata.changeDetection, encapsulation, interpolation: metadata.interpolation, viewProviders: metadata.viewProviders || null, isStandalone: !!metadata.standalone });
25037 compilationDepth++;
25038 try {
25039 if (meta.usesInheritance) {
25040 addDirectiveDefToUndecoratedParents(type);
25041 }
25042 ngComponentDef =
25043 compiler.compileComponent(angularCoreEnv, templateUrl, meta);
25044 if (metadata.standalone) {
25045 // Patch the component definition for standalone components with `directiveDefs` and
25046 // `pipeDefs` functions which lazily compute the directives/pipes available in the
25047 // standalone component. Also set `dependencies` to the lazily resolved list of imports.
25048 const imports = flatten(metadata.imports || EMPTY_ARRAY);
25049 const { directiveDefs, pipeDefs } = getStandaloneDefFunctions(type, imports);
25050 ngComponentDef.directiveDefs = directiveDefs;
25051 ngComponentDef.pipeDefs = pipeDefs;
25052 ngComponentDef.dependencies = () => imports.map(resolveForwardRef);
25053 }
25054 }
25055 finally {
25056 // Ensure that the compilation depth is decremented even when the compilation failed.
25057 compilationDepth--;
25058 }
25059 if (compilationDepth === 0) {
25060 // When NgModule decorator executed, we enqueued the module definition such that
25061 // it would only dequeue and add itself as module scope to all of its declarations,
25062 // but only if if all of its declarations had resolved. This call runs the check
25063 // to see if any modules that are in the queue can be dequeued and add scope to
25064 // their declarations.
25065 flushModuleScopingQueueAsMuchAsPossible();
25066 }
25067 // If component compilation is async, then the @NgModule annotation which declares the
25068 // component may execute and set an ngSelectorScope property on the component type. This
25069 // allows the component to patch itself with directiveDefs from the module after it
25070 // finishes compiling.
25071 if (hasSelectorScope(type)) {
25072 const scopes = transitiveScopesFor(type.ngSelectorScope);
25073 patchComponentDefWithScope(ngComponentDef, scopes);
25074 }
25075 if (metadata.schemas) {
25076 if (metadata.standalone) {
25077 ngComponentDef.schemas = metadata.schemas;
25078 }
25079 else {
25080 throw new Error(`The 'schemas' was specified for the ${stringifyForError(type)} but is only valid on a component that is standalone.`);
25081 }
25082 }
25083 else if (metadata.standalone) {
25084 ngComponentDef.schemas = [];
25085 }
25086 }
25087 return ngComponentDef;
25088 },
25089 // Make the property configurable in dev mode to allow overriding in tests
25090 configurable: !!ngDevMode,
25091 });
25092}
25093function getDependencyTypeForError(type) {
25094 if (getComponentDef(type))
25095 return 'component';
25096 if (getDirectiveDef(type))
25097 return 'directive';
25098 if (getPipeDef$1(type))
25099 return 'pipe';
25100 return 'type';
25101}
25102function verifyStandaloneImport(depType, importingType) {
25103 if (isForwardRef(depType)) {
25104 depType = resolveForwardRef(depType);
25105 if (!depType) {
25106 throw new Error(`Expected forwardRef function, imported from "${stringifyForError(importingType)}", to return a standalone entity or NgModule but got "${stringifyForError(depType) || depType}".`);
25107 }
25108 }
25109 if (getNgModuleDef(depType) == null) {
25110 const def = getComponentDef(depType) || getDirectiveDef(depType) || getPipeDef$1(depType);
25111 if (def != null) {
25112 // if a component, directive or pipe is imported make sure that it is standalone
25113 if (!def.standalone) {
25114 throw new Error(`The "${stringifyForError(depType)}" ${getDependencyTypeForError(depType)}, imported from "${stringifyForError(importingType)}", is not standalone. Did you forget to add the standalone: true flag?`);
25115 }
25116 }
25117 else {
25118 // it can be either a module with provider or an unknown (not annotated) type
25119 if (isModuleWithProviders(depType)) {
25120 throw new Error(`A module with providers was imported from "${stringifyForError(importingType)}". Modules with providers are not supported in standalone components imports.`);
25121 }
25122 else {
25123 throw new Error(`The "${stringifyForError(depType)}" type, imported from "${stringifyForError(importingType)}", must be a standalone component / directive / pipe or an NgModule. Did you forget to add the required @Component / @Directive / @Pipe or @NgModule annotation?`);
25124 }
25125 }
25126 }
25127}
25128/**
25129 * Build memoized `directiveDefs` and `pipeDefs` functions for the component definition of a
25130 * standalone component, which process `imports` and filter out directives and pipes. The use of
25131 * memoized functions here allows for the delayed resolution of any `forwardRef`s present in the
25132 * component's `imports`.
25133 */
25134function getStandaloneDefFunctions(type, imports) {
25135 let cachedDirectiveDefs = null;
25136 let cachedPipeDefs = null;
25137 const directiveDefs = () => {
25138 if (cachedDirectiveDefs === null) {
25139 // Standalone components are always able to self-reference, so include the component's own
25140 // definition in its `directiveDefs`.
25141 cachedDirectiveDefs = [getComponentDef(type)];
25142 const seen = new Set();
25143 for (const rawDep of imports) {
25144 ngDevMode && verifyStandaloneImport(rawDep, type);
25145 const dep = resolveForwardRef(rawDep);
25146 if (seen.has(dep)) {
25147 continue;
25148 }
25149 seen.add(dep);
25150 if (!!getNgModuleDef(dep)) {
25151 const scope = transitiveScopesFor(dep);
25152 for (const dir of scope.exported.directives) {
25153 const def = getComponentDef(dir) || getDirectiveDef(dir);
25154 if (def && !seen.has(dir)) {
25155 seen.add(dir);
25156 cachedDirectiveDefs.push(def);
25157 }
25158 }
25159 }
25160 else {
25161 const def = getComponentDef(dep) || getDirectiveDef(dep);
25162 if (def) {
25163 cachedDirectiveDefs.push(def);
25164 }
25165 }
25166 }
25167 }
25168 return cachedDirectiveDefs;
25169 };
25170 const pipeDefs = () => {
25171 if (cachedPipeDefs === null) {
25172 cachedPipeDefs = [];
25173 const seen = new Set();
25174 for (const rawDep of imports) {
25175 const dep = resolveForwardRef(rawDep);
25176 if (seen.has(dep)) {
25177 continue;
25178 }
25179 seen.add(dep);
25180 if (!!getNgModuleDef(dep)) {
25181 const scope = transitiveScopesFor(dep);
25182 for (const pipe of scope.exported.pipes) {
25183 const def = getPipeDef$1(pipe);
25184 if (def && !seen.has(pipe)) {
25185 seen.add(pipe);
25186 cachedPipeDefs.push(def);
25187 }
25188 }
25189 }
25190 else {
25191 const def = getPipeDef$1(dep);
25192 if (def) {
25193 cachedPipeDefs.push(def);
25194 }
25195 }
25196 }
25197 }
25198 return cachedPipeDefs;
25199 };
25200 return {
25201 directiveDefs,
25202 pipeDefs,
25203 };
25204}
25205function hasSelectorScope(component) {
25206 return component.ngSelectorScope !== undefined;
25207}
25208/**
25209 * Compile an Angular directive according to its decorator metadata, and patch the resulting
25210 * directive def onto the component type.
25211 *
25212 * In the event that compilation is not immediate, `compileDirective` will return a `Promise` which
25213 * will resolve when compilation completes and the directive becomes usable.
25214 */
25215function compileDirective(type, directive) {
25216 let ngDirectiveDef = null;
25217 addDirectiveFactoryDef(type, directive || {});
25218 Object.defineProperty(type, NG_DIR_DEF, {
25219 get: () => {
25220 if (ngDirectiveDef === null) {
25221 // `directive` can be null in the case of abstract directives as a base class
25222 // that use `@Directive()` with no selector. In that case, pass empty object to the
25223 // `directiveMetadata` function instead of null.
25224 const meta = getDirectiveMetadata(type, directive || {});
25225 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'directive', type });
25226 ngDirectiveDef =
25227 compiler.compileDirective(angularCoreEnv, meta.sourceMapUrl, meta.metadata);
25228 }
25229 return ngDirectiveDef;
25230 },
25231 // Make the property configurable in dev mode to allow overriding in tests
25232 configurable: !!ngDevMode,
25233 });
25234}
25235function getDirectiveMetadata(type, metadata) {
25236 const name = type && type.name;
25237 const sourceMapUrl = `ng:///${name}/ɵdir.js`;
25238 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'directive', type });
25239 const facade = directiveMetadata(type, metadata);
25240 facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl);
25241 if (facade.usesInheritance) {
25242 addDirectiveDefToUndecoratedParents(type);
25243 }
25244 return { metadata: facade, sourceMapUrl };
25245}
25246function addDirectiveFactoryDef(type, metadata) {
25247 let ngFactoryDef = null;
25248 Object.defineProperty(type, NG_FACTORY_DEF, {
25249 get: () => {
25250 if (ngFactoryDef === null) {
25251 const meta = getDirectiveMetadata(type, metadata);
25252 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'directive', type });
25253 ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${type.name}/ɵfac.js`, {
25254 name: meta.metadata.name,
25255 type: meta.metadata.type,
25256 typeArgumentCount: 0,
25257 deps: reflectDependencies(type),
25258 target: compiler.FactoryTarget.Directive
25259 });
25260 }
25261 return ngFactoryDef;
25262 },
25263 // Make the property configurable in dev mode to allow overriding in tests
25264 configurable: !!ngDevMode,
25265 });
25266}
25267function extendsDirectlyFromObject(type) {
25268 return Object.getPrototypeOf(type.prototype) === Object.prototype;
25269}
25270/**
25271 * Extract the `R3DirectiveMetadata` for a particular directive (either a `Directive` or a
25272 * `Component`).
25273 */
25274function directiveMetadata(type, metadata) {
25275 // Reflect inputs and outputs.
25276 const reflect = getReflect();
25277 const propMetadata = reflect.ownPropMetadata(type);
25278 return {
25279 name: type.name,
25280 type: type,
25281 selector: metadata.selector !== undefined ? metadata.selector : null,
25282 host: metadata.host || EMPTY_OBJ,
25283 propMetadata: propMetadata,
25284 inputs: metadata.inputs || EMPTY_ARRAY,
25285 outputs: metadata.outputs || EMPTY_ARRAY,
25286 queries: extractQueriesMetadata(type, propMetadata, isContentQuery),
25287 lifecycle: { usesOnChanges: reflect.hasLifecycleHook(type, 'ngOnChanges') },
25288 typeSourceSpan: null,
25289 usesInheritance: !extendsDirectlyFromObject(type),
25290 exportAs: extractExportAs(metadata.exportAs),
25291 providers: metadata.providers || null,
25292 viewQueries: extractQueriesMetadata(type, propMetadata, isViewQuery),
25293 isStandalone: !!metadata.standalone,
25294 };
25295}
25296/**
25297 * Adds a directive definition to all parent classes of a type that don't have an Angular decorator.
25298 */
25299function addDirectiveDefToUndecoratedParents(type) {
25300 const objPrototype = Object.prototype;
25301 let parent = Object.getPrototypeOf(type.prototype).constructor;
25302 // Go up the prototype until we hit `Object`.
25303 while (parent && parent !== objPrototype) {
25304 // Since inheritance works if the class was annotated already, we only need to add
25305 // the def if there are no annotations and the def hasn't been created already.
25306 if (!getDirectiveDef(parent) && !getComponentDef(parent) &&
25307 shouldAddAbstractDirective(parent)) {
25308 compileDirective(parent, null);
25309 }
25310 parent = Object.getPrototypeOf(parent);
25311 }
25312}
25313function convertToR3QueryPredicate(selector) {
25314 return typeof selector === 'string' ? splitByComma(selector) : resolveForwardRef(selector);
25315}
25316function convertToR3QueryMetadata(propertyName, ann) {
25317 return {
25318 propertyName: propertyName,
25319 predicate: convertToR3QueryPredicate(ann.selector),
25320 descendants: ann.descendants,
25321 first: ann.first,
25322 read: ann.read ? ann.read : null,
25323 static: !!ann.static,
25324 emitDistinctChangesOnly: !!ann.emitDistinctChangesOnly,
25325 };
25326}
25327function extractQueriesMetadata(type, propMetadata, isQueryAnn) {
25328 const queriesMeta = [];
25329 for (const field in propMetadata) {
25330 if (propMetadata.hasOwnProperty(field)) {
25331 const annotations = propMetadata[field];
25332 annotations.forEach(ann => {
25333 if (isQueryAnn(ann)) {
25334 if (!ann.selector) {
25335 throw new Error(`Can't construct a query for the property "${field}" of ` +
25336 `"${stringifyForError(type)}" since the query selector wasn't defined.`);
25337 }
25338 if (annotations.some(isInputAnnotation)) {
25339 throw new Error(`Cannot combine @Input decorators with query decorators`);
25340 }
25341 queriesMeta.push(convertToR3QueryMetadata(field, ann));
25342 }
25343 });
25344 }
25345 }
25346 return queriesMeta;
25347}
25348function extractExportAs(exportAs) {
25349 return exportAs === undefined ? null : splitByComma(exportAs);
25350}
25351function isContentQuery(value) {
25352 const name = value.ngMetadataName;
25353 return name === 'ContentChild' || name === 'ContentChildren';
25354}
25355function isViewQuery(value) {
25356 const name = value.ngMetadataName;
25357 return name === 'ViewChild' || name === 'ViewChildren';
25358}
25359function isInputAnnotation(value) {
25360 return value.ngMetadataName === 'Input';
25361}
25362function splitByComma(value) {
25363 return value.split(',').map(piece => piece.trim());
25364}
25365const LIFECYCLE_HOOKS = [
25366 'ngOnChanges', 'ngOnInit', 'ngOnDestroy', 'ngDoCheck', 'ngAfterViewInit', 'ngAfterViewChecked',
25367 'ngAfterContentInit', 'ngAfterContentChecked'
25368];
25369function shouldAddAbstractDirective(type) {
25370 const reflect = getReflect();
25371 if (LIFECYCLE_HOOKS.some(hookName => reflect.hasLifecycleHook(type, hookName))) {
25372 return true;
25373 }
25374 const propMetadata = reflect.propMetadata(type);
25375 for (const field in propMetadata) {
25376 const annotations = propMetadata[field];
25377 for (let i = 0; i < annotations.length; i++) {
25378 const current = annotations[i];
25379 const metadataName = current.ngMetadataName;
25380 if (isInputAnnotation(current) || isContentQuery(current) || isViewQuery(current) ||
25381 metadataName === 'Output' || metadataName === 'HostBinding' ||
25382 metadataName === 'HostListener') {
25383 return true;
25384 }
25385 }
25386 }
25387 return false;
25388}
25389
25390/**
25391 * @license
25392 * Copyright Google LLC All Rights Reserved.
25393 *
25394 * Use of this source code is governed by an MIT-style license that can be
25395 * found in the LICENSE file at https://angular.io/license
25396 */
25397function compilePipe(type, meta) {
25398 let ngPipeDef = null;
25399 let ngFactoryDef = null;
25400 Object.defineProperty(type, NG_FACTORY_DEF, {
25401 get: () => {
25402 if (ngFactoryDef === null) {
25403 const metadata = getPipeMetadata(type, meta);
25404 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'pipe', type: metadata.type });
25405 ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${metadata.name}/ɵfac.js`, {
25406 name: metadata.name,
25407 type: metadata.type,
25408 typeArgumentCount: 0,
25409 deps: reflectDependencies(type),
25410 target: compiler.FactoryTarget.Pipe
25411 });
25412 }
25413 return ngFactoryDef;
25414 },
25415 // Make the property configurable in dev mode to allow overriding in tests
25416 configurable: !!ngDevMode,
25417 });
25418 Object.defineProperty(type, NG_PIPE_DEF, {
25419 get: () => {
25420 if (ngPipeDef === null) {
25421 const metadata = getPipeMetadata(type, meta);
25422 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'pipe', type: metadata.type });
25423 ngPipeDef =
25424 compiler.compilePipe(angularCoreEnv, `ng:///${metadata.name}/ɵpipe.js`, metadata);
25425 }
25426 return ngPipeDef;
25427 },
25428 // Make the property configurable in dev mode to allow overriding in tests
25429 configurable: !!ngDevMode,
25430 });
25431}
25432function getPipeMetadata(type, meta) {
25433 return {
25434 type: type,
25435 name: type.name,
25436 pipeName: meta.name,
25437 pure: meta.pure !== undefined ? meta.pure : true,
25438 isStandalone: !!meta.standalone,
25439 };
25440}
25441
25442/**
25443 * @license
25444 * Copyright Google LLC All Rights Reserved.
25445 *
25446 * Use of this source code is governed by an MIT-style license that can be
25447 * found in the LICENSE file at https://angular.io/license
25448 */
25449/**
25450 * Type of the Directive metadata.
25451 *
25452 * @publicApi
25453 */
25454const Directive = makeDecorator('Directive', (dir = {}) => dir, undefined, undefined, (type, meta) => compileDirective(type, meta));
25455/**
25456 * Component decorator and metadata.
25457 *
25458 * @Annotation
25459 * @publicApi
25460 */
25461const Component = makeDecorator('Component', (c = {}) => (Object.assign({ changeDetection: ChangeDetectionStrategy.Default }, c)), Directive, undefined, (type, meta) => compileComponent(type, meta));
25462/**
25463 * @Annotation
25464 * @publicApi
25465 */
25466const Pipe = makeDecorator('Pipe', (p) => (Object.assign({ pure: true }, p)), undefined, undefined, (type, meta) => compilePipe(type, meta));
25467/**
25468 * @Annotation
25469 * @publicApi
25470 */
25471const Input = makePropDecorator('Input', (bindingPropertyName) => ({ bindingPropertyName }));
25472/**
25473 * @Annotation
25474 * @publicApi
25475 */
25476const Output = makePropDecorator('Output', (bindingPropertyName) => ({ bindingPropertyName }));
25477/**
25478 * @Annotation
25479 * @publicApi
25480 */
25481const HostBinding = makePropDecorator('HostBinding', (hostPropertyName) => ({ hostPropertyName }));
25482/**
25483 * Decorator that binds a DOM event to a host listener and supplies configuration metadata.
25484 * Angular invokes the supplied handler method when the host element emits the specified event,
25485 * and updates the bound element with the result.
25486 *
25487 * If the handler method returns false, applies `preventDefault` on the bound element.
25488 *
25489 * @usageNotes
25490 *
25491 * The following example declares a directive
25492 * that attaches a click listener to a button and counts clicks.
25493 *
25494 * ```ts
25495 * @Directive({selector: 'button[counting]'})
25496 * class CountClicks {
25497 * numberOfClicks = 0;
25498 *
25499 * @HostListener('click', ['$event.target'])
25500 * onClick(btn) {
25501 * console.log('button', btn, 'number of clicks:', this.numberOfClicks++);
25502 * }
25503 * }
25504 *
25505 * @Component({
25506 * selector: 'app',
25507 * template: '<button counting>Increment</button>',
25508 * })
25509 * class App {}
25510 *
25511 * ```
25512 *
25513 * The following example registers another DOM event handler that listens for `Enter` key-press
25514 * events on the global `window`.
25515 * ``` ts
25516 * import { HostListener, Component } from "@angular/core";
25517 *
25518 * @Component({
25519 * selector: 'app',
25520 * template: `<h1>Hello, you have pressed enter {{counter}} number of times!</h1> Press enter key
25521 * to increment the counter.
25522 * <button (click)="resetCounter()">Reset Counter</button>`
25523 * })
25524 * class AppComponent {
25525 * counter = 0;
25526 * @HostListener('window:keydown.enter', ['$event'])
25527 * handleKeyDown(event: KeyboardEvent) {
25528 * this.counter++;
25529 * }
25530 * resetCounter() {
25531 * this.counter = 0;
25532 * }
25533 * }
25534 * ```
25535 * The list of valid key names for `keydown` and `keyup` events
25536 * can be found here:
25537 * https://www.w3.org/TR/DOM-Level-3-Events-key/#named-key-attribute-values
25538 *
25539 * Note that keys can also be combined, e.g. `@HostListener('keydown.shift.a')`.
25540 *
25541 * The global target names that can be used to prefix an event name are
25542 * `document:`, `window:` and `body:`.
25543 *
25544 * @Annotation
25545 * @publicApi
25546 */
25547const HostListener = makePropDecorator('HostListener', (eventName, args) => ({ eventName, args }));
25548
25549/**
25550 * @license
25551 * Copyright Google LLC All Rights Reserved.
25552 *
25553 * Use of this source code is governed by an MIT-style license that can be
25554 * found in the LICENSE file at https://angular.io/license
25555 */
25556/**
25557 * @Annotation
25558 * @publicApi
25559 */
25560const NgModule = makeDecorator('NgModule', (ngModule) => ngModule, undefined, undefined,
25561/**
25562 * Decorator that marks the following class as an NgModule, and supplies
25563 * configuration metadata for it.
25564 *
25565 * * The `declarations` and `entryComponents` options configure the compiler
25566 * with information about what belongs to the NgModule.
25567 * * The `providers` options configures the NgModule's injector to provide
25568 * dependencies the NgModule members.
25569 * * The `imports` and `exports` options bring in members from other modules, and make
25570 * this module's members available to others.
25571 */
25572(type, meta) => compileNgModule(type, meta));
25573
25574/**
25575 * @license
25576 * Copyright Google LLC All Rights Reserved.
25577 *
25578 * Use of this source code is governed by an MIT-style license that can be
25579 * found in the LICENSE file at https://angular.io/license
25580 */
25581
25582/**
25583 * @license
25584 * Copyright Google LLC All Rights Reserved.
25585 *
25586 * Use of this source code is governed by an MIT-style license that can be
25587 * found in the LICENSE file at https://angular.io/license
25588 */
25589function noop(...args) {
25590 // Do nothing.
25591}
25592
25593/**
25594 * @license
25595 * Copyright Google LLC All Rights Reserved.
25596 *
25597 * Use of this source code is governed by an MIT-style license that can be
25598 * found in the LICENSE file at https://angular.io/license
25599 */
25600/**
25601 * The existence of this constant (in this particular file) informs the Angular compiler that the
25602 * current program is actually @angular/core, which needs to be compiled specially.
25603 */
25604const ITS_JUST_ANGULAR = true;
25605
25606/**
25607 * A [DI token](guide/glossary#di-token "DI token definition") that you can use to provide
25608 * one or more initialization functions.
25609 *
25610 * The provided functions are injected at application startup and executed during
25611 * app initialization. If any of these functions returns a Promise or an Observable, initialization
25612 * does not complete until the Promise is resolved or the Observable is completed.
25613 *
25614 * You can, for example, create a factory function that loads language data
25615 * or an external configuration, and provide that function to the `APP_INITIALIZER` token.
25616 * The function is executed during the application bootstrap process,
25617 * and the needed data is available on startup.
25618 *
25619 * @see `ApplicationInitStatus`
25620 *
25621 * @usageNotes
25622 *
25623 * The following example illustrates how to configure a multi-provider using `APP_INITIALIZER` token
25624 * and a function returning a promise.
25625 *
25626 * ```
25627 * function initializeApp(): Promise<any> {
25628 * return new Promise((resolve, reject) => {
25629 * // Do some asynchronous stuff
25630 * resolve();
25631 * });
25632 * }
25633 *
25634 * @NgModule({
25635 * imports: [BrowserModule],
25636 * declarations: [AppComponent],
25637 * bootstrap: [AppComponent],
25638 * providers: [{
25639 * provide: APP_INITIALIZER,
25640 * useFactory: () => initializeApp,
25641 * multi: true
25642 * }]
25643 * })
25644 * export class AppModule {}
25645 * ```
25646 *
25647 * It's also possible to configure a multi-provider using `APP_INITIALIZER` token and a function
25648 * returning an observable, see an example below. Note: the `HttpClient` in this example is used for
25649 * demo purposes to illustrate how the factory function can work with other providers available
25650 * through DI.
25651 *
25652 * ```
25653 * function initializeAppFactory(httpClient: HttpClient): () => Observable<any> {
25654 * return () => httpClient.get("https://someUrl.com/api/user")
25655 * .pipe(
25656 * tap(user => { ... })
25657 * );
25658 * }
25659 *
25660 * @NgModule({
25661 * imports: [BrowserModule, HttpClientModule],
25662 * declarations: [AppComponent],
25663 * bootstrap: [AppComponent],
25664 * providers: [{
25665 * provide: APP_INITIALIZER,
25666 * useFactory: initializeAppFactory,
25667 * deps: [HttpClient],
25668 * multi: true
25669 * }]
25670 * })
25671 * export class AppModule {}
25672 * ```
25673 *
25674 * @publicApi
25675 */
25676const APP_INITIALIZER = new InjectionToken('Application Initializer');
25677/**
25678 * A class that reflects the state of running {@link APP_INITIALIZER} functions.
25679 *
25680 * @publicApi
25681 */
25682class ApplicationInitStatus {
25683 constructor(appInits) {
25684 this.appInits = appInits;
25685 this.resolve = noop;
25686 this.reject = noop;
25687 this.initialized = false;
25688 this.done = false;
25689 this.donePromise = new Promise((res, rej) => {
25690 this.resolve = res;
25691 this.reject = rej;
25692 });
25693 }
25694 /** @internal */
25695 runInitializers() {
25696 if (this.initialized) {
25697 return;
25698 }
25699 const asyncInitPromises = [];
25700 const complete = () => {
25701 this.done = true;
25702 this.resolve();
25703 };
25704 if (this.appInits) {
25705 for (let i = 0; i < this.appInits.length; i++) {
25706 const initResult = this.appInits[i]();
25707 if (isPromise(initResult)) {
25708 asyncInitPromises.push(initResult);
25709 }
25710 else if (isObservable(initResult)) {
25711 const observableAsPromise = new Promise((resolve, reject) => {
25712 initResult.subscribe({ complete: resolve, error: reject });
25713 });
25714 asyncInitPromises.push(observableAsPromise);
25715 }
25716 }
25717 }
25718 Promise.all(asyncInitPromises)
25719 .then(() => {
25720 complete();
25721 })
25722 .catch(e => {
25723 this.reject(e);
25724 });
25725 if (asyncInitPromises.length === 0) {
25726 complete();
25727 }
25728 this.initialized = true;
25729 }
25730}
25731ApplicationInitStatus.ɵfac = function ApplicationInitStatus_Factory(t) { return new (t || ApplicationInitStatus)(ɵɵinject(APP_INITIALIZER, 8)); };
25732ApplicationInitStatus.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationInitStatus, factory: ApplicationInitStatus.ɵfac, providedIn: 'root' });
25733(function () {
25734 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
25735 type: Injectable,
25736 args: [{ providedIn: 'root' }]
25737 }], function () {
25738 return [{ type: undefined, decorators: [{
25739 type: Inject,
25740 args: [APP_INITIALIZER]
25741 }, {
25742 type: Optional
25743 }] }];
25744 }, null);
25745})();
25746
25747/**
25748 * @license
25749 * Copyright Google LLC All Rights Reserved.
25750 *
25751 * Use of this source code is governed by an MIT-style license that can be
25752 * found in the LICENSE file at https://angular.io/license
25753 */
25754/**
25755 * A [DI token](guide/glossary#di-token "DI token definition") representing a unique string ID, used
25756 * primarily for prefixing application attributes and CSS styles when
25757 * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used.
25758 *
25759 * BY default, the value is randomly generated and assigned to the application by Angular.
25760 * To provide a custom ID value, use a DI provider <!-- TODO: provider --> to configure
25761 * the root {@link Injector} that uses this token.
25762 *
25763 * @publicApi
25764 */
25765const APP_ID = new InjectionToken('AppId', {
25766 providedIn: 'root',
25767 factory: _appIdRandomProviderFactory,
25768});
25769function _appIdRandomProviderFactory() {
25770 return `${_randomChar()}${_randomChar()}${_randomChar()}`;
25771}
25772/**
25773 * Providers that generate a random `APP_ID_TOKEN`.
25774 * @publicApi
25775 */
25776const APP_ID_RANDOM_PROVIDER = {
25777 provide: APP_ID,
25778 useFactory: _appIdRandomProviderFactory,
25779 deps: [],
25780};
25781function _randomChar() {
25782 return String.fromCharCode(97 + Math.floor(Math.random() * 25));
25783}
25784/**
25785 * A function that is executed when a platform is initialized.
25786 * @publicApi
25787 */
25788const PLATFORM_INITIALIZER = new InjectionToken('Platform Initializer');
25789/**
25790 * A token that indicates an opaque platform ID.
25791 * @publicApi
25792 */
25793const PLATFORM_ID = new InjectionToken('Platform ID', {
25794 providedIn: 'platform',
25795 factory: () => 'unknown', // set a default platform name, when none set explicitly
25796});
25797/**
25798 * A [DI token](guide/glossary#di-token "DI token definition") that provides a set of callbacks to
25799 * be called for every component that is bootstrapped.
25800 *
25801 * Each callback must take a `ComponentRef` instance and return nothing.
25802 *
25803 * `(componentRef: ComponentRef) => void`
25804 *
25805 * @publicApi
25806 */
25807const APP_BOOTSTRAP_LISTENER = new InjectionToken('appBootstrapListener');
25808/**
25809 * A [DI token](guide/glossary#di-token "DI token definition") that indicates the root directory of
25810 * the application
25811 * @publicApi
25812 */
25813const PACKAGE_ROOT_URL = new InjectionToken('Application Packages Root URL');
25814// We keep this token here, rather than the animations package, so that modules that only care
25815// about which animations module is loaded (e.g. the CDK) can retrieve it without having to
25816// include extra dependencies. See #44970 for more context.
25817/**
25818 * A [DI token](guide/glossary#di-token "DI token definition") that indicates which animations
25819 * module has been loaded.
25820 * @publicApi
25821 */
25822const ANIMATION_MODULE_TYPE = new InjectionToken('AnimationModuleType');
25823
25824/**
25825 * @license
25826 * Copyright Google LLC All Rights Reserved.
25827 *
25828 * Use of this source code is governed by an MIT-style license that can be
25829 * found in the LICENSE file at https://angular.io/license
25830 */
25831class Console {
25832 log(message) {
25833 // tslint:disable-next-line:no-console
25834 console.log(message);
25835 }
25836 // Note: for reporting errors use `DOM.logError()` as it is platform specific
25837 warn(message) {
25838 // tslint:disable-next-line:no-console
25839 console.warn(message);
25840 }
25841}
25842Console.ɵfac = function Console_Factory(t) { return new (t || Console)(); };
25843Console.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Console, factory: Console.ɵfac, providedIn: 'platform' });
25844(function () {
25845 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Console, [{
25846 type: Injectable,
25847 args: [{ providedIn: 'platform' }]
25848 }], null, null);
25849})();
25850
25851/**
25852 * @license
25853 * Copyright Google LLC All Rights Reserved.
25854 *
25855 * Use of this source code is governed by an MIT-style license that can be
25856 * found in the LICENSE file at https://angular.io/license
25857 */
25858/**
25859 * Work out the locale from the potential global properties.
25860 *
25861 * * Closure Compiler: use `goog.LOCALE`.
25862 * * Ivy enabled: use `$localize.locale`
25863 */
25864function getGlobalLocale() {
25865 if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
25866 typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
25867 // * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
25868 // * In order to preserve backwards compatibility, we use Angular default value over
25869 // Closure Compiler's one.
25870 return goog.LOCALE;
25871 }
25872 else {
25873 // KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
25874 // COMPILE-TIME INLINER.
25875 //
25876 // * During compile time inlining of translations the expression will be replaced
25877 // with a string literal that is the current locale. Other forms of this expression are not
25878 // guaranteed to be replaced.
25879 //
25880 // * During runtime translation evaluation, the developer is required to set `$localize.locale`
25881 // if required, or just to provide their own `LOCALE_ID` provider.
25882 return (typeof $localize !== 'undefined' && $localize.locale) || DEFAULT_LOCALE_ID;
25883 }
25884}
25885/**
25886 * Provide this token to set the locale of your application.
25887 * It is used for i18n extraction, by i18n pipes (DatePipe, I18nPluralPipe, CurrencyPipe,
25888 * DecimalPipe and PercentPipe) and by ICU expressions.
25889 *
25890 * See the [i18n guide](guide/i18n-common-locale-id) for more information.
25891 *
25892 * @usageNotes
25893 * ### Example
25894 *
25895 * ```typescript
25896 * import { LOCALE_ID } from '@angular/core';
25897 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25898 * import { AppModule } from './app/app.module';
25899 *
25900 * platformBrowserDynamic().bootstrapModule(AppModule, {
25901 * providers: [{provide: LOCALE_ID, useValue: 'en-US' }]
25902 * });
25903 * ```
25904 *
25905 * @publicApi
25906 */
25907const LOCALE_ID = new InjectionToken('LocaleId', {
25908 providedIn: 'root',
25909 factory: () => inject(LOCALE_ID, InjectFlags.Optional | InjectFlags.SkipSelf) || getGlobalLocale(),
25910});
25911/**
25912 * Provide this token to set the default currency code your application uses for
25913 * CurrencyPipe when there is no currency code passed into it. This is only used by
25914 * CurrencyPipe and has no relation to locale currency. Defaults to USD if not configured.
25915 *
25916 * See the [i18n guide](guide/i18n-common-locale-id) for more information.
25917 *
25918 * <div class="alert is-helpful">
25919 *
25920 * **Deprecation notice:**
25921 *
25922 * The default currency code is currently always `USD` but this is deprecated from v9.
25923 *
25924 * **In v10 the default currency code will be taken from the current locale.**
25925 *
25926 * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in
25927 * your application `NgModule`:
25928 *
25929 * ```ts
25930 * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
25931 * ```
25932 *
25933 * </div>
25934 *
25935 * @usageNotes
25936 * ### Example
25937 *
25938 * ```typescript
25939 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25940 * import { AppModule } from './app/app.module';
25941 *
25942 * platformBrowserDynamic().bootstrapModule(AppModule, {
25943 * providers: [{provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' }]
25944 * });
25945 * ```
25946 *
25947 * @publicApi
25948 */
25949const DEFAULT_CURRENCY_CODE = new InjectionToken('DefaultCurrencyCode', {
25950 providedIn: 'root',
25951 factory: () => USD_CURRENCY_CODE,
25952});
25953/**
25954 * Use this token at bootstrap to provide the content of your translation file (`xtb`,
25955 * `xlf` or `xlf2`) when you want to translate your application in another language.
25956 *
25957 * See the [i18n guide](guide/i18n-common-merge) for more information.
25958 *
25959 * @usageNotes
25960 * ### Example
25961 *
25962 * ```typescript
25963 * import { TRANSLATIONS } from '@angular/core';
25964 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25965 * import { AppModule } from './app/app.module';
25966 *
25967 * // content of your translation file
25968 * const translations = '....';
25969 *
25970 * platformBrowserDynamic().bootstrapModule(AppModule, {
25971 * providers: [{provide: TRANSLATIONS, useValue: translations }]
25972 * });
25973 * ```
25974 *
25975 * @publicApi
25976 */
25977const TRANSLATIONS = new InjectionToken('Translations');
25978/**
25979 * Provide this token at bootstrap to set the format of your {@link TRANSLATIONS}: `xtb`,
25980 * `xlf` or `xlf2`.
25981 *
25982 * See the [i18n guide](guide/i18n-common-merge) for more information.
25983 *
25984 * @usageNotes
25985 * ### Example
25986 *
25987 * ```typescript
25988 * import { TRANSLATIONS_FORMAT } from '@angular/core';
25989 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25990 * import { AppModule } from './app/app.module';
25991 *
25992 * platformBrowserDynamic().bootstrapModule(AppModule, {
25993 * providers: [{provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }]
25994 * });
25995 * ```
25996 *
25997 * @publicApi
25998 */
25999const TRANSLATIONS_FORMAT = new InjectionToken('TranslationsFormat');
26000/**
26001 * Use this enum at bootstrap as an option of `bootstrapModule` to define the strategy
26002 * that the compiler should use in case of missing translations:
26003 * - Error: throw if you have missing translations.
26004 * - Warning (default): show a warning in the console and/or shell.
26005 * - Ignore: do nothing.
26006 *
26007 * See the [i18n guide](guide/i18n-common-merge#report-missing-translations) for more information.
26008 *
26009 * @usageNotes
26010 * ### Example
26011 * ```typescript
26012 * import { MissingTranslationStrategy } from '@angular/core';
26013 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
26014 * import { AppModule } from './app/app.module';
26015 *
26016 * platformBrowserDynamic().bootstrapModule(AppModule, {
26017 * missingTranslation: MissingTranslationStrategy.Error
26018 * });
26019 * ```
26020 *
26021 * @publicApi
26022 */
26023var MissingTranslationStrategy;
26024(function (MissingTranslationStrategy) {
26025 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
26026 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
26027 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
26028})(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
26029
26030/**
26031 * @license
26032 * Copyright Google LLC All Rights Reserved.
26033 *
26034 * Use of this source code is governed by an MIT-style license that can be
26035 * found in the LICENSE file at https://angular.io/license
26036 */
26037/**
26038 * Combination of NgModuleFactory and ComponentFactories.
26039 *
26040 * @publicApi
26041 *
26042 * @deprecated
26043 * Ivy JIT mode doesn't require accessing this symbol.
26044 * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
26045 * additional context.
26046 */
26047class ModuleWithComponentFactories {
26048 constructor(ngModuleFactory, componentFactories) {
26049 this.ngModuleFactory = ngModuleFactory;
26050 this.componentFactories = componentFactories;
26051 }
26052}
26053/**
26054 * Low-level service for running the angular compiler during runtime
26055 * to create {@link ComponentFactory}s, which
26056 * can later be used to create and render a Component instance.
26057 *
26058 * Each `@NgModule` provides an own `Compiler` to its injector,
26059 * that will use the directives/pipes of the ng module for compilation
26060 * of components.
26061 *
26062 * @publicApi
26063 *
26064 * @deprecated
26065 * Ivy JIT mode doesn't require accessing this symbol.
26066 * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
26067 * additional context.
26068 */
26069class Compiler {
26070 /**
26071 * Compiles the given NgModule and all of its components. All templates of the components listed
26072 * in `entryComponents` have to be inlined.
26073 */
26074 compileModuleSync(moduleType) {
26075 return new NgModuleFactory(moduleType);
26076 }
26077 /**
26078 * Compiles the given NgModule and all of its components
26079 */
26080 compileModuleAsync(moduleType) {
26081 return Promise.resolve(this.compileModuleSync(moduleType));
26082 }
26083 /**
26084 * Same as {@link #compileModuleSync} but also creates ComponentFactories for all components.
26085 */
26086 compileModuleAndAllComponentsSync(moduleType) {
26087 const ngModuleFactory = this.compileModuleSync(moduleType);
26088 const moduleDef = getNgModuleDef(moduleType);
26089 const componentFactories = maybeUnwrapFn(moduleDef.declarations)
26090 .reduce((factories, declaration) => {
26091 const componentDef = getComponentDef(declaration);
26092 componentDef && factories.push(new ComponentFactory(componentDef));
26093 return factories;
26094 }, []);
26095 return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
26096 }
26097 /**
26098 * Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components.
26099 */
26100 compileModuleAndAllComponentsAsync(moduleType) {
26101 return Promise.resolve(this.compileModuleAndAllComponentsSync(moduleType));
26102 }
26103 /**
26104 * Clears all caches.
26105 */
26106 clearCache() { }
26107 /**
26108 * Clears the cache for the given component/ngModule.
26109 */
26110 clearCacheFor(type) { }
26111 /**
26112 * Returns the id for a given NgModule, if one is defined and known to the compiler.
26113 */
26114 getModuleId(moduleType) {
26115 return undefined;
26116 }
26117}
26118Compiler.ɵfac = function Compiler_Factory(t) { return new (t || Compiler)(); };
26119Compiler.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Compiler, factory: Compiler.ɵfac, providedIn: 'root' });
26120(function () {
26121 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Compiler, [{
26122 type: Injectable,
26123 args: [{ providedIn: 'root' }]
26124 }], null, null);
26125})();
26126/**
26127 * Token to provide CompilerOptions in the platform injector.
26128 *
26129 * @publicApi
26130 */
26131const COMPILER_OPTIONS = new InjectionToken('compilerOptions');
26132/**
26133 * A factory for creating a Compiler
26134 *
26135 * @publicApi
26136 *
26137 * @deprecated
26138 * Ivy JIT mode doesn't require accessing this symbol.
26139 * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
26140 * additional context.
26141 */
26142class CompilerFactory {
26143}
26144
26145/**
26146 * @license
26147 * Copyright Google LLC All Rights Reserved.
26148 *
26149 * Use of this source code is governed by an MIT-style license that can be
26150 * found in the LICENSE file at https://angular.io/license
26151 */
26152const promise = (() => Promise.resolve(0))();
26153function scheduleMicroTask(fn) {
26154 if (typeof Zone === 'undefined') {
26155 // use promise to schedule microTask instead of use Zone
26156 promise.then(() => {
26157 fn && fn.apply(null, null);
26158 });
26159 }
26160 else {
26161 Zone.current.scheduleMicroTask('scheduleMicrotask', fn);
26162 }
26163}
26164
26165/**
26166 * @license
26167 * Copyright Google LLC All Rights Reserved.
26168 *
26169 * Use of this source code is governed by an MIT-style license that can be
26170 * found in the LICENSE file at https://angular.io/license
26171 */
26172function getNativeRequestAnimationFrame() {
26173 let nativeRequestAnimationFrame = _global['requestAnimationFrame'];
26174 let nativeCancelAnimationFrame = _global['cancelAnimationFrame'];
26175 if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
26176 // use unpatched version of requestAnimationFrame(native delegate) if possible
26177 // to avoid another Change detection
26178 const unpatchedRequestAnimationFrame = nativeRequestAnimationFrame[Zone.__symbol__('OriginalDelegate')];
26179 if (unpatchedRequestAnimationFrame) {
26180 nativeRequestAnimationFrame = unpatchedRequestAnimationFrame;
26181 }
26182 const unpatchedCancelAnimationFrame = nativeCancelAnimationFrame[Zone.__symbol__('OriginalDelegate')];
26183 if (unpatchedCancelAnimationFrame) {
26184 nativeCancelAnimationFrame = unpatchedCancelAnimationFrame;
26185 }
26186 }
26187 return { nativeRequestAnimationFrame, nativeCancelAnimationFrame };
26188}
26189
26190/**
26191 * @license
26192 * Copyright Google LLC All Rights Reserved.
26193 *
26194 * Use of this source code is governed by an MIT-style license that can be
26195 * found in the LICENSE file at https://angular.io/license
26196 */
26197/**
26198 * An injectable service for executing work inside or outside of the Angular zone.
26199 *
26200 * The most common use of this service is to optimize performance when starting a work consisting of
26201 * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
26202 * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
26203 * can reenter the Angular zone via {@link #run}.
26204 *
26205 * <!-- TODO: add/fix links to:
26206 * - docs explaining zones and the use of zones in Angular and change-detection
26207 * - link to runOutsideAngular/run (throughout this file!)
26208 * -->
26209 *
26210 * @usageNotes
26211 * ### Example
26212 *
26213 * ```
26214 * import {Component, NgZone} from '@angular/core';
26215 * import {NgIf} from '@angular/common';
26216 *
26217 * @Component({
26218 * selector: 'ng-zone-demo',
26219 * template: `
26220 * <h2>Demo: NgZone</h2>
26221 *
26222 * <p>Progress: {{progress}}%</p>
26223 * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
26224 *
26225 * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
26226 * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
26227 * `,
26228 * })
26229 * export class NgZoneDemo {
26230 * progress: number = 0;
26231 * label: string;
26232 *
26233 * constructor(private _ngZone: NgZone) {}
26234 *
26235 * // Loop inside the Angular zone
26236 * // so the UI DOES refresh after each setTimeout cycle
26237 * processWithinAngularZone() {
26238 * this.label = 'inside';
26239 * this.progress = 0;
26240 * this._increaseProgress(() => console.log('Inside Done!'));
26241 * }
26242 *
26243 * // Loop outside of the Angular zone
26244 * // so the UI DOES NOT refresh after each setTimeout cycle
26245 * processOutsideOfAngularZone() {
26246 * this.label = 'outside';
26247 * this.progress = 0;
26248 * this._ngZone.runOutsideAngular(() => {
26249 * this._increaseProgress(() => {
26250 * // reenter the Angular zone and display done
26251 * this._ngZone.run(() => { console.log('Outside Done!'); });
26252 * });
26253 * });
26254 * }
26255 *
26256 * _increaseProgress(doneCallback: () => void) {
26257 * this.progress += 1;
26258 * console.log(`Current progress: ${this.progress}%`);
26259 *
26260 * if (this.progress < 100) {
26261 * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
26262 * } else {
26263 * doneCallback();
26264 * }
26265 * }
26266 * }
26267 * ```
26268 *
26269 * @publicApi
26270 */
26271class NgZone {
26272 constructor({ enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false }) {
26273 this.hasPendingMacrotasks = false;
26274 this.hasPendingMicrotasks = false;
26275 /**
26276 * Whether there are no outstanding microtasks or macrotasks.
26277 */
26278 this.isStable = true;
26279 /**
26280 * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
26281 */
26282 this.onUnstable = new EventEmitter(false);
26283 /**
26284 * Notifies when there is no more microtasks enqueued in the current VM Turn.
26285 * This is a hint for Angular to do change detection, which may enqueue more microtasks.
26286 * For this reason this event can fire multiple times per VM Turn.
26287 */
26288 this.onMicrotaskEmpty = new EventEmitter(false);
26289 /**
26290 * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
26291 * implies we are about to relinquish VM turn.
26292 * This event gets called just once.
26293 */
26294 this.onStable = new EventEmitter(false);
26295 /**
26296 * Notifies that an error has been delivered.
26297 */
26298 this.onError = new EventEmitter(false);
26299 if (typeof Zone == 'undefined') {
26300 throw new Error(`In this configuration Angular requires Zone.js`);
26301 }
26302 Zone.assertZonePatched();
26303 const self = this;
26304 self._nesting = 0;
26305 self._outer = self._inner = Zone.current;
26306 if (Zone['TaskTrackingZoneSpec']) {
26307 self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']);
26308 }
26309 if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
26310 self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
26311 }
26312 // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
26313 // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
26314 self.shouldCoalesceEventChangeDetection =
26315 !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
26316 self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
26317 self.lastRequestAnimationFrameId = -1;
26318 self.nativeRequestAnimationFrame = getNativeRequestAnimationFrame().nativeRequestAnimationFrame;
26319 forkInnerZoneWithAngularBehavior(self);
26320 }
26321 static isInAngularZone() {
26322 // Zone needs to be checked, because this method might be called even when NoopNgZone is used.
26323 return typeof Zone !== 'undefined' && Zone.current.get('isAngularZone') === true;
26324 }
26325 static assertInAngularZone() {
26326 if (!NgZone.isInAngularZone()) {
26327 throw new Error('Expected to be in Angular Zone, but it is not!');
26328 }
26329 }
26330 static assertNotInAngularZone() {
26331 if (NgZone.isInAngularZone()) {
26332 throw new Error('Expected to not be in Angular Zone, but it is!');
26333 }
26334 }
26335 /**
26336 * Executes the `fn` function synchronously within the Angular zone and returns value returned by
26337 * the function.
26338 *
26339 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
26340 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
26341 *
26342 * Any future tasks or microtasks scheduled from within this function will continue executing from
26343 * within the Angular zone.
26344 *
26345 * If a synchronous error happens it will be rethrown and not reported via `onError`.
26346 */
26347 run(fn, applyThis, applyArgs) {
26348 return this._inner.run(fn, applyThis, applyArgs);
26349 }
26350 /**
26351 * Executes the `fn` function synchronously within the Angular zone as a task and returns value
26352 * returned by the function.
26353 *
26354 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
26355 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
26356 *
26357 * Any future tasks or microtasks scheduled from within this function will continue executing from
26358 * within the Angular zone.
26359 *
26360 * If a synchronous error happens it will be rethrown and not reported via `onError`.
26361 */
26362 runTask(fn, applyThis, applyArgs, name) {
26363 const zone = this._inner;
26364 const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
26365 try {
26366 return zone.runTask(task, applyThis, applyArgs);
26367 }
26368 finally {
26369 zone.cancelTask(task);
26370 }
26371 }
26372 /**
26373 * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
26374 * rethrown.
26375 */
26376 runGuarded(fn, applyThis, applyArgs) {
26377 return this._inner.runGuarded(fn, applyThis, applyArgs);
26378 }
26379 /**
26380 * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
26381 * the function.
26382 *
26383 * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
26384 * work that
26385 * doesn't trigger Angular change-detection or is subject to Angular's error handling.
26386 *
26387 * Any future tasks or microtasks scheduled from within this function will continue executing from
26388 * outside of the Angular zone.
26389 *
26390 * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
26391 */
26392 runOutsideAngular(fn) {
26393 return this._outer.run(fn);
26394 }
26395}
26396const EMPTY_PAYLOAD = {};
26397function checkStable(zone) {
26398 // TODO: @JiaLiPassion, should check zone.isCheckStableRunning to prevent
26399 // re-entry. The case is:
26400 //
26401 // @Component({...})
26402 // export class AppComponent {
26403 // constructor(private ngZone: NgZone) {
26404 // this.ngZone.onStable.subscribe(() => {
26405 // this.ngZone.run(() => console.log('stable'););
26406 // });
26407 // }
26408 //
26409 // The onStable subscriber run another function inside ngZone
26410 // which causes `checkStable()` re-entry.
26411 // But this fix causes some issues in g3, so this fix will be
26412 // launched in another PR.
26413 if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
26414 try {
26415 zone._nesting++;
26416 zone.onMicrotaskEmpty.emit(null);
26417 }
26418 finally {
26419 zone._nesting--;
26420 if (!zone.hasPendingMicrotasks) {
26421 try {
26422 zone.runOutsideAngular(() => zone.onStable.emit(null));
26423 }
26424 finally {
26425 zone.isStable = true;
26426 }
26427 }
26428 }
26429 }
26430}
26431function delayChangeDetectionForEvents(zone) {
26432 /**
26433 * We also need to check _nesting here
26434 * Consider the following case with shouldCoalesceRunChangeDetection = true
26435 *
26436 * ngZone.run(() => {});
26437 * ngZone.run(() => {});
26438 *
26439 * We want the two `ngZone.run()` only trigger one change detection
26440 * when shouldCoalesceRunChangeDetection is true.
26441 * And because in this case, change detection run in async way(requestAnimationFrame),
26442 * so we also need to check the _nesting here to prevent multiple
26443 * change detections.
26444 */
26445 if (zone.isCheckStableRunning || zone.lastRequestAnimationFrameId !== -1) {
26446 return;
26447 }
26448 zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(_global, () => {
26449 // This is a work around for https://github.com/angular/angular/issues/36839.
26450 // The core issue is that when event coalescing is enabled it is possible for microtasks
26451 // to get flushed too early (As is the case with `Promise.then`) between the
26452 // coalescing eventTasks.
26453 //
26454 // To workaround this we schedule a "fake" eventTask before we process the
26455 // coalescing eventTasks. The benefit of this is that the "fake" container eventTask
26456 // will prevent the microtasks queue from getting drained in between the coalescing
26457 // eventTask execution.
26458 if (!zone.fakeTopEventTask) {
26459 zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
26460 zone.lastRequestAnimationFrameId = -1;
26461 updateMicroTaskStatus(zone);
26462 zone.isCheckStableRunning = true;
26463 checkStable(zone);
26464 zone.isCheckStableRunning = false;
26465 }, undefined, () => { }, () => { });
26466 }
26467 zone.fakeTopEventTask.invoke();
26468 });
26469 updateMicroTaskStatus(zone);
26470}
26471function forkInnerZoneWithAngularBehavior(zone) {
26472 const delayChangeDetectionForEventsDelegate = () => {
26473 delayChangeDetectionForEvents(zone);
26474 };
26475 zone._inner = zone._inner.fork({
26476 name: 'angular',
26477 properties: { 'isAngularZone': true },
26478 onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
26479 try {
26480 onEnter(zone);
26481 return delegate.invokeTask(target, task, applyThis, applyArgs);
26482 }
26483 finally {
26484 if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
26485 zone.shouldCoalesceRunChangeDetection) {
26486 delayChangeDetectionForEventsDelegate();
26487 }
26488 onLeave(zone);
26489 }
26490 },
26491 onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
26492 try {
26493 onEnter(zone);
26494 return delegate.invoke(target, callback, applyThis, applyArgs, source);
26495 }
26496 finally {
26497 if (zone.shouldCoalesceRunChangeDetection) {
26498 delayChangeDetectionForEventsDelegate();
26499 }
26500 onLeave(zone);
26501 }
26502 },
26503 onHasTask: (delegate, current, target, hasTaskState) => {
26504 delegate.hasTask(target, hasTaskState);
26505 if (current === target) {
26506 // We are only interested in hasTask events which originate from our zone
26507 // (A child hasTask event is not interesting to us)
26508 if (hasTaskState.change == 'microTask') {
26509 zone._hasPendingMicrotasks = hasTaskState.microTask;
26510 updateMicroTaskStatus(zone);
26511 checkStable(zone);
26512 }
26513 else if (hasTaskState.change == 'macroTask') {
26514 zone.hasPendingMacrotasks = hasTaskState.macroTask;
26515 }
26516 }
26517 },
26518 onHandleError: (delegate, current, target, error) => {
26519 delegate.handleError(target, error);
26520 zone.runOutsideAngular(() => zone.onError.emit(error));
26521 return false;
26522 }
26523 });
26524}
26525function updateMicroTaskStatus(zone) {
26526 if (zone._hasPendingMicrotasks ||
26527 ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
26528 zone.lastRequestAnimationFrameId !== -1)) {
26529 zone.hasPendingMicrotasks = true;
26530 }
26531 else {
26532 zone.hasPendingMicrotasks = false;
26533 }
26534}
26535function onEnter(zone) {
26536 zone._nesting++;
26537 if (zone.isStable) {
26538 zone.isStable = false;
26539 zone.onUnstable.emit(null);
26540 }
26541}
26542function onLeave(zone) {
26543 zone._nesting--;
26544 checkStable(zone);
26545}
26546/**
26547 * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
26548 * to framework to perform rendering.
26549 */
26550class NoopNgZone {
26551 constructor() {
26552 this.hasPendingMicrotasks = false;
26553 this.hasPendingMacrotasks = false;
26554 this.isStable = true;
26555 this.onUnstable = new EventEmitter();
26556 this.onMicrotaskEmpty = new EventEmitter();
26557 this.onStable = new EventEmitter();
26558 this.onError = new EventEmitter();
26559 }
26560 run(fn, applyThis, applyArgs) {
26561 return fn.apply(applyThis, applyArgs);
26562 }
26563 runGuarded(fn, applyThis, applyArgs) {
26564 return fn.apply(applyThis, applyArgs);
26565 }
26566 runOutsideAngular(fn) {
26567 return fn();
26568 }
26569 runTask(fn, applyThis, applyArgs, name) {
26570 return fn.apply(applyThis, applyArgs);
26571 }
26572}
26573
26574/**
26575 * @license
26576 * Copyright Google LLC All Rights Reserved.
26577 *
26578 * Use of this source code is governed by an MIT-style license that can be
26579 * found in the LICENSE file at https://angular.io/license
26580 */
26581/**
26582 * Internal injection token that can used to access an instance of a Testability class.
26583 *
26584 * This token acts as a bridge between the core bootstrap code and the `Testability` class. This is
26585 * needed to ensure that there are no direct references to the `Testability` class, so it can be
26586 * tree-shaken away (if not referenced). For the environments/setups when the `Testability` class
26587 * should be available, this token is used to add a provider that references the `Testability`
26588 * class. Otherwise, only this token is retained in a bundle, but the `Testability` class is not.
26589 */
26590const TESTABILITY = new InjectionToken('');
26591/**
26592 * Internal injection token to retrieve Testability getter class instance.
26593 */
26594const TESTABILITY_GETTER = new InjectionToken('');
26595/**
26596 * The Testability service provides testing hooks that can be accessed from
26597 * the browser.
26598 *
26599 * Angular applications bootstrapped using an NgModule (via `@NgModule.bootstrap` field) will also
26600 * instantiate Testability by default (in both development and production modes).
26601 *
26602 * For applications bootstrapped using the `bootstrapApplication` function, Testability is not
26603 * included by default. You can include it into your applications by getting the list of necessary
26604 * providers using the `provideProtractorTestingSupport()` function and adding them into the
26605 * `options.providers` array. Example:
26606 *
26607 * ```typescript
26608 * import {provideProtractorTestingSupport} from '@angular/platform-browser';
26609 *
26610 * await bootstrapApplication(RootComponent, providers: [provideProtractorTestingSupport()]);
26611 * ```
26612 *
26613 * @publicApi
26614 */
26615class Testability {
26616 constructor(_ngZone, registry, testabilityGetter) {
26617 this._ngZone = _ngZone;
26618 this.registry = registry;
26619 this._pendingCount = 0;
26620 this._isZoneStable = true;
26621 /**
26622 * Whether any work was done since the last 'whenStable' callback. This is
26623 * useful to detect if this could have potentially destabilized another
26624 * component while it is stabilizing.
26625 * @internal
26626 */
26627 this._didWork = false;
26628 this._callbacks = [];
26629 this.taskTrackingZone = null;
26630 // If there was no Testability logic registered in the global scope
26631 // before, register the current testability getter as a global one.
26632 if (!_testabilityGetter) {
26633 setTestabilityGetter(testabilityGetter);
26634 testabilityGetter.addToWindow(registry);
26635 }
26636 this._watchAngularEvents();
26637 _ngZone.run(() => {
26638 this.taskTrackingZone =
26639 typeof Zone == 'undefined' ? null : Zone.current.get('TaskTrackingZone');
26640 });
26641 }
26642 _watchAngularEvents() {
26643 this._ngZone.onUnstable.subscribe({
26644 next: () => {
26645 this._didWork = true;
26646 this._isZoneStable = false;
26647 }
26648 });
26649 this._ngZone.runOutsideAngular(() => {
26650 this._ngZone.onStable.subscribe({
26651 next: () => {
26652 NgZone.assertNotInAngularZone();
26653 scheduleMicroTask(() => {
26654 this._isZoneStable = true;
26655 this._runCallbacksIfReady();
26656 });
26657 }
26658 });
26659 });
26660 }
26661 /**
26662 * Increases the number of pending request
26663 * @deprecated pending requests are now tracked with zones.
26664 */
26665 increasePendingRequestCount() {
26666 this._pendingCount += 1;
26667 this._didWork = true;
26668 return this._pendingCount;
26669 }
26670 /**
26671 * Decreases the number of pending request
26672 * @deprecated pending requests are now tracked with zones
26673 */
26674 decreasePendingRequestCount() {
26675 this._pendingCount -= 1;
26676 if (this._pendingCount < 0) {
26677 throw new Error('pending async requests below zero');
26678 }
26679 this._runCallbacksIfReady();
26680 return this._pendingCount;
26681 }
26682 /**
26683 * Whether an associated application is stable
26684 */
26685 isStable() {
26686 return this._isZoneStable && this._pendingCount === 0 && !this._ngZone.hasPendingMacrotasks;
26687 }
26688 _runCallbacksIfReady() {
26689 if (this.isStable()) {
26690 // Schedules the call backs in a new frame so that it is always async.
26691 scheduleMicroTask(() => {
26692 while (this._callbacks.length !== 0) {
26693 let cb = this._callbacks.pop();
26694 clearTimeout(cb.timeoutId);
26695 cb.doneCb(this._didWork);
26696 }
26697 this._didWork = false;
26698 });
26699 }
26700 else {
26701 // Still not stable, send updates.
26702 let pending = this.getPendingTasks();
26703 this._callbacks = this._callbacks.filter((cb) => {
26704 if (cb.updateCb && cb.updateCb(pending)) {
26705 clearTimeout(cb.timeoutId);
26706 return false;
26707 }
26708 return true;
26709 });
26710 this._didWork = true;
26711 }
26712 }
26713 getPendingTasks() {
26714 if (!this.taskTrackingZone) {
26715 return [];
26716 }
26717 // Copy the tasks data so that we don't leak tasks.
26718 return this.taskTrackingZone.macroTasks.map((t) => {
26719 return {
26720 source: t.source,
26721 // From TaskTrackingZone:
26722 // https://github.com/angular/zone.js/blob/master/lib/zone-spec/task-tracking.ts#L40
26723 creationLocation: t.creationLocation,
26724 data: t.data
26725 };
26726 });
26727 }
26728 addCallback(cb, timeout, updateCb) {
26729 let timeoutId = -1;
26730 if (timeout && timeout > 0) {
26731 timeoutId = setTimeout(() => {
26732 this._callbacks = this._callbacks.filter((cb) => cb.timeoutId !== timeoutId);
26733 cb(this._didWork, this.getPendingTasks());
26734 }, timeout);
26735 }
26736 this._callbacks.push({ doneCb: cb, timeoutId: timeoutId, updateCb: updateCb });
26737 }
26738 /**
26739 * Wait for the application to be stable with a timeout. If the timeout is reached before that
26740 * happens, the callback receives a list of the macro tasks that were pending, otherwise null.
26741 *
26742 * @param doneCb The callback to invoke when Angular is stable or the timeout expires
26743 * whichever comes first.
26744 * @param timeout Optional. The maximum time to wait for Angular to become stable. If not
26745 * specified, whenStable() will wait forever.
26746 * @param updateCb Optional. If specified, this callback will be invoked whenever the set of
26747 * pending macrotasks changes. If this callback returns true doneCb will not be invoked
26748 * and no further updates will be issued.
26749 */
26750 whenStable(doneCb, timeout, updateCb) {
26751 if (updateCb && !this.taskTrackingZone) {
26752 throw new Error('Task tracking zone is required when passing an update callback to ' +
26753 'whenStable(). Is "zone.js/plugins/task-tracking" loaded?');
26754 }
26755 // These arguments are 'Function' above to keep the public API simple.
26756 this.addCallback(doneCb, timeout, updateCb);
26757 this._runCallbacksIfReady();
26758 }
26759 /**
26760 * Get the number of pending requests
26761 * @deprecated pending requests are now tracked with zones
26762 */
26763 getPendingRequestCount() {
26764 return this._pendingCount;
26765 }
26766 /**
26767 * Registers an application with a testability hook so that it can be tracked.
26768 * @param token token of application, root element
26769 *
26770 * @internal
26771 */
26772 registerApplication(token) {
26773 this.registry.registerApplication(token, this);
26774 }
26775 /**
26776 * Unregisters an application.
26777 * @param token token of application, root element
26778 *
26779 * @internal
26780 */
26781 unregisterApplication(token) {
26782 this.registry.unregisterApplication(token);
26783 }
26784 /**
26785 * Find providers by name
26786 * @param using The root element to search from
26787 * @param provider The name of binding variable
26788 * @param exactMatch Whether using exactMatch
26789 */
26790 findProviders(using, provider, exactMatch) {
26791 // TODO(juliemr): implement.
26792 return [];
26793 }
26794}
26795Testability.ɵfac = function Testability_Factory(t) { return new (t || Testability)(ɵɵinject(NgZone), ɵɵinject(TestabilityRegistry), ɵɵinject(TESTABILITY_GETTER)); };
26796Testability.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Testability, factory: Testability.ɵfac });
26797(function () {
26798 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Testability, [{
26799 type: Injectable
26800 }], function () {
26801 return [{ type: NgZone }, { type: TestabilityRegistry }, { type: undefined, decorators: [{
26802 type: Inject,
26803 args: [TESTABILITY_GETTER]
26804 }] }];
26805 }, null);
26806})();
26807/**
26808 * A global registry of {@link Testability} instances for specific elements.
26809 * @publicApi
26810 */
26811class TestabilityRegistry {
26812 constructor() {
26813 /** @internal */
26814 this._applications = new Map();
26815 }
26816 /**
26817 * Registers an application with a testability hook so that it can be tracked
26818 * @param token token of application, root element
26819 * @param testability Testability hook
26820 */
26821 registerApplication(token, testability) {
26822 this._applications.set(token, testability);
26823 }
26824 /**
26825 * Unregisters an application.
26826 * @param token token of application, root element
26827 */
26828 unregisterApplication(token) {
26829 this._applications.delete(token);
26830 }
26831 /**
26832 * Unregisters all applications
26833 */
26834 unregisterAllApplications() {
26835 this._applications.clear();
26836 }
26837 /**
26838 * Get a testability hook associated with the application
26839 * @param elem root element
26840 */
26841 getTestability(elem) {
26842 return this._applications.get(elem) || null;
26843 }
26844 /**
26845 * Get all registered testabilities
26846 */
26847 getAllTestabilities() {
26848 return Array.from(this._applications.values());
26849 }
26850 /**
26851 * Get all registered applications(root elements)
26852 */
26853 getAllRootElements() {
26854 return Array.from(this._applications.keys());
26855 }
26856 /**
26857 * Find testability of a node in the Tree
26858 * @param elem node
26859 * @param findInAncestors whether finding testability in ancestors if testability was not found in
26860 * current node
26861 */
26862 findTestabilityInTree(elem, findInAncestors = true) {
26863 var _a;
26864 return (_a = _testabilityGetter === null || _testabilityGetter === void 0 ? void 0 : _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors)) !== null && _a !== void 0 ? _a : null;
26865 }
26866}
26867TestabilityRegistry.ɵfac = function TestabilityRegistry_Factory(t) { return new (t || TestabilityRegistry)(); };
26868TestabilityRegistry.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: TestabilityRegistry, factory: TestabilityRegistry.ɵfac, providedIn: 'platform' });
26869(function () {
26870 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(TestabilityRegistry, [{
26871 type: Injectable,
26872 args: [{ providedIn: 'platform' }]
26873 }], null, null);
26874})();
26875/**
26876 * Set the {@link GetTestability} implementation used by the Angular testing framework.
26877 * @publicApi
26878 */
26879function setTestabilityGetter(getter) {
26880 _testabilityGetter = getter;
26881}
26882let _testabilityGetter;
26883
26884/**
26885 * @license
26886 * Copyright Google LLC All Rights Reserved.
26887 *
26888 * Use of this source code is governed by an MIT-style license that can be
26889 * found in the LICENSE file at https://angular.io/license
26890 */
26891let _platformInjector = null;
26892/**
26893 * Internal token to indicate whether having multiple bootstrapped platform should be allowed (only
26894 * one bootstrapped platform is allowed by default). This token helps to support SSR scenarios.
26895 */
26896const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken');
26897/**
26898 * Internal token that allows to register extra callbacks that should be invoked during the
26899 * `PlatformRef.destroy` operation. This token is needed to avoid a direct reference to the
26900 * `PlatformRef` class (i.e. register the callback via `PlatformRef.onDestroy`), thus making the
26901 * entire class tree-shakeable.
26902 */
26903const PLATFORM_ON_DESTROY = new InjectionToken('PlatformOnDestroy');
26904const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;
26905function compileNgModuleFactory(injector, options, moduleType) {
26906 ngDevMode && assertNgModuleType(moduleType);
26907 const moduleFactory = new NgModuleFactory(moduleType);
26908 // All of the logic below is irrelevant for AOT-compiled code.
26909 if (typeof ngJitMode !== 'undefined' && !ngJitMode) {
26910 return Promise.resolve(moduleFactory);
26911 }
26912 const compilerOptions = injector.get(COMPILER_OPTIONS, []).concat(options);
26913 // Configure the compiler to use the provided options. This call may fail when multiple modules
26914 // are bootstrapped with incompatible options, as a component can only be compiled according to
26915 // a single set of options.
26916 setJitOptions({
26917 defaultEncapsulation: _lastDefined(compilerOptions.map(opts => opts.defaultEncapsulation)),
26918 preserveWhitespaces: _lastDefined(compilerOptions.map(opts => opts.preserveWhitespaces)),
26919 });
26920 if (isComponentResourceResolutionQueueEmpty()) {
26921 return Promise.resolve(moduleFactory);
26922 }
26923 const compilerProviders = _mergeArrays(compilerOptions.map(o => o.providers));
26924 // In case there are no compiler providers, we just return the module factory as
26925 // there won't be any resource loader. This can happen with Ivy, because AOT compiled
26926 // modules can be still passed through "bootstrapModule". In that case we shouldn't
26927 // unnecessarily require the JIT compiler.
26928 if (compilerProviders.length === 0) {
26929 return Promise.resolve(moduleFactory);
26930 }
26931 const compiler = getCompilerFacade({
26932 usage: 0 /* JitCompilerUsage.Decorator */,
26933 kind: 'NgModule',
26934 type: moduleType,
26935 });
26936 const compilerInjector = Injector.create({ providers: compilerProviders });
26937 const resourceLoader = compilerInjector.get(compiler.ResourceLoader);
26938 // The resource loader can also return a string while the "resolveComponentResources"
26939 // always expects a promise. Therefore we need to wrap the returned value in a promise.
26940 return resolveComponentResources(url => Promise.resolve(resourceLoader.get(url)))
26941 .then(() => moduleFactory);
26942}
26943function publishDefaultGlobalUtils() {
26944 ngDevMode && publishDefaultGlobalUtils$1();
26945}
26946function isBoundToModule(cf) {
26947 return cf.isBoundToModule;
26948}
26949/**
26950 * A token for third-party components that can register themselves with NgProbe.
26951 *
26952 * @publicApi
26953 */
26954class NgProbeToken {
26955 constructor(name, token) {
26956 this.name = name;
26957 this.token = token;
26958 }
26959}
26960/**
26961 * Creates a platform.
26962 * Platforms must be created on launch using this function.
26963 *
26964 * @publicApi
26965 */
26966function createPlatform(injector) {
26967 if (_platformInjector && !_platformInjector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
26968 throw new RuntimeError(400 /* RuntimeErrorCode.MULTIPLE_PLATFORMS */, ngDevMode &&
26969 'There can be only one platform. Destroy the previous one to create a new one.');
26970 }
26971 publishDefaultGlobalUtils();
26972 _platformInjector = injector;
26973 const platform = injector.get(PlatformRef);
26974 runPlatformInitializers(injector);
26975 return platform;
26976}
26977/**
26978 * The goal of this function is to bootstrap a platform injector,
26979 * but avoid referencing `PlatformRef` class.
26980 * This function is needed for bootstrapping a Standalone Component.
26981 */
26982function createOrReusePlatformInjector(providers = []) {
26983 // If a platform injector already exists, it means that the platform
26984 // is already bootstrapped and no additional actions are required.
26985 if (_platformInjector)
26986 return _platformInjector;
26987 // Otherwise, setup a new platform injector and run platform initializers.
26988 const injector = createPlatformInjector(providers);
26989 _platformInjector = injector;
26990 publishDefaultGlobalUtils();
26991 runPlatformInitializers(injector);
26992 return injector;
26993}
26994function runPlatformInitializers(injector) {
26995 const inits = injector.get(PLATFORM_INITIALIZER, null);
26996 if (inits) {
26997 inits.forEach((init) => init());
26998 }
26999}
27000/**
27001 * Internal bootstrap application API that implements the core bootstrap logic.
27002 *
27003 * Platforms (such as `platform-browser`) may require different set of application and platform
27004 * providers for an application to function correctly. As a result, platforms may use this function
27005 * internally and supply the necessary providers during the bootstrap, while exposing
27006 * platform-specific APIs as a part of their public API.
27007 *
27008 * @returns A promise that returns an `ApplicationRef` instance once resolved.
27009 */
27010function internalBootstrapApplication(config) {
27011 const { rootComponent, appProviders, platformProviders } = config;
27012 NG_DEV_MODE && assertStandaloneComponentType(rootComponent);
27013 const platformInjector = createOrReusePlatformInjector(platformProviders);
27014 const ngZone = new NgZone(getNgZoneOptions());
27015 return ngZone.run(() => {
27016 // Create root application injector based on a set of providers configured at the platform
27017 // bootstrap level as well as providers passed to the bootstrap call by a user.
27018 const allAppProviders = [
27019 { provide: NgZone, useValue: ngZone },
27020 ...(appProviders || []), //
27021 ];
27022 const appInjector = createEnvironmentInjector(allAppProviders, platformInjector, 'Environment Injector');
27023 const exceptionHandler = appInjector.get(ErrorHandler, null);
27024 if (NG_DEV_MODE && !exceptionHandler) {
27025 throw new RuntimeError(402 /* RuntimeErrorCode.ERROR_HANDLER_NOT_FOUND */, 'No `ErrorHandler` found in the Dependency Injection tree.');
27026 }
27027 let onErrorSubscription;
27028 ngZone.runOutsideAngular(() => {
27029 onErrorSubscription = ngZone.onError.subscribe({
27030 next: (error) => {
27031 exceptionHandler.handleError(error);
27032 }
27033 });
27034 });
27035 return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
27036 const initStatus = appInjector.get(ApplicationInitStatus);
27037 initStatus.runInitializers();
27038 return initStatus.donePromise.then(() => {
27039 const localeId = appInjector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
27040 setLocaleId(localeId || DEFAULT_LOCALE_ID);
27041 const appRef = appInjector.get(ApplicationRef);
27042 appRef.onDestroy(() => onErrorSubscription.unsubscribe());
27043 appRef.bootstrap(rootComponent);
27044 return appRef;
27045 });
27046 });
27047 });
27048}
27049/**
27050 * Creates a factory for a platform. Can be used to provide or override `Providers` specific to
27051 * your application's runtime needs, such as `PLATFORM_INITIALIZER` and `PLATFORM_ID`.
27052 * @param parentPlatformFactory Another platform factory to modify. Allows you to compose factories
27053 * to build up configurations that might be required by different libraries or parts of the
27054 * application.
27055 * @param name Identifies the new platform factory.
27056 * @param providers A set of dependency providers for platforms created with the new factory.
27057 *
27058 * @publicApi
27059 */
27060function createPlatformFactory(parentPlatformFactory, name, providers = []) {
27061 const desc = `Platform: ${name}`;
27062 const marker = new InjectionToken(desc);
27063 return (extraProviders = []) => {
27064 let platform = getPlatform();
27065 if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
27066 const platformProviders = [
27067 ...providers,
27068 ...extraProviders,
27069 { provide: marker, useValue: true }
27070 ];
27071 if (parentPlatformFactory) {
27072 parentPlatformFactory(platformProviders);
27073 }
27074 else {
27075 createPlatform(createPlatformInjector(platformProviders, desc));
27076 }
27077 }
27078 return assertPlatform(marker);
27079 };
27080}
27081/**
27082 * Checks that there is currently a platform that contains the given token as a provider.
27083 *
27084 * @publicApi
27085 */
27086function assertPlatform(requiredToken) {
27087 const platform = getPlatform();
27088 if (!platform) {
27089 throw new RuntimeError(401 /* RuntimeErrorCode.PLATFORM_NOT_FOUND */, ngDevMode && 'No platform exists!');
27090 }
27091 if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
27092 !platform.injector.get(requiredToken, null)) {
27093 throw new RuntimeError(400 /* RuntimeErrorCode.MULTIPLE_PLATFORMS */, 'A platform with a different configuration has been created. Please destroy it first.');
27094 }
27095 return platform;
27096}
27097/**
27098 * Helper function to create an instance of a platform injector (that maintains the 'platform'
27099 * scope).
27100 */
27101function createPlatformInjector(providers = [], name) {
27102 return Injector.create({
27103 name,
27104 providers: [
27105 { provide: INJECTOR_SCOPE, useValue: 'platform' },
27106 { provide: PLATFORM_ON_DESTROY, useValue: () => _platformInjector = null },
27107 ...providers
27108 ],
27109 });
27110}
27111/**
27112 * Destroys the current Angular platform and all Angular applications on the page.
27113 * Destroys all modules and listeners registered with the platform.
27114 *
27115 * @publicApi
27116 */
27117function destroyPlatform() {
27118 var _a;
27119 (_a = getPlatform()) === null || _a === void 0 ? void 0 : _a.destroy();
27120}
27121/**
27122 * Returns the current platform.
27123 *
27124 * @publicApi
27125 */
27126function getPlatform() {
27127 var _a;
27128 return (_a = _platformInjector === null || _platformInjector === void 0 ? void 0 : _platformInjector.get(PlatformRef)) !== null && _a !== void 0 ? _a : null;
27129}
27130/**
27131 * The Angular platform is the entry point for Angular on a web page.
27132 * Each page has exactly one platform. Services (such as reflection) which are common
27133 * to every Angular application running on the page are bound in its scope.
27134 * A page's platform is initialized implicitly when a platform is created using a platform
27135 * factory such as `PlatformBrowser`, or explicitly by calling the `createPlatform()` function.
27136 *
27137 * @publicApi
27138 */
27139class PlatformRef {
27140 /** @internal */
27141 constructor(_injector) {
27142 this._injector = _injector;
27143 this._modules = [];
27144 this._destroyListeners = [];
27145 this._destroyed = false;
27146 }
27147 /**
27148 * Creates an instance of an `@NgModule` for the given platform.
27149 *
27150 * @deprecated Passing NgModule factories as the `PlatformRef.bootstrapModuleFactory` function
27151 * argument is deprecated. Use the `PlatformRef.bootstrapModule` API instead.
27152 */
27153 bootstrapModuleFactory(moduleFactory, options) {
27154 // Note: We need to create the NgZone _before_ we instantiate the module,
27155 // as instantiating the module creates some providers eagerly.
27156 // So we create a mini parent injector that just contains the new NgZone and
27157 // pass that as parent to the NgModuleFactory.
27158 const ngZone = getNgZone(options === null || options === void 0 ? void 0 : options.ngZone, getNgZoneOptions(options));
27159 const providers = [{ provide: NgZone, useValue: ngZone }];
27160 // Note: Create ngZoneInjector within ngZone.run so that all of the instantiated services are
27161 // created within the Angular zone
27162 // Do not try to replace ngZone.run with ApplicationRef#run because ApplicationRef would then be
27163 // created outside of the Angular zone.
27164 return ngZone.run(() => {
27165 const ngZoneInjector = Injector.create({ providers: providers, parent: this.injector, name: moduleFactory.moduleType.name });
27166 const moduleRef = moduleFactory.create(ngZoneInjector);
27167 const exceptionHandler = moduleRef.injector.get(ErrorHandler, null);
27168 if (!exceptionHandler) {
27169 throw new RuntimeError(402 /* RuntimeErrorCode.ERROR_HANDLER_NOT_FOUND */, ngDevMode && 'No ErrorHandler. Is platform module (BrowserModule) included?');
27170 }
27171 ngZone.runOutsideAngular(() => {
27172 const subscription = ngZone.onError.subscribe({
27173 next: (error) => {
27174 exceptionHandler.handleError(error);
27175 }
27176 });
27177 moduleRef.onDestroy(() => {
27178 remove(this._modules, moduleRef);
27179 subscription.unsubscribe();
27180 });
27181 });
27182 return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
27183 const initStatus = moduleRef.injector.get(ApplicationInitStatus);
27184 initStatus.runInitializers();
27185 return initStatus.donePromise.then(() => {
27186 // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy
27187 const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
27188 setLocaleId(localeId || DEFAULT_LOCALE_ID);
27189 this._moduleDoBootstrap(moduleRef);
27190 return moduleRef;
27191 });
27192 });
27193 });
27194 }
27195 /**
27196 * Creates an instance of an `@NgModule` for a given platform.
27197 *
27198 * @usageNotes
27199 * ### Simple Example
27200 *
27201 * ```typescript
27202 * @NgModule({
27203 * imports: [BrowserModule]
27204 * })
27205 * class MyModule {}
27206 *
27207 * let moduleRef = platformBrowser().bootstrapModule(MyModule);
27208 * ```
27209 *
27210 */
27211 bootstrapModule(moduleType, compilerOptions = []) {
27212 const options = optionsReducer({}, compilerOptions);
27213 return compileNgModuleFactory(this.injector, options, moduleType)
27214 .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
27215 }
27216 _moduleDoBootstrap(moduleRef) {
27217 const appRef = moduleRef.injector.get(ApplicationRef);
27218 if (moduleRef._bootstrapComponents.length > 0) {
27219 moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
27220 }
27221 else if (moduleRef.instance.ngDoBootstrap) {
27222 moduleRef.instance.ngDoBootstrap(appRef);
27223 }
27224 else {
27225 throw new RuntimeError(403 /* RuntimeErrorCode.BOOTSTRAP_COMPONENTS_NOT_FOUND */, ngDevMode &&
27226 `The module ${stringify(moduleRef.instance.constructor)} was bootstrapped, ` +
27227 `but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
27228 `Please define one of these.`);
27229 }
27230 this._modules.push(moduleRef);
27231 }
27232 /**
27233 * Registers a listener to be called when the platform is destroyed.
27234 */
27235 onDestroy(callback) {
27236 this._destroyListeners.push(callback);
27237 }
27238 /**
27239 * Retrieves the platform {@link Injector}, which is the parent injector for
27240 * every Angular application on the page and provides singleton providers.
27241 */
27242 get injector() {
27243 return this._injector;
27244 }
27245 /**
27246 * Destroys the current Angular platform and all Angular applications on the page.
27247 * Destroys all modules and listeners registered with the platform.
27248 */
27249 destroy() {
27250 if (this._destroyed) {
27251 throw new RuntimeError(404 /* RuntimeErrorCode.PLATFORM_ALREADY_DESTROYED */, ngDevMode && 'The platform has already been destroyed!');
27252 }
27253 this._modules.slice().forEach(module => module.destroy());
27254 this._destroyListeners.forEach(listener => listener());
27255 const destroyListener = this._injector.get(PLATFORM_ON_DESTROY, null);
27256 destroyListener === null || destroyListener === void 0 ? void 0 : destroyListener();
27257 this._destroyed = true;
27258 }
27259 /**
27260 * Indicates whether this instance was destroyed.
27261 */
27262 get destroyed() {
27263 return this._destroyed;
27264 }
27265}
27266PlatformRef.ɵfac = function PlatformRef_Factory(t) { return new (t || PlatformRef)(ɵɵinject(Injector)); };
27267PlatformRef.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: PlatformRef, factory: PlatformRef.ɵfac, providedIn: 'platform' });
27268(function () {
27269 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PlatformRef, [{
27270 type: Injectable,
27271 args: [{ providedIn: 'platform' }]
27272 }], function () { return [{ type: Injector }]; }, null);
27273})();
27274// Transforms a set of `BootstrapOptions` (supported by the NgModule-based bootstrap APIs) ->
27275// `NgZoneOptions` that are recognized by the NgZone constructor. Passing no options will result in
27276// a set of default options returned.
27277function getNgZoneOptions(options) {
27278 return {
27279 enableLongStackTrace: typeof ngDevMode === 'undefined' ? false : !!ngDevMode,
27280 shouldCoalesceEventChangeDetection: !!(options && options.ngZoneEventCoalescing) || false,
27281 shouldCoalesceRunChangeDetection: !!(options && options.ngZoneRunCoalescing) || false,
27282 };
27283}
27284function getNgZone(ngZoneToUse, options) {
27285 let ngZone;
27286 if (ngZoneToUse === 'noop') {
27287 ngZone = new NoopNgZone();
27288 }
27289 else {
27290 ngZone = (ngZoneToUse === 'zone.js' ? undefined : ngZoneToUse) || new NgZone(options);
27291 }
27292 return ngZone;
27293}
27294function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
27295 try {
27296 const result = callback();
27297 if (isPromise(result)) {
27298 return result.catch((e) => {
27299 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
27300 // rethrow as the exception handler might not do it
27301 throw e;
27302 });
27303 }
27304 return result;
27305 }
27306 catch (e) {
27307 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
27308 // rethrow as the exception handler might not do it
27309 throw e;
27310 }
27311}
27312function optionsReducer(dst, objs) {
27313 if (Array.isArray(objs)) {
27314 dst = objs.reduce(optionsReducer, dst);
27315 }
27316 else {
27317 dst = Object.assign(Object.assign({}, dst), objs);
27318 }
27319 return dst;
27320}
27321/**
27322 * A reference to an Angular application running on a page.
27323 *
27324 * @usageNotes
27325 *
27326 * {@a is-stable-examples}
27327 * ### isStable examples and caveats
27328 *
27329 * Note two important points about `isStable`, demonstrated in the examples below:
27330 * - the application will never be stable if you start any kind
27331 * of recurrent asynchronous task when the application starts
27332 * (for example for a polling process, started with a `setInterval`, a `setTimeout`
27333 * or using RxJS operators like `interval`);
27334 * - the `isStable` Observable runs outside of the Angular zone.
27335 *
27336 * Let's imagine that you start a recurrent task
27337 * (here incrementing a counter, using RxJS `interval`),
27338 * and at the same time subscribe to `isStable`.
27339 *
27340 * ```
27341 * constructor(appRef: ApplicationRef) {
27342 * appRef.isStable.pipe(
27343 * filter(stable => stable)
27344 * ).subscribe(() => console.log('App is stable now');
27345 * interval(1000).subscribe(counter => console.log(counter));
27346 * }
27347 * ```
27348 * In this example, `isStable` will never emit `true`,
27349 * and the trace "App is stable now" will never get logged.
27350 *
27351 * If you want to execute something when the app is stable,
27352 * you have to wait for the application to be stable
27353 * before starting your polling process.
27354 *
27355 * ```
27356 * constructor(appRef: ApplicationRef) {
27357 * appRef.isStable.pipe(
27358 * first(stable => stable),
27359 * tap(stable => console.log('App is stable now')),
27360 * switchMap(() => interval(1000))
27361 * ).subscribe(counter => console.log(counter));
27362 * }
27363 * ```
27364 * In this example, the trace "App is stable now" will be logged
27365 * and then the counter starts incrementing every second.
27366 *
27367 * Note also that this Observable runs outside of the Angular zone,
27368 * which means that the code in the subscription
27369 * to this Observable will not trigger the change detection.
27370 *
27371 * Let's imagine that instead of logging the counter value,
27372 * you update a field of your component
27373 * and display it in its template.
27374 *
27375 * ```
27376 * constructor(appRef: ApplicationRef) {
27377 * appRef.isStable.pipe(
27378 * first(stable => stable),
27379 * switchMap(() => interval(1000))
27380 * ).subscribe(counter => this.value = counter);
27381 * }
27382 * ```
27383 * As the `isStable` Observable runs outside the zone,
27384 * the `value` field will be updated properly,
27385 * but the template will not be refreshed!
27386 *
27387 * You'll have to manually trigger the change detection to update the template.
27388 *
27389 * ```
27390 * constructor(appRef: ApplicationRef, cd: ChangeDetectorRef) {
27391 * appRef.isStable.pipe(
27392 * first(stable => stable),
27393 * switchMap(() => interval(1000))
27394 * ).subscribe(counter => {
27395 * this.value = counter;
27396 * cd.detectChanges();
27397 * });
27398 * }
27399 * ```
27400 *
27401 * Or make the subscription callback run inside the zone.
27402 *
27403 * ```
27404 * constructor(appRef: ApplicationRef, zone: NgZone) {
27405 * appRef.isStable.pipe(
27406 * first(stable => stable),
27407 * switchMap(() => interval(1000))
27408 * ).subscribe(counter => zone.run(() => this.value = counter));
27409 * }
27410 * ```
27411 *
27412 * @publicApi
27413 */
27414class ApplicationRef {
27415 /** @internal */
27416 constructor(_zone, _injector, _exceptionHandler, _initStatus) {
27417 this._zone = _zone;
27418 this._injector = _injector;
27419 this._exceptionHandler = _exceptionHandler;
27420 this._initStatus = _initStatus;
27421 /** @internal */
27422 this._bootstrapListeners = [];
27423 this._views = [];
27424 this._runningTick = false;
27425 this._stable = true;
27426 this._destroyed = false;
27427 this._destroyListeners = [];
27428 /**
27429 * Get a list of component types registered to this application.
27430 * This list is populated even before the component is created.
27431 */
27432 this.componentTypes = [];
27433 /**
27434 * Get a list of components registered to this application.
27435 */
27436 this.components = [];
27437 this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({
27438 next: () => {
27439 this._zone.run(() => {
27440 this.tick();
27441 });
27442 }
27443 });
27444 const isCurrentlyStable = new Observable((observer) => {
27445 this._stable = this._zone.isStable && !this._zone.hasPendingMacrotasks &&
27446 !this._zone.hasPendingMicrotasks;
27447 this._zone.runOutsideAngular(() => {
27448 observer.next(this._stable);
27449 observer.complete();
27450 });
27451 });
27452 const isStable = new Observable((observer) => {
27453 // Create the subscription to onStable outside the Angular Zone so that
27454 // the callback is run outside the Angular Zone.
27455 let stableSub;
27456 this._zone.runOutsideAngular(() => {
27457 stableSub = this._zone.onStable.subscribe(() => {
27458 NgZone.assertNotInAngularZone();
27459 // Check whether there are no pending macro/micro tasks in the next tick
27460 // to allow for NgZone to update the state.
27461 scheduleMicroTask(() => {
27462 if (!this._stable && !this._zone.hasPendingMacrotasks &&
27463 !this._zone.hasPendingMicrotasks) {
27464 this._stable = true;
27465 observer.next(true);
27466 }
27467 });
27468 });
27469 });
27470 const unstableSub = this._zone.onUnstable.subscribe(() => {
27471 NgZone.assertInAngularZone();
27472 if (this._stable) {
27473 this._stable = false;
27474 this._zone.runOutsideAngular(() => {
27475 observer.next(false);
27476 });
27477 }
27478 });
27479 return () => {
27480 stableSub.unsubscribe();
27481 unstableSub.unsubscribe();
27482 };
27483 });
27484 this.isStable =
27485 merge$1(isCurrentlyStable, isStable.pipe(share()));
27486 }
27487 /**
27488 * Indicates whether this instance was destroyed.
27489 */
27490 get destroyed() {
27491 return this._destroyed;
27492 }
27493 /** @internal */
27494 get injector() {
27495 return this._injector;
27496 }
27497 /**
27498 * Bootstrap a component onto the element identified by its selector or, optionally, to a
27499 * specified element.
27500 *
27501 * @usageNotes
27502 * ### Bootstrap process
27503 *
27504 * When bootstrapping a component, Angular mounts it onto a target DOM element
27505 * and kicks off automatic change detection. The target DOM element can be
27506 * provided using the `rootSelectorOrNode` argument.
27507 *
27508 * If the target DOM element is not provided, Angular tries to find one on a page
27509 * using the `selector` of the component that is being bootstrapped
27510 * (first matched element is used).
27511 *
27512 * ### Example
27513 *
27514 * Generally, we define the component to bootstrap in the `bootstrap` array of `NgModule`,
27515 * but it requires us to know the component while writing the application code.
27516 *
27517 * Imagine a situation where we have to wait for an API call to decide about the component to
27518 * bootstrap. We can use the `ngDoBootstrap` hook of the `NgModule` and call this method to
27519 * dynamically bootstrap a component.
27520 *
27521 * {@example core/ts/platform/platform.ts region='componentSelector'}
27522 *
27523 * Optionally, a component can be mounted onto a DOM element that does not match the
27524 * selector of the bootstrapped component.
27525 *
27526 * In the following example, we are providing a CSS selector to match the target element.
27527 *
27528 * {@example core/ts/platform/platform.ts region='cssSelector'}
27529 *
27530 * While in this example, we are providing reference to a DOM node.
27531 *
27532 * {@example core/ts/platform/platform.ts region='domNode'}
27533 */
27534 bootstrap(componentOrFactory, rootSelectorOrNode) {
27535 NG_DEV_MODE && this.warnIfDestroyed();
27536 const isComponentFactory = componentOrFactory instanceof ComponentFactory$1;
27537 if (!this._initStatus.done) {
27538 const standalone = !isComponentFactory && isStandalone(componentOrFactory);
27539 const errorMessage = 'Cannot bootstrap as there are still asynchronous initializers running.' +
27540 (standalone ? '' :
27541 ' Bootstrap components in the `ngDoBootstrap` method of the root module.');
27542 throw new RuntimeError(405 /* RuntimeErrorCode.ASYNC_INITIALIZERS_STILL_RUNNING */, NG_DEV_MODE && errorMessage);
27543 }
27544 let componentFactory;
27545 if (isComponentFactory) {
27546 componentFactory = componentOrFactory;
27547 }
27548 else {
27549 const resolver = this._injector.get(ComponentFactoryResolver$1);
27550 componentFactory = resolver.resolveComponentFactory(componentOrFactory);
27551 }
27552 this.componentTypes.push(componentFactory.componentType);
27553 // Create a factory associated with the current module if it's not bound to some other
27554 const ngModule = isBoundToModule(componentFactory) ? undefined : this._injector.get(NgModuleRef$1);
27555 const selectorOrNode = rootSelectorOrNode || componentFactory.selector;
27556 const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);
27557 const nativeElement = compRef.location.nativeElement;
27558 const testability = compRef.injector.get(TESTABILITY, null);
27559 testability === null || testability === void 0 ? void 0 : testability.registerApplication(nativeElement);
27560 compRef.onDestroy(() => {
27561 this.detachView(compRef.hostView);
27562 remove(this.components, compRef);
27563 testability === null || testability === void 0 ? void 0 : testability.unregisterApplication(nativeElement);
27564 });
27565 this._loadComponent(compRef);
27566 if (typeof ngDevMode === 'undefined' || ngDevMode) {
27567 const _console = this._injector.get(Console);
27568 _console.log(`Angular is running in development mode. Call enableProdMode() to enable production mode.`);
27569 }
27570 return compRef;
27571 }
27572 /**
27573 * Invoke this method to explicitly process change detection and its side-effects.
27574 *
27575 * In development mode, `tick()` also performs a second change detection cycle to ensure that no
27576 * further changes are detected. If additional changes are picked up during this second cycle,
27577 * bindings in the app have side-effects that cannot be resolved in a single change detection
27578 * pass.
27579 * In this case, Angular throws an error, since an Angular application can only have one change
27580 * detection pass during which all change detection must complete.
27581 */
27582 tick() {
27583 NG_DEV_MODE && this.warnIfDestroyed();
27584 if (this._runningTick) {
27585 throw new RuntimeError(101 /* RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK */, ngDevMode && 'ApplicationRef.tick is called recursively');
27586 }
27587 try {
27588 this._runningTick = true;
27589 for (let view of this._views) {
27590 view.detectChanges();
27591 }
27592 if (typeof ngDevMode === 'undefined' || ngDevMode) {
27593 for (let view of this._views) {
27594 view.checkNoChanges();
27595 }
27596 }
27597 }
27598 catch (e) {
27599 // Attention: Don't rethrow as it could cancel subscriptions to Observables!
27600 this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));
27601 }
27602 finally {
27603 this._runningTick = false;
27604 }
27605 }
27606 /**
27607 * Attaches a view so that it will be dirty checked.
27608 * The view will be automatically detached when it is destroyed.
27609 * This will throw if the view is already attached to a ViewContainer.
27610 */
27611 attachView(viewRef) {
27612 NG_DEV_MODE && this.warnIfDestroyed();
27613 const view = viewRef;
27614 this._views.push(view);
27615 view.attachToAppRef(this);
27616 }
27617 /**
27618 * Detaches a view from dirty checking again.
27619 */
27620 detachView(viewRef) {
27621 NG_DEV_MODE && this.warnIfDestroyed();
27622 const view = viewRef;
27623 remove(this._views, view);
27624 view.detachFromAppRef();
27625 }
27626 _loadComponent(componentRef) {
27627 this.attachView(componentRef.hostView);
27628 this.tick();
27629 this.components.push(componentRef);
27630 // Get the listeners lazily to prevent DI cycles.
27631 const listeners = this._injector.get(APP_BOOTSTRAP_LISTENER, []).concat(this._bootstrapListeners);
27632 listeners.forEach((listener) => listener(componentRef));
27633 }
27634 /** @internal */
27635 ngOnDestroy() {
27636 if (this._destroyed)
27637 return;
27638 try {
27639 // Call all the lifecycle hooks.
27640 this._destroyListeners.forEach(listener => listener());
27641 // Destroy all registered views.
27642 this._views.slice().forEach((view) => view.destroy());
27643 this._onMicrotaskEmptySubscription.unsubscribe();
27644 }
27645 finally {
27646 // Indicate that this instance is destroyed.
27647 this._destroyed = true;
27648 // Release all references.
27649 this._views = [];
27650 this._bootstrapListeners = [];
27651 this._destroyListeners = [];
27652 }
27653 }
27654 /**
27655 * Registers a listener to be called when an instance is destroyed.
27656 *
27657 * @param callback A callback function to add as a listener.
27658 * @returns A function which unregisters a listener.
27659 *
27660 * @internal
27661 */
27662 onDestroy(callback) {
27663 NG_DEV_MODE && this.warnIfDestroyed();
27664 this._destroyListeners.push(callback);
27665 return () => remove(this._destroyListeners, callback);
27666 }
27667 /**
27668 * Destroys an Angular application represented by this `ApplicationRef`. Calling this function
27669 * will destroy the associated environnement injectors as well as all the bootstrapped components
27670 * with their views.
27671 */
27672 destroy() {
27673 if (this._destroyed) {
27674 throw new RuntimeError(406 /* RuntimeErrorCode.APPLICATION_REF_ALREADY_DESTROYED */, ngDevMode && 'This instance of the `ApplicationRef` has already been destroyed.');
27675 }
27676 const injector = this._injector;
27677 // Check that this injector instance supports destroy operation.
27678 if (injector.destroy && !injector.destroyed) {
27679 // Destroying an underlying injector will trigger the `ngOnDestroy` lifecycle
27680 // hook, which invokes the remaining cleanup actions.
27681 injector.destroy();
27682 }
27683 }
27684 /**
27685 * Returns the number of attached views.
27686 */
27687 get viewCount() {
27688 return this._views.length;
27689 }
27690 warnIfDestroyed() {
27691 if (NG_DEV_MODE && this._destroyed) {
27692 console.warn(formatRuntimeError(406 /* RuntimeErrorCode.APPLICATION_REF_ALREADY_DESTROYED */, 'This instance of the `ApplicationRef` has already been destroyed.'));
27693 }
27694 }
27695}
27696ApplicationRef.ɵfac = function ApplicationRef_Factory(t) { return new (t || ApplicationRef)(ɵɵinject(NgZone), ɵɵinject(Injector), ɵɵinject(ErrorHandler), ɵɵinject(ApplicationInitStatus)); };
27697ApplicationRef.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationRef, factory: ApplicationRef.ɵfac, providedIn: 'root' });
27698(function () {
27699 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationRef, [{
27700 type: Injectable,
27701 args: [{ providedIn: 'root' }]
27702 }], function () { return [{ type: NgZone }, { type: Injector }, { type: ErrorHandler }, { type: ApplicationInitStatus }]; }, null);
27703})();
27704function remove(list, el) {
27705 const index = list.indexOf(el);
27706 if (index > -1) {
27707 list.splice(index, 1);
27708 }
27709}
27710function _lastDefined(args) {
27711 for (let i = args.length - 1; i >= 0; i--) {
27712 if (args[i] !== undefined) {
27713 return args[i];
27714 }
27715 }
27716 return undefined;
27717}
27718function _mergeArrays(parts) {
27719 const result = [];
27720 parts.forEach((part) => part && result.push(...part));
27721 return result;
27722}
27723
27724/**
27725 * @license
27726 * Copyright Google LLC All Rights Reserved.
27727 *
27728 * Use of this source code is governed by an MIT-style license that can be
27729 * found in the LICENSE file at https://angular.io/license
27730 */
27731/**
27732 * This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
27733 *
27734 * For more information on how to run and debug tests with either Ivy or View Engine (legacy),
27735 * please see [BAZEL.md](./docs/BAZEL.md).
27736 */
27737let _devMode = true;
27738let _runModeLocked = false;
27739/**
27740 * Returns whether Angular is in development mode. After called once,
27741 * the value is locked and won't change any more.
27742 *
27743 * By default, this is true, unless a user calls `enableProdMode` before calling this.
27744 *
27745 * @publicApi
27746 */
27747function isDevMode() {
27748 _runModeLocked = true;
27749 return _devMode;
27750}
27751/**
27752 * Disable Angular's development mode, which turns off assertions and other
27753 * checks within the framework.
27754 *
27755 * One important assertion this disables verifies that a change detection pass
27756 * does not result in additional changes to any bindings (also known as
27757 * unidirectional data flow).
27758 *
27759 * @publicApi
27760 */
27761function enableProdMode() {
27762 if (_runModeLocked) {
27763 throw new Error('Cannot enable prod mode after platform setup.');
27764 }
27765 // The below check is there so when ngDevMode is set via terser
27766 // `global['ngDevMode'] = false;` is also dropped.
27767 if (typeof ngDevMode === undefined || !!ngDevMode) {
27768 _global['ngDevMode'] = false;
27769 }
27770 _devMode = false;
27771}
27772
27773/**
27774 * @license
27775 * Copyright Google LLC All Rights Reserved.
27776 *
27777 * Use of this source code is governed by an MIT-style license that can be
27778 * found in the LICENSE file at https://angular.io/license
27779 */
27780
27781/**
27782 * @license
27783 * Copyright Google LLC All Rights Reserved.
27784 *
27785 * Use of this source code is governed by an MIT-style license that can be
27786 * found in the LICENSE file at https://angular.io/license
27787 */
27788
27789/**
27790 * @license
27791 * Copyright Google LLC All Rights Reserved.
27792 *
27793 * Use of this source code is governed by an MIT-style license that can be
27794 * found in the LICENSE file at https://angular.io/license
27795 */
27796/**
27797 * Returns the NgModuleFactory with the given id (specified using [@NgModule.id
27798 * field](api/core/NgModule#id)), if it exists and has been loaded. Factories for NgModules that do
27799 * not specify an `id` cannot be retrieved. Throws if an NgModule cannot be found.
27800 * @publicApi
27801 * @deprecated Use `getNgModuleById` instead.
27802 */
27803function getModuleFactory(id) {
27804 const type = getRegisteredNgModuleType(id);
27805 if (!type)
27806 throw noModuleError(id);
27807 return new NgModuleFactory(type);
27808}
27809/**
27810 * Returns the NgModule class with the given id (specified using [@NgModule.id
27811 * field](api/core/NgModule#id)), if it exists and has been loaded. Classes for NgModules that do
27812 * not specify an `id` cannot be retrieved. Throws if an NgModule cannot be found.
27813 * @publicApi
27814 */
27815function getNgModuleById(id) {
27816 const type = getRegisteredNgModuleType(id);
27817 if (!type)
27818 throw noModuleError(id);
27819 return type;
27820}
27821function noModuleError(id) {
27822 return new Error(`No module with ID ${id} loaded`);
27823}
27824
27825/**
27826 * @license
27827 * Copyright Google LLC All Rights Reserved.
27828 *
27829 * Use of this source code is governed by an MIT-style license that can be
27830 * found in the LICENSE file at https://angular.io/license
27831 */
27832/**
27833 * Base class that provides change detection functionality.
27834 * A change-detection tree collects all views that are to be checked for changes.
27835 * Use the methods to add and remove views from the tree, initiate change-detection,
27836 * and explicitly mark views as _dirty_, meaning that they have changed and need to be re-rendered.
27837 *
27838 * @see [Using change detection hooks](guide/lifecycle-hooks#using-change-detection-hooks)
27839 * @see [Defining custom change detection](guide/lifecycle-hooks#defining-custom-change-detection)
27840 *
27841 * @usageNotes
27842 *
27843 * The following examples demonstrate how to modify default change-detection behavior
27844 * to perform explicit detection when needed.
27845 *
27846 * ### Use `markForCheck()` with `CheckOnce` strategy
27847 *
27848 * The following example sets the `OnPush` change-detection strategy for a component
27849 * (`CheckOnce`, rather than the default `CheckAlways`), then forces a second check
27850 * after an interval. See [live demo](https://plnkr.co/edit/GC512b?p=preview).
27851 *
27852 * <code-example path="core/ts/change_detect/change-detection.ts"
27853 * region="mark-for-check"></code-example>
27854 *
27855 * ### Detach change detector to limit how often check occurs
27856 *
27857 * The following example defines a component with a large list of read-only data
27858 * that is expected to change constantly, many times per second.
27859 * To improve performance, we want to check and update the list
27860 * less often than the changes actually occur. To do that, we detach
27861 * the component's change detector and perform an explicit local check every five seconds.
27862 *
27863 * <code-example path="core/ts/change_detect/change-detection.ts" region="detach"></code-example>
27864 *
27865 *
27866 * ### Reattaching a detached component
27867 *
27868 * The following example creates a component displaying live data.
27869 * The component detaches its change detector from the main change detector tree
27870 * when the `live` property is set to false, and reattaches it when the property
27871 * becomes true.
27872 *
27873 * <code-example path="core/ts/change_detect/change-detection.ts" region="reattach"></code-example>
27874 *
27875 * @publicApi
27876 */
27877class ChangeDetectorRef {
27878}
27879/**
27880 * @internal
27881 * @nocollapse
27882 */
27883ChangeDetectorRef.__NG_ELEMENT_ID__ = injectChangeDetectorRef;
27884/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
27885function injectChangeDetectorRef(flags) {
27886 return createViewRef(getCurrentTNode(), getLView(), (flags & 16 /* InternalInjectFlags.ForPipe */) === 16 /* InternalInjectFlags.ForPipe */);
27887}
27888/**
27889 * Creates a ViewRef and stores it on the injector as ChangeDetectorRef (public alias).
27890 *
27891 * @param tNode The node that is requesting a ChangeDetectorRef
27892 * @param lView The view to which the node belongs
27893 * @param isPipe Whether the view is being injected into a pipe.
27894 * @returns The ChangeDetectorRef to use
27895 */
27896function createViewRef(tNode, lView, isPipe) {
27897 if (isComponentHost(tNode) && !isPipe) {
27898 // The LView represents the location where the component is declared.
27899 // Instead we want the LView for the component View and so we need to look it up.
27900 const componentView = getComponentLViewByIndex(tNode.index, lView); // look down
27901 return new ViewRef$1(componentView, componentView);
27902 }
27903 else if (tNode.type & (3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 32 /* TNodeType.Icu */)) {
27904 // The LView represents the location where the injection is requested from.
27905 // We need to locate the containing LView (in case where the `lView` is an embedded view)
27906 const hostComponentView = lView[DECLARATION_COMPONENT_VIEW]; // look up
27907 return new ViewRef$1(hostComponentView, lView);
27908 }
27909 return null;
27910}
27911
27912/**
27913 * @license
27914 * Copyright Google LLC All Rights Reserved.
27915 *
27916 * Use of this source code is governed by an MIT-style license that can be
27917 * found in the LICENSE file at https://angular.io/license
27918 */
27919/**
27920 * Represents an Angular [view](guide/glossary#view "Definition").
27921 *
27922 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
27923 *
27924 * @publicApi
27925 */
27926class ViewRef extends ChangeDetectorRef {
27927}
27928/**
27929 * Represents an Angular [view](guide/glossary#view) in a view container.
27930 * An [embedded view](guide/glossary#view-tree) can be referenced from a component
27931 * other than the hosting component whose template defines it, or it can be defined
27932 * independently by a `TemplateRef`.
27933 *
27934 * Properties of elements in a view can change, but the structure (number and order) of elements in
27935 * a view cannot. Change the structure of elements by inserting, moving, or
27936 * removing nested views in a view container.
27937 *
27938 * @see `ViewContainerRef`
27939 *
27940 * @usageNotes
27941 *
27942 * The following template breaks down into two separate `TemplateRef` instances,
27943 * an outer one and an inner one.
27944 *
27945 * ```
27946 * Count: {{items.length}}
27947 * <ul>
27948 * <li *ngFor="let item of items">{{item}}</li>
27949 * </ul>
27950 * ```
27951 *
27952 * This is the outer `TemplateRef`:
27953 *
27954 * ```
27955 * Count: {{items.length}}
27956 * <ul>
27957 * <ng-template ngFor let-item [ngForOf]="items"></ng-template>
27958 * </ul>
27959 * ```
27960 *
27961 * This is the inner `TemplateRef`:
27962 *
27963 * ```
27964 * <li>{{item}}</li>
27965 * ```
27966 *
27967 * The outer and inner `TemplateRef` instances are assembled into views as follows:
27968 *
27969 * ```
27970 * <!-- ViewRef: outer-0 -->
27971 * Count: 2
27972 * <ul>
27973 * <ng-template view-container-ref></ng-template>
27974 * <!-- ViewRef: inner-1 --><li>first</li><!-- /ViewRef: inner-1 -->
27975 * <!-- ViewRef: inner-2 --><li>second</li><!-- /ViewRef: inner-2 -->
27976 * </ul>
27977 * <!-- /ViewRef: outer-0 -->
27978 * ```
27979 * @publicApi
27980 */
27981class EmbeddedViewRef extends ViewRef {
27982}
27983
27984/**
27985 * @license
27986 * Copyright Google LLC All Rights Reserved.
27987 *
27988 * Use of this source code is governed by an MIT-style license that can be
27989 * found in the LICENSE file at https://angular.io/license
27990 */
27991
27992/**
27993 * @license
27994 * Copyright Google LLC All Rights Reserved.
27995 *
27996 * Use of this source code is governed by an MIT-style license that can be
27997 * found in the LICENSE file at https://angular.io/license
27998 */
27999// This file exists for easily patching NgModuleFactoryLoader in g3
28000var ng_module_factory_loader_impl = {};
28001
28002/**
28003 * @license
28004 * Copyright Google LLC All Rights Reserved.
28005 *
28006 * Use of this source code is governed by an MIT-style license that can be
28007 * found in the LICENSE file at https://angular.io/license
28008 */
28009/**
28010 * @publicApi
28011 */
28012class DebugEventListener {
28013 constructor(name, callback) {
28014 this.name = name;
28015 this.callback = callback;
28016 }
28017}
28018/**
28019 * @publicApi
28020 */
28021function asNativeElements(debugEls) {
28022 return debugEls.map((el) => el.nativeElement);
28023}
28024/**
28025 * @publicApi
28026 */
28027class DebugNode {
28028 constructor(nativeNode) {
28029 this.nativeNode = nativeNode;
28030 }
28031 /**
28032 * The `DebugElement` parent. Will be `null` if this is the root element.
28033 */
28034 get parent() {
28035 const parent = this.nativeNode.parentNode;
28036 return parent ? new DebugElement(parent) : null;
28037 }
28038 /**
28039 * The host dependency injector. For example, the root element's component instance injector.
28040 */
28041 get injector() {
28042 return getInjector(this.nativeNode);
28043 }
28044 /**
28045 * The element's own component instance, if it has one.
28046 */
28047 get componentInstance() {
28048 const nativeElement = this.nativeNode;
28049 return nativeElement &&
28050 (getComponent$1(nativeElement) || getOwningComponent(nativeElement));
28051 }
28052 /**
28053 * An object that provides parent context for this element. Often an ancestor component instance
28054 * that governs this element.
28055 *
28056 * When an element is repeated within *ngFor, the context is an `NgForOf` whose `$implicit`
28057 * property is the value of the row instance value. For example, the `hero` in `*ngFor="let hero
28058 * of heroes"`.
28059 */
28060 get context() {
28061 return getComponent$1(this.nativeNode) || getContext(this.nativeNode);
28062 }
28063 /**
28064 * The callbacks attached to the component's @Output properties and/or the element's event
28065 * properties.
28066 */
28067 get listeners() {
28068 return getListeners(this.nativeNode).filter(listener => listener.type === 'dom');
28069 }
28070 /**
28071 * Dictionary of objects associated with template local variables (e.g. #foo), keyed by the local
28072 * variable name.
28073 */
28074 get references() {
28075 return getLocalRefs(this.nativeNode);
28076 }
28077 /**
28078 * This component's injector lookup tokens. Includes the component itself plus the tokens that the
28079 * component lists in its providers metadata.
28080 */
28081 get providerTokens() {
28082 return getInjectionTokens(this.nativeNode);
28083 }
28084}
28085/**
28086 * @publicApi
28087 *
28088 * @see [Component testing scenarios](guide/testing-components-scenarios)
28089 * @see [Basics of testing components](guide/testing-components-basics)
28090 * @see [Testing utility APIs](guide/testing-utility-apis)
28091 */
28092class DebugElement extends DebugNode {
28093 constructor(nativeNode) {
28094 ngDevMode && assertDomNode(nativeNode);
28095 super(nativeNode);
28096 }
28097 /**
28098 * The underlying DOM element at the root of the component.
28099 */
28100 get nativeElement() {
28101 return this.nativeNode.nodeType == Node.ELEMENT_NODE ? this.nativeNode : null;
28102 }
28103 /**
28104 * The element tag name, if it is an element.
28105 */
28106 get name() {
28107 const context = getLContext(this.nativeNode);
28108 const lView = context ? context.lView : null;
28109 if (lView !== null) {
28110 const tData = lView[TVIEW].data;
28111 const tNode = tData[context.nodeIndex];
28112 return tNode.value;
28113 }
28114 else {
28115 return this.nativeNode.nodeName;
28116 }
28117 }
28118 /**
28119 * Gets a map of property names to property values for an element.
28120 *
28121 * This map includes:
28122 * - Regular property bindings (e.g. `[id]="id"`)
28123 * - Host property bindings (e.g. `host: { '[id]': "id" }`)
28124 * - Interpolated property bindings (e.g. `id="{{ value }}")
28125 *
28126 * It does not include:
28127 * - input property bindings (e.g. `[myCustomInput]="value"`)
28128 * - attribute bindings (e.g. `[attr.role]="menu"`)
28129 */
28130 get properties() {
28131 const context = getLContext(this.nativeNode);
28132 const lView = context ? context.lView : null;
28133 if (lView === null) {
28134 return {};
28135 }
28136 const tData = lView[TVIEW].data;
28137 const tNode = tData[context.nodeIndex];
28138 const properties = {};
28139 // Collect properties from the DOM.
28140 copyDomProperties(this.nativeElement, properties);
28141 // Collect properties from the bindings. This is needed for animation renderer which has
28142 // synthetic properties which don't get reflected into the DOM.
28143 collectPropertyBindings(properties, tNode, lView, tData);
28144 return properties;
28145 }
28146 /**
28147 * A map of attribute names to attribute values for an element.
28148 */
28149 get attributes() {
28150 const attributes = {};
28151 const element = this.nativeElement;
28152 if (!element) {
28153 return attributes;
28154 }
28155 const context = getLContext(element);
28156 const lView = context ? context.lView : null;
28157 if (lView === null) {
28158 return {};
28159 }
28160 const tNodeAttrs = lView[TVIEW].data[context.nodeIndex].attrs;
28161 const lowercaseTNodeAttrs = [];
28162 // For debug nodes we take the element's attribute directly from the DOM since it allows us
28163 // to account for ones that weren't set via bindings (e.g. ViewEngine keeps track of the ones
28164 // that are set through `Renderer2`). The problem is that the browser will lowercase all names,
28165 // however since we have the attributes already on the TNode, we can preserve the case by going
28166 // through them once, adding them to the `attributes` map and putting their lower-cased name
28167 // into an array. Afterwards when we're going through the native DOM attributes, we can check
28168 // whether we haven't run into an attribute already through the TNode.
28169 if (tNodeAttrs) {
28170 let i = 0;
28171 while (i < tNodeAttrs.length) {
28172 const attrName = tNodeAttrs[i];
28173 // Stop as soon as we hit a marker. We only care about the regular attributes. Everything
28174 // else will be handled below when we read the final attributes off the DOM.
28175 if (typeof attrName !== 'string')
28176 break;
28177 const attrValue = tNodeAttrs[i + 1];
28178 attributes[attrName] = attrValue;
28179 lowercaseTNodeAttrs.push(attrName.toLowerCase());
28180 i += 2;
28181 }
28182 }
28183 const eAttrs = element.attributes;
28184 for (let i = 0; i < eAttrs.length; i++) {
28185 const attr = eAttrs[i];
28186 const lowercaseName = attr.name.toLowerCase();
28187 // Make sure that we don't assign the same attribute both in its
28188 // case-sensitive form and the lower-cased one from the browser.
28189 if (lowercaseTNodeAttrs.indexOf(lowercaseName) === -1) {
28190 // Save the lowercase name to align the behavior between browsers.
28191 // IE preserves the case, while all other browser convert it to lower case.
28192 attributes[lowercaseName] = attr.value;
28193 }
28194 }
28195 return attributes;
28196 }
28197 /**
28198 * The inline styles of the DOM element.
28199 *
28200 * Will be `null` if there is no `style` property on the underlying DOM element.
28201 *
28202 * @see [ElementCSSInlineStyle](https://developer.mozilla.org/en-US/docs/Web/API/ElementCSSInlineStyle/style)
28203 */
28204 get styles() {
28205 if (this.nativeElement && this.nativeElement.style) {
28206 return this.nativeElement.style;
28207 }
28208 return {};
28209 }
28210 /**
28211 * A map containing the class names on the element as keys.
28212 *
28213 * This map is derived from the `className` property of the DOM element.
28214 *
28215 * Note: The values of this object will always be `true`. The class key will not appear in the KV
28216 * object if it does not exist on the element.
28217 *
28218 * @see [Element.className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className)
28219 */
28220 get classes() {
28221 const result = {};
28222 const element = this.nativeElement;
28223 // SVG elements return an `SVGAnimatedString` instead of a plain string for the `className`.
28224 const className = element.className;
28225 const classes = typeof className !== 'string' ? className.baseVal.split(' ') : className.split(' ');
28226 classes.forEach((value) => result[value] = true);
28227 return result;
28228 }
28229 /**
28230 * The `childNodes` of the DOM element as a `DebugNode` array.
28231 *
28232 * @see [Node.childNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes)
28233 */
28234 get childNodes() {
28235 const childNodes = this.nativeNode.childNodes;
28236 const children = [];
28237 for (let i = 0; i < childNodes.length; i++) {
28238 const element = childNodes[i];
28239 children.push(getDebugNode(element));
28240 }
28241 return children;
28242 }
28243 /**
28244 * The immediate `DebugElement` children. Walk the tree by descending through `children`.
28245 */
28246 get children() {
28247 const nativeElement = this.nativeElement;
28248 if (!nativeElement)
28249 return [];
28250 const childNodes = nativeElement.children;
28251 const children = [];
28252 for (let i = 0; i < childNodes.length; i++) {
28253 const element = childNodes[i];
28254 children.push(getDebugNode(element));
28255 }
28256 return children;
28257 }
28258 /**
28259 * @returns the first `DebugElement` that matches the predicate at any depth in the subtree.
28260 */
28261 query(predicate) {
28262 const results = this.queryAll(predicate);
28263 return results[0] || null;
28264 }
28265 /**
28266 * @returns All `DebugElement` matches for the predicate at any depth in the subtree.
28267 */
28268 queryAll(predicate) {
28269 const matches = [];
28270 _queryAll(this, predicate, matches, true);
28271 return matches;
28272 }
28273 /**
28274 * @returns All `DebugNode` matches for the predicate at any depth in the subtree.
28275 */
28276 queryAllNodes(predicate) {
28277 const matches = [];
28278 _queryAll(this, predicate, matches, false);
28279 return matches;
28280 }
28281 /**
28282 * Triggers the event by its name if there is a corresponding listener in the element's
28283 * `listeners` collection.
28284 *
28285 * If the event lacks a listener or there's some other problem, consider
28286 * calling `nativeElement.dispatchEvent(eventObject)`.
28287 *
28288 * @param eventName The name of the event to trigger
28289 * @param eventObj The _event object_ expected by the handler
28290 *
28291 * @see [Testing components scenarios](guide/testing-components-scenarios#trigger-event-handler)
28292 */
28293 triggerEventHandler(eventName, eventObj) {
28294 const node = this.nativeNode;
28295 const invokedListeners = [];
28296 this.listeners.forEach(listener => {
28297 if (listener.name === eventName) {
28298 const callback = listener.callback;
28299 callback.call(node, eventObj);
28300 invokedListeners.push(callback);
28301 }
28302 });
28303 // We need to check whether `eventListeners` exists, because it's something
28304 // that Zone.js only adds to `EventTarget` in browser environments.
28305 if (typeof node.eventListeners === 'function') {
28306 // Note that in Ivy we wrap event listeners with a call to `event.preventDefault` in some
28307 // cases. We use '__ngUnwrap__' as a special token that gives us access to the actual event
28308 // listener.
28309 node.eventListeners(eventName).forEach((listener) => {
28310 // In order to ensure that we can detect the special __ngUnwrap__ token described above, we
28311 // use `toString` on the listener and see if it contains the token. We use this approach to
28312 // ensure that it still worked with compiled code since it cannot remove or rename string
28313 // literals. We also considered using a special function name (i.e. if(listener.name ===
28314 // special)) but that was more cumbersome and we were also concerned the compiled code could
28315 // strip the name, turning the condition in to ("" === "") and always returning true.
28316 if (listener.toString().indexOf('__ngUnwrap__') !== -1) {
28317 const unwrappedListener = listener('__ngUnwrap__');
28318 return invokedListeners.indexOf(unwrappedListener) === -1 &&
28319 unwrappedListener.call(node, eventObj);
28320 }
28321 });
28322 }
28323 }
28324}
28325function copyDomProperties(element, properties) {
28326 if (element) {
28327 // Skip own properties (as those are patched)
28328 let obj = Object.getPrototypeOf(element);
28329 const NodePrototype = Node.prototype;
28330 while (obj !== null && obj !== NodePrototype) {
28331 const descriptors = Object.getOwnPropertyDescriptors(obj);
28332 for (let key in descriptors) {
28333 if (!key.startsWith('__') && !key.startsWith('on')) {
28334 // don't include properties starting with `__` and `on`.
28335 // `__` are patched values which should not be included.
28336 // `on` are listeners which also should not be included.
28337 const value = element[key];
28338 if (isPrimitiveValue(value)) {
28339 properties[key] = value;
28340 }
28341 }
28342 }
28343 obj = Object.getPrototypeOf(obj);
28344 }
28345 }
28346}
28347function isPrimitiveValue(value) {
28348 return typeof value === 'string' || typeof value === 'boolean' || typeof value === 'number' ||
28349 value === null;
28350}
28351function _queryAll(parentElement, predicate, matches, elementsOnly) {
28352 const context = getLContext(parentElement.nativeNode);
28353 const lView = context ? context.lView : null;
28354 if (lView !== null) {
28355 const parentTNode = lView[TVIEW].data[context.nodeIndex];
28356 _queryNodeChildren(parentTNode, lView, predicate, matches, elementsOnly, parentElement.nativeNode);
28357 }
28358 else {
28359 // If the context is null, then `parentElement` was either created with Renderer2 or native DOM
28360 // APIs.
28361 _queryNativeNodeDescendants(parentElement.nativeNode, predicate, matches, elementsOnly);
28362 }
28363}
28364/**
28365 * Recursively match the current TNode against the predicate, and goes on with the next ones.
28366 *
28367 * @param tNode the current TNode
28368 * @param lView the LView of this TNode
28369 * @param predicate the predicate to match
28370 * @param matches the list of positive matches
28371 * @param elementsOnly whether only elements should be searched
28372 * @param rootNativeNode the root native node on which predicate should not be matched
28373 */
28374function _queryNodeChildren(tNode, lView, predicate, matches, elementsOnly, rootNativeNode) {
28375 ngDevMode && assertTNodeForLView(tNode, lView);
28376 const nativeNode = getNativeByTNodeOrNull(tNode, lView);
28377 // For each type of TNode, specific logic is executed.
28378 if (tNode.type & (3 /* TNodeType.AnyRNode */ | 8 /* TNodeType.ElementContainer */)) {
28379 // Case 1: the TNode is an element
28380 // The native node has to be checked.
28381 _addQueryMatch(nativeNode, predicate, matches, elementsOnly, rootNativeNode);
28382 if (isComponentHost(tNode)) {
28383 // If the element is the host of a component, then all nodes in its view have to be processed.
28384 // Note: the component's content (tNode.child) will be processed from the insertion points.
28385 const componentView = getComponentLViewByIndex(tNode.index, lView);
28386 if (componentView && componentView[TVIEW].firstChild) {
28387 _queryNodeChildren(componentView[TVIEW].firstChild, componentView, predicate, matches, elementsOnly, rootNativeNode);
28388 }
28389 }
28390 else {
28391 if (tNode.child) {
28392 // Otherwise, its children have to be processed.
28393 _queryNodeChildren(tNode.child, lView, predicate, matches, elementsOnly, rootNativeNode);
28394 }
28395 // We also have to query the DOM directly in order to catch elements inserted through
28396 // Renderer2. Note that this is __not__ optimal, because we're walking similar trees multiple
28397 // times. ViewEngine could do it more efficiently, because all the insertions go through
28398 // Renderer2, however that's not the case in Ivy. This approach is being used because:
28399 // 1. Matching the ViewEngine behavior would mean potentially introducing a depedency
28400 // from `Renderer2` to Ivy which could bring Ivy code into ViewEngine.
28401 // 2. We would have to make `Renderer3` "know" about debug nodes.
28402 // 3. It allows us to capture nodes that were inserted directly via the DOM.
28403 nativeNode && _queryNativeNodeDescendants(nativeNode, predicate, matches, elementsOnly);
28404 }
28405 // In all cases, if a dynamic container exists for this node, each view inside it has to be
28406 // processed.
28407 const nodeOrContainer = lView[tNode.index];
28408 if (isLContainer(nodeOrContainer)) {
28409 _queryNodeChildrenInContainer(nodeOrContainer, predicate, matches, elementsOnly, rootNativeNode);
28410 }
28411 }
28412 else if (tNode.type & 4 /* TNodeType.Container */) {
28413 // Case 2: the TNode is a container
28414 // The native node has to be checked.
28415 const lContainer = lView[tNode.index];
28416 _addQueryMatch(lContainer[NATIVE], predicate, matches, elementsOnly, rootNativeNode);
28417 // Each view inside the container has to be processed.
28418 _queryNodeChildrenInContainer(lContainer, predicate, matches, elementsOnly, rootNativeNode);
28419 }
28420 else if (tNode.type & 16 /* TNodeType.Projection */) {
28421 // Case 3: the TNode is a projection insertion point (i.e. a <ng-content>).
28422 // The nodes projected at this location all need to be processed.
28423 const componentView = lView[DECLARATION_COMPONENT_VIEW];
28424 const componentHost = componentView[T_HOST];
28425 const head = componentHost.projection[tNode.projection];
28426 if (Array.isArray(head)) {
28427 for (let nativeNode of head) {
28428 _addQueryMatch(nativeNode, predicate, matches, elementsOnly, rootNativeNode);
28429 }
28430 }
28431 else if (head) {
28432 const nextLView = componentView[PARENT];
28433 const nextTNode = nextLView[TVIEW].data[head.index];
28434 _queryNodeChildren(nextTNode, nextLView, predicate, matches, elementsOnly, rootNativeNode);
28435 }
28436 }
28437 else if (tNode.child) {
28438 // Case 4: the TNode is a view.
28439 _queryNodeChildren(tNode.child, lView, predicate, matches, elementsOnly, rootNativeNode);
28440 }
28441 // We don't want to go to the next sibling of the root node.
28442 if (rootNativeNode !== nativeNode) {
28443 // To determine the next node to be processed, we need to use the next or the projectionNext
28444 // link, depending on whether the current node has been projected.
28445 const nextTNode = (tNode.flags & 4 /* TNodeFlags.isProjected */) ? tNode.projectionNext : tNode.next;
28446 if (nextTNode) {
28447 _queryNodeChildren(nextTNode, lView, predicate, matches, elementsOnly, rootNativeNode);
28448 }
28449 }
28450}
28451/**
28452 * Process all TNodes in a given container.
28453 *
28454 * @param lContainer the container to be processed
28455 * @param predicate the predicate to match
28456 * @param matches the list of positive matches
28457 * @param elementsOnly whether only elements should be searched
28458 * @param rootNativeNode the root native node on which predicate should not be matched
28459 */
28460function _queryNodeChildrenInContainer(lContainer, predicate, matches, elementsOnly, rootNativeNode) {
28461 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
28462 const childView = lContainer[i];
28463 const firstChild = childView[TVIEW].firstChild;
28464 if (firstChild) {
28465 _queryNodeChildren(firstChild, childView, predicate, matches, elementsOnly, rootNativeNode);
28466 }
28467 }
28468}
28469/**
28470 * Match the current native node against the predicate.
28471 *
28472 * @param nativeNode the current native node
28473 * @param predicate the predicate to match
28474 * @param matches the list of positive matches
28475 * @param elementsOnly whether only elements should be searched
28476 * @param rootNativeNode the root native node on which predicate should not be matched
28477 */
28478function _addQueryMatch(nativeNode, predicate, matches, elementsOnly, rootNativeNode) {
28479 if (rootNativeNode !== nativeNode) {
28480 const debugNode = getDebugNode(nativeNode);
28481 if (!debugNode) {
28482 return;
28483 }
28484 // Type of the "predicate and "matches" array are set based on the value of
28485 // the "elementsOnly" parameter. TypeScript is not able to properly infer these
28486 // types with generics, so we manually cast the parameters accordingly.
28487 if (elementsOnly && (debugNode instanceof DebugElement) && predicate(debugNode) &&
28488 matches.indexOf(debugNode) === -1) {
28489 matches.push(debugNode);
28490 }
28491 else if (!elementsOnly && predicate(debugNode) &&
28492 matches.indexOf(debugNode) === -1) {
28493 matches.push(debugNode);
28494 }
28495 }
28496}
28497/**
28498 * Match all the descendants of a DOM node against a predicate.
28499 *
28500 * @param nativeNode the current native node
28501 * @param predicate the predicate to match
28502 * @param matches the list where matches are stored
28503 * @param elementsOnly whether only elements should be searched
28504 */
28505function _queryNativeNodeDescendants(parentNode, predicate, matches, elementsOnly) {
28506 const nodes = parentNode.childNodes;
28507 const length = nodes.length;
28508 for (let i = 0; i < length; i++) {
28509 const node = nodes[i];
28510 const debugNode = getDebugNode(node);
28511 if (debugNode) {
28512 if (elementsOnly && (debugNode instanceof DebugElement) && predicate(debugNode) &&
28513 matches.indexOf(debugNode) === -1) {
28514 matches.push(debugNode);
28515 }
28516 else if (!elementsOnly && predicate(debugNode) &&
28517 matches.indexOf(debugNode) === -1) {
28518 matches.push(debugNode);
28519 }
28520 _queryNativeNodeDescendants(node, predicate, matches, elementsOnly);
28521 }
28522 }
28523}
28524/**
28525 * Iterates through the property bindings for a given node and generates
28526 * a map of property names to values. This map only contains property bindings
28527 * defined in templates, not in host bindings.
28528 */
28529function collectPropertyBindings(properties, tNode, lView, tData) {
28530 let bindingIndexes = tNode.propertyBindings;
28531 if (bindingIndexes !== null) {
28532 for (let i = 0; i < bindingIndexes.length; i++) {
28533 const bindingIndex = bindingIndexes[i];
28534 const propMetadata = tData[bindingIndex];
28535 const metadataParts = propMetadata.split(INTERPOLATION_DELIMITER);
28536 const propertyName = metadataParts[0];
28537 if (metadataParts.length > 1) {
28538 let value = metadataParts[1];
28539 for (let j = 1; j < metadataParts.length - 1; j++) {
28540 value += renderStringify(lView[bindingIndex + j - 1]) + metadataParts[j + 1];
28541 }
28542 properties[propertyName] = value;
28543 }
28544 else {
28545 properties[propertyName] = lView[bindingIndex];
28546 }
28547 }
28548 }
28549}
28550// Need to keep the nodes in a global Map so that multiple angular apps are supported.
28551const _nativeNodeToDebugNode = new Map();
28552const NG_DEBUG_PROPERTY = '__ng_debug__';
28553/**
28554 * @publicApi
28555 */
28556function getDebugNode(nativeNode) {
28557 if (nativeNode instanceof Node) {
28558 if (!(nativeNode.hasOwnProperty(NG_DEBUG_PROPERTY))) {
28559 nativeNode[NG_DEBUG_PROPERTY] = nativeNode.nodeType == Node.ELEMENT_NODE ?
28560 new DebugElement(nativeNode) :
28561 new DebugNode(nativeNode);
28562 }
28563 return nativeNode[NG_DEBUG_PROPERTY];
28564 }
28565 return null;
28566}
28567// TODO: cleanup all references to this function and remove it.
28568function getDebugNodeR2(_nativeNode) {
28569 return null;
28570}
28571function getAllDebugNodes() {
28572 return Array.from(_nativeNodeToDebugNode.values());
28573}
28574function indexDebugNode(node) {
28575 _nativeNodeToDebugNode.set(node.nativeNode, node);
28576}
28577function removeDebugNodeFromIndex(node) {
28578 _nativeNodeToDebugNode.delete(node.nativeNode);
28579}
28580
28581/**
28582 * @license
28583 * Copyright Google LLC All Rights Reserved.
28584 *
28585 * Use of this source code is governed by an MIT-style license that can be
28586 * found in the LICENSE file at https://angular.io/license
28587 */
28588class DefaultIterableDifferFactory {
28589 constructor() { }
28590 supports(obj) {
28591 return isListLikeIterable(obj);
28592 }
28593 create(trackByFn) {
28594 return new DefaultIterableDiffer(trackByFn);
28595 }
28596}
28597const trackByIdentity = (index, item) => item;
28598/**
28599 * @deprecated v4.0.0 - Should not be part of public API.
28600 * @publicApi
28601 */
28602class DefaultIterableDiffer {
28603 constructor(trackByFn) {
28604 this.length = 0;
28605 // Keeps track of the used records at any point in time (during & across `_check()` calls)
28606 this._linkedRecords = null;
28607 // Keeps track of the removed records at any point in time during `_check()` calls.
28608 this._unlinkedRecords = null;
28609 this._previousItHead = null;
28610 this._itHead = null;
28611 this._itTail = null;
28612 this._additionsHead = null;
28613 this._additionsTail = null;
28614 this._movesHead = null;
28615 this._movesTail = null;
28616 this._removalsHead = null;
28617 this._removalsTail = null;
28618 // Keeps track of records where custom track by is the same, but item identity has changed
28619 this._identityChangesHead = null;
28620 this._identityChangesTail = null;
28621 this._trackByFn = trackByFn || trackByIdentity;
28622 }
28623 forEachItem(fn) {
28624 let record;
28625 for (record = this._itHead; record !== null; record = record._next) {
28626 fn(record);
28627 }
28628 }
28629 forEachOperation(fn) {
28630 let nextIt = this._itHead;
28631 let nextRemove = this._removalsHead;
28632 let addRemoveOffset = 0;
28633 let moveOffsets = null;
28634 while (nextIt || nextRemove) {
28635 // Figure out which is the next record to process
28636 // Order: remove, add, move
28637 const record = !nextRemove ||
28638 nextIt &&
28639 nextIt.currentIndex <
28640 getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
28641 nextIt :
28642 nextRemove;
28643 const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets);
28644 const currentIndex = record.currentIndex;
28645 // consume the item, and adjust the addRemoveOffset and update moveDistance if necessary
28646 if (record === nextRemove) {
28647 addRemoveOffset--;
28648 nextRemove = nextRemove._nextRemoved;
28649 }
28650 else {
28651 nextIt = nextIt._next;
28652 if (record.previousIndex == null) {
28653 addRemoveOffset++;
28654 }
28655 else {
28656 // INVARIANT: currentIndex < previousIndex
28657 if (!moveOffsets)
28658 moveOffsets = [];
28659 const localMovePreviousIndex = adjPreviousIndex - addRemoveOffset;
28660 const localCurrentIndex = currentIndex - addRemoveOffset;
28661 if (localMovePreviousIndex != localCurrentIndex) {
28662 for (let i = 0; i < localMovePreviousIndex; i++) {
28663 const offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0);
28664 const index = offset + i;
28665 if (localCurrentIndex <= index && index < localMovePreviousIndex) {
28666 moveOffsets[i] = offset + 1;
28667 }
28668 }
28669 const previousIndex = record.previousIndex;
28670 moveOffsets[previousIndex] = localCurrentIndex - localMovePreviousIndex;
28671 }
28672 }
28673 }
28674 if (adjPreviousIndex !== currentIndex) {
28675 fn(record, adjPreviousIndex, currentIndex);
28676 }
28677 }
28678 }
28679 forEachPreviousItem(fn) {
28680 let record;
28681 for (record = this._previousItHead; record !== null; record = record._nextPrevious) {
28682 fn(record);
28683 }
28684 }
28685 forEachAddedItem(fn) {
28686 let record;
28687 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
28688 fn(record);
28689 }
28690 }
28691 forEachMovedItem(fn) {
28692 let record;
28693 for (record = this._movesHead; record !== null; record = record._nextMoved) {
28694 fn(record);
28695 }
28696 }
28697 forEachRemovedItem(fn) {
28698 let record;
28699 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
28700 fn(record);
28701 }
28702 }
28703 forEachIdentityChange(fn) {
28704 let record;
28705 for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) {
28706 fn(record);
28707 }
28708 }
28709 diff(collection) {
28710 if (collection == null)
28711 collection = [];
28712 if (!isListLikeIterable(collection)) {
28713 throw new RuntimeError(900 /* RuntimeErrorCode.INVALID_DIFFER_INPUT */, ngDevMode &&
28714 `Error trying to diff '${stringify(collection)}'. Only arrays and iterables are allowed`);
28715 }
28716 if (this.check(collection)) {
28717 return this;
28718 }
28719 else {
28720 return null;
28721 }
28722 }
28723 onDestroy() { }
28724 check(collection) {
28725 this._reset();
28726 let record = this._itHead;
28727 let mayBeDirty = false;
28728 let index;
28729 let item;
28730 let itemTrackBy;
28731 if (Array.isArray(collection)) {
28732 this.length = collection.length;
28733 for (let index = 0; index < this.length; index++) {
28734 item = collection[index];
28735 itemTrackBy = this._trackByFn(index, item);
28736 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
28737 record = this._mismatch(record, item, itemTrackBy, index);
28738 mayBeDirty = true;
28739 }
28740 else {
28741 if (mayBeDirty) {
28742 // TODO(misko): can we limit this to duplicates only?
28743 record = this._verifyReinsertion(record, item, itemTrackBy, index);
28744 }
28745 if (!Object.is(record.item, item))
28746 this._addIdentityChange(record, item);
28747 }
28748 record = record._next;
28749 }
28750 }
28751 else {
28752 index = 0;
28753 iterateListLike(collection, (item) => {
28754 itemTrackBy = this._trackByFn(index, item);
28755 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
28756 record = this._mismatch(record, item, itemTrackBy, index);
28757 mayBeDirty = true;
28758 }
28759 else {
28760 if (mayBeDirty) {
28761 // TODO(misko): can we limit this to duplicates only?
28762 record = this._verifyReinsertion(record, item, itemTrackBy, index);
28763 }
28764 if (!Object.is(record.item, item))
28765 this._addIdentityChange(record, item);
28766 }
28767 record = record._next;
28768 index++;
28769 });
28770 this.length = index;
28771 }
28772 this._truncate(record);
28773 this.collection = collection;
28774 return this.isDirty;
28775 }
28776 /* CollectionChanges is considered dirty if it has any additions, moves, removals, or identity
28777 * changes.
28778 */
28779 get isDirty() {
28780 return this._additionsHead !== null || this._movesHead !== null ||
28781 this._removalsHead !== null || this._identityChangesHead !== null;
28782 }
28783 /**
28784 * Reset the state of the change objects to show no changes. This means set previousKey to
28785 * currentKey, and clear all of the queues (additions, moves, removals).
28786 * Set the previousIndexes of moved and added items to their currentIndexes
28787 * Reset the list of additions, moves and removals
28788 *
28789 * @internal
28790 */
28791 _reset() {
28792 if (this.isDirty) {
28793 let record;
28794 for (record = this._previousItHead = this._itHead; record !== null; record = record._next) {
28795 record._nextPrevious = record._next;
28796 }
28797 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
28798 record.previousIndex = record.currentIndex;
28799 }
28800 this._additionsHead = this._additionsTail = null;
28801 for (record = this._movesHead; record !== null; record = record._nextMoved) {
28802 record.previousIndex = record.currentIndex;
28803 }
28804 this._movesHead = this._movesTail = null;
28805 this._removalsHead = this._removalsTail = null;
28806 this._identityChangesHead = this._identityChangesTail = null;
28807 // TODO(vicb): when assert gets supported
28808 // assert(!this.isDirty);
28809 }
28810 }
28811 /**
28812 * This is the core function which handles differences between collections.
28813 *
28814 * - `record` is the record which we saw at this position last time. If null then it is a new
28815 * item.
28816 * - `item` is the current item in the collection
28817 * - `index` is the position of the item in the collection
28818 *
28819 * @internal
28820 */
28821 _mismatch(record, item, itemTrackBy, index) {
28822 // The previous record after which we will append the current one.
28823 let previousRecord;
28824 if (record === null) {
28825 previousRecord = this._itTail;
28826 }
28827 else {
28828 previousRecord = record._prev;
28829 // Remove the record from the collection since we know it does not match the item.
28830 this._remove(record);
28831 }
28832 // See if we have evicted the item, which used to be at some anterior position of _itHead list.
28833 record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
28834 if (record !== null) {
28835 // It is an item which we have evicted earlier: reinsert it back into the list.
28836 // But first we need to check if identity changed, so we can update in view if necessary.
28837 if (!Object.is(record.item, item))
28838 this._addIdentityChange(record, item);
28839 this._reinsertAfter(record, previousRecord, index);
28840 }
28841 else {
28842 // Attempt to see if the item is at some posterior position of _itHead list.
28843 record = this._linkedRecords === null ? null : this._linkedRecords.get(itemTrackBy, index);
28844 if (record !== null) {
28845 // We have the item in _itHead at/after `index` position. We need to move it forward in the
28846 // collection.
28847 // But first we need to check if identity changed, so we can update in view if necessary.
28848 if (!Object.is(record.item, item))
28849 this._addIdentityChange(record, item);
28850 this._moveAfter(record, previousRecord, index);
28851 }
28852 else {
28853 // It is a new item: add it.
28854 record =
28855 this._addAfter(new IterableChangeRecord_(item, itemTrackBy), previousRecord, index);
28856 }
28857 }
28858 return record;
28859 }
28860 /**
28861 * This check is only needed if an array contains duplicates. (Short circuit of nothing dirty)
28862 *
28863 * Use case: `[a, a]` => `[b, a, a]`
28864 *
28865 * If we did not have this check then the insertion of `b` would:
28866 * 1) evict first `a`
28867 * 2) insert `b` at `0` index.
28868 * 3) leave `a` at index `1` as is. <-- this is wrong!
28869 * 3) reinsert `a` at index 2. <-- this is wrong!
28870 *
28871 * The correct behavior is:
28872 * 1) evict first `a`
28873 * 2) insert `b` at `0` index.
28874 * 3) reinsert `a` at index 1.
28875 * 3) move `a` at from `1` to `2`.
28876 *
28877 *
28878 * Double check that we have not evicted a duplicate item. We need to check if the item type may
28879 * have already been removed:
28880 * The insertion of b will evict the first 'a'. If we don't reinsert it now it will be reinserted
28881 * at the end. Which will show up as the two 'a's switching position. This is incorrect, since a
28882 * better way to think of it is as insert of 'b' rather then switch 'a' with 'b' and then add 'a'
28883 * at the end.
28884 *
28885 * @internal
28886 */
28887 _verifyReinsertion(record, item, itemTrackBy, index) {
28888 let reinsertRecord = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
28889 if (reinsertRecord !== null) {
28890 record = this._reinsertAfter(reinsertRecord, record._prev, index);
28891 }
28892 else if (record.currentIndex != index) {
28893 record.currentIndex = index;
28894 this._addToMoves(record, index);
28895 }
28896 return record;
28897 }
28898 /**
28899 * Get rid of any excess {@link IterableChangeRecord_}s from the previous collection
28900 *
28901 * - `record` The first excess {@link IterableChangeRecord_}.
28902 *
28903 * @internal
28904 */
28905 _truncate(record) {
28906 // Anything after that needs to be removed;
28907 while (record !== null) {
28908 const nextRecord = record._next;
28909 this._addToRemovals(this._unlink(record));
28910 record = nextRecord;
28911 }
28912 if (this._unlinkedRecords !== null) {
28913 this._unlinkedRecords.clear();
28914 }
28915 if (this._additionsTail !== null) {
28916 this._additionsTail._nextAdded = null;
28917 }
28918 if (this._movesTail !== null) {
28919 this._movesTail._nextMoved = null;
28920 }
28921 if (this._itTail !== null) {
28922 this._itTail._next = null;
28923 }
28924 if (this._removalsTail !== null) {
28925 this._removalsTail._nextRemoved = null;
28926 }
28927 if (this._identityChangesTail !== null) {
28928 this._identityChangesTail._nextIdentityChange = null;
28929 }
28930 }
28931 /** @internal */
28932 _reinsertAfter(record, prevRecord, index) {
28933 if (this._unlinkedRecords !== null) {
28934 this._unlinkedRecords.remove(record);
28935 }
28936 const prev = record._prevRemoved;
28937 const next = record._nextRemoved;
28938 if (prev === null) {
28939 this._removalsHead = next;
28940 }
28941 else {
28942 prev._nextRemoved = next;
28943 }
28944 if (next === null) {
28945 this._removalsTail = prev;
28946 }
28947 else {
28948 next._prevRemoved = prev;
28949 }
28950 this._insertAfter(record, prevRecord, index);
28951 this._addToMoves(record, index);
28952 return record;
28953 }
28954 /** @internal */
28955 _moveAfter(record, prevRecord, index) {
28956 this._unlink(record);
28957 this._insertAfter(record, prevRecord, index);
28958 this._addToMoves(record, index);
28959 return record;
28960 }
28961 /** @internal */
28962 _addAfter(record, prevRecord, index) {
28963 this._insertAfter(record, prevRecord, index);
28964 if (this._additionsTail === null) {
28965 // TODO(vicb):
28966 // assert(this._additionsHead === null);
28967 this._additionsTail = this._additionsHead = record;
28968 }
28969 else {
28970 // TODO(vicb):
28971 // assert(_additionsTail._nextAdded === null);
28972 // assert(record._nextAdded === null);
28973 this._additionsTail = this._additionsTail._nextAdded = record;
28974 }
28975 return record;
28976 }
28977 /** @internal */
28978 _insertAfter(record, prevRecord, index) {
28979 // TODO(vicb):
28980 // assert(record != prevRecord);
28981 // assert(record._next === null);
28982 // assert(record._prev === null);
28983 const next = prevRecord === null ? this._itHead : prevRecord._next;
28984 // TODO(vicb):
28985 // assert(next != record);
28986 // assert(prevRecord != record);
28987 record._next = next;
28988 record._prev = prevRecord;
28989 if (next === null) {
28990 this._itTail = record;
28991 }
28992 else {
28993 next._prev = record;
28994 }
28995 if (prevRecord === null) {
28996 this._itHead = record;
28997 }
28998 else {
28999 prevRecord._next = record;
29000 }
29001 if (this._linkedRecords === null) {
29002 this._linkedRecords = new _DuplicateMap();
29003 }
29004 this._linkedRecords.put(record);
29005 record.currentIndex = index;
29006 return record;
29007 }
29008 /** @internal */
29009 _remove(record) {
29010 return this._addToRemovals(this._unlink(record));
29011 }
29012 /** @internal */
29013 _unlink(record) {
29014 if (this._linkedRecords !== null) {
29015 this._linkedRecords.remove(record);
29016 }
29017 const prev = record._prev;
29018 const next = record._next;
29019 // TODO(vicb):
29020 // assert((record._prev = null) === null);
29021 // assert((record._next = null) === null);
29022 if (prev === null) {
29023 this._itHead = next;
29024 }
29025 else {
29026 prev._next = next;
29027 }
29028 if (next === null) {
29029 this._itTail = prev;
29030 }
29031 else {
29032 next._prev = prev;
29033 }
29034 return record;
29035 }
29036 /** @internal */
29037 _addToMoves(record, toIndex) {
29038 // TODO(vicb):
29039 // assert(record._nextMoved === null);
29040 if (record.previousIndex === toIndex) {
29041 return record;
29042 }
29043 if (this._movesTail === null) {
29044 // TODO(vicb):
29045 // assert(_movesHead === null);
29046 this._movesTail = this._movesHead = record;
29047 }
29048 else {
29049 // TODO(vicb):
29050 // assert(_movesTail._nextMoved === null);
29051 this._movesTail = this._movesTail._nextMoved = record;
29052 }
29053 return record;
29054 }
29055 _addToRemovals(record) {
29056 if (this._unlinkedRecords === null) {
29057 this._unlinkedRecords = new _DuplicateMap();
29058 }
29059 this._unlinkedRecords.put(record);
29060 record.currentIndex = null;
29061 record._nextRemoved = null;
29062 if (this._removalsTail === null) {
29063 // TODO(vicb):
29064 // assert(_removalsHead === null);
29065 this._removalsTail = this._removalsHead = record;
29066 record._prevRemoved = null;
29067 }
29068 else {
29069 // TODO(vicb):
29070 // assert(_removalsTail._nextRemoved === null);
29071 // assert(record._nextRemoved === null);
29072 record._prevRemoved = this._removalsTail;
29073 this._removalsTail = this._removalsTail._nextRemoved = record;
29074 }
29075 return record;
29076 }
29077 /** @internal */
29078 _addIdentityChange(record, item) {
29079 record.item = item;
29080 if (this._identityChangesTail === null) {
29081 this._identityChangesTail = this._identityChangesHead = record;
29082 }
29083 else {
29084 this._identityChangesTail = this._identityChangesTail._nextIdentityChange = record;
29085 }
29086 return record;
29087 }
29088}
29089class IterableChangeRecord_ {
29090 constructor(item, trackById) {
29091 this.item = item;
29092 this.trackById = trackById;
29093 this.currentIndex = null;
29094 this.previousIndex = null;
29095 /** @internal */
29096 this._nextPrevious = null;
29097 /** @internal */
29098 this._prev = null;
29099 /** @internal */
29100 this._next = null;
29101 /** @internal */
29102 this._prevDup = null;
29103 /** @internal */
29104 this._nextDup = null;
29105 /** @internal */
29106 this._prevRemoved = null;
29107 /** @internal */
29108 this._nextRemoved = null;
29109 /** @internal */
29110 this._nextAdded = null;
29111 /** @internal */
29112 this._nextMoved = null;
29113 /** @internal */
29114 this._nextIdentityChange = null;
29115 }
29116}
29117// A linked list of IterableChangeRecords with the same IterableChangeRecord_.item
29118class _DuplicateItemRecordList {
29119 constructor() {
29120 /** @internal */
29121 this._head = null;
29122 /** @internal */
29123 this._tail = null;
29124 }
29125 /**
29126 * Append the record to the list of duplicates.
29127 *
29128 * Note: by design all records in the list of duplicates hold the same value in record.item.
29129 */
29130 add(record) {
29131 if (this._head === null) {
29132 this._head = this._tail = record;
29133 record._nextDup = null;
29134 record._prevDup = null;
29135 }
29136 else {
29137 // TODO(vicb):
29138 // assert(record.item == _head.item ||
29139 // record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN);
29140 this._tail._nextDup = record;
29141 record._prevDup = this._tail;
29142 record._nextDup = null;
29143 this._tail = record;
29144 }
29145 }
29146 // Returns a IterableChangeRecord_ having IterableChangeRecord_.trackById == trackById and
29147 // IterableChangeRecord_.currentIndex >= atOrAfterIndex
29148 get(trackById, atOrAfterIndex) {
29149 let record;
29150 for (record = this._head; record !== null; record = record._nextDup) {
29151 if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex) &&
29152 Object.is(record.trackById, trackById)) {
29153 return record;
29154 }
29155 }
29156 return null;
29157 }
29158 /**
29159 * Remove one {@link IterableChangeRecord_} from the list of duplicates.
29160 *
29161 * Returns whether the list of duplicates is empty.
29162 */
29163 remove(record) {
29164 // TODO(vicb):
29165 // assert(() {
29166 // // verify that the record being removed is in the list.
29167 // for (IterableChangeRecord_ cursor = _head; cursor != null; cursor = cursor._nextDup) {
29168 // if (identical(cursor, record)) return true;
29169 // }
29170 // return false;
29171 //});
29172 const prev = record._prevDup;
29173 const next = record._nextDup;
29174 if (prev === null) {
29175 this._head = next;
29176 }
29177 else {
29178 prev._nextDup = next;
29179 }
29180 if (next === null) {
29181 this._tail = prev;
29182 }
29183 else {
29184 next._prevDup = prev;
29185 }
29186 return this._head === null;
29187 }
29188}
29189class _DuplicateMap {
29190 constructor() {
29191 this.map = new Map();
29192 }
29193 put(record) {
29194 const key = record.trackById;
29195 let duplicates = this.map.get(key);
29196 if (!duplicates) {
29197 duplicates = new _DuplicateItemRecordList();
29198 this.map.set(key, duplicates);
29199 }
29200 duplicates.add(record);
29201 }
29202 /**
29203 * Retrieve the `value` using key. Because the IterableChangeRecord_ value may be one which we
29204 * have already iterated over, we use the `atOrAfterIndex` to pretend it is not there.
29205 *
29206 * Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we
29207 * have any more `a`s needs to return the second `a`.
29208 */
29209 get(trackById, atOrAfterIndex) {
29210 const key = trackById;
29211 const recordList = this.map.get(key);
29212 return recordList ? recordList.get(trackById, atOrAfterIndex) : null;
29213 }
29214 /**
29215 * Removes a {@link IterableChangeRecord_} from the list of duplicates.
29216 *
29217 * The list of duplicates also is removed from the map if it gets empty.
29218 */
29219 remove(record) {
29220 const key = record.trackById;
29221 const recordList = this.map.get(key);
29222 // Remove the list of duplicates when it gets empty
29223 if (recordList.remove(record)) {
29224 this.map.delete(key);
29225 }
29226 return record;
29227 }
29228 get isEmpty() {
29229 return this.map.size === 0;
29230 }
29231 clear() {
29232 this.map.clear();
29233 }
29234}
29235function getPreviousIndex(item, addRemoveOffset, moveOffsets) {
29236 const previousIndex = item.previousIndex;
29237 if (previousIndex === null)
29238 return previousIndex;
29239 let moveOffset = 0;
29240 if (moveOffsets && previousIndex < moveOffsets.length) {
29241 moveOffset = moveOffsets[previousIndex];
29242 }
29243 return previousIndex + addRemoveOffset + moveOffset;
29244}
29245
29246/**
29247 * @license
29248 * Copyright Google LLC All Rights Reserved.
29249 *
29250 * Use of this source code is governed by an MIT-style license that can be
29251 * found in the LICENSE file at https://angular.io/license
29252 */
29253class DefaultKeyValueDifferFactory {
29254 constructor() { }
29255 supports(obj) {
29256 return obj instanceof Map || isJsObject(obj);
29257 }
29258 create() {
29259 return new DefaultKeyValueDiffer();
29260 }
29261}
29262class DefaultKeyValueDiffer {
29263 constructor() {
29264 this._records = new Map();
29265 this._mapHead = null;
29266 // _appendAfter is used in the check loop
29267 this._appendAfter = null;
29268 this._previousMapHead = null;
29269 this._changesHead = null;
29270 this._changesTail = null;
29271 this._additionsHead = null;
29272 this._additionsTail = null;
29273 this._removalsHead = null;
29274 this._removalsTail = null;
29275 }
29276 get isDirty() {
29277 return this._additionsHead !== null || this._changesHead !== null ||
29278 this._removalsHead !== null;
29279 }
29280 forEachItem(fn) {
29281 let record;
29282 for (record = this._mapHead; record !== null; record = record._next) {
29283 fn(record);
29284 }
29285 }
29286 forEachPreviousItem(fn) {
29287 let record;
29288 for (record = this._previousMapHead; record !== null; record = record._nextPrevious) {
29289 fn(record);
29290 }
29291 }
29292 forEachChangedItem(fn) {
29293 let record;
29294 for (record = this._changesHead; record !== null; record = record._nextChanged) {
29295 fn(record);
29296 }
29297 }
29298 forEachAddedItem(fn) {
29299 let record;
29300 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
29301 fn(record);
29302 }
29303 }
29304 forEachRemovedItem(fn) {
29305 let record;
29306 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
29307 fn(record);
29308 }
29309 }
29310 diff(map) {
29311 if (!map) {
29312 map = new Map();
29313 }
29314 else if (!(map instanceof Map || isJsObject(map))) {
29315 throw new RuntimeError(900 /* RuntimeErrorCode.INVALID_DIFFER_INPUT */, ngDevMode &&
29316 `Error trying to diff '${stringify(map)}'. Only maps and objects are allowed`);
29317 }
29318 return this.check(map) ? this : null;
29319 }
29320 onDestroy() { }
29321 /**
29322 * Check the current state of the map vs the previous.
29323 * The algorithm is optimised for when the keys do no change.
29324 */
29325 check(map) {
29326 this._reset();
29327 let insertBefore = this._mapHead;
29328 this._appendAfter = null;
29329 this._forEach(map, (value, key) => {
29330 if (insertBefore && insertBefore.key === key) {
29331 this._maybeAddToChanges(insertBefore, value);
29332 this._appendAfter = insertBefore;
29333 insertBefore = insertBefore._next;
29334 }
29335 else {
29336 const record = this._getOrCreateRecordForKey(key, value);
29337 insertBefore = this._insertBeforeOrAppend(insertBefore, record);
29338 }
29339 });
29340 // Items remaining at the end of the list have been deleted
29341 if (insertBefore) {
29342 if (insertBefore._prev) {
29343 insertBefore._prev._next = null;
29344 }
29345 this._removalsHead = insertBefore;
29346 for (let record = insertBefore; record !== null; record = record._nextRemoved) {
29347 if (record === this._mapHead) {
29348 this._mapHead = null;
29349 }
29350 this._records.delete(record.key);
29351 record._nextRemoved = record._next;
29352 record.previousValue = record.currentValue;
29353 record.currentValue = null;
29354 record._prev = null;
29355 record._next = null;
29356 }
29357 }
29358 // Make sure tails have no next records from previous runs
29359 if (this._changesTail)
29360 this._changesTail._nextChanged = null;
29361 if (this._additionsTail)
29362 this._additionsTail._nextAdded = null;
29363 return this.isDirty;
29364 }
29365 /**
29366 * Inserts a record before `before` or append at the end of the list when `before` is null.
29367 *
29368 * Notes:
29369 * - This method appends at `this._appendAfter`,
29370 * - This method updates `this._appendAfter`,
29371 * - The return value is the new value for the insertion pointer.
29372 */
29373 _insertBeforeOrAppend(before, record) {
29374 if (before) {
29375 const prev = before._prev;
29376 record._next = before;
29377 record._prev = prev;
29378 before._prev = record;
29379 if (prev) {
29380 prev._next = record;
29381 }
29382 if (before === this._mapHead) {
29383 this._mapHead = record;
29384 }
29385 this._appendAfter = before;
29386 return before;
29387 }
29388 if (this._appendAfter) {
29389 this._appendAfter._next = record;
29390 record._prev = this._appendAfter;
29391 }
29392 else {
29393 this._mapHead = record;
29394 }
29395 this._appendAfter = record;
29396 return null;
29397 }
29398 _getOrCreateRecordForKey(key, value) {
29399 if (this._records.has(key)) {
29400 const record = this._records.get(key);
29401 this._maybeAddToChanges(record, value);
29402 const prev = record._prev;
29403 const next = record._next;
29404 if (prev) {
29405 prev._next = next;
29406 }
29407 if (next) {
29408 next._prev = prev;
29409 }
29410 record._next = null;
29411 record._prev = null;
29412 return record;
29413 }
29414 const record = new KeyValueChangeRecord_(key);
29415 this._records.set(key, record);
29416 record.currentValue = value;
29417 this._addToAdditions(record);
29418 return record;
29419 }
29420 /** @internal */
29421 _reset() {
29422 if (this.isDirty) {
29423 let record;
29424 // let `_previousMapHead` contain the state of the map before the changes
29425 this._previousMapHead = this._mapHead;
29426 for (record = this._previousMapHead; record !== null; record = record._next) {
29427 record._nextPrevious = record._next;
29428 }
29429 // Update `record.previousValue` with the value of the item before the changes
29430 // We need to update all changed items (that's those which have been added and changed)
29431 for (record = this._changesHead; record !== null; record = record._nextChanged) {
29432 record.previousValue = record.currentValue;
29433 }
29434 for (record = this._additionsHead; record != null; record = record._nextAdded) {
29435 record.previousValue = record.currentValue;
29436 }
29437 this._changesHead = this._changesTail = null;
29438 this._additionsHead = this._additionsTail = null;
29439 this._removalsHead = null;
29440 }
29441 }
29442 // Add the record or a given key to the list of changes only when the value has actually changed
29443 _maybeAddToChanges(record, newValue) {
29444 if (!Object.is(newValue, record.currentValue)) {
29445 record.previousValue = record.currentValue;
29446 record.currentValue = newValue;
29447 this._addToChanges(record);
29448 }
29449 }
29450 _addToAdditions(record) {
29451 if (this._additionsHead === null) {
29452 this._additionsHead = this._additionsTail = record;
29453 }
29454 else {
29455 this._additionsTail._nextAdded = record;
29456 this._additionsTail = record;
29457 }
29458 }
29459 _addToChanges(record) {
29460 if (this._changesHead === null) {
29461 this._changesHead = this._changesTail = record;
29462 }
29463 else {
29464 this._changesTail._nextChanged = record;
29465 this._changesTail = record;
29466 }
29467 }
29468 /** @internal */
29469 _forEach(obj, fn) {
29470 if (obj instanceof Map) {
29471 obj.forEach(fn);
29472 }
29473 else {
29474 Object.keys(obj).forEach(k => fn(obj[k], k));
29475 }
29476 }
29477}
29478class KeyValueChangeRecord_ {
29479 constructor(key) {
29480 this.key = key;
29481 this.previousValue = null;
29482 this.currentValue = null;
29483 /** @internal */
29484 this._nextPrevious = null;
29485 /** @internal */
29486 this._next = null;
29487 /** @internal */
29488 this._prev = null;
29489 /** @internal */
29490 this._nextAdded = null;
29491 /** @internal */
29492 this._nextRemoved = null;
29493 /** @internal */
29494 this._nextChanged = null;
29495 }
29496}
29497
29498/**
29499 * @license
29500 * Copyright Google LLC All Rights Reserved.
29501 *
29502 * Use of this source code is governed by an MIT-style license that can be
29503 * found in the LICENSE file at https://angular.io/license
29504 */
29505function defaultIterableDiffersFactory() {
29506 return new IterableDiffers([new DefaultIterableDifferFactory()]);
29507}
29508/**
29509 * A repository of different iterable diffing strategies used by NgFor, NgClass, and others.
29510 *
29511 * @publicApi
29512 */
29513class IterableDiffers {
29514 constructor(factories) {
29515 this.factories = factories;
29516 }
29517 static create(factories, parent) {
29518 if (parent != null) {
29519 const copied = parent.factories.slice();
29520 factories = factories.concat(copied);
29521 }
29522 return new IterableDiffers(factories);
29523 }
29524 /**
29525 * Takes an array of {@link IterableDifferFactory} and returns a provider used to extend the
29526 * inherited {@link IterableDiffers} instance with the provided factories and return a new
29527 * {@link IterableDiffers} instance.
29528 *
29529 * @usageNotes
29530 * ### Example
29531 *
29532 * The following example shows how to extend an existing list of factories,
29533 * which will only be applied to the injector for this component and its children.
29534 * This step is all that's required to make a new {@link IterableDiffer} available.
29535 *
29536 * ```
29537 * @Component({
29538 * viewProviders: [
29539 * IterableDiffers.extend([new ImmutableListDiffer()])
29540 * ]
29541 * })
29542 * ```
29543 */
29544 static extend(factories) {
29545 return {
29546 provide: IterableDiffers,
29547 useFactory: (parent) => {
29548 // if parent is null, it means that we are in the root injector and we have just overridden
29549 // the default injection mechanism for IterableDiffers, in such a case just assume
29550 // `defaultIterableDiffersFactory`.
29551 return IterableDiffers.create(factories, parent || defaultIterableDiffersFactory());
29552 },
29553 // Dependency technically isn't optional, but we can provide a better error message this way.
29554 deps: [[IterableDiffers, new SkipSelf(), new Optional()]]
29555 };
29556 }
29557 find(iterable) {
29558 const factory = this.factories.find(f => f.supports(iterable));
29559 if (factory != null) {
29560 return factory;
29561 }
29562 else {
29563 throw new RuntimeError(901 /* RuntimeErrorCode.NO_SUPPORTING_DIFFER_FACTORY */, ngDevMode &&
29564 `Cannot find a differ supporting object '${iterable}' of type '${getTypeNameForDebugging(iterable)}'`);
29565 }
29566 }
29567}
29568/** @nocollapse */
29569IterableDiffers.ɵprov = ɵɵdefineInjectable({ token: IterableDiffers, providedIn: 'root', factory: defaultIterableDiffersFactory });
29570function getTypeNameForDebugging(type) {
29571 return type['name'] || typeof type;
29572}
29573
29574/**
29575 * @license
29576 * Copyright Google LLC All Rights Reserved.
29577 *
29578 * Use of this source code is governed by an MIT-style license that can be
29579 * found in the LICENSE file at https://angular.io/license
29580 */
29581function defaultKeyValueDiffersFactory() {
29582 return new KeyValueDiffers([new DefaultKeyValueDifferFactory()]);
29583}
29584/**
29585 * A repository of different Map diffing strategies used by NgClass, NgStyle, and others.
29586 *
29587 * @publicApi
29588 */
29589class KeyValueDiffers {
29590 constructor(factories) {
29591 this.factories = factories;
29592 }
29593 static create(factories, parent) {
29594 if (parent) {
29595 const copied = parent.factories.slice();
29596 factories = factories.concat(copied);
29597 }
29598 return new KeyValueDiffers(factories);
29599 }
29600 /**
29601 * Takes an array of {@link KeyValueDifferFactory} and returns a provider used to extend the
29602 * inherited {@link KeyValueDiffers} instance with the provided factories and return a new
29603 * {@link KeyValueDiffers} instance.
29604 *
29605 * @usageNotes
29606 * ### Example
29607 *
29608 * The following example shows how to extend an existing list of factories,
29609 * which will only be applied to the injector for this component and its children.
29610 * This step is all that's required to make a new {@link KeyValueDiffer} available.
29611 *
29612 * ```
29613 * @Component({
29614 * viewProviders: [
29615 * KeyValueDiffers.extend([new ImmutableMapDiffer()])
29616 * ]
29617 * })
29618 * ```
29619 */
29620 static extend(factories) {
29621 return {
29622 provide: KeyValueDiffers,
29623 useFactory: (parent) => {
29624 // if parent is null, it means that we are in the root injector and we have just overridden
29625 // the default injection mechanism for KeyValueDiffers, in such a case just assume
29626 // `defaultKeyValueDiffersFactory`.
29627 return KeyValueDiffers.create(factories, parent || defaultKeyValueDiffersFactory());
29628 },
29629 // Dependency technically isn't optional, but we can provide a better error message this way.
29630 deps: [[KeyValueDiffers, new SkipSelf(), new Optional()]]
29631 };
29632 }
29633 find(kv) {
29634 const factory = this.factories.find(f => f.supports(kv));
29635 if (factory) {
29636 return factory;
29637 }
29638 throw new RuntimeError(901 /* RuntimeErrorCode.NO_SUPPORTING_DIFFER_FACTORY */, ngDevMode && `Cannot find a differ supporting object '${kv}'`);
29639 }
29640}
29641/** @nocollapse */
29642KeyValueDiffers.ɵprov = ɵɵdefineInjectable({ token: KeyValueDiffers, providedIn: 'root', factory: defaultKeyValueDiffersFactory });
29643
29644/**
29645 * @license
29646 * Copyright Google LLC All Rights Reserved.
29647 *
29648 * Use of this source code is governed by an MIT-style license that can be
29649 * found in the LICENSE file at https://angular.io/license
29650 */
29651/**
29652 * Structural diffing for `Object`s and `Map`s.
29653 */
29654const keyValDiff = [new DefaultKeyValueDifferFactory()];
29655/**
29656 * Structural diffing for `Iterable` types such as `Array`s.
29657 */
29658const iterableDiff = [new DefaultIterableDifferFactory()];
29659const defaultIterableDiffers = new IterableDiffers(iterableDiff);
29660const defaultKeyValueDiffers = new KeyValueDiffers(keyValDiff);
29661
29662/**
29663 * @license
29664 * Copyright Google LLC All Rights Reserved.
29665 *
29666 * Use of this source code is governed by an MIT-style license that can be
29667 * found in the LICENSE file at https://angular.io/license
29668 */
29669
29670/**
29671 * @license
29672 * Copyright Google LLC All Rights Reserved.
29673 *
29674 * Use of this source code is governed by an MIT-style license that can be
29675 * found in the LICENSE file at https://angular.io/license
29676 */
29677/**
29678 * This platform has to be included in any other platform
29679 *
29680 * @publicApi
29681 */
29682const platformCore = createPlatformFactory(null, 'core', []);
29683
29684/**
29685 * Re-exported by `BrowserModule`, which is included automatically in the root
29686 * `AppModule` when you create a new app with the CLI `new` command. Eagerly injects
29687 * `ApplicationRef` to instantiate it.
29688 *
29689 * @publicApi
29690 */
29691class ApplicationModule {
29692 // Inject ApplicationRef to make it eager...
29693 constructor(appRef) { }
29694}
29695ApplicationModule.ɵfac = function ApplicationModule_Factory(t) { return new (t || ApplicationModule)(ɵɵinject(ApplicationRef)); };
29696ApplicationModule.ɵmod = /*@__PURE__*/ ɵɵdefineNgModule({ type: ApplicationModule });
29697ApplicationModule.ɵinj = /*@__PURE__*/ ɵɵdefineInjector({});
29698(function () {
29699 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationModule, [{
29700 type: NgModule
29701 }], function () { return [{ type: ApplicationRef }]; }, null);
29702})();
29703
29704/**
29705 * @license
29706 * Copyright Google LLC All Rights Reserved.
29707 *
29708 * Use of this source code is governed by an MIT-style license that can be
29709 * found in the LICENSE file at https://angular.io/license
29710 */
29711/** Coerces a value (typically a string) to a boolean. */
29712function coerceToBoolean(value) {
29713 return typeof value === 'boolean' ? value : (value != null && value !== 'false');
29714}
29715
29716/**
29717 * @license
29718 * Copyright Google LLC All Rights Reserved.
29719 *
29720 * Use of this source code is governed by an MIT-style license that can be
29721 * found in the LICENSE file at https://angular.io/license
29722 */
29723// TODO(alxhub): allows tests to compile, can be removed when tests have been updated.
29724const ɵivyEnabled = true;
29725
29726/**
29727 * @license
29728 * Copyright Google LLC All Rights Reserved.
29729 *
29730 * Use of this source code is governed by an MIT-style license that can be
29731 * found in the LICENSE file at https://angular.io/license
29732 */
29733/**
29734 * Compiles a partial directive declaration object into a full directive definition object.
29735 *
29736 * @codeGenApi
29737 */
29738function ɵɵngDeclareDirective(decl) {
29739 const compiler = getCompilerFacade({ usage: 1 /* JitCompilerUsage.PartialDeclaration */, kind: 'directive', type: decl.type });
29740 return compiler.compileDirectiveDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl);
29741}
29742/**
29743 * Evaluates the class metadata declaration.
29744 *
29745 * @codeGenApi
29746 */
29747function ɵɵngDeclareClassMetadata(decl) {
29748 var _a, _b;
29749 setClassMetadata(decl.type, decl.decorators, (_a = decl.ctorParameters) !== null && _a !== void 0 ? _a : null, (_b = decl.propDecorators) !== null && _b !== void 0 ? _b : null);
29750}
29751/**
29752 * Compiles a partial component declaration object into a full component definition object.
29753 *
29754 * @codeGenApi
29755 */
29756function ɵɵngDeclareComponent(decl) {
29757 const compiler = getCompilerFacade({ usage: 1 /* JitCompilerUsage.PartialDeclaration */, kind: 'component', type: decl.type });
29758 return compiler.compileComponentDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵcmp.js`, decl);
29759}
29760/**
29761 * Compiles a partial pipe declaration object into a full pipe definition object.
29762 *
29763 * @codeGenApi
29764 */
29765function ɵɵngDeclareFactory(decl) {
29766 const compiler = getCompilerFacade({
29767 usage: 1 /* JitCompilerUsage.PartialDeclaration */,
29768 kind: getFactoryKind(decl.target),
29769 type: decl.type
29770 });
29771 return compiler.compileFactoryDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl);
29772}
29773function getFactoryKind(target) {
29774 switch (target) {
29775 case FactoryTarget.Directive:
29776 return 'directive';
29777 case FactoryTarget.Component:
29778 return 'component';
29779 case FactoryTarget.Injectable:
29780 return 'injectable';
29781 case FactoryTarget.Pipe:
29782 return 'pipe';
29783 case FactoryTarget.NgModule:
29784 return 'NgModule';
29785 }
29786}
29787/**
29788 * Compiles a partial injectable declaration object into a full injectable definition object.
29789 *
29790 * @codeGenApi
29791 */
29792function ɵɵngDeclareInjectable(decl) {
29793 const compiler = getCompilerFacade({ usage: 1 /* JitCompilerUsage.PartialDeclaration */, kind: 'injectable', type: decl.type });
29794 return compiler.compileInjectableDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵprov.js`, decl);
29795}
29796/**
29797 * Compiles a partial injector declaration object into a full injector definition object.
29798 *
29799 * @codeGenApi
29800 */
29801function ɵɵngDeclareInjector(decl) {
29802 const compiler = getCompilerFacade({ usage: 1 /* JitCompilerUsage.PartialDeclaration */, kind: 'NgModule', type: decl.type });
29803 return compiler.compileInjectorDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵinj.js`, decl);
29804}
29805/**
29806 * Compiles a partial NgModule declaration object into a full NgModule definition object.
29807 *
29808 * @codeGenApi
29809 */
29810function ɵɵngDeclareNgModule(decl) {
29811 const compiler = getCompilerFacade({ usage: 1 /* JitCompilerUsage.PartialDeclaration */, kind: 'NgModule', type: decl.type });
29812 return compiler.compileNgModuleDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵmod.js`, decl);
29813}
29814/**
29815 * Compiles a partial pipe declaration object into a full pipe definition object.
29816 *
29817 * @codeGenApi
29818 */
29819function ɵɵngDeclarePipe(decl) {
29820 const compiler = getCompilerFacade({ usage: 1 /* JitCompilerUsage.PartialDeclaration */, kind: 'pipe', type: decl.type });
29821 return compiler.compilePipeDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵpipe.js`, decl);
29822}
29823
29824/**
29825 * @license
29826 * Copyright Google LLC All Rights Reserved.
29827 *
29828 * Use of this source code is governed by an MIT-style license that can be
29829 * found in the LICENSE file at https://angular.io/license
29830 */
29831// clang-format on
29832
29833/**
29834 * @license
29835 * Copyright Google LLC All Rights Reserved.
29836 *
29837 * Use of this source code is governed by an MIT-style license that can be
29838 * found in the LICENSE file at https://angular.io/license
29839 */
29840if (typeof ngDevMode !== 'undefined' && ngDevMode) {
29841 // This helper is to give a reasonable error message to people upgrading to v9 that have not yet
29842 // installed `@angular/localize` in their app.
29843 // tslint:disable-next-line: no-toplevel-property-access
29844 _global.$localize = _global.$localize || function () {
29845 throw new Error('It looks like your application or one of its dependencies is using i18n.\n' +
29846 'Angular 9 introduced a global `$localize()` function that needs to be loaded.\n' +
29847 'Please run `ng add @angular/localize` from the Angular CLI.\n' +
29848 '(For non-CLI projects, add `import \'@angular/localize/init\';` to your `polyfills.ts` file.\n' +
29849 'For server-side rendering applications add the import to your `main.server.ts` file.)');
29850 };
29851}
29852
29853/**
29854 * @license
29855 * Copyright Google LLC All Rights Reserved.
29856 *
29857 * Use of this source code is governed by an MIT-style license that can be
29858 * found in the LICENSE file at https://angular.io/license
29859 */
29860// This file only reexports content of the `src` folder. Keep it that way.
29861
29862/**
29863 * @license
29864 * Copyright Google LLC All Rights Reserved.
29865 *
29866 * Use of this source code is governed by an MIT-style license that can be
29867 * found in the LICENSE file at https://angular.io/license
29868 */
29869
29870/**
29871 * Generated bundle index. Do not edit.
29872 */
29873
29874export { ANALYZE_FOR_ENTRY_COMPONENTS, ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory$1 as ComponentFactory, ComponentFactoryResolver$1 as ComponentFactoryResolver, ComponentRef$1 as ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, Directive, ENVIRONMENT_INITIALIZER, ElementRef, EmbeddedViewRef, EnvironmentInjector, ErrorHandler, EventEmitter, Host, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory$1 as NgModuleFactory, NgModuleRef$1 as NgModuleRef, NgProbeToken, NgZone, Optional, Output, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, ReflectiveInjector, ReflectiveKey, Renderer2, RendererFactory2, RendererStyleFlags2, ResolvedReflectiveFactory, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, asNativeElements, assertPlatform, createEnvironmentInjector, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, isDevMode, platformCore, resolveForwardRef, setTestabilityGetter, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER, ChangeDetectorStatus as ɵChangeDetectorStatus, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, LContext as ɵLContext, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, ViewRef$1 as ɵViewRef, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, coerceToBoolean as ɵcoerceToBoolean, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory as ɵcompileNgModuleFactory, compilePipe as ɵcompilePipe, createInjector as ɵcreateInjector, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, getDebugNode as ɵgetDebugNode, getDebugNodeR2 as ɵgetDebugNodeR2, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalBootstrapApplication as ɵinternalBootstrapApplication, isBoundToModule as ɵisBoundToModule, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy, isListLikeIterable as ɵisListLikeIterable, isObservable as ɵisObservable, isPromise as ɵisPromise, isStandalone as ɵisStandalone, isSubscribable as ɵisSubscribable, ɵivyEnabled, makeDecorator as ɵmakeDecorator, markDirty as ɵmarkDirty, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, publishDefaultGlobalUtils$1 as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, registerLocaleData as ɵregisterLocaleData, renderComponent as ɵrenderComponent, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setClassMetadata as ɵsetClassMetadata, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, whenRendered as ɵwhenRendered, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵInheritDefinitionFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcontentQuery, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵviewQuery };
29875//# sourceMappingURL=core.mjs.map