UNPKG

1.16 MBJavaScriptView Raw
1/**
2 * @license Angular v13.3.9
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 : ''}`;
185 if (ngDevMode && code < 0) {
186 errorMessage = `${errorMessage}. Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
187 }
188 return errorMessage;
189}
190
191/**
192 * @license
193 * Copyright Google LLC All Rights Reserved.
194 *
195 * Use of this source code is governed by an MIT-style license that can be
196 * found in the LICENSE file at https://angular.io/license
197 */
198/**
199 * Used for stringify render output in Ivy.
200 * Important! This function is very performance-sensitive and we should
201 * be extra careful not to introduce megamorphic reads in it.
202 * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations.
203 */
204function renderStringify(value) {
205 if (typeof value === 'string')
206 return value;
207 if (value == null)
208 return '';
209 // Use `String` so that it invokes the `toString` method of the value. Note that this
210 // appears to be faster than calling `value.toString` (see `render_stringify` benchmark).
211 return String(value);
212}
213/**
214 * Used to stringify a value so that it can be displayed in an error message.
215 * Important! This function contains a megamorphic read and should only be
216 * used for error messages.
217 */
218function stringifyForError(value) {
219 if (typeof value === 'function')
220 return value.name || value.toString();
221 if (typeof value === 'object' && value != null && typeof value.type === 'function') {
222 return value.type.name || value.type.toString();
223 }
224 return renderStringify(value);
225}
226
227/**
228 * @license
229 * Copyright Google LLC All Rights Reserved.
230 *
231 * Use of this source code is governed by an MIT-style license that can be
232 * found in the LICENSE file at https://angular.io/license
233 */
234/** Called when directives inject each other (creating a circular dependency) */
235function throwCyclicDependencyError(token, path) {
236 const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
237 throw new RuntimeError(-200 /* CYCLIC_DI_DEPENDENCY */, `Circular dependency in DI detected for ${token}${depPath}`);
238}
239function throwMixedMultiProviderError() {
240 throw new Error(`Cannot mix multi providers and regular providers`);
241}
242function throwInvalidProviderError(ngModuleType, providers, provider) {
243 let ngModuleDetail = '';
244 if (ngModuleType && providers) {
245 const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...');
246 ngModuleDetail =
247 ` - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`;
248 }
249 throw new Error(`Invalid provider for the NgModule '${stringify(ngModuleType)}'` + ngModuleDetail);
250}
251/** Throws an error when a token is not found in DI. */
252function throwProviderNotFoundError(token, injectorName) {
253 const injectorDetails = injectorName ? ` in ${injectorName}` : '';
254 throw new RuntimeError(-201 /* PROVIDER_NOT_FOUND */, `No provider for ${stringifyForError(token)} found${injectorDetails}`);
255}
256
257/**
258 * @license
259 * Copyright Google LLC All Rights Reserved.
260 *
261 * Use of this source code is governed by an MIT-style license that can be
262 * found in the LICENSE file at https://angular.io/license
263 */
264function assertNumber(actual, msg) {
265 if (!(typeof actual === 'number')) {
266 throwError(msg, typeof actual, 'number', '===');
267 }
268}
269function assertNumberInRange(actual, minInclusive, maxInclusive) {
270 assertNumber(actual, 'Expected a number');
271 assertLessThanOrEqual(actual, maxInclusive, 'Expected number to be less than or equal to');
272 assertGreaterThanOrEqual(actual, minInclusive, 'Expected number to be greater than or equal to');
273}
274function assertString(actual, msg) {
275 if (!(typeof actual === 'string')) {
276 throwError(msg, actual === null ? 'null' : typeof actual, 'string', '===');
277 }
278}
279function assertFunction(actual, msg) {
280 if (!(typeof actual === 'function')) {
281 throwError(msg, actual === null ? 'null' : typeof actual, 'function', '===');
282 }
283}
284function assertEqual(actual, expected, msg) {
285 if (!(actual == expected)) {
286 throwError(msg, actual, expected, '==');
287 }
288}
289function assertNotEqual(actual, expected, msg) {
290 if (!(actual != expected)) {
291 throwError(msg, actual, expected, '!=');
292 }
293}
294function assertSame(actual, expected, msg) {
295 if (!(actual === expected)) {
296 throwError(msg, actual, expected, '===');
297 }
298}
299function assertNotSame(actual, expected, msg) {
300 if (!(actual !== expected)) {
301 throwError(msg, actual, expected, '!==');
302 }
303}
304function assertLessThan(actual, expected, msg) {
305 if (!(actual < expected)) {
306 throwError(msg, actual, expected, '<');
307 }
308}
309function assertLessThanOrEqual(actual, expected, msg) {
310 if (!(actual <= expected)) {
311 throwError(msg, actual, expected, '<=');
312 }
313}
314function assertGreaterThan(actual, expected, msg) {
315 if (!(actual > expected)) {
316 throwError(msg, actual, expected, '>');
317 }
318}
319function assertGreaterThanOrEqual(actual, expected, msg) {
320 if (!(actual >= expected)) {
321 throwError(msg, actual, expected, '>=');
322 }
323}
324function assertNotDefined(actual, msg) {
325 if (actual != null) {
326 throwError(msg, actual, null, '==');
327 }
328}
329function assertDefined(actual, msg) {
330 if (actual == null) {
331 throwError(msg, actual, null, '!=');
332 }
333}
334function throwError(msg, actual, expected, comparison) {
335 throw new Error(`ASSERTION ERROR: ${msg}` +
336 (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
337}
338function assertDomNode(node) {
339 // If we're in a worker, `Node` will not be defined.
340 if (!(typeof Node !== 'undefined' && node instanceof Node) &&
341 !(typeof node === 'object' && node != null &&
342 node.constructor.name === 'WebWorkerRenderNode')) {
343 throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
344 }
345}
346function assertIndexInRange(arr, index) {
347 assertDefined(arr, 'Array must be defined.');
348 const maxLen = arr.length;
349 if (index < 0 || index >= maxLen) {
350 throwError(`Index expected to be less than ${maxLen} but got ${index}`);
351 }
352}
353function assertOneOf(value, ...validValues) {
354 if (validValues.indexOf(value) !== -1)
355 return true;
356 throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${JSON.stringify(value)}.`);
357}
358
359/**
360 * @license
361 * Copyright Google LLC All Rights Reserved.
362 *
363 * Use of this source code is governed by an MIT-style license that can be
364 * found in the LICENSE file at https://angular.io/license
365 */
366/**
367 * Construct an injectable definition which defines how a token will be constructed by the DI
368 * system, and in which injectors (if any) it will be available.
369 *
370 * This should be assigned to a static `ɵprov` field on a type, which will then be an
371 * `InjectableType`.
372 *
373 * Options:
374 * * `providedIn` determines which injectors will include the injectable, by either associating it
375 * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
376 * provided in the `'root'` injector, which will be the application-level injector in most apps.
377 * * `factory` gives the zero argument function which will create an instance of the injectable.
378 * The factory can call `inject` to access the `Injector` and request injection of dependencies.
379 *
380 * @codeGenApi
381 * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
382 */
383function ɵɵdefineInjectable(opts) {
384 return {
385 token: opts.token,
386 providedIn: opts.providedIn || null,
387 factory: opts.factory,
388 value: undefined,
389 };
390}
391/**
392 * @deprecated in v8, delete after v10. This API should be used only by generated code, and that
393 * code should now use ɵɵdefineInjectable instead.
394 * @publicApi
395 */
396const defineInjectable = ɵɵdefineInjectable;
397/**
398 * Construct an `InjectorDef` which configures an injector.
399 *
400 * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
401 * `InjectorType`.
402 *
403 * Options:
404 *
405 * * `providers`: an optional array of providers to add to the injector. Each provider must
406 * either have a factory or point to a type which has a `ɵprov` static property (the
407 * type must be an `InjectableType`).
408 * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
409 * whose providers will also be added to the injector. Locally provided types will override
410 * providers from imports.
411 *
412 * @codeGenApi
413 */
414function ɵɵdefineInjector(options) {
415 return { providers: options.providers || [], imports: options.imports || [] };
416}
417/**
418 * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
419 * inherited value.
420 *
421 * @param type A type which may have its own (non-inherited) `ɵprov`.
422 */
423function getInjectableDef(type) {
424 return getOwnDefinition(type, NG_PROV_DEF) || getOwnDefinition(type, NG_INJECTABLE_DEF);
425}
426/**
427 * Return definition only if it is defined directly on `type` and is not inherited from a base
428 * class of `type`.
429 */
430function getOwnDefinition(type, field) {
431 return type.hasOwnProperty(field) ? type[field] : null;
432}
433/**
434 * Read the injectable def (`ɵprov`) for `type` or read the `ɵprov` from one of its ancestors.
435 *
436 * @param type A type which may have `ɵprov`, via inheritance.
437 *
438 * @deprecated Will be removed in a future version of Angular, where an error will occur in the
439 * scenario if we find the `ɵprov` on an ancestor only.
440 */
441function getInheritedInjectableDef(type) {
442 const def = type && (type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF]);
443 if (def) {
444 const typeName = getTypeName(type);
445 // TODO(FW-1307): Re-add ngDevMode when closure can handle it
446 // ngDevMode &&
447 console.warn(`DEPRECATED: DI is instantiating a token "${typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` +
448 `This will become an error in a future version of Angular. Please add @Injectable() to the "${typeName}" class.`);
449 return def;
450 }
451 else {
452 return null;
453 }
454}
455/** Gets the name of a type, accounting for some cross-browser differences. */
456function getTypeName(type) {
457 // `Function.prototype.name` behaves differently between IE and other browsers. In most browsers
458 // it'll always return the name of the function itself, no matter how many other functions it
459 // inherits from. On IE the function doesn't have its own `name` property, but it takes it from
460 // the lowest level in the prototype chain. E.g. if we have `class Foo extends Parent` most
461 // browsers will evaluate `Foo.name` to `Foo` while IE will return `Parent`. We work around
462 // the issue by converting the function to a string and parsing its name out that way via a regex.
463 if (type.hasOwnProperty('name')) {
464 return type.name;
465 }
466 const match = ('' + type).match(/^function\s*([^\s(]+)/);
467 return match === null ? '' : match[1];
468}
469/**
470 * Read the injector def type in a way which is immune to accidentally reading inherited value.
471 *
472 * @param type type which may have an injector def (`ɵinj`)
473 */
474function getInjectorDef(type) {
475 return type && (type.hasOwnProperty(NG_INJ_DEF) || type.hasOwnProperty(NG_INJECTOR_DEF)) ?
476 type[NG_INJ_DEF] :
477 null;
478}
479const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty });
480const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty });
481// We need to keep these around so we can read off old defs if new defs are unavailable
482const NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty });
483const NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty });
484
485/**
486 * @license
487 * Copyright Google LLC All Rights Reserved.
488 *
489 * Use of this source code is governed by an MIT-style license that can be
490 * found in the LICENSE file at https://angular.io/license
491 */
492/**
493 * Injection flags for DI.
494 *
495 * @publicApi
496 */
497var InjectFlags;
498(function (InjectFlags) {
499 // TODO(alxhub): make this 'const' (and remove `InternalInjectFlags` enum) when ngc no longer
500 // writes exports of it into ngfactory files.
501 /** Check self and check parent injector if needed */
502 InjectFlags[InjectFlags["Default"] = 0] = "Default";
503 /**
504 * Specifies that an injector should retrieve a dependency from any injector until reaching the
505 * host element of the current component. (Only used with Element Injector)
506 */
507 InjectFlags[InjectFlags["Host"] = 1] = "Host";
508 /** Don't ascend to ancestors of the node requesting injection. */
509 InjectFlags[InjectFlags["Self"] = 2] = "Self";
510 /** Skip the node that is requesting injection. */
511 InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf";
512 /** Inject `defaultValue` instead if token not found. */
513 InjectFlags[InjectFlags["Optional"] = 8] = "Optional";
514})(InjectFlags || (InjectFlags = {}));
515
516/**
517 * @license
518 * Copyright Google LLC All Rights Reserved.
519 *
520 * Use of this source code is governed by an MIT-style license that can be
521 * found in the LICENSE file at https://angular.io/license
522 */
523/**
524 * Current implementation of inject.
525 *
526 * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
527 * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
528 * way for two reasons:
529 * 1. `Injector` should not depend on ivy logic.
530 * 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
531 */
532let _injectImplementation;
533function getInjectImplementation() {
534 return _injectImplementation;
535}
536/**
537 * Sets the current inject implementation.
538 */
539function setInjectImplementation(impl) {
540 const previous = _injectImplementation;
541 _injectImplementation = impl;
542 return previous;
543}
544/**
545 * Injects `root` tokens in limp mode.
546 *
547 * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
548 * `"root"`. This is known as the limp mode injection. In such case the value is stored in the
549 * injectable definition.
550 */
551function injectRootLimpMode(token, notFoundValue, flags) {
552 const injectableDef = getInjectableDef(token);
553 if (injectableDef && injectableDef.providedIn == 'root') {
554 return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
555 injectableDef.value;
556 }
557 if (flags & InjectFlags.Optional)
558 return null;
559 if (notFoundValue !== undefined)
560 return notFoundValue;
561 throwProviderNotFoundError(stringify(token), 'Injector');
562}
563/**
564 * Assert that `_injectImplementation` is not `fn`.
565 *
566 * This is useful, to prevent infinite recursion.
567 *
568 * @param fn Function which it should not equal to
569 */
570function assertInjectImplementationNotEqual(fn) {
571 ngDevMode &&
572 assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion');
573}
574
575/**
576 * @license
577 * Copyright Google LLC All Rights Reserved.
578 *
579 * Use of this source code is governed by an MIT-style license that can be
580 * found in the LICENSE file at https://angular.io/license
581 */
582/**
583 * Convince closure compiler that the wrapped function has no side-effects.
584 *
585 * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to
586 * allow us to execute a function but have closure compiler mark the call as no-side-effects.
587 * It is important that the return value for the `noSideEffects` function be assigned
588 * to something which is retained otherwise the call to `noSideEffects` will be removed by closure
589 * compiler.
590 */
591function noSideEffects(fn) {
592 return { toString: fn }.toString();
593}
594
595/**
596 * @license
597 * Copyright Google LLC All Rights Reserved.
598 *
599 * Use of this source code is governed by an MIT-style license that can be
600 * found in the LICENSE file at https://angular.io/license
601 */
602/**
603 * The strategy that the default change detector uses to detect changes.
604 * When set, takes effect the next time change detection is triggered.
605 *
606 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
607 *
608 * @publicApi
609 */
610var ChangeDetectionStrategy;
611(function (ChangeDetectionStrategy) {
612 /**
613 * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated
614 * until reactivated by setting the strategy to `Default` (`CheckAlways`).
615 * Change detection can still be explicitly invoked.
616 * This strategy applies to all child directives and cannot be overridden.
617 */
618 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
619 /**
620 * Use the default `CheckAlways` strategy, in which change detection is automatic until
621 * explicitly deactivated.
622 */
623 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
624})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
625/**
626 * Defines the possible states of the default change detector.
627 * @see `ChangeDetectorRef`
628 */
629var ChangeDetectorStatus;
630(function (ChangeDetectorStatus) {
631 /**
632 * A state in which, after calling `detectChanges()`, the change detector
633 * state becomes `Checked`, and must be explicitly invoked or reactivated.
634 */
635 ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce";
636 /**
637 * A state in which change detection is skipped until the change detector mode
638 * becomes `CheckOnce`.
639 */
640 ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked";
641 /**
642 * A state in which change detection continues automatically until explicitly
643 * deactivated.
644 */
645 ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways";
646 /**
647 * A state in which a change detector sub tree is not a part of the main tree and
648 * should be skipped.
649 */
650 ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached";
651 /**
652 * Indicates that the change detector encountered an error checking a binding
653 * or calling a directive lifecycle method and is now in an inconsistent state. Change
654 * detectors in this state do not detect changes.
655 */
656 ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored";
657 /**
658 * Indicates that the change detector has been destroyed.
659 */
660 ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed";
661})(ChangeDetectorStatus || (ChangeDetectorStatus = {}));
662/**
663 * Reports whether a given strategy is currently the default for change detection.
664 * @param changeDetectionStrategy The strategy to check.
665 * @returns True if the given strategy is the current default, false otherwise.
666 * @see `ChangeDetectorStatus`
667 * @see `ChangeDetectorRef`
668 */
669function isDefaultChangeDetectionStrategy(changeDetectionStrategy) {
670 return changeDetectionStrategy == null ||
671 changeDetectionStrategy === ChangeDetectionStrategy.Default;
672}
673
674/**
675 * @license
676 * Copyright Google LLC All Rights Reserved.
677 *
678 * Use of this source code is governed by an MIT-style license that can be
679 * found in the LICENSE file at https://angular.io/license
680 */
681/**
682 * Defines the CSS styles encapsulation policies for the {@link Component} decorator's
683 * `encapsulation` option.
684 *
685 * See {@link Component#encapsulation encapsulation}.
686 *
687 * @usageNotes
688 * ### Example
689 *
690 * {@example core/ts/metadata/encapsulation.ts region='longform'}
691 *
692 * @publicApi
693 */
694var ViewEncapsulation$1;
695(function (ViewEncapsulation) {
696 // TODO: consider making `ViewEncapsulation` a `const enum` instead. See
697 // https://github.com/angular/angular/issues/44119 for additional information.
698 /**
699 * Emulates a native Shadow DOM encapsulation behavior by adding a specific attribute to the
700 * component's host element and applying the same attribute to all the CSS selectors provided
701 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls}.
702 *
703 * This is the default option.
704 */
705 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
706 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
707 /**
708 * Doesn't provide any sort of CSS style encapsulation, meaning that all the styles provided
709 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls} are applicable
710 * to any HTML element of the application regardless of their host Component.
711 */
712 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
713 /**
714 * Uses the browser's native Shadow DOM API to encapsulate CSS styles, meaning that it creates
715 * a ShadowRoot for the component's host element which is then used to encapsulate
716 * all the Component's styling.
717 */
718 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
719})(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
720
721/**
722 * @license
723 * Copyright Google LLC All Rights Reserved.
724 *
725 * Use of this source code is governed by an MIT-style license that can be
726 * found in the LICENSE file at https://angular.io/license
727 */
728const __globalThis = typeof globalThis !== 'undefined' && globalThis;
729const __window = typeof window !== 'undefined' && window;
730const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
731 self instanceof WorkerGlobalScope && self;
732const __global = typeof global !== 'undefined' && global;
733// Always use __globalThis if available, which is the spec-defined global variable across all
734// environments, then fallback to __global first, because in Node tests both __global and
735// __window may be defined and _global should be __global in that case.
736const _global = __globalThis || __global || __window || __self;
737
738/**
739 * @license
740 * Copyright Google LLC All Rights Reserved.
741 *
742 * Use of this source code is governed by an MIT-style license that can be
743 * found in the LICENSE file at https://angular.io/license
744 */
745function ngDevModeResetPerfCounters() {
746 const locationString = typeof location !== 'undefined' ? location.toString() : '';
747 const newCounters = {
748 namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1,
749 firstCreatePass: 0,
750 tNode: 0,
751 tView: 0,
752 rendererCreateTextNode: 0,
753 rendererSetText: 0,
754 rendererCreateElement: 0,
755 rendererAddEventListener: 0,
756 rendererSetAttribute: 0,
757 rendererRemoveAttribute: 0,
758 rendererSetProperty: 0,
759 rendererSetClassName: 0,
760 rendererAddClass: 0,
761 rendererRemoveClass: 0,
762 rendererSetStyle: 0,
763 rendererRemoveStyle: 0,
764 rendererDestroy: 0,
765 rendererDestroyNode: 0,
766 rendererMoveNode: 0,
767 rendererRemoveNode: 0,
768 rendererAppendChild: 0,
769 rendererInsertBefore: 0,
770 rendererCreateComment: 0,
771 };
772 // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
773 const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
774 _global['ngDevMode'] = allowNgDevModeTrue && newCounters;
775 return newCounters;
776}
777/**
778 * This function checks to see if the `ngDevMode` has been set. If yes,
779 * then we honor it, otherwise we default to dev mode with additional checks.
780 *
781 * The idea is that unless we are doing production build where we explicitly
782 * set `ngDevMode == false` we should be helping the developer by providing
783 * as much early warning and errors as possible.
784 *
785 * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions
786 * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode
787 * is defined for the entire instruction set.
788 *
789 * When checking `ngDevMode` on toplevel, always init it before referencing it
790 * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can
791 * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595.
792 *
793 * Details on possible values for `ngDevMode` can be found on its docstring.
794 *
795 * NOTE:
796 * - changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`.
797 */
798function initNgDevMode() {
799 // The below checks are to ensure that calling `initNgDevMode` multiple times does not
800 // reset the counters.
801 // If the `ngDevMode` is not an object, then it means we have not created the perf counters
802 // yet.
803 if (typeof ngDevMode === 'undefined' || ngDevMode) {
804 if (typeof ngDevMode !== 'object') {
805 ngDevModeResetPerfCounters();
806 }
807 return typeof ngDevMode !== 'undefined' && !!ngDevMode;
808 }
809 return false;
810}
811
812/**
813 * @license
814 * Copyright Google LLC All Rights Reserved.
815 *
816 * Use of this source code is governed by an MIT-style license that can be
817 * found in the LICENSE file at https://angular.io/license
818 */
819/**
820 * This file contains reuseable "empty" symbols that can be used as default return values
821 * in different parts of the rendering code. Because the same symbols are returned, this
822 * allows for identity checks against these values to be consistently used by the framework
823 * code.
824 */
825const EMPTY_OBJ = {};
826const EMPTY_ARRAY = [];
827// freezing the values prevents any code from accidentally inserting new values in
828if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
829 // These property accesses can be ignored because ngDevMode will be set to false
830 // when optimizing code and the whole if statement will be dropped.
831 // tslint:disable-next-line:no-toplevel-property-access
832 Object.freeze(EMPTY_OBJ);
833 // tslint:disable-next-line:no-toplevel-property-access
834 Object.freeze(EMPTY_ARRAY);
835}
836
837/**
838 * @license
839 * Copyright Google LLC All Rights Reserved.
840 *
841 * Use of this source code is governed by an MIT-style license that can be
842 * found in the LICENSE file at https://angular.io/license
843 */
844const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty });
845const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty });
846const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty });
847const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty });
848const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty });
849/**
850 * If a directive is diPublic, bloomAdd sets a property on the type with this constant as
851 * the key and the directive's unique ID as the value. This allows us to map directives to their
852 * bloom filter bit for DI.
853 */
854// TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified.
855const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty });
856
857/**
858 * @license
859 * Copyright Google LLC All Rights Reserved.
860 *
861 * Use of this source code is governed by an MIT-style license that can be
862 * found in the LICENSE file at https://angular.io/license
863 */
864let _renderCompCount = 0;
865/**
866 * Create a component definition object.
867 *
868 *
869 * # Example
870 * ```
871 * class MyDirective {
872 * // Generated by Angular Template Compiler
873 * // [Symbol] syntax will not be supported by TypeScript until v2.7
874 * static ɵcmp = defineComponent({
875 * ...
876 * });
877 * }
878 * ```
879 * @codeGenApi
880 */
881function ɵɵdefineComponent(componentDefinition) {
882 return noSideEffects(() => {
883 // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
884 // See the `initNgDevMode` docstring for more information.
885 (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
886 const type = componentDefinition.type;
887 const declaredInputs = {};
888 const def = {
889 type: type,
890 providersResolver: null,
891 decls: componentDefinition.decls,
892 vars: componentDefinition.vars,
893 factory: null,
894 template: componentDefinition.template || null,
895 consts: componentDefinition.consts || null,
896 ngContentSelectors: componentDefinition.ngContentSelectors,
897 hostBindings: componentDefinition.hostBindings || null,
898 hostVars: componentDefinition.hostVars || 0,
899 hostAttrs: componentDefinition.hostAttrs || null,
900 contentQueries: componentDefinition.contentQueries || null,
901 declaredInputs: declaredInputs,
902 inputs: null,
903 outputs: null,
904 exportAs: componentDefinition.exportAs || null,
905 onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
906 directiveDefs: null,
907 pipeDefs: null,
908 selectors: componentDefinition.selectors || EMPTY_ARRAY,
909 viewQuery: componentDefinition.viewQuery || null,
910 features: componentDefinition.features || null,
911 data: componentDefinition.data || {},
912 encapsulation: componentDefinition.encapsulation || ViewEncapsulation$1.Emulated,
913 id: 'c',
914 styles: componentDefinition.styles || EMPTY_ARRAY,
915 _: null,
916 setInput: null,
917 schemas: componentDefinition.schemas || null,
918 tView: null,
919 };
920 const directiveTypes = componentDefinition.directives;
921 const feature = componentDefinition.features;
922 const pipeTypes = componentDefinition.pipes;
923 def.id += _renderCompCount++;
924 def.inputs = invertObject(componentDefinition.inputs, declaredInputs),
925 def.outputs = invertObject(componentDefinition.outputs),
926 feature && feature.forEach((fn) => fn(def));
927 def.directiveDefs = directiveTypes ?
928 () => (typeof directiveTypes === 'function' ? directiveTypes() : directiveTypes)
929 .map(extractDirectiveDef) :
930 null;
931 def.pipeDefs = pipeTypes ?
932 () => (typeof pipeTypes === 'function' ? pipeTypes() : pipeTypes).map(extractPipeDef) :
933 null;
934 return def;
935 });
936}
937/**
938 * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
939 * definition, when generating a direct reference in the component file would otherwise create an
940 * import cycle.
941 *
942 * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
943 *
944 * @codeGenApi
945 */
946function ɵɵsetComponentScope(type, directives, pipes) {
947 const def = type.ɵcmp;
948 def.directiveDefs = () => directives.map(extractDirectiveDef);
949 def.pipeDefs = () => pipes.map(extractPipeDef);
950}
951function extractDirectiveDef(type) {
952 const def = getComponentDef(type) || getDirectiveDef(type);
953 if (ngDevMode && !def) {
954 throw new Error(`'${type.name}' is neither 'ComponentType' or 'DirectiveType'.`);
955 }
956 return def;
957}
958function extractPipeDef(type) {
959 const def = getPipeDef$1(type);
960 if (ngDevMode && !def) {
961 throw new Error(`'${type.name}' is not a 'PipeType'.`);
962 }
963 return def;
964}
965const autoRegisterModuleById = {};
966/**
967 * @codeGenApi
968 */
969function ɵɵdefineNgModule(def) {
970 return noSideEffects(() => {
971 const res = {
972 type: def.type,
973 bootstrap: def.bootstrap || EMPTY_ARRAY,
974 declarations: def.declarations || EMPTY_ARRAY,
975 imports: def.imports || EMPTY_ARRAY,
976 exports: def.exports || EMPTY_ARRAY,
977 transitiveCompileScopes: null,
978 schemas: def.schemas || null,
979 id: def.id || null,
980 };
981 if (def.id != null) {
982 autoRegisterModuleById[def.id] = def.type;
983 }
984 return res;
985 });
986}
987/**
988 * Adds the module metadata that is necessary to compute the module's transitive scope to an
989 * existing module definition.
990 *
991 * Scope metadata of modules is not used in production builds, so calls to this function can be
992 * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
993 * to become eligible for tree-shaking as well.
994 *
995 * @codeGenApi
996 */
997function ɵɵsetNgModuleScope(type, scope) {
998 return noSideEffects(() => {
999 const ngModuleDef = getNgModuleDef(type, true);
1000 ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
1001 ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
1002 ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
1003 });
1004}
1005/**
1006 * Inverts an inputs or outputs lookup such that the keys, which were the
1007 * minified keys, are part of the values, and the values are parsed so that
1008 * the publicName of the property is the new key
1009 *
1010 * e.g. for
1011 *
1012 * ```
1013 * class Comp {
1014 * @Input()
1015 * propName1: string;
1016 *
1017 * @Input('publicName2')
1018 * declaredPropName2: number;
1019 * }
1020 * ```
1021 *
1022 * will be serialized as
1023 *
1024 * ```
1025 * {
1026 * propName1: 'propName1',
1027 * declaredPropName2: ['publicName2', 'declaredPropName2'],
1028 * }
1029 * ```
1030 *
1031 * which is than translated by the minifier as:
1032 *
1033 * ```
1034 * {
1035 * minifiedPropName1: 'propName1',
1036 * minifiedPropName2: ['publicName2', 'declaredPropName2'],
1037 * }
1038 * ```
1039 *
1040 * becomes: (public name => minifiedName)
1041 *
1042 * ```
1043 * {
1044 * 'propName1': 'minifiedPropName1',
1045 * 'publicName2': 'minifiedPropName2',
1046 * }
1047 * ```
1048 *
1049 * Optionally the function can take `secondary` which will result in: (public name => declared name)
1050 *
1051 * ```
1052 * {
1053 * 'propName1': 'propName1',
1054 * 'publicName2': 'declaredPropName2',
1055 * }
1056 * ```
1057 *
1058
1059 */
1060function invertObject(obj, secondary) {
1061 if (obj == null)
1062 return EMPTY_OBJ;
1063 const newLookup = {};
1064 for (const minifiedKey in obj) {
1065 if (obj.hasOwnProperty(minifiedKey)) {
1066 let publicName = obj[minifiedKey];
1067 let declaredName = publicName;
1068 if (Array.isArray(publicName)) {
1069 declaredName = publicName[1];
1070 publicName = publicName[0];
1071 }
1072 newLookup[publicName] = minifiedKey;
1073 if (secondary) {
1074 (secondary[publicName] = declaredName);
1075 }
1076 }
1077 }
1078 return newLookup;
1079}
1080/**
1081 * Create a directive definition object.
1082 *
1083 * # Example
1084 * ```ts
1085 * class MyDirective {
1086 * // Generated by Angular Template Compiler
1087 * // [Symbol] syntax will not be supported by TypeScript until v2.7
1088 * static ɵdir = ɵɵdefineDirective({
1089 * ...
1090 * });
1091 * }
1092 * ```
1093 *
1094 * @codeGenApi
1095 */
1096const ɵɵdefineDirective = ɵɵdefineComponent;
1097/**
1098 * Create a pipe definition object.
1099 *
1100 * # Example
1101 * ```
1102 * class MyPipe implements PipeTransform {
1103 * // Generated by Angular Template Compiler
1104 * static ɵpipe = definePipe({
1105 * ...
1106 * });
1107 * }
1108 * ```
1109 * @param pipeDef Pipe definition generated by the compiler
1110 *
1111 * @codeGenApi
1112 */
1113function ɵɵdefinePipe(pipeDef) {
1114 return {
1115 type: pipeDef.type,
1116 name: pipeDef.name,
1117 factory: null,
1118 pure: pipeDef.pure !== false,
1119 onDestroy: pipeDef.type.prototype.ngOnDestroy || null
1120 };
1121}
1122/**
1123 * The following getter methods retrieve the definition from the type. Currently the retrieval
1124 * honors inheritance, but in the future we may change the rule to require that definitions are
1125 * explicit. This would require some sort of migration strategy.
1126 */
1127function getComponentDef(type) {
1128 return type[NG_COMP_DEF] || null;
1129}
1130function getDirectiveDef(type) {
1131 return type[NG_DIR_DEF] || null;
1132}
1133function getPipeDef$1(type) {
1134 return type[NG_PIPE_DEF] || null;
1135}
1136function getNgModuleDef(type, throwNotFound) {
1137 const ngModuleDef = type[NG_MOD_DEF] || null;
1138 if (!ngModuleDef && throwNotFound === true) {
1139 throw new Error(`Type ${stringify(type)} does not have 'ɵmod' property.`);
1140 }
1141 return ngModuleDef;
1142}
1143
1144/**
1145 * @license
1146 * Copyright Google LLC All Rights Reserved.
1147 *
1148 * Use of this source code is governed by an MIT-style license that can be
1149 * found in the LICENSE file at https://angular.io/license
1150 */
1151// Below are constants for LView indices to help us look up LView members
1152// without having to remember the specific indices.
1153// Uglify will inline these when minifying so there shouldn't be a cost.
1154const HOST = 0;
1155const TVIEW = 1;
1156const FLAGS = 2;
1157const PARENT = 3;
1158const NEXT = 4;
1159const TRANSPLANTED_VIEWS_TO_REFRESH = 5;
1160const T_HOST = 6;
1161const CLEANUP = 7;
1162const CONTEXT = 8;
1163const INJECTOR$1 = 9;
1164const RENDERER_FACTORY = 10;
1165const RENDERER = 11;
1166const SANITIZER = 12;
1167const CHILD_HEAD = 13;
1168const CHILD_TAIL = 14;
1169// FIXME(misko): Investigate if the three declarations aren't all same thing.
1170const DECLARATION_VIEW = 15;
1171const DECLARATION_COMPONENT_VIEW = 16;
1172const DECLARATION_LCONTAINER = 17;
1173const PREORDER_HOOK_FLAGS = 18;
1174const QUERIES = 19;
1175/**
1176 * Size of LView's header. Necessary to adjust for it when setting slots.
1177 *
1178 * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
1179 * instruction index into `LView` index. All other indexes should be in the `LView` index space and
1180 * there should be no need to refer to `HEADER_OFFSET` anywhere else.
1181 */
1182const HEADER_OFFSET = 20;
1183/**
1184 * Converts `TViewType` into human readable text.
1185 * Make sure this matches with `TViewType`
1186 */
1187const TViewTypeAsString = [
1188 'Root',
1189 'Component',
1190 'Embedded', // 2
1191];
1192// Note: This hack is necessary so we don't erroneously get a circular dependency
1193// failure based on types.
1194const unusedValueExportToPlacateAjd$8 = 1;
1195
1196/**
1197 * @license
1198 * Copyright Google LLC All Rights Reserved.
1199 *
1200 * Use of this source code is governed by an MIT-style license that can be
1201 * found in the LICENSE file at https://angular.io/license
1202 */
1203/**
1204 * Special location which allows easy identification of type. If we have an array which was
1205 * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
1206 * `LContainer`.
1207 */
1208const TYPE = 1;
1209/**
1210 * Below are constants for LContainer indices to help us look up LContainer members
1211 * without having to remember the specific indices.
1212 * Uglify will inline these when minifying so there shouldn't be a cost.
1213 */
1214/**
1215 * Flag to signify that this `LContainer` may have transplanted views which need to be change
1216 * detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
1217 *
1218 * This flag, once set, is never unset for the `LContainer`. This means that when unset we can skip
1219 * a lot of work in `refreshEmbeddedViews`. But when set we still need to verify
1220 * that the `MOVED_VIEWS` are transplanted and on-push.
1221 */
1222const HAS_TRANSPLANTED_VIEWS = 2;
1223// PARENT, NEXT, TRANSPLANTED_VIEWS_TO_REFRESH are indices 3, 4, and 5
1224// As we already have these constants in LView, we don't need to re-create them.
1225// T_HOST is index 6
1226// We already have this constants in LView, we don't need to re-create it.
1227const NATIVE = 7;
1228const VIEW_REFS = 8;
1229const MOVED_VIEWS = 9;
1230/**
1231 * Size of LContainer's header. Represents the index after which all views in the
1232 * container will be inserted. We need to keep a record of current views so we know
1233 * which views are already in the DOM (and don't need to be re-added) and so we can
1234 * remove views from the DOM when they are no longer required.
1235 */
1236const CONTAINER_HEADER_OFFSET = 10;
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 /* hasContentQuery */) !== 0;
1264}
1265function isComponentHost(tNode) {
1266 return (tNode.flags & 2 /* isComponentHost */) === 2 /* isComponentHost */;
1267}
1268function isDirectiveHost(tNode) {
1269 return (tNode.flags & 1 /* isDirectiveHost */) === 1 /* isDirectiveHost */;
1270}
1271function isComponentDef(def) {
1272 return def.template !== null;
1273}
1274function isRootView(target) {
1275 return (target[FLAGS] & 512 /* 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 /* 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 /* 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?.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 /* CreationMode */) === 4 /* 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] & 128 /* Attached */) === 128 /* 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}
1955function getCurrentTNode() {
1956 let currentTNode = getCurrentTNodePlaceholderOk();
1957 while (currentTNode !== null && currentTNode.type === 64 /* Placeholder */) {
1958 currentTNode = currentTNode.parent;
1959 }
1960 return currentTNode;
1961}
1962function getCurrentTNodePlaceholderOk() {
1963 return instructionState.lFrame.currentTNode;
1964}
1965function getCurrentParentTNode() {
1966 const lFrame = instructionState.lFrame;
1967 const currentTNode = lFrame.currentTNode;
1968 return lFrame.isParent ? currentTNode : currentTNode.parent;
1969}
1970function setCurrentTNode(tNode, isParent) {
1971 ngDevMode && tNode && assertTNodeForTView(tNode, instructionState.lFrame.tView);
1972 const lFrame = instructionState.lFrame;
1973 lFrame.currentTNode = tNode;
1974 lFrame.isParent = isParent;
1975}
1976function isCurrentTNodeParent() {
1977 return instructionState.lFrame.isParent;
1978}
1979function setCurrentTNodeAsNotParent() {
1980 instructionState.lFrame.isParent = false;
1981}
1982function setCurrentTNodeAsParent() {
1983 instructionState.lFrame.isParent = true;
1984}
1985function getContextLView() {
1986 return instructionState.lFrame.contextLView;
1987}
1988function isInCheckNoChangesMode() {
1989 !ngDevMode && throwError('Must never be called in production mode');
1990 return _isInCheckNoChangesMode;
1991}
1992function setIsInCheckNoChangesMode(mode) {
1993 !ngDevMode && throwError('Must never be called in production mode');
1994 _isInCheckNoChangesMode = mode;
1995}
1996// top level variables should not be exported for performance reasons (PERF_NOTES.md)
1997function getBindingRoot() {
1998 const lFrame = instructionState.lFrame;
1999 let index = lFrame.bindingRootIndex;
2000 if (index === -1) {
2001 index = lFrame.bindingRootIndex = lFrame.tView.bindingStartIndex;
2002 }
2003 return index;
2004}
2005function getBindingIndex() {
2006 return instructionState.lFrame.bindingIndex;
2007}
2008function setBindingIndex(value) {
2009 return instructionState.lFrame.bindingIndex = value;
2010}
2011function nextBindingIndex() {
2012 return instructionState.lFrame.bindingIndex++;
2013}
2014function incrementBindingIndex(count) {
2015 const lFrame = instructionState.lFrame;
2016 const index = lFrame.bindingIndex;
2017 lFrame.bindingIndex = lFrame.bindingIndex + count;
2018 return index;
2019}
2020function isInI18nBlock() {
2021 return instructionState.lFrame.inI18n;
2022}
2023function setInI18nBlock(isInI18nBlock) {
2024 instructionState.lFrame.inI18n = isInI18nBlock;
2025}
2026/**
2027 * Set a new binding root index so that host template functions can execute.
2028 *
2029 * Bindings inside the host template are 0 index. But because we don't know ahead of time
2030 * how many host bindings we have we can't pre-compute them. For this reason they are all
2031 * 0 index and we just shift the root so that they match next available location in the LView.
2032 *
2033 * @param bindingRootIndex Root index for `hostBindings`
2034 * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive
2035 * whose `hostBindings` are being processed.
2036 */
2037function setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex) {
2038 const lFrame = instructionState.lFrame;
2039 lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex;
2040 setCurrentDirectiveIndex(currentDirectiveIndex);
2041}
2042/**
2043 * When host binding is executing this points to the directive index.
2044 * `TView.data[getCurrentDirectiveIndex()]` is `DirectiveDef`
2045 * `LView[getCurrentDirectiveIndex()]` is directive instance.
2046 */
2047function getCurrentDirectiveIndex() {
2048 return instructionState.lFrame.currentDirectiveIndex;
2049}
2050/**
2051 * Sets an index of a directive whose `hostBindings` are being processed.
2052 *
2053 * @param currentDirectiveIndex `TData` index where current directive instance can be found.
2054 */
2055function setCurrentDirectiveIndex(currentDirectiveIndex) {
2056 instructionState.lFrame.currentDirectiveIndex = currentDirectiveIndex;
2057}
2058/**
2059 * Retrieve the current `DirectiveDef` which is active when `hostBindings` instruction is being
2060 * executed.
2061 *
2062 * @param tData Current `TData` where the `DirectiveDef` will be looked up at.
2063 */
2064function getCurrentDirectiveDef(tData) {
2065 const currentDirectiveIndex = instructionState.lFrame.currentDirectiveIndex;
2066 return currentDirectiveIndex === -1 ? null : tData[currentDirectiveIndex];
2067}
2068function getCurrentQueryIndex() {
2069 return instructionState.lFrame.currentQueryIndex;
2070}
2071function setCurrentQueryIndex(value) {
2072 instructionState.lFrame.currentQueryIndex = value;
2073}
2074/**
2075 * Returns a `TNode` of the location where the current `LView` is declared at.
2076 *
2077 * @param lView an `LView` that we want to find parent `TNode` for.
2078 */
2079function getDeclarationTNode(lView) {
2080 const tView = lView[TVIEW];
2081 // Return the declaration parent for embedded views
2082 if (tView.type === 2 /* Embedded */) {
2083 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
2084 return tView.declTNode;
2085 }
2086 // Components don't have `TView.declTNode` because each instance of component could be
2087 // inserted in different location, hence `TView.declTNode` is meaningless.
2088 // Falling back to `T_HOST` in case we cross component boundary.
2089 if (tView.type === 1 /* Component */) {
2090 return lView[T_HOST];
2091 }
2092 // Remaining TNode type is `TViewType.Root` which doesn't have a parent TNode.
2093 return null;
2094}
2095/**
2096 * This is a light weight version of the `enterView` which is needed by the DI system.
2097 *
2098 * @param lView `LView` location of the DI context.
2099 * @param tNode `TNode` for DI context
2100 * @param flags DI context flags. if `SkipSelf` flag is set than we walk up the declaration
2101 * tree from `tNode` until we find parent declared `TElementNode`.
2102 * @returns `true` if we have successfully entered DI associated with `tNode` (or with declared
2103 * `TNode` if `flags` has `SkipSelf`). Failing to enter DI implies that no associated
2104 * `NodeInjector` can be found and we should instead use `ModuleInjector`.
2105 * - If `true` than this call must be fallowed by `leaveDI`
2106 * - If `false` than this call failed and we should NOT call `leaveDI`
2107 */
2108function enterDI(lView, tNode, flags) {
2109 ngDevMode && assertLViewOrUndefined(lView);
2110 if (flags & InjectFlags.SkipSelf) {
2111 ngDevMode && assertTNodeForTView(tNode, lView[TVIEW]);
2112 let parentTNode = tNode;
2113 let parentLView = lView;
2114 while (true) {
2115 ngDevMode && assertDefined(parentTNode, 'Parent TNode should be defined');
2116 parentTNode = parentTNode.parent;
2117 if (parentTNode === null && !(flags & InjectFlags.Host)) {
2118 parentTNode = getDeclarationTNode(parentLView);
2119 if (parentTNode === null)
2120 break;
2121 // In this case, a parent exists and is definitely an element. So it will definitely
2122 // have an existing lView as the declaration view, which is why we can assume it's defined.
2123 ngDevMode && assertDefined(parentLView, 'Parent LView should be defined');
2124 parentLView = parentLView[DECLARATION_VIEW];
2125 // In Ivy there are Comment nodes that correspond to ngIf and NgFor embedded directives
2126 // We want to skip those and look only at Elements and ElementContainers to ensure
2127 // we're looking at true parent nodes, and not content or other types.
2128 if (parentTNode.type & (2 /* Element */ | 8 /* ElementContainer */)) {
2129 break;
2130 }
2131 }
2132 else {
2133 break;
2134 }
2135 }
2136 if (parentTNode === null) {
2137 // If we failed to find a parent TNode this means that we should use module injector.
2138 return false;
2139 }
2140 else {
2141 tNode = parentTNode;
2142 lView = parentLView;
2143 }
2144 }
2145 ngDevMode && assertTNodeForLView(tNode, lView);
2146 const lFrame = instructionState.lFrame = allocLFrame();
2147 lFrame.currentTNode = tNode;
2148 lFrame.lView = lView;
2149 return true;
2150}
2151/**
2152 * Swap the current lView with a new lView.
2153 *
2154 * For performance reasons we store the lView in the top level of the module.
2155 * This way we minimize the number of properties to read. Whenever a new view
2156 * is entered we have to store the lView for later, and when the view is
2157 * exited the state has to be restored
2158 *
2159 * @param newView New lView to become active
2160 * @returns the previously active lView;
2161 */
2162function enterView(newView) {
2163 ngDevMode && assertNotEqual(newView[0], newView[1], '????');
2164 ngDevMode && assertLViewOrUndefined(newView);
2165 const newLFrame = allocLFrame();
2166 if (ngDevMode) {
2167 assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
2168 assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
2169 assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
2170 assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
2171 assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
2172 assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
2173 assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
2174 assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
2175 assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
2176 }
2177 const tView = newView[TVIEW];
2178 instructionState.lFrame = newLFrame;
2179 ngDevMode && tView.firstChild && assertTNodeForTView(tView.firstChild, tView);
2180 newLFrame.currentTNode = tView.firstChild;
2181 newLFrame.lView = newView;
2182 newLFrame.tView = tView;
2183 newLFrame.contextLView = newView;
2184 newLFrame.bindingIndex = tView.bindingStartIndex;
2185 newLFrame.inI18n = false;
2186}
2187/**
2188 * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure.
2189 */
2190function allocLFrame() {
2191 const currentLFrame = instructionState.lFrame;
2192 const childLFrame = currentLFrame === null ? null : currentLFrame.child;
2193 const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame;
2194 return newLFrame;
2195}
2196function createLFrame(parent) {
2197 const lFrame = {
2198 currentTNode: null,
2199 isParent: true,
2200 lView: null,
2201 tView: null,
2202 selectedIndex: -1,
2203 contextLView: null,
2204 elementDepthCount: 0,
2205 currentNamespace: null,
2206 currentDirectiveIndex: -1,
2207 bindingRootIndex: -1,
2208 bindingIndex: -1,
2209 currentQueryIndex: 0,
2210 parent: parent,
2211 child: null,
2212 inI18n: false,
2213 };
2214 parent !== null && (parent.child = lFrame); // link the new LFrame for reuse.
2215 return lFrame;
2216}
2217/**
2218 * A lightweight version of leave which is used with DI.
2219 *
2220 * This function only resets `currentTNode` and `LView` as those are the only properties
2221 * used with DI (`enterDI()`).
2222 *
2223 * NOTE: This function is reexported as `leaveDI`. However `leaveDI` has return type of `void` where
2224 * as `leaveViewLight` has `LFrame`. This is so that `leaveViewLight` can be used in `leaveView`.
2225 */
2226function leaveViewLight() {
2227 const oldLFrame = instructionState.lFrame;
2228 instructionState.lFrame = oldLFrame.parent;
2229 oldLFrame.currentTNode = null;
2230 oldLFrame.lView = null;
2231 return oldLFrame;
2232}
2233/**
2234 * This is a lightweight version of the `leaveView` which is needed by the DI system.
2235 *
2236 * NOTE: this function is an alias so that we can change the type of the function to have `void`
2237 * return type.
2238 */
2239const leaveDI = leaveViewLight;
2240/**
2241 * Leave the current `LView`
2242 *
2243 * This pops the `LFrame` with the associated `LView` from the stack.
2244 *
2245 * IMPORTANT: We must zero out the `LFrame` values here otherwise they will be retained. This is
2246 * because for performance reasons we don't release `LFrame` but rather keep it for next use.
2247 */
2248function leaveView() {
2249 const oldLFrame = leaveViewLight();
2250 oldLFrame.isParent = true;
2251 oldLFrame.tView = null;
2252 oldLFrame.selectedIndex = -1;
2253 oldLFrame.contextLView = null;
2254 oldLFrame.elementDepthCount = 0;
2255 oldLFrame.currentDirectiveIndex = -1;
2256 oldLFrame.currentNamespace = null;
2257 oldLFrame.bindingRootIndex = -1;
2258 oldLFrame.bindingIndex = -1;
2259 oldLFrame.currentQueryIndex = 0;
2260}
2261function nextContextImpl(level) {
2262 const contextLView = instructionState.lFrame.contextLView =
2263 walkUpViews(level, instructionState.lFrame.contextLView);
2264 return contextLView[CONTEXT];
2265}
2266function walkUpViews(nestingLevel, currentView) {
2267 while (nestingLevel > 0) {
2268 ngDevMode &&
2269 assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.');
2270 currentView = currentView[DECLARATION_VIEW];
2271 nestingLevel--;
2272 }
2273 return currentView;
2274}
2275/**
2276 * Gets the currently selected element index.
2277 *
2278 * Used with {@link property} instruction (and more in the future) to identify the index in the
2279 * current `LView` to act on.
2280 */
2281function getSelectedIndex() {
2282 return instructionState.lFrame.selectedIndex;
2283}
2284/**
2285 * Sets the most recent index passed to {@link select}
2286 *
2287 * Used with {@link property} instruction (and more in the future) to identify the index in the
2288 * current `LView` to act on.
2289 *
2290 * (Note that if an "exit function" was set earlier (via `setElementExitFn()`) then that will be
2291 * run if and when the provided `index` value is different from the current selected index value.)
2292 */
2293function setSelectedIndex(index) {
2294 ngDevMode && index !== -1 &&
2295 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
2296 ngDevMode &&
2297 assertLessThan(index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView');
2298 instructionState.lFrame.selectedIndex = index;
2299}
2300/**
2301 * Gets the `tNode` that represents currently selected element.
2302 */
2303function getSelectedTNode() {
2304 const lFrame = instructionState.lFrame;
2305 return getTNode(lFrame.tView, lFrame.selectedIndex);
2306}
2307/**
2308 * Sets the namespace used to create elements to `'http://www.w3.org/2000/svg'` in global state.
2309 *
2310 * @codeGenApi
2311 */
2312function ɵɵnamespaceSVG() {
2313 instructionState.lFrame.currentNamespace = SVG_NAMESPACE;
2314}
2315/**
2316 * Sets the namespace used to create elements to `'http://www.w3.org/1998/MathML/'` in global state.
2317 *
2318 * @codeGenApi
2319 */
2320function ɵɵnamespaceMathML() {
2321 instructionState.lFrame.currentNamespace = MATH_ML_NAMESPACE;
2322}
2323/**
2324 * Sets the namespace used to create elements to `null`, which forces element creation to use
2325 * `createElement` rather than `createElementNS`.
2326 *
2327 * @codeGenApi
2328 */
2329function ɵɵnamespaceHTML() {
2330 namespaceHTMLInternal();
2331}
2332/**
2333 * Sets the namespace used to create elements to `null`, which forces element creation to use
2334 * `createElement` rather than `createElementNS`.
2335 */
2336function namespaceHTMLInternal() {
2337 instructionState.lFrame.currentNamespace = null;
2338}
2339function getNamespace$1() {
2340 return instructionState.lFrame.currentNamespace;
2341}
2342
2343/**
2344 * @license
2345 * Copyright Google LLC All Rights Reserved.
2346 *
2347 * Use of this source code is governed by an MIT-style license that can be
2348 * found in the LICENSE file at https://angular.io/license
2349 */
2350/**
2351 * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`.
2352 *
2353 * Must be run *only* on the first template pass.
2354 *
2355 * Sets up the pre-order hooks on the provided `tView`,
2356 * see {@link HookData} for details about the data structure.
2357 *
2358 * @param directiveIndex The index of the directive in LView
2359 * @param directiveDef The definition containing the hooks to setup in tView
2360 * @param tView The current TView
2361 */
2362function registerPreOrderHooks(directiveIndex, directiveDef, tView) {
2363 ngDevMode && assertFirstCreatePass(tView);
2364 const { ngOnChanges, ngOnInit, ngDoCheck } = directiveDef.type.prototype;
2365 if (ngOnChanges) {
2366 const wrappedOnChanges = NgOnChangesFeatureImpl(directiveDef);
2367 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, wrappedOnChanges);
2368 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = []))
2369 .push(directiveIndex, wrappedOnChanges);
2370 }
2371 if (ngOnInit) {
2372 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(0 - directiveIndex, ngOnInit);
2373 }
2374 if (ngDoCheck) {
2375 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, ngDoCheck);
2376 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, ngDoCheck);
2377 }
2378}
2379/**
2380 *
2381 * Loops through the directives on the provided `tNode` and queues hooks to be
2382 * run that are not initialization hooks.
2383 *
2384 * Should be executed during `elementEnd()` and similar to
2385 * preserve hook execution order. Content, view, and destroy hooks for projected
2386 * components and directives must be called *before* their hosts.
2387 *
2388 * Sets up the content, view, and destroy hooks on the provided `tView`,
2389 * see {@link HookData} for details about the data structure.
2390 *
2391 * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up
2392 * separately at `elementStart`.
2393 *
2394 * @param tView The current TView
2395 * @param tNode The TNode whose directives are to be searched for hooks to queue
2396 */
2397function registerPostOrderHooks(tView, tNode) {
2398 ngDevMode && assertFirstCreatePass(tView);
2399 // It's necessary to loop through the directives at elementEnd() (rather than processing in
2400 // directiveCreate) so we can preserve the current hook order. Content, view, and destroy
2401 // hooks for projected components and directives must be called *before* their hosts.
2402 for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) {
2403 const directiveDef = tView.data[i];
2404 ngDevMode && assertDefined(directiveDef, 'Expecting DirectiveDef');
2405 const lifecycleHooks = directiveDef.type.prototype;
2406 const { ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked, ngOnDestroy } = lifecycleHooks;
2407 if (ngAfterContentInit) {
2408 (tView.contentHooks || (tView.contentHooks = [])).push(-i, ngAfterContentInit);
2409 }
2410 if (ngAfterContentChecked) {
2411 (tView.contentHooks || (tView.contentHooks = [])).push(i, ngAfterContentChecked);
2412 (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, ngAfterContentChecked);
2413 }
2414 if (ngAfterViewInit) {
2415 (tView.viewHooks || (tView.viewHooks = [])).push(-i, ngAfterViewInit);
2416 }
2417 if (ngAfterViewChecked) {
2418 (tView.viewHooks || (tView.viewHooks = [])).push(i, ngAfterViewChecked);
2419 (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, ngAfterViewChecked);
2420 }
2421 if (ngOnDestroy != null) {
2422 (tView.destroyHooks || (tView.destroyHooks = [])).push(i, ngOnDestroy);
2423 }
2424 }
2425}
2426/**
2427 * Executing hooks requires complex logic as we need to deal with 2 constraints.
2428 *
2429 * 1. Init hooks (ngOnInit, ngAfterContentInit, ngAfterViewInit) must all be executed once and only
2430 * once, across many change detection cycles. This must be true even if some hooks throw, or if
2431 * some recursively trigger a change detection cycle.
2432 * To solve that, it is required to track the state of the execution of these init hooks.
2433 * This is done by storing and maintaining flags in the view: the {@link InitPhaseState},
2434 * and the index within that phase. They can be seen as a cursor in the following structure:
2435 * [[onInit1, onInit2], [afterContentInit1], [afterViewInit1, afterViewInit2, afterViewInit3]]
2436 * They are are stored as flags in LView[FLAGS].
2437 *
2438 * 2. Pre-order hooks can be executed in batches, because of the select instruction.
2439 * To be able to pause and resume their execution, we also need some state about the hook's array
2440 * that is being processed:
2441 * - the index of the next hook to be executed
2442 * - the number of init hooks already found in the processed part of the array
2443 * They are are stored as flags in LView[PREORDER_HOOK_FLAGS].
2444 */
2445/**
2446 * Executes pre-order check hooks ( OnChanges, DoChanges) given a view where all the init hooks were
2447 * executed once. This is a light version of executeInitAndCheckPreOrderHooks where we can skip read
2448 * / write of the init-hooks related flags.
2449 * @param lView The LView where hooks are defined
2450 * @param hooks Hooks to be run
2451 * @param nodeIndex 3 cases depending on the value:
2452 * - undefined: all hooks from the array should be executed (post-order case)
2453 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2454 * flushing the remaining hooks)
2455 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2456 * case, when executing select(number))
2457 */
2458function executeCheckHooks(lView, hooks, nodeIndex) {
2459 callHooks(lView, hooks, 3 /* InitPhaseCompleted */, nodeIndex);
2460}
2461/**
2462 * Executes post-order init and check hooks (one of AfterContentInit, AfterContentChecked,
2463 * AfterViewInit, AfterViewChecked) given a view where there are pending init hooks to be executed.
2464 * @param lView The LView where hooks are defined
2465 * @param hooks Hooks to be run
2466 * @param initPhase A phase for which hooks should be run
2467 * @param nodeIndex 3 cases depending on the value:
2468 * - undefined: all hooks from the array should be executed (post-order case)
2469 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2470 * flushing the remaining hooks)
2471 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2472 * case, when executing select(number))
2473 */
2474function executeInitAndCheckHooks(lView, hooks, initPhase, nodeIndex) {
2475 ngDevMode &&
2476 assertNotEqual(initPhase, 3 /* InitPhaseCompleted */, 'Init pre-order hooks should not be called more than once');
2477 if ((lView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhase) {
2478 callHooks(lView, hooks, initPhase, nodeIndex);
2479 }
2480}
2481function incrementInitPhaseFlags(lView, initPhase) {
2482 ngDevMode &&
2483 assertNotEqual(initPhase, 3 /* InitPhaseCompleted */, 'Init hooks phase should not be incremented after all init hooks have been run.');
2484 let flags = lView[FLAGS];
2485 if ((flags & 3 /* InitPhaseStateMask */) === initPhase) {
2486 flags &= 2047 /* IndexWithinInitPhaseReset */;
2487 flags += 1 /* InitPhaseStateIncrementer */;
2488 lView[FLAGS] = flags;
2489 }
2490}
2491/**
2492 * Calls lifecycle hooks with their contexts, skipping init hooks if it's not
2493 * the first LView pass
2494 *
2495 * @param currentView The current view
2496 * @param arr The array in which the hooks are found
2497 * @param initPhaseState the current state of the init phase
2498 * @param currentNodeIndex 3 cases depending on the value:
2499 * - undefined: all hooks from the array should be executed (post-order case)
2500 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2501 * flushing the remaining hooks)
2502 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2503 * case, when executing select(number))
2504 */
2505function callHooks(currentView, arr, initPhase, currentNodeIndex) {
2506 ngDevMode &&
2507 assertEqual(isInCheckNoChangesMode(), false, 'Hooks should never be run when in check no changes mode.');
2508 const startIndex = currentNodeIndex !== undefined ?
2509 (currentView[PREORDER_HOOK_FLAGS] & 65535 /* IndexOfTheNextPreOrderHookMaskMask */) :
2510 0;
2511 const nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1;
2512 const max = arr.length - 1; // Stop the loop at length - 1, because we look for the hook at i + 1
2513 let lastNodeIndexFound = 0;
2514 for (let i = startIndex; i < max; i++) {
2515 const hook = arr[i + 1];
2516 if (typeof hook === 'number') {
2517 lastNodeIndexFound = arr[i];
2518 if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) {
2519 break;
2520 }
2521 }
2522 else {
2523 const isInitHook = arr[i] < 0;
2524 if (isInitHook)
2525 currentView[PREORDER_HOOK_FLAGS] += 65536 /* NumberOfInitHooksCalledIncrementer */;
2526 if (lastNodeIndexFound < nodeIndexLimit || nodeIndexLimit == -1) {
2527 callHook(currentView, initPhase, arr, i);
2528 currentView[PREORDER_HOOK_FLAGS] =
2529 (currentView[PREORDER_HOOK_FLAGS] & 4294901760 /* NumberOfInitHooksCalledMask */) + i +
2530 2;
2531 }
2532 i++;
2533 }
2534 }
2535}
2536/**
2537 * Execute one hook against the current `LView`.
2538 *
2539 * @param currentView The current view
2540 * @param initPhaseState the current state of the init phase
2541 * @param arr The array in which the hooks are found
2542 * @param i The current index within the hook data array
2543 */
2544function callHook(currentView, initPhase, arr, i) {
2545 const isInitHook = arr[i] < 0;
2546 const hook = arr[i + 1];
2547 const directiveIndex = isInitHook ? -arr[i] : arr[i];
2548 const directive = currentView[directiveIndex];
2549 if (isInitHook) {
2550 const indexWithintInitPhase = currentView[FLAGS] >> 11 /* IndexWithinInitPhaseShift */;
2551 // The init phase state must be always checked here as it may have been recursively updated.
2552 if (indexWithintInitPhase <
2553 (currentView[PREORDER_HOOK_FLAGS] >> 16 /* NumberOfInitHooksCalledShift */) &&
2554 (currentView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhase) {
2555 currentView[FLAGS] += 2048 /* IndexWithinInitPhaseIncrementer */;
2556 profiler(4 /* LifecycleHookStart */, directive, hook);
2557 try {
2558 hook.call(directive);
2559 }
2560 finally {
2561 profiler(5 /* LifecycleHookEnd */, directive, hook);
2562 }
2563 }
2564 }
2565 else {
2566 profiler(4 /* LifecycleHookStart */, directive, hook);
2567 try {
2568 hook.call(directive);
2569 }
2570 finally {
2571 profiler(5 /* LifecycleHookEnd */, directive, hook);
2572 }
2573 }
2574}
2575
2576/**
2577 * @license
2578 * Copyright Google LLC All Rights Reserved.
2579 *
2580 * Use of this source code is governed by an MIT-style license that can be
2581 * found in the LICENSE file at https://angular.io/license
2582 */
2583const NO_PARENT_INJECTOR = -1;
2584/**
2585 * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in
2586 * `TView.data`. This allows us to store information about the current node's tokens (which
2587 * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
2588 * shared, so they live in `LView`).
2589 *
2590 * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter
2591 * determines whether a directive is available on the associated node or not. This prevents us
2592 * from searching the directives array at this level unless it's probable the directive is in it.
2593 *
2594 * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
2595 *
2596 * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed
2597 * using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
2598 * will differ based on where it is flattened into the main array, so it's not possible to know
2599 * the indices ahead of time and save their types here. The interfaces are still included here
2600 * for documentation purposes.
2601 *
2602 * export interface LInjector extends Array<any> {
2603 *
2604 * // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
2605 * [0]: number;
2606 *
2607 * // Cumulative bloom for directive IDs 32-63
2608 * [1]: number;
2609 *
2610 * // Cumulative bloom for directive IDs 64-95
2611 * [2]: number;
2612 *
2613 * // Cumulative bloom for directive IDs 96-127
2614 * [3]: number;
2615 *
2616 * // Cumulative bloom for directive IDs 128-159
2617 * [4]: number;
2618 *
2619 * // Cumulative bloom for directive IDs 160 - 191
2620 * [5]: number;
2621 *
2622 * // Cumulative bloom for directive IDs 192 - 223
2623 * [6]: number;
2624 *
2625 * // Cumulative bloom for directive IDs 224 - 255
2626 * [7]: number;
2627 *
2628 * // We need to store a reference to the injector's parent so DI can keep looking up
2629 * // the injector tree until it finds the dependency it's looking for.
2630 * [PARENT_INJECTOR]: number;
2631 * }
2632 *
2633 * export interface TInjector extends Array<any> {
2634 *
2635 * // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
2636 * [0]: number;
2637 *
2638 * // Shared node bloom for directive IDs 32-63
2639 * [1]: number;
2640 *
2641 * // Shared node bloom for directive IDs 64-95
2642 * [2]: number;
2643 *
2644 * // Shared node bloom for directive IDs 96-127
2645 * [3]: number;
2646 *
2647 * // Shared node bloom for directive IDs 128-159
2648 * [4]: number;
2649 *
2650 * // Shared node bloom for directive IDs 160 - 191
2651 * [5]: number;
2652 *
2653 * // Shared node bloom for directive IDs 192 - 223
2654 * [6]: number;
2655 *
2656 * // Shared node bloom for directive IDs 224 - 255
2657 * [7]: number;
2658 *
2659 * // Necessary to find directive indices for a particular node.
2660 * [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
2661 * }
2662 */
2663/**
2664 * Factory for creating instances of injectors in the NodeInjector.
2665 *
2666 * This factory is complicated by the fact that it can resolve `multi` factories as well.
2667 *
2668 * NOTE: Some of the fields are optional which means that this class has two hidden classes.
2669 * - One without `multi` support (most common)
2670 * - One with `multi` values, (rare).
2671 *
2672 * Since VMs can cache up to 4 inline hidden classes this is OK.
2673 *
2674 * - Single factory: Only `resolving` and `factory` is defined.
2675 * - `providers` factory: `componentProviders` is a number and `index = -1`.
2676 * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`.
2677 */
2678class NodeInjectorFactory {
2679 constructor(
2680 /**
2681 * Factory to invoke in order to create a new instance.
2682 */
2683 factory,
2684 /**
2685 * Set to `true` if the token is declared in `viewProviders` (or if it is component).
2686 */
2687 isViewProvider, injectImplementation) {
2688 this.factory = factory;
2689 /**
2690 * Marker set to true during factory invocation to see if we get into recursive loop.
2691 * Recursive loop causes an error to be displayed.
2692 */
2693 this.resolving = false;
2694 ngDevMode && assertDefined(factory, 'Factory not specified');
2695 ngDevMode && assertEqual(typeof factory, 'function', 'Expected factory function.');
2696 this.canSeeViewProviders = isViewProvider;
2697 this.injectImpl = injectImplementation;
2698 }
2699}
2700function isFactory(obj) {
2701 return obj instanceof NodeInjectorFactory;
2702}
2703// Note: This hack is necessary so we don't erroneously get a circular dependency
2704// failure based on types.
2705const unusedValueExportToPlacateAjd$5 = 1;
2706
2707/**
2708 * Converts `TNodeType` into human readable text.
2709 * Make sure this matches with `TNodeType`
2710 */
2711function toTNodeTypeAsString(tNodeType) {
2712 let text = '';
2713 (tNodeType & 1 /* Text */) && (text += '|Text');
2714 (tNodeType & 2 /* Element */) && (text += '|Element');
2715 (tNodeType & 4 /* Container */) && (text += '|Container');
2716 (tNodeType & 8 /* ElementContainer */) && (text += '|ElementContainer');
2717 (tNodeType & 16 /* Projection */) && (text += '|Projection');
2718 (tNodeType & 32 /* Icu */) && (text += '|IcuContainer');
2719 (tNodeType & 64 /* Placeholder */) && (text += '|Placeholder');
2720 return text.length > 0 ? text.substring(1) : text;
2721}
2722// Note: This hack is necessary so we don't erroneously get a circular dependency
2723// failure based on types.
2724const unusedValueExportToPlacateAjd$4 = 1;
2725/**
2726 * Returns `true` if the `TNode` has a directive which has `@Input()` for `class` binding.
2727 *
2728 * ```
2729 * <div my-dir [class]="exp"></div>
2730 * ```
2731 * and
2732 * ```
2733 * @Directive({
2734 * })
2735 * class MyDirective {
2736 * @Input()
2737 * class: string;
2738 * }
2739 * ```
2740 *
2741 * In the above case it is necessary to write the reconciled styling information into the
2742 * directive's input.
2743 *
2744 * @param tNode
2745 */
2746function hasClassInput(tNode) {
2747 return (tNode.flags & 16 /* hasClassInput */) !== 0;
2748}
2749/**
2750 * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
2751 *
2752 * ```
2753 * <div my-dir [style]="exp"></div>
2754 * ```
2755 * and
2756 * ```
2757 * @Directive({
2758 * })
2759 * class MyDirective {
2760 * @Input()
2761 * class: string;
2762 * }
2763 * ```
2764 *
2765 * In the above case it is necessary to write the reconciled styling information into the
2766 * directive's input.
2767 *
2768 * @param tNode
2769 */
2770function hasStyleInput(tNode) {
2771 return (tNode.flags & 32 /* hasStyleInput */) !== 0;
2772}
2773
2774/**
2775 * @license
2776 * Copyright Google LLC All Rights Reserved.
2777 *
2778 * Use of this source code is governed by an MIT-style license that can be
2779 * found in the LICENSE file at https://angular.io/license
2780 */
2781function assertTNodeType(tNode, expectedTypes, message) {
2782 assertDefined(tNode, 'should be called with a TNode');
2783 if ((tNode.type & expectedTypes) === 0) {
2784 throwError(message ||
2785 `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
2786 }
2787}
2788function assertPureTNodeType(type) {
2789 if (!(type === 2 /* Element */ || //
2790 type === 1 /* Text */ || //
2791 type === 4 /* Container */ || //
2792 type === 8 /* ElementContainer */ || //
2793 type === 32 /* Icu */ || //
2794 type === 16 /* Projection */ || //
2795 type === 64 /* Placeholder */)) {
2796 throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
2797 }
2798}
2799
2800/**
2801 * Assigns all attribute values to the provided element via the inferred renderer.
2802 *
2803 * This function accepts two forms of attribute entries:
2804 *
2805 * default: (key, value):
2806 * attrs = [key1, value1, key2, value2]
2807 *
2808 * namespaced: (NAMESPACE_MARKER, uri, name, value)
2809 * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
2810 *
2811 * The `attrs` array can contain a mix of both the default and namespaced entries.
2812 * The "default" values are set without a marker, but if the function comes across
2813 * a marker value then it will attempt to set a namespaced value. If the marker is
2814 * not of a namespaced value then the function will quit and return the index value
2815 * where it stopped during the iteration of the attrs array.
2816 *
2817 * See [AttributeMarker] to understand what the namespace marker value is.
2818 *
2819 * Note that this instruction does not support assigning style and class values to
2820 * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
2821 * are applied to an element.
2822 * @param renderer The renderer to be used
2823 * @param native The element that the attributes will be assigned to
2824 * @param attrs The attribute array of values that will be assigned to the element
2825 * @returns the index value that was last accessed in the attributes array
2826 */
2827function setUpAttributes(renderer, native, attrs) {
2828 const isProc = isProceduralRenderer(renderer);
2829 let i = 0;
2830 while (i < attrs.length) {
2831 const value = attrs[i];
2832 if (typeof value === 'number') {
2833 // only namespaces are supported. Other value types (such as style/class
2834 // entries) are not supported in this function.
2835 if (value !== 0 /* NamespaceURI */) {
2836 break;
2837 }
2838 // we just landed on the marker value ... therefore
2839 // we should skip to the next entry
2840 i++;
2841 const namespaceURI = attrs[i++];
2842 const attrName = attrs[i++];
2843 const attrVal = attrs[i++];
2844 ngDevMode && ngDevMode.rendererSetAttribute++;
2845 isProc ?
2846 renderer.setAttribute(native, attrName, attrVal, namespaceURI) :
2847 native.setAttributeNS(namespaceURI, attrName, attrVal);
2848 }
2849 else {
2850 // attrName is string;
2851 const attrName = value;
2852 const attrVal = attrs[++i];
2853 // Standard attributes
2854 ngDevMode && ngDevMode.rendererSetAttribute++;
2855 if (isAnimationProp(attrName)) {
2856 if (isProc) {
2857 renderer.setProperty(native, attrName, attrVal);
2858 }
2859 }
2860 else {
2861 isProc ?
2862 renderer.setAttribute(native, attrName, attrVal) :
2863 native.setAttribute(attrName, attrVal);
2864 }
2865 i++;
2866 }
2867 }
2868 // another piece of code may iterate over the same attributes array. Therefore
2869 // it may be helpful to return the exact spot where the attributes array exited
2870 // whether by running into an unsupported marker or if all the static values were
2871 // iterated over.
2872 return i;
2873}
2874/**
2875 * Test whether the given value is a marker that indicates that the following
2876 * attribute values in a `TAttributes` array are only the names of attributes,
2877 * and not name-value pairs.
2878 * @param marker The attribute marker to test.
2879 * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
2880 */
2881function isNameOnlyAttributeMarker(marker) {
2882 return marker === 3 /* Bindings */ || marker === 4 /* Template */ ||
2883 marker === 6 /* I18n */;
2884}
2885function isAnimationProp(name) {
2886 // Perf note: accessing charCodeAt to check for the first character of a string is faster as
2887 // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
2888 // charCodeAt doesn't allocate memory to return a substring.
2889 return name.charCodeAt(0) === 64 /* AT_SIGN */;
2890}
2891/**
2892 * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
2893 *
2894 * This merge function keeps the order of attrs same.
2895 *
2896 * @param dst Location of where the merged `TAttributes` should end up.
2897 * @param src `TAttributes` which should be appended to `dst`
2898 */
2899function mergeHostAttrs(dst, src) {
2900 if (src === null || src.length === 0) {
2901 // do nothing
2902 }
2903 else if (dst === null || dst.length === 0) {
2904 // We have source, but dst is empty, just make a copy.
2905 dst = src.slice();
2906 }
2907 else {
2908 let srcMarker = -1 /* ImplicitAttributes */;
2909 for (let i = 0; i < src.length; i++) {
2910 const item = src[i];
2911 if (typeof item === 'number') {
2912 srcMarker = item;
2913 }
2914 else {
2915 if (srcMarker === 0 /* NamespaceURI */) {
2916 // Case where we need to consume `key1`, `key2`, `value` items.
2917 }
2918 else if (srcMarker === -1 /* ImplicitAttributes */ ||
2919 srcMarker === 2 /* Styles */) {
2920 // Case where we have to consume `key1` and `value` only.
2921 mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
2922 }
2923 else {
2924 // Case where we have to consume `key1` only.
2925 mergeHostAttribute(dst, srcMarker, item, null, null);
2926 }
2927 }
2928 }
2929 }
2930 return dst;
2931}
2932/**
2933 * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
2934 *
2935 * @param dst `TAttributes` to append to.
2936 * @param marker Region where the `key`/`value` should be added.
2937 * @param key1 Key to add to `TAttributes`
2938 * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
2939 * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
2940 */
2941function mergeHostAttribute(dst, marker, key1, key2, value) {
2942 let i = 0;
2943 // Assume that new markers will be inserted at the end.
2944 let markerInsertPosition = dst.length;
2945 // scan until correct type.
2946 if (marker === -1 /* ImplicitAttributes */) {
2947 markerInsertPosition = -1;
2948 }
2949 else {
2950 while (i < dst.length) {
2951 const dstValue = dst[i++];
2952 if (typeof dstValue === 'number') {
2953 if (dstValue === marker) {
2954 markerInsertPosition = -1;
2955 break;
2956 }
2957 else if (dstValue > marker) {
2958 // We need to save this as we want the markers to be inserted in specific order.
2959 markerInsertPosition = i - 1;
2960 break;
2961 }
2962 }
2963 }
2964 }
2965 // search until you find place of insertion
2966 while (i < dst.length) {
2967 const item = dst[i];
2968 if (typeof item === 'number') {
2969 // since `i` started as the index after the marker, we did not find it if we are at the next
2970 // marker
2971 break;
2972 }
2973 else if (item === key1) {
2974 // We already have same token
2975 if (key2 === null) {
2976 if (value !== null) {
2977 dst[i + 1] = value;
2978 }
2979 return;
2980 }
2981 else if (key2 === dst[i + 1]) {
2982 dst[i + 2] = value;
2983 return;
2984 }
2985 }
2986 // Increment counter.
2987 i++;
2988 if (key2 !== null)
2989 i++;
2990 if (value !== null)
2991 i++;
2992 }
2993 // insert at location.
2994 if (markerInsertPosition !== -1) {
2995 dst.splice(markerInsertPosition, 0, marker);
2996 i = markerInsertPosition + 1;
2997 }
2998 dst.splice(i++, 0, key1);
2999 if (key2 !== null) {
3000 dst.splice(i++, 0, key2);
3001 }
3002 if (value !== null) {
3003 dst.splice(i++, 0, value);
3004 }
3005}
3006
3007/**
3008 * @license
3009 * Copyright Google LLC All Rights Reserved.
3010 *
3011 * Use of this source code is governed by an MIT-style license that can be
3012 * found in the LICENSE file at https://angular.io/license
3013 */
3014/// Parent Injector Utils ///////////////////////////////////////////////////////////////
3015function hasParentInjector(parentLocation) {
3016 return parentLocation !== NO_PARENT_INJECTOR;
3017}
3018function getParentInjectorIndex(parentLocation) {
3019 ngDevMode && assertNumber(parentLocation, 'Number expected');
3020 ngDevMode && assertNotEqual(parentLocation, -1, 'Not a valid state.');
3021 const parentInjectorIndex = parentLocation & 32767 /* InjectorIndexMask */;
3022 ngDevMode &&
3023 assertGreaterThan(parentInjectorIndex, HEADER_OFFSET, 'Parent injector must be pointing past HEADER_OFFSET.');
3024 return parentLocation & 32767 /* InjectorIndexMask */;
3025}
3026function getParentInjectorViewOffset(parentLocation) {
3027 return parentLocation >> 16 /* ViewOffsetShift */;
3028}
3029/**
3030 * Unwraps a parent injector location number to find the view offset from the current injector,
3031 * then walks up the declaration view tree until the view is found that contains the parent
3032 * injector.
3033 *
3034 * @param location The location of the parent injector, which contains the view offset
3035 * @param startView The LView instance from which to start walking up the view tree
3036 * @returns The LView instance that contains the parent injector
3037 */
3038function getParentInjectorView(location, startView) {
3039 let viewOffset = getParentInjectorViewOffset(location);
3040 let parentView = startView;
3041 // For most cases, the parent injector can be found on the host node (e.g. for component
3042 // or container), but we must keep the loop here to support the rarer case of deeply nested
3043 // <ng-template> tags or inline views, where the parent injector might live many views
3044 // above the child injector.
3045 while (viewOffset > 0) {
3046 parentView = parentView[DECLARATION_VIEW];
3047 viewOffset--;
3048 }
3049 return parentView;
3050}
3051
3052/**
3053 * @license
3054 * Copyright Google LLC All Rights Reserved.
3055 *
3056 * Use of this source code is governed by an MIT-style license that can be
3057 * found in the LICENSE file at https://angular.io/license
3058 */
3059/**
3060 * Defines if the call to `inject` should include `viewProviders` in its resolution.
3061 *
3062 * This is set to true when we try to instantiate a component. This value is reset in
3063 * `getNodeInjectable` to a value which matches the declaration location of the token about to be
3064 * instantiated. This is done so that if we are injecting a token which was declared outside of
3065 * `viewProviders` we don't accidentally pull `viewProviders` in.
3066 *
3067 * Example:
3068 *
3069 * ```
3070 * @Injectable()
3071 * class MyService {
3072 * constructor(public value: String) {}
3073 * }
3074 *
3075 * @Component({
3076 * providers: [
3077 * MyService,
3078 * {provide: String, value: 'providers' }
3079 * ]
3080 * viewProviders: [
3081 * {provide: String, value: 'viewProviders'}
3082 * ]
3083 * })
3084 * class MyComponent {
3085 * constructor(myService: MyService, value: String) {
3086 * // We expect that Component can see into `viewProviders`.
3087 * expect(value).toEqual('viewProviders');
3088 * // `MyService` was not declared in `viewProviders` hence it can't see it.
3089 * expect(myService.value).toEqual('providers');
3090 * }
3091 * }
3092 *
3093 * ```
3094 */
3095let includeViewProviders = true;
3096function setIncludeViewProviders(v) {
3097 const oldValue = includeViewProviders;
3098 includeViewProviders = v;
3099 return oldValue;
3100}
3101/**
3102 * The number of slots in each bloom filter (used by DI). The larger this number, the fewer
3103 * directives that will share slots, and thus, the fewer false positives when checking for
3104 * the existence of a directive.
3105 */
3106const BLOOM_SIZE = 256;
3107const BLOOM_MASK = BLOOM_SIZE - 1;
3108/**
3109 * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits,
3110 * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash
3111 * number.
3112 */
3113const BLOOM_BUCKET_BITS = 5;
3114/** Counter used to generate unique IDs for directives. */
3115let nextNgElementId = 0;
3116/**
3117 * Registers this directive as present in its node's injector by flipping the directive's
3118 * corresponding bit in the injector's bloom filter.
3119 *
3120 * @param injectorIndex The index of the node injector where this token should be registered
3121 * @param tView The TView for the injector's bloom filters
3122 * @param type The directive token to register
3123 */
3124function bloomAdd(injectorIndex, tView, type) {
3125 ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
3126 let id;
3127 if (typeof type === 'string') {
3128 id = type.charCodeAt(0) || 0;
3129 }
3130 else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
3131 id = type[NG_ELEMENT_ID];
3132 }
3133 // Set a unique ID on the directive type, so if something tries to inject the directive,
3134 // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
3135 if (id == null) {
3136 id = type[NG_ELEMENT_ID] = nextNgElementId++;
3137 }
3138 // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
3139 // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
3140 const bloomHash = id & BLOOM_MASK;
3141 // Create a mask that targets the specific bit associated with the directive.
3142 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
3143 // to bit positions 0 - 31 in a 32 bit integer.
3144 const mask = 1 << bloomHash;
3145 // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`.
3146 // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask
3147 // should be written to.
3148 tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask;
3149}
3150/**
3151 * Creates (or gets an existing) injector for a given element or container.
3152 *
3153 * @param tNode for which an injector should be retrieved / created.
3154 * @param lView View where the node is stored
3155 * @returns Node injector
3156 */
3157function getOrCreateNodeInjectorForNode(tNode, lView) {
3158 const existingInjectorIndex = getInjectorIndex(tNode, lView);
3159 if (existingInjectorIndex !== -1) {
3160 return existingInjectorIndex;
3161 }
3162 const tView = lView[TVIEW];
3163 if (tView.firstCreatePass) {
3164 tNode.injectorIndex = lView.length;
3165 insertBloom(tView.data, tNode); // foundation for node bloom
3166 insertBloom(lView, null); // foundation for cumulative bloom
3167 insertBloom(tView.blueprint, null);
3168 }
3169 const parentLoc = getParentInjectorLocation(tNode, lView);
3170 const injectorIndex = tNode.injectorIndex;
3171 // If a parent injector can't be found, its location is set to -1.
3172 // In that case, we don't need to set up a cumulative bloom
3173 if (hasParentInjector(parentLoc)) {
3174 const parentIndex = getParentInjectorIndex(parentLoc);
3175 const parentLView = getParentInjectorView(parentLoc, lView);
3176 const parentData = parentLView[TVIEW].data;
3177 // Creates a cumulative bloom filter that merges the parent's bloom filter
3178 // and its own cumulative bloom (which contains tokens for all ancestors)
3179 for (let i = 0; i < 8 /* BLOOM_SIZE */; i++) {
3180 lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
3181 }
3182 }
3183 lView[injectorIndex + 8 /* PARENT */] = parentLoc;
3184 return injectorIndex;
3185}
3186function insertBloom(arr, footer) {
3187 arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
3188}
3189function getInjectorIndex(tNode, lView) {
3190 if (tNode.injectorIndex === -1 ||
3191 // If the injector index is the same as its parent's injector index, then the index has been
3192 // copied down from the parent node. No injector has been created yet on this node.
3193 (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
3194 // After the first template pass, the injector index might exist but the parent values
3195 // might not have been calculated yet for this instance
3196 lView[tNode.injectorIndex + 8 /* PARENT */] === null) {
3197 return -1;
3198 }
3199 else {
3200 ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
3201 return tNode.injectorIndex;
3202 }
3203}
3204/**
3205 * Finds the index of the parent injector, with a view offset if applicable. Used to set the
3206 * parent injector initially.
3207 *
3208 * @returns Returns a number that is the combination of the number of LViews that we have to go up
3209 * to find the LView containing the parent inject AND the index of the injector within that LView.
3210 */
3211function getParentInjectorLocation(tNode, lView) {
3212 if (tNode.parent && tNode.parent.injectorIndex !== -1) {
3213 // If we have a parent `TNode` and there is an injector associated with it we are done, because
3214 // the parent injector is within the current `LView`.
3215 return tNode.parent.injectorIndex; // ViewOffset is 0
3216 }
3217 // When parent injector location is computed it may be outside of the current view. (ie it could
3218 // be pointing to a declared parent location). This variable stores number of declaration parents
3219 // we need to walk up in order to find the parent injector location.
3220 let declarationViewOffset = 0;
3221 let parentTNode = null;
3222 let lViewCursor = lView;
3223 // The parent injector is not in the current `LView`. We will have to walk the declared parent
3224 // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
3225 // `NodeInjector`.
3226 while (lViewCursor !== null) {
3227 // First determine the `parentTNode` location. The parent pointer differs based on `TView.type`.
3228 const tView = lViewCursor[TVIEW];
3229 const tViewType = tView.type;
3230 if (tViewType === 2 /* Embedded */) {
3231 ngDevMode &&
3232 assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
3233 parentTNode = tView.declTNode;
3234 }
3235 else if (tViewType === 1 /* Component */) {
3236 // Components don't have `TView.declTNode` because each instance of component could be
3237 // inserted in different location, hence `TView.declTNode` is meaningless.
3238 parentTNode = lViewCursor[T_HOST];
3239 }
3240 else {
3241 ngDevMode && assertEqual(tView.type, 0 /* Root */, 'Root type expected');
3242 parentTNode = null;
3243 }
3244 if (parentTNode === null) {
3245 // If we have no parent, than we are done.
3246 return NO_PARENT_INJECTOR;
3247 }
3248 ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]);
3249 // Every iteration of the loop requires that we go to the declared parent.
3250 declarationViewOffset++;
3251 lViewCursor = lViewCursor[DECLARATION_VIEW];
3252 if (parentTNode.injectorIndex !== -1) {
3253 // We found a NodeInjector which points to something.
3254 return (parentTNode.injectorIndex |
3255 (declarationViewOffset << 16 /* ViewOffsetShift */));
3256 }
3257 }
3258 return NO_PARENT_INJECTOR;
3259}
3260/**
3261 * Makes a type or an injection token public to the DI system by adding it to an
3262 * injector's bloom filter.
3263 *
3264 * @param di The node injector in which a directive will be added
3265 * @param token The type or the injection token to be made public
3266 */
3267function diPublicInInjector(injectorIndex, tView, token) {
3268 bloomAdd(injectorIndex, tView, token);
3269}
3270/**
3271 * Inject static attribute value into directive constructor.
3272 *
3273 * This method is used with `factory` functions which are generated as part of
3274 * `defineDirective` or `defineComponent`. The method retrieves the static value
3275 * of an attribute. (Dynamic attributes are not supported since they are not resolved
3276 * at the time of injection and can change over time.)
3277 *
3278 * # Example
3279 * Given:
3280 * ```
3281 * @Component(...)
3282 * class MyComponent {
3283 * constructor(@Attribute('title') title: string) { ... }
3284 * }
3285 * ```
3286 * When instantiated with
3287 * ```
3288 * <my-component title="Hello"></my-component>
3289 * ```
3290 *
3291 * Then factory method generated is:
3292 * ```
3293 * MyComponent.ɵcmp = defineComponent({
3294 * factory: () => new MyComponent(injectAttribute('title'))
3295 * ...
3296 * })
3297 * ```
3298 *
3299 * @publicApi
3300 */
3301function injectAttributeImpl(tNode, attrNameToInject) {
3302 ngDevMode && assertTNodeType(tNode, 12 /* AnyContainer */ | 3 /* AnyRNode */);
3303 ngDevMode && assertDefined(tNode, 'expecting tNode');
3304 if (attrNameToInject === 'class') {
3305 return tNode.classes;
3306 }
3307 if (attrNameToInject === 'style') {
3308 return tNode.styles;
3309 }
3310 const attrs = tNode.attrs;
3311 if (attrs) {
3312 const attrsLength = attrs.length;
3313 let i = 0;
3314 while (i < attrsLength) {
3315 const value = attrs[i];
3316 // If we hit a `Bindings` or `Template` marker then we are done.
3317 if (isNameOnlyAttributeMarker(value))
3318 break;
3319 // Skip namespaced attributes
3320 if (value === 0 /* NamespaceURI */) {
3321 // we skip the next two values
3322 // as namespaced attributes looks like
3323 // [..., AttributeMarker.NamespaceURI, 'http://someuri.com/test', 'test:exist',
3324 // 'existValue', ...]
3325 i = i + 2;
3326 }
3327 else if (typeof value === 'number') {
3328 // Skip to the first value of the marked attribute.
3329 i++;
3330 while (i < attrsLength && typeof attrs[i] === 'string') {
3331 i++;
3332 }
3333 }
3334 else if (value === attrNameToInject) {
3335 return attrs[i + 1];
3336 }
3337 else {
3338 i = i + 2;
3339 }
3340 }
3341 }
3342 return null;
3343}
3344function notFoundValueOrThrow(notFoundValue, token, flags) {
3345 if (flags & InjectFlags.Optional) {
3346 return notFoundValue;
3347 }
3348 else {
3349 throwProviderNotFoundError(token, 'NodeInjector');
3350 }
3351}
3352/**
3353 * Returns the value associated to the given token from the ModuleInjector or throws exception
3354 *
3355 * @param lView The `LView` that contains the `tNode`
3356 * @param token The token to look for
3357 * @param flags Injection flags
3358 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3359 * @returns the value from the injector or throws an exception
3360 */
3361function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) {
3362 if (flags & InjectFlags.Optional && notFoundValue === undefined) {
3363 // This must be set or the NullInjector will throw for optional deps
3364 notFoundValue = null;
3365 }
3366 if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
3367 const moduleInjector = lView[INJECTOR$1];
3368 // switch to `injectInjectorOnly` implementation for module injector, since module injector
3369 // should not have access to Component/Directive DI scope (that may happen through
3370 // `directiveInject` implementation)
3371 const previousInjectImplementation = setInjectImplementation(undefined);
3372 try {
3373 if (moduleInjector) {
3374 return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
3375 }
3376 else {
3377 return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
3378 }
3379 }
3380 finally {
3381 setInjectImplementation(previousInjectImplementation);
3382 }
3383 }
3384 return notFoundValueOrThrow(notFoundValue, token, flags);
3385}
3386/**
3387 * Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
3388 *
3389 * Look for the injector providing the token by walking up the node injector tree and then
3390 * the module injector tree.
3391 *
3392 * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom
3393 * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`)
3394 *
3395 * @param tNode The Node where the search for the injector should start
3396 * @param lView The `LView` that contains the `tNode`
3397 * @param token The token to look for
3398 * @param flags Injection flags
3399 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3400 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
3401 */
3402function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) {
3403 if (tNode !== null) {
3404 const bloomHash = bloomHashBitOrFactory(token);
3405 // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
3406 // so just call the factory function to create it.
3407 if (typeof bloomHash === 'function') {
3408 if (!enterDI(lView, tNode, flags)) {
3409 // Failed to enter DI, try module injector instead. If a token is injected with the @Host
3410 // flag, the module injector is not searched for that token in Ivy.
3411 return (flags & InjectFlags.Host) ?
3412 notFoundValueOrThrow(notFoundValue, token, flags) :
3413 lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
3414 }
3415 try {
3416 const value = bloomHash(flags);
3417 if (value == null && !(flags & InjectFlags.Optional)) {
3418 throwProviderNotFoundError(token);
3419 }
3420 else {
3421 return value;
3422 }
3423 }
3424 finally {
3425 leaveDI();
3426 }
3427 }
3428 else if (typeof bloomHash === 'number') {
3429 // A reference to the previous injector TView that was found while climbing the element
3430 // injector tree. This is used to know if viewProviders can be accessed on the current
3431 // injector.
3432 let previousTView = null;
3433 let injectorIndex = getInjectorIndex(tNode, lView);
3434 let parentLocation = NO_PARENT_INJECTOR;
3435 let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
3436 // If we should skip this injector, or if there is no injector on this node, start by
3437 // searching the parent injector.
3438 if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
3439 parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
3440 lView[injectorIndex + 8 /* PARENT */];
3441 if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
3442 injectorIndex = -1;
3443 }
3444 else {
3445 previousTView = lView[TVIEW];
3446 injectorIndex = getParentInjectorIndex(parentLocation);
3447 lView = getParentInjectorView(parentLocation, lView);
3448 }
3449 }
3450 // Traverse up the injector tree until we find a potential match or until we know there
3451 // *isn't* a match.
3452 while (injectorIndex !== -1) {
3453 ngDevMode && assertNodeInjector(lView, injectorIndex);
3454 // Check the current injector. If it matches, see if it contains token.
3455 const tView = lView[TVIEW];
3456 ngDevMode &&
3457 assertTNodeForLView(tView.data[injectorIndex + 8 /* TNODE */], lView);
3458 if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
3459 // At this point, we have an injector which *may* contain the token, so we step through
3460 // the providers and directives associated with the injector's corresponding node to get
3461 // the instance.
3462 const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode);
3463 if (instance !== NOT_FOUND) {
3464 return instance;
3465 }
3466 }
3467 parentLocation = lView[injectorIndex + 8 /* PARENT */];
3468 if (parentLocation !== NO_PARENT_INJECTOR &&
3469 shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* TNODE */] === hostTElementNode) &&
3470 bloomHasToken(bloomHash, injectorIndex, lView)) {
3471 // The def wasn't found anywhere on this node, so it was a false positive.
3472 // Traverse up the tree and continue searching.
3473 previousTView = tView;
3474 injectorIndex = getParentInjectorIndex(parentLocation);
3475 lView = getParentInjectorView(parentLocation, lView);
3476 }
3477 else {
3478 // If we should not search parent OR If the ancestor bloom filter value does not have the
3479 // bit corresponding to the directive we can give up on traversing up to find the specific
3480 // injector.
3481 injectorIndex = -1;
3482 }
3483 }
3484 }
3485 }
3486 return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
3487}
3488const NOT_FOUND = {};
3489function createNodeInjector() {
3490 return new NodeInjector(getCurrentTNode(), getLView());
3491}
3492function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) {
3493 const currentTView = lView[TVIEW];
3494 const tNode = currentTView.data[injectorIndex + 8 /* TNODE */];
3495 // First, we need to determine if view providers can be accessed by the starting element.
3496 // There are two possibilities
3497 const canAccessViewProviders = previousTView == null ?
3498 // 1) This is the first invocation `previousTView == null` which means that we are at the
3499 // `TNode` of where injector is starting to look. In such a case the only time we are allowed
3500 // to look into the ViewProviders is if:
3501 // - we are on a component
3502 // - AND the injector set `includeViewProviders` to true (implying that the token can see
3503 // ViewProviders because it is the Component or a Service which itself was declared in
3504 // ViewProviders)
3505 (isComponentHost(tNode) && includeViewProviders) :
3506 // 2) `previousTView != null` which means that we are now walking across the parent nodes.
3507 // In such a case we are only allowed to look into the ViewProviders if:
3508 // - We just crossed from child View to Parent View `previousTView != currentTView`
3509 // - AND the parent TNode is an Element.
3510 // This means that we just came from the Component's View and therefore are allowed to see
3511 // into the ViewProviders.
3512 (previousTView != currentTView && ((tNode.type & 3 /* AnyRNode */) !== 0));
3513 // This special case happens when there is a @host on the inject and when we are searching
3514 // on the host element node.
3515 const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode;
3516 const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase);
3517 if (injectableIdx !== null) {
3518 return getNodeInjectable(lView, currentTView, injectableIdx, tNode);
3519 }
3520 else {
3521 return NOT_FOUND;
3522 }
3523}
3524/**
3525 * Searches for the given token among the node's directives and providers.
3526 *
3527 * @param tNode TNode on which directives are present.
3528 * @param tView The tView we are currently processing
3529 * @param token Provider token or type of a directive to look for.
3530 * @param canAccessViewProviders Whether view providers should be considered.
3531 * @param isHostSpecialCase Whether the host special case applies.
3532 * @returns Index of a found directive or provider, or null when none found.
3533 */
3534function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) {
3535 const nodeProviderIndexes = tNode.providerIndexes;
3536 const tInjectables = tView.data;
3537 const injectablesStart = nodeProviderIndexes & 1048575 /* ProvidersStartIndexMask */;
3538 const directivesStart = tNode.directiveStart;
3539 const directiveEnd = tNode.directiveEnd;
3540 const cptViewProvidersCount = nodeProviderIndexes >> 20 /* CptViewProvidersCountShift */;
3541 const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount;
3542 // When the host special case applies, only the viewProviders and the component are visible
3543 const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd;
3544 for (let i = startingIndex; i < endIndex; i++) {
3545 const providerTokenOrDef = tInjectables[i];
3546 if (i < directivesStart && token === providerTokenOrDef ||
3547 i >= directivesStart && providerTokenOrDef.type === token) {
3548 return i;
3549 }
3550 }
3551 if (isHostSpecialCase) {
3552 const dirDef = tInjectables[directivesStart];
3553 if (dirDef && isComponentDef(dirDef) && dirDef.type === token) {
3554 return directivesStart;
3555 }
3556 }
3557 return null;
3558}
3559/**
3560 * Retrieve or instantiate the injectable from the `LView` at particular `index`.
3561 *
3562 * This function checks to see if the value has already been instantiated and if so returns the
3563 * cached `injectable`. Otherwise if it detects that the value is still a factory it
3564 * instantiates the `injectable` and caches the value.
3565 */
3566function getNodeInjectable(lView, tView, index, tNode) {
3567 let value = lView[index];
3568 const tData = tView.data;
3569 if (isFactory(value)) {
3570 const factory = value;
3571 if (factory.resolving) {
3572 throwCyclicDependencyError(stringifyForError(tData[index]));
3573 }
3574 const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
3575 factory.resolving = true;
3576 const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
3577 const success = enterDI(lView, tNode, InjectFlags.Default);
3578 ngDevMode &&
3579 assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.');
3580 try {
3581 value = lView[index] = factory.factory(undefined, tData, lView, tNode);
3582 // This code path is hit for both directives and providers.
3583 // For perf reasons, we want to avoid searching for hooks on providers.
3584 // It does no harm to try (the hooks just won't exist), but the extra
3585 // checks are unnecessary and this is a hot path. So we check to see
3586 // if the index of the dependency is in the directive range for this
3587 // tNode. If it's not, we know it's a provider and skip hook registration.
3588 if (tView.firstCreatePass && index >= tNode.directiveStart) {
3589 ngDevMode && assertDirectiveDef(tData[index]);
3590 registerPreOrderHooks(index, tData[index], tView);
3591 }
3592 }
3593 finally {
3594 previousInjectImplementation !== null &&
3595 setInjectImplementation(previousInjectImplementation);
3596 setIncludeViewProviders(previousIncludeViewProviders);
3597 factory.resolving = false;
3598 leaveDI();
3599 }
3600 }
3601 return value;
3602}
3603/**
3604 * Returns the bit in an injector's bloom filter that should be used to determine whether or not
3605 * the directive might be provided by the injector.
3606 *
3607 * When a directive is public, it is added to the bloom filter and given a unique ID that can be
3608 * retrieved on the Type. When the directive isn't public or the token is not a directive `null`
3609 * is returned as the node injector can not possibly provide that token.
3610 *
3611 * @param token the injection token
3612 * @returns the matching bit to check in the bloom filter or `null` if the token is not known.
3613 * When the returned value is negative then it represents special values such as `Injector`.
3614 */
3615function bloomHashBitOrFactory(token) {
3616 ngDevMode && assertDefined(token, 'token must be defined');
3617 if (typeof token === 'string') {
3618 return token.charCodeAt(0) || 0;
3619 }
3620 const tokenId =
3621 // First check with `hasOwnProperty` so we don't get an inherited ID.
3622 token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined;
3623 // Negative token IDs are used for special objects such as `Injector`
3624 if (typeof tokenId === 'number') {
3625 if (tokenId >= 0) {
3626 return tokenId & BLOOM_MASK;
3627 }
3628 else {
3629 ngDevMode &&
3630 assertEqual(tokenId, -1 /* Injector */, 'Expecting to get Special Injector Id');
3631 return createNodeInjector;
3632 }
3633 }
3634 else {
3635 return tokenId;
3636 }
3637}
3638function bloomHasToken(bloomHash, injectorIndex, injectorView) {
3639 // Create a mask that targets the specific bit associated with the directive we're looking for.
3640 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
3641 // to bit positions 0 - 31 in a 32 bit integer.
3642 const mask = 1 << bloomHash;
3643 // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of
3644 // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset
3645 // that should be used.
3646 const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)];
3647 // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
3648 // this injector is a potential match.
3649 return !!(value & mask);
3650}
3651/** Returns true if flags prevent parent injector from being searched for tokens */
3652function shouldSearchParent(flags, isFirstHostTNode) {
3653 return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode);
3654}
3655class NodeInjector {
3656 constructor(_tNode, _lView) {
3657 this._tNode = _tNode;
3658 this._lView = _lView;
3659 }
3660 get(token, notFoundValue, flags) {
3661 return getOrCreateInjectable(this._tNode, this._lView, token, flags, notFoundValue);
3662 }
3663}
3664/**
3665 * @codeGenApi
3666 */
3667function ɵɵgetInheritedFactory(type) {
3668 return noSideEffects(() => {
3669 const ownConstructor = type.prototype.constructor;
3670 const ownFactory = ownConstructor[NG_FACTORY_DEF] || getFactoryOf(ownConstructor);
3671 const objectPrototype = Object.prototype;
3672 let parent = Object.getPrototypeOf(type.prototype).constructor;
3673 // Go up the prototype until we hit `Object`.
3674 while (parent && parent !== objectPrototype) {
3675 const factory = parent[NG_FACTORY_DEF] || getFactoryOf(parent);
3676 // If we hit something that has a factory and the factory isn't the same as the type,
3677 // we've found the inherited factory. Note the check that the factory isn't the type's
3678 // own factory is redundant in most cases, but if the user has custom decorators on the
3679 // class, this lookup will start one level down in the prototype chain, causing us to
3680 // find the own factory first and potentially triggering an infinite loop downstream.
3681 if (factory && factory !== ownFactory) {
3682 return factory;
3683 }
3684 parent = Object.getPrototypeOf(parent);
3685 }
3686 // There is no factory defined. Either this was improper usage of inheritance
3687 // (no Angular decorator on the superclass) or there is no constructor at all
3688 // in the inheritance chain. Since the two cases cannot be distinguished, the
3689 // latter has to be assumed.
3690 return t => new t();
3691 });
3692}
3693function getFactoryOf(type) {
3694 if (isForwardRef(type)) {
3695 return () => {
3696 const factory = getFactoryOf(resolveForwardRef(type));
3697 return factory && factory();
3698 };
3699 }
3700 return getFactoryDef(type);
3701}
3702
3703/**
3704 * @license
3705 * Copyright Google LLC All Rights Reserved.
3706 *
3707 * Use of this source code is governed by an MIT-style license that can be
3708 * found in the LICENSE file at https://angular.io/license
3709 */
3710/**
3711 * Facade for the attribute injection from DI.
3712 *
3713 * @codeGenApi
3714 */
3715function ɵɵinjectAttribute(attrNameToInject) {
3716 return injectAttributeImpl(getCurrentTNode(), attrNameToInject);
3717}
3718
3719/**
3720 * @license
3721 * Copyright Google LLC All Rights Reserved.
3722 *
3723 * Use of this source code is governed by an MIT-style license that can be
3724 * found in the LICENSE file at https://angular.io/license
3725 */
3726const ANNOTATIONS = '__annotations__';
3727const PARAMETERS = '__parameters__';
3728const PROP_METADATA = '__prop__metadata__';
3729/**
3730 * @suppress {globalThis}
3731 */
3732function makeDecorator(name, props, parentClass, additionalProcessing, typeFn) {
3733 return noSideEffects(() => {
3734 const metaCtor = makeMetadataCtor(props);
3735 function DecoratorFactory(...args) {
3736 if (this instanceof DecoratorFactory) {
3737 metaCtor.call(this, ...args);
3738 return this;
3739 }
3740 const annotationInstance = new DecoratorFactory(...args);
3741 return function TypeDecorator(cls) {
3742 if (typeFn)
3743 typeFn(cls, ...args);
3744 // Use of Object.defineProperty is important since it creates non-enumerable property which
3745 // prevents the property is copied during subclassing.
3746 const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
3747 cls[ANNOTATIONS] :
3748 Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
3749 annotations.push(annotationInstance);
3750 if (additionalProcessing)
3751 additionalProcessing(cls);
3752 return cls;
3753 };
3754 }
3755 if (parentClass) {
3756 DecoratorFactory.prototype = Object.create(parentClass.prototype);
3757 }
3758 DecoratorFactory.prototype.ngMetadataName = name;
3759 DecoratorFactory.annotationCls = DecoratorFactory;
3760 return DecoratorFactory;
3761 });
3762}
3763function makeMetadataCtor(props) {
3764 return function ctor(...args) {
3765 if (props) {
3766 const values = props(...args);
3767 for (const propName in values) {
3768 this[propName] = values[propName];
3769 }
3770 }
3771 };
3772}
3773function makeParamDecorator(name, props, parentClass) {
3774 return noSideEffects(() => {
3775 const metaCtor = makeMetadataCtor(props);
3776 function ParamDecoratorFactory(...args) {
3777 if (this instanceof ParamDecoratorFactory) {
3778 metaCtor.apply(this, args);
3779 return this;
3780 }
3781 const annotationInstance = new ParamDecoratorFactory(...args);
3782 ParamDecorator.annotation = annotationInstance;
3783 return ParamDecorator;
3784 function ParamDecorator(cls, unusedKey, index) {
3785 // Use of Object.defineProperty is important since it creates non-enumerable property which
3786 // prevents the property is copied during subclassing.
3787 const parameters = cls.hasOwnProperty(PARAMETERS) ?
3788 cls[PARAMETERS] :
3789 Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS];
3790 // there might be gaps if some in between parameters do not have annotations.
3791 // we pad with nulls.
3792 while (parameters.length <= index) {
3793 parameters.push(null);
3794 }
3795 (parameters[index] = parameters[index] || []).push(annotationInstance);
3796 return cls;
3797 }
3798 }
3799 if (parentClass) {
3800 ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
3801 }
3802 ParamDecoratorFactory.prototype.ngMetadataName = name;
3803 ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
3804 return ParamDecoratorFactory;
3805 });
3806}
3807function makePropDecorator(name, props, parentClass, additionalProcessing) {
3808 return noSideEffects(() => {
3809 const metaCtor = makeMetadataCtor(props);
3810 function PropDecoratorFactory(...args) {
3811 if (this instanceof PropDecoratorFactory) {
3812 metaCtor.apply(this, args);
3813 return this;
3814 }
3815 const decoratorInstance = new PropDecoratorFactory(...args);
3816 function PropDecorator(target, name) {
3817 const constructor = target.constructor;
3818 // Use of Object.defineProperty is important because it creates a non-enumerable property
3819 // which prevents the property from being copied during subclassing.
3820 const meta = constructor.hasOwnProperty(PROP_METADATA) ?
3821 constructor[PROP_METADATA] :
3822 Object.defineProperty(constructor, PROP_METADATA, { value: {} })[PROP_METADATA];
3823 meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
3824 meta[name].unshift(decoratorInstance);
3825 if (additionalProcessing)
3826 additionalProcessing(target, name, ...args);
3827 }
3828 return PropDecorator;
3829 }
3830 if (parentClass) {
3831 PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
3832 }
3833 PropDecoratorFactory.prototype.ngMetadataName = name;
3834 PropDecoratorFactory.annotationCls = PropDecoratorFactory;
3835 return PropDecoratorFactory;
3836 });
3837}
3838
3839/**
3840 * @license
3841 * Copyright Google LLC All Rights Reserved.
3842 *
3843 * Use of this source code is governed by an MIT-style license that can be
3844 * found in the LICENSE file at https://angular.io/license
3845 */
3846/**
3847 * Attribute decorator and metadata.
3848 *
3849 * @Annotation
3850 * @publicApi
3851 */
3852const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName) }));
3853
3854/**
3855 * @license
3856 * Copyright Google LLC All Rights Reserved.
3857 *
3858 * Use of this source code is governed by an MIT-style license that can be
3859 * found in the LICENSE file at https://angular.io/license
3860 */
3861/**
3862 * Creates a token that can be used in a DI Provider.
3863 *
3864 * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
3865 * runtime representation) such as when injecting an interface, callable type, array or
3866 * parameterized type.
3867 *
3868 * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
3869 * the `Injector`. This provides an additional level of type safety.
3870 *
3871 * ```
3872 * interface MyInterface {...}
3873 * const myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
3874 * // myInterface is inferred to be MyInterface.
3875 * ```
3876 *
3877 * When creating an `InjectionToken`, you can optionally specify a factory function which returns
3878 * (possibly by creating) a default value of the parameterized type `T`. This sets up the
3879 * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
3880 * application's root injector. If the factory function, which takes zero arguments, needs to inject
3881 * dependencies, it can do so using the `inject` function.
3882 * As you can see in the Tree-shakable InjectionToken example below.
3883 *
3884 * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
3885 * overrides the above behavior and marks the token as belonging to a particular `@NgModule`. As
3886 * mentioned above, `'root'` is the default value for `providedIn`.
3887 *
3888 * @usageNotes
3889 * ### Basic Examples
3890 *
3891 * ### Plain InjectionToken
3892 *
3893 * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
3894 *
3895 * ### Tree-shakable InjectionToken
3896 *
3897 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
3898 *
3899 *
3900 * @publicApi
3901 */
3902class InjectionToken {
3903 /**
3904 * @param _desc Description for the token,
3905 * used only for debugging purposes,
3906 * it should but does not need to be unique
3907 * @param options Options for the token's usage, as described above
3908 */
3909 constructor(_desc, options) {
3910 this._desc = _desc;
3911 /** @internal */
3912 this.ngMetadataName = 'InjectionToken';
3913 this.ɵprov = undefined;
3914 if (typeof options == 'number') {
3915 (typeof ngDevMode === 'undefined' || ngDevMode) &&
3916 assertLessThan(options, 0, 'Only negative numbers are supported here');
3917 // This is a special hack to assign __NG_ELEMENT_ID__ to this instance.
3918 // See `InjectorMarkers`
3919 this.__NG_ELEMENT_ID__ = options;
3920 }
3921 else if (options !== undefined) {
3922 this.ɵprov = ɵɵdefineInjectable({
3923 token: this,
3924 providedIn: options.providedIn || 'root',
3925 factory: options.factory,
3926 });
3927 }
3928 }
3929 toString() {
3930 return `InjectionToken ${this._desc}`;
3931 }
3932}
3933
3934/**
3935 * @license
3936 * Copyright Google LLC All Rights Reserved.
3937 *
3938 * Use of this source code is governed by an MIT-style license that can be
3939 * found in the LICENSE file at https://angular.io/license
3940 */
3941/**
3942 * A DI token that you can use to create a virtual [provider](guide/glossary#provider)
3943 * that will populate the `entryComponents` field of components and NgModules
3944 * based on its `useValue` property value.
3945 * All components that are referenced in the `useValue` value (either directly
3946 * or in a nested array or map) are added to the `entryComponents` property.
3947 *
3948 * @usageNotes
3949 *
3950 * The following example shows how the router can populate the `entryComponents`
3951 * field of an NgModule based on a router configuration that refers
3952 * to components.
3953 *
3954 * ```typescript
3955 * // helper function inside the router
3956 * function provideRoutes(routes) {
3957 * return [
3958 * {provide: ROUTES, useValue: routes},
3959 * {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: routes, multi: true}
3960 * ];
3961 * }
3962 *
3963 * // user code
3964 * let routes = [
3965 * {path: '/root', component: RootComp},
3966 * {path: '/teams', component: TeamsComp}
3967 * ];
3968 *
3969 * @NgModule({
3970 * providers: [provideRoutes(routes)]
3971 * })
3972 * class ModuleWithRoutes {}
3973 * ```
3974 *
3975 * @publicApi
3976 * @deprecated Since 9.0.0. With Ivy, this property is no longer necessary.
3977 */
3978const ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForEntryComponents');
3979// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
3980// explicitly set.
3981const emitDistinctChangesOnlyDefaultValue = true;
3982/**
3983 * Base class for query metadata.
3984 *
3985 * @see `ContentChildren`.
3986 * @see `ContentChild`.
3987 * @see `ViewChildren`.
3988 * @see `ViewChild`.
3989 *
3990 * @publicApi
3991 */
3992class Query {
3993}
3994/**
3995 * ContentChildren decorator and metadata.
3996 *
3997 *
3998 * @Annotation
3999 * @publicApi
4000 */
4001const ContentChildren = makePropDecorator('ContentChildren', (selector, data = {}) => ({
4002 selector,
4003 first: false,
4004 isViewQuery: false,
4005 descendants: false,
4006 emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue,
4007 ...data
4008}), Query);
4009/**
4010 * ContentChild decorator and metadata.
4011 *
4012 *
4013 * @Annotation
4014 *
4015 * @publicApi
4016 */
4017const ContentChild = makePropDecorator('ContentChild', (selector, data = {}) => ({ selector, first: true, isViewQuery: false, descendants: true, ...data }), Query);
4018/**
4019 * ViewChildren decorator and metadata.
4020 *
4021 * @Annotation
4022 * @publicApi
4023 */
4024const ViewChildren = makePropDecorator('ViewChildren', (selector, data = {}) => ({
4025 selector,
4026 first: false,
4027 isViewQuery: true,
4028 descendants: true,
4029 emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue,
4030 ...data
4031}), Query);
4032/**
4033 * ViewChild decorator and metadata.
4034 *
4035 * @Annotation
4036 * @publicApi
4037 */
4038const ViewChild = makePropDecorator('ViewChild', (selector, data) => ({ selector, first: true, isViewQuery: true, descendants: true, ...data }), Query);
4039
4040/**
4041 * @license
4042 * Copyright Google LLC All Rights Reserved.
4043 *
4044 * Use of this source code is governed by an MIT-style license that can be
4045 * found in the LICENSE file at https://angular.io/license
4046 */
4047var FactoryTarget;
4048(function (FactoryTarget) {
4049 FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
4050 FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
4051 FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
4052 FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
4053 FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
4054})(FactoryTarget || (FactoryTarget = {}));
4055var ViewEncapsulation;
4056(function (ViewEncapsulation) {
4057 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
4058 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
4059 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
4060 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
4061})(ViewEncapsulation || (ViewEncapsulation = {}));
4062
4063/**
4064 * @license
4065 * Copyright Google LLC All Rights Reserved.
4066 *
4067 * Use of this source code is governed by an MIT-style license that can be
4068 * found in the LICENSE file at https://angular.io/license
4069 */
4070function getCompilerFacade(request) {
4071 const globalNg = _global['ng'];
4072 if (globalNg && globalNg.ɵcompilerFacade) {
4073 return globalNg.ɵcompilerFacade;
4074 }
4075 if (typeof ngDevMode === 'undefined' || ngDevMode) {
4076 // Log the type as an error so that a developer can easily navigate to the type from the
4077 // console.
4078 console.error(`JIT compilation failed for ${request.kind}`, request.type);
4079 let message = `The ${request.kind} '${request
4080 .type.name}' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.\n\n`;
4081 if (request.usage === 1 /* PartialDeclaration */) {
4082 message += `The ${request.kind} is part of a library that has been partially compiled.\n`;
4083 message +=
4084 `However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.\n`;
4085 message += '\n';
4086 message +=
4087 `Ideally, the library is processed using the Angular Linker to become fully AOT compiled.\n`;
4088 }
4089 else {
4090 message +=
4091 `JIT compilation is discouraged for production use-cases! Consider using AOT mode instead.\n`;
4092 }
4093 message +=
4094 `Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',\n`;
4095 message +=
4096 `or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`;
4097 throw new Error(message);
4098 }
4099 else {
4100 throw new Error('JIT compiler unavailable');
4101 }
4102}
4103
4104/**
4105 * @license
4106 * Copyright Google LLC All Rights Reserved.
4107 *
4108 * Use of this source code is governed by an MIT-style license that can be
4109 * found in the LICENSE file at https://angular.io/license
4110 */
4111/**
4112 * @description
4113 *
4114 * Represents a type that a Component or other object is instances of.
4115 *
4116 * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is represented by
4117 * the `MyCustomComponent` constructor function.
4118 *
4119 * @publicApi
4120 */
4121const Type = Function;
4122function isType(v) {
4123 return typeof v === 'function';
4124}
4125
4126/**
4127 * @license
4128 * Copyright Google LLC All Rights Reserved.
4129 *
4130 * Use of this source code is governed by an MIT-style license that can be
4131 * found in the LICENSE file at https://angular.io/license
4132 */
4133/**
4134 * Equivalent to ES6 spread, add each item to an array.
4135 *
4136 * @param items The items to add
4137 * @param arr The array to which you want to add the items
4138 */
4139function addAllToArray(items, arr) {
4140 for (let i = 0; i < items.length; i++) {
4141 arr.push(items[i]);
4142 }
4143}
4144/**
4145 * Determines if the contents of two arrays is identical
4146 *
4147 * @param a first array
4148 * @param b second array
4149 * @param identityAccessor Optional function for extracting stable object identity from a value in
4150 * the array.
4151 */
4152function arrayEquals(a, b, identityAccessor) {
4153 if (a.length !== b.length)
4154 return false;
4155 for (let i = 0; i < a.length; i++) {
4156 let valueA = a[i];
4157 let valueB = b[i];
4158 if (identityAccessor) {
4159 valueA = identityAccessor(valueA);
4160 valueB = identityAccessor(valueB);
4161 }
4162 if (valueB !== valueA) {
4163 return false;
4164 }
4165 }
4166 return true;
4167}
4168/**
4169 * Flattens an array.
4170 */
4171function flatten(list, dst) {
4172 if (dst === undefined)
4173 dst = list;
4174 for (let i = 0; i < list.length; i++) {
4175 let item = list[i];
4176 if (Array.isArray(item)) {
4177 // we need to inline it.
4178 if (dst === list) {
4179 // Our assumption that the list was already flat was wrong and
4180 // we need to clone flat since we need to write to it.
4181 dst = list.slice(0, i);
4182 }
4183 flatten(item, dst);
4184 }
4185 else if (dst !== list) {
4186 dst.push(item);
4187 }
4188 }
4189 return dst;
4190}
4191function deepForEach(input, fn) {
4192 input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value));
4193}
4194function addToArray(arr, index, value) {
4195 // perf: array.push is faster than array.splice!
4196 if (index >= arr.length) {
4197 arr.push(value);
4198 }
4199 else {
4200 arr.splice(index, 0, value);
4201 }
4202}
4203function removeFromArray(arr, index) {
4204 // perf: array.pop is faster than array.splice!
4205 if (index >= arr.length - 1) {
4206 return arr.pop();
4207 }
4208 else {
4209 return arr.splice(index, 1)[0];
4210 }
4211}
4212function newArray(size, value) {
4213 const list = [];
4214 for (let i = 0; i < size; i++) {
4215 list.push(value);
4216 }
4217 return list;
4218}
4219/**
4220 * Remove item from array (Same as `Array.splice()` but faster.)
4221 *
4222 * `Array.splice()` is not as fast because it has to allocate an array for the elements which were
4223 * removed. This causes memory pressure and slows down code when most of the time we don't
4224 * care about the deleted items array.
4225 *
4226 * https://jsperf.com/fast-array-splice (About 20x faster)
4227 *
4228 * @param array Array to splice
4229 * @param index Index of element in array to remove.
4230 * @param count Number of items to remove.
4231 */
4232function arraySplice(array, index, count) {
4233 const length = array.length - count;
4234 while (index < length) {
4235 array[index] = array[index + count];
4236 index++;
4237 }
4238 while (count--) {
4239 array.pop(); // shrink the array
4240 }
4241}
4242/**
4243 * Same as `Array.splice(index, 0, value)` but faster.
4244 *
4245 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
4246 * removed. This causes memory pressure and slows down code when most of the time we don't
4247 * care about the deleted items array.
4248 *
4249 * @param array Array to splice.
4250 * @param index Index in array where the `value` should be added.
4251 * @param value Value to add to array.
4252 */
4253function arrayInsert(array, index, value) {
4254 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
4255 let end = array.length;
4256 while (end > index) {
4257 const previousEnd = end - 1;
4258 array[end] = array[previousEnd];
4259 end = previousEnd;
4260 }
4261 array[index] = value;
4262}
4263/**
4264 * Same as `Array.splice2(index, 0, value1, value2)` but faster.
4265 *
4266 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
4267 * removed. This causes memory pressure and slows down code when most of the time we don't
4268 * care about the deleted items array.
4269 *
4270 * @param array Array to splice.
4271 * @param index Index in array where the `value` should be added.
4272 * @param value1 Value to add to array.
4273 * @param value2 Value to add to array.
4274 */
4275function arrayInsert2(array, index, value1, value2) {
4276 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
4277 let end = array.length;
4278 if (end == index) {
4279 // inserting at the end.
4280 array.push(value1, value2);
4281 }
4282 else if (end === 1) {
4283 // corner case when we have less items in array than we have items to insert.
4284 array.push(value2, array[0]);
4285 array[0] = value1;
4286 }
4287 else {
4288 end--;
4289 array.push(array[end - 1], array[end]);
4290 while (end > index) {
4291 const previousEnd = end - 2;
4292 array[end] = array[previousEnd];
4293 end--;
4294 }
4295 array[index] = value1;
4296 array[index + 1] = value2;
4297 }
4298}
4299/**
4300 * Insert a `value` into an `array` so that the array remains sorted.
4301 *
4302 * NOTE:
4303 * - Duplicates are not allowed, and are ignored.
4304 * - This uses binary search algorithm for fast inserts.
4305 *
4306 * @param array A sorted array to insert into.
4307 * @param value The value to insert.
4308 * @returns index of the inserted value.
4309 */
4310function arrayInsertSorted(array, value) {
4311 let index = arrayIndexOfSorted(array, value);
4312 if (index < 0) {
4313 // if we did not find it insert it.
4314 index = ~index;
4315 arrayInsert(array, index, value);
4316 }
4317 return index;
4318}
4319/**
4320 * Remove `value` from a sorted `array`.
4321 *
4322 * NOTE:
4323 * - This uses binary search algorithm for fast removals.
4324 *
4325 * @param array A sorted array to remove from.
4326 * @param value The value to remove.
4327 * @returns index of the removed value.
4328 * - positive index if value found and removed.
4329 * - negative index if value not found. (`~index` to get the value where it should have been
4330 * inserted)
4331 */
4332function arrayRemoveSorted(array, value) {
4333 const index = arrayIndexOfSorted(array, value);
4334 if (index >= 0) {
4335 arraySplice(array, index, 1);
4336 }
4337 return index;
4338}
4339/**
4340 * Get an index of an `value` in a sorted `array`.
4341 *
4342 * NOTE:
4343 * - This uses binary search algorithm for fast removals.
4344 *
4345 * @param array A sorted array to binary search.
4346 * @param value The value to look for.
4347 * @returns index of the value.
4348 * - positive index if value found.
4349 * - negative index if value not found. (`~index` to get the value where it should have been
4350 * located)
4351 */
4352function arrayIndexOfSorted(array, value) {
4353 return _arrayIndexOfSorted(array, value, 0);
4354}
4355/**
4356 * Set a `value` for a `key`.
4357 *
4358 * @param keyValueArray to modify.
4359 * @param key The key to locate or create.
4360 * @param value The value to set for a `key`.
4361 * @returns index (always even) of where the value vas set.
4362 */
4363function keyValueArraySet(keyValueArray, key, value) {
4364 let index = keyValueArrayIndexOf(keyValueArray, key);
4365 if (index >= 0) {
4366 // if we found it set it.
4367 keyValueArray[index | 1] = value;
4368 }
4369 else {
4370 index = ~index;
4371 arrayInsert2(keyValueArray, index, key, value);
4372 }
4373 return index;
4374}
4375/**
4376 * Retrieve a `value` for a `key` (on `undefined` if not found.)
4377 *
4378 * @param keyValueArray to search.
4379 * @param key The key to locate.
4380 * @return The `value` stored at the `key` location or `undefined if not found.
4381 */
4382function keyValueArrayGet(keyValueArray, key) {
4383 const index = keyValueArrayIndexOf(keyValueArray, key);
4384 if (index >= 0) {
4385 // if we found it retrieve it.
4386 return keyValueArray[index | 1];
4387 }
4388 return undefined;
4389}
4390/**
4391 * Retrieve a `key` index value in the array or `-1` if not found.
4392 *
4393 * @param keyValueArray to search.
4394 * @param key The key to locate.
4395 * @returns index of where the key is (or should have been.)
4396 * - positive (even) index if key found.
4397 * - negative index if key not found. (`~index` (even) to get the index where it should have
4398 * been inserted.)
4399 */
4400function keyValueArrayIndexOf(keyValueArray, key) {
4401 return _arrayIndexOfSorted(keyValueArray, key, 1);
4402}
4403/**
4404 * Delete a `key` (and `value`) from the `KeyValueArray`.
4405 *
4406 * @param keyValueArray to modify.
4407 * @param key The key to locate or delete (if exist).
4408 * @returns index of where the key was (or should have been.)
4409 * - positive (even) index if key found and deleted.
4410 * - negative index if key not found. (`~index` (even) to get the index where it should have
4411 * been.)
4412 */
4413function keyValueArrayDelete(keyValueArray, key) {
4414 const index = keyValueArrayIndexOf(keyValueArray, key);
4415 if (index >= 0) {
4416 // if we found it remove it.
4417 arraySplice(keyValueArray, index, 2);
4418 }
4419 return index;
4420}
4421/**
4422 * INTERNAL: Get an index of an `value` in a sorted `array` by grouping search by `shift`.
4423 *
4424 * NOTE:
4425 * - This uses binary search algorithm for fast removals.
4426 *
4427 * @param array A sorted array to binary search.
4428 * @param value The value to look for.
4429 * @param shift grouping shift.
4430 * - `0` means look at every location
4431 * - `1` means only look at every other (even) location (the odd locations are to be ignored as
4432 * they are values.)
4433 * @returns index of the value.
4434 * - positive index if value found.
4435 * - negative index if value not found. (`~index` to get the value where it should have been
4436 * inserted)
4437 */
4438function _arrayIndexOfSorted(array, value, shift) {
4439 ngDevMode && assertEqual(Array.isArray(array), true, 'Expecting an array');
4440 let start = 0;
4441 let end = array.length >> shift;
4442 while (end !== start) {
4443 const middle = start + ((end - start) >> 1); // find the middle.
4444 const current = array[middle << shift];
4445 if (value === current) {
4446 return (middle << shift);
4447 }
4448 else if (current > value) {
4449 end = middle;
4450 }
4451 else {
4452 start = middle + 1; // We already searched middle so make it non-inclusive by adding 1
4453 }
4454 }
4455 return ~(end << shift);
4456}
4457
4458/**
4459 * @license
4460 * Copyright Google LLC All Rights Reserved.
4461 *
4462 * Use of this source code is governed by an MIT-style license that can be
4463 * found in the LICENSE file at https://angular.io/license
4464 */
4465/*
4466 * #########################
4467 * Attention: These Regular expressions have to hold even if the code is minified!
4468 * ##########################
4469 */
4470/**
4471 * Regular expression that detects pass-through constructors for ES5 output. This Regex
4472 * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
4473 * it intends to capture the pattern where existing constructors have been downleveled from
4474 * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
4475 *
4476 * ```
4477 * function MyClass() {
4478 * var _this = _super.apply(this, arguments) || this;
4479 * ```
4480 *
4481 * downleveled to ES5 with `downlevelIteration` for TypeScript < 4.2:
4482 * ```
4483 * function MyClass() {
4484 * var _this = _super.apply(this, __spread(arguments)) || this;
4485 * ```
4486 *
4487 * or downleveled to ES5 with `downlevelIteration` for TypeScript >= 4.2:
4488 * ```
4489 * function MyClass() {
4490 * var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
4491 * ```
4492 *
4493 * More details can be found in: https://github.com/angular/angular/issues/38453.
4494 */
4495const ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|(?:[^()]+\(\[\],)?[^()]+\(arguments\).*)\)/;
4496/** Regular expression that detects ES2015 classes which extend from other classes. */
4497const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
4498/**
4499 * Regular expression that detects ES2015 classes which extend from other classes and
4500 * have an explicit constructor defined.
4501 */
4502const ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
4503/**
4504 * Regular expression that detects ES2015 classes which extend from other classes
4505 * and inherit a constructor.
4506 */
4507const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{[^}]*super\(\.\.\.arguments\)/;
4508/**
4509 * Determine whether a stringified type is a class which delegates its constructor
4510 * to its parent.
4511 *
4512 * This is not trivial since compiled code can actually contain a constructor function
4513 * even if the original source code did not. For instance, when the child class contains
4514 * an initialized instance property.
4515 */
4516function isDelegateCtor(typeStr) {
4517 return ES5_DELEGATE_CTOR.test(typeStr) ||
4518 ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
4519 (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
4520}
4521class ReflectionCapabilities {
4522 constructor(reflect) {
4523 this._reflect = reflect || _global['Reflect'];
4524 }
4525 isReflectionEnabled() {
4526 return true;
4527 }
4528 factory(t) {
4529 return (...args) => new t(...args);
4530 }
4531 /** @internal */
4532 _zipTypesAndAnnotations(paramTypes, paramAnnotations) {
4533 let result;
4534 if (typeof paramTypes === 'undefined') {
4535 result = newArray(paramAnnotations.length);
4536 }
4537 else {
4538 result = newArray(paramTypes.length);
4539 }
4540 for (let i = 0; i < result.length; i++) {
4541 // TS outputs Object for parameters without types, while Traceur omits
4542 // the annotations. For now we preserve the Traceur behavior to aid
4543 // migration, but this can be revisited.
4544 if (typeof paramTypes === 'undefined') {
4545 result[i] = [];
4546 }
4547 else if (paramTypes[i] && paramTypes[i] != Object) {
4548 result[i] = [paramTypes[i]];
4549 }
4550 else {
4551 result[i] = [];
4552 }
4553 if (paramAnnotations && paramAnnotations[i] != null) {
4554 result[i] = result[i].concat(paramAnnotations[i]);
4555 }
4556 }
4557 return result;
4558 }
4559 _ownParameters(type, parentCtor) {
4560 const typeStr = type.toString();
4561 // If we have no decorators, we only have function.length as metadata.
4562 // In that case, to detect whether a child class declared an own constructor or not,
4563 // we need to look inside of that constructor to check whether it is
4564 // just calling the parent.
4565 // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
4566 // that sets 'design:paramtypes' to []
4567 // if a class inherits from another class but has no ctor declared itself.
4568 if (isDelegateCtor(typeStr)) {
4569 return null;
4570 }
4571 // Prefer the direct API.
4572 if (type.parameters && type.parameters !== parentCtor.parameters) {
4573 return type.parameters;
4574 }
4575 // API of tsickle for lowering decorators to properties on the class.
4576 const tsickleCtorParams = type.ctorParameters;
4577 if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
4578 // Newer tsickle uses a function closure
4579 // Retain the non-function case for compatibility with older tsickle
4580 const ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
4581 const paramTypes = ctorParameters.map((ctorParam) => ctorParam && ctorParam.type);
4582 const paramAnnotations = ctorParameters.map((ctorParam) => ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
4583 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
4584 }
4585 // API for metadata created by invoking the decorators.
4586 const paramAnnotations = type.hasOwnProperty(PARAMETERS) && type[PARAMETERS];
4587 const paramTypes = this._reflect && this._reflect.getOwnMetadata &&
4588 this._reflect.getOwnMetadata('design:paramtypes', type);
4589 if (paramTypes || paramAnnotations) {
4590 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
4591 }
4592 // If a class has no decorators, at least create metadata
4593 // based on function.length.
4594 // Note: We know that this is a real constructor as we checked
4595 // the content of the constructor above.
4596 return newArray(type.length);
4597 }
4598 parameters(type) {
4599 // Note: only report metadata if we have at least one class decorator
4600 // to stay in sync with the static reflector.
4601 if (!isType(type)) {
4602 return [];
4603 }
4604 const parentCtor = getParentCtor(type);
4605 let parameters = this._ownParameters(type, parentCtor);
4606 if (!parameters && parentCtor !== Object) {
4607 parameters = this.parameters(parentCtor);
4608 }
4609 return parameters || [];
4610 }
4611 _ownAnnotations(typeOrFunc, parentCtor) {
4612 // Prefer the direct API.
4613 if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
4614 let annotations = typeOrFunc.annotations;
4615 if (typeof annotations === 'function' && annotations.annotations) {
4616 annotations = annotations.annotations;
4617 }
4618 return annotations;
4619 }
4620 // API of tsickle for lowering decorators to properties on the class.
4621 if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) {
4622 return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators);
4623 }
4624 // API for metadata created by invoking the decorators.
4625 if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
4626 return typeOrFunc[ANNOTATIONS];
4627 }
4628 return null;
4629 }
4630 annotations(typeOrFunc) {
4631 if (!isType(typeOrFunc)) {
4632 return [];
4633 }
4634 const parentCtor = getParentCtor(typeOrFunc);
4635 const ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
4636 const parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
4637 return parentAnnotations.concat(ownAnnotations);
4638 }
4639 _ownPropMetadata(typeOrFunc, parentCtor) {
4640 // Prefer the direct API.
4641 if (typeOrFunc.propMetadata &&
4642 typeOrFunc.propMetadata !== parentCtor.propMetadata) {
4643 let propMetadata = typeOrFunc.propMetadata;
4644 if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
4645 propMetadata = propMetadata.propMetadata;
4646 }
4647 return propMetadata;
4648 }
4649 // API of tsickle for lowering decorators to properties on the class.
4650 if (typeOrFunc.propDecorators &&
4651 typeOrFunc.propDecorators !== parentCtor.propDecorators) {
4652 const propDecorators = typeOrFunc.propDecorators;
4653 const propMetadata = {};
4654 Object.keys(propDecorators).forEach(prop => {
4655 propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
4656 });
4657 return propMetadata;
4658 }
4659 // API for metadata created by invoking the decorators.
4660 if (typeOrFunc.hasOwnProperty(PROP_METADATA)) {
4661 return typeOrFunc[PROP_METADATA];
4662 }
4663 return null;
4664 }
4665 propMetadata(typeOrFunc) {
4666 if (!isType(typeOrFunc)) {
4667 return {};
4668 }
4669 const parentCtor = getParentCtor(typeOrFunc);
4670 const propMetadata = {};
4671 if (parentCtor !== Object) {
4672 const parentPropMetadata = this.propMetadata(parentCtor);
4673 Object.keys(parentPropMetadata).forEach((propName) => {
4674 propMetadata[propName] = parentPropMetadata[propName];
4675 });
4676 }
4677 const ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
4678 if (ownPropMetadata) {
4679 Object.keys(ownPropMetadata).forEach((propName) => {
4680 const decorators = [];
4681 if (propMetadata.hasOwnProperty(propName)) {
4682 decorators.push(...propMetadata[propName]);
4683 }
4684 decorators.push(...ownPropMetadata[propName]);
4685 propMetadata[propName] = decorators;
4686 });
4687 }
4688 return propMetadata;
4689 }
4690 ownPropMetadata(typeOrFunc) {
4691 if (!isType(typeOrFunc)) {
4692 return {};
4693 }
4694 return this._ownPropMetadata(typeOrFunc, getParentCtor(typeOrFunc)) || {};
4695 }
4696 hasLifecycleHook(type, lcProperty) {
4697 return type instanceof Type && lcProperty in type.prototype;
4698 }
4699 guards(type) {
4700 return {};
4701 }
4702 getter(name) {
4703 return new Function('o', 'return o.' + name + ';');
4704 }
4705 setter(name) {
4706 return new Function('o', 'v', 'return o.' + name + ' = v;');
4707 }
4708 method(name) {
4709 const functionBody = `if (!o.${name}) throw new Error('"${name}" is undefined');
4710 return o.${name}.apply(o, args);`;
4711 return new Function('o', 'args', functionBody);
4712 }
4713 // There is not a concept of import uri in Js, but this is useful in developing Dart applications.
4714 importUri(type) {
4715 // StaticSymbol
4716 if (typeof type === 'object' && type['filePath']) {
4717 return type['filePath'];
4718 }
4719 // Runtime type
4720 return `./${stringify(type)}`;
4721 }
4722 resourceUri(type) {
4723 return `./${stringify(type)}`;
4724 }
4725 resolveIdentifier(name, moduleUrl, members, runtime) {
4726 return runtime;
4727 }
4728 resolveEnum(enumIdentifier, name) {
4729 return enumIdentifier[name];
4730 }
4731}
4732function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
4733 if (!decoratorInvocations) {
4734 return [];
4735 }
4736 return decoratorInvocations.map(decoratorInvocation => {
4737 const decoratorType = decoratorInvocation.type;
4738 const annotationCls = decoratorType.annotationCls;
4739 const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
4740 return new annotationCls(...annotationArgs);
4741 });
4742}
4743function getParentCtor(ctor) {
4744 const parentProto = ctor.prototype ? Object.getPrototypeOf(ctor.prototype) : null;
4745 const parentCtor = parentProto ? parentProto.constructor : null;
4746 // Note: We always use `Object` as the null value
4747 // to simplify checking later on.
4748 return parentCtor || Object;
4749}
4750
4751/**
4752 * @license
4753 * Copyright Google LLC All Rights Reserved.
4754 *
4755 * Use of this source code is governed by an MIT-style license that can be
4756 * found in the LICENSE file at https://angular.io/license
4757 */
4758const _THROW_IF_NOT_FOUND = {};
4759const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
4760/*
4761 * Name of a property (that we patch onto DI decorator), which is used as an annotation of which
4762 * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators
4763 * in the code, thus making them tree-shakable.
4764 */
4765const DI_DECORATOR_FLAG = '__NG_DI_FLAG__';
4766const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath';
4767const NG_TOKEN_PATH = 'ngTokenPath';
4768const NEW_LINE = /\n/gm;
4769const NO_NEW_LINE = 'ɵ';
4770const SOURCE = '__source';
4771const USE_VALUE$1 = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
4772/**
4773 * Current injector value used by `inject`.
4774 * - `undefined`: it is an error to call `inject`
4775 * - `null`: `inject` can be called but there is no injector (limp-mode).
4776 * - Injector instance: Use the injector for resolution.
4777 */
4778let _currentInjector = undefined;
4779function setCurrentInjector(injector) {
4780 const former = _currentInjector;
4781 _currentInjector = injector;
4782 return former;
4783}
4784function injectInjectorOnly(token, flags = InjectFlags.Default) {
4785 if (_currentInjector === undefined) {
4786 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
4787 `inject() must be called from an injection context` :
4788 '';
4789 throw new RuntimeError(203 /* MISSING_INJECTION_CONTEXT */, errorMessage);
4790 }
4791 else if (_currentInjector === null) {
4792 return injectRootLimpMode(token, undefined, flags);
4793 }
4794 else {
4795 return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
4796 }
4797}
4798function ɵɵinject(token, flags = InjectFlags.Default) {
4799 return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef(token), flags);
4800}
4801/**
4802 * Throws an error indicating that a factory function could not be generated by the compiler for a
4803 * particular class.
4804 *
4805 * This instruction allows the actual error message to be optimized away when ngDevMode is turned
4806 * off, saving bytes of generated code while still providing a good experience in dev mode.
4807 *
4808 * The name of the class is not mentioned here, but will be in the generated factory function name
4809 * and thus in the stack trace.
4810 *
4811 * @codeGenApi
4812 */
4813function ɵɵinvalidFactoryDep(index) {
4814 const msg = ngDevMode ?
4815 `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${index} of the parameter list is invalid.
4816This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.
4817
4818Please 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.` :
4819 'invalid';
4820 throw new Error(msg);
4821}
4822/**
4823 * Injects a token from the currently active injector.
4824 *
4825 * Must be used in the context of a factory function such as one defined for an
4826 * `InjectionToken`. Throws an error if not called from such a context.
4827 *
4828 * Within such a factory function, using this function to request injection of a dependency
4829 * is faster and more type-safe than providing an additional array of dependencies
4830 * (as has been common with `useFactory` providers).
4831 *
4832 * @param token The injection token for the dependency to be injected.
4833 * @param flags Optional flags that control how injection is executed.
4834 * The flags correspond to injection strategies that can be specified with
4835 * parameter decorators `@Host`, `@Self`, `@SkipSef`, and `@Optional`.
4836 * @returns the injected value if injection is successful, `null` otherwise.
4837 *
4838 * @usageNotes
4839 *
4840 * ### Example
4841 *
4842 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
4843 *
4844 * @publicApi
4845 */
4846const inject = ɵɵinject;
4847function injectArgs(types) {
4848 const args = [];
4849 for (let i = 0; i < types.length; i++) {
4850 const arg = resolveForwardRef(types[i]);
4851 if (Array.isArray(arg)) {
4852 if (arg.length === 0) {
4853 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
4854 'Arguments array must have arguments.' :
4855 '';
4856 throw new RuntimeError(900 /* INVALID_DIFFER_INPUT */, errorMessage);
4857 }
4858 let type = undefined;
4859 let flags = InjectFlags.Default;
4860 for (let j = 0; j < arg.length; j++) {
4861 const meta = arg[j];
4862 const flag = getInjectFlag(meta);
4863 if (typeof flag === 'number') {
4864 // Special case when we handle @Inject decorator.
4865 if (flag === -1 /* Inject */) {
4866 type = meta.token;
4867 }
4868 else {
4869 flags |= flag;
4870 }
4871 }
4872 else {
4873 type = meta;
4874 }
4875 }
4876 args.push(ɵɵinject(type, flags));
4877 }
4878 else {
4879 args.push(ɵɵinject(arg));
4880 }
4881 }
4882 return args;
4883}
4884/**
4885 * Attaches a given InjectFlag to a given decorator using monkey-patching.
4886 * Since DI decorators can be used in providers `deps` array (when provider is configured using
4887 * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we
4888 * attach the flag to make it available both as a static property and as a field on decorator
4889 * instance.
4890 *
4891 * @param decorator Provided DI decorator.
4892 * @param flag InjectFlag that should be applied.
4893 */
4894function attachInjectFlag(decorator, flag) {
4895 decorator[DI_DECORATOR_FLAG] = flag;
4896 decorator.prototype[DI_DECORATOR_FLAG] = flag;
4897 return decorator;
4898}
4899/**
4900 * Reads monkey-patched property that contains InjectFlag attached to a decorator.
4901 *
4902 * @param token Token that may contain monkey-patched DI flags property.
4903 */
4904function getInjectFlag(token) {
4905 return token[DI_DECORATOR_FLAG];
4906}
4907function catchInjectorError(e, token, injectorErrorName, source) {
4908 const tokenPath = e[NG_TEMP_TOKEN_PATH];
4909 if (token[SOURCE]) {
4910 tokenPath.unshift(token[SOURCE]);
4911 }
4912 e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source);
4913 e[NG_TOKEN_PATH] = tokenPath;
4914 e[NG_TEMP_TOKEN_PATH] = null;
4915 throw e;
4916}
4917function formatError(text, obj, injectorErrorName, source = null) {
4918 text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text;
4919 let context = stringify(obj);
4920 if (Array.isArray(obj)) {
4921 context = obj.map(stringify).join(' -> ');
4922 }
4923 else if (typeof obj === 'object') {
4924 let parts = [];
4925 for (let key in obj) {
4926 if (obj.hasOwnProperty(key)) {
4927 let value = obj[key];
4928 parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value)));
4929 }
4930 }
4931 context = `{${parts.join(', ')}}`;
4932 }
4933 return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
4934}
4935
4936/**
4937 * @license
4938 * Copyright Google LLC All Rights Reserved.
4939 *
4940 * Use of this source code is governed by an MIT-style license that can be
4941 * found in the LICENSE file at https://angular.io/license
4942 */
4943/**
4944 * Inject decorator and metadata.
4945 *
4946 * @Annotation
4947 * @publicApi
4948 */
4949const Inject = attachInjectFlag(
4950// Disable tslint because `DecoratorFlags` is a const enum which gets inlined.
4951// tslint:disable-next-line: no-toplevel-property-access
4952makeParamDecorator('Inject', (token) => ({ token })), -1 /* Inject */);
4953/**
4954 * Optional decorator and metadata.
4955 *
4956 * @Annotation
4957 * @publicApi
4958 */
4959const Optional =
4960// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4961// tslint:disable-next-line: no-toplevel-property-access
4962attachInjectFlag(makeParamDecorator('Optional'), 8 /* Optional */);
4963/**
4964 * Self decorator and metadata.
4965 *
4966 * @Annotation
4967 * @publicApi
4968 */
4969const Self =
4970// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4971// tslint:disable-next-line: no-toplevel-property-access
4972attachInjectFlag(makeParamDecorator('Self'), 2 /* Self */);
4973/**
4974 * `SkipSelf` decorator and metadata.
4975 *
4976 * @Annotation
4977 * @publicApi
4978 */
4979const SkipSelf =
4980// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4981// tslint:disable-next-line: no-toplevel-property-access
4982attachInjectFlag(makeParamDecorator('SkipSelf'), 4 /* SkipSelf */);
4983/**
4984 * Host decorator and metadata.
4985 *
4986 * @Annotation
4987 * @publicApi
4988 */
4989const Host =
4990// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4991// tslint:disable-next-line: no-toplevel-property-access
4992attachInjectFlag(makeParamDecorator('Host'), 1 /* Host */);
4993
4994/**
4995 * @license
4996 * Copyright Google LLC All Rights Reserved.
4997 *
4998 * Use of this source code is governed by an MIT-style license that can be
4999 * found in the LICENSE file at https://angular.io/license
5000 */
5001let _reflect = null;
5002function getReflect() {
5003 return (_reflect = _reflect || new ReflectionCapabilities());
5004}
5005function reflectDependencies(type) {
5006 return convertDependencies(getReflect().parameters(type));
5007}
5008function convertDependencies(deps) {
5009 return deps.map(dep => reflectDependency(dep));
5010}
5011function reflectDependency(dep) {
5012 const meta = {
5013 token: null,
5014 attribute: null,
5015 host: false,
5016 optional: false,
5017 self: false,
5018 skipSelf: false,
5019 };
5020 if (Array.isArray(dep) && dep.length > 0) {
5021 for (let j = 0; j < dep.length; j++) {
5022 const param = dep[j];
5023 if (param === undefined) {
5024 // param may be undefined if type of dep is not set by ngtsc
5025 continue;
5026 }
5027 const proto = Object.getPrototypeOf(param);
5028 if (param instanceof Optional || proto.ngMetadataName === 'Optional') {
5029 meta.optional = true;
5030 }
5031 else if (param instanceof SkipSelf || proto.ngMetadataName === 'SkipSelf') {
5032 meta.skipSelf = true;
5033 }
5034 else if (param instanceof Self || proto.ngMetadataName === 'Self') {
5035 meta.self = true;
5036 }
5037 else if (param instanceof Host || proto.ngMetadataName === 'Host') {
5038 meta.host = true;
5039 }
5040 else if (param instanceof Inject) {
5041 meta.token = param.token;
5042 }
5043 else if (param instanceof Attribute) {
5044 if (param.attributeName === undefined) {
5045 throw new Error(`Attribute name must be defined.`);
5046 }
5047 meta.attribute = param.attributeName;
5048 }
5049 else {
5050 meta.token = param;
5051 }
5052 }
5053 }
5054 else if (dep === undefined || (Array.isArray(dep) && dep.length === 0)) {
5055 meta.token = null;
5056 }
5057 else {
5058 meta.token = dep;
5059 }
5060 return meta;
5061}
5062
5063/**
5064 * @license
5065 * Copyright Google LLC All Rights Reserved.
5066 *
5067 * Use of this source code is governed by an MIT-style license that can be
5068 * found in the LICENSE file at https://angular.io/license
5069 */
5070/**
5071 * Used to resolve resource URLs on `@Component` when used with JIT compilation.
5072 *
5073 * Example:
5074 * ```
5075 * @Component({
5076 * selector: 'my-comp',
5077 * templateUrl: 'my-comp.html', // This requires asynchronous resolution
5078 * })
5079 * class MyComponent{
5080 * }
5081 *
5082 * // Calling `renderComponent` will fail because `renderComponent` is a synchronous process
5083 * // and `MyComponent`'s `@Component.templateUrl` needs to be resolved asynchronously.
5084 *
5085 * // Calling `resolveComponentResources()` will resolve `@Component.templateUrl` into
5086 * // `@Component.template`, which allows `renderComponent` to proceed in a synchronous manner.
5087 *
5088 * // Use browser's `fetch()` function as the default resource resolution strategy.
5089 * resolveComponentResources(fetch).then(() => {
5090 * // After resolution all URLs have been converted into `template` strings.
5091 * renderComponent(MyComponent);
5092 * });
5093 *
5094 * ```
5095 *
5096 * NOTE: In AOT the resolution happens during compilation, and so there should be no need
5097 * to call this method outside JIT mode.
5098 *
5099 * @param resourceResolver a function which is responsible for returning a `Promise` to the
5100 * contents of the resolved URL. Browser's `fetch()` method is a good default implementation.
5101 */
5102function resolveComponentResources(resourceResolver) {
5103 // Store all promises which are fetching the resources.
5104 const componentResolved = [];
5105 // Cache so that we don't fetch the same resource more than once.
5106 const urlMap = new Map();
5107 function cachedResourceResolve(url) {
5108 let promise = urlMap.get(url);
5109 if (!promise) {
5110 const resp = resourceResolver(url);
5111 urlMap.set(url, promise = resp.then(unwrapResponse));
5112 }
5113 return promise;
5114 }
5115 componentResourceResolutionQueue.forEach((component, type) => {
5116 const promises = [];
5117 if (component.templateUrl) {
5118 promises.push(cachedResourceResolve(component.templateUrl).then((template) => {
5119 component.template = template;
5120 }));
5121 }
5122 const styleUrls = component.styleUrls;
5123 const styles = component.styles || (component.styles = []);
5124 const styleOffset = component.styles.length;
5125 styleUrls && styleUrls.forEach((styleUrl, index) => {
5126 styles.push(''); // pre-allocate array.
5127 promises.push(cachedResourceResolve(styleUrl).then((style) => {
5128 styles[styleOffset + index] = style;
5129 styleUrls.splice(styleUrls.indexOf(styleUrl), 1);
5130 if (styleUrls.length == 0) {
5131 component.styleUrls = undefined;
5132 }
5133 }));
5134 });
5135 const fullyResolved = Promise.all(promises).then(() => componentDefResolved(type));
5136 componentResolved.push(fullyResolved);
5137 });
5138 clearResolutionOfComponentResourcesQueue();
5139 return Promise.all(componentResolved).then(() => undefined);
5140}
5141let componentResourceResolutionQueue = new Map();
5142// Track when existing ɵcmp for a Type is waiting on resources.
5143const componentDefPendingResolution = new Set();
5144function maybeQueueResolutionOfComponentResources(type, metadata) {
5145 if (componentNeedsResolution(metadata)) {
5146 componentResourceResolutionQueue.set(type, metadata);
5147 componentDefPendingResolution.add(type);
5148 }
5149}
5150function isComponentDefPendingResolution(type) {
5151 return componentDefPendingResolution.has(type);
5152}
5153function componentNeedsResolution(component) {
5154 return !!((component.templateUrl && !component.hasOwnProperty('template')) ||
5155 component.styleUrls && component.styleUrls.length);
5156}
5157function clearResolutionOfComponentResourcesQueue() {
5158 const old = componentResourceResolutionQueue;
5159 componentResourceResolutionQueue = new Map();
5160 return old;
5161}
5162function restoreComponentResolutionQueue(queue) {
5163 componentDefPendingResolution.clear();
5164 queue.forEach((_, type) => componentDefPendingResolution.add(type));
5165 componentResourceResolutionQueue = queue;
5166}
5167function isComponentResourceResolutionQueueEmpty() {
5168 return componentResourceResolutionQueue.size === 0;
5169}
5170function unwrapResponse(response) {
5171 return typeof response == 'string' ? response : response.text();
5172}
5173function componentDefResolved(type) {
5174 componentDefPendingResolution.delete(type);
5175}
5176
5177/**
5178 * @license
5179 * Copyright Google LLC All Rights Reserved.
5180 *
5181 * Use of this source code is governed by an MIT-style license that can be
5182 * found in the LICENSE file at https://angular.io/license
5183 */
5184/**
5185 * The Trusted Types policy, or null if Trusted Types are not
5186 * enabled/supported, or undefined if the policy has not been created yet.
5187 */
5188let policy$1;
5189/**
5190 * Returns the Trusted Types policy, or null if Trusted Types are not
5191 * enabled/supported. The first call to this function will create the policy.
5192 */
5193function getPolicy$1() {
5194 if (policy$1 === undefined) {
5195 policy$1 = null;
5196 if (_global.trustedTypes) {
5197 try {
5198 policy$1 = _global.trustedTypes.createPolicy('angular', {
5199 createHTML: (s) => s,
5200 createScript: (s) => s,
5201 createScriptURL: (s) => s,
5202 });
5203 }
5204 catch {
5205 // trustedTypes.createPolicy throws if called with a name that is
5206 // already registered, even in report-only mode. Until the API changes,
5207 // catch the error not to break the applications functionally. In such
5208 // cases, the code will fall back to using strings.
5209 }
5210 }
5211 }
5212 return policy$1;
5213}
5214/**
5215 * Unsafely promote a string to a TrustedHTML, falling back to strings when
5216 * Trusted Types are not available.
5217 * @security This is a security-sensitive function; any use of this function
5218 * must go through security review. In particular, it must be assured that the
5219 * provided string will never cause an XSS vulnerability if used in a context
5220 * that will be interpreted as HTML by a browser, e.g. when assigning to
5221 * element.innerHTML.
5222 */
5223function trustedHTMLFromString(html) {
5224 return getPolicy$1()?.createHTML(html) || html;
5225}
5226/**
5227 * Unsafely promote a string to a TrustedScript, falling back to strings when
5228 * Trusted Types are not available.
5229 * @security In particular, it must be assured that the provided string will
5230 * never cause an XSS vulnerability if used in a context that will be
5231 * interpreted and executed as a script by a browser, e.g. when calling eval.
5232 */
5233function trustedScriptFromString(script) {
5234 return getPolicy$1()?.createScript(script) || script;
5235}
5236/**
5237 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
5238 * when Trusted Types are not available.
5239 * @security This is a security-sensitive function; any use of this function
5240 * must go through security review. In particular, it must be assured that the
5241 * provided string will never cause an XSS vulnerability if used in a context
5242 * that will cause a browser to load and execute a resource, e.g. when
5243 * assigning to script.src.
5244 */
5245function trustedScriptURLFromString(url) {
5246 return getPolicy$1()?.createScriptURL(url) || url;
5247}
5248/**
5249 * Unsafely call the Function constructor with the given string arguments. It
5250 * is only available in development mode, and should be stripped out of
5251 * production code.
5252 * @security This is a security-sensitive function; any use of this function
5253 * must go through security review. In particular, it must be assured that it
5254 * is only called from development code, as use in production code can lead to
5255 * XSS vulnerabilities.
5256 */
5257function newTrustedFunctionForDev(...args) {
5258 if (typeof ngDevMode === 'undefined') {
5259 throw new Error('newTrustedFunctionForDev should never be called in production');
5260 }
5261 if (!_global.trustedTypes) {
5262 // In environments that don't support Trusted Types, fall back to the most
5263 // straightforward implementation:
5264 return new Function(...args);
5265 }
5266 // Chrome currently does not support passing TrustedScript to the Function
5267 // constructor. The following implements the workaround proposed on the page
5268 // below, where the Chromium bug is also referenced:
5269 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
5270 const fnArgs = args.slice(0, -1).join(',');
5271 const fnBody = args[args.length - 1];
5272 const body = `(function anonymous(${fnArgs}
5273) { ${fnBody}
5274})`;
5275 // Using eval directly confuses the compiler and prevents this module from
5276 // being stripped out of JS binaries even if not used. The global['eval']
5277 // indirection fixes that.
5278 const fn = _global['eval'](trustedScriptFromString(body));
5279 if (fn.bind === undefined) {
5280 // Workaround for a browser bug that only exists in Chrome 83, where passing
5281 // a TrustedScript to eval just returns the TrustedScript back without
5282 // evaluating it. In that case, fall back to the most straightforward
5283 // implementation:
5284 return new Function(...args);
5285 }
5286 // To completely mimic the behavior of calling "new Function", two more
5287 // things need to happen:
5288 // 1. Stringifying the resulting function should return its source code
5289 fn.toString = () => body;
5290 // 2. When calling the resulting function, `this` should refer to `global`
5291 return fn.bind(_global);
5292 // When Trusted Types support in Function constructors is widely available,
5293 // the implementation of this function can be simplified to:
5294 // return new Function(...args.map(a => trustedScriptFromString(a)));
5295}
5296
5297/**
5298 * @license
5299 * Copyright Google LLC All Rights Reserved.
5300 *
5301 * Use of this source code is governed by an MIT-style license that can be
5302 * found in the LICENSE file at https://angular.io/license
5303 */
5304/**
5305 * The Trusted Types policy, or null if Trusted Types are not
5306 * enabled/supported, or undefined if the policy has not been created yet.
5307 */
5308let policy;
5309/**
5310 * Returns the Trusted Types policy, or null if Trusted Types are not
5311 * enabled/supported. The first call to this function will create the policy.
5312 */
5313function getPolicy() {
5314 if (policy === undefined) {
5315 policy = null;
5316 if (_global.trustedTypes) {
5317 try {
5318 policy = _global.trustedTypes
5319 .createPolicy('angular#unsafe-bypass', {
5320 createHTML: (s) => s,
5321 createScript: (s) => s,
5322 createScriptURL: (s) => s,
5323 });
5324 }
5325 catch {
5326 // trustedTypes.createPolicy throws if called with a name that is
5327 // already registered, even in report-only mode. Until the API changes,
5328 // catch the error not to break the applications functionally. In such
5329 // cases, the code will fall back to using strings.
5330 }
5331 }
5332 }
5333 return policy;
5334}
5335/**
5336 * Unsafely promote a string to a TrustedHTML, falling back to strings when
5337 * Trusted Types are not available.
5338 * @security This is a security-sensitive function; any use of this function
5339 * must go through security review. In particular, it must be assured that it
5340 * is only passed strings that come directly from custom sanitizers or the
5341 * bypassSecurityTrust* functions.
5342 */
5343function trustedHTMLFromStringBypass(html) {
5344 return getPolicy()?.createHTML(html) || html;
5345}
5346/**
5347 * Unsafely promote a string to a TrustedScript, falling back to strings when
5348 * Trusted Types are not available.
5349 * @security This is a security-sensitive function; any use of this function
5350 * must go through security review. In particular, it must be assured that it
5351 * is only passed strings that come directly from custom sanitizers or the
5352 * bypassSecurityTrust* functions.
5353 */
5354function trustedScriptFromStringBypass(script) {
5355 return getPolicy()?.createScript(script) || script;
5356}
5357/**
5358 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
5359 * when Trusted Types are not available.
5360 * @security This is a security-sensitive function; any use of this function
5361 * must go through security review. In particular, it must be assured that it
5362 * is only passed strings that come directly from custom sanitizers or the
5363 * bypassSecurityTrust* functions.
5364 */
5365function trustedScriptURLFromStringBypass(url) {
5366 return getPolicy()?.createScriptURL(url) || url;
5367}
5368
5369/**
5370 * @license
5371 * Copyright Google LLC All Rights Reserved.
5372 *
5373 * Use of this source code is governed by an MIT-style license that can be
5374 * found in the LICENSE file at https://angular.io/license
5375 */
5376class SafeValueImpl {
5377 constructor(changingThisBreaksApplicationSecurity) {
5378 this.changingThisBreaksApplicationSecurity = changingThisBreaksApplicationSecurity;
5379 }
5380 toString() {
5381 return `SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity}` +
5382 ` (see https://g.co/ng/security#xss)`;
5383 }
5384}
5385class SafeHtmlImpl extends SafeValueImpl {
5386 getTypeName() {
5387 return "HTML" /* Html */;
5388 }
5389}
5390class SafeStyleImpl extends SafeValueImpl {
5391 getTypeName() {
5392 return "Style" /* Style */;
5393 }
5394}
5395class SafeScriptImpl extends SafeValueImpl {
5396 getTypeName() {
5397 return "Script" /* Script */;
5398 }
5399}
5400class SafeUrlImpl extends SafeValueImpl {
5401 getTypeName() {
5402 return "URL" /* Url */;
5403 }
5404}
5405class SafeResourceUrlImpl extends SafeValueImpl {
5406 getTypeName() {
5407 return "ResourceURL" /* ResourceUrl */;
5408 }
5409}
5410function unwrapSafeValue(value) {
5411 return value instanceof SafeValueImpl ? value.changingThisBreaksApplicationSecurity :
5412 value;
5413}
5414function allowSanitizationBypassAndThrow(value, type) {
5415 const actualType = getSanitizationBypassType(value);
5416 if (actualType != null && actualType !== type) {
5417 // Allow ResourceURLs in URL contexts, they are strictly more trusted.
5418 if (actualType === "ResourceURL" /* ResourceUrl */ && type === "URL" /* Url */)
5419 return true;
5420 throw new Error(`Required a safe ${type}, got a ${actualType} (see https://g.co/ng/security#xss)`);
5421 }
5422 return actualType === type;
5423}
5424function getSanitizationBypassType(value) {
5425 return value instanceof SafeValueImpl && value.getTypeName() || null;
5426}
5427/**
5428 * Mark `html` string as trusted.
5429 *
5430 * This function wraps the trusted string in `String` and brands it in a way which makes it
5431 * recognizable to {@link htmlSanitizer} to be trusted implicitly.
5432 *
5433 * @param trustedHtml `html` string which needs to be implicitly trusted.
5434 * @returns a `html` which has been branded to be implicitly trusted.
5435 */
5436function bypassSanitizationTrustHtml(trustedHtml) {
5437 return new SafeHtmlImpl(trustedHtml);
5438}
5439/**
5440 * Mark `style` string as trusted.
5441 *
5442 * This function wraps the trusted string in `String` and brands it in a way which makes it
5443 * recognizable to {@link styleSanitizer} to be trusted implicitly.
5444 *
5445 * @param trustedStyle `style` string which needs to be implicitly trusted.
5446 * @returns a `style` hich has been branded to be implicitly trusted.
5447 */
5448function bypassSanitizationTrustStyle(trustedStyle) {
5449 return new SafeStyleImpl(trustedStyle);
5450}
5451/**
5452 * Mark `script` string as trusted.
5453 *
5454 * This function wraps the trusted string in `String` and brands it in a way which makes it
5455 * recognizable to {@link scriptSanitizer} to be trusted implicitly.
5456 *
5457 * @param trustedScript `script` string which needs to be implicitly trusted.
5458 * @returns a `script` which has been branded to be implicitly trusted.
5459 */
5460function bypassSanitizationTrustScript(trustedScript) {
5461 return new SafeScriptImpl(trustedScript);
5462}
5463/**
5464 * Mark `url` string as trusted.
5465 *
5466 * This function wraps the trusted string in `String` and brands it in a way which makes it
5467 * recognizable to {@link urlSanitizer} to be trusted implicitly.
5468 *
5469 * @param trustedUrl `url` string which needs to be implicitly trusted.
5470 * @returns a `url` which has been branded to be implicitly trusted.
5471 */
5472function bypassSanitizationTrustUrl(trustedUrl) {
5473 return new SafeUrlImpl(trustedUrl);
5474}
5475/**
5476 * Mark `url` string as trusted.
5477 *
5478 * This function wraps the trusted string in `String` and brands it in a way which makes it
5479 * recognizable to {@link resourceUrlSanitizer} to be trusted implicitly.
5480 *
5481 * @param trustedResourceUrl `url` string which needs to be implicitly trusted.
5482 * @returns a `url` which has been branded to be implicitly trusted.
5483 */
5484function bypassSanitizationTrustResourceUrl(trustedResourceUrl) {
5485 return new SafeResourceUrlImpl(trustedResourceUrl);
5486}
5487
5488/**
5489 * @license
5490 * Copyright Google LLC All Rights Reserved.
5491 *
5492 * Use of this source code is governed by an MIT-style license that can be
5493 * found in the LICENSE file at https://angular.io/license
5494 */
5495/**
5496 * This helper is used to get hold of an inert tree of DOM elements containing dirty HTML
5497 * that needs sanitizing.
5498 * Depending upon browser support we use one of two strategies for doing this.
5499 * Default: DOMParser strategy
5500 * Fallback: InertDocument strategy
5501 */
5502function getInertBodyHelper(defaultDoc) {
5503 const inertDocumentHelper = new InertDocumentHelper(defaultDoc);
5504 return isDOMParserAvailable() ? new DOMParserHelper(inertDocumentHelper) : inertDocumentHelper;
5505}
5506/**
5507 * Uses DOMParser to create and fill an inert body element.
5508 * This is the default strategy used in browsers that support it.
5509 */
5510class DOMParserHelper {
5511 constructor(inertDocumentHelper) {
5512 this.inertDocumentHelper = inertDocumentHelper;
5513 }
5514 getInertBodyElement(html) {
5515 // We add these extra elements to ensure that the rest of the content is parsed as expected
5516 // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the
5517 // `<head>` tag. Note that the `<body>` tag is closed implicitly to prevent unclosed tags
5518 // in `html` from consuming the otherwise explicit `</body>` tag.
5519 html = '<body><remove></remove>' + html;
5520 try {
5521 const body = new window.DOMParser()
5522 .parseFromString(trustedHTMLFromString(html), 'text/html')
5523 .body;
5524 if (body === null) {
5525 // In some browsers (e.g. Mozilla/5.0 iPad AppleWebKit Mobile) the `body` property only
5526 // becomes available in the following tick of the JS engine. In that case we fall back to
5527 // the `inertDocumentHelper` instead.
5528 return this.inertDocumentHelper.getInertBodyElement(html);
5529 }
5530 body.removeChild(body.firstChild);
5531 return body;
5532 }
5533 catch {
5534 return null;
5535 }
5536 }
5537}
5538/**
5539 * Use an HTML5 `template` element, if supported, or an inert body element created via
5540 * `createHtmlDocument` to create and fill an inert DOM element.
5541 * This is the fallback strategy if the browser does not support DOMParser.
5542 */
5543class InertDocumentHelper {
5544 constructor(defaultDoc) {
5545 this.defaultDoc = defaultDoc;
5546 this.inertDocument = this.defaultDoc.implementation.createHTMLDocument('sanitization-inert');
5547 if (this.inertDocument.body == null) {
5548 // usually there should be only one body element in the document, but IE doesn't have any, so
5549 // we need to create one.
5550 const inertHtml = this.inertDocument.createElement('html');
5551 this.inertDocument.appendChild(inertHtml);
5552 const inertBodyElement = this.inertDocument.createElement('body');
5553 inertHtml.appendChild(inertBodyElement);
5554 }
5555 }
5556 getInertBodyElement(html) {
5557 // Prefer using <template> element if supported.
5558 const templateEl = this.inertDocument.createElement('template');
5559 if ('content' in templateEl) {
5560 templateEl.innerHTML = trustedHTMLFromString(html);
5561 return templateEl;
5562 }
5563 // Note that previously we used to do something like `this.inertDocument.body.innerHTML = html`
5564 // and we returned the inert `body` node. This was changed, because IE seems to treat setting
5565 // `innerHTML` on an inserted element differently, compared to one that hasn't been inserted
5566 // yet. In particular, IE appears to split some of the text into multiple text nodes rather
5567 // than keeping them in a single one which ends up messing with Ivy's i18n parsing further
5568 // down the line. This has been worked around by creating a new inert `body` and using it as
5569 // the root node in which we insert the HTML.
5570 const inertBody = this.inertDocument.createElement('body');
5571 inertBody.innerHTML = trustedHTMLFromString(html);
5572 // Support: IE 11 only
5573 // strip custom-namespaced attributes on IE<=11
5574 if (this.defaultDoc.documentMode) {
5575 this.stripCustomNsAttrs(inertBody);
5576 }
5577 return inertBody;
5578 }
5579 /**
5580 * When IE11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1'
5581 * attribute to declare ns1 namespace and prefixes the attribute with 'ns1' (e.g.
5582 * 'ns1:xlink:foo').
5583 *
5584 * This is undesirable since we don't want to allow any of these custom attributes. This method
5585 * strips them all.
5586 */
5587 stripCustomNsAttrs(el) {
5588 const elAttrs = el.attributes;
5589 // loop backwards so that we can support removals.
5590 for (let i = elAttrs.length - 1; 0 < i; i--) {
5591 const attrib = elAttrs.item(i);
5592 const attrName = attrib.name;
5593 if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) {
5594 el.removeAttribute(attrName);
5595 }
5596 }
5597 let childNode = el.firstChild;
5598 while (childNode) {
5599 if (childNode.nodeType === Node.ELEMENT_NODE)
5600 this.stripCustomNsAttrs(childNode);
5601 childNode = childNode.nextSibling;
5602 }
5603 }
5604}
5605/**
5606 * We need to determine whether the DOMParser exists in the global context and
5607 * supports parsing HTML; HTML parsing support is not as wide as other formats, see
5608 * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility.
5609 *
5610 * @suppress {uselessCode}
5611 */
5612function isDOMParserAvailable() {
5613 try {
5614 return !!new window.DOMParser().parseFromString(trustedHTMLFromString(''), 'text/html');
5615 }
5616 catch {
5617 return false;
5618 }
5619}
5620
5621/**
5622 * @license
5623 * Copyright Google LLC All Rights Reserved.
5624 *
5625 * Use of this source code is governed by an MIT-style license that can be
5626 * found in the LICENSE file at https://angular.io/license
5627 */
5628/**
5629 * A pattern that recognizes a commonly useful subset of URLs that are safe.
5630 *
5631 * This regular expression matches a subset of URLs that will not cause script
5632 * execution if used in URL context within a HTML document. Specifically, this
5633 * regular expression matches if (comment from here on and regex copied from
5634 * Soy's EscapingConventions):
5635 * (1) Either an allowed protocol (http, https, mailto or ftp).
5636 * (2) or no protocol. A protocol must be followed by a colon. The below
5637 * allows that by allowing colons only after one of the characters [/?#].
5638 * A colon after a hash (#) must be in the fragment.
5639 * Otherwise, a colon after a (?) must be in a query.
5640 * Otherwise, a colon after a single solidus (/) must be in a path.
5641 * Otherwise, a colon after a double solidus (//) must be in the authority
5642 * (before port).
5643 *
5644 * The pattern disallows &, used in HTML entity declarations before
5645 * one of the characters in [/?#]. This disallows HTML entities used in the
5646 * protocol name, which should never happen, e.g. "h&#116;tp" for "http".
5647 * It also disallows HTML entities in the first path part of a relative path,
5648 * e.g. "foo&lt;bar/baz". Our existing escaping functions should not produce
5649 * that. More importantly, it disallows masking of a colon,
5650 * e.g. "javascript&#58;...".
5651 *
5652 * This regular expression was taken from the Closure sanitization library.
5653 */
5654const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi;
5655/* A pattern that matches safe srcset values */
5656const SAFE_SRCSET_PATTERN = /^(?:(?:https?|file):|[^&:/?#]*(?:[/?#]|$))/gi;
5657/** A pattern that matches safe data URLs. Only matches image, video and audio types. */
5658const 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;
5659function _sanitizeUrl(url) {
5660 url = String(url);
5661 if (url.match(SAFE_URL_PATTERN) || url.match(DATA_URL_PATTERN))
5662 return url;
5663 if (typeof ngDevMode === 'undefined' || ngDevMode) {
5664 console.warn(`WARNING: sanitizing unsafe URL value ${url} (see https://g.co/ng/security#xss)`);
5665 }
5666 return 'unsafe:' + url;
5667}
5668function sanitizeSrcset(srcset) {
5669 srcset = String(srcset);
5670 return srcset.split(',').map((srcset) => _sanitizeUrl(srcset.trim())).join(', ');
5671}
5672
5673/**
5674 * @license
5675 * Copyright Google LLC All Rights Reserved.
5676 *
5677 * Use of this source code is governed by an MIT-style license that can be
5678 * found in the LICENSE file at https://angular.io/license
5679 */
5680function tagSet(tags) {
5681 const res = {};
5682 for (const t of tags.split(','))
5683 res[t] = true;
5684 return res;
5685}
5686function merge(...sets) {
5687 const res = {};
5688 for (const s of sets) {
5689 for (const v in s) {
5690 if (s.hasOwnProperty(v))
5691 res[v] = true;
5692 }
5693 }
5694 return res;
5695}
5696// Good source of info about elements and attributes
5697// https://html.spec.whatwg.org/#semantics
5698// https://simon.html5.org/html-elements
5699// Safe Void Elements - HTML5
5700// https://html.spec.whatwg.org/#void-elements
5701const VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr');
5702// Elements that you can, intentionally, leave open (and which close themselves)
5703// https://html.spec.whatwg.org/#optional-tags
5704const OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr');
5705const OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt');
5706const OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS);
5707// Safe Block Elements - HTML5
5708const BLOCK_ELEMENTS = merge(OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet('address,article,' +
5709 'aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
5710 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul'));
5711// Inline Elements - HTML5
5712const INLINE_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet('a,abbr,acronym,audio,b,' +
5713 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' +
5714 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video'));
5715const VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS);
5716// Attributes that have href and hence need to be sanitized
5717const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
5718// Attributes that have special href set hence need to be sanitized
5719const SRCSET_ATTRS = tagSet('srcset');
5720const HTML_ATTRS = tagSet('abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' +
5721 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' +
5722 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' +
5723 'scope,scrolling,shape,size,sizes,span,srclang,start,summary,tabindex,target,title,translate,type,usemap,' +
5724 'valign,value,vspace,width');
5725// Accessibility attributes as per WAI-ARIA 1.1 (W3C Working Draft 14 December 2018)
5726const ARIA_ATTRS = tagSet('aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,' +
5727 'aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,' +
5728 'aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,' +
5729 'aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,' +
5730 'aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,' +
5731 'aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,' +
5732 'aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext');
5733// NB: This currently consciously doesn't support SVG. SVG sanitization has had several security
5734// issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via
5735// innerHTML is required, SVG attributes should be added here.
5736// NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those
5737// can be sanitized, but they increase security surface area without a legitimate use case, so they
5738// are left out here.
5739const VALID_ATTRS = merge(URI_ATTRS, SRCSET_ATTRS, HTML_ATTRS, ARIA_ATTRS);
5740// Elements whose content should not be traversed/preserved, if the elements themselves are invalid.
5741//
5742// Typically, `<invalid>Some content</invalid>` would traverse (and in this case preserve)
5743// `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we
5744// don't want to preserve the content, if the elements themselves are going to be removed.
5745const SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template');
5746/**
5747 * SanitizingHtmlSerializer serializes a DOM fragment, stripping out any unsafe elements and unsafe
5748 * attributes.
5749 */
5750class SanitizingHtmlSerializer {
5751 constructor() {
5752 // Explicitly track if something was stripped, to avoid accidentally warning of sanitization just
5753 // because characters were re-encoded.
5754 this.sanitizedSomething = false;
5755 this.buf = [];
5756 }
5757 sanitizeChildren(el) {
5758 // This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters.
5759 // However this code never accesses properties off of `document` before deleting its contents
5760 // again, so it shouldn't be vulnerable to DOM clobbering.
5761 let current = el.firstChild;
5762 let traverseContent = true;
5763 while (current) {
5764 if (current.nodeType === Node.ELEMENT_NODE) {
5765 traverseContent = this.startElement(current);
5766 }
5767 else if (current.nodeType === Node.TEXT_NODE) {
5768 this.chars(current.nodeValue);
5769 }
5770 else {
5771 // Strip non-element, non-text nodes.
5772 this.sanitizedSomething = true;
5773 }
5774 if (traverseContent && current.firstChild) {
5775 current = current.firstChild;
5776 continue;
5777 }
5778 while (current) {
5779 // Leaving the element. Walk up and to the right, closing tags as we go.
5780 if (current.nodeType === Node.ELEMENT_NODE) {
5781 this.endElement(current);
5782 }
5783 let next = this.checkClobberedElement(current, current.nextSibling);
5784 if (next) {
5785 current = next;
5786 break;
5787 }
5788 current = this.checkClobberedElement(current, current.parentNode);
5789 }
5790 }
5791 return this.buf.join('');
5792 }
5793 /**
5794 * Sanitizes an opening element tag (if valid) and returns whether the element's contents should
5795 * be traversed. Element content must always be traversed (even if the element itself is not
5796 * valid/safe), unless the element is one of `SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS`.
5797 *
5798 * @param element The element to sanitize.
5799 * @return True if the element's contents should be traversed.
5800 */
5801 startElement(element) {
5802 const tagName = element.nodeName.toLowerCase();
5803 if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
5804 this.sanitizedSomething = true;
5805 return !SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS.hasOwnProperty(tagName);
5806 }
5807 this.buf.push('<');
5808 this.buf.push(tagName);
5809 const elAttrs = element.attributes;
5810 for (let i = 0; i < elAttrs.length; i++) {
5811 const elAttr = elAttrs.item(i);
5812 const attrName = elAttr.name;
5813 const lower = attrName.toLowerCase();
5814 if (!VALID_ATTRS.hasOwnProperty(lower)) {
5815 this.sanitizedSomething = true;
5816 continue;
5817 }
5818 let value = elAttr.value;
5819 // TODO(martinprobst): Special case image URIs for data:image/...
5820 if (URI_ATTRS[lower])
5821 value = _sanitizeUrl(value);
5822 if (SRCSET_ATTRS[lower])
5823 value = sanitizeSrcset(value);
5824 this.buf.push(' ', attrName, '="', encodeEntities(value), '"');
5825 }
5826 this.buf.push('>');
5827 return true;
5828 }
5829 endElement(current) {
5830 const tagName = current.nodeName.toLowerCase();
5831 if (VALID_ELEMENTS.hasOwnProperty(tagName) && !VOID_ELEMENTS.hasOwnProperty(tagName)) {
5832 this.buf.push('</');
5833 this.buf.push(tagName);
5834 this.buf.push('>');
5835 }
5836 }
5837 chars(chars) {
5838 this.buf.push(encodeEntities(chars));
5839 }
5840 checkClobberedElement(node, nextNode) {
5841 if (nextNode &&
5842 (node.compareDocumentPosition(nextNode) &
5843 Node.DOCUMENT_POSITION_CONTAINED_BY) === Node.DOCUMENT_POSITION_CONTAINED_BY) {
5844 throw new Error(`Failed to sanitize html because the element is clobbered: ${node.outerHTML}`);
5845 }
5846 return nextNode;
5847 }
5848}
5849// Regular Expressions for parsing tags and attributes
5850const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
5851// ! to ~ is the ASCII range.
5852const NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
5853/**
5854 * Escapes all potentially dangerous characters, so that the
5855 * resulting string can be safely inserted into attribute or
5856 * element text.
5857 * @param value
5858 */
5859function encodeEntities(value) {
5860 return value.replace(/&/g, '&amp;')
5861 .replace(SURROGATE_PAIR_REGEXP, function (match) {
5862 const hi = match.charCodeAt(0);
5863 const low = match.charCodeAt(1);
5864 return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
5865 })
5866 .replace(NON_ALPHANUMERIC_REGEXP, function (match) {
5867 return '&#' + match.charCodeAt(0) + ';';
5868 })
5869 .replace(/</g, '&lt;')
5870 .replace(/>/g, '&gt;');
5871}
5872let inertBodyHelper;
5873/**
5874 * Sanitizes the given unsafe, untrusted HTML fragment, and returns HTML text that is safe to add to
5875 * the DOM in a browser environment.
5876 */
5877function _sanitizeHtml(defaultDoc, unsafeHtmlInput) {
5878 let inertBodyElement = null;
5879 try {
5880 inertBodyHelper = inertBodyHelper || getInertBodyHelper(defaultDoc);
5881 // Make sure unsafeHtml is actually a string (TypeScript types are not enforced at runtime).
5882 let unsafeHtml = unsafeHtmlInput ? String(unsafeHtmlInput) : '';
5883 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
5884 // mXSS protection. Repeatedly parse the document to make sure it stabilizes, so that a browser
5885 // trying to auto-correct incorrect HTML cannot cause formerly inert HTML to become dangerous.
5886 let mXSSAttempts = 5;
5887 let parsedHtml = unsafeHtml;
5888 do {
5889 if (mXSSAttempts === 0) {
5890 throw new Error('Failed to sanitize html because the input is unstable');
5891 }
5892 mXSSAttempts--;
5893 unsafeHtml = parsedHtml;
5894 parsedHtml = inertBodyElement.innerHTML;
5895 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
5896 } while (unsafeHtml !== parsedHtml);
5897 const sanitizer = new SanitizingHtmlSerializer();
5898 const safeHtml = sanitizer.sanitizeChildren(getTemplateContent(inertBodyElement) || inertBodyElement);
5899 if ((typeof ngDevMode === 'undefined' || ngDevMode) && sanitizer.sanitizedSomething) {
5900 console.warn('WARNING: sanitizing HTML stripped some content, see https://g.co/ng/security#xss');
5901 }
5902 return trustedHTMLFromString(safeHtml);
5903 }
5904 finally {
5905 // In case anything goes wrong, clear out inertElement to reset the entire DOM structure.
5906 if (inertBodyElement) {
5907 const parent = getTemplateContent(inertBodyElement) || inertBodyElement;
5908 while (parent.firstChild) {
5909 parent.removeChild(parent.firstChild);
5910 }
5911 }
5912 }
5913}
5914function getTemplateContent(el) {
5915 return 'content' in el /** Microsoft/TypeScript#21517 */ && isTemplateElement(el) ?
5916 el.content :
5917 null;
5918}
5919function isTemplateElement(el) {
5920 return el.nodeType === Node.ELEMENT_NODE && el.nodeName === 'TEMPLATE';
5921}
5922
5923/**
5924 * @license
5925 * Copyright Google LLC All Rights Reserved.
5926 *
5927 * Use of this source code is governed by an MIT-style license that can be
5928 * found in the LICENSE file at https://angular.io/license
5929 */
5930/**
5931 * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
5932 * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
5933 * handled.
5934 *
5935 * See DomSanitizer for more details on security in Angular applications.
5936 *
5937 * @publicApi
5938 */
5939var SecurityContext;
5940(function (SecurityContext) {
5941 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
5942 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
5943 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
5944 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
5945 SecurityContext[SecurityContext["URL"] = 4] = "URL";
5946 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
5947})(SecurityContext || (SecurityContext = {}));
5948
5949/**
5950 * @license
5951 * Copyright Google LLC All Rights Reserved.
5952 *
5953 * Use of this source code is governed by an MIT-style license that can be
5954 * found in the LICENSE file at https://angular.io/license
5955 */
5956/**
5957 * An `html` sanitizer which converts untrusted `html` **string** into trusted string by removing
5958 * dangerous content.
5959 *
5960 * This method parses the `html` and locates potentially dangerous content (such as urls and
5961 * javascript) and removes it.
5962 *
5963 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustHtml}.
5964 *
5965 * @param unsafeHtml untrusted `html`, typically from the user.
5966 * @returns `html` string which is safe to display to user, because all of the dangerous javascript
5967 * and urls have been removed.
5968 *
5969 * @codeGenApi
5970 */
5971function ɵɵsanitizeHtml(unsafeHtml) {
5972 const sanitizer = getSanitizer();
5973 if (sanitizer) {
5974 return trustedHTMLFromStringBypass(sanitizer.sanitize(SecurityContext.HTML, unsafeHtml) || '');
5975 }
5976 if (allowSanitizationBypassAndThrow(unsafeHtml, "HTML" /* Html */)) {
5977 return trustedHTMLFromStringBypass(unwrapSafeValue(unsafeHtml));
5978 }
5979 return _sanitizeHtml(getDocument(), renderStringify(unsafeHtml));
5980}
5981/**
5982 * A `style` sanitizer which converts untrusted `style` **string** into trusted string by removing
5983 * dangerous content.
5984 *
5985 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustStyle}.
5986 *
5987 * @param unsafeStyle untrusted `style`, typically from the user.
5988 * @returns `style` string which is safe to bind to the `style` properties.
5989 *
5990 * @codeGenApi
5991 */
5992function ɵɵsanitizeStyle(unsafeStyle) {
5993 const sanitizer = getSanitizer();
5994 if (sanitizer) {
5995 return sanitizer.sanitize(SecurityContext.STYLE, unsafeStyle) || '';
5996 }
5997 if (allowSanitizationBypassAndThrow(unsafeStyle, "Style" /* Style */)) {
5998 return unwrapSafeValue(unsafeStyle);
5999 }
6000 return renderStringify(unsafeStyle);
6001}
6002/**
6003 * A `url` sanitizer which converts untrusted `url` **string** into trusted string by removing
6004 * dangerous
6005 * content.
6006 *
6007 * This method parses the `url` and locates potentially dangerous content (such as javascript) and
6008 * removes it.
6009 *
6010 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustUrl}.
6011 *
6012 * @param unsafeUrl untrusted `url`, typically from the user.
6013 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
6014 * all of the dangerous javascript has been removed.
6015 *
6016 * @codeGenApi
6017 */
6018function ɵɵsanitizeUrl(unsafeUrl) {
6019 const sanitizer = getSanitizer();
6020 if (sanitizer) {
6021 return sanitizer.sanitize(SecurityContext.URL, unsafeUrl) || '';
6022 }
6023 if (allowSanitizationBypassAndThrow(unsafeUrl, "URL" /* Url */)) {
6024 return unwrapSafeValue(unsafeUrl);
6025 }
6026 return _sanitizeUrl(renderStringify(unsafeUrl));
6027}
6028/**
6029 * A `url` sanitizer which only lets trusted `url`s through.
6030 *
6031 * This passes only `url`s marked trusted by calling {@link bypassSanitizationTrustResourceUrl}.
6032 *
6033 * @param unsafeResourceUrl untrusted `url`, typically from the user.
6034 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
6035 * only trusted `url`s have been allowed to pass.
6036 *
6037 * @codeGenApi
6038 */
6039function ɵɵsanitizeResourceUrl(unsafeResourceUrl) {
6040 const sanitizer = getSanitizer();
6041 if (sanitizer) {
6042 return trustedScriptURLFromStringBypass(sanitizer.sanitize(SecurityContext.RESOURCE_URL, unsafeResourceUrl) || '');
6043 }
6044 if (allowSanitizationBypassAndThrow(unsafeResourceUrl, "ResourceURL" /* ResourceUrl */)) {
6045 return trustedScriptURLFromStringBypass(unwrapSafeValue(unsafeResourceUrl));
6046 }
6047 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
6048 'unsafe value used in a resource URL context (see https://g.co/ng/security#xss)' :
6049 '';
6050 throw new RuntimeError(904 /* UNSAFE_VALUE_IN_RESOURCE_URL */, errorMessage);
6051}
6052/**
6053 * A `script` sanitizer which only lets trusted javascript through.
6054 *
6055 * This passes only `script`s marked trusted by calling {@link
6056 * bypassSanitizationTrustScript}.
6057 *
6058 * @param unsafeScript untrusted `script`, typically from the user.
6059 * @returns `url` string which is safe to bind to the `<script>` element such as `<img src>`,
6060 * because only trusted `scripts` have been allowed to pass.
6061 *
6062 * @codeGenApi
6063 */
6064function ɵɵsanitizeScript(unsafeScript) {
6065 const sanitizer = getSanitizer();
6066 if (sanitizer) {
6067 return trustedScriptFromStringBypass(sanitizer.sanitize(SecurityContext.SCRIPT, unsafeScript) || '');
6068 }
6069 if (allowSanitizationBypassAndThrow(unsafeScript, "Script" /* Script */)) {
6070 return trustedScriptFromStringBypass(unwrapSafeValue(unsafeScript));
6071 }
6072 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
6073 'unsafe value used in a script context' :
6074 '';
6075 throw new RuntimeError(905 /* UNSAFE_VALUE_IN_SCRIPT */, errorMessage);
6076}
6077/**
6078 * A template tag function for promoting the associated constant literal to a
6079 * TrustedHTML. Interpolation is explicitly not allowed.
6080 *
6081 * @param html constant template literal containing trusted HTML.
6082 * @returns TrustedHTML wrapping `html`.
6083 *
6084 * @security This is a security-sensitive function and should only be used to
6085 * convert constant values of attributes and properties found in
6086 * application-provided Angular templates to TrustedHTML.
6087 *
6088 * @codeGenApi
6089 */
6090function ɵɵtrustConstantHtml(html) {
6091 // The following runtime check ensures that the function was called as a
6092 // template tag (e.g. ɵɵtrustConstantHtml`content`), without any interpolation
6093 // (e.g. not ɵɵtrustConstantHtml`content ${variable}`). A TemplateStringsArray
6094 // is an array with a `raw` property that is also an array. The associated
6095 // template literal has no interpolation if and only if the length of the
6096 // TemplateStringsArray is 1.
6097 if (ngDevMode && (!Array.isArray(html) || !Array.isArray(html.raw) || html.length !== 1)) {
6098 throw new Error(`Unexpected interpolation in trusted HTML constant: ${html.join('?')}`);
6099 }
6100 return trustedHTMLFromString(html[0]);
6101}
6102/**
6103 * A template tag function for promoting the associated constant literal to a
6104 * TrustedScriptURL. Interpolation is explicitly not allowed.
6105 *
6106 * @param url constant template literal containing a trusted script URL.
6107 * @returns TrustedScriptURL wrapping `url`.
6108 *
6109 * @security This is a security-sensitive function and should only be used to
6110 * convert constant values of attributes and properties found in
6111 * application-provided Angular templates to TrustedScriptURL.
6112 *
6113 * @codeGenApi
6114 */
6115function ɵɵtrustConstantResourceUrl(url) {
6116 // The following runtime check ensures that the function was called as a
6117 // template tag (e.g. ɵɵtrustConstantResourceUrl`content`), without any
6118 // interpolation (e.g. not ɵɵtrustConstantResourceUrl`content ${variable}`). A
6119 // TemplateStringsArray is an array with a `raw` property that is also an
6120 // array. The associated template literal has no interpolation if and only if
6121 // the length of the TemplateStringsArray is 1.
6122 if (ngDevMode && (!Array.isArray(url) || !Array.isArray(url.raw) || url.length !== 1)) {
6123 throw new Error(`Unexpected interpolation in trusted URL constant: ${url.join('?')}`);
6124 }
6125 return trustedScriptURLFromString(url[0]);
6126}
6127/**
6128 * Detects which sanitizer to use for URL property, based on tag name and prop name.
6129 *
6130 * The rules are based on the RESOURCE_URL context config from
6131 * `packages/compiler/src/schema/dom_security_schema.ts`.
6132 * If tag and prop names don't match Resource URL schema, use URL sanitizer.
6133 */
6134function getUrlSanitizer(tag, prop) {
6135 if ((prop === 'src' &&
6136 (tag === 'embed' || tag === 'frame' || tag === 'iframe' || tag === 'media' ||
6137 tag === 'script')) ||
6138 (prop === 'href' && (tag === 'base' || tag === 'link'))) {
6139 return ɵɵsanitizeResourceUrl;
6140 }
6141 return ɵɵsanitizeUrl;
6142}
6143/**
6144 * Sanitizes URL, selecting sanitizer function based on tag and property names.
6145 *
6146 * This function is used in case we can't define security context at compile time, when only prop
6147 * name is available. This happens when we generate host bindings for Directives/Components. The
6148 * host element is unknown at compile time, so we defer calculation of specific sanitizer to
6149 * runtime.
6150 *
6151 * @param unsafeUrl untrusted `url`, typically from the user.
6152 * @param tag target element tag name.
6153 * @param prop name of the property that contains the value.
6154 * @returns `url` string which is safe to bind.
6155 *
6156 * @codeGenApi
6157 */
6158function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl, tag, prop) {
6159 return getUrlSanitizer(tag, prop)(unsafeUrl);
6160}
6161function validateAgainstEventProperties(name) {
6162 if (name.toLowerCase().startsWith('on')) {
6163 const errorMessage = `Binding to event property '${name}' is disallowed for security reasons, ` +
6164 `please use (${name.slice(2)})=...` +
6165 `\nIf '${name}' is a directive input, make sure the directive is imported by the` +
6166 ` current module.`;
6167 throw new RuntimeError(306 /* INVALID_EVENT_BINDING */, errorMessage);
6168 }
6169}
6170function validateAgainstEventAttributes(name) {
6171 if (name.toLowerCase().startsWith('on')) {
6172 const errorMessage = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
6173 `please use (${name.slice(2)})=...`;
6174 throw new RuntimeError(306 /* INVALID_EVENT_BINDING */, errorMessage);
6175 }
6176}
6177function getSanitizer() {
6178 const lView = getLView();
6179 return lView && lView[SANITIZER];
6180}
6181
6182/**
6183 * @license
6184 * Copyright Google LLC All Rights Reserved.
6185 *
6186 * Use of this source code is governed by an MIT-style license that can be
6187 * found in the LICENSE file at https://angular.io/license
6188 */
6189/**
6190 * Returns the matching `LContext` data for a given DOM node, directive or component instance.
6191 *
6192 * This function will examine the provided DOM element, component, or directive instance\'s
6193 * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched
6194 * value will be that of the newly created `LContext`.
6195 *
6196 * If the monkey-patched value is the `LView` instance then the context value for that
6197 * target will be created and the monkey-patch reference will be updated. Therefore when this
6198 * function is called it may mutate the provided element\'s, component\'s or any of the associated
6199 * directive\'s monkey-patch values.
6200 *
6201 * If the monkey-patch value is not detected then the code will walk up the DOM until an element
6202 * is found which contains a monkey-patch reference. When that occurs then the provided element
6203 * will be updated with a new context (which is then returned). If the monkey-patch value is not
6204 * detected for a component/directive instance then it will throw an error (all components and
6205 * directives should be automatically monkey-patched by ivy).
6206 *
6207 * @param target Component, Directive or DOM Node.
6208 */
6209function getLContext(target) {
6210 let mpValue = readPatchedData(target);
6211 if (mpValue) {
6212 // only when it's an array is it considered an LView instance
6213 // ... otherwise it's an already constructed LContext instance
6214 if (Array.isArray(mpValue)) {
6215 const lView = mpValue;
6216 let nodeIndex;
6217 let component = undefined;
6218 let directives = undefined;
6219 if (isComponentInstance(target)) {
6220 nodeIndex = findViaComponent(lView, target);
6221 if (nodeIndex == -1) {
6222 throw new Error('The provided component was not found in the application');
6223 }
6224 component = target;
6225 }
6226 else if (isDirectiveInstance(target)) {
6227 nodeIndex = findViaDirective(lView, target);
6228 if (nodeIndex == -1) {
6229 throw new Error('The provided directive was not found in the application');
6230 }
6231 directives = getDirectivesAtNodeIndex(nodeIndex, lView, false);
6232 }
6233 else {
6234 nodeIndex = findViaNativeElement(lView, target);
6235 if (nodeIndex == -1) {
6236 return null;
6237 }
6238 }
6239 // the goal is not to fill the entire context full of data because the lookups
6240 // are expensive. Instead, only the target data (the element, component, container, ICU
6241 // expression or directive details) are filled into the context. If called multiple times
6242 // with different target values then the missing target data will be filled in.
6243 const native = unwrapRNode(lView[nodeIndex]);
6244 const existingCtx = readPatchedData(native);
6245 const context = (existingCtx && !Array.isArray(existingCtx)) ?
6246 existingCtx :
6247 createLContext(lView, nodeIndex, native);
6248 // only when the component has been discovered then update the monkey-patch
6249 if (component && context.component === undefined) {
6250 context.component = component;
6251 attachPatchData(context.component, context);
6252 }
6253 // only when the directives have been discovered then update the monkey-patch
6254 if (directives && context.directives === undefined) {
6255 context.directives = directives;
6256 for (let i = 0; i < directives.length; i++) {
6257 attachPatchData(directives[i], context);
6258 }
6259 }
6260 attachPatchData(context.native, context);
6261 mpValue = context;
6262 }
6263 }
6264 else {
6265 const rElement = target;
6266 ngDevMode && assertDomNode(rElement);
6267 // if the context is not found then we need to traverse upwards up the DOM
6268 // to find the nearest element that has already been monkey patched with data
6269 let parent = rElement;
6270 while (parent = parent.parentNode) {
6271 const parentContext = readPatchedData(parent);
6272 if (parentContext) {
6273 let lView;
6274 if (Array.isArray(parentContext)) {
6275 lView = parentContext;
6276 }
6277 else {
6278 lView = parentContext.lView;
6279 }
6280 // the edge of the app was also reached here through another means
6281 // (maybe because the DOM was changed manually).
6282 if (!lView) {
6283 return null;
6284 }
6285 const index = findViaNativeElement(lView, rElement);
6286 if (index >= 0) {
6287 const native = unwrapRNode(lView[index]);
6288 const context = createLContext(lView, index, native);
6289 attachPatchData(native, context);
6290 mpValue = context;
6291 break;
6292 }
6293 }
6294 }
6295 }
6296 return mpValue || null;
6297}
6298/**
6299 * Creates an empty instance of a `LContext` context
6300 */
6301function createLContext(lView, nodeIndex, native) {
6302 return {
6303 lView,
6304 nodeIndex,
6305 native,
6306 component: undefined,
6307 directives: undefined,
6308 localRefs: undefined,
6309 };
6310}
6311/**
6312 * Takes a component instance and returns the view for that component.
6313 *
6314 * @param componentInstance
6315 * @returns The component's view
6316 */
6317function getComponentViewByInstance(componentInstance) {
6318 let lView = readPatchedData(componentInstance);
6319 let view;
6320 if (Array.isArray(lView)) {
6321 const nodeIndex = findViaComponent(lView, componentInstance);
6322 view = getComponentLViewByIndex(nodeIndex, lView);
6323 const context = createLContext(lView, nodeIndex, view[HOST]);
6324 context.component = componentInstance;
6325 attachPatchData(componentInstance, context);
6326 attachPatchData(context.native, context);
6327 }
6328 else {
6329 const context = lView;
6330 view = getComponentLViewByIndex(context.nodeIndex, context.lView);
6331 }
6332 return view;
6333}
6334/**
6335 * This property will be monkey-patched on elements, components and directives.
6336 */
6337const MONKEY_PATCH_KEY_NAME = '__ngContext__';
6338/**
6339 * Assigns the given data to the given target (which could be a component,
6340 * directive or DOM node instance) using monkey-patching.
6341 */
6342function attachPatchData(target, data) {
6343 ngDevMode && assertDefined(target, 'Target expected');
6344 target[MONKEY_PATCH_KEY_NAME] = data;
6345}
6346/**
6347 * Returns the monkey-patch value data present on the target (which could be
6348 * a component, directive or a DOM node).
6349 */
6350function readPatchedData(target) {
6351 ngDevMode && assertDefined(target, 'Target expected');
6352 return target[MONKEY_PATCH_KEY_NAME] || null;
6353}
6354function readPatchedLView(target) {
6355 const value = readPatchedData(target);
6356 if (value) {
6357 return Array.isArray(value) ? value : value.lView;
6358 }
6359 return null;
6360}
6361function isComponentInstance(instance) {
6362 return instance && instance.constructor && instance.constructor.ɵcmp;
6363}
6364function isDirectiveInstance(instance) {
6365 return instance && instance.constructor && instance.constructor.ɵdir;
6366}
6367/**
6368 * Locates the element within the given LView and returns the matching index
6369 */
6370function findViaNativeElement(lView, target) {
6371 const tView = lView[TVIEW];
6372 for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
6373 if (unwrapRNode(lView[i]) === target) {
6374 return i;
6375 }
6376 }
6377 return -1;
6378}
6379/**
6380 * Locates the next tNode (child, sibling or parent).
6381 */
6382function traverseNextElement(tNode) {
6383 if (tNode.child) {
6384 return tNode.child;
6385 }
6386 else if (tNode.next) {
6387 return tNode.next;
6388 }
6389 else {
6390 // Let's take the following template: <div><span>text</span></div><component/>
6391 // After checking the text node, we need to find the next parent that has a "next" TNode,
6392 // in this case the parent `div`, so that we can find the component.
6393 while (tNode.parent && !tNode.parent.next) {
6394 tNode = tNode.parent;
6395 }
6396 return tNode.parent && tNode.parent.next;
6397 }
6398}
6399/**
6400 * Locates the component within the given LView and returns the matching index
6401 */
6402function findViaComponent(lView, componentInstance) {
6403 const componentIndices = lView[TVIEW].components;
6404 if (componentIndices) {
6405 for (let i = 0; i < componentIndices.length; i++) {
6406 const elementComponentIndex = componentIndices[i];
6407 const componentView = getComponentLViewByIndex(elementComponentIndex, lView);
6408 if (componentView[CONTEXT] === componentInstance) {
6409 return elementComponentIndex;
6410 }
6411 }
6412 }
6413 else {
6414 const rootComponentView = getComponentLViewByIndex(HEADER_OFFSET, lView);
6415 const rootComponent = rootComponentView[CONTEXT];
6416 if (rootComponent === componentInstance) {
6417 // we are dealing with the root element here therefore we know that the
6418 // element is the very first element after the HEADER data in the lView
6419 return HEADER_OFFSET;
6420 }
6421 }
6422 return -1;
6423}
6424/**
6425 * Locates the directive within the given LView and returns the matching index
6426 */
6427function findViaDirective(lView, directiveInstance) {
6428 // if a directive is monkey patched then it will (by default)
6429 // have a reference to the LView of the current view. The
6430 // element bound to the directive being search lives somewhere
6431 // in the view data. We loop through the nodes and check their
6432 // list of directives for the instance.
6433 let tNode = lView[TVIEW].firstChild;
6434 while (tNode) {
6435 const directiveIndexStart = tNode.directiveStart;
6436 const directiveIndexEnd = tNode.directiveEnd;
6437 for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
6438 if (lView[i] === directiveInstance) {
6439 return tNode.index;
6440 }
6441 }
6442 tNode = traverseNextElement(tNode);
6443 }
6444 return -1;
6445}
6446/**
6447 * Returns a list of directives extracted from the given view based on the
6448 * provided list of directive index values.
6449 *
6450 * @param nodeIndex The node index
6451 * @param lView The target view data
6452 * @param includeComponents Whether or not to include components in returned directives
6453 */
6454function getDirectivesAtNodeIndex(nodeIndex, lView, includeComponents) {
6455 const tNode = lView[TVIEW].data[nodeIndex];
6456 let directiveStartIndex = tNode.directiveStart;
6457 if (directiveStartIndex == 0)
6458 return EMPTY_ARRAY;
6459 const directiveEndIndex = tNode.directiveEnd;
6460 if (!includeComponents && tNode.flags & 2 /* isComponentHost */)
6461 directiveStartIndex++;
6462 return lView.slice(directiveStartIndex, directiveEndIndex);
6463}
6464function getComponentAtNodeIndex(nodeIndex, lView) {
6465 const tNode = lView[TVIEW].data[nodeIndex];
6466 let directiveStartIndex = tNode.directiveStart;
6467 return tNode.flags & 2 /* isComponentHost */ ? lView[directiveStartIndex] : null;
6468}
6469/**
6470 * Returns a map of local references (local reference name => element or directive instance) that
6471 * exist on a given element.
6472 */
6473function discoverLocalRefs(lView, nodeIndex) {
6474 const tNode = lView[TVIEW].data[nodeIndex];
6475 if (tNode && tNode.localNames) {
6476 const result = {};
6477 let localIndex = tNode.index + 1;
6478 for (let i = 0; i < tNode.localNames.length; i += 2) {
6479 result[tNode.localNames[i]] = lView[localIndex];
6480 localIndex++;
6481 }
6482 return result;
6483 }
6484 return null;
6485}
6486
6487/**
6488 * @license
6489 * Copyright Google LLC All Rights Reserved.
6490 *
6491 * Use of this source code is governed by an MIT-style license that can be
6492 * found in the LICENSE file at https://angular.io/license
6493 */
6494const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
6495const ERROR_LOGGER = 'ngErrorLogger';
6496function wrappedError(message, originalError) {
6497 const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
6498 const error = Error(msg);
6499 error[ERROR_ORIGINAL_ERROR] = originalError;
6500 return error;
6501}
6502function getOriginalError(error) {
6503 return error[ERROR_ORIGINAL_ERROR];
6504}
6505function getErrorLogger(error) {
6506 return error && error[ERROR_LOGGER] || defaultErrorLogger;
6507}
6508function defaultErrorLogger(console, ...values) {
6509 console.error(...values);
6510}
6511
6512/**
6513 * @license
6514 * Copyright Google LLC All Rights Reserved.
6515 *
6516 * Use of this source code is governed by an MIT-style license that can be
6517 * found in the LICENSE file at https://angular.io/license
6518 */
6519/**
6520 * Provides a hook for centralized exception handling.
6521 *
6522 * The default implementation of `ErrorHandler` prints error messages to the `console`. To
6523 * intercept error handling, write a custom exception handler that replaces this default as
6524 * appropriate for your app.
6525 *
6526 * @usageNotes
6527 * ### Example
6528 *
6529 * ```
6530 * class MyErrorHandler implements ErrorHandler {
6531 * handleError(error) {
6532 * // do something with the exception
6533 * }
6534 * }
6535 *
6536 * @NgModule({
6537 * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
6538 * })
6539 * class MyModule {}
6540 * ```
6541 *
6542 * @publicApi
6543 */
6544class ErrorHandler {
6545 constructor() {
6546 /**
6547 * @internal
6548 */
6549 this._console = console;
6550 }
6551 handleError(error) {
6552 const originalError = this._findOriginalError(error);
6553 // Note: Browser consoles show the place from where console.error was called.
6554 // We can use this to give users additional information about the error.
6555 const errorLogger = getErrorLogger(error);
6556 errorLogger(this._console, `ERROR`, error);
6557 if (originalError) {
6558 errorLogger(this._console, `ORIGINAL ERROR`, originalError);
6559 }
6560 }
6561 /** @internal */
6562 _findOriginalError(error) {
6563 let e = error && getOriginalError(error);
6564 while (e && getOriginalError(e)) {
6565 e = getOriginalError(e);
6566 }
6567 return e || null;
6568 }
6569}
6570
6571/**
6572 * @license
6573 * Copyright Google LLC All Rights Reserved.
6574 *
6575 * Use of this source code is governed by an MIT-style license that can be
6576 * found in the LICENSE file at https://angular.io/license
6577 */
6578/**
6579 * Defines a schema that allows an NgModule to contain the following:
6580 * - Non-Angular elements named with dash case (`-`).
6581 * - Element properties named with dash case (`-`).
6582 * Dash case is the naming convention for custom elements.
6583 *
6584 * @publicApi
6585 */
6586const CUSTOM_ELEMENTS_SCHEMA = {
6587 name: 'custom-elements'
6588};
6589/**
6590 * Defines a schema that allows any property on any element.
6591 *
6592 * This schema allows you to ignore the errors related to any unknown elements or properties in a
6593 * template. The usage of this schema is generally discouraged because it prevents useful validation
6594 * and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
6595 *
6596 * @publicApi
6597 */
6598const NO_ERRORS_SCHEMA = {
6599 name: 'no-errors-schema'
6600};
6601
6602/**
6603 * @license
6604 * Copyright Google LLC All Rights Reserved.
6605 *
6606 * Use of this source code is governed by an MIT-style license that can be
6607 * found in the LICENSE file at https://angular.io/license
6608 */
6609/**
6610 * Disallowed strings in the comment.
6611 *
6612 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
6613 */
6614const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
6615/**
6616 * Delimiter in the disallowed strings which needs to be wrapped with zero with character.
6617 */
6618const COMMENT_DELIMITER = /(<|>)/;
6619const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
6620/**
6621 * Escape the content of comment strings so that it can be safely inserted into a comment node.
6622 *
6623 * The issue is that HTML does not specify any way to escape comment end text inside the comment.
6624 * Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
6625 * "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
6626 * can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
6627 *
6628 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
6629 *
6630 * ```
6631 * div.innerHTML = div.innerHTML
6632 * ```
6633 *
6634 * One would expect that the above code would be safe to do, but it turns out that because comment
6635 * text is not escaped, the comment may contain text which will prematurely close the comment
6636 * opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
6637 * may contain such text and expect them to be safe.)
6638 *
6639 * This function escapes the comment text by looking for comment delimiters (`<` and `>`) and
6640 * surrounding them with `_>_` where the `_` is a zero width space `\u200B`. The result is that if a
6641 * comment contains any of the comment start/end delimiters (such as `<!--`, `-->` or `--!>`) the
6642 * text it will render normally but it will not cause the HTML parser to close/open the comment.
6643 *
6644 * @param value text to make safe for comment node by escaping the comment open/close character
6645 * sequence.
6646 */
6647function escapeCommentText(value) {
6648 return value.replace(COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED));
6649}
6650
6651/**
6652 * @license
6653 * Copyright Google LLC All Rights Reserved.
6654 *
6655 * Use of this source code is governed by an MIT-style license that can be
6656 * found in the LICENSE file at https://angular.io/license
6657 */
6658function normalizeDebugBindingName(name) {
6659 // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
6660 name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
6661 return `ng-reflect-${name}`;
6662}
6663const CAMEL_CASE_REGEXP = /([A-Z])/g;
6664function camelCaseToDashCase(input) {
6665 return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
6666}
6667function normalizeDebugBindingValue(value) {
6668 try {
6669 // Limit the size of the value as otherwise the DOM just gets polluted.
6670 return value != null ? value.toString().slice(0, 30) : value;
6671 }
6672 catch (e) {
6673 return '[ERROR] Exception while trying to serialize the value';
6674 }
6675}
6676
6677/**
6678 * @license
6679 * Copyright Google LLC All Rights Reserved.
6680 *
6681 * Use of this source code is governed by an MIT-style license that can be
6682 * found in the LICENSE file at https://angular.io/license
6683 */
6684const defaultScheduler = (() => (typeof requestAnimationFrame !== 'undefined' &&
6685 requestAnimationFrame || // browser only
6686 setTimeout // everything else
6687)
6688 .bind(_global))();
6689/**
6690 *
6691 * @codeGenApi
6692 */
6693function ɵɵresolveWindow(element) {
6694 return element.ownerDocument.defaultView;
6695}
6696/**
6697 *
6698 * @codeGenApi
6699 */
6700function ɵɵresolveDocument(element) {
6701 return element.ownerDocument;
6702}
6703/**
6704 *
6705 * @codeGenApi
6706 */
6707function ɵɵresolveBody(element) {
6708 return element.ownerDocument.body;
6709}
6710/**
6711 * The special delimiter we use to separate property names, prefixes, and suffixes
6712 * in property binding metadata. See storeBindingMetadata().
6713 *
6714 * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter
6715 * because it is a very uncommon character that is unlikely to be part of a user's
6716 * property names or interpolation strings. If it is in fact used in a property
6717 * binding, DebugElement.properties will not return the correct value for that
6718 * binding. However, there should be no runtime effect for real applications.
6719 *
6720 * This character is typically rendered as a question mark inside of a diamond.
6721 * See https://en.wikipedia.org/wiki/Specials_(Unicode_block)
6722 *
6723 */
6724const INTERPOLATION_DELIMITER = `�`;
6725/**
6726 * Unwrap a value which might be behind a closure (for forward declaration reasons).
6727 */
6728function maybeUnwrapFn(value) {
6729 if (value instanceof Function) {
6730 return value();
6731 }
6732 else {
6733 return value;
6734 }
6735}
6736
6737/**
6738 * @license
6739 * Copyright Google LLC All Rights Reserved.
6740 *
6741 * Use of this source code is governed by an MIT-style license that can be
6742 * found in the LICENSE file at https://angular.io/license
6743 */
6744/** Called when there are multiple component selectors that match a given node */
6745function throwMultipleComponentError(tNode, first, second) {
6746 throw new RuntimeError(-300 /* MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
6747 `${stringifyForError(first)} and ` +
6748 `${stringifyForError(second)}`);
6749}
6750/** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
6751function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
6752 const field = propName ? ` for '${propName}'` : '';
6753 let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
6754 if (creationMode) {
6755 msg +=
6756 ` It seems like the view has been created after its parent and its children have been dirty checked.` +
6757 ` Has it been created in a change detection hook?`;
6758 }
6759 throw new RuntimeError(-100 /* EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
6760}
6761function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
6762 const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
6763 let oldValue = prefix, newValue = prefix;
6764 for (let i = 0; i < chunks.length; i++) {
6765 const slotIdx = rootIndex + i;
6766 oldValue += `${lView[slotIdx]}${chunks[i]}`;
6767 newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
6768 }
6769 return { propName, oldValue, newValue };
6770}
6771/**
6772 * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
6773 * - property name (for property bindings or interpolations)
6774 * - old and new values, enriched using information from metadata
6775 *
6776 * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
6777 * function description.
6778 */
6779function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
6780 const tData = lView[TVIEW].data;
6781 const metadata = tData[bindingIndex];
6782 if (typeof metadata === 'string') {
6783 // metadata for property interpolation
6784 if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
6785 return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
6786 }
6787 // metadata for property binding
6788 return { propName: metadata, oldValue, newValue };
6789 }
6790 // metadata is not available for this expression, check if this expression is a part of the
6791 // property interpolation by going from the current binding index left and look for a string that
6792 // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
6793 // [..., 'id�Prefix � and � suffix', null, null, null, ...]
6794 if (metadata === null) {
6795 let idx = bindingIndex - 1;
6796 while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
6797 idx--;
6798 }
6799 const meta = tData[idx];
6800 if (typeof meta === 'string') {
6801 const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
6802 // first interpolation delimiter separates property name from interpolation parts (in case of
6803 // property interpolations), so we subtract one from total number of found delimiters
6804 if (matches && (matches.length - 1) > bindingIndex - idx) {
6805 return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
6806 }
6807 }
6808 }
6809 return { propName: undefined, oldValue, newValue };
6810}
6811
6812/**
6813 * @license
6814 * Copyright Google LLC All Rights Reserved.
6815 *
6816 * Use of this source code is governed by an MIT-style license that can be
6817 * found in the LICENSE file at https://angular.io/license
6818 */
6819/**
6820 * Flags for renderer-specific style modifiers.
6821 * @publicApi
6822 */
6823var RendererStyleFlags2;
6824(function (RendererStyleFlags2) {
6825 // TODO(misko): This needs to be refactored into a separate file so that it can be imported from
6826 // `node_manipulation.ts` Currently doing the import cause resolution order to change and fails
6827 // the tests. The work around is to have hard coded value in `node_manipulation.ts` for now.
6828 /**
6829 * Marks a style as important.
6830 */
6831 RendererStyleFlags2[RendererStyleFlags2["Important"] = 1] = "Important";
6832 /**
6833 * Marks a style as using dash case naming (this-is-dash-case).
6834 */
6835 RendererStyleFlags2[RendererStyleFlags2["DashCase"] = 2] = "DashCase";
6836})(RendererStyleFlags2 || (RendererStyleFlags2 = {}));
6837
6838/**
6839 * @license
6840 * Copyright Google LLC All Rights Reserved.
6841 *
6842 * Use of this source code is governed by an MIT-style license that can be
6843 * found in the LICENSE file at https://angular.io/license
6844 */
6845let _icuContainerIterate;
6846/**
6847 * Iterator which provides ability to visit all of the `TIcuContainerNode` root `RNode`s.
6848 */
6849function icuContainerIterate(tIcuContainerNode, lView) {
6850 return _icuContainerIterate(tIcuContainerNode, lView);
6851}
6852/**
6853 * Ensures that `IcuContainerVisitor`'s implementation is present.
6854 *
6855 * This function is invoked when i18n instruction comes across an ICU. The purpose is to allow the
6856 * bundler to tree shake ICU logic and only load it if ICU instruction is executed.
6857 */
6858function ensureIcuContainerVisitorLoaded(loader) {
6859 if (_icuContainerIterate === undefined) {
6860 // Do not inline this function. We want to keep `ensureIcuContainerVisitorLoaded` light, so it
6861 // can be inlined into call-site.
6862 _icuContainerIterate = loader();
6863 }
6864}
6865
6866/**
6867 * @license
6868 * Copyright Google LLC All Rights Reserved.
6869 *
6870 * Use of this source code is governed by an MIT-style license that can be
6871 * found in the LICENSE file at https://angular.io/license
6872 */
6873// Note: This hack is necessary so we don't erroneously get a circular dependency
6874// failure based on types.
6875const unusedValueExportToPlacateAjd$3 = 1;
6876
6877/**
6878 * @license
6879 * Copyright Google LLC All Rights Reserved.
6880 *
6881 * Use of this source code is governed by an MIT-style license that can be
6882 * found in the LICENSE file at https://angular.io/license
6883 */
6884/**
6885 * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of
6886 * that LContainer, which is an LView
6887 * @param lView the lView whose parent to get
6888 */
6889function getLViewParent(lView) {
6890 ngDevMode && assertLView(lView);
6891 const parent = lView[PARENT];
6892 return isLContainer(parent) ? parent[PARENT] : parent;
6893}
6894/**
6895 * Retrieve the root view from any component or `LView` by walking the parent `LView` until
6896 * reaching the root `LView`.
6897 *
6898 * @param componentOrLView any component or `LView`
6899 */
6900function getRootView(componentOrLView) {
6901 ngDevMode && assertDefined(componentOrLView, 'component');
6902 let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView);
6903 while (lView && !(lView[FLAGS] & 512 /* IsRoot */)) {
6904 lView = getLViewParent(lView);
6905 }
6906 ngDevMode && assertLView(lView);
6907 return lView;
6908}
6909/**
6910 * Returns the `RootContext` instance that is associated with
6911 * the application where the target is situated. It does this by walking the parent views until it
6912 * gets to the root view, then getting the context off of that.
6913 *
6914 * @param viewOrComponent the `LView` or component to get the root context for.
6915 */
6916function getRootContext(viewOrComponent) {
6917 const rootView = getRootView(viewOrComponent);
6918 ngDevMode &&
6919 assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?');
6920 return rootView[CONTEXT];
6921}
6922/**
6923 * Gets the first `LContainer` in the LView or `null` if none exists.
6924 */
6925function getFirstLContainer(lView) {
6926 return getNearestLContainer(lView[CHILD_HEAD]);
6927}
6928/**
6929 * Gets the next `LContainer` that is a sibling of the given container.
6930 */
6931function getNextLContainer(container) {
6932 return getNearestLContainer(container[NEXT]);
6933}
6934function getNearestLContainer(viewOrContainer) {
6935 while (viewOrContainer !== null && !isLContainer(viewOrContainer)) {
6936 viewOrContainer = viewOrContainer[NEXT];
6937 }
6938 return viewOrContainer;
6939}
6940
6941/**
6942 * @license
6943 * Copyright Google LLC All Rights Reserved.
6944 *
6945 * Use of this source code is governed by an MIT-style license that can be
6946 * found in the LICENSE file at https://angular.io/license
6947 */
6948const unusedValueToPlacateAjd$2 = unusedValueExportToPlacateAjd$7 + unusedValueExportToPlacateAjd$4 + unusedValueExportToPlacateAjd$3 + unusedValueExportToPlacateAjd$6 + unusedValueExportToPlacateAjd$8;
6949/**
6950 * NOTE: for performance reasons, the possible actions are inlined within the function instead of
6951 * being passed as an argument.
6952 */
6953function applyToElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
6954 // If this slot was allocated for a text node dynamically created by i18n, the text node itself
6955 // won't be created until i18nApply() in the update block, so this node should be skipped.
6956 // For more info, see "ICU expressions should work inside an ngTemplateOutlet inside an ngFor"
6957 // in `i18n_spec.ts`.
6958 if (lNodeToHandle != null) {
6959 let lContainer;
6960 let isComponent = false;
6961 // We are expecting an RNode, but in the case of a component or LContainer the `RNode` is
6962 // wrapped in an array which needs to be unwrapped. We need to know if it is a component and if
6963 // it has LContainer so that we can process all of those cases appropriately.
6964 if (isLContainer(lNodeToHandle)) {
6965 lContainer = lNodeToHandle;
6966 }
6967 else if (isLView(lNodeToHandle)) {
6968 isComponent = true;
6969 ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView');
6970 lNodeToHandle = lNodeToHandle[HOST];
6971 }
6972 const rNode = unwrapRNode(lNodeToHandle);
6973 ngDevMode && !isProceduralRenderer(renderer) && assertDomNode(rNode);
6974 if (action === 0 /* Create */ && parent !== null) {
6975 if (beforeNode == null) {
6976 nativeAppendChild(renderer, parent, rNode);
6977 }
6978 else {
6979 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
6980 }
6981 }
6982 else if (action === 1 /* Insert */ && parent !== null) {
6983 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
6984 }
6985 else if (action === 2 /* Detach */) {
6986 nativeRemoveNode(renderer, rNode, isComponent);
6987 }
6988 else if (action === 3 /* Destroy */) {
6989 ngDevMode && ngDevMode.rendererDestroyNode++;
6990 renderer.destroyNode(rNode);
6991 }
6992 if (lContainer != null) {
6993 applyContainer(renderer, action, lContainer, parent, beforeNode);
6994 }
6995 }
6996}
6997function createTextNode(renderer, value) {
6998 ngDevMode && ngDevMode.rendererCreateTextNode++;
6999 ngDevMode && ngDevMode.rendererSetText++;
7000 return isProceduralRenderer(renderer) ? renderer.createText(value) :
7001 renderer.createTextNode(value);
7002}
7003function updateTextNode(renderer, rNode, value) {
7004 ngDevMode && ngDevMode.rendererSetText++;
7005 isProceduralRenderer(renderer) ? renderer.setValue(rNode, value) : rNode.textContent = value;
7006}
7007function createCommentNode(renderer, value) {
7008 ngDevMode && ngDevMode.rendererCreateComment++;
7009 // isProceduralRenderer check is not needed because both `Renderer2` and `Renderer3` have the same
7010 // method name.
7011 return renderer.createComment(escapeCommentText(value));
7012}
7013/**
7014 * Creates a native element from a tag name, using a renderer.
7015 * @param renderer A renderer to use
7016 * @param name the tag name
7017 * @param namespace Optional namespace for element.
7018 * @returns the element created
7019 */
7020function createElementNode(renderer, name, namespace) {
7021 ngDevMode && ngDevMode.rendererCreateElement++;
7022 if (isProceduralRenderer(renderer)) {
7023 return renderer.createElement(name, namespace);
7024 }
7025 else {
7026 const namespaceUri = namespace !== null ? getNamespaceUri(namespace) : null;
7027 return namespaceUri === null ? renderer.createElement(name) :
7028 renderer.createElementNS(namespaceUri, name);
7029 }
7030}
7031/**
7032 * Removes all DOM elements associated with a view.
7033 *
7034 * Because some root nodes of the view may be containers, we sometimes need
7035 * to propagate deeply into the nested containers to remove all elements in the
7036 * views beneath it.
7037 *
7038 * @param tView The `TView' of the `LView` from which elements should be added or removed
7039 * @param lView The view from which elements should be added or removed
7040 */
7041function removeViewFromContainer(tView, lView) {
7042 const renderer = lView[RENDERER];
7043 applyView(tView, lView, renderer, 2 /* Detach */, null, null);
7044 lView[HOST] = null;
7045 lView[T_HOST] = null;
7046}
7047/**
7048 * Adds all DOM elements associated with a view.
7049 *
7050 * Because some root nodes of the view may be containers, we sometimes need
7051 * to propagate deeply into the nested containers to add all elements in the
7052 * views beneath it.
7053 *
7054 * @param tView The `TView' of the `LView` from which elements should be added or removed
7055 * @param parentTNode The `TNode` where the `LView` should be attached to.
7056 * @param renderer Current renderer to use for DOM manipulations.
7057 * @param lView The view from which elements should be added or removed
7058 * @param parentNativeNode The parent `RElement` where it should be inserted into.
7059 * @param beforeNode The node before which elements should be added, if insert mode
7060 */
7061function addViewToContainer(tView, parentTNode, renderer, lView, parentNativeNode, beforeNode) {
7062 lView[HOST] = parentNativeNode;
7063 lView[T_HOST] = parentTNode;
7064 applyView(tView, lView, renderer, 1 /* Insert */, parentNativeNode, beforeNode);
7065}
7066/**
7067 * Detach a `LView` from the DOM by detaching its nodes.
7068 *
7069 * @param tView The `TView' of the `LView` to be detached
7070 * @param lView the `LView` to be detached.
7071 */
7072function renderDetachView(tView, lView) {
7073 applyView(tView, lView, lView[RENDERER], 2 /* Detach */, null, null);
7074}
7075/**
7076 * Traverses down and up the tree of views and containers to remove listeners and
7077 * call onDestroy callbacks.
7078 *
7079 * Notes:
7080 * - Because it's used for onDestroy calls, it needs to be bottom-up.
7081 * - Must process containers instead of their views to avoid splicing
7082 * when views are destroyed and re-added.
7083 * - Using a while loop because it's faster than recursion
7084 * - Destroy only called on movement to sibling or movement to parent (laterally or up)
7085 *
7086 * @param rootView The view to destroy
7087 */
7088function destroyViewTree(rootView) {
7089 // If the view has no children, we can clean it up and return early.
7090 let lViewOrLContainer = rootView[CHILD_HEAD];
7091 if (!lViewOrLContainer) {
7092 return cleanUpView(rootView[TVIEW], rootView);
7093 }
7094 while (lViewOrLContainer) {
7095 let next = null;
7096 if (isLView(lViewOrLContainer)) {
7097 // If LView, traverse down to child.
7098 next = lViewOrLContainer[CHILD_HEAD];
7099 }
7100 else {
7101 ngDevMode && assertLContainer(lViewOrLContainer);
7102 // If container, traverse down to its first LView.
7103 const firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET];
7104 if (firstView)
7105 next = firstView;
7106 }
7107 if (!next) {
7108 // Only clean up view when moving to the side or up, as destroy hooks
7109 // should be called in order from the bottom up.
7110 while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) {
7111 if (isLView(lViewOrLContainer)) {
7112 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
7113 }
7114 lViewOrLContainer = lViewOrLContainer[PARENT];
7115 }
7116 if (lViewOrLContainer === null)
7117 lViewOrLContainer = rootView;
7118 if (isLView(lViewOrLContainer)) {
7119 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
7120 }
7121 next = lViewOrLContainer && lViewOrLContainer[NEXT];
7122 }
7123 lViewOrLContainer = next;
7124 }
7125}
7126/**
7127 * Inserts a view into a container.
7128 *
7129 * This adds the view to the container's array of active views in the correct
7130 * position. It also adds the view's elements to the DOM if the container isn't a
7131 * root node of another view (in that case, the view's elements will be added when
7132 * the container's parent view is added later).
7133 *
7134 * @param tView The `TView' of the `LView` to insert
7135 * @param lView The view to insert
7136 * @param lContainer The container into which the view should be inserted
7137 * @param index Which index in the container to insert the child view into
7138 */
7139function insertView(tView, lView, lContainer, index) {
7140 ngDevMode && assertLView(lView);
7141 ngDevMode && assertLContainer(lContainer);
7142 const indexInContainer = CONTAINER_HEADER_OFFSET + index;
7143 const containerLength = lContainer.length;
7144 if (index > 0) {
7145 // This is a new view, we need to add it to the children.
7146 lContainer[indexInContainer - 1][NEXT] = lView;
7147 }
7148 if (index < containerLength - CONTAINER_HEADER_OFFSET) {
7149 lView[NEXT] = lContainer[indexInContainer];
7150 addToArray(lContainer, CONTAINER_HEADER_OFFSET + index, lView);
7151 }
7152 else {
7153 lContainer.push(lView);
7154 lView[NEXT] = null;
7155 }
7156 lView[PARENT] = lContainer;
7157 // track views where declaration and insertion points are different
7158 const declarationLContainer = lView[DECLARATION_LCONTAINER];
7159 if (declarationLContainer !== null && lContainer !== declarationLContainer) {
7160 trackMovedView(declarationLContainer, lView);
7161 }
7162 // notify query that a new view has been added
7163 const lQueries = lView[QUERIES];
7164 if (lQueries !== null) {
7165 lQueries.insertView(tView);
7166 }
7167 // Sets the attached flag
7168 lView[FLAGS] |= 128 /* Attached */;
7169}
7170/**
7171 * Track views created from the declaration container (TemplateRef) and inserted into a
7172 * different LContainer.
7173 */
7174function trackMovedView(declarationContainer, lView) {
7175 ngDevMode && assertDefined(lView, 'LView required');
7176 ngDevMode && assertLContainer(declarationContainer);
7177 const movedViews = declarationContainer[MOVED_VIEWS];
7178 const insertedLContainer = lView[PARENT];
7179 ngDevMode && assertLContainer(insertedLContainer);
7180 const insertedComponentLView = insertedLContainer[PARENT][DECLARATION_COMPONENT_VIEW];
7181 ngDevMode && assertDefined(insertedComponentLView, 'Missing insertedComponentLView');
7182 const declaredComponentLView = lView[DECLARATION_COMPONENT_VIEW];
7183 ngDevMode && assertDefined(declaredComponentLView, 'Missing declaredComponentLView');
7184 if (declaredComponentLView !== insertedComponentLView) {
7185 // At this point the declaration-component is not same as insertion-component; this means that
7186 // this is a transplanted view. Mark the declared lView as having transplanted views so that
7187 // those views can participate in CD.
7188 declarationContainer[HAS_TRANSPLANTED_VIEWS] = true;
7189 }
7190 if (movedViews === null) {
7191 declarationContainer[MOVED_VIEWS] = [lView];
7192 }
7193 else {
7194 movedViews.push(lView);
7195 }
7196}
7197function detachMovedView(declarationContainer, lView) {
7198 ngDevMode && assertLContainer(declarationContainer);
7199 ngDevMode &&
7200 assertDefined(declarationContainer[MOVED_VIEWS], 'A projected view should belong to a non-empty projected views collection');
7201 const movedViews = declarationContainer[MOVED_VIEWS];
7202 const declarationViewIndex = movedViews.indexOf(lView);
7203 const insertionLContainer = lView[PARENT];
7204 ngDevMode && assertLContainer(insertionLContainer);
7205 // If the view was marked for refresh but then detached before it was checked (where the flag
7206 // would be cleared and the counter decremented), we need to decrement the view counter here
7207 // instead.
7208 if (lView[FLAGS] & 1024 /* RefreshTransplantedView */) {
7209 lView[FLAGS] &= ~1024 /* RefreshTransplantedView */;
7210 updateTransplantedViewCount(insertionLContainer, -1);
7211 }
7212 movedViews.splice(declarationViewIndex, 1);
7213}
7214/**
7215 * Detaches a view from a container.
7216 *
7217 * This method removes the view from the container's array of active views. It also
7218 * removes the view's elements from the DOM.
7219 *
7220 * @param lContainer The container from which to detach a view
7221 * @param removeIndex The index of the view to detach
7222 * @returns Detached LView instance.
7223 */
7224function detachView(lContainer, removeIndex) {
7225 if (lContainer.length <= CONTAINER_HEADER_OFFSET)
7226 return;
7227 const indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
7228 const viewToDetach = lContainer[indexInContainer];
7229 if (viewToDetach) {
7230 const declarationLContainer = viewToDetach[DECLARATION_LCONTAINER];
7231 if (declarationLContainer !== null && declarationLContainer !== lContainer) {
7232 detachMovedView(declarationLContainer, viewToDetach);
7233 }
7234 if (removeIndex > 0) {
7235 lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT];
7236 }
7237 const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
7238 removeViewFromContainer(viewToDetach[TVIEW], viewToDetach);
7239 // notify query that a view has been removed
7240 const lQueries = removedLView[QUERIES];
7241 if (lQueries !== null) {
7242 lQueries.detachView(removedLView[TVIEW]);
7243 }
7244 viewToDetach[PARENT] = null;
7245 viewToDetach[NEXT] = null;
7246 // Unsets the attached flag
7247 viewToDetach[FLAGS] &= ~128 /* Attached */;
7248 }
7249 return viewToDetach;
7250}
7251/**
7252 * A standalone function which destroys an LView,
7253 * conducting clean up (e.g. removing listeners, calling onDestroys).
7254 *
7255 * @param tView The `TView' of the `LView` to be destroyed
7256 * @param lView The view to be destroyed.
7257 */
7258function destroyLView(tView, lView) {
7259 if (!(lView[FLAGS] & 256 /* Destroyed */)) {
7260 const renderer = lView[RENDERER];
7261 if (isProceduralRenderer(renderer) && renderer.destroyNode) {
7262 applyView(tView, lView, renderer, 3 /* Destroy */, null, null);
7263 }
7264 destroyViewTree(lView);
7265 }
7266}
7267/**
7268 * Calls onDestroys hooks for all directives and pipes in a given view and then removes all
7269 * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks
7270 * can be propagated to @Output listeners.
7271 *
7272 * @param tView `TView` for the `LView` to clean up.
7273 * @param lView The LView to clean up
7274 */
7275function cleanUpView(tView, lView) {
7276 if (!(lView[FLAGS] & 256 /* Destroyed */)) {
7277 // Usually the Attached flag is removed when the view is detached from its parent, however
7278 // if it's a root view, the flag won't be unset hence why we're also removing on destroy.
7279 lView[FLAGS] &= ~128 /* Attached */;
7280 // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
7281 // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
7282 // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
7283 // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
7284 // really more of an "afterDestroy" hook if you think about it.
7285 lView[FLAGS] |= 256 /* Destroyed */;
7286 executeOnDestroys(tView, lView);
7287 processCleanups(tView, lView);
7288 // For component views only, the local renderer is destroyed at clean up time.
7289 if (lView[TVIEW].type === 1 /* Component */ && isProceduralRenderer(lView[RENDERER])) {
7290 ngDevMode && ngDevMode.rendererDestroy++;
7291 lView[RENDERER].destroy();
7292 }
7293 const declarationContainer = lView[DECLARATION_LCONTAINER];
7294 // we are dealing with an embedded view that is still inserted into a container
7295 if (declarationContainer !== null && isLContainer(lView[PARENT])) {
7296 // and this is a projected view
7297 if (declarationContainer !== lView[PARENT]) {
7298 detachMovedView(declarationContainer, lView);
7299 }
7300 // For embedded views still attached to a container: remove query result from this view.
7301 const lQueries = lView[QUERIES];
7302 if (lQueries !== null) {
7303 lQueries.detachView(tView);
7304 }
7305 }
7306 }
7307}
7308/** Removes listeners and unsubscribes from output subscriptions */
7309function processCleanups(tView, lView) {
7310 const tCleanup = tView.cleanup;
7311 const lCleanup = lView[CLEANUP];
7312 // `LCleanup` contains both share information with `TCleanup` as well as instance specific
7313 // information appended at the end. We need to know where the end of the `TCleanup` information
7314 // is, and we track this with `lastLCleanupIndex`.
7315 let lastLCleanupIndex = -1;
7316 if (tCleanup !== null) {
7317 for (let i = 0; i < tCleanup.length - 1; i += 2) {
7318 if (typeof tCleanup[i] === 'string') {
7319 // This is a native DOM listener
7320 const idxOrTargetGetter = tCleanup[i + 1];
7321 const target = typeof idxOrTargetGetter === 'function' ?
7322 idxOrTargetGetter(lView) :
7323 unwrapRNode(lView[idxOrTargetGetter]);
7324 const listener = lCleanup[lastLCleanupIndex = tCleanup[i + 2]];
7325 const useCaptureOrSubIdx = tCleanup[i + 3];
7326 if (typeof useCaptureOrSubIdx === 'boolean') {
7327 // native DOM listener registered with Renderer3
7328 target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx);
7329 }
7330 else {
7331 if (useCaptureOrSubIdx >= 0) {
7332 // unregister
7333 lCleanup[lastLCleanupIndex = useCaptureOrSubIdx]();
7334 }
7335 else {
7336 // Subscription
7337 lCleanup[lastLCleanupIndex = -useCaptureOrSubIdx].unsubscribe();
7338 }
7339 }
7340 i += 2;
7341 }
7342 else {
7343 // This is a cleanup function that is grouped with the index of its context
7344 const context = lCleanup[lastLCleanupIndex = tCleanup[i + 1]];
7345 tCleanup[i].call(context);
7346 }
7347 }
7348 }
7349 if (lCleanup !== null) {
7350 for (let i = lastLCleanupIndex + 1; i < lCleanup.length; i++) {
7351 const instanceCleanupFn = lCleanup[i];
7352 ngDevMode && assertFunction(instanceCleanupFn, 'Expecting instance cleanup function.');
7353 instanceCleanupFn();
7354 }
7355 lView[CLEANUP] = null;
7356 }
7357}
7358/** Calls onDestroy hooks for this view */
7359function executeOnDestroys(tView, lView) {
7360 let destroyHooks;
7361 if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
7362 for (let i = 0; i < destroyHooks.length; i += 2) {
7363 const context = lView[destroyHooks[i]];
7364 // Only call the destroy hook if the context has been requested.
7365 if (!(context instanceof NodeInjectorFactory)) {
7366 const toCall = destroyHooks[i + 1];
7367 if (Array.isArray(toCall)) {
7368 for (let j = 0; j < toCall.length; j += 2) {
7369 const callContext = context[toCall[j]];
7370 const hook = toCall[j + 1];
7371 profiler(4 /* LifecycleHookStart */, callContext, hook);
7372 try {
7373 hook.call(callContext);
7374 }
7375 finally {
7376 profiler(5 /* LifecycleHookEnd */, callContext, hook);
7377 }
7378 }
7379 }
7380 else {
7381 profiler(4 /* LifecycleHookStart */, context, toCall);
7382 try {
7383 toCall.call(context);
7384 }
7385 finally {
7386 profiler(5 /* LifecycleHookEnd */, context, toCall);
7387 }
7388 }
7389 }
7390 }
7391 }
7392}
7393/**
7394 * Returns a native element if a node can be inserted into the given parent.
7395 *
7396 * There are two reasons why we may not be able to insert a element immediately.
7397 * - Projection: When creating a child content element of a component, we have to skip the
7398 * insertion because the content of a component will be projected.
7399 * `<component><content>delayed due to projection</content></component>`
7400 * - Parent container is disconnected: This can happen when we are inserting a view into
7401 * parent container, which itself is disconnected. For example the parent container is part
7402 * of a View which has not be inserted or is made for projection but has not been inserted
7403 * into destination.
7404 *
7405 * @param tView: Current `TView`.
7406 * @param tNode: `TNode` for which we wish to retrieve render parent.
7407 * @param lView: Current `LView`.
7408 */
7409function getParentRElement(tView, tNode, lView) {
7410 return getClosestRElement(tView, tNode.parent, lView);
7411}
7412/**
7413 * Get closest `RElement` or `null` if it can't be found.
7414 *
7415 * If `TNode` is `TNodeType.Element` => return `RElement` at `LView[tNode.index]` location.
7416 * If `TNode` is `TNodeType.ElementContainer|IcuContain` => return the parent (recursively).
7417 * If `TNode` is `null` then return host `RElement`:
7418 * - return `null` if projection
7419 * - return `null` if parent container is disconnected (we have no parent.)
7420 *
7421 * @param tView: Current `TView`.
7422 * @param tNode: `TNode` for which we wish to retrieve `RElement` (or `null` if host element is
7423 * needed).
7424 * @param lView: Current `LView`.
7425 * @returns `null` if the `RElement` can't be determined at this time (no parent / projection)
7426 */
7427function getClosestRElement(tView, tNode, lView) {
7428 let parentTNode = tNode;
7429 // Skip over element and ICU containers as those are represented by a comment node and
7430 // can't be used as a render parent.
7431 while (parentTNode !== null &&
7432 (parentTNode.type & (8 /* ElementContainer */ | 32 /* Icu */))) {
7433 tNode = parentTNode;
7434 parentTNode = tNode.parent;
7435 }
7436 // If the parent tNode is null, then we are inserting across views: either into an embedded view
7437 // or a component view.
7438 if (parentTNode === null) {
7439 // We are inserting a root element of the component view into the component host element and
7440 // it should always be eager.
7441 return lView[HOST];
7442 }
7443 else {
7444 ngDevMode && assertTNodeType(parentTNode, 3 /* AnyRNode */ | 4 /* Container */);
7445 if (parentTNode.flags & 2 /* isComponentHost */) {
7446 ngDevMode && assertTNodeForLView(parentTNode, lView);
7447 const encapsulation = tView.data[parentTNode.directiveStart].encapsulation;
7448 // We've got a parent which is an element in the current view. We just need to verify if the
7449 // parent element is not a component. Component's content nodes are not inserted immediately
7450 // because they will be projected, and so doing insert at this point would be wasteful.
7451 // Since the projection would then move it to its final destination. Note that we can't
7452 // make this assumption when using the Shadow DOM, because the native projection placeholders
7453 // (<content> or <slot>) have to be in place as elements are being inserted.
7454 if (encapsulation === ViewEncapsulation$1.None ||
7455 encapsulation === ViewEncapsulation$1.Emulated) {
7456 return null;
7457 }
7458 }
7459 return getNativeByTNode(parentTNode, lView);
7460 }
7461}
7462/**
7463 * Inserts a native node before another native node for a given parent using {@link Renderer3}.
7464 * This is a utility function that can be used when native nodes were determined - it abstracts an
7465 * actual renderer being used.
7466 */
7467function nativeInsertBefore(renderer, parent, child, beforeNode, isMove) {
7468 ngDevMode && ngDevMode.rendererInsertBefore++;
7469 if (isProceduralRenderer(renderer)) {
7470 renderer.insertBefore(parent, child, beforeNode, isMove);
7471 }
7472 else {
7473 parent.insertBefore(child, beforeNode, isMove);
7474 }
7475}
7476function nativeAppendChild(renderer, parent, child) {
7477 ngDevMode && ngDevMode.rendererAppendChild++;
7478 ngDevMode && assertDefined(parent, 'parent node must be defined');
7479 if (isProceduralRenderer(renderer)) {
7480 renderer.appendChild(parent, child);
7481 }
7482 else {
7483 parent.appendChild(child);
7484 }
7485}
7486function nativeAppendOrInsertBefore(renderer, parent, child, beforeNode, isMove) {
7487 if (beforeNode !== null) {
7488 nativeInsertBefore(renderer, parent, child, beforeNode, isMove);
7489 }
7490 else {
7491 nativeAppendChild(renderer, parent, child);
7492 }
7493}
7494/** Removes a node from the DOM given its native parent. */
7495function nativeRemoveChild(renderer, parent, child, isHostElement) {
7496 if (isProceduralRenderer(renderer)) {
7497 renderer.removeChild(parent, child, isHostElement);
7498 }
7499 else {
7500 parent.removeChild(child);
7501 }
7502}
7503/**
7504 * Returns a native parent of a given native node.
7505 */
7506function nativeParentNode(renderer, node) {
7507 return (isProceduralRenderer(renderer) ? renderer.parentNode(node) : node.parentNode);
7508}
7509/**
7510 * Returns a native sibling of a given native node.
7511 */
7512function nativeNextSibling(renderer, node) {
7513 return isProceduralRenderer(renderer) ? renderer.nextSibling(node) : node.nextSibling;
7514}
7515/**
7516 * Find a node in front of which `currentTNode` should be inserted.
7517 *
7518 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
7519 * takes `TNode.insertBeforeIndex` into account if i18n code has been invoked.
7520 *
7521 * @param parentTNode parent `TNode`
7522 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
7523 * @param lView current `LView`
7524 */
7525function getInsertInFrontOfRNode(parentTNode, currentTNode, lView) {
7526 return _getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView);
7527}
7528/**
7529 * Find a node in front of which `currentTNode` should be inserted. (Does not take i18n into
7530 * account)
7531 *
7532 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
7533 * does not take `TNode.insertBeforeIndex` into account.
7534 *
7535 * @param parentTNode parent `TNode`
7536 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
7537 * @param lView current `LView`
7538 */
7539function getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView) {
7540 if (parentTNode.type & (8 /* ElementContainer */ | 32 /* Icu */)) {
7541 return getNativeByTNode(parentTNode, lView);
7542 }
7543 return null;
7544}
7545/**
7546 * Tree shakable boundary for `getInsertInFrontOfRNodeWithI18n` function.
7547 *
7548 * This function will only be set if i18n code runs.
7549 */
7550let _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithNoI18n;
7551/**
7552 * Tree shakable boundary for `processI18nInsertBefore` function.
7553 *
7554 * This function will only be set if i18n code runs.
7555 */
7556let _processI18nInsertBefore;
7557function setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore) {
7558 _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithI18n;
7559 _processI18nInsertBefore = processI18nInsertBefore;
7560}
7561/**
7562 * Appends the `child` native node (or a collection of nodes) to the `parent`.
7563 *
7564 * @param tView The `TView' to be appended
7565 * @param lView The current LView
7566 * @param childRNode The native child (or children) that should be appended
7567 * @param childTNode The TNode of the child element
7568 */
7569function appendChild(tView, lView, childRNode, childTNode) {
7570 const parentRNode = getParentRElement(tView, childTNode, lView);
7571 const renderer = lView[RENDERER];
7572 const parentTNode = childTNode.parent || lView[T_HOST];
7573 const anchorNode = getInsertInFrontOfRNode(parentTNode, childTNode, lView);
7574 if (parentRNode != null) {
7575 if (Array.isArray(childRNode)) {
7576 for (let i = 0; i < childRNode.length; i++) {
7577 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode[i], anchorNode, false);
7578 }
7579 }
7580 else {
7581 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode, anchorNode, false);
7582 }
7583 }
7584 _processI18nInsertBefore !== undefined &&
7585 _processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRNode);
7586}
7587/**
7588 * Returns the first native node for a given LView, starting from the provided TNode.
7589 *
7590 * Native nodes are returned in the order in which those appear in the native tree (DOM).
7591 */
7592function getFirstNativeNode(lView, tNode) {
7593 if (tNode !== null) {
7594 ngDevMode &&
7595 assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */ | 32 /* Icu */ | 16 /* Projection */);
7596 const tNodeType = tNode.type;
7597 if (tNodeType & 3 /* AnyRNode */) {
7598 return getNativeByTNode(tNode, lView);
7599 }
7600 else if (tNodeType & 4 /* Container */) {
7601 return getBeforeNodeForView(-1, lView[tNode.index]);
7602 }
7603 else if (tNodeType & 8 /* ElementContainer */) {
7604 const elIcuContainerChild = tNode.child;
7605 if (elIcuContainerChild !== null) {
7606 return getFirstNativeNode(lView, elIcuContainerChild);
7607 }
7608 else {
7609 const rNodeOrLContainer = lView[tNode.index];
7610 if (isLContainer(rNodeOrLContainer)) {
7611 return getBeforeNodeForView(-1, rNodeOrLContainer);
7612 }
7613 else {
7614 return unwrapRNode(rNodeOrLContainer);
7615 }
7616 }
7617 }
7618 else if (tNodeType & 32 /* Icu */) {
7619 let nextRNode = icuContainerIterate(tNode, lView);
7620 let rNode = nextRNode();
7621 // If the ICU container has no nodes, than we use the ICU anchor as the node.
7622 return rNode || unwrapRNode(lView[tNode.index]);
7623 }
7624 else {
7625 const projectionNodes = getProjectionNodes(lView, tNode);
7626 if (projectionNodes !== null) {
7627 if (Array.isArray(projectionNodes)) {
7628 return projectionNodes[0];
7629 }
7630 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
7631 ngDevMode && assertParentView(parentView);
7632 return getFirstNativeNode(parentView, projectionNodes);
7633 }
7634 else {
7635 return getFirstNativeNode(lView, tNode.next);
7636 }
7637 }
7638 }
7639 return null;
7640}
7641function getProjectionNodes(lView, tNode) {
7642 if (tNode !== null) {
7643 const componentView = lView[DECLARATION_COMPONENT_VIEW];
7644 const componentHost = componentView[T_HOST];
7645 const slotIdx = tNode.projection;
7646 ngDevMode && assertProjectionSlots(lView);
7647 return componentHost.projection[slotIdx];
7648 }
7649 return null;
7650}
7651function getBeforeNodeForView(viewIndexInContainer, lContainer) {
7652 const nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1;
7653 if (nextViewIndex < lContainer.length) {
7654 const lView = lContainer[nextViewIndex];
7655 const firstTNodeOfView = lView[TVIEW].firstChild;
7656 if (firstTNodeOfView !== null) {
7657 return getFirstNativeNode(lView, firstTNodeOfView);
7658 }
7659 }
7660 return lContainer[NATIVE];
7661}
7662/**
7663 * Removes a native node itself using a given renderer. To remove the node we are looking up its
7664 * parent from the native tree as not all platforms / browsers support the equivalent of
7665 * node.remove().
7666 *
7667 * @param renderer A renderer to be used
7668 * @param rNode The native node that should be removed
7669 * @param isHostElement A flag indicating if a node to be removed is a host of a component.
7670 */
7671function nativeRemoveNode(renderer, rNode, isHostElement) {
7672 ngDevMode && ngDevMode.rendererRemoveNode++;
7673 const nativeParent = nativeParentNode(renderer, rNode);
7674 if (nativeParent) {
7675 nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
7676 }
7677}
7678/**
7679 * Performs the operation of `action` on the node. Typically this involves inserting or removing
7680 * nodes on the LView or projection boundary.
7681 */
7682function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode, isProjection) {
7683 while (tNode != null) {
7684 ngDevMode && assertTNodeForLView(tNode, lView);
7685 ngDevMode &&
7686 assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */ | 16 /* Projection */ | 32 /* Icu */);
7687 const rawSlotValue = lView[tNode.index];
7688 const tNodeType = tNode.type;
7689 if (isProjection) {
7690 if (action === 0 /* Create */) {
7691 rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
7692 tNode.flags |= 4 /* isProjected */;
7693 }
7694 }
7695 if ((tNode.flags & 64 /* isDetached */) !== 64 /* isDetached */) {
7696 if (tNodeType & 8 /* ElementContainer */) {
7697 applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
7698 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
7699 }
7700 else if (tNodeType & 32 /* Icu */) {
7701 const nextRNode = icuContainerIterate(tNode, lView);
7702 let rNode;
7703 while (rNode = nextRNode()) {
7704 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
7705 }
7706 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
7707 }
7708 else if (tNodeType & 16 /* Projection */) {
7709 applyProjectionRecursive(renderer, action, lView, tNode, parentRElement, beforeNode);
7710 }
7711 else {
7712 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */ | 4 /* Container */);
7713 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
7714 }
7715 }
7716 tNode = isProjection ? tNode.projectionNext : tNode.next;
7717 }
7718}
7719function applyView(tView, lView, renderer, action, parentRElement, beforeNode) {
7720 applyNodes(renderer, action, tView.firstChild, lView, parentRElement, beforeNode, false);
7721}
7722/**
7723 * `applyProjection` performs operation on the projection.
7724 *
7725 * Inserting a projection requires us to locate the projected nodes from the parent component. The
7726 * complication is that those nodes themselves could be re-projected from their parent component.
7727 *
7728 * @param tView The `TView` of `LView` which needs to be inserted, detached, destroyed
7729 * @param lView The `LView` which needs to be inserted, detached, destroyed.
7730 * @param tProjectionNode node to project
7731 */
7732function applyProjection(tView, lView, tProjectionNode) {
7733 const renderer = lView[RENDERER];
7734 const parentRNode = getParentRElement(tView, tProjectionNode, lView);
7735 const parentTNode = tProjectionNode.parent || lView[T_HOST];
7736 let beforeNode = getInsertInFrontOfRNode(parentTNode, tProjectionNode, lView);
7737 applyProjectionRecursive(renderer, 0 /* Create */, lView, tProjectionNode, parentRNode, beforeNode);
7738}
7739/**
7740 * `applyProjectionRecursive` performs operation on the projection specified by `action` (insert,
7741 * detach, destroy)
7742 *
7743 * Inserting a projection requires us to locate the projected nodes from the parent component. The
7744 * complication is that those nodes themselves could be re-projected from their parent component.
7745 *
7746 * @param renderer Render to use
7747 * @param action action to perform (insert, detach, destroy)
7748 * @param lView The LView which needs to be inserted, detached, destroyed.
7749 * @param tProjectionNode node to project
7750 * @param parentRElement parent DOM element for insertion/removal.
7751 * @param beforeNode Before which node the insertions should happen.
7752 */
7753function applyProjectionRecursive(renderer, action, lView, tProjectionNode, parentRElement, beforeNode) {
7754 const componentLView = lView[DECLARATION_COMPONENT_VIEW];
7755 const componentNode = componentLView[T_HOST];
7756 ngDevMode &&
7757 assertEqual(typeof tProjectionNode.projection, 'number', 'expecting projection index');
7758 const nodeToProjectOrRNodes = componentNode.projection[tProjectionNode.projection];
7759 if (Array.isArray(nodeToProjectOrRNodes)) {
7760 // This should not exist, it is a bit of a hack. When we bootstrap a top level node and we
7761 // need to support passing projectable nodes, so we cheat and put them in the TNode
7762 // of the Host TView. (Yes we put instance info at the T Level). We can get away with it
7763 // because we know that that TView is not shared and therefore it will not be a problem.
7764 // This should be refactored and cleaned up.
7765 for (let i = 0; i < nodeToProjectOrRNodes.length; i++) {
7766 const rNode = nodeToProjectOrRNodes[i];
7767 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
7768 }
7769 }
7770 else {
7771 let nodeToProject = nodeToProjectOrRNodes;
7772 const projectedComponentLView = componentLView[PARENT];
7773 applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
7774 }
7775}
7776/**
7777 * `applyContainer` performs an operation on the container and its views as specified by
7778 * `action` (insert, detach, destroy)
7779 *
7780 * Inserting a Container is complicated by the fact that the container may have Views which
7781 * themselves have containers or projections.
7782 *
7783 * @param renderer Renderer to use
7784 * @param action action to perform (insert, detach, destroy)
7785 * @param lContainer The LContainer which needs to be inserted, detached, destroyed.
7786 * @param parentRElement parent DOM element for insertion/removal.
7787 * @param beforeNode Before which node the insertions should happen.
7788 */
7789function applyContainer(renderer, action, lContainer, parentRElement, beforeNode) {
7790 ngDevMode && assertLContainer(lContainer);
7791 const anchor = lContainer[NATIVE]; // LContainer has its own before node.
7792 const native = unwrapRNode(lContainer);
7793 // An LContainer can be created dynamically on any node by injecting ViewContainerRef.
7794 // Asking for a ViewContainerRef on an element will result in a creation of a separate anchor
7795 // node (comment in the DOM) that will be different from the LContainer's host node. In this
7796 // particular case we need to execute action on 2 nodes:
7797 // - container's host node (this is done in the executeActionOnElementOrContainer)
7798 // - container's host node (this is done here)
7799 if (anchor !== native) {
7800 // This is very strange to me (Misko). I would expect that the native is same as anchor. I
7801 // don't see a reason why they should be different, but they are.
7802 //
7803 // If they are we need to process the second anchor as well.
7804 applyToElementOrContainer(action, renderer, parentRElement, anchor, beforeNode);
7805 }
7806 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
7807 const lView = lContainer[i];
7808 applyView(lView[TVIEW], lView, renderer, action, parentRElement, anchor);
7809 }
7810}
7811/**
7812 * Writes class/style to element.
7813 *
7814 * @param renderer Renderer to use.
7815 * @param isClassBased `true` if it should be written to `class` (`false` to write to `style`)
7816 * @param rNode The Node to write to.
7817 * @param prop Property to write to. This would be the class/style name.
7818 * @param value Value to write. If `null`/`undefined`/`false` this is considered a remove (set/add
7819 * otherwise).
7820 */
7821function applyStyling(renderer, isClassBased, rNode, prop, value) {
7822 const isProcedural = isProceduralRenderer(renderer);
7823 if (isClassBased) {
7824 // We actually want JS true/false here because any truthy value should add the class
7825 if (!value) {
7826 ngDevMode && ngDevMode.rendererRemoveClass++;
7827 if (isProcedural) {
7828 renderer.removeClass(rNode, prop);
7829 }
7830 else {
7831 rNode.classList.remove(prop);
7832 }
7833 }
7834 else {
7835 ngDevMode && ngDevMode.rendererAddClass++;
7836 if (isProcedural) {
7837 renderer.addClass(rNode, prop);
7838 }
7839 else {
7840 ngDevMode && assertDefined(rNode.classList, 'HTMLElement expected');
7841 rNode.classList.add(prop);
7842 }
7843 }
7844 }
7845 else {
7846 let flags = prop.indexOf('-') === -1 ? undefined : RendererStyleFlags2.DashCase;
7847 if (value == null /** || value === undefined */) {
7848 ngDevMode && ngDevMode.rendererRemoveStyle++;
7849 if (isProcedural) {
7850 renderer.removeStyle(rNode, prop, flags);
7851 }
7852 else {
7853 rNode.style.removeProperty(prop);
7854 }
7855 }
7856 else {
7857 // A value is important if it ends with `!important`. The style
7858 // parser strips any semicolons at the end of the value.
7859 const isImportant = typeof value === 'string' ? value.endsWith('!important') : false;
7860 if (isImportant) {
7861 // !important has to be stripped from the value for it to be valid.
7862 value = value.slice(0, -10);
7863 flags |= RendererStyleFlags2.Important;
7864 }
7865 ngDevMode && ngDevMode.rendererSetStyle++;
7866 if (isProcedural) {
7867 renderer.setStyle(rNode, prop, value, flags);
7868 }
7869 else {
7870 ngDevMode && assertDefined(rNode.style, 'HTMLElement expected');
7871 rNode.style.setProperty(prop, value, isImportant ? 'important' : '');
7872 }
7873 }
7874 }
7875}
7876/**
7877 * Write `cssText` to `RElement`.
7878 *
7879 * This function does direct write without any reconciliation. Used for writing initial values, so
7880 * that static styling values do not pull in the style parser.
7881 *
7882 * @param renderer Renderer to use
7883 * @param element The element which needs to be updated.
7884 * @param newValue The new class list to write.
7885 */
7886function writeDirectStyle(renderer, element, newValue) {
7887 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
7888 if (isProceduralRenderer(renderer)) {
7889 renderer.setAttribute(element, 'style', newValue);
7890 }
7891 else {
7892 element.style.cssText = newValue;
7893 }
7894 ngDevMode && ngDevMode.rendererSetStyle++;
7895}
7896/**
7897 * Write `className` to `RElement`.
7898 *
7899 * This function does direct write without any reconciliation. Used for writing initial values, so
7900 * that static styling values do not pull in the style parser.
7901 *
7902 * @param renderer Renderer to use
7903 * @param element The element which needs to be updated.
7904 * @param newValue The new class list to write.
7905 */
7906function writeDirectClass(renderer, element, newValue) {
7907 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
7908 if (isProceduralRenderer(renderer)) {
7909 if (newValue === '') {
7910 // There are tests in `google3` which expect `element.getAttribute('class')` to be `null`.
7911 renderer.removeAttribute(element, 'class');
7912 }
7913 else {
7914 renderer.setAttribute(element, 'class', newValue);
7915 }
7916 }
7917 else {
7918 element.className = newValue;
7919 }
7920 ngDevMode && ngDevMode.rendererSetClassName++;
7921}
7922
7923/**
7924 * @license
7925 * Copyright Google LLC All Rights Reserved.
7926 *
7927 * Use of this source code is governed by an MIT-style license that can be
7928 * found in the LICENSE file at https://angular.io/license
7929 */
7930/**
7931 * Returns an index of `classToSearch` in `className` taking token boundaries into account.
7932 *
7933 * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
7934 *
7935 * @param className A string containing classes (whitespace separated)
7936 * @param classToSearch A class name to locate
7937 * @param startingIndex Starting location of search
7938 * @returns an index of the located class (or -1 if not found)
7939 */
7940function classIndexOf(className, classToSearch, startingIndex) {
7941 ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
7942 let end = className.length;
7943 while (true) {
7944 const foundIndex = className.indexOf(classToSearch, startingIndex);
7945 if (foundIndex === -1)
7946 return foundIndex;
7947 if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* SPACE */) {
7948 // Ensure that it has leading whitespace
7949 const length = classToSearch.length;
7950 if (foundIndex + length === end ||
7951 className.charCodeAt(foundIndex + length) <= 32 /* SPACE */) {
7952 // Ensure that it has trailing whitespace
7953 return foundIndex;
7954 }
7955 }
7956 // False positive, keep searching from where we left off.
7957 startingIndex = foundIndex + 1;
7958 }
7959}
7960
7961/**
7962 * @license
7963 * Copyright Google LLC All Rights Reserved.
7964 *
7965 * Use of this source code is governed by an MIT-style license that can be
7966 * found in the LICENSE file at https://angular.io/license
7967 */
7968const unusedValueToPlacateAjd$1 = unusedValueExportToPlacateAjd$4 + unusedValueExportToPlacateAjd$3;
7969const NG_TEMPLATE_SELECTOR = 'ng-template';
7970/**
7971 * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
7972 *
7973 * @param attrs `TAttributes` to search through.
7974 * @param cssClassToMatch class to match (lowercase)
7975 * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
7976 * addition to the `AttributeMarker.Classes`.
7977 */
7978function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
7979 // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
7980 // It is strange to me that sometimes the class information comes in form of `class` attribute
7981 // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
7982 // if that is the right behavior.
7983 ngDevMode &&
7984 assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
7985 let i = 0;
7986 while (i < attrs.length) {
7987 let item = attrs[i++];
7988 if (isProjectionMode && item === 'class') {
7989 item = attrs[i];
7990 if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
7991 return true;
7992 }
7993 }
7994 else if (item === 1 /* Classes */) {
7995 // We found the classes section. Start searching for the class.
7996 while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
7997 // while we have strings
7998 if (item.toLowerCase() === cssClassToMatch)
7999 return true;
8000 }
8001 return false;
8002 }
8003 }
8004 return false;
8005}
8006/**
8007 * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
8008 *
8009 * @param tNode current TNode
8010 */
8011function isInlineTemplate(tNode) {
8012 return tNode.type === 4 /* Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
8013}
8014/**
8015 * Function that checks whether a given tNode matches tag-based selector and has a valid type.
8016 *
8017 * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
8018 * directive matching mode:
8019 * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
8020 * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
8021 * tag name was extracted from * syntax so we would match the same directive twice);
8022 * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
8023 * (applicable to TNodeType.Container only).
8024 */
8025function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
8026 const tagNameToCompare = tNode.type === 4 /* Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
8027 return currentSelector === tagNameToCompare;
8028}
8029/**
8030 * A utility function to match an Ivy node static data against a simple CSS selector
8031 *
8032 * @param node static data of the node to match
8033 * @param selector The selector to try matching against the node.
8034 * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
8035 * directive matching.
8036 * @returns true if node matches the selector.
8037 */
8038function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
8039 ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
8040 let mode = 4 /* ELEMENT */;
8041 const nodeAttrs = tNode.attrs || [];
8042 // Find the index of first attribute that has no value, only a name.
8043 const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
8044 // When processing ":not" selectors, we skip to the next ":not" if the
8045 // current one doesn't match
8046 let skipToNextSelector = false;
8047 for (let i = 0; i < selector.length; i++) {
8048 const current = selector[i];
8049 if (typeof current === 'number') {
8050 // If we finish processing a :not selector and it hasn't failed, return false
8051 if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
8052 return false;
8053 }
8054 // If we are skipping to the next :not() and this mode flag is positive,
8055 // it's a part of the current :not() selector, and we should keep skipping
8056 if (skipToNextSelector && isPositive(current))
8057 continue;
8058 skipToNextSelector = false;
8059 mode = current | (mode & 1 /* NOT */);
8060 continue;
8061 }
8062 if (skipToNextSelector)
8063 continue;
8064 if (mode & 4 /* ELEMENT */) {
8065 mode = 2 /* ATTRIBUTE */ | mode & 1 /* NOT */;
8066 if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
8067 current === '' && selector.length === 1) {
8068 if (isPositive(mode))
8069 return false;
8070 skipToNextSelector = true;
8071 }
8072 }
8073 else {
8074 const selectorAttrValue = mode & 8 /* CLASS */ ? current : selector[++i];
8075 // special case for matching against classes when a tNode has been instantiated with
8076 // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
8077 if ((mode & 8 /* CLASS */) && tNode.attrs !== null) {
8078 if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
8079 if (isPositive(mode))
8080 return false;
8081 skipToNextSelector = true;
8082 }
8083 continue;
8084 }
8085 const attrName = (mode & 8 /* CLASS */) ? 'class' : current;
8086 const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
8087 if (attrIndexInNode === -1) {
8088 if (isPositive(mode))
8089 return false;
8090 skipToNextSelector = true;
8091 continue;
8092 }
8093 if (selectorAttrValue !== '') {
8094 let nodeAttrValue;
8095 if (attrIndexInNode > nameOnlyMarkerIdx) {
8096 nodeAttrValue = '';
8097 }
8098 else {
8099 ngDevMode &&
8100 assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* NamespaceURI */, 'We do not match directives on namespaced attributes');
8101 // we lowercase the attribute value to be able to match
8102 // selectors without case-sensitivity
8103 // (selectors are already in lowercase when generated)
8104 nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
8105 }
8106 const compareAgainstClassName = mode & 8 /* CLASS */ ? nodeAttrValue : null;
8107 if (compareAgainstClassName &&
8108 classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
8109 mode & 2 /* ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
8110 if (isPositive(mode))
8111 return false;
8112 skipToNextSelector = true;
8113 }
8114 }
8115 }
8116 }
8117 return isPositive(mode) || skipToNextSelector;
8118}
8119function isPositive(mode) {
8120 return (mode & 1 /* NOT */) === 0;
8121}
8122/**
8123 * Examines the attribute's definition array for a node to find the index of the
8124 * attribute that matches the given `name`.
8125 *
8126 * NOTE: This will not match namespaced attributes.
8127 *
8128 * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
8129 * The following table summarizes which types of attributes we attempt to match:
8130 *
8131 * ===========================================================================================================
8132 * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
8133 * Attributes
8134 * ===========================================================================================================
8135 * Inline + Projection | YES | YES | NO | YES
8136 * -----------------------------------------------------------------------------------------------------------
8137 * Inline + Directive | NO | NO | YES | NO
8138 * -----------------------------------------------------------------------------------------------------------
8139 * Non-inline + Projection | YES | YES | NO | YES
8140 * -----------------------------------------------------------------------------------------------------------
8141 * Non-inline + Directive | YES | YES | NO | YES
8142 * ===========================================================================================================
8143 *
8144 * @param name the name of the attribute to find
8145 * @param attrs the attribute array to examine
8146 * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
8147 * rather than a manually expanded template node (e.g `<ng-template>`).
8148 * @param isProjectionMode true if we are matching against content projection otherwise we are
8149 * matching against directives.
8150 */
8151function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
8152 if (attrs === null)
8153 return -1;
8154 let i = 0;
8155 if (isProjectionMode || !isInlineTemplate) {
8156 let bindingsMode = false;
8157 while (i < attrs.length) {
8158 const maybeAttrName = attrs[i];
8159 if (maybeAttrName === name) {
8160 return i;
8161 }
8162 else if (maybeAttrName === 3 /* Bindings */ || maybeAttrName === 6 /* I18n */) {
8163 bindingsMode = true;
8164 }
8165 else if (maybeAttrName === 1 /* Classes */ || maybeAttrName === 2 /* Styles */) {
8166 let value = attrs[++i];
8167 // We should skip classes here because we have a separate mechanism for
8168 // matching classes in projection mode.
8169 while (typeof value === 'string') {
8170 value = attrs[++i];
8171 }
8172 continue;
8173 }
8174 else if (maybeAttrName === 4 /* Template */) {
8175 // We do not care about Template attributes in this scenario.
8176 break;
8177 }
8178 else if (maybeAttrName === 0 /* NamespaceURI */) {
8179 // Skip the whole namespaced attribute and value. This is by design.
8180 i += 4;
8181 continue;
8182 }
8183 // In binding mode there are only names, rather than name-value pairs.
8184 i += bindingsMode ? 1 : 2;
8185 }
8186 // We did not match the attribute
8187 return -1;
8188 }
8189 else {
8190 return matchTemplateAttribute(attrs, name);
8191 }
8192}
8193function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
8194 for (let i = 0; i < selector.length; i++) {
8195 if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
8196 return true;
8197 }
8198 }
8199 return false;
8200}
8201function getProjectAsAttrValue(tNode) {
8202 const nodeAttrs = tNode.attrs;
8203 if (nodeAttrs != null) {
8204 const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* ProjectAs */);
8205 // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
8206 // (attribute names are stored at even indexes)
8207 if ((ngProjectAsAttrIdx & 1) === 0) {
8208 return nodeAttrs[ngProjectAsAttrIdx + 1];
8209 }
8210 }
8211 return null;
8212}
8213function getNameOnlyMarkerIndex(nodeAttrs) {
8214 for (let i = 0; i < nodeAttrs.length; i++) {
8215 const nodeAttr = nodeAttrs[i];
8216 if (isNameOnlyAttributeMarker(nodeAttr)) {
8217 return i;
8218 }
8219 }
8220 return nodeAttrs.length;
8221}
8222function matchTemplateAttribute(attrs, name) {
8223 let i = attrs.indexOf(4 /* Template */);
8224 if (i > -1) {
8225 i++;
8226 while (i < attrs.length) {
8227 const attr = attrs[i];
8228 // Return in case we checked all template attrs and are switching to the next section in the
8229 // attrs array (that starts with a number that represents an attribute marker).
8230 if (typeof attr === 'number')
8231 return -1;
8232 if (attr === name)
8233 return i;
8234 i++;
8235 }
8236 }
8237 return -1;
8238}
8239/**
8240 * Checks whether a selector is inside a CssSelectorList
8241 * @param selector Selector to be checked.
8242 * @param list List in which to look for the selector.
8243 */
8244function isSelectorInSelectorList(selector, list) {
8245 selectorListLoop: for (let i = 0; i < list.length; i++) {
8246 const currentSelectorInList = list[i];
8247 if (selector.length !== currentSelectorInList.length) {
8248 continue;
8249 }
8250 for (let j = 0; j < selector.length; j++) {
8251 if (selector[j] !== currentSelectorInList[j]) {
8252 continue selectorListLoop;
8253 }
8254 }
8255 return true;
8256 }
8257 return false;
8258}
8259function maybeWrapInNotSelector(isNegativeMode, chunk) {
8260 return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
8261}
8262function stringifyCSSSelector(selector) {
8263 let result = selector[0];
8264 let i = 1;
8265 let mode = 2 /* ATTRIBUTE */;
8266 let currentChunk = '';
8267 let isNegativeMode = false;
8268 while (i < selector.length) {
8269 let valueOrMarker = selector[i];
8270 if (typeof valueOrMarker === 'string') {
8271 if (mode & 2 /* ATTRIBUTE */) {
8272 const attrValue = selector[++i];
8273 currentChunk +=
8274 '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
8275 }
8276 else if (mode & 8 /* CLASS */) {
8277 currentChunk += '.' + valueOrMarker;
8278 }
8279 else if (mode & 4 /* ELEMENT */) {
8280 currentChunk += ' ' + valueOrMarker;
8281 }
8282 }
8283 else {
8284 //
8285 // Append current chunk to the final result in case we come across SelectorFlag, which
8286 // indicates that the previous section of a selector is over. We need to accumulate content
8287 // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
8288 // ```
8289 // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
8290 // ```
8291 // should be transformed to `.classA :not(.classB .classC)`.
8292 //
8293 // Note: for negative selector part, we accumulate content between flags until we find the
8294 // next negative flag. This is needed to support a case where `:not()` rule contains more than
8295 // one chunk, e.g. the following selector:
8296 // ```
8297 // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
8298 // ```
8299 // should be stringified to `:not(p.foo) :not(.bar)`
8300 //
8301 if (currentChunk !== '' && !isPositive(valueOrMarker)) {
8302 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
8303 currentChunk = '';
8304 }
8305 mode = valueOrMarker;
8306 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
8307 // mode is maintained for remaining chunks of a selector.
8308 isNegativeMode = isNegativeMode || !isPositive(mode);
8309 }
8310 i++;
8311 }
8312 if (currentChunk !== '') {
8313 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
8314 }
8315 return result;
8316}
8317/**
8318 * Generates string representation of CSS selector in parsed form.
8319 *
8320 * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
8321 * additional parsing at runtime (for example, for directive matching). However in some cases (for
8322 * example, while bootstrapping a component), a string version of the selector is required to query
8323 * for the host element on the page. This function takes the parsed form of a selector and returns
8324 * its string representation.
8325 *
8326 * @param selectorList selector in parsed form
8327 * @returns string representation of a given selector
8328 */
8329function stringifyCSSSelectorList(selectorList) {
8330 return selectorList.map(stringifyCSSSelector).join(',');
8331}
8332/**
8333 * Extracts attributes and classes information from a given CSS selector.
8334 *
8335 * This function is used while creating a component dynamically. In this case, the host element
8336 * (that is created dynamically) should contain attributes and classes specified in component's CSS
8337 * selector.
8338 *
8339 * @param selector CSS selector in parsed form (in a form of array)
8340 * @returns object with `attrs` and `classes` fields that contain extracted information
8341 */
8342function extractAttrsAndClassesFromSelector(selector) {
8343 const attrs = [];
8344 const classes = [];
8345 let i = 1;
8346 let mode = 2 /* ATTRIBUTE */;
8347 while (i < selector.length) {
8348 let valueOrMarker = selector[i];
8349 if (typeof valueOrMarker === 'string') {
8350 if (mode === 2 /* ATTRIBUTE */) {
8351 if (valueOrMarker !== '') {
8352 attrs.push(valueOrMarker, selector[++i]);
8353 }
8354 }
8355 else if (mode === 8 /* CLASS */) {
8356 classes.push(valueOrMarker);
8357 }
8358 }
8359 else {
8360 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
8361 // mode is maintained for remaining chunks of a selector. Since attributes and classes are
8362 // extracted only for "positive" part of the selector, we can stop here.
8363 if (!isPositive(mode))
8364 break;
8365 mode = valueOrMarker;
8366 }
8367 i++;
8368 }
8369 return { attrs, classes };
8370}
8371
8372/**
8373 * @license
8374 * Copyright Google LLC All Rights Reserved.
8375 *
8376 * Use of this source code is governed by an MIT-style license that can be
8377 * found in the LICENSE file at https://angular.io/license
8378 */
8379/** A special value which designates that a value has not changed. */
8380const NO_CHANGE = (typeof ngDevMode === 'undefined' || ngDevMode) ? { __brand__: 'NO_CHANGE' } : {};
8381
8382/**
8383 * @license
8384 * Copyright Google LLC All Rights Reserved.
8385 *
8386 * Use of this source code is governed by an MIT-style license that can be
8387 * found in the LICENSE file at https://angular.io/license
8388 */
8389/**
8390 * Advances to an element for later binding instructions.
8391 *
8392 * Used in conjunction with instructions like {@link property} to act on elements with specified
8393 * indices, for example those created with {@link element} or {@link elementStart}.
8394 *
8395 * ```ts
8396 * (rf: RenderFlags, ctx: any) => {
8397 * if (rf & 1) {
8398 * text(0, 'Hello');
8399 * text(1, 'Goodbye')
8400 * element(2, 'div');
8401 * }
8402 * if (rf & 2) {
8403 * advance(2); // Advance twice to the <div>.
8404 * property('title', 'test');
8405 * }
8406 * }
8407 * ```
8408 * @param delta Number of elements to advance forwards by.
8409 *
8410 * @codeGenApi
8411 */
8412function ɵɵadvance(delta) {
8413 ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
8414 selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, !!ngDevMode && isInCheckNoChangesMode());
8415}
8416function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
8417 ngDevMode && assertIndexInDeclRange(lView, index);
8418 // Flush the initial hooks for elements in the view that have been added up to this point.
8419 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
8420 if (!checkNoChangesMode) {
8421 const hooksInitPhaseCompleted = (lView[FLAGS] & 3 /* InitPhaseStateMask */) === 3 /* InitPhaseCompleted */;
8422 if (hooksInitPhaseCompleted) {
8423 const preOrderCheckHooks = tView.preOrderCheckHooks;
8424 if (preOrderCheckHooks !== null) {
8425 executeCheckHooks(lView, preOrderCheckHooks, index);
8426 }
8427 }
8428 else {
8429 const preOrderHooks = tView.preOrderHooks;
8430 if (preOrderHooks !== null) {
8431 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* OnInitHooksToBeRun */, index);
8432 }
8433 }
8434 }
8435 // We must set the selected index *after* running the hooks, because hooks may have side-effects
8436 // that cause other template functions to run, thus updating the selected index, which is global
8437 // state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index
8438 // will be altered by the time we leave the `ɵɵadvance` instruction.
8439 setSelectedIndex(index);
8440}
8441
8442/**
8443 * @license
8444 * Copyright Google LLC All Rights Reserved.
8445 *
8446 * Use of this source code is governed by an MIT-style license that can be
8447 * found in the LICENSE file at https://angular.io/license
8448 */
8449/**
8450 * THIS FILE CONTAINS CODE WHICH SHOULD BE TREE SHAKEN AND NEVER CALLED FROM PRODUCTION CODE!!!
8451 */
8452/**
8453 * Creates an `Array` construction with a given name. This is useful when
8454 * looking for memory consumption to see what time of array it is.
8455 *
8456 *
8457 * @param name Name to give to the constructor
8458 * @returns A subclass of `Array` if possible. This can only be done in
8459 * environments which support `class` construct.
8460 */
8461function createNamedArrayType(name) {
8462 // This should never be called in prod mode, so let's verify that is the case.
8463 if (ngDevMode) {
8464 try {
8465 // If this function were compromised the following could lead to arbitrary
8466 // script execution. We bless it with Trusted Types anyway since this
8467 // function is stripped out of production binaries.
8468 return (newTrustedFunctionForDev('Array', `return class ${name} extends Array{}`))(Array);
8469 }
8470 catch (e) {
8471 // If it does not work just give up and fall back to regular Array.
8472 return Array;
8473 }
8474 }
8475 else {
8476 throw new Error('Looks like we are in \'prod mode\', but we are creating a named Array type, which is wrong! Check your code');
8477 }
8478}
8479
8480/**
8481 * @license
8482 * Copyright Google LLC All Rights Reserved.
8483 *
8484 * Use of this source code is governed by an MIT-style license that can be
8485 * found in the LICENSE file at https://angular.io/license
8486 */
8487function toTStylingRange(prev, next) {
8488 ngDevMode && assertNumberInRange(prev, 0, 32767 /* UNSIGNED_MASK */);
8489 ngDevMode && assertNumberInRange(next, 0, 32767 /* UNSIGNED_MASK */);
8490 return (prev << 17 /* PREV_SHIFT */ | next << 2 /* NEXT_SHIFT */);
8491}
8492function getTStylingRangePrev(tStylingRange) {
8493 ngDevMode && assertNumber(tStylingRange, 'expected number');
8494 return (tStylingRange >> 17 /* PREV_SHIFT */) & 32767 /* UNSIGNED_MASK */;
8495}
8496function getTStylingRangePrevDuplicate(tStylingRange) {
8497 ngDevMode && assertNumber(tStylingRange, 'expected number');
8498 return (tStylingRange & 2 /* PREV_DUPLICATE */) ==
8499 2 /* PREV_DUPLICATE */;
8500}
8501function setTStylingRangePrev(tStylingRange, previous) {
8502 ngDevMode && assertNumber(tStylingRange, 'expected number');
8503 ngDevMode && assertNumberInRange(previous, 0, 32767 /* UNSIGNED_MASK */);
8504 return ((tStylingRange & ~4294836224 /* PREV_MASK */) |
8505 (previous << 17 /* PREV_SHIFT */));
8506}
8507function setTStylingRangePrevDuplicate(tStylingRange) {
8508 ngDevMode && assertNumber(tStylingRange, 'expected number');
8509 return (tStylingRange | 2 /* PREV_DUPLICATE */);
8510}
8511function getTStylingRangeNext(tStylingRange) {
8512 ngDevMode && assertNumber(tStylingRange, 'expected number');
8513 return (tStylingRange & 131068 /* NEXT_MASK */) >> 2 /* NEXT_SHIFT */;
8514}
8515function setTStylingRangeNext(tStylingRange, next) {
8516 ngDevMode && assertNumber(tStylingRange, 'expected number');
8517 ngDevMode && assertNumberInRange(next, 0, 32767 /* UNSIGNED_MASK */);
8518 return ((tStylingRange & ~131068 /* NEXT_MASK */) | //
8519 next << 2 /* NEXT_SHIFT */);
8520}
8521function getTStylingRangeNextDuplicate(tStylingRange) {
8522 ngDevMode && assertNumber(tStylingRange, 'expected number');
8523 return (tStylingRange & 1 /* NEXT_DUPLICATE */) ===
8524 1 /* NEXT_DUPLICATE */;
8525}
8526function setTStylingRangeNextDuplicate(tStylingRange) {
8527 ngDevMode && assertNumber(tStylingRange, 'expected number');
8528 return (tStylingRange | 1 /* NEXT_DUPLICATE */);
8529}
8530function getTStylingRangeTail(tStylingRange) {
8531 ngDevMode && assertNumber(tStylingRange, 'expected number');
8532 const next = getTStylingRangeNext(tStylingRange);
8533 return next === 0 ? getTStylingRangePrev(tStylingRange) : next;
8534}
8535
8536/**
8537 * @license
8538 * Copyright Google LLC All Rights Reserved.
8539 *
8540 * Use of this source code is governed by an MIT-style license that can be
8541 * found in the LICENSE file at https://angular.io/license
8542 */
8543/**
8544 * Patch a `debug` property on top of the existing object.
8545 *
8546 * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
8547 *
8548 * @param obj Object to patch
8549 * @param debug Value to patch
8550 */
8551function attachDebugObject(obj, debug) {
8552 if (ngDevMode) {
8553 Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
8554 }
8555 else {
8556 throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
8557 }
8558}
8559/**
8560 * Patch a `debug` property getter on top of the existing object.
8561 *
8562 * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
8563 *
8564 * @param obj Object to patch
8565 * @param debugGetter Getter returning a value to patch
8566 */
8567function attachDebugGetter(obj, debugGetter) {
8568 if (ngDevMode) {
8569 Object.defineProperty(obj, 'debug', { get: debugGetter, enumerable: false });
8570 }
8571 else {
8572 throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
8573 }
8574}
8575
8576/**
8577 * @license
8578 * Copyright Google LLC All Rights Reserved.
8579 *
8580 * Use of this source code is governed by an MIT-style license that can be
8581 * found in the LICENSE file at https://angular.io/license
8582 */
8583/*
8584 * This file contains conditionally attached classes which provide human readable (debug) level
8585 * information for `LView`, `LContainer` and other internal data structures. These data structures
8586 * are stored internally as array which makes it very difficult during debugging to reason about the
8587 * current state of the system.
8588 *
8589 * Patching the array with extra property does change the array's hidden class' but it does not
8590 * change the cost of access, therefore this patching should not have significant if any impact in
8591 * `ngDevMode` mode. (see: https://jsperf.com/array-vs-monkey-patch-array)
8592 *
8593 * So instead of seeing:
8594 * ```
8595 * Array(30) [Object, 659, null, …]
8596 * ```
8597 *
8598 * You get to see:
8599 * ```
8600 * LViewDebug {
8601 * views: [...],
8602 * flags: {attached: true, ...}
8603 * nodes: [
8604 * {html: '<div id="123">', ..., nodes: [
8605 * {html: '<span>', ..., nodes: null}
8606 * ]}
8607 * ]
8608 * }
8609 * ```
8610 */
8611let LVIEW_COMPONENT_CACHE;
8612let LVIEW_EMBEDDED_CACHE;
8613let LVIEW_ROOT;
8614let LVIEW_COMPONENT;
8615let LVIEW_EMBEDDED;
8616/**
8617 * This function clones a blueprint and creates LView.
8618 *
8619 * Simple slice will keep the same type, and we need it to be LView
8620 */
8621function cloneToLViewFromTViewBlueprint(tView) {
8622 const debugTView = tView;
8623 const lView = getLViewToClone(debugTView.type, tView.template && tView.template.name);
8624 return lView.concat(tView.blueprint);
8625}
8626class LRootView extends Array {
8627}
8628class LComponentView extends Array {
8629}
8630class LEmbeddedView extends Array {
8631}
8632function getLViewToClone(type, name) {
8633 switch (type) {
8634 case 0 /* Root */:
8635 if (LVIEW_ROOT === undefined)
8636 LVIEW_ROOT = new LRootView();
8637 return LVIEW_ROOT;
8638 case 1 /* Component */:
8639 if (!ngDevMode || !ngDevMode.namedConstructors) {
8640 if (LVIEW_COMPONENT === undefined)
8641 LVIEW_COMPONENT = new LComponentView();
8642 return LVIEW_COMPONENT;
8643 }
8644 if (LVIEW_COMPONENT_CACHE === undefined)
8645 LVIEW_COMPONENT_CACHE = new Map();
8646 let componentArray = LVIEW_COMPONENT_CACHE.get(name);
8647 if (componentArray === undefined) {
8648 componentArray = new (createNamedArrayType('LComponentView' + nameSuffix(name)))();
8649 LVIEW_COMPONENT_CACHE.set(name, componentArray);
8650 }
8651 return componentArray;
8652 case 2 /* Embedded */:
8653 if (!ngDevMode || !ngDevMode.namedConstructors) {
8654 if (LVIEW_EMBEDDED === undefined)
8655 LVIEW_EMBEDDED = new LEmbeddedView();
8656 return LVIEW_EMBEDDED;
8657 }
8658 if (LVIEW_EMBEDDED_CACHE === undefined)
8659 LVIEW_EMBEDDED_CACHE = new Map();
8660 let embeddedArray = LVIEW_EMBEDDED_CACHE.get(name);
8661 if (embeddedArray === undefined) {
8662 embeddedArray = new (createNamedArrayType('LEmbeddedView' + nameSuffix(name)))();
8663 LVIEW_EMBEDDED_CACHE.set(name, embeddedArray);
8664 }
8665 return embeddedArray;
8666 }
8667}
8668function nameSuffix(text) {
8669 if (text == null)
8670 return '';
8671 const index = text.lastIndexOf('_Template');
8672 return '_' + (index === -1 ? text : text.substr(0, index));
8673}
8674/**
8675 * This class is a debug version of Object literal so that we can have constructor name show up
8676 * in
8677 * debug tools in ngDevMode.
8678 */
8679const TViewConstructor = class TView {
8680 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) {
8681 this.type = type;
8682 this.blueprint = blueprint;
8683 this.template = template;
8684 this.queries = queries;
8685 this.viewQuery = viewQuery;
8686 this.declTNode = declTNode;
8687 this.data = data;
8688 this.bindingStartIndex = bindingStartIndex;
8689 this.expandoStartIndex = expandoStartIndex;
8690 this.hostBindingOpCodes = hostBindingOpCodes;
8691 this.firstCreatePass = firstCreatePass;
8692 this.firstUpdatePass = firstUpdatePass;
8693 this.staticViewQueries = staticViewQueries;
8694 this.staticContentQueries = staticContentQueries;
8695 this.preOrderHooks = preOrderHooks;
8696 this.preOrderCheckHooks = preOrderCheckHooks;
8697 this.contentHooks = contentHooks;
8698 this.contentCheckHooks = contentCheckHooks;
8699 this.viewHooks = viewHooks;
8700 this.viewCheckHooks = viewCheckHooks;
8701 this.destroyHooks = destroyHooks;
8702 this.cleanup = cleanup;
8703 this.contentQueries = contentQueries;
8704 this.components = components;
8705 this.directiveRegistry = directiveRegistry;
8706 this.pipeRegistry = pipeRegistry;
8707 this.firstChild = firstChild;
8708 this.schemas = schemas;
8709 this.consts = consts;
8710 this.incompleteFirstPass = incompleteFirstPass;
8711 this._decls = _decls;
8712 this._vars = _vars;
8713 }
8714 get template_() {
8715 const buf = [];
8716 processTNodeChildren(this.firstChild, buf);
8717 return buf.join('');
8718 }
8719 get type_() {
8720 return TViewTypeAsString[this.type] || `TViewType.?${this.type}?`;
8721 }
8722};
8723class TNode {
8724 constructor(tView_, //
8725 type, //
8726 index, //
8727 insertBeforeIndex, //
8728 injectorIndex, //
8729 directiveStart, //
8730 directiveEnd, //
8731 directiveStylingLast, //
8732 propertyBindings, //
8733 flags, //
8734 providerIndexes, //
8735 value, //
8736 attrs, //
8737 mergedAttrs, //
8738 localNames, //
8739 initialInputs, //
8740 inputs, //
8741 outputs, //
8742 tViews, //
8743 next, //
8744 projectionNext, //
8745 child, //
8746 parent, //
8747 projection, //
8748 styles, //
8749 stylesWithoutHost, //
8750 residualStyles, //
8751 classes, //
8752 classesWithoutHost, //
8753 residualClasses, //
8754 classBindings, //
8755 styleBindings) {
8756 this.tView_ = tView_;
8757 this.type = type;
8758 this.index = index;
8759 this.insertBeforeIndex = insertBeforeIndex;
8760 this.injectorIndex = injectorIndex;
8761 this.directiveStart = directiveStart;
8762 this.directiveEnd = directiveEnd;
8763 this.directiveStylingLast = directiveStylingLast;
8764 this.propertyBindings = propertyBindings;
8765 this.flags = flags;
8766 this.providerIndexes = providerIndexes;
8767 this.value = value;
8768 this.attrs = attrs;
8769 this.mergedAttrs = mergedAttrs;
8770 this.localNames = localNames;
8771 this.initialInputs = initialInputs;
8772 this.inputs = inputs;
8773 this.outputs = outputs;
8774 this.tViews = tViews;
8775 this.next = next;
8776 this.projectionNext = projectionNext;
8777 this.child = child;
8778 this.parent = parent;
8779 this.projection = projection;
8780 this.styles = styles;
8781 this.stylesWithoutHost = stylesWithoutHost;
8782 this.residualStyles = residualStyles;
8783 this.classes = classes;
8784 this.classesWithoutHost = classesWithoutHost;
8785 this.residualClasses = residualClasses;
8786 this.classBindings = classBindings;
8787 this.styleBindings = styleBindings;
8788 }
8789 /**
8790 * Return a human debug version of the set of `NodeInjector`s which will be consulted when
8791 * resolving tokens from this `TNode`.
8792 *
8793 * When debugging applications, it is often difficult to determine which `NodeInjector`s will be
8794 * consulted. This method shows a list of `DebugNode`s representing the `TNode`s which will be
8795 * consulted in order when resolving a token starting at this `TNode`.
8796 *
8797 * The original data is stored in `LView` and `TView` with a lot of offset indexes, and so it is
8798 * difficult to reason about.
8799 *
8800 * @param lView The `LView` instance for this `TNode`.
8801 */
8802 debugNodeInjectorPath(lView) {
8803 const path = [];
8804 let injectorIndex = getInjectorIndex(this, lView);
8805 if (injectorIndex === -1) {
8806 // Looks like the current `TNode` does not have `NodeInjector` associated with it => look for
8807 // parent NodeInjector.
8808 const parentLocation = getParentInjectorLocation(this, lView);
8809 if (parentLocation !== NO_PARENT_INJECTOR) {
8810 // We found a parent, so start searching from the parent location.
8811 injectorIndex = getParentInjectorIndex(parentLocation);
8812 lView = getParentInjectorView(parentLocation, lView);
8813 }
8814 else {
8815 // No parents have been found, so there are no `NodeInjector`s to consult.
8816 }
8817 }
8818 while (injectorIndex !== -1) {
8819 ngDevMode && assertNodeInjector(lView, injectorIndex);
8820 const tNode = lView[TVIEW].data[injectorIndex + 8 /* TNODE */];
8821 path.push(buildDebugNode(tNode, lView));
8822 const parentLocation = lView[injectorIndex + 8 /* PARENT */];
8823 if (parentLocation === NO_PARENT_INJECTOR) {
8824 injectorIndex = -1;
8825 }
8826 else {
8827 injectorIndex = getParentInjectorIndex(parentLocation);
8828 lView = getParentInjectorView(parentLocation, lView);
8829 }
8830 }
8831 return path;
8832 }
8833 get type_() {
8834 return toTNodeTypeAsString(this.type) || `TNodeType.?${this.type}?`;
8835 }
8836 get flags_() {
8837 const flags = [];
8838 if (this.flags & 16 /* hasClassInput */)
8839 flags.push('TNodeFlags.hasClassInput');
8840 if (this.flags & 8 /* hasContentQuery */)
8841 flags.push('TNodeFlags.hasContentQuery');
8842 if (this.flags & 32 /* hasStyleInput */)
8843 flags.push('TNodeFlags.hasStyleInput');
8844 if (this.flags & 128 /* hasHostBindings */)
8845 flags.push('TNodeFlags.hasHostBindings');
8846 if (this.flags & 2 /* isComponentHost */)
8847 flags.push('TNodeFlags.isComponentHost');
8848 if (this.flags & 1 /* isDirectiveHost */)
8849 flags.push('TNodeFlags.isDirectiveHost');
8850 if (this.flags & 64 /* isDetached */)
8851 flags.push('TNodeFlags.isDetached');
8852 if (this.flags & 4 /* isProjected */)
8853 flags.push('TNodeFlags.isProjected');
8854 return flags.join('|');
8855 }
8856 get template_() {
8857 if (this.type & 1 /* Text */)
8858 return this.value;
8859 const buf = [];
8860 const tagName = typeof this.value === 'string' && this.value || this.type_;
8861 buf.push('<', tagName);
8862 if (this.flags) {
8863 buf.push(' ', this.flags_);
8864 }
8865 if (this.attrs) {
8866 for (let i = 0; i < this.attrs.length;) {
8867 const attrName = this.attrs[i++];
8868 if (typeof attrName == 'number') {
8869 break;
8870 }
8871 const attrValue = this.attrs[i++];
8872 buf.push(' ', attrName, '="', attrValue, '"');
8873 }
8874 }
8875 buf.push('>');
8876 processTNodeChildren(this.child, buf);
8877 buf.push('</', tagName, '>');
8878 return buf.join('');
8879 }
8880 get styleBindings_() {
8881 return toDebugStyleBinding(this, false);
8882 }
8883 get classBindings_() {
8884 return toDebugStyleBinding(this, true);
8885 }
8886 get providerIndexStart_() {
8887 return this.providerIndexes & 1048575 /* ProvidersStartIndexMask */;
8888 }
8889 get providerIndexEnd_() {
8890 return this.providerIndexStart_ +
8891 (this.providerIndexes >>> 20 /* CptViewProvidersCountShift */);
8892 }
8893}
8894const TNodeDebug = TNode;
8895function toDebugStyleBinding(tNode, isClassBased) {
8896 const tData = tNode.tView_.data;
8897 const bindings = [];
8898 const range = isClassBased ? tNode.classBindings : tNode.styleBindings;
8899 const prev = getTStylingRangePrev(range);
8900 const next = getTStylingRangeNext(range);
8901 let isTemplate = next !== 0;
8902 let cursor = isTemplate ? next : prev;
8903 while (cursor !== 0) {
8904 const itemKey = tData[cursor];
8905 const itemRange = tData[cursor + 1];
8906 bindings.unshift({
8907 key: itemKey,
8908 index: cursor,
8909 isTemplate: isTemplate,
8910 prevDuplicate: getTStylingRangePrevDuplicate(itemRange),
8911 nextDuplicate: getTStylingRangeNextDuplicate(itemRange),
8912 nextIndex: getTStylingRangeNext(itemRange),
8913 prevIndex: getTStylingRangePrev(itemRange),
8914 });
8915 if (cursor === prev)
8916 isTemplate = false;
8917 cursor = getTStylingRangePrev(itemRange);
8918 }
8919 bindings.push((isClassBased ? tNode.residualClasses : tNode.residualStyles) || null);
8920 return bindings;
8921}
8922function processTNodeChildren(tNode, buf) {
8923 while (tNode) {
8924 buf.push(tNode.template_);
8925 tNode = tNode.next;
8926 }
8927}
8928class TViewData extends Array {
8929}
8930let TVIEWDATA_EMPTY; // can't initialize here or it will not be tree shaken, because
8931// `LView` constructor could have side-effects.
8932/**
8933 * This function clones a blueprint and creates TData.
8934 *
8935 * Simple slice will keep the same type, and we need it to be TData
8936 */
8937function cloneToTViewData(list) {
8938 if (TVIEWDATA_EMPTY === undefined)
8939 TVIEWDATA_EMPTY = new TViewData();
8940 return TVIEWDATA_EMPTY.concat(list);
8941}
8942class LViewBlueprint extends Array {
8943}
8944class MatchesArray extends Array {
8945}
8946class TViewComponents extends Array {
8947}
8948class TNodeLocalNames extends Array {
8949}
8950class TNodeInitialInputs extends Array {
8951}
8952class LCleanup extends Array {
8953}
8954class TCleanup extends Array {
8955}
8956function attachLViewDebug(lView) {
8957 attachDebugObject(lView, new LViewDebug(lView));
8958}
8959function attachLContainerDebug(lContainer) {
8960 attachDebugObject(lContainer, new LContainerDebug(lContainer));
8961}
8962function toDebug(obj) {
8963 if (obj) {
8964 const debug = obj.debug;
8965 assertDefined(debug, 'Object does not have a debug representation.');
8966 return debug;
8967 }
8968 else {
8969 return obj;
8970 }
8971}
8972/**
8973 * Use this method to unwrap a native element in `LView` and convert it into HTML for easier
8974 * reading.
8975 *
8976 * @param value possibly wrapped native DOM node.
8977 * @param includeChildren If `true` then the serialized HTML form will include child elements
8978 * (same
8979 * as `outerHTML`). If `false` then the serialized HTML form will only contain the element
8980 * itself
8981 * (will not serialize child elements).
8982 */
8983function toHtml(value, includeChildren = false) {
8984 const node = unwrapRNode(value);
8985 if (node) {
8986 switch (node.nodeType) {
8987 case Node.TEXT_NODE:
8988 return node.textContent;
8989 case Node.COMMENT_NODE:
8990 return `<!--${node.textContent}-->`;
8991 case Node.ELEMENT_NODE:
8992 const outerHTML = node.outerHTML;
8993 if (includeChildren) {
8994 return outerHTML;
8995 }
8996 else {
8997 const innerHTML = '>' + node.innerHTML + '<';
8998 return (outerHTML.split(innerHTML)[0]) + '>';
8999 }
9000 }
9001 }
9002 return null;
9003}
9004class LViewDebug {
9005 constructor(_raw_lView) {
9006 this._raw_lView = _raw_lView;
9007 }
9008 /**
9009 * Flags associated with the `LView` unpacked into a more readable state.
9010 */
9011 get flags() {
9012 const flags = this._raw_lView[FLAGS];
9013 return {
9014 __raw__flags__: flags,
9015 initPhaseState: flags & 3 /* InitPhaseStateMask */,
9016 creationMode: !!(flags & 4 /* CreationMode */),
9017 firstViewPass: !!(flags & 8 /* FirstLViewPass */),
9018 checkAlways: !!(flags & 16 /* CheckAlways */),
9019 dirty: !!(flags & 64 /* Dirty */),
9020 attached: !!(flags & 128 /* Attached */),
9021 destroyed: !!(flags & 256 /* Destroyed */),
9022 isRoot: !!(flags & 512 /* IsRoot */),
9023 indexWithinInitPhase: flags >> 11 /* IndexWithinInitPhaseShift */,
9024 };
9025 }
9026 get parent() {
9027 return toDebug(this._raw_lView[PARENT]);
9028 }
9029 get hostHTML() {
9030 return toHtml(this._raw_lView[HOST], true);
9031 }
9032 get html() {
9033 return (this.nodes || []).map(mapToHTML).join('');
9034 }
9035 get context() {
9036 return this._raw_lView[CONTEXT];
9037 }
9038 /**
9039 * The tree of nodes associated with the current `LView`. The nodes have been normalized into
9040 * a tree structure with relevant details pulled out for readability.
9041 */
9042 get nodes() {
9043 const lView = this._raw_lView;
9044 const tNode = lView[TVIEW].firstChild;
9045 return toDebugNodes(tNode, lView);
9046 }
9047 get template() {
9048 return this.tView.template_;
9049 }
9050 get tView() {
9051 return this._raw_lView[TVIEW];
9052 }
9053 get cleanup() {
9054 return this._raw_lView[CLEANUP];
9055 }
9056 get injector() {
9057 return this._raw_lView[INJECTOR$1];
9058 }
9059 get rendererFactory() {
9060 return this._raw_lView[RENDERER_FACTORY];
9061 }
9062 get renderer() {
9063 return this._raw_lView[RENDERER];
9064 }
9065 get sanitizer() {
9066 return this._raw_lView[SANITIZER];
9067 }
9068 get childHead() {
9069 return toDebug(this._raw_lView[CHILD_HEAD]);
9070 }
9071 get next() {
9072 return toDebug(this._raw_lView[NEXT]);
9073 }
9074 get childTail() {
9075 return toDebug(this._raw_lView[CHILD_TAIL]);
9076 }
9077 get declarationView() {
9078 return toDebug(this._raw_lView[DECLARATION_VIEW]);
9079 }
9080 get queries() {
9081 return this._raw_lView[QUERIES];
9082 }
9083 get tHost() {
9084 return this._raw_lView[T_HOST];
9085 }
9086 get decls() {
9087 return toLViewRange(this.tView, this._raw_lView, HEADER_OFFSET, this.tView.bindingStartIndex);
9088 }
9089 get vars() {
9090 return toLViewRange(this.tView, this._raw_lView, this.tView.bindingStartIndex, this.tView.expandoStartIndex);
9091 }
9092 get expando() {
9093 return toLViewRange(this.tView, this._raw_lView, this.tView.expandoStartIndex, this._raw_lView.length);
9094 }
9095 /**
9096 * Normalized view of child views (and containers) attached at this location.
9097 */
9098 get childViews() {
9099 const childViews = [];
9100 let child = this.childHead;
9101 while (child) {
9102 childViews.push(child);
9103 child = child.next;
9104 }
9105 return childViews;
9106 }
9107}
9108function mapToHTML(node) {
9109 if (node.type === 'ElementContainer') {
9110 return (node.children || []).map(mapToHTML).join('');
9111 }
9112 else if (node.type === 'IcuContainer') {
9113 throw new Error('Not implemented');
9114 }
9115 else {
9116 return toHtml(node.native, true) || '';
9117 }
9118}
9119function toLViewRange(tView, lView, start, end) {
9120 let content = [];
9121 for (let index = start; index < end; index++) {
9122 content.push({ index: index, t: tView.data[index], l: lView[index] });
9123 }
9124 return { start: start, end: end, length: end - start, content: content };
9125}
9126/**
9127 * Turns a flat list of nodes into a tree by walking the associated `TNode` tree.
9128 *
9129 * @param tNode
9130 * @param lView
9131 */
9132function toDebugNodes(tNode, lView) {
9133 if (tNode) {
9134 const debugNodes = [];
9135 let tNodeCursor = tNode;
9136 while (tNodeCursor) {
9137 debugNodes.push(buildDebugNode(tNodeCursor, lView));
9138 tNodeCursor = tNodeCursor.next;
9139 }
9140 return debugNodes;
9141 }
9142 else {
9143 return [];
9144 }
9145}
9146function buildDebugNode(tNode, lView) {
9147 const rawValue = lView[tNode.index];
9148 const native = unwrapRNode(rawValue);
9149 const factories = [];
9150 const instances = [];
9151 const tView = lView[TVIEW];
9152 for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
9153 const def = tView.data[i];
9154 factories.push(def.type);
9155 instances.push(lView[i]);
9156 }
9157 return {
9158 html: toHtml(native),
9159 type: toTNodeTypeAsString(tNode.type),
9160 tNode,
9161 native: native,
9162 children: toDebugNodes(tNode.child, lView),
9163 factories,
9164 instances,
9165 injector: buildNodeInjectorDebug(tNode, tView, lView),
9166 get injectorResolutionPath() {
9167 return tNode.debugNodeInjectorPath(lView);
9168 },
9169 };
9170}
9171function buildNodeInjectorDebug(tNode, tView, lView) {
9172 const viewProviders = [];
9173 for (let i = tNode.providerIndexStart_; i < tNode.providerIndexEnd_; i++) {
9174 viewProviders.push(tView.data[i]);
9175 }
9176 const providers = [];
9177 for (let i = tNode.providerIndexEnd_; i < tNode.directiveEnd; i++) {
9178 providers.push(tView.data[i]);
9179 }
9180 const nodeInjectorDebug = {
9181 bloom: toBloom(lView, tNode.injectorIndex),
9182 cumulativeBloom: toBloom(tView.data, tNode.injectorIndex),
9183 providers,
9184 viewProviders,
9185 parentInjectorIndex: lView[tNode.providerIndexStart_ - 1],
9186 };
9187 return nodeInjectorDebug;
9188}
9189/**
9190 * Convert a number at `idx` location in `array` into binary representation.
9191 *
9192 * @param array
9193 * @param idx
9194 */
9195function binary(array, idx) {
9196 const value = array[idx];
9197 // If not a number we print 8 `?` to retain alignment but let user know that it was called on
9198 // wrong type.
9199 if (typeof value !== 'number')
9200 return '????????';
9201 // We prefix 0s so that we have constant length number
9202 const text = '00000000' + value.toString(2);
9203 return text.substring(text.length - 8);
9204}
9205/**
9206 * Convert a bloom filter at location `idx` in `array` into binary representation.
9207 *
9208 * @param array
9209 * @param idx
9210 */
9211function toBloom(array, idx) {
9212 if (idx < 0) {
9213 return 'NO_NODE_INJECTOR';
9214 }
9215 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)}`;
9216}
9217class LContainerDebug {
9218 constructor(_raw_lContainer) {
9219 this._raw_lContainer = _raw_lContainer;
9220 }
9221 get hasTransplantedViews() {
9222 return this._raw_lContainer[HAS_TRANSPLANTED_VIEWS];
9223 }
9224 get views() {
9225 return this._raw_lContainer.slice(CONTAINER_HEADER_OFFSET)
9226 .map(toDebug);
9227 }
9228 get parent() {
9229 return toDebug(this._raw_lContainer[PARENT]);
9230 }
9231 get movedViews() {
9232 return this._raw_lContainer[MOVED_VIEWS];
9233 }
9234 get host() {
9235 return this._raw_lContainer[HOST];
9236 }
9237 get native() {
9238 return this._raw_lContainer[NATIVE];
9239 }
9240 get next() {
9241 return toDebug(this._raw_lContainer[NEXT]);
9242 }
9243}
9244
9245/**
9246 * A permanent marker promise which signifies that the current CD tree is
9247 * clean.
9248 */
9249const _CLEAN_PROMISE = (() => Promise.resolve(null))();
9250/**
9251 * Invoke `HostBindingsFunction`s for view.
9252 *
9253 * This methods executes `TView.hostBindingOpCodes`. It is used to execute the
9254 * `HostBindingsFunction`s associated with the current `LView`.
9255 *
9256 * @param tView Current `TView`.
9257 * @param lView Current `LView`.
9258 */
9259function processHostBindingOpCodes(tView, lView) {
9260 const hostBindingOpCodes = tView.hostBindingOpCodes;
9261 if (hostBindingOpCodes === null)
9262 return;
9263 try {
9264 for (let i = 0; i < hostBindingOpCodes.length; i++) {
9265 const opCode = hostBindingOpCodes[i];
9266 if (opCode < 0) {
9267 // Negative numbers are element indexes.
9268 setSelectedIndex(~opCode);
9269 }
9270 else {
9271 // Positive numbers are NumberTuple which store bindingRootIndex and directiveIndex.
9272 const directiveIdx = opCode;
9273 const bindingRootIndx = hostBindingOpCodes[++i];
9274 const hostBindingFn = hostBindingOpCodes[++i];
9275 setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
9276 const context = lView[directiveIdx];
9277 hostBindingFn(2 /* Update */, context);
9278 }
9279 }
9280 }
9281 finally {
9282 setSelectedIndex(-1);
9283 }
9284}
9285/** Refreshes all content queries declared by directives in a given view */
9286function refreshContentQueries(tView, lView) {
9287 const contentQueries = tView.contentQueries;
9288 if (contentQueries !== null) {
9289 for (let i = 0; i < contentQueries.length; i += 2) {
9290 const queryStartIdx = contentQueries[i];
9291 const directiveDefIdx = contentQueries[i + 1];
9292 if (directiveDefIdx !== -1) {
9293 const directiveDef = tView.data[directiveDefIdx];
9294 ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
9295 ngDevMode &&
9296 assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
9297 setCurrentQueryIndex(queryStartIdx);
9298 directiveDef.contentQueries(2 /* Update */, lView[directiveDefIdx], directiveDefIdx);
9299 }
9300 }
9301 }
9302}
9303/** Refreshes child components in the current view (update mode). */
9304function refreshChildComponents(hostLView, components) {
9305 for (let i = 0; i < components.length; i++) {
9306 refreshComponent(hostLView, components[i]);
9307 }
9308}
9309/** Renders child components in the current view (creation mode). */
9310function renderChildComponents(hostLView, components) {
9311 for (let i = 0; i < components.length; i++) {
9312 renderComponent$1(hostLView, components[i]);
9313 }
9314}
9315function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector) {
9316 const lView = ngDevMode ? cloneToLViewFromTViewBlueprint(tView) : tView.blueprint.slice();
9317 lView[HOST] = host;
9318 lView[FLAGS] = flags | 4 /* CreationMode */ | 128 /* Attached */ | 8 /* FirstLViewPass */;
9319 resetPreOrderHookFlags(lView);
9320 ngDevMode && tView.declTNode && parentLView && assertTNodeForLView(tView.declTNode, parentLView);
9321 lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
9322 lView[CONTEXT] = context;
9323 lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]);
9324 ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required');
9325 lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]);
9326 ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required');
9327 lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null;
9328 lView[INJECTOR$1] = injector || parentLView && parentLView[INJECTOR$1] || null;
9329 lView[T_HOST] = tHostNode;
9330 ngDevMode &&
9331 assertEqual(tView.type == 2 /* Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
9332 lView[DECLARATION_COMPONENT_VIEW] =
9333 tView.type == 2 /* Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
9334 ngDevMode && attachLViewDebug(lView);
9335 return lView;
9336}
9337function getOrCreateTNode(tView, index, type, name, attrs) {
9338 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
9339 // `view_engine_compatibility` for additional context.
9340 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
9341 // Keep this function short, so that the VM will inline it.
9342 ngDevMode && assertPureTNodeType(type);
9343 let tNode = tView.data[index];
9344 if (tNode === null) {
9345 tNode = createTNodeAtIndex(tView, index, type, name, attrs);
9346 if (isInI18nBlock()) {
9347 // If we are in i18n block then all elements should be pre declared through `Placeholder`
9348 // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
9349 // If the `TNode` was not pre-declared than it means it was not mentioned which means it was
9350 // removed, so we mark it as detached.
9351 tNode.flags |= 64 /* isDetached */;
9352 }
9353 }
9354 else if (tNode.type & 64 /* Placeholder */) {
9355 tNode.type = type;
9356 tNode.value = name;
9357 tNode.attrs = attrs;
9358 const parent = getCurrentParentTNode();
9359 tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex;
9360 ngDevMode && assertTNodeForTView(tNode, tView);
9361 ngDevMode && assertEqual(index, tNode.index, 'Expecting same index');
9362 }
9363 setCurrentTNode(tNode, true);
9364 return tNode;
9365}
9366function createTNodeAtIndex(tView, index, type, name, attrs) {
9367 const currentTNode = getCurrentTNodePlaceholderOk();
9368 const isParent = isCurrentTNodeParent();
9369 const parent = isParent ? currentTNode : currentTNode && currentTNode.parent;
9370 // Parents cannot cross component boundaries because components will be used in multiple places.
9371 const tNode = tView.data[index] =
9372 createTNode(tView, parent, type, index, name, attrs);
9373 // Assign a pointer to the first child node of a given view. The first node is not always the one
9374 // at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
9375 // the index 1 or more, so we can't just check node index.
9376 if (tView.firstChild === null) {
9377 tView.firstChild = tNode;
9378 }
9379 if (currentTNode !== null) {
9380 if (isParent) {
9381 // FIXME(misko): This logic looks unnecessarily complicated. Could we simplify?
9382 if (currentTNode.child == null && tNode.parent !== null) {
9383 // We are in the same view, which means we are adding content node to the parent view.
9384 currentTNode.child = tNode;
9385 }
9386 }
9387 else {
9388 if (currentTNode.next === null) {
9389 // In the case of i18n the `currentTNode` may already be linked, in which case we don't want
9390 // to break the links which i18n created.
9391 currentTNode.next = tNode;
9392 }
9393 }
9394 }
9395 return tNode;
9396}
9397/**
9398 * When elements are created dynamically after a view blueprint is created (e.g. through
9399 * i18nApply()), we need to adjust the blueprint for future
9400 * template passes.
9401 *
9402 * @param tView `TView` associated with `LView`
9403 * @param lView The `LView` containing the blueprint to adjust
9404 * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
9405 * @param initialValue Initial value to store in blueprint
9406 */
9407function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
9408 if (numSlotsToAlloc === 0)
9409 return -1;
9410 if (ngDevMode) {
9411 assertFirstCreatePass(tView);
9412 assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
9413 assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
9414 assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
9415 assertFirstUpdatePass(tView);
9416 }
9417 const allocIdx = lView.length;
9418 for (let i = 0; i < numSlotsToAlloc; i++) {
9419 lView.push(initialValue);
9420 tView.blueprint.push(initialValue);
9421 tView.data.push(null);
9422 }
9423 return allocIdx;
9424}
9425//////////////////////////
9426//// Render
9427//////////////////////////
9428/**
9429 * Processes a view in the creation mode. This includes a number of steps in a specific order:
9430 * - creating view query functions (if any);
9431 * - executing a template function in the creation mode;
9432 * - updating static queries (if any);
9433 * - creating child components defined in a given view.
9434 */
9435function renderView(tView, lView, context) {
9436 ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
9437 enterView(lView);
9438 try {
9439 const viewQuery = tView.viewQuery;
9440 if (viewQuery !== null) {
9441 executeViewQueryFn(1 /* Create */, viewQuery, context);
9442 }
9443 // Execute a template associated with this view, if it exists. A template function might not be
9444 // defined for the root component views.
9445 const templateFn = tView.template;
9446 if (templateFn !== null) {
9447 executeTemplate(tView, lView, templateFn, 1 /* Create */, context);
9448 }
9449 // This needs to be set before children are processed to support recursive components.
9450 // This must be set to false immediately after the first creation run because in an
9451 // ngFor loop, all the views will be created together before update mode runs and turns
9452 // off firstCreatePass. If we don't set it here, instances will perform directive
9453 // matching, etc again and again.
9454 if (tView.firstCreatePass) {
9455 tView.firstCreatePass = false;
9456 }
9457 // We resolve content queries specifically marked as `static` in creation mode. Dynamic
9458 // content queries are resolved during change detection (i.e. update mode), after embedded
9459 // views are refreshed (see block above).
9460 if (tView.staticContentQueries) {
9461 refreshContentQueries(tView, lView);
9462 }
9463 // We must materialize query results before child components are processed
9464 // in case a child component has projected a container. The LContainer needs
9465 // to exist so the embedded views are properly attached by the container.
9466 if (tView.staticViewQueries) {
9467 executeViewQueryFn(2 /* Update */, tView.viewQuery, context);
9468 }
9469 // Render child component views.
9470 const components = tView.components;
9471 if (components !== null) {
9472 renderChildComponents(lView, components);
9473 }
9474 }
9475 catch (error) {
9476 // If we didn't manage to get past the first template pass due to
9477 // an error, mark the view as corrupted so we can try to recover.
9478 if (tView.firstCreatePass) {
9479 tView.incompleteFirstPass = true;
9480 tView.firstCreatePass = false;
9481 }
9482 throw error;
9483 }
9484 finally {
9485 lView[FLAGS] &= ~4 /* CreationMode */;
9486 leaveView();
9487 }
9488}
9489/**
9490 * Processes a view in update mode. This includes a number of steps in a specific order:
9491 * - executing a template function in update mode;
9492 * - executing hooks;
9493 * - refreshing queries;
9494 * - setting host bindings;
9495 * - refreshing child (embedded and component) views.
9496 */
9497function refreshView(tView, lView, templateFn, context) {
9498 ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
9499 const flags = lView[FLAGS];
9500 if ((flags & 256 /* Destroyed */) === 256 /* Destroyed */)
9501 return;
9502 enterView(lView);
9503 // Check no changes mode is a dev only mode used to verify that bindings have not changed
9504 // since they were assigned. We do not want to execute lifecycle hooks in that mode.
9505 const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
9506 try {
9507 resetPreOrderHookFlags(lView);
9508 setBindingIndex(tView.bindingStartIndex);
9509 if (templateFn !== null) {
9510 executeTemplate(tView, lView, templateFn, 2 /* Update */, context);
9511 }
9512 const hooksInitPhaseCompleted = (flags & 3 /* InitPhaseStateMask */) === 3 /* InitPhaseCompleted */;
9513 // execute pre-order hooks (OnInit, OnChanges, DoCheck)
9514 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
9515 if (!isInCheckNoChangesPass) {
9516 if (hooksInitPhaseCompleted) {
9517 const preOrderCheckHooks = tView.preOrderCheckHooks;
9518 if (preOrderCheckHooks !== null) {
9519 executeCheckHooks(lView, preOrderCheckHooks, null);
9520 }
9521 }
9522 else {
9523 const preOrderHooks = tView.preOrderHooks;
9524 if (preOrderHooks !== null) {
9525 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* OnInitHooksToBeRun */, null);
9526 }
9527 incrementInitPhaseFlags(lView, 0 /* OnInitHooksToBeRun */);
9528 }
9529 }
9530 // First mark transplanted views that are declared in this lView as needing a refresh at their
9531 // insertion points. This is needed to avoid the situation where the template is defined in this
9532 // `LView` but its declaration appears after the insertion component.
9533 markTransplantedViewsForRefresh(lView);
9534 refreshEmbeddedViews(lView);
9535 // Content query results must be refreshed before content hooks are called.
9536 if (tView.contentQueries !== null) {
9537 refreshContentQueries(tView, lView);
9538 }
9539 // execute content hooks (AfterContentInit, AfterContentChecked)
9540 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
9541 if (!isInCheckNoChangesPass) {
9542 if (hooksInitPhaseCompleted) {
9543 const contentCheckHooks = tView.contentCheckHooks;
9544 if (contentCheckHooks !== null) {
9545 executeCheckHooks(lView, contentCheckHooks);
9546 }
9547 }
9548 else {
9549 const contentHooks = tView.contentHooks;
9550 if (contentHooks !== null) {
9551 executeInitAndCheckHooks(lView, contentHooks, 1 /* AfterContentInitHooksToBeRun */);
9552 }
9553 incrementInitPhaseFlags(lView, 1 /* AfterContentInitHooksToBeRun */);
9554 }
9555 }
9556 processHostBindingOpCodes(tView, lView);
9557 // Refresh child component views.
9558 const components = tView.components;
9559 if (components !== null) {
9560 refreshChildComponents(lView, components);
9561 }
9562 // View queries must execute after refreshing child components because a template in this view
9563 // could be inserted in a child component. If the view query executes before child component
9564 // refresh, the template might not yet be inserted.
9565 const viewQuery = tView.viewQuery;
9566 if (viewQuery !== null) {
9567 executeViewQueryFn(2 /* Update */, viewQuery, context);
9568 }
9569 // execute view hooks (AfterViewInit, AfterViewChecked)
9570 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
9571 if (!isInCheckNoChangesPass) {
9572 if (hooksInitPhaseCompleted) {
9573 const viewCheckHooks = tView.viewCheckHooks;
9574 if (viewCheckHooks !== null) {
9575 executeCheckHooks(lView, viewCheckHooks);
9576 }
9577 }
9578 else {
9579 const viewHooks = tView.viewHooks;
9580 if (viewHooks !== null) {
9581 executeInitAndCheckHooks(lView, viewHooks, 2 /* AfterViewInitHooksToBeRun */);
9582 }
9583 incrementInitPhaseFlags(lView, 2 /* AfterViewInitHooksToBeRun */);
9584 }
9585 }
9586 if (tView.firstUpdatePass === true) {
9587 // We need to make sure that we only flip the flag on successful `refreshView` only
9588 // Don't do this in `finally` block.
9589 // If we did this in `finally` block then an exception could block the execution of styling
9590 // instructions which in turn would be unable to insert themselves into the styling linked
9591 // list. The result of this would be that if the exception would not be throw on subsequent CD
9592 // the styling would be unable to process it data and reflect to the DOM.
9593 tView.firstUpdatePass = false;
9594 }
9595 // Do not reset the dirty state when running in check no changes mode. We don't want components
9596 // to behave differently depending on whether check no changes is enabled or not. For example:
9597 // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
9598 // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
9599 // no changes cycle, the component would be not be dirty for the next update pass. This would
9600 // be different in production mode where the component dirty state is not reset.
9601 if (!isInCheckNoChangesPass) {
9602 lView[FLAGS] &= ~(64 /* Dirty */ | 8 /* FirstLViewPass */);
9603 }
9604 if (lView[FLAGS] & 1024 /* RefreshTransplantedView */) {
9605 lView[FLAGS] &= ~1024 /* RefreshTransplantedView */;
9606 updateTransplantedViewCount(lView[PARENT], -1);
9607 }
9608 }
9609 finally {
9610 leaveView();
9611 }
9612}
9613function renderComponentOrTemplate(tView, lView, templateFn, context) {
9614 const rendererFactory = lView[RENDERER_FACTORY];
9615 // Check no changes mode is a dev only mode used to verify that bindings have not changed
9616 // since they were assigned. We do not want to invoke renderer factory functions in that mode
9617 // to avoid any possible side-effects.
9618 const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
9619 const creationModeIsActive = isCreationMode(lView);
9620 try {
9621 if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.begin) {
9622 rendererFactory.begin();
9623 }
9624 if (creationModeIsActive) {
9625 renderView(tView, lView, context);
9626 }
9627 refreshView(tView, lView, templateFn, context);
9628 }
9629 finally {
9630 if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.end) {
9631 rendererFactory.end();
9632 }
9633 }
9634}
9635function executeTemplate(tView, lView, templateFn, rf, context) {
9636 const prevSelectedIndex = getSelectedIndex();
9637 const isUpdatePhase = rf & 2 /* Update */;
9638 try {
9639 setSelectedIndex(-1);
9640 if (isUpdatePhase && lView.length > HEADER_OFFSET) {
9641 // When we're updating, inherently select 0 so we don't
9642 // have to generate that instruction for most update blocks.
9643 selectIndexInternal(tView, lView, HEADER_OFFSET, !!ngDevMode && isInCheckNoChangesMode());
9644 }
9645 const preHookType = isUpdatePhase ? 2 /* TemplateUpdateStart */ : 0 /* TemplateCreateStart */;
9646 profiler(preHookType, context);
9647 templateFn(rf, context);
9648 }
9649 finally {
9650 setSelectedIndex(prevSelectedIndex);
9651 const postHookType = isUpdatePhase ? 3 /* TemplateUpdateEnd */ : 1 /* TemplateCreateEnd */;
9652 profiler(postHookType, context);
9653 }
9654}
9655//////////////////////////
9656//// Element
9657//////////////////////////
9658function executeContentQueries(tView, tNode, lView) {
9659 if (isContentQueryHost(tNode)) {
9660 const start = tNode.directiveStart;
9661 const end = tNode.directiveEnd;
9662 for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
9663 const def = tView.data[directiveIndex];
9664 if (def.contentQueries) {
9665 def.contentQueries(1 /* Create */, lView[directiveIndex], directiveIndex);
9666 }
9667 }
9668 }
9669}
9670/**
9671 * Creates directive instances.
9672 */
9673function createDirectivesInstances(tView, lView, tNode) {
9674 if (!getBindingsEnabled())
9675 return;
9676 instantiateAllDirectives(tView, lView, tNode, getNativeByTNode(tNode, lView));
9677 if ((tNode.flags & 128 /* hasHostBindings */) === 128 /* hasHostBindings */) {
9678 invokeDirectivesHostBindings(tView, lView, tNode);
9679 }
9680}
9681/**
9682 * Takes a list of local names and indices and pushes the resolved local variable values
9683 * to LView in the same order as they are loaded in the template with load().
9684 */
9685function saveResolvedLocalsInData(viewData, tNode, localRefExtractor = getNativeByTNode) {
9686 const localNames = tNode.localNames;
9687 if (localNames !== null) {
9688 let localIndex = tNode.index + 1;
9689 for (let i = 0; i < localNames.length; i += 2) {
9690 const index = localNames[i + 1];
9691 const value = index === -1 ?
9692 localRefExtractor(tNode, viewData) :
9693 viewData[index];
9694 viewData[localIndex++] = value;
9695 }
9696 }
9697}
9698/**
9699 * Gets TView from a template function or creates a new TView
9700 * if it doesn't already exist.
9701 *
9702 * @param def ComponentDef
9703 * @returns TView
9704 */
9705function getOrCreateTComponentView(def) {
9706 const tView = def.tView;
9707 // Create a TView if there isn't one, or recreate it if the first create pass didn't
9708 // complete successfully since we can't know for sure whether it's in a usable shape.
9709 if (tView === null || tView.incompleteFirstPass) {
9710 // Declaration node here is null since this function is called when we dynamically create a
9711 // component and hence there is no declaration.
9712 const declTNode = null;
9713 return def.tView = createTView(1 /* Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
9714 }
9715 return tView;
9716}
9717/**
9718 * Creates a TView instance
9719 *
9720 * @param type Type of `TView`.
9721 * @param declTNode Declaration location of this `TView`.
9722 * @param templateFn Template function
9723 * @param decls The number of nodes, local refs, and pipes in this template
9724 * @param directives Registry of directives for this view
9725 * @param pipes Registry of pipes for this view
9726 * @param viewQuery View queries for this view
9727 * @param schemas Schemas for this view
9728 * @param consts Constants for this view
9729 */
9730function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
9731 ngDevMode && ngDevMode.tView++;
9732 const bindingStartIndex = HEADER_OFFSET + decls;
9733 // This length does not yet contain host bindings from child directives because at this point,
9734 // we don't know which directives are active on this template. As soon as a directive is matched
9735 // that has a host binding, we will update the blueprint with that def's hostVars count.
9736 const initialViewLength = bindingStartIndex + vars;
9737 const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
9738 const consts = typeof constsOrFactory === 'function' ? constsOrFactory() : constsOrFactory;
9739 const tView = blueprint[TVIEW] = ngDevMode ?
9740 new TViewConstructor(type, // type: TViewType,
9741 blueprint, // blueprint: LView,
9742 templateFn, // template: ComponentTemplate<{}>|null,
9743 null, // queries: TQueries|null
9744 viewQuery, // viewQuery: ViewQueriesFunction<{}>|null,
9745 declTNode, // declTNode: TNode|null,
9746 cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData,
9747 bindingStartIndex, // bindingStartIndex: number,
9748 initialViewLength, // expandoStartIndex: number,
9749 null, // hostBindingOpCodes: HostBindingOpCodes,
9750 true, // firstCreatePass: boolean,
9751 true, // firstUpdatePass: boolean,
9752 false, // staticViewQueries: boolean,
9753 false, // staticContentQueries: boolean,
9754 null, // preOrderHooks: HookData|null,
9755 null, // preOrderCheckHooks: HookData|null,
9756 null, // contentHooks: HookData|null,
9757 null, // contentCheckHooks: HookData|null,
9758 null, // viewHooks: HookData|null,
9759 null, // viewCheckHooks: HookData|null,
9760 null, // destroyHooks: DestroyHookData|null,
9761 null, // cleanup: any[]|null,
9762 null, // contentQueries: number[]|null,
9763 null, // components: number[]|null,
9764 typeof directives === 'function' ? //
9765 directives() : //
9766 directives, // directiveRegistry: DirectiveDefList|null,
9767 typeof pipes === 'function' ? pipes() : pipes, // pipeRegistry: PipeDefList|null,
9768 null, // firstChild: TNode|null,
9769 schemas, // schemas: SchemaMetadata[]|null,
9770 consts, // consts: TConstants|null
9771 false, // incompleteFirstPass: boolean
9772 decls, // ngDevMode only: decls
9773 vars) :
9774 {
9775 type: type,
9776 blueprint: blueprint,
9777 template: templateFn,
9778 queries: null,
9779 viewQuery: viewQuery,
9780 declTNode: declTNode,
9781 data: blueprint.slice().fill(null, bindingStartIndex),
9782 bindingStartIndex: bindingStartIndex,
9783 expandoStartIndex: initialViewLength,
9784 hostBindingOpCodes: null,
9785 firstCreatePass: true,
9786 firstUpdatePass: true,
9787 staticViewQueries: false,
9788 staticContentQueries: false,
9789 preOrderHooks: null,
9790 preOrderCheckHooks: null,
9791 contentHooks: null,
9792 contentCheckHooks: null,
9793 viewHooks: null,
9794 viewCheckHooks: null,
9795 destroyHooks: null,
9796 cleanup: null,
9797 contentQueries: null,
9798 components: null,
9799 directiveRegistry: typeof directives === 'function' ? directives() : directives,
9800 pipeRegistry: typeof pipes === 'function' ? pipes() : pipes,
9801 firstChild: null,
9802 schemas: schemas,
9803 consts: consts,
9804 incompleteFirstPass: false
9805 };
9806 if (ngDevMode) {
9807 // For performance reasons it is important that the tView retains the same shape during runtime.
9808 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
9809 // prevent class transitions.
9810 Object.seal(tView);
9811 }
9812 return tView;
9813}
9814function createViewBlueprint(bindingStartIndex, initialViewLength) {
9815 const blueprint = ngDevMode ? new LViewBlueprint() : [];
9816 for (let i = 0; i < initialViewLength; i++) {
9817 blueprint.push(i < bindingStartIndex ? null : NO_CHANGE);
9818 }
9819 return blueprint;
9820}
9821function createError(text, token) {
9822 return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
9823}
9824function assertHostNodeExists(rElement, elementOrSelector) {
9825 if (!rElement) {
9826 if (typeof elementOrSelector === 'string') {
9827 throw createError('Host node with selector not found:', elementOrSelector);
9828 }
9829 else {
9830 throw createError('Host node is required:', elementOrSelector);
9831 }
9832 }
9833}
9834/**
9835 * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
9836 *
9837 * @param rendererFactory Factory function to create renderer instance.
9838 * @param elementOrSelector Render element or CSS selector to locate the element.
9839 * @param encapsulation View Encapsulation defined for component that requests host element.
9840 */
9841function locateHostElement(renderer, elementOrSelector, encapsulation) {
9842 if (isProceduralRenderer(renderer)) {
9843 // When using native Shadow DOM, do not clear host element to allow native slot projection
9844 const preserveContent = encapsulation === ViewEncapsulation$1.ShadowDom;
9845 return renderer.selectRootElement(elementOrSelector, preserveContent);
9846 }
9847 let rElement = typeof elementOrSelector === 'string' ?
9848 renderer.querySelector(elementOrSelector) :
9849 elementOrSelector;
9850 ngDevMode && assertHostNodeExists(rElement, elementOrSelector);
9851 // Always clear host element's content when Renderer3 is in use. For procedural renderer case we
9852 // make it depend on whether ShadowDom encapsulation is used (in which case the content should be
9853 // preserved to allow native slot projection). ShadowDom encapsulation requires procedural
9854 // renderer, and procedural renderer case is handled above.
9855 rElement.textContent = '';
9856 return rElement;
9857}
9858/**
9859 * Saves context for this cleanup function in LView.cleanupInstances.
9860 *
9861 * On the first template pass, saves in TView:
9862 * - Cleanup function
9863 * - Index of context we just saved in LView.cleanupInstances
9864 *
9865 * This function can also be used to store instance specific cleanup fns. In that case the `context`
9866 * is `null` and the function is store in `LView` (rather than it `TView`).
9867 */
9868function storeCleanupWithContext(tView, lView, context, cleanupFn) {
9869 const lCleanup = getOrCreateLViewCleanup(lView);
9870 if (context === null) {
9871 // If context is null that this is instance specific callback. These callbacks can only be
9872 // inserted after template shared instances. For this reason in ngDevMode we freeze the TView.
9873 if (ngDevMode) {
9874 Object.freeze(getOrCreateTViewCleanup(tView));
9875 }
9876 lCleanup.push(cleanupFn);
9877 }
9878 else {
9879 lCleanup.push(context);
9880 if (tView.firstCreatePass) {
9881 getOrCreateTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1);
9882 }
9883 }
9884}
9885function createTNode(tView, tParent, type, index, value, attrs) {
9886 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
9887 // `view_engine_compatibility` for additional context.
9888 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
9889 ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\'');
9890 ngDevMode && ngDevMode.tNode++;
9891 ngDevMode && tParent && assertTNodeForTView(tParent, tView);
9892 let injectorIndex = tParent ? tParent.injectorIndex : -1;
9893 const tNode = ngDevMode ?
9894 new TNodeDebug(tView, // tView_: TView
9895 type, // type: TNodeType
9896 index, // index: number
9897 null, // insertBeforeIndex: null|-1|number|number[]
9898 injectorIndex, // injectorIndex: number
9899 -1, // directiveStart: number
9900 -1, // directiveEnd: number
9901 -1, // directiveStylingLast: number
9902 null, // propertyBindings: number[]|null
9903 0, // flags: TNodeFlags
9904 0, // providerIndexes: TNodeProviderIndexes
9905 value, // value: string|null
9906 attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
9907 null, // mergedAttrs
9908 null, // localNames: (string|number)[]|null
9909 undefined, // initialInputs: (string[]|null)[]|null|undefined
9910 null, // inputs: PropertyAliases|null
9911 null, // outputs: PropertyAliases|null
9912 null, // tViews: ITView|ITView[]|null
9913 null, // next: ITNode|null
9914 null, // projectionNext: ITNode|null
9915 null, // child: ITNode|null
9916 tParent, // parent: TElementNode|TContainerNode|null
9917 null, // projection: number|(ITNode|RNode[])[]|null
9918 null, // styles: string|null
9919 null, // stylesWithoutHost: string|null
9920 undefined, // residualStyles: string|null
9921 null, // classes: string|null
9922 null, // classesWithoutHost: string|null
9923 undefined, // residualClasses: string|null
9924 0, // classBindings: TStylingRange;
9925 0) :
9926 {
9927 type,
9928 index,
9929 insertBeforeIndex: null,
9930 injectorIndex,
9931 directiveStart: -1,
9932 directiveEnd: -1,
9933 directiveStylingLast: -1,
9934 propertyBindings: null,
9935 flags: 0,
9936 providerIndexes: 0,
9937 value: value,
9938 attrs: attrs,
9939 mergedAttrs: null,
9940 localNames: null,
9941 initialInputs: undefined,
9942 inputs: null,
9943 outputs: null,
9944 tViews: null,
9945 next: null,
9946 projectionNext: null,
9947 child: null,
9948 parent: tParent,
9949 projection: null,
9950 styles: null,
9951 stylesWithoutHost: null,
9952 residualStyles: undefined,
9953 classes: null,
9954 classesWithoutHost: null,
9955 residualClasses: undefined,
9956 classBindings: 0,
9957 styleBindings: 0,
9958 };
9959 if (ngDevMode) {
9960 // For performance reasons it is important that the tNode retains the same shape during runtime.
9961 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
9962 // prevent class transitions.
9963 Object.seal(tNode);
9964 }
9965 return tNode;
9966}
9967function generatePropertyAliases(inputAliasMap, directiveDefIdx, propStore) {
9968 for (let publicName in inputAliasMap) {
9969 if (inputAliasMap.hasOwnProperty(publicName)) {
9970 propStore = propStore === null ? {} : propStore;
9971 const internalName = inputAliasMap[publicName];
9972 if (propStore.hasOwnProperty(publicName)) {
9973 propStore[publicName].push(directiveDefIdx, internalName);
9974 }
9975 else {
9976 (propStore[publicName] = [directiveDefIdx, internalName]);
9977 }
9978 }
9979 }
9980 return propStore;
9981}
9982/**
9983 * Initializes data structures required to work with directive inputs and outputs.
9984 * Initialization is done for all directives matched on a given TNode.
9985 */
9986function initializeInputAndOutputAliases(tView, tNode) {
9987 ngDevMode && assertFirstCreatePass(tView);
9988 const start = tNode.directiveStart;
9989 const end = tNode.directiveEnd;
9990 const tViewData = tView.data;
9991 const tNodeAttrs = tNode.attrs;
9992 const inputsFromAttrs = ngDevMode ? new TNodeInitialInputs() : [];
9993 let inputsStore = null;
9994 let outputsStore = null;
9995 for (let i = start; i < end; i++) {
9996 const directiveDef = tViewData[i];
9997 const directiveInputs = directiveDef.inputs;
9998 // Do not use unbound attributes as inputs to structural directives, since structural
9999 // directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
10000 // TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
10001 // should be set for inline templates.
10002 const initialInputs = (tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
10003 generateInitialInputs(directiveInputs, tNodeAttrs) :
10004 null;
10005 inputsFromAttrs.push(initialInputs);
10006 inputsStore = generatePropertyAliases(directiveInputs, i, inputsStore);
10007 outputsStore = generatePropertyAliases(directiveDef.outputs, i, outputsStore);
10008 }
10009 if (inputsStore !== null) {
10010 if (inputsStore.hasOwnProperty('class')) {
10011 tNode.flags |= 16 /* hasClassInput */;
10012 }
10013 if (inputsStore.hasOwnProperty('style')) {
10014 tNode.flags |= 32 /* hasStyleInput */;
10015 }
10016 }
10017 tNode.initialInputs = inputsFromAttrs;
10018 tNode.inputs = inputsStore;
10019 tNode.outputs = outputsStore;
10020}
10021/**
10022 * Mapping between attributes names that don't correspond to their element property names.
10023 *
10024 * Performance note: this function is written as a series of if checks (instead of, say, a property
10025 * object lookup) for performance reasons - the series of `if` checks seems to be the fastest way of
10026 * mapping property names. Do NOT change without benchmarking.
10027 *
10028 * Note: this mapping has to be kept in sync with the equally named mapping in the template
10029 * type-checking machinery of ngtsc.
10030 */
10031function mapPropName(name) {
10032 if (name === 'class')
10033 return 'className';
10034 if (name === 'for')
10035 return 'htmlFor';
10036 if (name === 'formaction')
10037 return 'formAction';
10038 if (name === 'innerHtml')
10039 return 'innerHTML';
10040 if (name === 'readonly')
10041 return 'readOnly';
10042 if (name === 'tabindex')
10043 return 'tabIndex';
10044 return name;
10045}
10046function elementPropertyInternal(tView, tNode, lView, propName, value, renderer, sanitizer, nativeOnly) {
10047 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
10048 const element = getNativeByTNode(tNode, lView);
10049 let inputData = tNode.inputs;
10050 let dataValue;
10051 if (!nativeOnly && inputData != null && (dataValue = inputData[propName])) {
10052 setInputsForProperty(tView, lView, dataValue, propName, value);
10053 if (isComponentHost(tNode))
10054 markDirtyIfOnPush(lView, tNode.index);
10055 if (ngDevMode) {
10056 setNgReflectProperties(lView, element, tNode.type, dataValue, value);
10057 }
10058 }
10059 else if (tNode.type & 3 /* AnyRNode */) {
10060 propName = mapPropName(propName);
10061 if (ngDevMode) {
10062 validateAgainstEventProperties(propName);
10063 if (!validateProperty(element, tNode.value, propName, tView.schemas)) {
10064 // Return here since we only log warnings for unknown properties.
10065 logUnknownPropertyError(propName, tNode.value);
10066 return;
10067 }
10068 ngDevMode.rendererSetProperty++;
10069 }
10070 // It is assumed that the sanitizer is only added when the compiler determines that the
10071 // property is risky, so sanitization can be done without further checks.
10072 value = sanitizer != null ? sanitizer(value, tNode.value || '', propName) : value;
10073 if (isProceduralRenderer(renderer)) {
10074 renderer.setProperty(element, propName, value);
10075 }
10076 else if (!isAnimationProp(propName)) {
10077 element.setProperty ? element.setProperty(propName, value) :
10078 element[propName] = value;
10079 }
10080 }
10081 else if (tNode.type & 12 /* AnyContainer */) {
10082 // If the node is a container and the property didn't
10083 // match any of the inputs or schemas we should throw.
10084 if (ngDevMode && !matchingSchemas(tView.schemas, tNode.value)) {
10085 logUnknownPropertyError(propName, tNode.value);
10086 }
10087 }
10088}
10089/** If node is an OnPush component, marks its LView dirty. */
10090function markDirtyIfOnPush(lView, viewIndex) {
10091 ngDevMode && assertLView(lView);
10092 const childComponentLView = getComponentLViewByIndex(viewIndex, lView);
10093 if (!(childComponentLView[FLAGS] & 16 /* CheckAlways */)) {
10094 childComponentLView[FLAGS] |= 64 /* Dirty */;
10095 }
10096}
10097function setNgReflectProperty(lView, element, type, attrName, value) {
10098 const renderer = lView[RENDERER];
10099 attrName = normalizeDebugBindingName(attrName);
10100 const debugValue = normalizeDebugBindingValue(value);
10101 if (type & 3 /* AnyRNode */) {
10102 if (value == null) {
10103 isProceduralRenderer(renderer) ? renderer.removeAttribute(element, attrName) :
10104 element.removeAttribute(attrName);
10105 }
10106 else {
10107 isProceduralRenderer(renderer) ?
10108 renderer.setAttribute(element, attrName, debugValue) :
10109 element.setAttribute(attrName, debugValue);
10110 }
10111 }
10112 else {
10113 const textContent = escapeCommentText(`bindings=${JSON.stringify({ [attrName]: debugValue }, null, 2)}`);
10114 if (isProceduralRenderer(renderer)) {
10115 renderer.setValue(element, textContent);
10116 }
10117 else {
10118 element.textContent = textContent;
10119 }
10120 }
10121}
10122function setNgReflectProperties(lView, element, type, dataValue, value) {
10123 if (type & (3 /* AnyRNode */ | 4 /* Container */)) {
10124 /**
10125 * dataValue is an array containing runtime input or output names for the directives:
10126 * i+0: directive instance index
10127 * i+1: privateName
10128 *
10129 * e.g. [0, 'change', 'change-minified']
10130 * we want to set the reflected property with the privateName: dataValue[i+1]
10131 */
10132 for (let i = 0; i < dataValue.length; i += 2) {
10133 setNgReflectProperty(lView, element, type, dataValue[i + 1], value);
10134 }
10135 }
10136}
10137/**
10138 * Validates that the property of the element is known at runtime and returns
10139 * false if it's not the case.
10140 * This check is relevant for JIT-compiled components (for AOT-compiled
10141 * ones this check happens at build time).
10142 *
10143 * The property is considered known if either:
10144 * - it's a known property of the element
10145 * - the element is allowed by one of the schemas
10146 * - the property is used for animations
10147 *
10148 * @param element Element to validate
10149 * @param tagName Name of the tag to check
10150 * @param propName Name of the property to check
10151 * @param schemas Array of schemas
10152 */
10153function validateProperty(element, tagName, propName, schemas) {
10154 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
10155 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
10156 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
10157 // execute the check below.
10158 if (schemas === null)
10159 return true;
10160 // The property is considered valid if the element matches the schema, it exists on the element,
10161 // or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
10162 if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
10163 return true;
10164 }
10165 // Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
10166 // need to account for both here, while being careful with `typeof null` also returning 'object'.
10167 return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
10168}
10169/**
10170 * Returns true if the tag name is allowed by specified schemas.
10171 * @param schemas Array of schemas
10172 * @param tagName Name of the tag
10173 */
10174function matchingSchemas(schemas, tagName) {
10175 if (schemas !== null) {
10176 for (let i = 0; i < schemas.length; i++) {
10177 const schema = schemas[i];
10178 if (schema === NO_ERRORS_SCHEMA ||
10179 schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
10180 return true;
10181 }
10182 }
10183 }
10184 return false;
10185}
10186/**
10187 * Logs an error that a property is not supported on an element.
10188 * @param propName Name of the invalid property.
10189 * @param tagName Name of the node on which we encountered the property.
10190 */
10191function logUnknownPropertyError(propName, tagName) {
10192 const message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'.`;
10193 console.error(formatRuntimeError(303 /* UNKNOWN_BINDING */, message));
10194}
10195/**
10196 * Instantiate a root component.
10197 */
10198function instantiateRootComponent(tView, lView, def) {
10199 const rootTNode = getCurrentTNode();
10200 if (tView.firstCreatePass) {
10201 if (def.providersResolver)
10202 def.providersResolver(def);
10203 const directiveIndex = allocExpando(tView, lView, 1, null);
10204 ngDevMode &&
10205 assertEqual(directiveIndex, rootTNode.directiveStart, 'Because this is a root component the allocated expando should match the TNode component.');
10206 configureViewWithDirective(tView, rootTNode, lView, directiveIndex, def);
10207 }
10208 const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart, rootTNode);
10209 attachPatchData(directive, lView);
10210 const native = getNativeByTNode(rootTNode, lView);
10211 if (native) {
10212 attachPatchData(native, lView);
10213 }
10214 return directive;
10215}
10216/**
10217 * Resolve the matched directives on a node.
10218 */
10219function resolveDirectives(tView, lView, tNode, localRefs) {
10220 // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
10221 // tsickle.
10222 ngDevMode && assertFirstCreatePass(tView);
10223 let hasDirectives = false;
10224 if (getBindingsEnabled()) {
10225 const directiveDefs = findDirectiveDefMatches(tView, lView, tNode);
10226 const exportsMap = localRefs === null ? null : { '': -1 };
10227 if (directiveDefs !== null) {
10228 hasDirectives = true;
10229 initTNodeFlags(tNode, tView.data.length, directiveDefs.length);
10230 // When the same token is provided by several directives on the same node, some rules apply in
10231 // the viewEngine:
10232 // - viewProviders have priority over providers
10233 // - the last directive in NgModule.declarations has priority over the previous one
10234 // So to match these rules, the order in which providers are added in the arrays is very
10235 // important.
10236 for (let i = 0; i < directiveDefs.length; i++) {
10237 const def = directiveDefs[i];
10238 if (def.providersResolver)
10239 def.providersResolver(def);
10240 }
10241 let preOrderHooksFound = false;
10242 let preOrderCheckHooksFound = false;
10243 let directiveIdx = allocExpando(tView, lView, directiveDefs.length, null);
10244 ngDevMode &&
10245 assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
10246 for (let i = 0; i < directiveDefs.length; i++) {
10247 const def = directiveDefs[i];
10248 // Merge the attrs in the order of matches. This assumes that the first directive is the
10249 // component itself, so that the component has the least priority.
10250 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
10251 configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
10252 saveNameToExportMap(directiveIdx, def, exportsMap);
10253 if (def.contentQueries !== null)
10254 tNode.flags |= 8 /* hasContentQuery */;
10255 if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
10256 tNode.flags |= 128 /* hasHostBindings */;
10257 const lifeCycleHooks = def.type.prototype;
10258 // Only push a node index into the preOrderHooks array if this is the first
10259 // pre-order hook found on this node.
10260 if (!preOrderHooksFound &&
10261 (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
10262 // We will push the actual hook function into this array later during dir instantiation.
10263 // We cannot do it now because we must ensure hooks are registered in the same
10264 // order that directives are created (i.e. injection order).
10265 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
10266 preOrderHooksFound = true;
10267 }
10268 if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
10269 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
10270 preOrderCheckHooksFound = true;
10271 }
10272 directiveIdx++;
10273 }
10274 initializeInputAndOutputAliases(tView, tNode);
10275 }
10276 if (exportsMap)
10277 cacheMatchingLocalNames(tNode, localRefs, exportsMap);
10278 }
10279 // Merge the template attrs last so that they have the highest priority.
10280 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
10281 return hasDirectives;
10282}
10283/**
10284 * Add `hostBindings` to the `TView.hostBindingOpCodes`.
10285 *
10286 * @param tView `TView` to which the `hostBindings` should be added.
10287 * @param tNode `TNode` the element which contains the directive
10288 * @param lView `LView` current `LView`
10289 * @param directiveIdx Directive index in view.
10290 * @param directiveVarsIdx Where will the directive's vars be stored
10291 * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
10292 */
10293function registerHostBindingOpCodes(tView, tNode, lView, directiveIdx, directiveVarsIdx, def) {
10294 ngDevMode && assertFirstCreatePass(tView);
10295 const hostBindings = def.hostBindings;
10296 if (hostBindings) {
10297 let hostBindingOpCodes = tView.hostBindingOpCodes;
10298 if (hostBindingOpCodes === null) {
10299 hostBindingOpCodes = tView.hostBindingOpCodes = [];
10300 }
10301 const elementIndx = ~tNode.index;
10302 if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
10303 // Conditionally add select element so that we are more efficient in execution.
10304 // NOTE: this is strictly not necessary and it trades code size for runtime perf.
10305 // (We could just always add it.)
10306 hostBindingOpCodes.push(elementIndx);
10307 }
10308 hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
10309 }
10310}
10311/**
10312 * Returns the last selected element index in the `HostBindingOpCodes`
10313 *
10314 * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
10315 * if it changes. This method returns the last index (or '0' if not found.)
10316 *
10317 * Selected element index are only the ones which are negative.
10318 */
10319function lastSelectedElementIdx(hostBindingOpCodes) {
10320 let i = hostBindingOpCodes.length;
10321 while (i > 0) {
10322 const value = hostBindingOpCodes[--i];
10323 if (typeof value === 'number' && value < 0) {
10324 return value;
10325 }
10326 }
10327 return 0;
10328}
10329/**
10330 * Instantiate all the directives that were previously resolved on the current node.
10331 */
10332function instantiateAllDirectives(tView, lView, tNode, native) {
10333 const start = tNode.directiveStart;
10334 const end = tNode.directiveEnd;
10335 if (!tView.firstCreatePass) {
10336 getOrCreateNodeInjectorForNode(tNode, lView);
10337 }
10338 attachPatchData(native, lView);
10339 const initialInputs = tNode.initialInputs;
10340 for (let i = start; i < end; i++) {
10341 const def = tView.data[i];
10342 const isComponent = isComponentDef(def);
10343 if (isComponent) {
10344 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */);
10345 addComponentLogic(lView, tNode, def);
10346 }
10347 const directive = getNodeInjectable(lView, tView, i, tNode);
10348 attachPatchData(directive, lView);
10349 if (initialInputs !== null) {
10350 setInputsFromAttrs(lView, i - start, directive, def, tNode, initialInputs);
10351 }
10352 if (isComponent) {
10353 const componentView = getComponentLViewByIndex(tNode.index, lView);
10354 componentView[CONTEXT] = directive;
10355 }
10356 }
10357}
10358function invokeDirectivesHostBindings(tView, lView, tNode) {
10359 const start = tNode.directiveStart;
10360 const end = tNode.directiveEnd;
10361 const firstCreatePass = tView.firstCreatePass;
10362 const elementIndex = tNode.index;
10363 const currentDirectiveIndex = getCurrentDirectiveIndex();
10364 try {
10365 setSelectedIndex(elementIndex);
10366 for (let dirIndex = start; dirIndex < end; dirIndex++) {
10367 const def = tView.data[dirIndex];
10368 const directive = lView[dirIndex];
10369 setCurrentDirectiveIndex(dirIndex);
10370 if (def.hostBindings !== null || def.hostVars !== 0 || def.hostAttrs !== null) {
10371 invokeHostBindingsInCreationMode(def, directive);
10372 }
10373 }
10374 }
10375 finally {
10376 setSelectedIndex(-1);
10377 setCurrentDirectiveIndex(currentDirectiveIndex);
10378 }
10379}
10380/**
10381 * Invoke the host bindings in creation mode.
10382 *
10383 * @param def `DirectiveDef` which may contain the `hostBindings` function.
10384 * @param directive Instance of directive.
10385 */
10386function invokeHostBindingsInCreationMode(def, directive) {
10387 if (def.hostBindings !== null) {
10388 def.hostBindings(1 /* Create */, directive);
10389 }
10390}
10391/**
10392 * Matches the current node against all available selectors.
10393 * If a component is matched (at most one), it is returned in first position in the array.
10394 */
10395function findDirectiveDefMatches(tView, viewData, tNode) {
10396 ngDevMode && assertFirstCreatePass(tView);
10397 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */);
10398 const registry = tView.directiveRegistry;
10399 let matches = null;
10400 if (registry) {
10401 for (let i = 0; i < registry.length; i++) {
10402 const def = registry[i];
10403 if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) {
10404 matches || (matches = ngDevMode ? new MatchesArray() : []);
10405 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, viewData), tView, def.type);
10406 if (isComponentDef(def)) {
10407 if (ngDevMode) {
10408 assertTNodeType(tNode, 2 /* Element */, `"${tNode.value}" tags cannot be used as component hosts. ` +
10409 `Please use a different tag to activate the ${stringify(def.type)} component.`);
10410 if (tNode.flags & 2 /* isComponentHost */) {
10411 // If another component has been matched previously, it's the first element in the
10412 // `matches` array, see how we store components/directives in `matches` below.
10413 throwMultipleComponentError(tNode, matches[0].type, def.type);
10414 }
10415 }
10416 markAsComponentHost(tView, tNode);
10417 // The component is always stored first with directives after.
10418 matches.unshift(def);
10419 }
10420 else {
10421 matches.push(def);
10422 }
10423 }
10424 }
10425 }
10426 return matches;
10427}
10428/**
10429 * Marks a given TNode as a component's host. This consists of:
10430 * - setting appropriate TNode flags;
10431 * - storing index of component's host element so it will be queued for view refresh during CD.
10432 */
10433function markAsComponentHost(tView, hostTNode) {
10434 ngDevMode && assertFirstCreatePass(tView);
10435 hostTNode.flags |= 2 /* isComponentHost */;
10436 (tView.components || (tView.components = ngDevMode ? new TViewComponents() : []))
10437 .push(hostTNode.index);
10438}
10439/** Caches local names and their matching directive indices for query and template lookups. */
10440function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
10441 if (localRefs) {
10442 const localNames = tNode.localNames = ngDevMode ? new TNodeLocalNames() : [];
10443 // Local names must be stored in tNode in the same order that localRefs are defined
10444 // in the template to ensure the data is loaded in the same slots as their refs
10445 // in the template (for template queries).
10446 for (let i = 0; i < localRefs.length; i += 2) {
10447 const index = exportsMap[localRefs[i + 1]];
10448 if (index == null)
10449 throw new RuntimeError(-301 /* EXPORT_NOT_FOUND */, ngDevMode && `Export of name '${localRefs[i + 1]}' not found!`);
10450 localNames.push(localRefs[i], index);
10451 }
10452 }
10453}
10454/**
10455 * Builds up an export map as directives are created, so local refs can be quickly mapped
10456 * to their directive instances.
10457 */
10458function saveNameToExportMap(directiveIdx, def, exportsMap) {
10459 if (exportsMap) {
10460 if (def.exportAs) {
10461 for (let i = 0; i < def.exportAs.length; i++) {
10462 exportsMap[def.exportAs[i]] = directiveIdx;
10463 }
10464 }
10465 if (isComponentDef(def))
10466 exportsMap[''] = directiveIdx;
10467 }
10468}
10469/**
10470 * Initializes the flags on the current node, setting all indices to the initial index,
10471 * the directive count to 0, and adding the isComponent flag.
10472 * @param index the initial index
10473 */
10474function initTNodeFlags(tNode, index, numberOfDirectives) {
10475 ngDevMode &&
10476 assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
10477 tNode.flags |= 1 /* isDirectiveHost */;
10478 // When the first directive is created on a node, save the index
10479 tNode.directiveStart = index;
10480 tNode.directiveEnd = index + numberOfDirectives;
10481 tNode.providerIndexes = index;
10482}
10483/**
10484 * Setup directive for instantiation.
10485 *
10486 * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
10487 * as `LView`. `TView` gets the `DirectiveDef`.
10488 *
10489 * @param tView `TView`
10490 * @param tNode `TNode`
10491 * @param lView `LView`
10492 * @param directiveIndex Index where the directive will be stored in the Expando.
10493 * @param def `DirectiveDef`
10494 */
10495function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
10496 ngDevMode &&
10497 assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
10498 tView.data[directiveIndex] = def;
10499 const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
10500 const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null);
10501 tView.blueprint[directiveIndex] = nodeInjectorFactory;
10502 lView[directiveIndex] = nodeInjectorFactory;
10503 registerHostBindingOpCodes(tView, tNode, lView, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
10504}
10505function addComponentLogic(lView, hostTNode, def) {
10506 const native = getNativeByTNode(hostTNode, lView);
10507 const tView = getOrCreateTComponentView(def);
10508 // Only component views should be added to the view tree directly. Embedded views are
10509 // accessed through their containers because they may be removed / re-added later.
10510 const rendererFactory = lView[RENDERER_FACTORY];
10511 const componentView = addToViewTree(lView, createLView(lView, tView, null, def.onPush ? 64 /* Dirty */ : 16 /* CheckAlways */, native, hostTNode, rendererFactory, rendererFactory.createRenderer(native, def), null, null));
10512 // Component view will always be created before any injected LContainers,
10513 // so this is a regular element, wrap it with the component view
10514 lView[hostTNode.index] = componentView;
10515}
10516function elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace) {
10517 if (ngDevMode) {
10518 assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
10519 validateAgainstEventAttributes(name);
10520 assertTNodeType(tNode, 2 /* Element */, `Attempted to set attribute \`${name}\` on a container node. ` +
10521 `Host bindings are not valid on ng-container or ng-template.`);
10522 }
10523 const element = getNativeByTNode(tNode, lView);
10524 setElementAttribute(lView[RENDERER], element, namespace, tNode.value, name, value, sanitizer);
10525}
10526function setElementAttribute(renderer, element, namespace, tagName, name, value, sanitizer) {
10527 if (value == null) {
10528 ngDevMode && ngDevMode.rendererRemoveAttribute++;
10529 isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) :
10530 element.removeAttribute(name);
10531 }
10532 else {
10533 ngDevMode && ngDevMode.rendererSetAttribute++;
10534 const strValue = sanitizer == null ? renderStringify(value) : sanitizer(value, tagName || '', name);
10535 if (isProceduralRenderer(renderer)) {
10536 renderer.setAttribute(element, name, strValue, namespace);
10537 }
10538 else {
10539 namespace ? element.setAttributeNS(namespace, name, strValue) :
10540 element.setAttribute(name, strValue);
10541 }
10542 }
10543}
10544/**
10545 * Sets initial input properties on directive instances from attribute data
10546 *
10547 * @param lView Current LView that is being processed.
10548 * @param directiveIndex Index of the directive in directives array
10549 * @param instance Instance of the directive on which to set the initial inputs
10550 * @param def The directive def that contains the list of inputs
10551 * @param tNode The static data for this node
10552 */
10553function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initialInputData) {
10554 const initialInputs = initialInputData[directiveIndex];
10555 if (initialInputs !== null) {
10556 const setInput = def.setInput;
10557 for (let i = 0; i < initialInputs.length;) {
10558 const publicName = initialInputs[i++];
10559 const privateName = initialInputs[i++];
10560 const value = initialInputs[i++];
10561 if (setInput !== null) {
10562 def.setInput(instance, value, publicName, privateName);
10563 }
10564 else {
10565 instance[privateName] = value;
10566 }
10567 if (ngDevMode) {
10568 const nativeElement = getNativeByTNode(tNode, lView);
10569 setNgReflectProperty(lView, nativeElement, tNode.type, privateName, value);
10570 }
10571 }
10572 }
10573}
10574/**
10575 * Generates initialInputData for a node and stores it in the template's static storage
10576 * so subsequent template invocations don't have to recalculate it.
10577 *
10578 * initialInputData is an array containing values that need to be set as input properties
10579 * for directives on this node, but only once on creation. We need this array to support
10580 * the case where you set an @Input property of a directive using attribute-like syntax.
10581 * e.g. if you have a `name` @Input, you can set it once like this:
10582 *
10583 * <my-component name="Bess"></my-component>
10584 *
10585 * @param inputs The list of inputs from the directive def
10586 * @param attrs The static attrs on this node
10587 */
10588function generateInitialInputs(inputs, attrs) {
10589 let inputsToStore = null;
10590 let i = 0;
10591 while (i < attrs.length) {
10592 const attrName = attrs[i];
10593 if (attrName === 0 /* NamespaceURI */) {
10594 // We do not allow inputs on namespaced attributes.
10595 i += 4;
10596 continue;
10597 }
10598 else if (attrName === 5 /* ProjectAs */) {
10599 // Skip over the `ngProjectAs` value.
10600 i += 2;
10601 continue;
10602 }
10603 // If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
10604 if (typeof attrName === 'number')
10605 break;
10606 if (inputs.hasOwnProperty(attrName)) {
10607 if (inputsToStore === null)
10608 inputsToStore = [];
10609 inputsToStore.push(attrName, inputs[attrName], attrs[i + 1]);
10610 }
10611 i += 2;
10612 }
10613 return inputsToStore;
10614}
10615//////////////////////////
10616//// ViewContainer & View
10617//////////////////////////
10618// Not sure why I need to do `any` here but TS complains later.
10619const LContainerArray = class LContainer extends Array {
10620};
10621/**
10622 * Creates a LContainer, either from a container instruction, or for a ViewContainerRef.
10623 *
10624 * @param hostNative The host element for the LContainer
10625 * @param hostTNode The host TNode for the LContainer
10626 * @param currentView The parent view of the LContainer
10627 * @param native The native comment element
10628 * @param isForViewContainerRef Optional a flag indicating the ViewContainerRef case
10629 * @returns LContainer
10630 */
10631function createLContainer(hostNative, currentView, native, tNode) {
10632 ngDevMode && assertLView(currentView);
10633 ngDevMode && !isProceduralRenderer(currentView[RENDERER]) && assertDomNode(native);
10634 // https://jsperf.com/array-literal-vs-new-array-really
10635 const lContainer = new (ngDevMode ? LContainerArray : Array)(hostNative, // host native
10636 true, // Boolean `true` in this position signifies that this is an `LContainer`
10637 false, // has transplanted views
10638 currentView, // parent
10639 null, // next
10640 0, // transplanted views to refresh count
10641 tNode, // t_host
10642 native, // native,
10643 null, // view refs
10644 null);
10645 ngDevMode &&
10646 assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
10647 ngDevMode && attachLContainerDebug(lContainer);
10648 return lContainer;
10649}
10650/**
10651 * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
10652 * them by executing an associated template function.
10653 */
10654function refreshEmbeddedViews(lView) {
10655 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
10656 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
10657 const embeddedLView = lContainer[i];
10658 const embeddedTView = embeddedLView[TVIEW];
10659 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
10660 if (viewAttachedToChangeDetector(embeddedLView)) {
10661 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
10662 }
10663 }
10664 }
10665}
10666/**
10667 * Mark transplanted views as needing to be refreshed at their insertion points.
10668 *
10669 * @param lView The `LView` that may have transplanted views.
10670 */
10671function markTransplantedViewsForRefresh(lView) {
10672 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
10673 if (!lContainer[HAS_TRANSPLANTED_VIEWS])
10674 continue;
10675 const movedViews = lContainer[MOVED_VIEWS];
10676 ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
10677 for (let i = 0; i < movedViews.length; i++) {
10678 const movedLView = movedViews[i];
10679 const insertionLContainer = movedLView[PARENT];
10680 ngDevMode && assertLContainer(insertionLContainer);
10681 // We don't want to increment the counter if the moved LView was already marked for
10682 // refresh.
10683 if ((movedLView[FLAGS] & 1024 /* RefreshTransplantedView */) === 0) {
10684 updateTransplantedViewCount(insertionLContainer, 1);
10685 }
10686 // Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
10687 // those that aren't (declaration component === insertion component). In the latter case,
10688 // it's fine to add the flag, as we will clear it immediately in
10689 // `refreshEmbeddedViews` for the view currently being refreshed.
10690 movedLView[FLAGS] |= 1024 /* RefreshTransplantedView */;
10691 }
10692 }
10693}
10694/////////////
10695/**
10696 * Refreshes components by entering the component view and processing its bindings, queries, etc.
10697 *
10698 * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
10699 */
10700function refreshComponent(hostLView, componentHostIdx) {
10701 ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
10702 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
10703 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
10704 if (viewAttachedToChangeDetector(componentView)) {
10705 const tView = componentView[TVIEW];
10706 if (componentView[FLAGS] & (16 /* CheckAlways */ | 64 /* Dirty */)) {
10707 refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
10708 }
10709 else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
10710 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
10711 refreshContainsDirtyView(componentView);
10712 }
10713 }
10714}
10715/**
10716 * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
10717 * children or descendants of the given lView.
10718 *
10719 * @param lView The lView which contains descendant transplanted views that need to be refreshed.
10720 */
10721function refreshContainsDirtyView(lView) {
10722 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
10723 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
10724 const embeddedLView = lContainer[i];
10725 if (embeddedLView[FLAGS] & 1024 /* RefreshTransplantedView */) {
10726 const embeddedTView = embeddedLView[TVIEW];
10727 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
10728 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
10729 }
10730 else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
10731 refreshContainsDirtyView(embeddedLView);
10732 }
10733 }
10734 }
10735 const tView = lView[TVIEW];
10736 // Refresh child component views.
10737 const components = tView.components;
10738 if (components !== null) {
10739 for (let i = 0; i < components.length; i++) {
10740 const componentView = getComponentLViewByIndex(components[i], lView);
10741 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
10742 if (viewAttachedToChangeDetector(componentView) &&
10743 componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
10744 refreshContainsDirtyView(componentView);
10745 }
10746 }
10747 }
10748}
10749function renderComponent$1(hostLView, componentHostIdx) {
10750 ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
10751 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
10752 const componentTView = componentView[TVIEW];
10753 syncViewWithBlueprint(componentTView, componentView);
10754 renderView(componentTView, componentView, componentView[CONTEXT]);
10755}
10756/**
10757 * Syncs an LView instance with its blueprint if they have gotten out of sync.
10758 *
10759 * Typically, blueprints and their view instances should always be in sync, so the loop here
10760 * will be skipped. However, consider this case of two components side-by-side:
10761 *
10762 * App template:
10763 * ```
10764 * <comp></comp>
10765 * <comp></comp>
10766 * ```
10767 *
10768 * The following will happen:
10769 * 1. App template begins processing.
10770 * 2. First <comp> is matched as a component and its LView is created.
10771 * 3. Second <comp> is matched as a component and its LView is created.
10772 * 4. App template completes processing, so it's time to check child templates.
10773 * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
10774 * 6. Second <comp> template is checked. Its blueprint has been updated by the first
10775 * <comp> template, but its LView was created before this update, so it is out of sync.
10776 *
10777 * Note that embedded views inside ngFor loops will never be out of sync because these views
10778 * are processed as soon as they are created.
10779 *
10780 * @param tView The `TView` that contains the blueprint for syncing
10781 * @param lView The view to sync
10782 */
10783function syncViewWithBlueprint(tView, lView) {
10784 for (let i = lView.length; i < tView.blueprint.length; i++) {
10785 lView.push(tView.blueprint[i]);
10786 }
10787}
10788/**
10789 * Adds LView or LContainer to the end of the current view tree.
10790 *
10791 * This structure will be used to traverse through nested views to remove listeners
10792 * and call onDestroy callbacks.
10793 *
10794 * @param lView The view where LView or LContainer should be added
10795 * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header
10796 * @param lViewOrLContainer The LView or LContainer to add to the view tree
10797 * @returns The state passed in
10798 */
10799function addToViewTree(lView, lViewOrLContainer) {
10800 // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
10801 // to the end of the queue, which means if the developer retrieves the LContainers from RNodes out
10802 // of order, the change detection will run out of order, as the act of retrieving the the
10803 // LContainer from the RNode is what adds it to the queue.
10804 if (lView[CHILD_HEAD]) {
10805 lView[CHILD_TAIL][NEXT] = lViewOrLContainer;
10806 }
10807 else {
10808 lView[CHILD_HEAD] = lViewOrLContainer;
10809 }
10810 lView[CHILD_TAIL] = lViewOrLContainer;
10811 return lViewOrLContainer;
10812}
10813///////////////////////////////
10814//// Change detection
10815///////////////////////////////
10816/**
10817 * Marks current view and all ancestors dirty.
10818 *
10819 * Returns the root view because it is found as a byproduct of marking the view tree
10820 * dirty, and can be used by methods that consume markViewDirty() to easily schedule
10821 * change detection. Otherwise, such methods would need to traverse up the view tree
10822 * an additional time to get the root view and schedule a tick on it.
10823 *
10824 * @param lView The starting LView to mark dirty
10825 * @returns the root LView
10826 */
10827function markViewDirty(lView) {
10828 while (lView) {
10829 lView[FLAGS] |= 64 /* Dirty */;
10830 const parent = getLViewParent(lView);
10831 // Stop traversing up as soon as you find a root view that wasn't attached to any container
10832 if (isRootView(lView) && !parent) {
10833 return lView;
10834 }
10835 // continue otherwise
10836 lView = parent;
10837 }
10838 return null;
10839}
10840/**
10841 * Used to schedule change detection on the whole application.
10842 *
10843 * Unlike `tick`, `scheduleTick` coalesces multiple calls into one change detection run.
10844 * It is usually called indirectly by calling `markDirty` when the view needs to be
10845 * re-rendered.
10846 *
10847 * Typically `scheduleTick` uses `requestAnimationFrame` to coalesce multiple
10848 * `scheduleTick` requests. The scheduling function can be overridden in
10849 * `renderComponent`'s `scheduler` option.
10850 */
10851function scheduleTick(rootContext, flags) {
10852 const nothingScheduled = rootContext.flags === 0 /* Empty */;
10853 if (nothingScheduled && rootContext.clean == _CLEAN_PROMISE) {
10854 // https://github.com/angular/angular/issues/39296
10855 // should only attach the flags when really scheduling a tick
10856 rootContext.flags |= flags;
10857 let res;
10858 rootContext.clean = new Promise((r) => res = r);
10859 rootContext.scheduler(() => {
10860 if (rootContext.flags & 1 /* DetectChanges */) {
10861 rootContext.flags &= ~1 /* DetectChanges */;
10862 tickRootContext(rootContext);
10863 }
10864 if (rootContext.flags & 2 /* FlushPlayers */) {
10865 rootContext.flags &= ~2 /* FlushPlayers */;
10866 const playerHandler = rootContext.playerHandler;
10867 if (playerHandler) {
10868 playerHandler.flushPlayers();
10869 }
10870 }
10871 rootContext.clean = _CLEAN_PROMISE;
10872 res(null);
10873 });
10874 }
10875}
10876function tickRootContext(rootContext) {
10877 for (let i = 0; i < rootContext.components.length; i++) {
10878 const rootComponent = rootContext.components[i];
10879 const lView = readPatchedLView(rootComponent);
10880 const tView = lView[TVIEW];
10881 renderComponentOrTemplate(tView, lView, tView.template, rootComponent);
10882 }
10883}
10884function detectChangesInternal(tView, lView, context) {
10885 const rendererFactory = lView[RENDERER_FACTORY];
10886 if (rendererFactory.begin)
10887 rendererFactory.begin();
10888 try {
10889 refreshView(tView, lView, tView.template, context);
10890 }
10891 catch (error) {
10892 handleError(lView, error);
10893 throw error;
10894 }
10895 finally {
10896 if (rendererFactory.end)
10897 rendererFactory.end();
10898 }
10899}
10900/**
10901 * Synchronously perform change detection on a root view and its components.
10902 *
10903 * @param lView The view which the change detection should be performed on.
10904 */
10905function detectChangesInRootView(lView) {
10906 tickRootContext(lView[CONTEXT]);
10907}
10908function checkNoChangesInternal(tView, view, context) {
10909 setIsInCheckNoChangesMode(true);
10910 try {
10911 detectChangesInternal(tView, view, context);
10912 }
10913 finally {
10914 setIsInCheckNoChangesMode(false);
10915 }
10916}
10917/**
10918 * Checks the change detector on a root view and its components, and throws if any changes are
10919 * detected.
10920 *
10921 * This is used in development mode to verify that running change detection doesn't
10922 * introduce other changes.
10923 *
10924 * @param lView The view which the change detection should be checked on.
10925 */
10926function checkNoChangesInRootView(lView) {
10927 setIsInCheckNoChangesMode(true);
10928 try {
10929 detectChangesInRootView(lView);
10930 }
10931 finally {
10932 setIsInCheckNoChangesMode(false);
10933 }
10934}
10935function executeViewQueryFn(flags, viewQueryFn, component) {
10936 ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
10937 setCurrentQueryIndex(0);
10938 viewQueryFn(flags, component);
10939}
10940///////////////////////////////
10941//// Bindings & interpolations
10942///////////////////////////////
10943/**
10944 * Stores meta-data for a property binding to be used by TestBed's `DebugElement.properties`.
10945 *
10946 * In order to support TestBed's `DebugElement.properties` we need to save, for each binding:
10947 * - a bound property name;
10948 * - a static parts of interpolated strings;
10949 *
10950 * A given property metadata is saved at the binding's index in the `TView.data` (in other words, a
10951 * property binding metadata will be stored in `TView.data` at the same index as a bound value in
10952 * `LView`). Metadata are represented as `INTERPOLATION_DELIMITER`-delimited string with the
10953 * following format:
10954 * - `propertyName` for bound properties;
10955 * - `propertyName�prefix�interpolation_static_part1�..interpolation_static_partN�suffix` for
10956 * interpolated properties.
10957 *
10958 * @param tData `TData` where meta-data will be saved;
10959 * @param tNode `TNode` that is a target of the binding;
10960 * @param propertyName bound property name;
10961 * @param bindingIndex binding index in `LView`
10962 * @param interpolationParts static interpolation parts (for property interpolations)
10963 */
10964function storePropertyBindingMetadata(tData, tNode, propertyName, bindingIndex, ...interpolationParts) {
10965 // Binding meta-data are stored only the first time a given property instruction is processed.
10966 // Since we don't have a concept of the "first update pass" we need to check for presence of the
10967 // binding meta-data to decide if one should be stored (or if was stored already).
10968 if (tData[bindingIndex] === null) {
10969 if (tNode.inputs == null || !tNode.inputs[propertyName]) {
10970 const propBindingIdxs = tNode.propertyBindings || (tNode.propertyBindings = []);
10971 propBindingIdxs.push(bindingIndex);
10972 let bindingMetadata = propertyName;
10973 if (interpolationParts.length > 0) {
10974 bindingMetadata +=
10975 INTERPOLATION_DELIMITER + interpolationParts.join(INTERPOLATION_DELIMITER);
10976 }
10977 tData[bindingIndex] = bindingMetadata;
10978 }
10979 }
10980}
10981const CLEAN_PROMISE = _CLEAN_PROMISE;
10982function getOrCreateLViewCleanup(view) {
10983 // top level variables should not be exported for performance reasons (PERF_NOTES.md)
10984 return view[CLEANUP] || (view[CLEANUP] = ngDevMode ? new LCleanup() : []);
10985}
10986function getOrCreateTViewCleanup(tView) {
10987 return tView.cleanup || (tView.cleanup = ngDevMode ? new TCleanup() : []);
10988}
10989/**
10990 * There are cases where the sub component's renderer needs to be included
10991 * instead of the current renderer (see the componentSyntheticHost* instructions).
10992 */
10993function loadComponentRenderer(currentDef, tNode, lView) {
10994 // TODO(FW-2043): the `currentDef` is null when host bindings are invoked while creating root
10995 // component (see packages/core/src/render3/component.ts). This is not consistent with the process
10996 // of creating inner components, when current directive index is available in the state. In order
10997 // to avoid relying on current def being `null` (thus special-casing root component creation), the
10998 // process of creating root component should be unified with the process of creating inner
10999 // components.
11000 if (currentDef === null || isComponentDef(currentDef)) {
11001 lView = unwrapLView(lView[tNode.index]);
11002 }
11003 return lView[RENDERER];
11004}
11005/** Handles an error thrown in an LView. */
11006function handleError(lView, error) {
11007 const injector = lView[INJECTOR$1];
11008 const errorHandler = injector ? injector.get(ErrorHandler, null) : null;
11009 errorHandler && errorHandler.handleError(error);
11010}
11011/**
11012 * Set the inputs of directives at the current node to corresponding value.
11013 *
11014 * @param tView The current TView
11015 * @param lView the `LView` which contains the directives.
11016 * @param inputs mapping between the public "input" name and privately-known,
11017 * possibly minified, property names to write to.
11018 * @param value Value to set.
11019 */
11020function setInputsForProperty(tView, lView, inputs, publicName, value) {
11021 for (let i = 0; i < inputs.length;) {
11022 const index = inputs[i++];
11023 const privateName = inputs[i++];
11024 const instance = lView[index];
11025 ngDevMode && assertIndexInRange(lView, index);
11026 const def = tView.data[index];
11027 if (def.setInput !== null) {
11028 def.setInput(instance, value, publicName, privateName);
11029 }
11030 else {
11031 instance[privateName] = value;
11032 }
11033 }
11034}
11035/**
11036 * Updates a text binding at a given index in a given LView.
11037 */
11038function textBindingInternal(lView, index, value) {
11039 ngDevMode && assertString(value, 'Value should be a string');
11040 ngDevMode && assertNotSame(value, NO_CHANGE, 'value should not be NO_CHANGE');
11041 ngDevMode && assertIndexInRange(lView, index);
11042 const element = getNativeByIndex(index, lView);
11043 ngDevMode && assertDefined(element, 'native element should exist');
11044 updateTextNode(lView[RENDERER], element, value);
11045}
11046
11047/**
11048 * @license
11049 * Copyright Google LLC All Rights Reserved.
11050 *
11051 * Use of this source code is governed by an MIT-style license that can be
11052 * found in the LICENSE file at https://angular.io/license
11053 */
11054/**
11055 * Compute the static styling (class/style) from `TAttributes`.
11056 *
11057 * This function should be called during `firstCreatePass` only.
11058 *
11059 * @param tNode The `TNode` into which the styling information should be loaded.
11060 * @param attrs `TAttributes` containing the styling information.
11061 * @param writeToHost Where should the resulting static styles be written?
11062 * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
11063 * - `true` Write to `TNode.styles` / `TNode.classes`
11064 */
11065function computeStaticStyling(tNode, attrs, writeToHost) {
11066 ngDevMode &&
11067 assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
11068 let styles = writeToHost ? tNode.styles : null;
11069 let classes = writeToHost ? tNode.classes : null;
11070 let mode = 0;
11071 if (attrs !== null) {
11072 for (let i = 0; i < attrs.length; i++) {
11073 const value = attrs[i];
11074 if (typeof value === 'number') {
11075 mode = value;
11076 }
11077 else if (mode == 1 /* Classes */) {
11078 classes = concatStringsWithSpace(classes, value);
11079 }
11080 else if (mode == 2 /* Styles */) {
11081 const style = value;
11082 const styleValue = attrs[++i];
11083 styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
11084 }
11085 }
11086 }
11087 writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
11088 writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
11089}
11090
11091/**
11092 * @license
11093 * Copyright Google LLC All Rights Reserved.
11094 *
11095 * Use of this source code is governed by an MIT-style license that can be
11096 * found in the LICENSE file at https://angular.io/license
11097 */
11098/**
11099 * Synchronously perform change detection on a component (and possibly its sub-components).
11100 *
11101 * This function triggers change detection in a synchronous way on a component.
11102 *
11103 * @param component The component which the change detection should be performed on.
11104 */
11105function detectChanges(component) {
11106 const view = getComponentViewByInstance(component);
11107 detectChangesInternal(view[TVIEW], view, component);
11108}
11109/**
11110 * Marks the component as dirty (needing change detection). Marking a component dirty will
11111 * schedule a change detection on it at some point in the future.
11112 *
11113 * Marking an already dirty component as dirty won't do anything. Only one outstanding change
11114 * detection can be scheduled per component tree.
11115 *
11116 * @param component Component to mark as dirty.
11117 */
11118function markDirty(component) {
11119 ngDevMode && assertDefined(component, 'component');
11120 const rootView = markViewDirty(getComponentViewByInstance(component));
11121 ngDevMode && assertDefined(rootView[CONTEXT], 'rootContext should be defined');
11122 scheduleTick(rootView[CONTEXT], 1 /* DetectChanges */);
11123}
11124/**
11125 * Used to perform change detection on the whole application.
11126 *
11127 * This is equivalent to `detectChanges`, but invoked on root component. Additionally, `tick`
11128 * executes lifecycle hooks and conditionally checks components based on their
11129 * `ChangeDetectionStrategy` and dirtiness.
11130 *
11131 * The preferred way to trigger change detection is to call `markDirty`. `markDirty` internally
11132 * schedules `tick` using a scheduler in order to coalesce multiple `markDirty` calls into a
11133 * single change detection run. By default, the scheduler is `requestAnimationFrame`, but can
11134 * be changed when calling `renderComponent` and providing the `scheduler` option.
11135 */
11136function tick(component) {
11137 const rootView = getRootView(component);
11138 const rootContext = rootView[CONTEXT];
11139 tickRootContext(rootContext);
11140}
11141
11142/**
11143 * @license
11144 * Copyright Google LLC All Rights Reserved.
11145 *
11146 * Use of this source code is governed by an MIT-style license that can be
11147 * found in the LICENSE file at https://angular.io/license
11148 */
11149/**
11150 * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors.
11151 *
11152 * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a
11153 * project.
11154 *
11155 * @publicApi
11156 */
11157const INJECTOR = new InjectionToken('INJECTOR',
11158// Dissable tslint because this is const enum which gets inlined not top level prop access.
11159// tslint:disable-next-line: no-toplevel-property-access
11160-1 /* Injector */);
11161
11162/**
11163 * @license
11164 * Copyright Google LLC All Rights Reserved.
11165 *
11166 * Use of this source code is governed by an MIT-style license that can be
11167 * found in the LICENSE file at https://angular.io/license
11168 */
11169class NullInjector {
11170 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
11171 if (notFoundValue === THROW_IF_NOT_FOUND) {
11172 const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`);
11173 error.name = 'NullInjectorError';
11174 throw error;
11175 }
11176 return notFoundValue;
11177 }
11178}
11179
11180/**
11181 * @license
11182 * Copyright Google LLC All Rights Reserved.
11183 *
11184 * Use of this source code is governed by an MIT-style license that can be
11185 * found in the LICENSE file at https://angular.io/license
11186 */
11187/**
11188 * An internal token whose presence in an injector indicates that the injector should treat itself
11189 * as a root scoped injector when processing requests for unknown tokens which may indicate
11190 * they are provided in the root scope.
11191 */
11192const INJECTOR_SCOPE = new InjectionToken('Set Injector scope.');
11193
11194/**
11195 * @license
11196 * Copyright Google LLC All Rights Reserved.
11197 *
11198 * Use of this source code is governed by an MIT-style license that can be
11199 * found in the LICENSE file at https://angular.io/license
11200 */
11201/**
11202 * Marker which indicates that a value has not yet been created from the factory function.
11203 */
11204const NOT_YET = {};
11205/**
11206 * Marker which indicates that the factory function for a token is in the process of being called.
11207 *
11208 * If the injector is asked to inject a token with its value set to CIRCULAR, that indicates
11209 * injection of a dependency has recursively attempted to inject the original token, and there is
11210 * a circular dependency among the providers.
11211 */
11212const CIRCULAR = {};
11213/**
11214 * A lazily initialized NullInjector.
11215 */
11216let NULL_INJECTOR$1 = undefined;
11217function getNullInjector() {
11218 if (NULL_INJECTOR$1 === undefined) {
11219 NULL_INJECTOR$1 = new NullInjector();
11220 }
11221 return NULL_INJECTOR$1;
11222}
11223/**
11224 * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s.
11225 *
11226 * @publicApi
11227 */
11228function createInjector(defType, parent = null, additionalProviders = null, name) {
11229 const injector = createInjectorWithoutInjectorInstances(defType, parent, additionalProviders, name);
11230 injector._resolveInjectorDefTypes();
11231 return injector;
11232}
11233/**
11234 * Creates a new injector without eagerly resolving its injector types. Can be used in places
11235 * where resolving the injector types immediately can lead to an infinite loop. The injector types
11236 * should be resolved at a later point by calling `_resolveInjectorDefTypes`.
11237 */
11238function createInjectorWithoutInjectorInstances(defType, parent = null, additionalProviders = null, name) {
11239 return new R3Injector(defType, additionalProviders, parent || getNullInjector(), name);
11240}
11241class R3Injector {
11242 constructor(def, additionalProviders, parent, source = null) {
11243 this.parent = parent;
11244 /**
11245 * Map of tokens to records which contain the instances of those tokens.
11246 * - `null` value implies that we don't have the record. Used by tree-shakable injectors
11247 * to prevent further searches.
11248 */
11249 this.records = new Map();
11250 /**
11251 * The transitive set of `InjectorType`s which define this injector.
11252 */
11253 this.injectorDefTypes = new Set();
11254 /**
11255 * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks.
11256 */
11257 this.onDestroy = new Set();
11258 this._destroyed = false;
11259 const dedupStack = [];
11260 // Start off by creating Records for every provider declared in every InjectorType
11261 // included transitively in additional providers then do the same for `def`. This order is
11262 // important because `def` may include providers that override ones in additionalProviders.
11263 additionalProviders &&
11264 deepForEach(additionalProviders, provider => this.processProvider(provider, def, additionalProviders));
11265 deepForEach([def], injectorDef => this.processInjectorType(injectorDef, [], dedupStack));
11266 // Make sure the INJECTOR token provides this injector.
11267 this.records.set(INJECTOR, makeRecord(undefined, this));
11268 // Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide
11269 // any injectable scoped to APP_ROOT_SCOPE.
11270 const record = this.records.get(INJECTOR_SCOPE);
11271 this.scope = record != null ? record.value : null;
11272 // Source name, used for debugging
11273 this.source = source || (typeof def === 'object' ? null : stringify(def));
11274 }
11275 /**
11276 * Flag indicating that this injector was previously destroyed.
11277 */
11278 get destroyed() {
11279 return this._destroyed;
11280 }
11281 /**
11282 * Destroy the injector and release references to every instance or provider associated with it.
11283 *
11284 * Also calls the `OnDestroy` lifecycle hooks of every instance that was created for which a
11285 * hook was found.
11286 */
11287 destroy() {
11288 this.assertNotDestroyed();
11289 // Set destroyed = true first, in case lifecycle hooks re-enter destroy().
11290 this._destroyed = true;
11291 try {
11292 // Call all the lifecycle hooks.
11293 this.onDestroy.forEach(service => service.ngOnDestroy());
11294 }
11295 finally {
11296 // Release all references.
11297 this.records.clear();
11298 this.onDestroy.clear();
11299 this.injectorDefTypes.clear();
11300 }
11301 }
11302 get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
11303 this.assertNotDestroyed();
11304 // Set the injection context.
11305 const previousInjector = setCurrentInjector(this);
11306 const previousInjectImplementation = setInjectImplementation(undefined);
11307 try {
11308 // Check for the SkipSelf flag.
11309 if (!(flags & InjectFlags.SkipSelf)) {
11310 // SkipSelf isn't set, check if the record belongs to this injector.
11311 let record = this.records.get(token);
11312 if (record === undefined) {
11313 // No record, but maybe the token is scoped to this injector. Look for an injectable
11314 // def with a scope matching this injector.
11315 const def = couldBeInjectableType(token) && getInjectableDef(token);
11316 if (def && this.injectableDefInScope(def)) {
11317 // Found an injectable def and it's scoped to this injector. Pretend as if it was here
11318 // all along.
11319 record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET);
11320 }
11321 else {
11322 record = null;
11323 }
11324 this.records.set(token, record);
11325 }
11326 // If a record was found, get the instance for it and return it.
11327 if (record != null /* NOT null || undefined */) {
11328 return this.hydrate(token, record);
11329 }
11330 }
11331 // Select the next injector based on the Self flag - if self is set, the next injector is
11332 // the NullInjector, otherwise it's the parent.
11333 const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector();
11334 // Set the notFoundValue based on the Optional flag - if optional is set and notFoundValue
11335 // is undefined, the value is null, otherwise it's the notFoundValue.
11336 notFoundValue = (flags & InjectFlags.Optional) && notFoundValue === THROW_IF_NOT_FOUND ?
11337 null :
11338 notFoundValue;
11339 return nextInjector.get(token, notFoundValue);
11340 }
11341 catch (e) {
11342 if (e.name === 'NullInjectorError') {
11343 const path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || [];
11344 path.unshift(stringify(token));
11345 if (previousInjector) {
11346 // We still have a parent injector, keep throwing
11347 throw e;
11348 }
11349 else {
11350 // Format & throw the final error message when we don't have any previous injector
11351 return catchInjectorError(e, token, 'R3InjectorError', this.source);
11352 }
11353 }
11354 else {
11355 throw e;
11356 }
11357 }
11358 finally {
11359 // Lastly, restore the previous injection context.
11360 setInjectImplementation(previousInjectImplementation);
11361 setCurrentInjector(previousInjector);
11362 }
11363 }
11364 /** @internal */
11365 _resolveInjectorDefTypes() {
11366 this.injectorDefTypes.forEach(defType => this.get(defType));
11367 }
11368 toString() {
11369 const tokens = [], records = this.records;
11370 records.forEach((v, token) => tokens.push(stringify(token)));
11371 return `R3Injector[${tokens.join(', ')}]`;
11372 }
11373 assertNotDestroyed() {
11374 if (this._destroyed) {
11375 throw new RuntimeError(205 /* INJECTOR_ALREADY_DESTROYED */, ngDevMode && 'Injector has already been destroyed.');
11376 }
11377 }
11378 /**
11379 * Add an `InjectorType` or `InjectorTypeWithProviders` and all of its transitive providers
11380 * to this injector.
11381 *
11382 * If an `InjectorTypeWithProviders` that declares providers besides the type is specified,
11383 * the function will return "true" to indicate that the providers of the type definition need
11384 * to be processed. This allows us to process providers of injector types after all imports of
11385 * an injector definition are processed. (following View Engine semantics: see FW-1349)
11386 */
11387 processInjectorType(defOrWrappedDef, parents, dedupStack) {
11388 defOrWrappedDef = resolveForwardRef(defOrWrappedDef);
11389 if (!defOrWrappedDef)
11390 return false;
11391 // Either the defOrWrappedDef is an InjectorType (with injector def) or an
11392 // InjectorDefTypeWithProviders (aka ModuleWithProviders). Detecting either is a megamorphic
11393 // read, so care is taken to only do the read once.
11394 // First attempt to read the injector def (`ɵinj`).
11395 let def = getInjectorDef(defOrWrappedDef);
11396 // If that's not present, then attempt to read ngModule from the InjectorDefTypeWithProviders.
11397 const ngModule = (def == null) && defOrWrappedDef.ngModule || undefined;
11398 // Determine the InjectorType. In the case where `defOrWrappedDef` is an `InjectorType`,
11399 // then this is easy. In the case of an InjectorDefTypeWithProviders, then the definition type
11400 // is the `ngModule`.
11401 const defType = (ngModule === undefined) ? defOrWrappedDef : ngModule;
11402 // Check for circular dependencies.
11403 if (ngDevMode && parents.indexOf(defType) !== -1) {
11404 const defName = stringify(defType);
11405 const path = parents.map(stringify);
11406 throwCyclicDependencyError(defName, path);
11407 }
11408 // Check for multiple imports of the same module
11409 const isDuplicate = dedupStack.indexOf(defType) !== -1;
11410 // Finally, if defOrWrappedType was an `InjectorDefTypeWithProviders`, then the actual
11411 // `InjectorDef` is on its `ngModule`.
11412 if (ngModule !== undefined) {
11413 def = getInjectorDef(ngModule);
11414 }
11415 // If no definition was found, it might be from exports. Remove it.
11416 if (def == null) {
11417 return false;
11418 }
11419 // Add providers in the same way that @NgModule resolution did:
11420 // First, include providers from any imports.
11421 if (def.imports != null && !isDuplicate) {
11422 // Before processing defType's imports, add it to the set of parents. This way, if it ends
11423 // up deeply importing itself, this can be detected.
11424 ngDevMode && parents.push(defType);
11425 // Add it to the set of dedups. This way we can detect multiple imports of the same module
11426 dedupStack.push(defType);
11427 let importTypesWithProviders;
11428 try {
11429 deepForEach(def.imports, imported => {
11430 if (this.processInjectorType(imported, parents, dedupStack)) {
11431 if (importTypesWithProviders === undefined)
11432 importTypesWithProviders = [];
11433 // If the processed import is an injector type with providers, we store it in the
11434 // list of import types with providers, so that we can process those afterwards.
11435 importTypesWithProviders.push(imported);
11436 }
11437 });
11438 }
11439 finally {
11440 // Remove it from the parents set when finished.
11441 ngDevMode && parents.pop();
11442 }
11443 // Imports which are declared with providers (TypeWithProviders) need to be processed
11444 // after all imported modules are processed. This is similar to how View Engine
11445 // processes/merges module imports in the metadata resolver. See: FW-1349.
11446 if (importTypesWithProviders !== undefined) {
11447 for (let i = 0; i < importTypesWithProviders.length; i++) {
11448 const { ngModule, providers } = importTypesWithProviders[i];
11449 deepForEach(providers, provider => this.processProvider(provider, ngModule, providers || EMPTY_ARRAY));
11450 }
11451 }
11452 }
11453 // Track the InjectorType and add a provider for it. It's important that this is done after the
11454 // def's imports.
11455 this.injectorDefTypes.add(defType);
11456 const factory = getFactoryDef(defType) || (() => new defType());
11457 this.records.set(defType, makeRecord(factory, NOT_YET));
11458 // Next, include providers listed on the definition itself.
11459 const defProviders = def.providers;
11460 if (defProviders != null && !isDuplicate) {
11461 const injectorType = defOrWrappedDef;
11462 deepForEach(defProviders, provider => this.processProvider(provider, injectorType, defProviders));
11463 }
11464 return (ngModule !== undefined &&
11465 defOrWrappedDef.providers !== undefined);
11466 }
11467 /**
11468 * Process a `SingleProvider` and add it.
11469 */
11470 processProvider(provider, ngModuleType, providers) {
11471 // Determine the token from the provider. Either it's its own token, or has a {provide: ...}
11472 // property.
11473 provider = resolveForwardRef(provider);
11474 let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider && provider.provide);
11475 // Construct a `Record` for the provider.
11476 const record = providerToRecord(provider, ngModuleType, providers);
11477 if (!isTypeProvider(provider) && provider.multi === true) {
11478 // If the provider indicates that it's a multi-provider, process it specially.
11479 // First check whether it's been defined already.
11480 let multiRecord = this.records.get(token);
11481 if (multiRecord) {
11482 // It has. Throw a nice error if
11483 if (ngDevMode && multiRecord.multi === undefined) {
11484 throwMixedMultiProviderError();
11485 }
11486 }
11487 else {
11488 multiRecord = makeRecord(undefined, NOT_YET, true);
11489 multiRecord.factory = () => injectArgs(multiRecord.multi);
11490 this.records.set(token, multiRecord);
11491 }
11492 token = provider;
11493 multiRecord.multi.push(provider);
11494 }
11495 else {
11496 const existing = this.records.get(token);
11497 if (ngDevMode && existing && existing.multi !== undefined) {
11498 throwMixedMultiProviderError();
11499 }
11500 }
11501 this.records.set(token, record);
11502 }
11503 hydrate(token, record) {
11504 if (ngDevMode && record.value === CIRCULAR) {
11505 throwCyclicDependencyError(stringify(token));
11506 }
11507 else if (record.value === NOT_YET) {
11508 record.value = CIRCULAR;
11509 record.value = record.factory();
11510 }
11511 if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) {
11512 this.onDestroy.add(record.value);
11513 }
11514 return record.value;
11515 }
11516 injectableDefInScope(def) {
11517 if (!def.providedIn) {
11518 return false;
11519 }
11520 const providedIn = resolveForwardRef(def.providedIn);
11521 if (typeof providedIn === 'string') {
11522 return providedIn === 'any' || (providedIn === this.scope);
11523 }
11524 else {
11525 return this.injectorDefTypes.has(providedIn);
11526 }
11527 }
11528}
11529function injectableDefOrInjectorDefFactory(token) {
11530 // Most tokens will have an injectable def directly on them, which specifies a factory directly.
11531 const injectableDef = getInjectableDef(token);
11532 const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token);
11533 if (factory !== null) {
11534 return factory;
11535 }
11536 // InjectionTokens should have an injectable def (ɵprov) and thus should be handled above.
11537 // If it's missing that, it's an error.
11538 if (token instanceof InjectionToken) {
11539 throw new RuntimeError(204 /* INVALID_INJECTION_TOKEN */, ngDevMode && `Token ${stringify(token)} is missing a ɵprov definition.`);
11540 }
11541 // Undecorated types can sometimes be created if they have no constructor arguments.
11542 if (token instanceof Function) {
11543 return getUndecoratedInjectableFactory(token);
11544 }
11545 // There was no way to resolve a factory for this token.
11546 throw new RuntimeError(204 /* INVALID_INJECTION_TOKEN */, ngDevMode && 'unreachable');
11547}
11548function getUndecoratedInjectableFactory(token) {
11549 // If the token has parameters then it has dependencies that we cannot resolve implicitly.
11550 const paramLength = token.length;
11551 if (paramLength > 0) {
11552 const args = newArray(paramLength, '?');
11553 throw new RuntimeError(204 /* INVALID_INJECTION_TOKEN */, ngDevMode && `Can't resolve all parameters for ${stringify(token)}: (${args.join(', ')}).`);
11554 }
11555 // The constructor function appears to have no parameters.
11556 // This might be because it inherits from a super-class. In which case, use an injectable
11557 // def from an ancestor if there is one.
11558 // Otherwise this really is a simple class with no dependencies, so return a factory that
11559 // just instantiates the zero-arg constructor.
11560 const inheritedInjectableDef = getInheritedInjectableDef(token);
11561 if (inheritedInjectableDef !== null) {
11562 return () => inheritedInjectableDef.factory(token);
11563 }
11564 else {
11565 return () => new token();
11566 }
11567}
11568function providerToRecord(provider, ngModuleType, providers) {
11569 if (isValueProvider(provider)) {
11570 return makeRecord(undefined, provider.useValue);
11571 }
11572 else {
11573 const factory = providerToFactory(provider, ngModuleType, providers);
11574 return makeRecord(factory, NOT_YET);
11575 }
11576}
11577/**
11578 * Converts a `SingleProvider` into a factory function.
11579 *
11580 * @param provider provider to convert to factory
11581 */
11582function providerToFactory(provider, ngModuleType, providers) {
11583 let factory = undefined;
11584 if (isTypeProvider(provider)) {
11585 const unwrappedProvider = resolveForwardRef(provider);
11586 return getFactoryDef(unwrappedProvider) || injectableDefOrInjectorDefFactory(unwrappedProvider);
11587 }
11588 else {
11589 if (isValueProvider(provider)) {
11590 factory = () => resolveForwardRef(provider.useValue);
11591 }
11592 else if (isFactoryProvider(provider)) {
11593 factory = () => provider.useFactory(...injectArgs(provider.deps || []));
11594 }
11595 else if (isExistingProvider(provider)) {
11596 factory = () => ɵɵinject(resolveForwardRef(provider.useExisting));
11597 }
11598 else {
11599 const classRef = resolveForwardRef(provider &&
11600 (provider.useClass || provider.provide));
11601 if (ngDevMode && !classRef) {
11602 throwInvalidProviderError(ngModuleType, providers, provider);
11603 }
11604 if (hasDeps(provider)) {
11605 factory = () => new (classRef)(...injectArgs(provider.deps));
11606 }
11607 else {
11608 return getFactoryDef(classRef) || injectableDefOrInjectorDefFactory(classRef);
11609 }
11610 }
11611 }
11612 return factory;
11613}
11614function makeRecord(factory, value, multi = false) {
11615 return {
11616 factory: factory,
11617 value: value,
11618 multi: multi ? [] : undefined,
11619 };
11620}
11621function isValueProvider(value) {
11622 return value !== null && typeof value == 'object' && USE_VALUE$1 in value;
11623}
11624function isExistingProvider(value) {
11625 return !!(value && value.useExisting);
11626}
11627function isFactoryProvider(value) {
11628 return !!(value && value.useFactory);
11629}
11630function isTypeProvider(value) {
11631 return typeof value === 'function';
11632}
11633function isClassProvider(value) {
11634 return !!value.useClass;
11635}
11636function hasDeps(value) {
11637 return !!value.deps;
11638}
11639function hasOnDestroy(value) {
11640 return value !== null && typeof value === 'object' &&
11641 typeof value.ngOnDestroy === 'function';
11642}
11643function couldBeInjectableType(value) {
11644 return (typeof value === 'function') ||
11645 (typeof value === 'object' && value instanceof InjectionToken);
11646}
11647
11648/**
11649 * @license
11650 * Copyright Google LLC All Rights Reserved.
11651 *
11652 * Use of this source code is governed by an MIT-style license that can be
11653 * found in the LICENSE file at https://angular.io/license
11654 */
11655/**
11656 * Concrete injectors implement this interface. Injectors are configured
11657 * with [providers](guide/glossary#provider) that associate
11658 * dependencies of various types with [injection tokens](guide/glossary#di-token).
11659 *
11660 * @see ["DI Providers"](guide/dependency-injection-providers).
11661 * @see `StaticProvider`
11662 *
11663 * @usageNotes
11664 *
11665 * The following example creates a service injector instance.
11666 *
11667 * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
11668 *
11669 * ### Usage example
11670 *
11671 * {@example core/di/ts/injector_spec.ts region='Injector'}
11672 *
11673 * `Injector` returns itself when given `Injector` as a token:
11674 *
11675 * {@example core/di/ts/injector_spec.ts region='injectInjector'}
11676 *
11677 * @publicApi
11678 */
11679class Injector {
11680 static create(options, parent) {
11681 if (Array.isArray(options)) {
11682 return createInjector({ name: '' }, parent, options, '');
11683 }
11684 else {
11685 const name = options.name ?? '';
11686 return createInjector({ name }, options.parent, options.providers, name);
11687 }
11688 }
11689}
11690Injector.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
11691Injector.NULL = ( /* @__PURE__ */new NullInjector());
11692/** @nocollapse */
11693Injector.ɵprov = ɵɵdefineInjectable({
11694 token: Injector,
11695 providedIn: 'any',
11696 factory: () => ɵɵinject(INJECTOR),
11697});
11698/**
11699 * @internal
11700 * @nocollapse
11701 */
11702Injector.__NG_ELEMENT_ID__ = -1 /* Injector */;
11703
11704/**
11705 * @license
11706 * Copyright Google LLC All Rights Reserved.
11707 *
11708 * Use of this source code is governed by an MIT-style license that can be
11709 * found in the LICENSE file at https://angular.io/license
11710 */
11711/**
11712 * Retrieves the component instance associated with a given DOM element.
11713 *
11714 * @usageNotes
11715 * Given the following DOM structure:
11716 *
11717 * ```html
11718 * <app-root>
11719 * <div>
11720 * <child-comp></child-comp>
11721 * </div>
11722 * </app-root>
11723 * ```
11724 *
11725 * Calling `getComponent` on `<child-comp>` will return the instance of `ChildComponent`
11726 * associated with this DOM element.
11727 *
11728 * Calling the function on `<app-root>` will return the `MyApp` instance.
11729 *
11730 *
11731 * @param element DOM element from which the component should be retrieved.
11732 * @returns Component instance associated with the element or `null` if there
11733 * is no component associated with it.
11734 *
11735 * @publicApi
11736 * @globalApi ng
11737 */
11738function getComponent$1(element) {
11739 assertDomElement(element);
11740 const context = getLContext(element);
11741 if (context === null)
11742 return null;
11743 if (context.component === undefined) {
11744 context.component = getComponentAtNodeIndex(context.nodeIndex, context.lView);
11745 }
11746 return context.component;
11747}
11748/**
11749 * If inside an embedded view (e.g. `*ngIf` or `*ngFor`), retrieves the context of the embedded
11750 * view that the element is part of. Otherwise retrieves the instance of the component whose view
11751 * owns the element (in this case, the result is the same as calling `getOwningComponent`).
11752 *
11753 * @param element Element for which to get the surrounding component instance.
11754 * @returns Instance of the component that is around the element or null if the element isn't
11755 * inside any component.
11756 *
11757 * @publicApi
11758 * @globalApi ng
11759 */
11760function getContext(element) {
11761 assertDomElement(element);
11762 const context = getLContext(element);
11763 return context === null ? null : context.lView[CONTEXT];
11764}
11765/**
11766 * Retrieves the component instance whose view contains the DOM element.
11767 *
11768 * For example, if `<child-comp>` is used in the template of `<app-comp>`
11769 * (i.e. a `ViewChild` of `<app-comp>`), calling `getOwningComponent` on `<child-comp>`
11770 * would return `<app-comp>`.
11771 *
11772 * @param elementOrDir DOM element, component or directive instance
11773 * for which to retrieve the root components.
11774 * @returns Component instance whose view owns the DOM element or null if the element is not
11775 * part of a component view.
11776 *
11777 * @publicApi
11778 * @globalApi ng
11779 */
11780function getOwningComponent(elementOrDir) {
11781 const context = getLContext(elementOrDir);
11782 if (context === null)
11783 return null;
11784 let lView = context.lView;
11785 let parent;
11786 ngDevMode && assertLView(lView);
11787 while (lView[TVIEW].type === 2 /* Embedded */ && (parent = getLViewParent(lView))) {
11788 lView = parent;
11789 }
11790 return lView[FLAGS] & 512 /* IsRoot */ ? null : lView[CONTEXT];
11791}
11792/**
11793 * Retrieves all root components associated with a DOM element, directive or component instance.
11794 * Root components are those which have been bootstrapped by Angular.
11795 *
11796 * @param elementOrDir DOM element, component or directive instance
11797 * for which to retrieve the root components.
11798 * @returns Root components associated with the target object.
11799 *
11800 * @publicApi
11801 * @globalApi ng
11802 */
11803function getRootComponents(elementOrDir) {
11804 return [...getRootContext(elementOrDir).components];
11805}
11806/**
11807 * Retrieves an `Injector` associated with an element, component or directive instance.
11808 *
11809 * @param elementOrDir DOM element, component or directive instance for which to
11810 * retrieve the injector.
11811 * @returns Injector associated with the element, component or directive instance.
11812 *
11813 * @publicApi
11814 * @globalApi ng
11815 */
11816function getInjector(elementOrDir) {
11817 const context = getLContext(elementOrDir);
11818 if (context === null)
11819 return Injector.NULL;
11820 const tNode = context.lView[TVIEW].data[context.nodeIndex];
11821 return new NodeInjector(tNode, context.lView);
11822}
11823/**
11824 * Retrieve a set of injection tokens at a given DOM node.
11825 *
11826 * @param element Element for which the injection tokens should be retrieved.
11827 */
11828function getInjectionTokens(element) {
11829 const context = getLContext(element);
11830 if (context === null)
11831 return [];
11832 const lView = context.lView;
11833 const tView = lView[TVIEW];
11834 const tNode = tView.data[context.nodeIndex];
11835 const providerTokens = [];
11836 const startIndex = tNode.providerIndexes & 1048575 /* ProvidersStartIndexMask */;
11837 const endIndex = tNode.directiveEnd;
11838 for (let i = startIndex; i < endIndex; i++) {
11839 let value = tView.data[i];
11840 if (isDirectiveDefHack(value)) {
11841 // The fact that we sometimes store Type and sometimes DirectiveDef in this location is a
11842 // design flaw. We should always store same type so that we can be monomorphic. The issue
11843 // is that for Components/Directives we store the def instead the type. The correct behavior
11844 // is that we should always be storing injectable type in this location.
11845 value = value.type;
11846 }
11847 providerTokens.push(value);
11848 }
11849 return providerTokens;
11850}
11851/**
11852 * Retrieves directive instances associated with a given DOM node. Does not include
11853 * component instances.
11854 *
11855 * @usageNotes
11856 * Given the following DOM structure:
11857 *
11858 * ```html
11859 * <app-root>
11860 * <button my-button></button>
11861 * <my-comp></my-comp>
11862 * </app-root>
11863 * ```
11864 *
11865 * Calling `getDirectives` on `<button>` will return an array with an instance of the `MyButton`
11866 * directive that is associated with the DOM node.
11867 *
11868 * Calling `getDirectives` on `<my-comp>` will return an empty array.
11869 *
11870 * @param node DOM node for which to get the directives.
11871 * @returns Array of directives associated with the node.
11872 *
11873 * @publicApi
11874 * @globalApi ng
11875 */
11876function getDirectives(node) {
11877 // Skip text nodes because we can't have directives associated with them.
11878 if (node instanceof Text) {
11879 return [];
11880 }
11881 const context = getLContext(node);
11882 if (context === null) {
11883 return [];
11884 }
11885 const lView = context.lView;
11886 const tView = lView[TVIEW];
11887 const nodeIndex = context.nodeIndex;
11888 if (!tView?.data[nodeIndex]) {
11889 return [];
11890 }
11891 if (context.directives === undefined) {
11892 context.directives = getDirectivesAtNodeIndex(nodeIndex, lView, false);
11893 }
11894 // The `directives` in this case are a named array called `LComponentView`. Clone the
11895 // result so we don't expose an internal data structure in the user's console.
11896 return context.directives === null ? [] : [...context.directives];
11897}
11898/**
11899 * Returns the debug (partial) metadata for a particular directive or component instance.
11900 * The function accepts an instance of a directive or component and returns the corresponding
11901 * metadata.
11902 *
11903 * @param directiveOrComponentInstance Instance of a directive or component
11904 * @returns metadata of the passed directive or component
11905 *
11906 * @publicApi
11907 * @globalApi ng
11908 */
11909function getDirectiveMetadata$1(directiveOrComponentInstance) {
11910 const { constructor } = directiveOrComponentInstance;
11911 if (!constructor) {
11912 throw new Error('Unable to find the instance constructor');
11913 }
11914 // In case a component inherits from a directive, we may have component and directive metadata
11915 // To ensure we don't get the metadata of the directive, we want to call `getComponentDef` first.
11916 const componentDef = getComponentDef(constructor);
11917 if (componentDef) {
11918 return {
11919 inputs: componentDef.inputs,
11920 outputs: componentDef.outputs,
11921 encapsulation: componentDef.encapsulation,
11922 changeDetection: componentDef.onPush ? ChangeDetectionStrategy.OnPush :
11923 ChangeDetectionStrategy.Default
11924 };
11925 }
11926 const directiveDef = getDirectiveDef(constructor);
11927 if (directiveDef) {
11928 return { inputs: directiveDef.inputs, outputs: directiveDef.outputs };
11929 }
11930 return null;
11931}
11932/**
11933 * Retrieve map of local references.
11934 *
11935 * The references are retrieved as a map of local reference name to element or directive instance.
11936 *
11937 * @param target DOM element, component or directive instance for which to retrieve
11938 * the local references.
11939 */
11940function getLocalRefs(target) {
11941 const context = getLContext(target);
11942 if (context === null)
11943 return {};
11944 if (context.localRefs === undefined) {
11945 context.localRefs = discoverLocalRefs(context.lView, context.nodeIndex);
11946 }
11947 return context.localRefs || {};
11948}
11949/**
11950 * Retrieves the host element of a component or directive instance.
11951 * The host element is the DOM element that matched the selector of the directive.
11952 *
11953 * @param componentOrDirective Component or directive instance for which the host
11954 * element should be retrieved.
11955 * @returns Host element of the target.
11956 *
11957 * @publicApi
11958 * @globalApi ng
11959 */
11960function getHostElement(componentOrDirective) {
11961 return getLContext(componentOrDirective).native;
11962}
11963/**
11964 * Retrieves the rendered text for a given component.
11965 *
11966 * This function retrieves the host element of a component and
11967 * and then returns the `textContent` for that element. This implies
11968 * that the text returned will include re-projected content of
11969 * the component as well.
11970 *
11971 * @param component The component to return the content text for.
11972 */
11973function getRenderedText(component) {
11974 const hostElement = getHostElement(component);
11975 return hostElement.textContent || '';
11976}
11977/**
11978 * Retrieves a list of event listeners associated with a DOM element. The list does include host
11979 * listeners, but it does not include event listeners defined outside of the Angular context
11980 * (e.g. through `addEventListener`).
11981 *
11982 * @usageNotes
11983 * Given the following DOM structure:
11984 *
11985 * ```html
11986 * <app-root>
11987 * <div (click)="doSomething()"></div>
11988 * </app-root>
11989 * ```
11990 *
11991 * Calling `getListeners` on `<div>` will return an object that looks as follows:
11992 *
11993 * ```ts
11994 * {
11995 * name: 'click',
11996 * element: <div>,
11997 * callback: () => doSomething(),
11998 * useCapture: false
11999 * }
12000 * ```
12001 *
12002 * @param element Element for which the DOM listeners should be retrieved.
12003 * @returns Array of event listeners on the DOM element.
12004 *
12005 * @publicApi
12006 * @globalApi ng
12007 */
12008function getListeners(element) {
12009 assertDomElement(element);
12010 const lContext = getLContext(element);
12011 if (lContext === null)
12012 return [];
12013 const lView = lContext.lView;
12014 const tView = lView[TVIEW];
12015 const lCleanup = lView[CLEANUP];
12016 const tCleanup = tView.cleanup;
12017 const listeners = [];
12018 if (tCleanup && lCleanup) {
12019 for (let i = 0; i < tCleanup.length;) {
12020 const firstParam = tCleanup[i++];
12021 const secondParam = tCleanup[i++];
12022 if (typeof firstParam === 'string') {
12023 const name = firstParam;
12024 const listenerElement = unwrapRNode(lView[secondParam]);
12025 const callback = lCleanup[tCleanup[i++]];
12026 const useCaptureOrIndx = tCleanup[i++];
12027 // if useCaptureOrIndx is boolean then report it as is.
12028 // if useCaptureOrIndx is positive number then it in unsubscribe method
12029 // if useCaptureOrIndx is negative number then it is a Subscription
12030 const type = (typeof useCaptureOrIndx === 'boolean' || useCaptureOrIndx >= 0) ? 'dom' : 'output';
12031 const useCapture = typeof useCaptureOrIndx === 'boolean' ? useCaptureOrIndx : false;
12032 if (element == listenerElement) {
12033 listeners.push({ element, name, callback, useCapture, type });
12034 }
12035 }
12036 }
12037 }
12038 listeners.sort(sortListeners);
12039 return listeners;
12040}
12041function sortListeners(a, b) {
12042 if (a.name == b.name)
12043 return 0;
12044 return a.name < b.name ? -1 : 1;
12045}
12046/**
12047 * This function should not exist because it is megamorphic and only mostly correct.
12048 *
12049 * See call site for more info.
12050 */
12051function isDirectiveDefHack(obj) {
12052 return obj.type !== undefined && obj.template !== undefined && obj.declaredInputs !== undefined;
12053}
12054/**
12055 * Returns the attached `DebugNode` instance for an element in the DOM.
12056 *
12057 * @param element DOM element which is owned by an existing component's view.
12058 */
12059function getDebugNode$1(element) {
12060 if (ngDevMode && !(element instanceof Node)) {
12061 throw new Error('Expecting instance of DOM Element');
12062 }
12063 const lContext = getLContext(element);
12064 if (lContext === null) {
12065 return null;
12066 }
12067 const lView = lContext.lView;
12068 const nodeIndex = lContext.nodeIndex;
12069 if (nodeIndex !== -1) {
12070 const valueInLView = lView[nodeIndex];
12071 // this means that value in the lView is a component with its own
12072 // data. In this situation the TNode is not accessed at the same spot.
12073 const tNode = isLView(valueInLView) ? valueInLView[T_HOST] : getTNode(lView[TVIEW], nodeIndex);
12074 ngDevMode &&
12075 assertEqual(tNode.index, nodeIndex, 'Expecting that TNode at index is same as index');
12076 return buildDebugNode(tNode, lView);
12077 }
12078 return null;
12079}
12080/**
12081 * Retrieve the component `LView` from component/element.
12082 *
12083 * NOTE: `LView` is a private and should not be leaked outside.
12084 * Don't export this method to `ng.*` on window.
12085 *
12086 * @param target DOM element or component instance for which to retrieve the LView.
12087 */
12088function getComponentLView(target) {
12089 const lContext = getLContext(target);
12090 const nodeIndx = lContext.nodeIndex;
12091 const lView = lContext.lView;
12092 const componentLView = lView[nodeIndx];
12093 ngDevMode && assertLView(componentLView);
12094 return componentLView;
12095}
12096/** Asserts that a value is a DOM Element. */
12097function assertDomElement(value) {
12098 if (typeof Element !== 'undefined' && !(value instanceof Element)) {
12099 throw new Error('Expecting instance of DOM Element');
12100 }
12101}
12102
12103/**
12104 * @license
12105 * Copyright Google LLC All Rights Reserved.
12106 *
12107 * Use of this source code is governed by an MIT-style license that can be
12108 * found in the LICENSE file at https://angular.io/license
12109 */
12110/**
12111 * Marks a component for check (in case of OnPush components) and synchronously
12112 * performs change detection on the application this component belongs to.
12113 *
12114 * @param component Component to {@link ChangeDetectorRef#markForCheck mark for check}.
12115 *
12116 * @publicApi
12117 * @globalApi ng
12118 */
12119function applyChanges(component) {
12120 markDirty(component);
12121 getRootComponents(component).forEach(rootComponent => detectChanges(rootComponent));
12122}
12123
12124/**
12125 * @license
12126 * Copyright Google LLC All Rights Reserved.
12127 *
12128 * Use of this source code is governed by an MIT-style license that can be
12129 * found in the LICENSE file at https://angular.io/license
12130 */
12131/**
12132 * This file introduces series of globally accessible debug tools
12133 * to allow for the Angular debugging story to function.
12134 *
12135 * To see this in action run the following command:
12136 *
12137 * bazel run //packages/core/test/bundling/todo:devserver
12138 *
12139 * Then load `localhost:5432` and start using the console tools.
12140 */
12141/**
12142 * This value reflects the property on the window where the dev
12143 * tools are patched (window.ng).
12144 * */
12145const GLOBAL_PUBLISH_EXPANDO_KEY = 'ng';
12146let _published = false;
12147/**
12148 * Publishes a collection of default debug tools onto`window.ng`.
12149 *
12150 * These functions are available globally when Angular is in development
12151 * mode and are automatically stripped away from prod mode is on.
12152 */
12153function publishDefaultGlobalUtils$1() {
12154 if (!_published) {
12155 _published = true;
12156 /**
12157 * Warning: this function is *INTERNAL* and should not be relied upon in application's code.
12158 * The contract of the function might be changed in any release and/or the function can be
12159 * removed completely.
12160 */
12161 publishGlobalUtil('ɵsetProfiler', setProfiler);
12162 publishGlobalUtil('getDirectiveMetadata', getDirectiveMetadata$1);
12163 publishGlobalUtil('getComponent', getComponent$1);
12164 publishGlobalUtil('getContext', getContext);
12165 publishGlobalUtil('getListeners', getListeners);
12166 publishGlobalUtil('getOwningComponent', getOwningComponent);
12167 publishGlobalUtil('getHostElement', getHostElement);
12168 publishGlobalUtil('getInjector', getInjector);
12169 publishGlobalUtil('getRootComponents', getRootComponents);
12170 publishGlobalUtil('getDirectives', getDirectives);
12171 publishGlobalUtil('applyChanges', applyChanges);
12172 }
12173}
12174/**
12175 * Publishes the given function to `window.ng` so that it can be
12176 * used from the browser console when an application is not in production.
12177 */
12178function publishGlobalUtil(name, fn) {
12179 if (typeof COMPILED === 'undefined' || !COMPILED) {
12180 // Note: we can't export `ng` when using closure enhanced optimization as:
12181 // - closure declares globals itself for minified names, which sometimes clobber our `ng` global
12182 // - we can't declare a closure extern as the namespace `ng` is already used within Google
12183 // for typings for AngularJS (via `goog.provide('ng....')`).
12184 const w = _global;
12185 ngDevMode && assertDefined(fn, 'function not defined');
12186 if (w) {
12187 let container = w[GLOBAL_PUBLISH_EXPANDO_KEY];
12188 if (!container) {
12189 container = w[GLOBAL_PUBLISH_EXPANDO_KEY] = {};
12190 }
12191 container[name] = fn;
12192 }
12193 }
12194}
12195
12196/**
12197 * @license
12198 * Copyright Google LLC All Rights Reserved.
12199 *
12200 * Use of this source code is governed by an MIT-style license that can be
12201 * found in the LICENSE file at https://angular.io/license
12202 */
12203// TODO: A hack to not pull in the NullInjector from @angular/core.
12204const NULL_INJECTOR = {
12205 get: (token, notFoundValue) => {
12206 throwProviderNotFoundError(token, 'NullInjector');
12207 }
12208};
12209/**
12210 * Bootstraps a Component into an existing host element and returns an instance
12211 * of the component.
12212 *
12213 * Use this function to bootstrap a component into the DOM tree. Each invocation
12214 * of this function will create a separate tree of components, injectors and
12215 * change detection cycles and lifetimes. To dynamically insert a new component
12216 * into an existing tree such that it shares the same injection, change detection
12217 * and object lifetime, use {@link ViewContainer#createComponent}.
12218 *
12219 * @param componentType Component to bootstrap
12220 * @param options Optional parameters which control bootstrapping
12221 */
12222function renderComponent(componentType /* Type as workaround for: Microsoft/TypeScript/issues/4881 */, opts = {}) {
12223 ngDevMode && publishDefaultGlobalUtils$1();
12224 ngDevMode && assertComponentType(componentType);
12225 const rendererFactory = opts.rendererFactory || domRendererFactory3;
12226 const sanitizer = opts.sanitizer || null;
12227 const componentDef = getComponentDef(componentType);
12228 if (componentDef.type != componentType)
12229 componentDef.type = componentType;
12230 // The first index of the first selector is the tag name.
12231 const componentTag = componentDef.selectors[0][0];
12232 const hostRenderer = rendererFactory.createRenderer(null, null);
12233 const hostRNode = locateHostElement(hostRenderer, opts.host || componentTag, componentDef.encapsulation);
12234 const rootFlags = componentDef.onPush ? 64 /* Dirty */ | 512 /* IsRoot */ :
12235 16 /* CheckAlways */ | 512 /* IsRoot */;
12236 const rootContext = createRootContext(opts.scheduler, opts.playerHandler);
12237 const renderer = rendererFactory.createRenderer(hostRNode, componentDef);
12238 const rootTView = createTView(0 /* Root */, null, null, 1, 0, null, null, null, null, null);
12239 const rootView = createLView(null, rootTView, rootContext, rootFlags, null, null, rendererFactory, renderer, null, opts.injector || null);
12240 enterView(rootView);
12241 let component;
12242 try {
12243 if (rendererFactory.begin)
12244 rendererFactory.begin();
12245 const componentView = createRootComponentView(hostRNode, componentDef, rootView, rendererFactory, renderer, sanitizer);
12246 component = createRootComponent(componentView, componentDef, rootView, rootContext, opts.hostFeatures || null);
12247 // create mode pass
12248 renderView(rootTView, rootView, null);
12249 // update mode pass
12250 refreshView(rootTView, rootView, null, null);
12251 }
12252 finally {
12253 leaveView();
12254 if (rendererFactory.end)
12255 rendererFactory.end();
12256 }
12257 return component;
12258}
12259/**
12260 * Creates the root component view and the root component node.
12261 *
12262 * @param rNode Render host element.
12263 * @param def ComponentDef
12264 * @param rootView The parent view where the host node is stored
12265 * @param rendererFactory Factory to be used for creating child renderers.
12266 * @param hostRenderer The current renderer
12267 * @param sanitizer The sanitizer, if provided
12268 *
12269 * @returns Component view created
12270 */
12271function createRootComponentView(rNode, def, rootView, rendererFactory, hostRenderer, sanitizer) {
12272 const tView = rootView[TVIEW];
12273 const index = HEADER_OFFSET;
12274 ngDevMode && assertIndexInRange(rootView, index);
12275 rootView[index] = rNode;
12276 // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
12277 // the same time we want to communicate the debug `TNode` that this is a special `TNode`
12278 // representing a host element.
12279 const tNode = getOrCreateTNode(tView, index, 2 /* Element */, '#host', null);
12280 const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
12281 if (mergedAttrs !== null) {
12282 computeStaticStyling(tNode, mergedAttrs, true);
12283 if (rNode !== null) {
12284 setUpAttributes(hostRenderer, rNode, mergedAttrs);
12285 if (tNode.classes !== null) {
12286 writeDirectClass(hostRenderer, rNode, tNode.classes);
12287 }
12288 if (tNode.styles !== null) {
12289 writeDirectStyle(hostRenderer, rNode, tNode.styles);
12290 }
12291 }
12292 }
12293 const viewRenderer = rendererFactory.createRenderer(rNode, def);
12294 const componentView = createLView(rootView, getOrCreateTComponentView(def), null, def.onPush ? 64 /* Dirty */ : 16 /* CheckAlways */, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null);
12295 if (tView.firstCreatePass) {
12296 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, def.type);
12297 markAsComponentHost(tView, tNode);
12298 initTNodeFlags(tNode, rootView.length, 1);
12299 }
12300 addToViewTree(rootView, componentView);
12301 // Store component view at node index, with node as the HOST
12302 return rootView[index] = componentView;
12303}
12304/**
12305 * Creates a root component and sets it up with features and host bindings. Shared by
12306 * renderComponent() and ViewContainerRef.createComponent().
12307 */
12308function createRootComponent(componentView, componentDef, rootLView, rootContext, hostFeatures) {
12309 const tView = rootLView[TVIEW];
12310 // Create directive instance with factory() and store at next index in viewData
12311 const component = instantiateRootComponent(tView, rootLView, componentDef);
12312 rootContext.components.push(component);
12313 componentView[CONTEXT] = component;
12314 hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
12315 // We want to generate an empty QueryList for root content queries for backwards
12316 // compatibility with ViewEngine.
12317 if (componentDef.contentQueries) {
12318 const tNode = getCurrentTNode();
12319 ngDevMode && assertDefined(tNode, 'TNode expected');
12320 componentDef.contentQueries(1 /* Create */, component, tNode.directiveStart);
12321 }
12322 const rootTNode = getCurrentTNode();
12323 ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
12324 if (tView.firstCreatePass &&
12325 (componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) {
12326 setSelectedIndex(rootTNode.index);
12327 const rootTView = rootLView[TVIEW];
12328 registerHostBindingOpCodes(rootTView, rootTNode, rootLView, rootTNode.directiveStart, rootTNode.directiveEnd, componentDef);
12329 invokeHostBindingsInCreationMode(componentDef, component);
12330 }
12331 return component;
12332}
12333function createRootContext(scheduler, playerHandler) {
12334 return {
12335 components: [],
12336 scheduler: scheduler || defaultScheduler,
12337 clean: CLEAN_PROMISE,
12338 playerHandler: playerHandler || null,
12339 flags: 0 /* Empty */
12340 };
12341}
12342/**
12343 * Used to enable lifecycle hooks on the root component.
12344 *
12345 * Include this feature when calling `renderComponent` if the root component
12346 * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't
12347 * be called properly.
12348 *
12349 * Example:
12350 *
12351 * ```
12352 * renderComponent(AppComponent, {hostFeatures: [LifecycleHooksFeature]});
12353 * ```
12354 */
12355function LifecycleHooksFeature(component, def) {
12356 const lView = readPatchedLView(component);
12357 ngDevMode && assertDefined(lView, 'LView is required');
12358 const tView = lView[TVIEW];
12359 const tNode = getCurrentTNode();
12360 ngDevMode && assertDefined(tNode, 'TNode is required');
12361 registerPostOrderHooks(tView, tNode);
12362}
12363/**
12364 * Wait on component until it is rendered.
12365 *
12366 * This function returns a `Promise` which is resolved when the component's
12367 * change detection is executed. This is determined by finding the scheduler
12368 * associated with the `component`'s render tree and waiting until the scheduler
12369 * flushes. If nothing is scheduled, the function returns a resolved promise.
12370 *
12371 * Example:
12372 * ```
12373 * await whenRendered(myComponent);
12374 * ```
12375 *
12376 * @param component Component to wait upon
12377 * @returns Promise which resolves when the component is rendered.
12378 */
12379function whenRendered(component) {
12380 return getRootContext(component).clean;
12381}
12382
12383/**
12384 * @license
12385 * Copyright Google LLC All Rights Reserved.
12386 *
12387 * Use of this source code is governed by an MIT-style license that can be
12388 * found in the LICENSE file at https://angular.io/license
12389 */
12390function getSuperType(type) {
12391 return Object.getPrototypeOf(type.prototype).constructor;
12392}
12393/**
12394 * Merges the definition from a super class to a sub class.
12395 * @param definition The definition that is a SubClass of another directive of component
12396 *
12397 * @codeGenApi
12398 */
12399function ɵɵInheritDefinitionFeature(definition) {
12400 let superType = getSuperType(definition.type);
12401 let shouldInheritFields = true;
12402 const inheritanceChain = [definition];
12403 while (superType) {
12404 let superDef = undefined;
12405 if (isComponentDef(definition)) {
12406 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12407 superDef = superType.ɵcmp || superType.ɵdir;
12408 }
12409 else {
12410 if (superType.ɵcmp) {
12411 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
12412 `Directives cannot inherit Components. Directive ${stringifyForError(definition.type)} is attempting to extend component ${stringifyForError(superType)}` :
12413 '';
12414 throw new RuntimeError(903 /* INVALID_INHERITANCE */, errorMessage);
12415 }
12416 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12417 superDef = superType.ɵdir;
12418 }
12419 if (superDef) {
12420 if (shouldInheritFields) {
12421 inheritanceChain.push(superDef);
12422 // Some fields in the definition may be empty, if there were no values to put in them that
12423 // would've justified object creation. Unwrap them if necessary.
12424 const writeableDef = definition;
12425 writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
12426 writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
12427 writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
12428 // Merge hostBindings
12429 const superHostBindings = superDef.hostBindings;
12430 superHostBindings && inheritHostBindings(definition, superHostBindings);
12431 // Merge queries
12432 const superViewQuery = superDef.viewQuery;
12433 const superContentQueries = superDef.contentQueries;
12434 superViewQuery && inheritViewQuery(definition, superViewQuery);
12435 superContentQueries && inheritContentQueries(definition, superContentQueries);
12436 // Merge inputs and outputs
12437 fillProperties(definition.inputs, superDef.inputs);
12438 fillProperties(definition.declaredInputs, superDef.declaredInputs);
12439 fillProperties(definition.outputs, superDef.outputs);
12440 // Merge animations metadata.
12441 // If `superDef` is a Component, the `data` field is present (defaults to an empty object).
12442 if (isComponentDef(superDef) && superDef.data.animation) {
12443 // If super def is a Component, the `definition` is also a Component, since Directives can
12444 // not inherit Components (we throw an error above and cannot reach this code).
12445 const defData = definition.data;
12446 defData.animation = (defData.animation || []).concat(superDef.data.animation);
12447 }
12448 }
12449 // Run parent features
12450 const features = superDef.features;
12451 if (features) {
12452 for (let i = 0; i < features.length; i++) {
12453 const feature = features[i];
12454 if (feature && feature.ngInherit) {
12455 feature(definition);
12456 }
12457 // If `InheritDefinitionFeature` is a part of the current `superDef`, it means that this
12458 // def already has all the necessary information inherited from its super class(es), so we
12459 // can stop merging fields from super classes. However we need to iterate through the
12460 // prototype chain to look for classes that might contain other "features" (like
12461 // NgOnChanges), which we should invoke for the original `definition`. We set the
12462 // `shouldInheritFields` flag to indicate that, essentially skipping fields inheritance
12463 // logic and only invoking functions from the "features" list.
12464 if (feature === ɵɵInheritDefinitionFeature) {
12465 shouldInheritFields = false;
12466 }
12467 }
12468 }
12469 }
12470 superType = Object.getPrototypeOf(superType);
12471 }
12472 mergeHostAttrsAcrossInheritance(inheritanceChain);
12473}
12474/**
12475 * Merge the `hostAttrs` and `hostVars` from the inherited parent to the base class.
12476 *
12477 * @param inheritanceChain A list of `WritableDefs` starting at the top most type and listing
12478 * sub-types in order. For each type take the `hostAttrs` and `hostVars` and merge it with the child
12479 * type.
12480 */
12481function mergeHostAttrsAcrossInheritance(inheritanceChain) {
12482 let hostVars = 0;
12483 let hostAttrs = null;
12484 // We process the inheritance order from the base to the leaves here.
12485 for (let i = inheritanceChain.length - 1; i >= 0; i--) {
12486 const def = inheritanceChain[i];
12487 // For each `hostVars`, we need to add the superclass amount.
12488 def.hostVars = (hostVars += def.hostVars);
12489 // for each `hostAttrs` we need to merge it with superclass.
12490 def.hostAttrs =
12491 mergeHostAttrs(def.hostAttrs, hostAttrs = mergeHostAttrs(hostAttrs, def.hostAttrs));
12492 }
12493}
12494function maybeUnwrapEmpty(value) {
12495 if (value === EMPTY_OBJ) {
12496 return {};
12497 }
12498 else if (value === EMPTY_ARRAY) {
12499 return [];
12500 }
12501 else {
12502 return value;
12503 }
12504}
12505function inheritViewQuery(definition, superViewQuery) {
12506 const prevViewQuery = definition.viewQuery;
12507 if (prevViewQuery) {
12508 definition.viewQuery = (rf, ctx) => {
12509 superViewQuery(rf, ctx);
12510 prevViewQuery(rf, ctx);
12511 };
12512 }
12513 else {
12514 definition.viewQuery = superViewQuery;
12515 }
12516}
12517function inheritContentQueries(definition, superContentQueries) {
12518 const prevContentQueries = definition.contentQueries;
12519 if (prevContentQueries) {
12520 definition.contentQueries = (rf, ctx, directiveIndex) => {
12521 superContentQueries(rf, ctx, directiveIndex);
12522 prevContentQueries(rf, ctx, directiveIndex);
12523 };
12524 }
12525 else {
12526 definition.contentQueries = superContentQueries;
12527 }
12528}
12529function inheritHostBindings(definition, superHostBindings) {
12530 const prevHostBindings = definition.hostBindings;
12531 if (prevHostBindings) {
12532 definition.hostBindings = (rf, ctx) => {
12533 superHostBindings(rf, ctx);
12534 prevHostBindings(rf, ctx);
12535 };
12536 }
12537 else {
12538 definition.hostBindings = superHostBindings;
12539 }
12540}
12541
12542/**
12543 * @license
12544 * Copyright Google LLC All Rights Reserved.
12545 *
12546 * Use of this source code is governed by an MIT-style license that can be
12547 * found in the LICENSE file at https://angular.io/license
12548 */
12549/**
12550 * Fields which exist on either directive or component definitions, and need to be copied from
12551 * parent to child classes by the `ɵɵCopyDefinitionFeature`.
12552 */
12553const COPY_DIRECTIVE_FIELDS = [
12554 // The child class should use the providers of its parent.
12555 'providersResolver',
12556 // Not listed here are any fields which are handled by the `ɵɵInheritDefinitionFeature`, such
12557 // as inputs, outputs, and host binding functions.
12558];
12559/**
12560 * Fields which exist only on component definitions, and need to be copied from parent to child
12561 * classes by the `ɵɵCopyDefinitionFeature`.
12562 *
12563 * The type here allows any field of `ComponentDef` which is not also a property of `DirectiveDef`,
12564 * since those should go in `COPY_DIRECTIVE_FIELDS` above.
12565 */
12566const COPY_COMPONENT_FIELDS = [
12567 // The child class should use the template function of its parent, including all template
12568 // semantics.
12569 'template',
12570 'decls',
12571 'consts',
12572 'vars',
12573 'onPush',
12574 'ngContentSelectors',
12575 // The child class should use the CSS styles of its parent, including all styling semantics.
12576 'styles',
12577 'encapsulation',
12578 // The child class should be checked by the runtime in the same way as its parent.
12579 'schemas',
12580];
12581/**
12582 * Copies the fields not handled by the `ɵɵInheritDefinitionFeature` from the supertype of a
12583 * definition.
12584 *
12585 * This exists primarily to support ngcc migration of an existing View Engine pattern, where an
12586 * entire decorator is inherited from a parent to a child class. When ngcc detects this case, it
12587 * generates a skeleton definition on the child class, and applies this feature.
12588 *
12589 * The `ɵɵCopyDefinitionFeature` then copies any needed fields from the parent class' definition,
12590 * including things like the component template function.
12591 *
12592 * @param definition The definition of a child class which inherits from a parent class with its
12593 * own definition.
12594 *
12595 * @codeGenApi
12596 */
12597function ɵɵCopyDefinitionFeature(definition) {
12598 let superType = getSuperType(definition.type);
12599 let superDef = undefined;
12600 if (isComponentDef(definition)) {
12601 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12602 superDef = superType.ɵcmp;
12603 }
12604 else {
12605 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12606 superDef = superType.ɵdir;
12607 }
12608 // Needed because `definition` fields are readonly.
12609 const defAny = definition;
12610 // Copy over any fields that apply to either directives or components.
12611 for (const field of COPY_DIRECTIVE_FIELDS) {
12612 defAny[field] = superDef[field];
12613 }
12614 if (isComponentDef(superDef)) {
12615 // Copy over any component-specific fields.
12616 for (const field of COPY_COMPONENT_FIELDS) {
12617 defAny[field] = superDef[field];
12618 }
12619 }
12620}
12621
12622/**
12623 * @license
12624 * Copyright Google LLC All Rights Reserved.
12625 *
12626 * Use of this source code is governed by an MIT-style license that can be
12627 * found in the LICENSE file at https://angular.io/license
12628 */
12629let _symbolIterator = null;
12630function getSymbolIterator() {
12631 if (!_symbolIterator) {
12632 const Symbol = _global['Symbol'];
12633 if (Symbol && Symbol.iterator) {
12634 _symbolIterator = Symbol.iterator;
12635 }
12636 else {
12637 // es6-shim specific logic
12638 const keys = Object.getOwnPropertyNames(Map.prototype);
12639 for (let i = 0; i < keys.length; ++i) {
12640 const key = keys[i];
12641 if (key !== 'entries' && key !== 'size' &&
12642 Map.prototype[key] === Map.prototype['entries']) {
12643 _symbolIterator = key;
12644 }
12645 }
12646 }
12647 }
12648 return _symbolIterator;
12649}
12650
12651/**
12652 * @license
12653 * Copyright Google LLC All Rights Reserved.
12654 *
12655 * Use of this source code is governed by an MIT-style license that can be
12656 * found in the LICENSE file at https://angular.io/license
12657 */
12658function devModeEqual(a, b) {
12659 const isListLikeIterableA = isListLikeIterable(a);
12660 const isListLikeIterableB = isListLikeIterable(b);
12661 if (isListLikeIterableA && isListLikeIterableB) {
12662 return areIterablesEqual(a, b, devModeEqual);
12663 }
12664 else {
12665 const isAObject = a && (typeof a === 'object' || typeof a === 'function');
12666 const isBObject = b && (typeof b === 'object' || typeof b === 'function');
12667 if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
12668 return true;
12669 }
12670 else {
12671 return Object.is(a, b);
12672 }
12673 }
12674}
12675function isListLikeIterable(obj) {
12676 if (!isJsObject(obj))
12677 return false;
12678 return Array.isArray(obj) ||
12679 (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
12680 getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop
12681}
12682function areIterablesEqual(a, b, comparator) {
12683 const iterator1 = a[getSymbolIterator()]();
12684 const iterator2 = b[getSymbolIterator()]();
12685 while (true) {
12686 const item1 = iterator1.next();
12687 const item2 = iterator2.next();
12688 if (item1.done && item2.done)
12689 return true;
12690 if (item1.done || item2.done)
12691 return false;
12692 if (!comparator(item1.value, item2.value))
12693 return false;
12694 }
12695}
12696function iterateListLike(obj, fn) {
12697 if (Array.isArray(obj)) {
12698 for (let i = 0; i < obj.length; i++) {
12699 fn(obj[i]);
12700 }
12701 }
12702 else {
12703 const iterator = obj[getSymbolIterator()]();
12704 let item;
12705 while (!((item = iterator.next()).done)) {
12706 fn(item.value);
12707 }
12708 }
12709}
12710function isJsObject(o) {
12711 return o !== null && (typeof o === 'function' || typeof o === 'object');
12712}
12713
12714/**
12715 * @license
12716 * Copyright Google LLC All Rights Reserved.
12717 *
12718 * Use of this source code is governed by an MIT-style license that can be
12719 * found in the LICENSE file at https://angular.io/license
12720 */
12721// TODO(misko): consider inlining
12722/** Updates binding and returns the value. */
12723function updateBinding(lView, bindingIndex, value) {
12724 return lView[bindingIndex] = value;
12725}
12726/** Gets the current binding value. */
12727function getBinding(lView, bindingIndex) {
12728 ngDevMode && assertIndexInRange(lView, bindingIndex);
12729 ngDevMode &&
12730 assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
12731 return lView[bindingIndex];
12732}
12733/**
12734 * Updates binding if changed, then returns whether it was updated.
12735 *
12736 * This function also checks the `CheckNoChangesMode` and throws if changes are made.
12737 * Some changes (Objects/iterables) during `CheckNoChangesMode` are exempt to comply with VE
12738 * behavior.
12739 *
12740 * @param lView current `LView`
12741 * @param bindingIndex The binding in the `LView` to check
12742 * @param value New value to check against `lView[bindingIndex]`
12743 * @returns `true` if the bindings has changed. (Throws if binding has changed during
12744 * `CheckNoChangesMode`)
12745 */
12746function bindingUpdated(lView, bindingIndex, value) {
12747 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
12748 ngDevMode &&
12749 assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`);
12750 const oldValue = lView[bindingIndex];
12751 if (Object.is(oldValue, value)) {
12752 return false;
12753 }
12754 else {
12755 if (ngDevMode && isInCheckNoChangesMode()) {
12756 // View engine didn't report undefined values as changed on the first checkNoChanges pass
12757 // (before the change detection was run).
12758 const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
12759 if (!devModeEqual(oldValueToCompare, value)) {
12760 const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
12761 throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName);
12762 }
12763 // There was a change, but the `devModeEqual` decided that the change is exempt from an error.
12764 // For this reason we exit as if no change. The early exit is needed to prevent the changed
12765 // value to be written into `LView` (If we would write the new value that we would not see it
12766 // as change on next CD.)
12767 return false;
12768 }
12769 lView[bindingIndex] = value;
12770 return true;
12771 }
12772}
12773/** Updates 2 bindings if changed, then returns whether either was updated. */
12774function bindingUpdated2(lView, bindingIndex, exp1, exp2) {
12775 const different = bindingUpdated(lView, bindingIndex, exp1);
12776 return bindingUpdated(lView, bindingIndex + 1, exp2) || different;
12777}
12778/** Updates 3 bindings if changed, then returns whether any was updated. */
12779function bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) {
12780 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
12781 return bindingUpdated(lView, bindingIndex + 2, exp3) || different;
12782}
12783/** Updates 4 bindings if changed, then returns whether any was updated. */
12784function bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) {
12785 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
12786 return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different;
12787}
12788
12789/**
12790 * @license
12791 * Copyright Google LLC All Rights Reserved.
12792 *
12793 * Use of this source code is governed by an MIT-style license that can be
12794 * found in the LICENSE file at https://angular.io/license
12795 */
12796/**
12797 * Updates the value of or removes a bound attribute on an Element.
12798 *
12799 * Used in the case of `[attr.title]="value"`
12800 *
12801 * @param name name The name of the attribute.
12802 * @param value value The attribute is removed when value is `null` or `undefined`.
12803 * Otherwise the attribute value is set to the stringified value.
12804 * @param sanitizer An optional function used to sanitize the value.
12805 * @param namespace Optional namespace to use when setting the attribute.
12806 *
12807 * @codeGenApi
12808 */
12809function ɵɵattribute(name, value, sanitizer, namespace) {
12810 const lView = getLView();
12811 const bindingIndex = nextBindingIndex();
12812 if (bindingUpdated(lView, bindingIndex, value)) {
12813 const tView = getTView();
12814 const tNode = getSelectedTNode();
12815 elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace);
12816 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, 'attr.' + name, bindingIndex);
12817 }
12818 return ɵɵattribute;
12819}
12820
12821/**
12822 * @license
12823 * Copyright Google LLC All Rights Reserved.
12824 *
12825 * Use of this source code is governed by an MIT-style license that can be
12826 * found in the LICENSE file at https://angular.io/license
12827 */
12828/**
12829 * Create interpolation bindings with a variable number of expressions.
12830 *
12831 * If there are 1 to 8 expressions `interpolation1()` to `interpolation8()` should be used instead.
12832 * Those are faster because there is no need to create an array of expressions and iterate over it.
12833 *
12834 * `values`:
12835 * - has static text at even indexes,
12836 * - has evaluated expressions at odd indexes.
12837 *
12838 * Returns the concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
12839 */
12840function interpolationV(lView, values) {
12841 ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
12842 ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
12843 let isBindingUpdated = false;
12844 let bindingIndex = getBindingIndex();
12845 for (let i = 1; i < values.length; i += 2) {
12846 // Check if bindings (odd indexes) have changed
12847 isBindingUpdated = bindingUpdated(lView, bindingIndex++, values[i]) || isBindingUpdated;
12848 }
12849 setBindingIndex(bindingIndex);
12850 if (!isBindingUpdated) {
12851 return NO_CHANGE;
12852 }
12853 // Build the updated content
12854 let content = values[0];
12855 for (let i = 1; i < values.length; i += 2) {
12856 content += renderStringify(values[i]) + values[i + 1];
12857 }
12858 return content;
12859}
12860/**
12861 * Creates an interpolation binding with 1 expression.
12862 *
12863 * @param prefix static value used for concatenation only.
12864 * @param v0 value checked for change.
12865 * @param suffix static value used for concatenation only.
12866 */
12867function interpolation1(lView, prefix, v0, suffix) {
12868 const different = bindingUpdated(lView, nextBindingIndex(), v0);
12869 return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE;
12870}
12871/**
12872 * Creates an interpolation binding with 2 expressions.
12873 */
12874function interpolation2(lView, prefix, v0, i0, v1, suffix) {
12875 const bindingIndex = getBindingIndex();
12876 const different = bindingUpdated2(lView, bindingIndex, v0, v1);
12877 incrementBindingIndex(2);
12878 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE;
12879}
12880/**
12881 * Creates an interpolation binding with 3 expressions.
12882 */
12883function interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix) {
12884 const bindingIndex = getBindingIndex();
12885 const different = bindingUpdated3(lView, bindingIndex, v0, v1, v2);
12886 incrementBindingIndex(3);
12887 return different ?
12888 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix :
12889 NO_CHANGE;
12890}
12891/**
12892 * Create an interpolation binding with 4 expressions.
12893 */
12894function interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
12895 const bindingIndex = getBindingIndex();
12896 const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
12897 incrementBindingIndex(4);
12898 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
12899 renderStringify(v2) + i2 + renderStringify(v3) + suffix :
12900 NO_CHANGE;
12901}
12902/**
12903 * Creates an interpolation binding with 5 expressions.
12904 */
12905function interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
12906 const bindingIndex = getBindingIndex();
12907 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
12908 different = bindingUpdated(lView, bindingIndex + 4, v4) || different;
12909 incrementBindingIndex(5);
12910 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
12911 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + suffix :
12912 NO_CHANGE;
12913}
12914/**
12915 * Creates an interpolation binding with 6 expressions.
12916 */
12917function interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
12918 const bindingIndex = getBindingIndex();
12919 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
12920 different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different;
12921 incrementBindingIndex(6);
12922 return different ?
12923 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
12924 renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix :
12925 NO_CHANGE;
12926}
12927/**
12928 * Creates an interpolation binding with 7 expressions.
12929 */
12930function interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
12931 const bindingIndex = getBindingIndex();
12932 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
12933 different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different;
12934 incrementBindingIndex(7);
12935 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
12936 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
12937 renderStringify(v5) + i5 + renderStringify(v6) + suffix :
12938 NO_CHANGE;
12939}
12940/**
12941 * Creates an interpolation binding with 8 expressions.
12942 */
12943function interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
12944 const bindingIndex = getBindingIndex();
12945 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
12946 different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different;
12947 incrementBindingIndex(8);
12948 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
12949 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
12950 renderStringify(v5) + i5 + renderStringify(v6) + i6 + renderStringify(v7) + suffix :
12951 NO_CHANGE;
12952}
12953
12954/**
12955 *
12956 * Update an interpolated attribute on an element with single bound value surrounded by text.
12957 *
12958 * Used when the value passed to a property has 1 interpolated value in it:
12959 *
12960 * ```html
12961 * <div attr.title="prefix{{v0}}suffix"></div>
12962 * ```
12963 *
12964 * Its compiled representation is::
12965 *
12966 * ```ts
12967 * ɵɵattributeInterpolate1('title', 'prefix', v0, 'suffix');
12968 * ```
12969 *
12970 * @param attrName The name of the attribute to update
12971 * @param prefix Static value used for concatenation only.
12972 * @param v0 Value checked for change.
12973 * @param suffix Static value used for concatenation only.
12974 * @param sanitizer An optional sanitizer function
12975 * @returns itself, so that it may be chained.
12976 * @codeGenApi
12977 */
12978function ɵɵattributeInterpolate1(attrName, prefix, v0, suffix, sanitizer, namespace) {
12979 const lView = getLView();
12980 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
12981 if (interpolatedValue !== NO_CHANGE) {
12982 const tNode = getSelectedTNode();
12983 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
12984 ngDevMode &&
12985 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 1, prefix, suffix);
12986 }
12987 return ɵɵattributeInterpolate1;
12988}
12989/**
12990 *
12991 * Update an interpolated attribute on an element with 2 bound values surrounded by text.
12992 *
12993 * Used when the value passed to a property has 2 interpolated values in it:
12994 *
12995 * ```html
12996 * <div attr.title="prefix{{v0}}-{{v1}}suffix"></div>
12997 * ```
12998 *
12999 * Its compiled representation is::
13000 *
13001 * ```ts
13002 * ɵɵattributeInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
13003 * ```
13004 *
13005 * @param attrName The name of the attribute to update
13006 * @param prefix Static value used for concatenation only.
13007 * @param v0 Value checked for change.
13008 * @param i0 Static value used for concatenation only.
13009 * @param v1 Value checked for change.
13010 * @param suffix Static value used for concatenation only.
13011 * @param sanitizer An optional sanitizer function
13012 * @returns itself, so that it may be chained.
13013 * @codeGenApi
13014 */
13015function ɵɵattributeInterpolate2(attrName, prefix, v0, i0, v1, suffix, sanitizer, namespace) {
13016 const lView = getLView();
13017 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
13018 if (interpolatedValue !== NO_CHANGE) {
13019 const tNode = getSelectedTNode();
13020 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13021 ngDevMode &&
13022 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 2, prefix, i0, suffix);
13023 }
13024 return ɵɵattributeInterpolate2;
13025}
13026/**
13027 *
13028 * Update an interpolated attribute on an element with 3 bound values surrounded by text.
13029 *
13030 * Used when the value passed to a property has 3 interpolated values in it:
13031 *
13032 * ```html
13033 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
13034 * ```
13035 *
13036 * Its compiled representation is::
13037 *
13038 * ```ts
13039 * ɵɵattributeInterpolate3(
13040 * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
13041 * ```
13042 *
13043 * @param attrName The name of the attribute to update
13044 * @param prefix Static value used for concatenation only.
13045 * @param v0 Value checked for change.
13046 * @param i0 Static value used for concatenation only.
13047 * @param v1 Value checked for change.
13048 * @param i1 Static value used for concatenation only.
13049 * @param v2 Value checked for change.
13050 * @param suffix Static value used for concatenation only.
13051 * @param sanitizer An optional sanitizer function
13052 * @returns itself, so that it may be chained.
13053 * @codeGenApi
13054 */
13055function ɵɵattributeInterpolate3(attrName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer, namespace) {
13056 const lView = getLView();
13057 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
13058 if (interpolatedValue !== NO_CHANGE) {
13059 const tNode = getSelectedTNode();
13060 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13061 ngDevMode &&
13062 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 3, prefix, i0, i1, suffix);
13063 }
13064 return ɵɵattributeInterpolate3;
13065}
13066/**
13067 *
13068 * Update an interpolated attribute on an element with 4 bound values surrounded by text.
13069 *
13070 * Used when the value passed to a property has 4 interpolated values in it:
13071 *
13072 * ```html
13073 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
13074 * ```
13075 *
13076 * Its compiled representation is::
13077 *
13078 * ```ts
13079 * ɵɵattributeInterpolate4(
13080 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
13081 * ```
13082 *
13083 * @param attrName The name of the attribute to update
13084 * @param prefix Static value used for concatenation only.
13085 * @param v0 Value checked for change.
13086 * @param i0 Static value used for concatenation only.
13087 * @param v1 Value checked for change.
13088 * @param i1 Static value used for concatenation only.
13089 * @param v2 Value checked for change.
13090 * @param i2 Static value used for concatenation only.
13091 * @param v3 Value checked for change.
13092 * @param suffix Static value used for concatenation only.
13093 * @param sanitizer An optional sanitizer function
13094 * @returns itself, so that it may be chained.
13095 * @codeGenApi
13096 */
13097function ɵɵattributeInterpolate4(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer, namespace) {
13098 const lView = getLView();
13099 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
13100 if (interpolatedValue !== NO_CHANGE) {
13101 const tNode = getSelectedTNode();
13102 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13103 ngDevMode &&
13104 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix);
13105 }
13106 return ɵɵattributeInterpolate4;
13107}
13108/**
13109 *
13110 * Update an interpolated attribute on an element with 5 bound values surrounded by text.
13111 *
13112 * Used when the value passed to a property has 5 interpolated values in it:
13113 *
13114 * ```html
13115 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
13116 * ```
13117 *
13118 * Its compiled representation is::
13119 *
13120 * ```ts
13121 * ɵɵattributeInterpolate5(
13122 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
13123 * ```
13124 *
13125 * @param attrName The name of the attribute to update
13126 * @param prefix Static value used for concatenation only.
13127 * @param v0 Value checked for change.
13128 * @param i0 Static value used for concatenation only.
13129 * @param v1 Value checked for change.
13130 * @param i1 Static value used for concatenation only.
13131 * @param v2 Value checked for change.
13132 * @param i2 Static value used for concatenation only.
13133 * @param v3 Value checked for change.
13134 * @param i3 Static value used for concatenation only.
13135 * @param v4 Value checked for change.
13136 * @param suffix Static value used for concatenation only.
13137 * @param sanitizer An optional sanitizer function
13138 * @returns itself, so that it may be chained.
13139 * @codeGenApi
13140 */
13141function ɵɵattributeInterpolate5(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer, namespace) {
13142 const lView = getLView();
13143 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
13144 if (interpolatedValue !== NO_CHANGE) {
13145 const tNode = getSelectedTNode();
13146 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13147 ngDevMode &&
13148 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix);
13149 }
13150 return ɵɵattributeInterpolate5;
13151}
13152/**
13153 *
13154 * Update an interpolated attribute on an element with 6 bound values surrounded by text.
13155 *
13156 * Used when the value passed to a property has 6 interpolated values in it:
13157 *
13158 * ```html
13159 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
13160 * ```
13161 *
13162 * Its compiled representation is::
13163 *
13164 * ```ts
13165 * ɵɵattributeInterpolate6(
13166 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
13167 * ```
13168 *
13169 * @param attrName The name of the attribute to update
13170 * @param prefix Static value used for concatenation only.
13171 * @param v0 Value checked for change.
13172 * @param i0 Static value used for concatenation only.
13173 * @param v1 Value checked for change.
13174 * @param i1 Static value used for concatenation only.
13175 * @param v2 Value checked for change.
13176 * @param i2 Static value used for concatenation only.
13177 * @param v3 Value checked for change.
13178 * @param i3 Static value used for concatenation only.
13179 * @param v4 Value checked for change.
13180 * @param i4 Static value used for concatenation only.
13181 * @param v5 Value checked for change.
13182 * @param suffix Static value used for concatenation only.
13183 * @param sanitizer An optional sanitizer function
13184 * @returns itself, so that it may be chained.
13185 * @codeGenApi
13186 */
13187function ɵɵattributeInterpolate6(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer, namespace) {
13188 const lView = getLView();
13189 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
13190 if (interpolatedValue !== NO_CHANGE) {
13191 const tNode = getSelectedTNode();
13192 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13193 ngDevMode &&
13194 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, i4, suffix);
13195 }
13196 return ɵɵattributeInterpolate6;
13197}
13198/**
13199 *
13200 * Update an interpolated attribute on an element with 7 bound values surrounded by text.
13201 *
13202 * Used when the value passed to a property has 7 interpolated values in it:
13203 *
13204 * ```html
13205 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
13206 * ```
13207 *
13208 * Its compiled representation is::
13209 *
13210 * ```ts
13211 * ɵɵattributeInterpolate7(
13212 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
13213 * ```
13214 *
13215 * @param attrName The name of the attribute to update
13216 * @param prefix Static value used for concatenation only.
13217 * @param v0 Value checked for change.
13218 * @param i0 Static value used for concatenation only.
13219 * @param v1 Value checked for change.
13220 * @param i1 Static value used for concatenation only.
13221 * @param v2 Value checked for change.
13222 * @param i2 Static value used for concatenation only.
13223 * @param v3 Value checked for change.
13224 * @param i3 Static value used for concatenation only.
13225 * @param v4 Value checked for change.
13226 * @param i4 Static value used for concatenation only.
13227 * @param v5 Value checked for change.
13228 * @param i5 Static value used for concatenation only.
13229 * @param v6 Value checked for change.
13230 * @param suffix Static value used for concatenation only.
13231 * @param sanitizer An optional sanitizer function
13232 * @returns itself, so that it may be chained.
13233 * @codeGenApi
13234 */
13235function ɵɵattributeInterpolate7(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer, namespace) {
13236 const lView = getLView();
13237 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
13238 if (interpolatedValue !== NO_CHANGE) {
13239 const tNode = getSelectedTNode();
13240 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13241 ngDevMode &&
13242 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, suffix);
13243 }
13244 return ɵɵattributeInterpolate7;
13245}
13246/**
13247 *
13248 * Update an interpolated attribute on an element with 8 bound values surrounded by text.
13249 *
13250 * Used when the value passed to a property has 8 interpolated values in it:
13251 *
13252 * ```html
13253 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
13254 * ```
13255 *
13256 * Its compiled representation is::
13257 *
13258 * ```ts
13259 * ɵɵattributeInterpolate8(
13260 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
13261 * ```
13262 *
13263 * @param attrName The name of the attribute to update
13264 * @param prefix Static value used for concatenation only.
13265 * @param v0 Value checked for change.
13266 * @param i0 Static value used for concatenation only.
13267 * @param v1 Value checked for change.
13268 * @param i1 Static value used for concatenation only.
13269 * @param v2 Value checked for change.
13270 * @param i2 Static value used for concatenation only.
13271 * @param v3 Value checked for change.
13272 * @param i3 Static value used for concatenation only.
13273 * @param v4 Value checked for change.
13274 * @param i4 Static value used for concatenation only.
13275 * @param v5 Value checked for change.
13276 * @param i5 Static value used for concatenation only.
13277 * @param v6 Value checked for change.
13278 * @param i6 Static value used for concatenation only.
13279 * @param v7 Value checked for change.
13280 * @param suffix Static value used for concatenation only.
13281 * @param sanitizer An optional sanitizer function
13282 * @returns itself, so that it may be chained.
13283 * @codeGenApi
13284 */
13285function ɵɵattributeInterpolate8(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer, namespace) {
13286 const lView = getLView();
13287 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
13288 if (interpolatedValue !== NO_CHANGE) {
13289 const tNode = getSelectedTNode();
13290 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13291 ngDevMode &&
13292 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, suffix);
13293 }
13294 return ɵɵattributeInterpolate8;
13295}
13296/**
13297 * Update an interpolated attribute on an element with 9 or more bound values surrounded by text.
13298 *
13299 * Used when the number of interpolated values exceeds 8.
13300 *
13301 * ```html
13302 * <div
13303 * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
13304 * ```
13305 *
13306 * Its compiled representation is::
13307 *
13308 * ```ts
13309 * ɵɵattributeInterpolateV(
13310 * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
13311 * 'suffix']);
13312 * ```
13313 *
13314 * @param attrName The name of the attribute to update.
13315 * @param values The collection of values and the strings in-between those values, beginning with
13316 * a string prefix and ending with a string suffix.
13317 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
13318 * @param sanitizer An optional sanitizer function
13319 * @returns itself, so that it may be chained.
13320 * @codeGenApi
13321 */
13322function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
13323 const lView = getLView();
13324 const interpolated = interpolationV(lView, values);
13325 if (interpolated !== NO_CHANGE) {
13326 const tNode = getSelectedTNode();
13327 elementAttributeInternal(tNode, lView, attrName, interpolated, sanitizer, namespace);
13328 if (ngDevMode) {
13329 const interpolationInBetween = [values[0]]; // prefix
13330 for (let i = 2; i < values.length; i += 2) {
13331 interpolationInBetween.push(values[i]);
13332 }
13333 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
13334 }
13335 }
13336 return ɵɵattributeInterpolateV;
13337}
13338
13339/**
13340 * @license
13341 * Copyright Google LLC All Rights Reserved.
13342 *
13343 * Use of this source code is governed by an MIT-style license that can be
13344 * found in the LICENSE file at https://angular.io/license
13345 */
13346function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
13347 ngDevMode && assertFirstCreatePass(tView);
13348 ngDevMode && ngDevMode.firstCreatePass++;
13349 const tViewConsts = tView.consts;
13350 // TODO(pk): refactor getOrCreateTNode to have the "create" only version
13351 const tNode = getOrCreateTNode(tView, index, 4 /* Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
13352 resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
13353 registerPostOrderHooks(tView, tNode);
13354 const embeddedTView = tNode.tViews = createTView(2 /* Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
13355 if (tView.queries !== null) {
13356 tView.queries.template(tView, tNode);
13357 embeddedTView.queries = tView.queries.embeddedTView(tNode);
13358 }
13359 return tNode;
13360}
13361/**
13362 * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
13363 *
13364 * <ng-template #foo>
13365 * <div></div>
13366 * </ng-template>
13367 *
13368 * @param index The index of the container in the data array
13369 * @param templateFn Inline template
13370 * @param decls The number of nodes, local refs, and pipes for this template
13371 * @param vars The number of bindings for this template
13372 * @param tagName The name of the container element, if applicable
13373 * @param attrsIndex Index of template attributes in the `consts` array.
13374 * @param localRefs Index of the local references in the `consts` array.
13375 * @param localRefExtractor A function which extracts local-refs values from the template.
13376 * Defaults to the current element associated with the local-ref.
13377 *
13378 * @codeGenApi
13379 */
13380function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
13381 const lView = getLView();
13382 const tView = getTView();
13383 const adjustedIndex = index + HEADER_OFFSET;
13384 const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
13385 tView.data[adjustedIndex];
13386 setCurrentTNode(tNode, false);
13387 const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : '');
13388 appendChild(tView, lView, comment, tNode);
13389 attachPatchData(comment, lView);
13390 addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
13391 if (isDirectiveHost(tNode)) {
13392 createDirectivesInstances(tView, lView, tNode);
13393 }
13394 if (localRefsIndex != null) {
13395 saveResolvedLocalsInData(lView, tNode, localRefExtractor);
13396 }
13397}
13398
13399/**
13400 * @license
13401 * Copyright Google LLC All Rights Reserved.
13402 *
13403 * Use of this source code is governed by an MIT-style license that can be
13404 * found in the LICENSE file at https://angular.io/license
13405 */
13406/** Store a value in the `data` at a given `index`. */
13407function store(tView, lView, index, value) {
13408 // We don't store any static data for local variables, so the first time
13409 // we see the template, we should store as null to avoid a sparse array
13410 if (index >= tView.data.length) {
13411 tView.data[index] = null;
13412 tView.blueprint[index] = null;
13413 }
13414 lView[index] = value;
13415}
13416/**
13417 * Retrieves a local reference from the current contextViewData.
13418 *
13419 * If the reference to retrieve is in a parent view, this instruction is used in conjunction
13420 * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
13421 *
13422 * @param index The index of the local ref in contextViewData.
13423 *
13424 * @codeGenApi
13425 */
13426function ɵɵreference(index) {
13427 const contextLView = getContextLView();
13428 return load(contextLView, HEADER_OFFSET + index);
13429}
13430
13431/**
13432 * @license
13433 * Copyright Google LLC All Rights Reserved.
13434 *
13435 * Use of this source code is governed by an MIT-style license that can be
13436 * found in the LICENSE file at https://angular.io/license
13437 */
13438/**
13439 * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
13440 *
13441 * This should be kept up to date with the public exports of @angular/core.
13442 */
13443const angularCoreDiEnv = {
13444 'ɵɵdefineInjectable': ɵɵdefineInjectable,
13445 'ɵɵdefineInjector': ɵɵdefineInjector,
13446 'ɵɵinject': ɵɵinject,
13447 'ɵɵinvalidFactoryDep': ɵɵinvalidFactoryDep,
13448 'resolveForwardRef': resolveForwardRef,
13449};
13450
13451/**
13452 * @license
13453 * Copyright Google LLC All Rights Reserved.
13454 *
13455 * Use of this source code is governed by an MIT-style license that can be
13456 * found in the LICENSE file at https://angular.io/license
13457 */
13458/**
13459 * Compile an Angular injectable according to its `Injectable` metadata, and patch the resulting
13460 * injectable def (`ɵprov`) onto the injectable type.
13461 */
13462function compileInjectable(type, meta) {
13463 let ngInjectableDef = null;
13464 let ngFactoryDef = null;
13465 // if NG_PROV_DEF is already defined on this class then don't overwrite it
13466 if (!type.hasOwnProperty(NG_PROV_DEF)) {
13467 Object.defineProperty(type, NG_PROV_DEF, {
13468 get: () => {
13469 if (ngInjectableDef === null) {
13470 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'injectable', type });
13471 ngInjectableDef = compiler.compileInjectable(angularCoreDiEnv, `ng:///${type.name}/ɵprov.js`, getInjectableMetadata(type, meta));
13472 }
13473 return ngInjectableDef;
13474 },
13475 });
13476 }
13477 // if NG_FACTORY_DEF is already defined on this class then don't overwrite it
13478 if (!type.hasOwnProperty(NG_FACTORY_DEF)) {
13479 Object.defineProperty(type, NG_FACTORY_DEF, {
13480 get: () => {
13481 if (ngFactoryDef === null) {
13482 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'injectable', type });
13483 ngFactoryDef = compiler.compileFactory(angularCoreDiEnv, `ng:///${type.name}/ɵfac.js`, {
13484 name: type.name,
13485 type,
13486 typeArgumentCount: 0,
13487 deps: reflectDependencies(type),
13488 target: compiler.FactoryTarget.Injectable
13489 });
13490 }
13491 return ngFactoryDef;
13492 },
13493 // Leave this configurable so that the factories from directives or pipes can take precedence.
13494 configurable: true
13495 });
13496 }
13497}
13498const USE_VALUE = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
13499function isUseClassProvider(meta) {
13500 return meta.useClass !== undefined;
13501}
13502function isUseValueProvider(meta) {
13503 return USE_VALUE in meta;
13504}
13505function isUseFactoryProvider(meta) {
13506 return meta.useFactory !== undefined;
13507}
13508function isUseExistingProvider(meta) {
13509 return meta.useExisting !== undefined;
13510}
13511function getInjectableMetadata(type, srcMeta) {
13512 // Allow the compilation of a class with a `@Injectable()` decorator without parameters
13513 const meta = srcMeta || { providedIn: null };
13514 const compilerMeta = {
13515 name: type.name,
13516 type: type,
13517 typeArgumentCount: 0,
13518 providedIn: meta.providedIn,
13519 };
13520 if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) {
13521 compilerMeta.deps = convertDependencies(meta.deps);
13522 }
13523 // Check to see if the user explicitly provided a `useXxxx` property.
13524 if (isUseClassProvider(meta)) {
13525 compilerMeta.useClass = meta.useClass;
13526 }
13527 else if (isUseValueProvider(meta)) {
13528 compilerMeta.useValue = meta.useValue;
13529 }
13530 else if (isUseFactoryProvider(meta)) {
13531 compilerMeta.useFactory = meta.useFactory;
13532 }
13533 else if (isUseExistingProvider(meta)) {
13534 compilerMeta.useExisting = meta.useExisting;
13535 }
13536 return compilerMeta;
13537}
13538
13539/**
13540 * @license
13541 * Copyright Google LLC All Rights Reserved.
13542 *
13543 * Use of this source code is governed by an MIT-style license that can be
13544 * found in the LICENSE file at https://angular.io/license
13545 */
13546/**
13547 * Injectable decorator and metadata.
13548 *
13549 * @Annotation
13550 * @publicApi
13551 */
13552const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, (type, meta) => compileInjectable(type, meta));
13553
13554/**
13555 * @license
13556 * Copyright Google LLC All Rights Reserved.
13557 *
13558 * Use of this source code is governed by an MIT-style license that can be
13559 * found in the LICENSE file at https://angular.io/license
13560 */
13561function findFirstClosedCycle(keys) {
13562 const res = [];
13563 for (let i = 0; i < keys.length; ++i) {
13564 if (res.indexOf(keys[i]) > -1) {
13565 res.push(keys[i]);
13566 return res;
13567 }
13568 res.push(keys[i]);
13569 }
13570 return res;
13571}
13572function constructResolvingPath(keys) {
13573 if (keys.length > 1) {
13574 const reversed = findFirstClosedCycle(keys.slice().reverse());
13575 const tokenStrs = reversed.map(k => stringify(k.token));
13576 return ' (' + tokenStrs.join(' -> ') + ')';
13577 }
13578 return '';
13579}
13580function injectionError(injector, key, constructResolvingMessage, originalError) {
13581 const keys = [key];
13582 const errMsg = constructResolvingMessage(keys);
13583 const error = (originalError ? wrappedError(errMsg, originalError) : Error(errMsg));
13584 error.addKey = addKey;
13585 error.keys = keys;
13586 error.injectors = [injector];
13587 error.constructResolvingMessage = constructResolvingMessage;
13588 error[ERROR_ORIGINAL_ERROR] = originalError;
13589 return error;
13590}
13591function addKey(injector, key) {
13592 this.injectors.push(injector);
13593 this.keys.push(key);
13594 // Note: This updated message won't be reflected in the `.stack` property
13595 this.message = this.constructResolvingMessage(this.keys);
13596}
13597/**
13598 * Thrown when trying to retrieve a dependency by key from {@link Injector}, but the
13599 * {@link Injector} does not have a {@link Provider} for the given key.
13600 *
13601 * @usageNotes
13602 * ### Example
13603 *
13604 * ```typescript
13605 * class A {
13606 * constructor(b:B) {}
13607 * }
13608 *
13609 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
13610 * ```
13611 */
13612function noProviderError(injector, key) {
13613 return injectionError(injector, key, function (keys) {
13614 const first = stringify(keys[0].token);
13615 return `No provider for ${first}!${constructResolvingPath(keys)}`;
13616 });
13617}
13618/**
13619 * Thrown when dependencies form a cycle.
13620 *
13621 * @usageNotes
13622 * ### Example
13623 *
13624 * ```typescript
13625 * var injector = Injector.resolveAndCreate([
13626 * {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]},
13627 * {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]}
13628 * ]);
13629 *
13630 * expect(() => injector.get("one")).toThrowError();
13631 * ```
13632 *
13633 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
13634 */
13635function cyclicDependencyError(injector, key) {
13636 return injectionError(injector, key, function (keys) {
13637 return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
13638 });
13639}
13640/**
13641 * Thrown when a constructing type returns with an Error.
13642 *
13643 * The `InstantiationError` class contains the original error plus the dependency graph which caused
13644 * this object to be instantiated.
13645 *
13646 * @usageNotes
13647 * ### Example
13648 *
13649 * ```typescript
13650 * class A {
13651 * constructor() {
13652 * throw new Error('message');
13653 * }
13654 * }
13655 *
13656 * var injector = Injector.resolveAndCreate([A]);
13657
13658 * try {
13659 * injector.get(A);
13660 * } catch (e) {
13661 * expect(e instanceof InstantiationError).toBe(true);
13662 * expect(e.originalException.message).toEqual("message");
13663 * expect(e.originalStack).toBeDefined();
13664 * }
13665 * ```
13666 */
13667function instantiationError(injector, originalException, originalStack, key) {
13668 return injectionError(injector, key, function (keys) {
13669 const first = stringify(keys[0].token);
13670 return `${originalException.message}: Error during instantiation of ${first}!${constructResolvingPath(keys)}.`;
13671 }, originalException);
13672}
13673/**
13674 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
13675 * creation.
13676 *
13677 * @usageNotes
13678 * ### Example
13679 *
13680 * ```typescript
13681 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
13682 * ```
13683 */
13684function invalidProviderError(provider) {
13685 return Error(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
13686}
13687/**
13688 * Thrown when the class has no annotation information.
13689 *
13690 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
13691 * need to be injected into the constructor.
13692 *
13693 * @usageNotes
13694 * ### Example
13695 *
13696 * ```typescript
13697 * class A {
13698 * constructor(b) {}
13699 * }
13700 *
13701 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
13702 * ```
13703 *
13704 * This error is also thrown when the class not marked with {@link Injectable} has parameter types.
13705 *
13706 * ```typescript
13707 * class B {}
13708 *
13709 * class A {
13710 * constructor(b:B) {} // no information about the parameter types of A is available at runtime.
13711 * }
13712 *
13713 * expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
13714 * ```
13715 *
13716 */
13717function noAnnotationError(typeOrFunc, params) {
13718 const signature = [];
13719 for (let i = 0, ii = params.length; i < ii; i++) {
13720 const parameter = params[i];
13721 if (!parameter || parameter.length == 0) {
13722 signature.push('?');
13723 }
13724 else {
13725 signature.push(parameter.map(stringify).join(' '));
13726 }
13727 }
13728 return Error('Cannot resolve all parameters for \'' + stringify(typeOrFunc) + '\'(' +
13729 signature.join(', ') + '). ' +
13730 'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
13731 stringify(typeOrFunc) + '\' is decorated with Injectable.');
13732}
13733/**
13734 * Thrown when getting an object by index.
13735 *
13736 * @usageNotes
13737 * ### Example
13738 *
13739 * ```typescript
13740 * class A {}
13741 *
13742 * var injector = Injector.resolveAndCreate([A]);
13743 *
13744 * expect(() => injector.getAt(100)).toThrowError();
13745 * ```
13746 *
13747 */
13748function outOfBoundsError(index) {
13749 return Error(`Index ${index} is out-of-bounds.`);
13750}
13751// TODO: add a working example after alpha38 is released
13752/**
13753 * Thrown when a multi provider and a regular provider are bound to the same token.
13754 *
13755 * @usageNotes
13756 * ### Example
13757 *
13758 * ```typescript
13759 * expect(() => Injector.resolveAndCreate([
13760 * { provide: "Strings", useValue: "string1", multi: true},
13761 * { provide: "Strings", useValue: "string2", multi: false}
13762 * ])).toThrowError();
13763 * ```
13764 */
13765function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) {
13766 return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
13767}
13768
13769/**
13770 * @license
13771 * Copyright Google LLC All Rights Reserved.
13772 *
13773 * Use of this source code is governed by an MIT-style license that can be
13774 * found in the LICENSE file at https://angular.io/license
13775 */
13776/**
13777 * A unique object used for retrieving items from the {@link ReflectiveInjector}.
13778 *
13779 * Keys have:
13780 * - a system-wide unique `id`.
13781 * - a `token`.
13782 *
13783 * `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
13784 * the
13785 * injector to store created objects in a more efficient way.
13786 *
13787 * `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
13788 * resolving
13789 * providers.
13790 *
13791 * @deprecated No replacement
13792 * @publicApi
13793 */
13794class ReflectiveKey {
13795 /**
13796 * Private
13797 */
13798 constructor(token, id) {
13799 this.token = token;
13800 this.id = id;
13801 if (!token) {
13802 throw new Error('Token must be defined!');
13803 }
13804 this.displayName = stringify(this.token);
13805 }
13806 /**
13807 * Retrieves a `Key` for a token.
13808 */
13809 static get(token) {
13810 return _globalKeyRegistry.get(resolveForwardRef(token));
13811 }
13812 /**
13813 * @returns the number of keys registered in the system.
13814 */
13815 static get numberOfKeys() {
13816 return _globalKeyRegistry.numberOfKeys;
13817 }
13818}
13819class KeyRegistry {
13820 constructor() {
13821 this._allKeys = new Map();
13822 }
13823 get(token) {
13824 if (token instanceof ReflectiveKey)
13825 return token;
13826 if (this._allKeys.has(token)) {
13827 return this._allKeys.get(token);
13828 }
13829 const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
13830 this._allKeys.set(token, newKey);
13831 return newKey;
13832 }
13833 get numberOfKeys() {
13834 return this._allKeys.size;
13835 }
13836}
13837const _globalKeyRegistry = new KeyRegistry();
13838
13839/**
13840 * @license
13841 * Copyright Google LLC All Rights Reserved.
13842 *
13843 * Use of this source code is governed by an MIT-style license that can be
13844 * found in the LICENSE file at https://angular.io/license
13845 */
13846/**
13847 * Provides access to reflection data about symbols. Used internally by Angular
13848 * to power dependency injection and compilation.
13849 */
13850class Reflector {
13851 constructor(reflectionCapabilities) {
13852 this.reflectionCapabilities = reflectionCapabilities;
13853 }
13854 updateCapabilities(caps) {
13855 this.reflectionCapabilities = caps;
13856 }
13857 factory(type) {
13858 return this.reflectionCapabilities.factory(type);
13859 }
13860 parameters(typeOrFunc) {
13861 return this.reflectionCapabilities.parameters(typeOrFunc);
13862 }
13863 annotations(typeOrFunc) {
13864 return this.reflectionCapabilities.annotations(typeOrFunc);
13865 }
13866 propMetadata(typeOrFunc) {
13867 return this.reflectionCapabilities.propMetadata(typeOrFunc);
13868 }
13869 hasLifecycleHook(type, lcProperty) {
13870 return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
13871 }
13872 getter(name) {
13873 return this.reflectionCapabilities.getter(name);
13874 }
13875 setter(name) {
13876 return this.reflectionCapabilities.setter(name);
13877 }
13878 method(name) {
13879 return this.reflectionCapabilities.method(name);
13880 }
13881 importUri(type) {
13882 return this.reflectionCapabilities.importUri(type);
13883 }
13884 resourceUri(type) {
13885 return this.reflectionCapabilities.resourceUri(type);
13886 }
13887 resolveIdentifier(name, moduleUrl, members, runtime) {
13888 return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime);
13889 }
13890 resolveEnum(identifier, name) {
13891 return this.reflectionCapabilities.resolveEnum(identifier, name);
13892 }
13893}
13894
13895/**
13896 * @license
13897 * Copyright Google LLC All Rights Reserved.
13898 *
13899 * Use of this source code is governed by an MIT-style license that can be
13900 * found in the LICENSE file at https://angular.io/license
13901 */
13902/**
13903 * The {@link Reflector} used internally in Angular to access metadata
13904 * about symbols.
13905 */
13906const reflector = new Reflector(new ReflectionCapabilities());
13907
13908/**
13909 * @license
13910 * Copyright Google LLC All Rights Reserved.
13911 *
13912 * Use of this source code is governed by an MIT-style license that can be
13913 * found in the LICENSE file at https://angular.io/license
13914 */
13915/**
13916 * `Dependency` is used by the framework to extend DI.
13917 * This is internal to Angular and should not be used directly.
13918 */
13919class ReflectiveDependency {
13920 constructor(key, optional, visibility) {
13921 this.key = key;
13922 this.optional = optional;
13923 this.visibility = visibility;
13924 }
13925 static fromKey(key) {
13926 return new ReflectiveDependency(key, false, null);
13927 }
13928}
13929const _EMPTY_LIST = [];
13930class ResolvedReflectiveProvider_ {
13931 constructor(key, resolvedFactories, multiProvider) {
13932 this.key = key;
13933 this.resolvedFactories = resolvedFactories;
13934 this.multiProvider = multiProvider;
13935 this.resolvedFactory = this.resolvedFactories[0];
13936 }
13937}
13938/**
13939 * An internal resolved representation of a factory function created by resolving `Provider`.
13940 * @publicApi
13941 */
13942class ResolvedReflectiveFactory {
13943 constructor(
13944 /**
13945 * Factory function which can return an instance of an object represented by a key.
13946 */
13947 factory,
13948 /**
13949 * Arguments (dependencies) to the `factory` function.
13950 */
13951 dependencies) {
13952 this.factory = factory;
13953 this.dependencies = dependencies;
13954 }
13955}
13956/**
13957 * Resolve a single provider.
13958 */
13959function resolveReflectiveFactory(provider) {
13960 let factoryFn;
13961 let resolvedDeps;
13962 if (provider.useClass) {
13963 const useClass = resolveForwardRef(provider.useClass);
13964 factoryFn = reflector.factory(useClass);
13965 resolvedDeps = _dependenciesFor(useClass);
13966 }
13967 else if (provider.useExisting) {
13968 factoryFn = (aliasInstance) => aliasInstance;
13969 resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
13970 }
13971 else if (provider.useFactory) {
13972 factoryFn = provider.useFactory;
13973 resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
13974 }
13975 else {
13976 factoryFn = () => provider.useValue;
13977 resolvedDeps = _EMPTY_LIST;
13978 }
13979 return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
13980}
13981/**
13982 * Converts the `Provider` into `ResolvedProvider`.
13983 *
13984 * `Injector` internally only uses `ResolvedProvider`, `Provider` contains convenience provider
13985 * syntax.
13986 */
13987function resolveReflectiveProvider(provider) {
13988 return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false);
13989}
13990/**
13991 * Resolve a list of Providers.
13992 */
13993function resolveReflectiveProviders(providers) {
13994 const normalized = _normalizeProviders(providers, []);
13995 const resolved = normalized.map(resolveReflectiveProvider);
13996 const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
13997 return Array.from(resolvedProviderMap.values());
13998}
13999/**
14000 * Merges a list of ResolvedProviders into a list where each key is contained exactly once and
14001 * multi providers have been merged.
14002 */
14003function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) {
14004 for (let i = 0; i < providers.length; i++) {
14005 const provider = providers[i];
14006 const existing = normalizedProvidersMap.get(provider.key.id);
14007 if (existing) {
14008 if (provider.multiProvider !== existing.multiProvider) {
14009 throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
14010 }
14011 if (provider.multiProvider) {
14012 for (let j = 0; j < provider.resolvedFactories.length; j++) {
14013 existing.resolvedFactories.push(provider.resolvedFactories[j]);
14014 }
14015 }
14016 else {
14017 normalizedProvidersMap.set(provider.key.id, provider);
14018 }
14019 }
14020 else {
14021 let resolvedProvider;
14022 if (provider.multiProvider) {
14023 resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider);
14024 }
14025 else {
14026 resolvedProvider = provider;
14027 }
14028 normalizedProvidersMap.set(provider.key.id, resolvedProvider);
14029 }
14030 }
14031 return normalizedProvidersMap;
14032}
14033function _normalizeProviders(providers, res) {
14034 providers.forEach(b => {
14035 if (b instanceof Type) {
14036 res.push({ provide: b, useClass: b });
14037 }
14038 else if (b && typeof b == 'object' && b.provide !== undefined) {
14039 res.push(b);
14040 }
14041 else if (Array.isArray(b)) {
14042 _normalizeProviders(b, res);
14043 }
14044 else {
14045 throw invalidProviderError(b);
14046 }
14047 });
14048 return res;
14049}
14050function constructDependencies(typeOrFunc, dependencies) {
14051 if (!dependencies) {
14052 return _dependenciesFor(typeOrFunc);
14053 }
14054 else {
14055 const params = dependencies.map(t => [t]);
14056 return dependencies.map(t => _extractToken(typeOrFunc, t, params));
14057 }
14058}
14059function _dependenciesFor(typeOrFunc) {
14060 const params = reflector.parameters(typeOrFunc);
14061 if (!params)
14062 return [];
14063 if (params.some(p => p == null)) {
14064 throw noAnnotationError(typeOrFunc, params);
14065 }
14066 return params.map(p => _extractToken(typeOrFunc, p, params));
14067}
14068function _extractToken(typeOrFunc, metadata, params) {
14069 let token = null;
14070 let optional = false;
14071 if (!Array.isArray(metadata)) {
14072 if (metadata instanceof Inject) {
14073 return _createDependency(metadata.token, optional, null);
14074 }
14075 else {
14076 return _createDependency(metadata, optional, null);
14077 }
14078 }
14079 let visibility = null;
14080 for (let i = 0; i < metadata.length; ++i) {
14081 const paramMetadata = metadata[i];
14082 if (paramMetadata instanceof Type) {
14083 token = paramMetadata;
14084 }
14085 else if (paramMetadata instanceof Inject) {
14086 token = paramMetadata.token;
14087 }
14088 else if (paramMetadata instanceof Optional) {
14089 optional = true;
14090 }
14091 else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
14092 visibility = paramMetadata;
14093 }
14094 else if (paramMetadata instanceof InjectionToken) {
14095 token = paramMetadata;
14096 }
14097 }
14098 token = resolveForwardRef(token);
14099 if (token != null) {
14100 return _createDependency(token, optional, visibility);
14101 }
14102 else {
14103 throw noAnnotationError(typeOrFunc, params);
14104 }
14105}
14106function _createDependency(token, optional, visibility) {
14107 return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
14108}
14109
14110/**
14111 * @license
14112 * Copyright Google LLC All Rights Reserved.
14113 *
14114 * Use of this source code is governed by an MIT-style license that can be
14115 * found in the LICENSE file at https://angular.io/license
14116 */
14117// Threshold for the dynamic version
14118const UNDEFINED = {};
14119/**
14120 * A ReflectiveDependency injection container used for instantiating objects and resolving
14121 * dependencies.
14122 *
14123 * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
14124 * constructor dependencies.
14125 *
14126 * In typical use, application code asks for the dependencies in the constructor and they are
14127 * resolved by the `Injector`.
14128 *
14129 * @usageNotes
14130 * ### Example
14131 *
14132 * The following example creates an `Injector` configured to create `Engine` and `Car`.
14133 *
14134 * ```typescript
14135 * @Injectable()
14136 * class Engine {
14137 * }
14138 *
14139 * @Injectable()
14140 * class Car {
14141 * constructor(public engine:Engine) {}
14142 * }
14143 *
14144 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
14145 * var car = injector.get(Car);
14146 * expect(car instanceof Car).toBe(true);
14147 * expect(car.engine instanceof Engine).toBe(true);
14148 * ```
14149 *
14150 * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
14151 * resolve all of the object's dependencies automatically.
14152 *
14153 * TODO: delete in v14.
14154 *
14155 * @deprecated from v5 - slow and brings in a lot of code, Use `Injector.create` instead.
14156 * @publicApi
14157 */
14158class ReflectiveInjector {
14159 /**
14160 * Turns an array of provider definitions into an array of resolved providers.
14161 *
14162 * A resolution is a process of flattening multiple nested arrays and converting individual
14163 * providers into an array of `ResolvedReflectiveProvider`s.
14164 *
14165 * @usageNotes
14166 * ### Example
14167 *
14168 * ```typescript
14169 * @Injectable()
14170 * class Engine {
14171 * }
14172 *
14173 * @Injectable()
14174 * class Car {
14175 * constructor(public engine:Engine) {}
14176 * }
14177 *
14178 * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
14179 *
14180 * expect(providers.length).toEqual(2);
14181 *
14182 * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
14183 * expect(providers[0].key.displayName).toBe("Car");
14184 * expect(providers[0].dependencies.length).toEqual(1);
14185 * expect(providers[0].factory).toBeDefined();
14186 *
14187 * expect(providers[1].key.displayName).toBe("Engine");
14188 * });
14189 * ```
14190 *
14191 */
14192 static resolve(providers) {
14193 return resolveReflectiveProviders(providers);
14194 }
14195 /**
14196 * Resolves an array of providers and creates an injector from those providers.
14197 *
14198 * The passed-in providers can be an array of `Type`, `Provider`,
14199 * or a recursive array of more providers.
14200 *
14201 * @usageNotes
14202 * ### Example
14203 *
14204 * ```typescript
14205 * @Injectable()
14206 * class Engine {
14207 * }
14208 *
14209 * @Injectable()
14210 * class Car {
14211 * constructor(public engine:Engine) {}
14212 * }
14213 *
14214 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
14215 * expect(injector.get(Car) instanceof Car).toBe(true);
14216 * ```
14217 */
14218 static resolveAndCreate(providers, parent) {
14219 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
14220 return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
14221 }
14222 /**
14223 * Creates an injector from previously resolved providers.
14224 *
14225 * This API is the recommended way to construct injectors in performance-sensitive parts.
14226 *
14227 * @usageNotes
14228 * ### Example
14229 *
14230 * ```typescript
14231 * @Injectable()
14232 * class Engine {
14233 * }
14234 *
14235 * @Injectable()
14236 * class Car {
14237 * constructor(public engine:Engine) {}
14238 * }
14239 *
14240 * var providers = ReflectiveInjector.resolve([Car, Engine]);
14241 * var injector = ReflectiveInjector.fromResolvedProviders(providers);
14242 * expect(injector.get(Car) instanceof Car).toBe(true);
14243 * ```
14244 */
14245 static fromResolvedProviders(providers, parent) {
14246 return new ReflectiveInjector_(providers, parent);
14247 }
14248}
14249class ReflectiveInjector_ {
14250 /**
14251 * Private
14252 */
14253 constructor(_providers, _parent) {
14254 /** @internal */
14255 this._constructionCounter = 0;
14256 this._providers = _providers;
14257 this.parent = _parent || null;
14258 const len = _providers.length;
14259 this.keyIds = [];
14260 this.objs = [];
14261 for (let i = 0; i < len; i++) {
14262 this.keyIds[i] = _providers[i].key.id;
14263 this.objs[i] = UNDEFINED;
14264 }
14265 }
14266 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
14267 return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
14268 }
14269 resolveAndCreateChild(providers) {
14270 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
14271 return this.createChildFromResolved(ResolvedReflectiveProviders);
14272 }
14273 createChildFromResolved(providers) {
14274 const inj = new ReflectiveInjector_(providers);
14275 inj.parent = this;
14276 return inj;
14277 }
14278 resolveAndInstantiate(provider) {
14279 return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
14280 }
14281 instantiateResolved(provider) {
14282 return this._instantiateProvider(provider);
14283 }
14284 getProviderAtIndex(index) {
14285 if (index < 0 || index >= this._providers.length) {
14286 throw outOfBoundsError(index);
14287 }
14288 return this._providers[index];
14289 }
14290 /** @internal */
14291 _new(provider) {
14292 if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
14293 throw cyclicDependencyError(this, provider.key);
14294 }
14295 return this._instantiateProvider(provider);
14296 }
14297 _getMaxNumberOfObjects() {
14298 return this.objs.length;
14299 }
14300 _instantiateProvider(provider) {
14301 if (provider.multiProvider) {
14302 const res = [];
14303 for (let i = 0; i < provider.resolvedFactories.length; ++i) {
14304 res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
14305 }
14306 return res;
14307 }
14308 else {
14309 return this._instantiate(provider, provider.resolvedFactories[0]);
14310 }
14311 }
14312 _instantiate(provider, ResolvedReflectiveFactory) {
14313 const factory = ResolvedReflectiveFactory.factory;
14314 let deps;
14315 try {
14316 deps =
14317 ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
14318 }
14319 catch (e) {
14320 if (e.addKey) {
14321 e.addKey(this, provider.key);
14322 }
14323 throw e;
14324 }
14325 let obj;
14326 try {
14327 obj = factory(...deps);
14328 }
14329 catch (e) {
14330 throw instantiationError(this, e, e.stack, provider.key);
14331 }
14332 return obj;
14333 }
14334 _getByReflectiveDependency(dep) {
14335 return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
14336 }
14337 _getByKey(key, visibility, notFoundValue) {
14338 if (key === ReflectiveInjector_.INJECTOR_KEY) {
14339 return this;
14340 }
14341 if (visibility instanceof Self) {
14342 return this._getByKeySelf(key, notFoundValue);
14343 }
14344 else {
14345 return this._getByKeyDefault(key, notFoundValue, visibility);
14346 }
14347 }
14348 _getObjByKeyId(keyId) {
14349 for (let i = 0; i < this.keyIds.length; i++) {
14350 if (this.keyIds[i] === keyId) {
14351 if (this.objs[i] === UNDEFINED) {
14352 this.objs[i] = this._new(this._providers[i]);
14353 }
14354 return this.objs[i];
14355 }
14356 }
14357 return UNDEFINED;
14358 }
14359 /** @internal */
14360 _throwOrNull(key, notFoundValue) {
14361 if (notFoundValue !== THROW_IF_NOT_FOUND) {
14362 return notFoundValue;
14363 }
14364 else {
14365 throw noProviderError(this, key);
14366 }
14367 }
14368 /** @internal */
14369 _getByKeySelf(key, notFoundValue) {
14370 const obj = this._getObjByKeyId(key.id);
14371 return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
14372 }
14373 /** @internal */
14374 _getByKeyDefault(key, notFoundValue, visibility) {
14375 let inj;
14376 if (visibility instanceof SkipSelf) {
14377 inj = this.parent;
14378 }
14379 else {
14380 inj = this;
14381 }
14382 while (inj instanceof ReflectiveInjector_) {
14383 const inj_ = inj;
14384 const obj = inj_._getObjByKeyId(key.id);
14385 if (obj !== UNDEFINED)
14386 return obj;
14387 inj = inj_.parent;
14388 }
14389 if (inj !== null) {
14390 return inj.get(key.token, notFoundValue);
14391 }
14392 else {
14393 return this._throwOrNull(key, notFoundValue);
14394 }
14395 }
14396 get displayName() {
14397 const providers = _mapProviders(this, (b) => ' "' + b.key.displayName + '" ')
14398 .join(', ');
14399 return `ReflectiveInjector(providers: [${providers}])`;
14400 }
14401 toString() {
14402 return this.displayName;
14403 }
14404}
14405ReflectiveInjector_.INJECTOR_KEY = ( /* @__PURE__ */ReflectiveKey.get(Injector));
14406function _mapProviders(injector, fn) {
14407 const res = [];
14408 for (let i = 0; i < injector._providers.length; ++i) {
14409 res[i] = fn(injector.getProviderAtIndex(i));
14410 }
14411 return res;
14412}
14413
14414/**
14415 * @license
14416 * Copyright Google LLC All Rights Reserved.
14417 *
14418 * Use of this source code is governed by an MIT-style license that can be
14419 * found in the LICENSE file at https://angular.io/license
14420 */
14421
14422/**
14423 * @license
14424 * Copyright Google LLC All Rights Reserved.
14425 *
14426 * Use of this source code is governed by an MIT-style license that can be
14427 * found in the LICENSE file at https://angular.io/license
14428 */
14429
14430/**
14431 * @license
14432 * Copyright Google LLC All Rights Reserved.
14433 *
14434 * Use of this source code is governed by an MIT-style license that can be
14435 * found in the LICENSE file at https://angular.io/license
14436 */
14437function ɵɵdirectiveInject(token, flags = InjectFlags.Default) {
14438 const lView = getLView();
14439 // Fall back to inject() if view hasn't been created. This situation can happen in tests
14440 // if inject utilities are used before bootstrapping.
14441 if (lView === null) {
14442 // Verify that we will not get into infinite loop.
14443 ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject);
14444 return ɵɵinject(token, flags);
14445 }
14446 const tNode = getCurrentTNode();
14447 return getOrCreateInjectable(tNode, lView, resolveForwardRef(token), flags);
14448}
14449/**
14450 * Throws an error indicating that a factory function could not be generated by the compiler for a
14451 * particular class.
14452 *
14453 * This instruction allows the actual error message to be optimized away when ngDevMode is turned
14454 * off, saving bytes of generated code while still providing a good experience in dev mode.
14455 *
14456 * The name of the class is not mentioned here, but will be in the generated factory function name
14457 * and thus in the stack trace.
14458 *
14459 * @codeGenApi
14460 */
14461function ɵɵinvalidFactory() {
14462 const msg = ngDevMode ? `This constructor was not compatible with Dependency Injection.` : 'invalid';
14463 throw new Error(msg);
14464}
14465
14466/**
14467 * @license
14468 * Copyright Google LLC All Rights Reserved.
14469 *
14470 * Use of this source code is governed by an MIT-style license that can be
14471 * found in the LICENSE file at https://angular.io/license
14472 */
14473/**
14474 * Update a property on a selected element.
14475 *
14476 * Operates on the element selected by index via the {@link select} instruction.
14477 *
14478 * If the property name also exists as an input property on one of the element's directives,
14479 * the component property will be set instead of the element property. This check must
14480 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled
14481 *
14482 * @param propName Name of property. Because it is going to DOM, this is not subject to
14483 * renaming as part of minification.
14484 * @param value New value to write.
14485 * @param sanitizer An optional function used to sanitize the value.
14486 * @returns This function returns itself so that it may be chained
14487 * (e.g. `property('name', ctx.name)('title', ctx.title)`)
14488 *
14489 * @codeGenApi
14490 */
14491function ɵɵproperty(propName, value, sanitizer) {
14492 const lView = getLView();
14493 const bindingIndex = nextBindingIndex();
14494 if (bindingUpdated(lView, bindingIndex, value)) {
14495 const tView = getTView();
14496 const tNode = getSelectedTNode();
14497 elementPropertyInternal(tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, false);
14498 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
14499 }
14500 return ɵɵproperty;
14501}
14502/**
14503 * Given `<div style="..." my-dir>` and `MyDir` with `@Input('style')` we need to write to
14504 * directive input.
14505 */
14506function setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased) {
14507 const inputs = tNode.inputs;
14508 const property = isClassBased ? 'class' : 'style';
14509 // We support both 'class' and `className` hence the fallback.
14510 setInputsForProperty(tView, lView, inputs[property], property, value);
14511}
14512
14513/**
14514 * @license
14515 * Copyright Google LLC All Rights Reserved.
14516 *
14517 * Use of this source code is governed by an MIT-style license that can be
14518 * found in the LICENSE file at https://angular.io/license
14519 */
14520function elementStartFirstCreatePass(index, tView, lView, native, name, attrsIndex, localRefsIndex) {
14521 ngDevMode && assertFirstCreatePass(tView);
14522 ngDevMode && ngDevMode.firstCreatePass++;
14523 const tViewConsts = tView.consts;
14524 const attrs = getConstant(tViewConsts, attrsIndex);
14525 const tNode = getOrCreateTNode(tView, index, 2 /* Element */, name, attrs);
14526 const hasDirectives = resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
14527 ngDevMode && validateElementIsKnown(native, tNode.value, tView.schemas, hasDirectives);
14528 if (tNode.attrs !== null) {
14529 computeStaticStyling(tNode, tNode.attrs, false);
14530 }
14531 if (tNode.mergedAttrs !== null) {
14532 computeStaticStyling(tNode, tNode.mergedAttrs, true);
14533 }
14534 if (tView.queries !== null) {
14535 tView.queries.elementStart(tView, tNode);
14536 }
14537 return tNode;
14538}
14539/**
14540 * Create DOM element. The instruction must later be followed by `elementEnd()` call.
14541 *
14542 * @param index Index of the element in the LView array
14543 * @param name Name of the DOM Node
14544 * @param attrsIndex Index of the element's attributes in the `consts` array.
14545 * @param localRefsIndex Index of the element's local references in the `consts` array.
14546 * @returns This function returns itself so that it may be chained.
14547 *
14548 * Attributes and localRefs are passed as an array of strings where elements with an even index
14549 * hold an attribute name and elements with an odd index hold an attribute value, ex.:
14550 * ['id', 'warning5', 'class', 'alert']
14551 *
14552 * @codeGenApi
14553 */
14554function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
14555 const lView = getLView();
14556 const tView = getTView();
14557 const adjustedIndex = HEADER_OFFSET + index;
14558 ngDevMode &&
14559 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'elements should be created before any bindings');
14560 ngDevMode && assertIndexInRange(lView, adjustedIndex);
14561 const renderer = lView[RENDERER];
14562 const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1());
14563 const tNode = tView.firstCreatePass ?
14564 elementStartFirstCreatePass(adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
14565 tView.data[adjustedIndex];
14566 setCurrentTNode(tNode, true);
14567 const mergedAttrs = tNode.mergedAttrs;
14568 if (mergedAttrs !== null) {
14569 setUpAttributes(renderer, native, mergedAttrs);
14570 }
14571 const classes = tNode.classes;
14572 if (classes !== null) {
14573 writeDirectClass(renderer, native, classes);
14574 }
14575 const styles = tNode.styles;
14576 if (styles !== null) {
14577 writeDirectStyle(renderer, native, styles);
14578 }
14579 if ((tNode.flags & 64 /* isDetached */) !== 64 /* isDetached */) {
14580 // In the i18n case, the translation may have removed this element, so only add it if it is not
14581 // detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
14582 appendChild(tView, lView, native, tNode);
14583 }
14584 // any immediate children of a component or template container must be pre-emptively
14585 // monkey-patched with the component view data so that the element can be inspected
14586 // later on using any element discovery utility methods (see `element_discovery.ts`)
14587 if (getElementDepthCount() === 0) {
14588 attachPatchData(native, lView);
14589 }
14590 increaseElementDepthCount();
14591 if (isDirectiveHost(tNode)) {
14592 createDirectivesInstances(tView, lView, tNode);
14593 executeContentQueries(tView, tNode, lView);
14594 }
14595 if (localRefsIndex !== null) {
14596 saveResolvedLocalsInData(lView, tNode);
14597 }
14598 return ɵɵelementStart;
14599}
14600/**
14601 * Mark the end of the element.
14602 * @returns This function returns itself so that it may be chained.
14603 *
14604 * @codeGenApi
14605 */
14606function ɵɵelementEnd() {
14607 let currentTNode = getCurrentTNode();
14608 ngDevMode && assertDefined(currentTNode, 'No parent node to close.');
14609 if (isCurrentTNodeParent()) {
14610 setCurrentTNodeAsNotParent();
14611 }
14612 else {
14613 ngDevMode && assertHasParent(getCurrentTNode());
14614 currentTNode = currentTNode.parent;
14615 setCurrentTNode(currentTNode, false);
14616 }
14617 const tNode = currentTNode;
14618 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */);
14619 decreaseElementDepthCount();
14620 const tView = getTView();
14621 if (tView.firstCreatePass) {
14622 registerPostOrderHooks(tView, currentTNode);
14623 if (isContentQueryHost(currentTNode)) {
14624 tView.queries.elementEnd(currentTNode);
14625 }
14626 }
14627 if (tNode.classesWithoutHost != null && hasClassInput(tNode)) {
14628 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.classesWithoutHost, true);
14629 }
14630 if (tNode.stylesWithoutHost != null && hasStyleInput(tNode)) {
14631 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.stylesWithoutHost, false);
14632 }
14633 return ɵɵelementEnd;
14634}
14635/**
14636 * Creates an empty element using {@link elementStart} and {@link elementEnd}
14637 *
14638 * @param index Index of the element in the data array
14639 * @param name Name of the DOM Node
14640 * @param attrsIndex Index of the element's attributes in the `consts` array.
14641 * @param localRefsIndex Index of the element's local references in the `consts` array.
14642 * @returns This function returns itself so that it may be chained.
14643 *
14644 * @codeGenApi
14645 */
14646function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
14647 ɵɵelementStart(index, name, attrsIndex, localRefsIndex);
14648 ɵɵelementEnd();
14649 return ɵɵelement;
14650}
14651/**
14652 * Validates that the element is known at runtime and produces
14653 * an error if it's not the case.
14654 * This check is relevant for JIT-compiled components (for AOT-compiled
14655 * ones this check happens at build time).
14656 *
14657 * The element is considered known if either:
14658 * - it's a known HTML element
14659 * - it's a known custom element
14660 * - the element matches any directive
14661 * - the element is allowed by one of the schemas
14662 *
14663 * @param element Element to validate
14664 * @param tagName Name of the tag to check
14665 * @param schemas Array of schemas
14666 * @param hasDirectives Boolean indicating that the element matches any directive
14667 */
14668function validateElementIsKnown(element, tagName, schemas, hasDirectives) {
14669 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
14670 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
14671 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
14672 // execute the check below.
14673 if (schemas === null)
14674 return;
14675 // If the element matches any directive, it's considered as valid.
14676 if (!hasDirectives && tagName !== null) {
14677 // The element is unknown if it's an instance of HTMLUnknownElement, or it isn't registered
14678 // as a custom element. Note that unknown elements with a dash in their name won't be instances
14679 // of HTMLUnknownElement in browsers that support web components.
14680 const isUnknown =
14681 // Note that we can't check for `typeof HTMLUnknownElement === 'function'`,
14682 // because while most browsers return 'function', IE returns 'object'.
14683 (typeof HTMLUnknownElement !== 'undefined' && HTMLUnknownElement &&
14684 element instanceof HTMLUnknownElement) ||
14685 (typeof customElements !== 'undefined' && tagName.indexOf('-') > -1 &&
14686 !customElements.get(tagName));
14687 if (isUnknown && !matchingSchemas(schemas, tagName)) {
14688 let message = `'${tagName}' is not a known element:\n`;
14689 message += `1. If '${tagName}' is an Angular component, then verify that it is part of this module.\n`;
14690 if (tagName && tagName.indexOf('-') > -1) {
14691 message += `2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`;
14692 }
14693 else {
14694 message +=
14695 `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
14696 }
14697 console.error(formatRuntimeError(304 /* UNKNOWN_ELEMENT */, message));
14698 }
14699 }
14700}
14701
14702/**
14703 * @license
14704 * Copyright Google LLC All Rights Reserved.
14705 *
14706 * Use of this source code is governed by an MIT-style license that can be
14707 * found in the LICENSE file at https://angular.io/license
14708 */
14709function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) {
14710 ngDevMode && ngDevMode.firstCreatePass++;
14711 const tViewConsts = tView.consts;
14712 const attrs = getConstant(tViewConsts, attrsIndex);
14713 const tNode = getOrCreateTNode(tView, index, 8 /* ElementContainer */, 'ng-container', attrs);
14714 // While ng-container doesn't necessarily support styling, we use the style context to identify
14715 // and execute directives on the ng-container.
14716 if (attrs !== null) {
14717 computeStaticStyling(tNode, attrs, true);
14718 }
14719 const localRefs = getConstant(tViewConsts, localRefsIndex);
14720 resolveDirectives(tView, lView, tNode, localRefs);
14721 if (tView.queries !== null) {
14722 tView.queries.elementStart(tView, tNode);
14723 }
14724 return tNode;
14725}
14726/**
14727 * Creates a logical container for other nodes (<ng-container>) backed by a comment node in the DOM.
14728 * The instruction must later be followed by `elementContainerEnd()` call.
14729 *
14730 * @param index Index of the element in the LView array
14731 * @param attrsIndex Index of the container attributes in the `consts` array.
14732 * @param localRefsIndex Index of the container's local references in the `consts` array.
14733 * @returns This function returns itself so that it may be chained.
14734 *
14735 * Even if this instruction accepts a set of attributes no actual attribute values are propagated to
14736 * the DOM (as a comment node can't have attributes). Attributes are here only for directive
14737 * matching purposes and setting initial inputs of directives.
14738 *
14739 * @codeGenApi
14740 */
14741function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
14742 const lView = getLView();
14743 const tView = getTView();
14744 const adjustedIndex = index + HEADER_OFFSET;
14745 ngDevMode && assertIndexInRange(lView, adjustedIndex);
14746 ngDevMode &&
14747 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings');
14748 const tNode = tView.firstCreatePass ?
14749 elementContainerStartFirstCreatePass(adjustedIndex, tView, lView, attrsIndex, localRefsIndex) :
14750 tView.data[adjustedIndex];
14751 setCurrentTNode(tNode, true);
14752 ngDevMode && ngDevMode.rendererCreateComment++;
14753 const native = lView[adjustedIndex] =
14754 lView[RENDERER].createComment(ngDevMode ? 'ng-container' : '');
14755 appendChild(tView, lView, native, tNode);
14756 attachPatchData(native, lView);
14757 if (isDirectiveHost(tNode)) {
14758 createDirectivesInstances(tView, lView, tNode);
14759 executeContentQueries(tView, tNode, lView);
14760 }
14761 if (localRefsIndex != null) {
14762 saveResolvedLocalsInData(lView, tNode);
14763 }
14764 return ɵɵelementContainerStart;
14765}
14766/**
14767 * Mark the end of the <ng-container>.
14768 * @returns This function returns itself so that it may be chained.
14769 *
14770 * @codeGenApi
14771 */
14772function ɵɵelementContainerEnd() {
14773 let currentTNode = getCurrentTNode();
14774 const tView = getTView();
14775 if (isCurrentTNodeParent()) {
14776 setCurrentTNodeAsNotParent();
14777 }
14778 else {
14779 ngDevMode && assertHasParent(currentTNode);
14780 currentTNode = currentTNode.parent;
14781 setCurrentTNode(currentTNode, false);
14782 }
14783 ngDevMode && assertTNodeType(currentTNode, 8 /* ElementContainer */);
14784 if (tView.firstCreatePass) {
14785 registerPostOrderHooks(tView, currentTNode);
14786 if (isContentQueryHost(currentTNode)) {
14787 tView.queries.elementEnd(currentTNode);
14788 }
14789 }
14790 return ɵɵelementContainerEnd;
14791}
14792/**
14793 * Creates an empty logical container using {@link elementContainerStart}
14794 * and {@link elementContainerEnd}
14795 *
14796 * @param index Index of the element in the LView array
14797 * @param attrsIndex Index of the container attributes in the `consts` array.
14798 * @param localRefsIndex Index of the container's local references in the `consts` array.
14799 * @returns This function returns itself so that it may be chained.
14800 *
14801 * @codeGenApi
14802 */
14803function ɵɵelementContainer(index, attrsIndex, localRefsIndex) {
14804 ɵɵelementContainerStart(index, attrsIndex, localRefsIndex);
14805 ɵɵelementContainerEnd();
14806 return ɵɵelementContainer;
14807}
14808
14809/**
14810 * Returns the current OpaqueViewState instance.
14811 *
14812 * Used in conjunction with the restoreView() instruction to save a snapshot
14813 * of the current view and restore it when listeners are invoked. This allows
14814 * walking the declaration view tree in listeners to get vars from parent views.
14815 *
14816 * @codeGenApi
14817 */
14818function ɵɵgetCurrentView() {
14819 return getLView();
14820}
14821
14822/**
14823 * @license
14824 * Copyright Google LLC All Rights Reserved.
14825 *
14826 * Use of this source code is governed by an MIT-style license that can be
14827 * found in the LICENSE file at https://angular.io/license
14828 */
14829/**
14830 * Determine if the argument is shaped like a Promise
14831 */
14832function isPromise(obj) {
14833 // allow any Promise/A+ compliant thenable.
14834 // It's up to the caller to ensure that obj.then conforms to the spec
14835 return !!obj && typeof obj.then === 'function';
14836}
14837/**
14838 * Determine if the argument is a Subscribable
14839 */
14840function isSubscribable(obj) {
14841 return !!obj && typeof obj.subscribe === 'function';
14842}
14843/**
14844 * Determine if the argument is an Observable
14845 *
14846 * Strictly this tests that the `obj` is `Subscribable`, since `Observable`
14847 * types need additional methods, such as `lift()`. But it is adequate for our
14848 * needs since within the Angular framework code we only ever need to use the
14849 * `subscribe()` method, and RxJS has mechanisms to wrap `Subscribable` objects
14850 * into `Observable` as needed.
14851 */
14852const isObservable = isSubscribable;
14853
14854/**
14855 * @license
14856 * Copyright Google LLC All Rights Reserved.
14857 *
14858 * Use of this source code is governed by an MIT-style license that can be
14859 * found in the LICENSE file at https://angular.io/license
14860 */
14861/**
14862 * Adds an event listener to the current node.
14863 *
14864 * If an output exists on one of the node's directives, it also subscribes to the output
14865 * and saves the subscription for later cleanup.
14866 *
14867 * @param eventName Name of the event
14868 * @param listenerFn The function to be called when event emits
14869 * @param useCapture Whether or not to use capture in event listener
14870 * @param eventTargetResolver Function that returns global target information in case this listener
14871 * should be attached to a global object like window, document or body
14872 *
14873 * @codeGenApi
14874 */
14875function ɵɵlistener(eventName, listenerFn, useCapture, eventTargetResolver) {
14876 const lView = getLView();
14877 const tView = getTView();
14878 const tNode = getCurrentTNode();
14879 listenerInternal(tView, lView, lView[RENDERER], tNode, eventName, listenerFn, !!useCapture, eventTargetResolver);
14880 return ɵɵlistener;
14881}
14882/**
14883 * Registers a synthetic host listener (e.g. `(@foo.start)`) on a component or directive.
14884 *
14885 * This instruction is for compatibility purposes and is designed to ensure that a
14886 * synthetic host listener (e.g. `@HostListener('@foo.start')`) properly gets rendered
14887 * in the component's renderer. Normally all host listeners are evaluated with the
14888 * parent component's renderer, but, in the case of animation @triggers, they need
14889 * to be evaluated with the sub component's renderer (because that's where the
14890 * animation triggers are defined).
14891 *
14892 * Do not use this instruction as a replacement for `listener`. This instruction
14893 * only exists to ensure compatibility with the ViewEngine's host binding behavior.
14894 *
14895 * @param eventName Name of the event
14896 * @param listenerFn The function to be called when event emits
14897 * @param useCapture Whether or not to use capture in event listener
14898 * @param eventTargetResolver Function that returns global target information in case this listener
14899 * should be attached to a global object like window, document or body
14900 *
14901 * @codeGenApi
14902 */
14903function ɵɵsyntheticHostListener(eventName, listenerFn) {
14904 const tNode = getCurrentTNode();
14905 const lView = getLView();
14906 const tView = getTView();
14907 const currentDef = getCurrentDirectiveDef(tView.data);
14908 const renderer = loadComponentRenderer(currentDef, tNode, lView);
14909 listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn, false);
14910 return ɵɵsyntheticHostListener;
14911}
14912/**
14913 * A utility function that checks if a given element has already an event handler registered for an
14914 * event with a specified name. The TView.cleanup data structure is used to find out which events
14915 * are registered for a given element.
14916 */
14917function findExistingListener(tView, lView, eventName, tNodeIdx) {
14918 const tCleanup = tView.cleanup;
14919 if (tCleanup != null) {
14920 for (let i = 0; i < tCleanup.length - 1; i += 2) {
14921 const cleanupEventName = tCleanup[i];
14922 if (cleanupEventName === eventName && tCleanup[i + 1] === tNodeIdx) {
14923 // We have found a matching event name on the same node but it might not have been
14924 // registered yet, so we must explicitly verify entries in the LView cleanup data
14925 // structures.
14926 const lCleanup = lView[CLEANUP];
14927 const listenerIdxInLCleanup = tCleanup[i + 2];
14928 return lCleanup.length > listenerIdxInLCleanup ? lCleanup[listenerIdxInLCleanup] : null;
14929 }
14930 // TView.cleanup can have a mix of 4-elements entries (for event handler cleanups) or
14931 // 2-element entries (for directive and queries destroy hooks). As such we can encounter
14932 // blocks of 4 or 2 items in the tView.cleanup and this is why we iterate over 2 elements
14933 // first and jump another 2 elements if we detect listeners cleanup (4 elements). Also check
14934 // documentation of TView.cleanup for more details of this data structure layout.
14935 if (typeof cleanupEventName === 'string') {
14936 i += 2;
14937 }
14938 }
14939 }
14940 return null;
14941}
14942function listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn, useCapture, eventTargetResolver) {
14943 const isTNodeDirectiveHost = isDirectiveHost(tNode);
14944 const firstCreatePass = tView.firstCreatePass;
14945 const tCleanup = firstCreatePass && getOrCreateTViewCleanup(tView);
14946 const context = lView[CONTEXT];
14947 // When the ɵɵlistener instruction was generated and is executed we know that there is either a
14948 // native listener or a directive output on this element. As such we we know that we will have to
14949 // register a listener and store its cleanup function on LView.
14950 const lCleanup = getOrCreateLViewCleanup(lView);
14951 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */);
14952 let processOutputs = true;
14953 // Adding a native event listener is applicable when:
14954 // - The corresponding TNode represents a DOM element.
14955 // - The event target has a resolver (usually resulting in a global object,
14956 // such as `window` or `document`).
14957 if ((tNode.type & 3 /* AnyRNode */) || eventTargetResolver) {
14958 const native = getNativeByTNode(tNode, lView);
14959 const target = eventTargetResolver ? eventTargetResolver(native) : native;
14960 const lCleanupIndex = lCleanup.length;
14961 const idxOrTargetGetter = eventTargetResolver ?
14962 (_lView) => eventTargetResolver(unwrapRNode(_lView[tNode.index])) :
14963 tNode.index;
14964 // In order to match current behavior, native DOM event listeners must be added for all
14965 // events (including outputs).
14966 if (isProceduralRenderer(renderer)) {
14967 // There might be cases where multiple directives on the same element try to register an event
14968 // handler function for the same event. In this situation we want to avoid registration of
14969 // several native listeners as each registration would be intercepted by NgZone and
14970 // trigger change detection. This would mean that a single user action would result in several
14971 // change detections being invoked. To avoid this situation we want to have only one call to
14972 // native handler registration (for the same element and same type of event).
14973 //
14974 // In order to have just one native event handler in presence of multiple handler functions,
14975 // we just register a first handler function as a native event listener and then chain
14976 // (coalesce) other handler functions on top of the first native handler function.
14977 let existingListener = null;
14978 // Please note that the coalescing described here doesn't happen for events specifying an
14979 // alternative target (ex. (document:click)) - this is to keep backward compatibility with the
14980 // view engine.
14981 // Also, we don't have to search for existing listeners is there are no directives
14982 // matching on a given node as we can't register multiple event handlers for the same event in
14983 // a template (this would mean having duplicate attributes).
14984 if (!eventTargetResolver && isTNodeDirectiveHost) {
14985 existingListener = findExistingListener(tView, lView, eventName, tNode.index);
14986 }
14987 if (existingListener !== null) {
14988 // Attach a new listener to coalesced listeners list, maintaining the order in which
14989 // listeners are registered. For performance reasons, we keep a reference to the last
14990 // listener in that list (in `__ngLastListenerFn__` field), so we can avoid going through
14991 // the entire set each time we need to add a new listener.
14992 const lastListenerFn = existingListener.__ngLastListenerFn__ || existingListener;
14993 lastListenerFn.__ngNextListenerFn__ = listenerFn;
14994 existingListener.__ngLastListenerFn__ = listenerFn;
14995 processOutputs = false;
14996 }
14997 else {
14998 listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
14999 const cleanupFn = renderer.listen(target, eventName, listenerFn);
15000 ngDevMode && ngDevMode.rendererAddEventListener++;
15001 lCleanup.push(listenerFn, cleanupFn);
15002 tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1);
15003 }
15004 }
15005 else {
15006 listenerFn = wrapListener(tNode, lView, context, listenerFn, true /** preventDefault */);
15007 target.addEventListener(eventName, listenerFn, useCapture);
15008 ngDevMode && ngDevMode.rendererAddEventListener++;
15009 lCleanup.push(listenerFn);
15010 tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCapture);
15011 }
15012 }
15013 else {
15014 // Even if there is no native listener to add, we still need to wrap the listener so that OnPush
15015 // ancestors are marked dirty when an event occurs.
15016 listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
15017 }
15018 // subscribe to directive outputs
15019 const outputs = tNode.outputs;
15020 let props;
15021 if (processOutputs && outputs !== null && (props = outputs[eventName])) {
15022 const propsLength = props.length;
15023 if (propsLength) {
15024 for (let i = 0; i < propsLength; i += 2) {
15025 const index = props[i];
15026 ngDevMode && assertIndexInRange(lView, index);
15027 const minifiedName = props[i + 1];
15028 const directiveInstance = lView[index];
15029 const output = directiveInstance[minifiedName];
15030 if (ngDevMode && !isObservable(output)) {
15031 throw new Error(`@Output ${minifiedName} not initialized in '${directiveInstance.constructor.name}'.`);
15032 }
15033 const subscription = output.subscribe(listenerFn);
15034 const idx = lCleanup.length;
15035 lCleanup.push(listenerFn, subscription);
15036 tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
15037 }
15038 }
15039 }
15040}
15041function executeListenerWithErrorHandling(lView, context, listenerFn, e) {
15042 try {
15043 profiler(6 /* OutputStart */, context, listenerFn);
15044 // Only explicitly returning false from a listener should preventDefault
15045 return listenerFn(e) !== false;
15046 }
15047 catch (error) {
15048 handleError(lView, error);
15049 return false;
15050 }
15051 finally {
15052 profiler(7 /* OutputEnd */, context, listenerFn);
15053 }
15054}
15055/**
15056 * Wraps an event listener with a function that marks ancestors dirty and prevents default behavior,
15057 * if applicable.
15058 *
15059 * @param tNode The TNode associated with this listener
15060 * @param lView The LView that contains this listener
15061 * @param listenerFn The listener function to call
15062 * @param wrapWithPreventDefault Whether or not to prevent default behavior
15063 * (the procedural renderer does this already, so in those cases, we should skip)
15064 */
15065function wrapListener(tNode, lView, context, listenerFn, wrapWithPreventDefault) {
15066 // Note: we are performing most of the work in the listener function itself
15067 // to optimize listener registration.
15068 return function wrapListenerIn_markDirtyAndPreventDefault(e) {
15069 // Ivy uses `Function` as a special token that allows us to unwrap the function
15070 // so that it can be invoked programmatically by `DebugNode.triggerEventHandler`.
15071 if (e === Function) {
15072 return listenerFn;
15073 }
15074 // In order to be backwards compatible with View Engine, events on component host nodes
15075 // must also mark the component view itself dirty (i.e. the view that it owns).
15076 const startView = tNode.flags & 2 /* isComponentHost */ ?
15077 getComponentLViewByIndex(tNode.index, lView) :
15078 lView;
15079 // See interfaces/view.ts for more on LViewFlags.ManualOnPush
15080 if ((lView[FLAGS] & 32 /* ManualOnPush */) === 0) {
15081 markViewDirty(startView);
15082 }
15083 let result = executeListenerWithErrorHandling(lView, context, listenerFn, e);
15084 // A just-invoked listener function might have coalesced listeners so we need to check for
15085 // their presence and invoke as needed.
15086 let nextListenerFn = wrapListenerIn_markDirtyAndPreventDefault.__ngNextListenerFn__;
15087 while (nextListenerFn) {
15088 // We should prevent default if any of the listeners explicitly return false
15089 result = executeListenerWithErrorHandling(lView, context, nextListenerFn, e) && result;
15090 nextListenerFn = nextListenerFn.__ngNextListenerFn__;
15091 }
15092 if (wrapWithPreventDefault && result === false) {
15093 e.preventDefault();
15094 // Necessary for legacy browsers that don't support preventDefault (e.g. IE)
15095 e.returnValue = false;
15096 }
15097 return result;
15098 };
15099}
15100
15101/**
15102 * @license
15103 * Copyright Google LLC All Rights Reserved.
15104 *
15105 * Use of this source code is governed by an MIT-style license that can be
15106 * found in the LICENSE file at https://angular.io/license
15107 */
15108
15109/**
15110 * @license
15111 * Copyright Google LLC All Rights Reserved.
15112 *
15113 * Use of this source code is governed by an MIT-style license that can be
15114 * found in the LICENSE file at https://angular.io/license
15115 */
15116/**
15117 * Retrieves a context at the level specified and saves it as the global, contextViewData.
15118 * Will get the next level up if level is not specified.
15119 *
15120 * This is used to save contexts of parent views so they can be bound in embedded views, or
15121 * in conjunction with reference() to bind a ref from a parent view.
15122 *
15123 * @param level The relative level of the view from which to grab context compared to contextVewData
15124 * @returns context
15125 *
15126 * @codeGenApi
15127 */
15128function ɵɵnextContext(level = 1) {
15129 return nextContextImpl(level);
15130}
15131
15132/**
15133 * @license
15134 * Copyright Google LLC All Rights Reserved.
15135 *
15136 * Use of this source code is governed by an MIT-style license that can be
15137 * found in the LICENSE file at https://angular.io/license
15138 */
15139/**
15140 * Checks a given node against matching projection slots and returns the
15141 * determined slot index. Returns "null" if no slot matched the given node.
15142 *
15143 * This function takes into account the parsed ngProjectAs selector from the
15144 * node's attributes. If present, it will check whether the ngProjectAs selector
15145 * matches any of the projection slot selectors.
15146 */
15147function matchingProjectionSlotIndex(tNode, projectionSlots) {
15148 let wildcardNgContentIndex = null;
15149 const ngProjectAsAttrVal = getProjectAsAttrValue(tNode);
15150 for (let i = 0; i < projectionSlots.length; i++) {
15151 const slotValue = projectionSlots[i];
15152 // The last wildcard projection slot should match all nodes which aren't matching
15153 // any selector. This is necessary to be backwards compatible with view engine.
15154 if (slotValue === '*') {
15155 wildcardNgContentIndex = i;
15156 continue;
15157 }
15158 // If we ran into an `ngProjectAs` attribute, we should match its parsed selector
15159 // to the list of selectors, otherwise we fall back to matching against the node.
15160 if (ngProjectAsAttrVal === null ?
15161 isNodeMatchingSelectorList(tNode, slotValue, /* isProjectionMode */ true) :
15162 isSelectorInSelectorList(ngProjectAsAttrVal, slotValue)) {
15163 return i; // first matching selector "captures" a given node
15164 }
15165 }
15166 return wildcardNgContentIndex;
15167}
15168/**
15169 * Instruction to distribute projectable nodes among <ng-content> occurrences in a given template.
15170 * It takes all the selectors from the entire component's template and decides where
15171 * each projected node belongs (it re-distributes nodes among "buckets" where each "bucket" is
15172 * backed by a selector).
15173 *
15174 * This function requires CSS selectors to be provided in 2 forms: parsed (by a compiler) and text,
15175 * un-parsed form.
15176 *
15177 * The parsed form is needed for efficient matching of a node against a given CSS selector.
15178 * The un-parsed, textual form is needed for support of the ngProjectAs attribute.
15179 *
15180 * Having a CSS selector in 2 different formats is not ideal, but alternatives have even more
15181 * drawbacks:
15182 * - having only a textual form would require runtime parsing of CSS selectors;
15183 * - we can't have only a parsed as we can't re-construct textual form from it (as entered by a
15184 * template author).
15185 *
15186 * @param projectionSlots? A collection of projection slots. A projection slot can be based
15187 * on a parsed CSS selectors or set to the wildcard selector ("*") in order to match
15188 * all nodes which do not match any selector. If not specified, a single wildcard
15189 * selector projection slot will be defined.
15190 *
15191 * @codeGenApi
15192 */
15193function ɵɵprojectionDef(projectionSlots) {
15194 const componentNode = getLView()[DECLARATION_COMPONENT_VIEW][T_HOST];
15195 if (!componentNode.projection) {
15196 // If no explicit projection slots are defined, fall back to a single
15197 // projection slot with the wildcard selector.
15198 const numProjectionSlots = projectionSlots ? projectionSlots.length : 1;
15199 const projectionHeads = componentNode.projection =
15200 newArray(numProjectionSlots, null);
15201 const tails = projectionHeads.slice();
15202 let componentChild = componentNode.child;
15203 while (componentChild !== null) {
15204 const slotIndex = projectionSlots ? matchingProjectionSlotIndex(componentChild, projectionSlots) : 0;
15205 if (slotIndex !== null) {
15206 if (tails[slotIndex]) {
15207 tails[slotIndex].projectionNext = componentChild;
15208 }
15209 else {
15210 projectionHeads[slotIndex] = componentChild;
15211 }
15212 tails[slotIndex] = componentChild;
15213 }
15214 componentChild = componentChild.next;
15215 }
15216 }
15217}
15218/**
15219 * Inserts previously re-distributed projected nodes. This instruction must be preceded by a call
15220 * to the projectionDef instruction.
15221 *
15222 * @param nodeIndex
15223 * @param selectorIndex:
15224 * - 0 when the selector is `*` (or unspecified as this is the default value),
15225 * - 1 based index of the selector from the {@link projectionDef}
15226 *
15227 * @codeGenApi
15228 */
15229function ɵɵprojection(nodeIndex, selectorIndex = 0, attrs) {
15230 const lView = getLView();
15231 const tView = getTView();
15232 const tProjectionNode = getOrCreateTNode(tView, HEADER_OFFSET + nodeIndex, 16 /* Projection */, null, attrs || null);
15233 // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views.
15234 if (tProjectionNode.projection === null)
15235 tProjectionNode.projection = selectorIndex;
15236 // `<ng-content>` has no content
15237 setCurrentTNodeAsNotParent();
15238 if ((tProjectionNode.flags & 64 /* isDetached */) !== 64 /* isDetached */) {
15239 // re-distribution of projectable nodes is stored on a component's view level
15240 applyProjection(tView, lView, tProjectionNode);
15241 }
15242}
15243
15244/**
15245 *
15246 * Update an interpolated property on an element with a lone bound value
15247 *
15248 * Used when the value passed to a property has 1 interpolated value in it, an no additional text
15249 * surrounds that interpolated value:
15250 *
15251 * ```html
15252 * <div title="{{v0}}"></div>
15253 * ```
15254 *
15255 * Its compiled representation is::
15256 *
15257 * ```ts
15258 * ɵɵpropertyInterpolate('title', v0);
15259 * ```
15260 *
15261 * If the property name also exists as an input property on one of the element's directives,
15262 * the component property will be set instead of the element property. This check must
15263 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15264 *
15265 * @param propName The name of the property to update
15266 * @param prefix Static value used for concatenation only.
15267 * @param v0 Value checked for change.
15268 * @param suffix Static value used for concatenation only.
15269 * @param sanitizer An optional sanitizer function
15270 * @returns itself, so that it may be chained.
15271 * @codeGenApi
15272 */
15273function ɵɵpropertyInterpolate(propName, v0, sanitizer) {
15274 ɵɵpropertyInterpolate1(propName, '', v0, '', sanitizer);
15275 return ɵɵpropertyInterpolate;
15276}
15277/**
15278 *
15279 * Update an interpolated property on an element with single bound value surrounded by text.
15280 *
15281 * Used when the value passed to a property has 1 interpolated value in it:
15282 *
15283 * ```html
15284 * <div title="prefix{{v0}}suffix"></div>
15285 * ```
15286 *
15287 * Its compiled representation is::
15288 *
15289 * ```ts
15290 * ɵɵpropertyInterpolate1('title', 'prefix', v0, 'suffix');
15291 * ```
15292 *
15293 * If the property name also exists as an input property on one of the element's directives,
15294 * the component property will be set instead of the element property. This check must
15295 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15296 *
15297 * @param propName The name of the property to update
15298 * @param prefix Static value used for concatenation only.
15299 * @param v0 Value checked for change.
15300 * @param suffix Static value used for concatenation only.
15301 * @param sanitizer An optional sanitizer function
15302 * @returns itself, so that it may be chained.
15303 * @codeGenApi
15304 */
15305function ɵɵpropertyInterpolate1(propName, prefix, v0, suffix, sanitizer) {
15306 const lView = getLView();
15307 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
15308 if (interpolatedValue !== NO_CHANGE) {
15309 const tView = getTView();
15310 const tNode = getSelectedTNode();
15311 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15312 ngDevMode &&
15313 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 1, prefix, suffix);
15314 }
15315 return ɵɵpropertyInterpolate1;
15316}
15317/**
15318 *
15319 * Update an interpolated property on an element with 2 bound values surrounded by text.
15320 *
15321 * Used when the value passed to a property has 2 interpolated values in it:
15322 *
15323 * ```html
15324 * <div title="prefix{{v0}}-{{v1}}suffix"></div>
15325 * ```
15326 *
15327 * Its compiled representation is::
15328 *
15329 * ```ts
15330 * ɵɵpropertyInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
15331 * ```
15332 *
15333 * If the property name also exists as an input property on one of the element's directives,
15334 * the component property will be set instead of the element property. This check must
15335 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15336 *
15337 * @param propName The name of the property to update
15338 * @param prefix Static value used for concatenation only.
15339 * @param v0 Value checked for change.
15340 * @param i0 Static value used for concatenation only.
15341 * @param v1 Value checked for change.
15342 * @param suffix Static value used for concatenation only.
15343 * @param sanitizer An optional sanitizer function
15344 * @returns itself, so that it may be chained.
15345 * @codeGenApi
15346 */
15347function ɵɵpropertyInterpolate2(propName, prefix, v0, i0, v1, suffix, sanitizer) {
15348 const lView = getLView();
15349 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
15350 if (interpolatedValue !== NO_CHANGE) {
15351 const tView = getTView();
15352 const tNode = getSelectedTNode();
15353 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15354 ngDevMode &&
15355 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 2, prefix, i0, suffix);
15356 }
15357 return ɵɵpropertyInterpolate2;
15358}
15359/**
15360 *
15361 * Update an interpolated property on an element with 3 bound values surrounded by text.
15362 *
15363 * Used when the value passed to a property has 3 interpolated values in it:
15364 *
15365 * ```html
15366 * <div title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
15367 * ```
15368 *
15369 * Its compiled representation is::
15370 *
15371 * ```ts
15372 * ɵɵpropertyInterpolate3(
15373 * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
15374 * ```
15375 *
15376 * If the property name also exists as an input property on one of the element's directives,
15377 * the component property will be set instead of the element property. This check must
15378 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15379 *
15380 * @param propName The name of the property to update
15381 * @param prefix Static value used for concatenation only.
15382 * @param v0 Value checked for change.
15383 * @param i0 Static value used for concatenation only.
15384 * @param v1 Value checked for change.
15385 * @param i1 Static value used for concatenation only.
15386 * @param v2 Value checked for change.
15387 * @param suffix Static value used for concatenation only.
15388 * @param sanitizer An optional sanitizer function
15389 * @returns itself, so that it may be chained.
15390 * @codeGenApi
15391 */
15392function ɵɵpropertyInterpolate3(propName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer) {
15393 const lView = getLView();
15394 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
15395 if (interpolatedValue !== NO_CHANGE) {
15396 const tView = getTView();
15397 const tNode = getSelectedTNode();
15398 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15399 ngDevMode &&
15400 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 3, prefix, i0, i1, suffix);
15401 }
15402 return ɵɵpropertyInterpolate3;
15403}
15404/**
15405 *
15406 * Update an interpolated property on an element with 4 bound values surrounded by text.
15407 *
15408 * Used when the value passed to a property has 4 interpolated values in it:
15409 *
15410 * ```html
15411 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
15412 * ```
15413 *
15414 * Its compiled representation is::
15415 *
15416 * ```ts
15417 * ɵɵpropertyInterpolate4(
15418 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
15419 * ```
15420 *
15421 * If the property name also exists as an input property on one of the element's directives,
15422 * the component property will be set instead of the element property. This check must
15423 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15424 *
15425 * @param propName The name of the property to update
15426 * @param prefix Static value used for concatenation only.
15427 * @param v0 Value checked for change.
15428 * @param i0 Static value used for concatenation only.
15429 * @param v1 Value checked for change.
15430 * @param i1 Static value used for concatenation only.
15431 * @param v2 Value checked for change.
15432 * @param i2 Static value used for concatenation only.
15433 * @param v3 Value checked for change.
15434 * @param suffix Static value used for concatenation only.
15435 * @param sanitizer An optional sanitizer function
15436 * @returns itself, so that it may be chained.
15437 * @codeGenApi
15438 */
15439function ɵɵpropertyInterpolate4(propName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer) {
15440 const lView = getLView();
15441 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
15442 if (interpolatedValue !== NO_CHANGE) {
15443 const tView = getTView();
15444 const tNode = getSelectedTNode();
15445 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15446 ngDevMode &&
15447 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix);
15448 }
15449 return ɵɵpropertyInterpolate4;
15450}
15451/**
15452 *
15453 * Update an interpolated property on an element with 5 bound values surrounded by text.
15454 *
15455 * Used when the value passed to a property has 5 interpolated values in it:
15456 *
15457 * ```html
15458 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
15459 * ```
15460 *
15461 * Its compiled representation is::
15462 *
15463 * ```ts
15464 * ɵɵpropertyInterpolate5(
15465 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
15466 * ```
15467 *
15468 * If the property name also exists as an input property on one of the element's directives,
15469 * the component property will be set instead of the element property. This check must
15470 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15471 *
15472 * @param propName The name of the property to update
15473 * @param prefix Static value used for concatenation only.
15474 * @param v0 Value checked for change.
15475 * @param i0 Static value used for concatenation only.
15476 * @param v1 Value checked for change.
15477 * @param i1 Static value used for concatenation only.
15478 * @param v2 Value checked for change.
15479 * @param i2 Static value used for concatenation only.
15480 * @param v3 Value checked for change.
15481 * @param i3 Static value used for concatenation only.
15482 * @param v4 Value checked for change.
15483 * @param suffix Static value used for concatenation only.
15484 * @param sanitizer An optional sanitizer function
15485 * @returns itself, so that it may be chained.
15486 * @codeGenApi
15487 */
15488function ɵɵpropertyInterpolate5(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer) {
15489 const lView = getLView();
15490 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
15491 if (interpolatedValue !== NO_CHANGE) {
15492 const tView = getTView();
15493 const tNode = getSelectedTNode();
15494 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15495 ngDevMode &&
15496 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix);
15497 }
15498 return ɵɵpropertyInterpolate5;
15499}
15500/**
15501 *
15502 * Update an interpolated property on an element with 6 bound values surrounded by text.
15503 *
15504 * Used when the value passed to a property has 6 interpolated values in it:
15505 *
15506 * ```html
15507 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
15508 * ```
15509 *
15510 * Its compiled representation is::
15511 *
15512 * ```ts
15513 * ɵɵpropertyInterpolate6(
15514 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
15515 * ```
15516 *
15517 * If the property name also exists as an input property on one of the element's directives,
15518 * the component property will be set instead of the element property. This check must
15519 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15520 *
15521 * @param propName The name of the property to update
15522 * @param prefix Static value used for concatenation only.
15523 * @param v0 Value checked for change.
15524 * @param i0 Static value used for concatenation only.
15525 * @param v1 Value checked for change.
15526 * @param i1 Static value used for concatenation only.
15527 * @param v2 Value checked for change.
15528 * @param i2 Static value used for concatenation only.
15529 * @param v3 Value checked for change.
15530 * @param i3 Static value used for concatenation only.
15531 * @param v4 Value checked for change.
15532 * @param i4 Static value used for concatenation only.
15533 * @param v5 Value checked for change.
15534 * @param suffix Static value used for concatenation only.
15535 * @param sanitizer An optional sanitizer function
15536 * @returns itself, so that it may be chained.
15537 * @codeGenApi
15538 */
15539function ɵɵpropertyInterpolate6(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer) {
15540 const lView = getLView();
15541 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
15542 if (interpolatedValue !== NO_CHANGE) {
15543 const tView = getTView();
15544 const tNode = getSelectedTNode();
15545 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15546 ngDevMode &&
15547 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, i4, suffix);
15548 }
15549 return ɵɵpropertyInterpolate6;
15550}
15551/**
15552 *
15553 * Update an interpolated property on an element with 7 bound values surrounded by text.
15554 *
15555 * Used when the value passed to a property has 7 interpolated values in it:
15556 *
15557 * ```html
15558 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
15559 * ```
15560 *
15561 * Its compiled representation is::
15562 *
15563 * ```ts
15564 * ɵɵpropertyInterpolate7(
15565 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
15566 * ```
15567 *
15568 * If the property name also exists as an input property on one of the element's directives,
15569 * the component property will be set instead of the element property. This check must
15570 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15571 *
15572 * @param propName The name of the property to update
15573 * @param prefix Static value used for concatenation only.
15574 * @param v0 Value checked for change.
15575 * @param i0 Static value used for concatenation only.
15576 * @param v1 Value checked for change.
15577 * @param i1 Static value used for concatenation only.
15578 * @param v2 Value checked for change.
15579 * @param i2 Static value used for concatenation only.
15580 * @param v3 Value checked for change.
15581 * @param i3 Static value used for concatenation only.
15582 * @param v4 Value checked for change.
15583 * @param i4 Static value used for concatenation only.
15584 * @param v5 Value checked for change.
15585 * @param i5 Static value used for concatenation only.
15586 * @param v6 Value checked for change.
15587 * @param suffix Static value used for concatenation only.
15588 * @param sanitizer An optional sanitizer function
15589 * @returns itself, so that it may be chained.
15590 * @codeGenApi
15591 */
15592function ɵɵpropertyInterpolate7(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer) {
15593 const lView = getLView();
15594 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
15595 if (interpolatedValue !== NO_CHANGE) {
15596 const tView = getTView();
15597 const tNode = getSelectedTNode();
15598 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15599 ngDevMode &&
15600 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, suffix);
15601 }
15602 return ɵɵpropertyInterpolate7;
15603}
15604/**
15605 *
15606 * Update an interpolated property on an element with 8 bound values surrounded by text.
15607 *
15608 * Used when the value passed to a property has 8 interpolated values in it:
15609 *
15610 * ```html
15611 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
15612 * ```
15613 *
15614 * Its compiled representation is::
15615 *
15616 * ```ts
15617 * ɵɵpropertyInterpolate8(
15618 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
15619 * ```
15620 *
15621 * If the property name also exists as an input property on one of the element's directives,
15622 * the component property will be set instead of the element property. This check must
15623 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15624 *
15625 * @param propName The name of the property to update
15626 * @param prefix Static value used for concatenation only.
15627 * @param v0 Value checked for change.
15628 * @param i0 Static value used for concatenation only.
15629 * @param v1 Value checked for change.
15630 * @param i1 Static value used for concatenation only.
15631 * @param v2 Value checked for change.
15632 * @param i2 Static value used for concatenation only.
15633 * @param v3 Value checked for change.
15634 * @param i3 Static value used for concatenation only.
15635 * @param v4 Value checked for change.
15636 * @param i4 Static value used for concatenation only.
15637 * @param v5 Value checked for change.
15638 * @param i5 Static value used for concatenation only.
15639 * @param v6 Value checked for change.
15640 * @param i6 Static value used for concatenation only.
15641 * @param v7 Value checked for change.
15642 * @param suffix Static value used for concatenation only.
15643 * @param sanitizer An optional sanitizer function
15644 * @returns itself, so that it may be chained.
15645 * @codeGenApi
15646 */
15647function ɵɵpropertyInterpolate8(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer) {
15648 const lView = getLView();
15649 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
15650 if (interpolatedValue !== NO_CHANGE) {
15651 const tView = getTView();
15652 const tNode = getSelectedTNode();
15653 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15654 ngDevMode &&
15655 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, suffix);
15656 }
15657 return ɵɵpropertyInterpolate8;
15658}
15659/**
15660 * Update an interpolated property on an element with 9 or more bound values surrounded by text.
15661 *
15662 * Used when the number of interpolated values exceeds 8.
15663 *
15664 * ```html
15665 * <div
15666 * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
15667 * ```
15668 *
15669 * Its compiled representation is::
15670 *
15671 * ```ts
15672 * ɵɵpropertyInterpolateV(
15673 * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
15674 * 'suffix']);
15675 * ```
15676 *
15677 * If the property name also exists as an input property on one of the element's directives,
15678 * the component property will be set instead of the element property. This check must
15679 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15680 *
15681 * @param propName The name of the property to update.
15682 * @param values The collection of values and the strings inbetween those values, beginning with a
15683 * string prefix and ending with a string suffix.
15684 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
15685 * @param sanitizer An optional sanitizer function
15686 * @returns itself, so that it may be chained.
15687 * @codeGenApi
15688 */
15689function ɵɵpropertyInterpolateV(propName, values, sanitizer) {
15690 const lView = getLView();
15691 const interpolatedValue = interpolationV(lView, values);
15692 if (interpolatedValue !== NO_CHANGE) {
15693 const tView = getTView();
15694 const tNode = getSelectedTNode();
15695 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15696 if (ngDevMode) {
15697 const interpolationInBetween = [values[0]]; // prefix
15698 for (let i = 2; i < values.length; i += 2) {
15699 interpolationInBetween.push(values[i]);
15700 }
15701 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
15702 }
15703 }
15704 return ɵɵpropertyInterpolateV;
15705}
15706
15707/**
15708 * @license
15709 * Copyright Google LLC All Rights Reserved.
15710 *
15711 * Use of this source code is governed by an MIT-style license that can be
15712 * found in the LICENSE file at https://angular.io/license
15713 */
15714/**
15715 * NOTE: The word `styling` is used interchangeably as style or class styling.
15716 *
15717 * This file contains code to link styling instructions together so that they can be replayed in
15718 * priority order. The file exists because Ivy styling instruction execution order does not match
15719 * that of the priority order. The purpose of this code is to create a linked list so that the
15720 * instructions can be traversed in priority order when computing the styles.
15721 *
15722 * Assume we are dealing with the following code:
15723 * ```
15724 * @Component({
15725 * template: `
15726 * <my-cmp [style]=" {color: '#001'} "
15727 * [style.color]=" #002 "
15728 * dir-style-color-1
15729 * dir-style-color-2> `
15730 * })
15731 * class ExampleComponent {
15732 * static ngComp = ... {
15733 * ...
15734 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
15735 * ɵɵstyleMap({color: '#001'});
15736 * ɵɵstyleProp('color', '#002');
15737 * ...
15738 * }
15739 * }
15740 *
15741 * @Directive({
15742 * selector: `[dir-style-color-1]',
15743 * })
15744 * class Style1Directive {
15745 * @HostBinding('style') style = {color: '#005'};
15746 * @HostBinding('style.color') color = '#006';
15747 *
15748 * static ngDir = ... {
15749 * ...
15750 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
15751 * ɵɵstyleMap({color: '#005'});
15752 * ɵɵstyleProp('color', '#006');
15753 * ...
15754 * }
15755 * }
15756 *
15757 * @Directive({
15758 * selector: `[dir-style-color-2]',
15759 * })
15760 * class Style2Directive {
15761 * @HostBinding('style') style = {color: '#007'};
15762 * @HostBinding('style.color') color = '#008';
15763 *
15764 * static ngDir = ... {
15765 * ...
15766 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
15767 * ɵɵstyleMap({color: '#007'});
15768 * ɵɵstyleProp('color', '#008');
15769 * ...
15770 * }
15771 * }
15772 *
15773 * @Directive({
15774 * selector: `my-cmp',
15775 * })
15776 * class MyComponent {
15777 * @HostBinding('style') style = {color: '#003'};
15778 * @HostBinding('style.color') color = '#004';
15779 *
15780 * static ngComp = ... {
15781 * ...
15782 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
15783 * ɵɵstyleMap({color: '#003'});
15784 * ɵɵstyleProp('color', '#004');
15785 * ...
15786 * }
15787 * }
15788 * ```
15789 *
15790 * The Order of instruction execution is:
15791 *
15792 * NOTE: the comment binding location is for illustrative purposes only.
15793 *
15794 * ```
15795 * // Template: (ExampleComponent)
15796 * ɵɵstyleMap({color: '#001'}); // Binding index: 10
15797 * ɵɵstyleProp('color', '#002'); // Binding index: 12
15798 * // MyComponent
15799 * ɵɵstyleMap({color: '#003'}); // Binding index: 20
15800 * ɵɵstyleProp('color', '#004'); // Binding index: 22
15801 * // Style1Directive
15802 * ɵɵstyleMap({color: '#005'}); // Binding index: 24
15803 * ɵɵstyleProp('color', '#006'); // Binding index: 26
15804 * // Style2Directive
15805 * ɵɵstyleMap({color: '#007'}); // Binding index: 28
15806 * ɵɵstyleProp('color', '#008'); // Binding index: 30
15807 * ```
15808 *
15809 * The correct priority order of concatenation is:
15810 *
15811 * ```
15812 * // MyComponent
15813 * ɵɵstyleMap({color: '#003'}); // Binding index: 20
15814 * ɵɵstyleProp('color', '#004'); // Binding index: 22
15815 * // Style1Directive
15816 * ɵɵstyleMap({color: '#005'}); // Binding index: 24
15817 * ɵɵstyleProp('color', '#006'); // Binding index: 26
15818 * // Style2Directive
15819 * ɵɵstyleMap({color: '#007'}); // Binding index: 28
15820 * ɵɵstyleProp('color', '#008'); // Binding index: 30
15821 * // Template: (ExampleComponent)
15822 * ɵɵstyleMap({color: '#001'}); // Binding index: 10
15823 * ɵɵstyleProp('color', '#002'); // Binding index: 12
15824 * ```
15825 *
15826 * What color should be rendered?
15827 *
15828 * Once the items are correctly sorted in the list, the answer is simply the last item in the
15829 * concatenation list which is `#002`.
15830 *
15831 * To do so we keep a linked list of all of the bindings which pertain to this element.
15832 * Notice that the bindings are inserted in the order of execution, but the `TView.data` allows
15833 * us to traverse them in the order of priority.
15834 *
15835 * |Idx|`TView.data`|`LView` | Notes
15836 * |---|------------|-----------------|--------------
15837 * |...| | |
15838 * |10 |`null` |`{color: '#001'}`| `ɵɵstyleMap('color', {color: '#001'})`
15839 * |11 |`30 | 12` | ... |
15840 * |12 |`color` |`'#002'` | `ɵɵstyleProp('color', '#002')`
15841 * |13 |`10 | 0` | ... |
15842 * |...| | |
15843 * |20 |`null` |`{color: '#003'}`| `ɵɵstyleMap('color', {color: '#003'})`
15844 * |21 |`0 | 22` | ... |
15845 * |22 |`color` |`'#004'` | `ɵɵstyleProp('color', '#004')`
15846 * |23 |`20 | 24` | ... |
15847 * |24 |`null` |`{color: '#005'}`| `ɵɵstyleMap('color', {color: '#005'})`
15848 * |25 |`22 | 26` | ... |
15849 * |26 |`color` |`'#006'` | `ɵɵstyleProp('color', '#006')`
15850 * |27 |`24 | 28` | ... |
15851 * |28 |`null` |`{color: '#007'}`| `ɵɵstyleMap('color', {color: '#007'})`
15852 * |29 |`26 | 30` | ... |
15853 * |30 |`color` |`'#008'` | `ɵɵstyleProp('color', '#008')`
15854 * |31 |`28 | 10` | ... |
15855 *
15856 * The above data structure allows us to re-concatenate the styling no matter which data binding
15857 * changes.
15858 *
15859 * NOTE: in addition to keeping track of next/previous index the `TView.data` also stores prev/next
15860 * duplicate bit. The duplicate bit if true says there either is a binding with the same name or
15861 * there is a map (which may contain the name). This information is useful in knowing if other
15862 * styles with higher priority need to be searched for overwrites.
15863 *
15864 * NOTE: See `should support example in 'tnode_linked_list.ts' documentation` in
15865 * `tnode_linked_list_spec.ts` for working example.
15866 */
15867let __unused_const_as_closure_does_not_like_standalone_comment_blocks__;
15868/**
15869 * Insert new `tStyleValue` at `TData` and link existing style bindings such that we maintain linked
15870 * list of styles and compute the duplicate flag.
15871 *
15872 * Note: this function is executed during `firstUpdatePass` only to populate the `TView.data`.
15873 *
15874 * The function works by keeping track of `tStylingRange` which contains two pointers pointing to
15875 * the head/tail of the template portion of the styles.
15876 * - if `isHost === false` (we are template) then insertion is at tail of `TStylingRange`
15877 * - if `isHost === true` (we are host binding) then insertion is at head of `TStylingRange`
15878 *
15879 * @param tData The `TData` to insert into.
15880 * @param tNode `TNode` associated with the styling element.
15881 * @param tStylingKey See `TStylingKey`.
15882 * @param index location of where `tStyleValue` should be stored (and linked into list.)
15883 * @param isHostBinding `true` if the insertion is for a `hostBinding`. (insertion is in front of
15884 * template.)
15885 * @param isClassBinding True if the associated `tStylingKey` as a `class` styling.
15886 * `tNode.classBindings` should be used (or `tNode.styleBindings` otherwise.)
15887 */
15888function insertTStylingBinding(tData, tNode, tStylingKeyWithStatic, index, isHostBinding, isClassBinding) {
15889 ngDevMode && assertFirstUpdatePass(getTView());
15890 let tBindings = isClassBinding ? tNode.classBindings : tNode.styleBindings;
15891 let tmplHead = getTStylingRangePrev(tBindings);
15892 let tmplTail = getTStylingRangeNext(tBindings);
15893 tData[index] = tStylingKeyWithStatic;
15894 let isKeyDuplicateOfStatic = false;
15895 let tStylingKey;
15896 if (Array.isArray(tStylingKeyWithStatic)) {
15897 // We are case when the `TStylingKey` contains static fields as well.
15898 const staticKeyValueArray = tStylingKeyWithStatic;
15899 tStylingKey = staticKeyValueArray[1]; // unwrap.
15900 // We need to check if our key is present in the static so that we can mark it as duplicate.
15901 if (tStylingKey === null ||
15902 keyValueArrayIndexOf(staticKeyValueArray, tStylingKey) > 0) {
15903 // tStylingKey is present in the statics, need to mark it as duplicate.
15904 isKeyDuplicateOfStatic = true;
15905 }
15906 }
15907 else {
15908 tStylingKey = tStylingKeyWithStatic;
15909 }
15910 if (isHostBinding) {
15911 // We are inserting host bindings
15912 // If we don't have template bindings then `tail` is 0.
15913 const hasTemplateBindings = tmplTail !== 0;
15914 // This is important to know because that means that the `head` can't point to the first
15915 // template bindings (there are none.) Instead the head points to the tail of the template.
15916 if (hasTemplateBindings) {
15917 // template head's "prev" will point to last host binding or to 0 if no host bindings yet
15918 const previousNode = getTStylingRangePrev(tData[tmplHead + 1]);
15919 tData[index + 1] = toTStylingRange(previousNode, tmplHead);
15920 // if a host binding has already been registered, we need to update the next of that host
15921 // binding to point to this one
15922 if (previousNode !== 0) {
15923 // We need to update the template-tail value to point to us.
15924 tData[previousNode + 1] =
15925 setTStylingRangeNext(tData[previousNode + 1], index);
15926 }
15927 // The "previous" of the template binding head should point to this host binding
15928 tData[tmplHead + 1] = setTStylingRangePrev(tData[tmplHead + 1], index);
15929 }
15930 else {
15931 tData[index + 1] = toTStylingRange(tmplHead, 0);
15932 // if a host binding has already been registered, we need to update the next of that host
15933 // binding to point to this one
15934 if (tmplHead !== 0) {
15935 // We need to update the template-tail value to point to us.
15936 tData[tmplHead + 1] = setTStylingRangeNext(tData[tmplHead + 1], index);
15937 }
15938 // if we don't have template, the head points to template-tail, and needs to be advanced.
15939 tmplHead = index;
15940 }
15941 }
15942 else {
15943 // We are inserting in template section.
15944 // We need to set this binding's "previous" to the current template tail
15945 tData[index + 1] = toTStylingRange(tmplTail, 0);
15946 ngDevMode &&
15947 assertEqual(tmplHead !== 0 && tmplTail === 0, false, 'Adding template bindings after hostBindings is not allowed.');
15948 if (tmplHead === 0) {
15949 tmplHead = index;
15950 }
15951 else {
15952 // We need to update the previous value "next" to point to this binding
15953 tData[tmplTail + 1] = setTStylingRangeNext(tData[tmplTail + 1], index);
15954 }
15955 tmplTail = index;
15956 }
15957 // Now we need to update / compute the duplicates.
15958 // Starting with our location search towards head (least priority)
15959 if (isKeyDuplicateOfStatic) {
15960 tData[index + 1] = setTStylingRangePrevDuplicate(tData[index + 1]);
15961 }
15962 markDuplicates(tData, tStylingKey, index, true, isClassBinding);
15963 markDuplicates(tData, tStylingKey, index, false, isClassBinding);
15964 markDuplicateOfResidualStyling(tNode, tStylingKey, tData, index, isClassBinding);
15965 tBindings = toTStylingRange(tmplHead, tmplTail);
15966 if (isClassBinding) {
15967 tNode.classBindings = tBindings;
15968 }
15969 else {
15970 tNode.styleBindings = tBindings;
15971 }
15972}
15973/**
15974 * Look into the residual styling to see if the current `tStylingKey` is duplicate of residual.
15975 *
15976 * @param tNode `TNode` where the residual is stored.
15977 * @param tStylingKey `TStylingKey` to store.
15978 * @param tData `TData` associated with the current `LView`.
15979 * @param index location of where `tStyleValue` should be stored (and linked into list.)
15980 * @param isClassBinding True if the associated `tStylingKey` as a `class` styling.
15981 * `tNode.classBindings` should be used (or `tNode.styleBindings` otherwise.)
15982 */
15983function markDuplicateOfResidualStyling(tNode, tStylingKey, tData, index, isClassBinding) {
15984 const residual = isClassBinding ? tNode.residualClasses : tNode.residualStyles;
15985 if (residual != null /* or undefined */ && typeof tStylingKey == 'string' &&
15986 keyValueArrayIndexOf(residual, tStylingKey) >= 0) {
15987 // We have duplicate in the residual so mark ourselves as duplicate.
15988 tData[index + 1] = setTStylingRangeNextDuplicate(tData[index + 1]);
15989 }
15990}
15991/**
15992 * Marks `TStyleValue`s as duplicates if another style binding in the list has the same
15993 * `TStyleValue`.
15994 *
15995 * NOTE: this function is intended to be called twice once with `isPrevDir` set to `true` and once
15996 * with it set to `false` to search both the previous as well as next items in the list.
15997 *
15998 * No duplicate case
15999 * ```
16000 * [style.color]
16001 * [style.width.px] <<- index
16002 * [style.height.px]
16003 * ```
16004 *
16005 * In the above case adding `[style.width.px]` to the existing `[style.color]` produces no
16006 * duplicates because `width` is not found in any other part of the linked list.
16007 *
16008 * Duplicate case
16009 * ```
16010 * [style.color]
16011 * [style.width.em]
16012 * [style.width.px] <<- index
16013 * ```
16014 * In the above case adding `[style.width.px]` will produce a duplicate with `[style.width.em]`
16015 * because `width` is found in the chain.
16016 *
16017 * Map case 1
16018 * ```
16019 * [style.width.px]
16020 * [style.color]
16021 * [style] <<- index
16022 * ```
16023 * In the above case adding `[style]` will produce a duplicate with any other bindings because
16024 * `[style]` is a Map and as such is fully dynamic and could produce `color` or `width`.
16025 *
16026 * Map case 2
16027 * ```
16028 * [style]
16029 * [style.width.px]
16030 * [style.color] <<- index
16031 * ```
16032 * In the above case adding `[style.color]` will produce a duplicate because there is already a
16033 * `[style]` binding which is a Map and as such is fully dynamic and could produce `color` or
16034 * `width`.
16035 *
16036 * NOTE: Once `[style]` (Map) is added into the system all things are mapped as duplicates.
16037 * NOTE: We use `style` as example, but same logic is applied to `class`es as well.
16038 *
16039 * @param tData `TData` where the linked list is stored.
16040 * @param tStylingKey `TStylingKeyPrimitive` which contains the value to compare to other keys in
16041 * the linked list.
16042 * @param index Starting location in the linked list to search from
16043 * @param isPrevDir Direction.
16044 * - `true` for previous (lower priority);
16045 * - `false` for next (higher priority).
16046 */
16047function markDuplicates(tData, tStylingKey, index, isPrevDir, isClassBinding) {
16048 const tStylingAtIndex = tData[index + 1];
16049 const isMap = tStylingKey === null;
16050 let cursor = isPrevDir ? getTStylingRangePrev(tStylingAtIndex) : getTStylingRangeNext(tStylingAtIndex);
16051 let foundDuplicate = false;
16052 // We keep iterating as long as we have a cursor
16053 // AND either:
16054 // - we found what we are looking for, OR
16055 // - we are a map in which case we have to continue searching even after we find what we were
16056 // looking for since we are a wild card and everything needs to be flipped to duplicate.
16057 while (cursor !== 0 && (foundDuplicate === false || isMap)) {
16058 ngDevMode && assertIndexInRange(tData, cursor);
16059 const tStylingValueAtCursor = tData[cursor];
16060 const tStyleRangeAtCursor = tData[cursor + 1];
16061 if (isStylingMatch(tStylingValueAtCursor, tStylingKey)) {
16062 foundDuplicate = true;
16063 tData[cursor + 1] = isPrevDir ? setTStylingRangeNextDuplicate(tStyleRangeAtCursor) :
16064 setTStylingRangePrevDuplicate(tStyleRangeAtCursor);
16065 }
16066 cursor = isPrevDir ? getTStylingRangePrev(tStyleRangeAtCursor) :
16067 getTStylingRangeNext(tStyleRangeAtCursor);
16068 }
16069 if (foundDuplicate) {
16070 // if we found a duplicate, than mark ourselves.
16071 tData[index + 1] = isPrevDir ? setTStylingRangePrevDuplicate(tStylingAtIndex) :
16072 setTStylingRangeNextDuplicate(tStylingAtIndex);
16073 }
16074}
16075/**
16076 * Determines if two `TStylingKey`s are a match.
16077 *
16078 * When computing whether a binding contains a duplicate, we need to compare if the instruction
16079 * `TStylingKey` has a match.
16080 *
16081 * Here are examples of `TStylingKey`s which match given `tStylingKeyCursor` is:
16082 * - `color`
16083 * - `color` // Match another color
16084 * - `null` // That means that `tStylingKey` is a `classMap`/`styleMap` instruction
16085 * - `['', 'color', 'other', true]` // wrapped `color` so match
16086 * - `['', null, 'other', true]` // wrapped `null` so match
16087 * - `['', 'width', 'color', 'value']` // wrapped static value contains a match on `'color'`
16088 * - `null` // `tStylingKeyCursor` always match as it is `classMap`/`styleMap` instruction
16089 *
16090 * @param tStylingKeyCursor
16091 * @param tStylingKey
16092 */
16093function isStylingMatch(tStylingKeyCursor, tStylingKey) {
16094 ngDevMode &&
16095 assertNotEqual(Array.isArray(tStylingKey), true, 'Expected that \'tStylingKey\' has been unwrapped');
16096 if (tStylingKeyCursor === null || // If the cursor is `null` it means that we have map at that
16097 // location so we must assume that we have a match.
16098 tStylingKey == null || // If `tStylingKey` is `null` then it is a map therefor assume that it
16099 // contains a match.
16100 (Array.isArray(tStylingKeyCursor) ? tStylingKeyCursor[1] : tStylingKeyCursor) ===
16101 tStylingKey // If the keys match explicitly than we are a match.
16102 ) {
16103 return true;
16104 }
16105 else if (Array.isArray(tStylingKeyCursor) && typeof tStylingKey === 'string') {
16106 // if we did not find a match, but `tStylingKeyCursor` is `KeyValueArray` that means cursor has
16107 // statics and we need to check those as well.
16108 return keyValueArrayIndexOf(tStylingKeyCursor, tStylingKey) >=
16109 0; // see if we are matching the key
16110 }
16111 return false;
16112}
16113
16114/**
16115 * @license
16116 * Copyright Google LLC All Rights Reserved.
16117 *
16118 * Use of this source code is governed by an MIT-style license that can be
16119 * found in the LICENSE file at https://angular.io/license
16120 */
16121// Global state of the parser. (This makes parser non-reentrant, but that is not an issue)
16122const parserState = {
16123 textEnd: 0,
16124 key: 0,
16125 keyEnd: 0,
16126 value: 0,
16127 valueEnd: 0,
16128};
16129/**
16130 * Retrieves the last parsed `key` of style.
16131 * @param text the text to substring the key from.
16132 */
16133function getLastParsedKey(text) {
16134 return text.substring(parserState.key, parserState.keyEnd);
16135}
16136/**
16137 * Retrieves the last parsed `value` of style.
16138 * @param text the text to substring the key from.
16139 */
16140function getLastParsedValue(text) {
16141 return text.substring(parserState.value, parserState.valueEnd);
16142}
16143/**
16144 * Initializes `className` string for parsing and parses the first token.
16145 *
16146 * This function is intended to be used in this format:
16147 * ```
16148 * for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) {
16149 * const key = getLastParsedKey();
16150 * ...
16151 * }
16152 * ```
16153 * @param text `className` to parse
16154 * @returns index where the next invocation of `parseClassNameNext` should resume.
16155 */
16156function parseClassName(text) {
16157 resetParserState(text);
16158 return parseClassNameNext(text, consumeWhitespace(text, 0, parserState.textEnd));
16159}
16160/**
16161 * Parses next `className` token.
16162 *
16163 * This function is intended to be used in this format:
16164 * ```
16165 * for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) {
16166 * const key = getLastParsedKey();
16167 * ...
16168 * }
16169 * ```
16170 *
16171 * @param text `className` to parse
16172 * @param index where the parsing should resume.
16173 * @returns index where the next invocation of `parseClassNameNext` should resume.
16174 */
16175function parseClassNameNext(text, index) {
16176 const end = parserState.textEnd;
16177 if (end === index) {
16178 return -1;
16179 }
16180 index = parserState.keyEnd = consumeClassToken(text, parserState.key = index, end);
16181 return consumeWhitespace(text, index, end);
16182}
16183/**
16184 * Initializes `cssText` string for parsing and parses the first key/values.
16185 *
16186 * This function is intended to be used in this format:
16187 * ```
16188 * for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i))) {
16189 * const key = getLastParsedKey();
16190 * const value = getLastParsedValue();
16191 * ...
16192 * }
16193 * ```
16194 * @param text `cssText` to parse
16195 * @returns index where the next invocation of `parseStyleNext` should resume.
16196 */
16197function parseStyle(text) {
16198 resetParserState(text);
16199 return parseStyleNext(text, consumeWhitespace(text, 0, parserState.textEnd));
16200}
16201/**
16202 * Parses the next `cssText` key/values.
16203 *
16204 * This function is intended to be used in this format:
16205 * ```
16206 * for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i))) {
16207 * const key = getLastParsedKey();
16208 * const value = getLastParsedValue();
16209 * ...
16210 * }
16211 *
16212 * @param text `cssText` to parse
16213 * @param index where the parsing should resume.
16214 * @returns index where the next invocation of `parseStyleNext` should resume.
16215 */
16216function parseStyleNext(text, startIndex) {
16217 const end = parserState.textEnd;
16218 let index = parserState.key = consumeWhitespace(text, startIndex, end);
16219 if (end === index) {
16220 // we reached an end so just quit
16221 return -1;
16222 }
16223 index = parserState.keyEnd = consumeStyleKey(text, index, end);
16224 index = consumeSeparator(text, index, end, 58 /* COLON */);
16225 index = parserState.value = consumeWhitespace(text, index, end);
16226 index = parserState.valueEnd = consumeStyleValue(text, index, end);
16227 return consumeSeparator(text, index, end, 59 /* SEMI_COLON */);
16228}
16229/**
16230 * Reset the global state of the styling parser.
16231 * @param text The styling text to parse.
16232 */
16233function resetParserState(text) {
16234 parserState.key = 0;
16235 parserState.keyEnd = 0;
16236 parserState.value = 0;
16237 parserState.valueEnd = 0;
16238 parserState.textEnd = text.length;
16239}
16240/**
16241 * Returns index of next non-whitespace character.
16242 *
16243 * @param text Text to scan
16244 * @param startIndex Starting index of character where the scan should start.
16245 * @param endIndex Ending index of character where the scan should end.
16246 * @returns Index of next non-whitespace character (May be the same as `start` if no whitespace at
16247 * that location.)
16248 */
16249function consumeWhitespace(text, startIndex, endIndex) {
16250 while (startIndex < endIndex && text.charCodeAt(startIndex) <= 32 /* SPACE */) {
16251 startIndex++;
16252 }
16253 return startIndex;
16254}
16255/**
16256 * Returns index of last char in class token.
16257 *
16258 * @param text Text to scan
16259 * @param startIndex Starting index of character where the scan should start.
16260 * @param endIndex Ending index of character where the scan should end.
16261 * @returns Index after last char in class token.
16262 */
16263function consumeClassToken(text, startIndex, endIndex) {
16264 while (startIndex < endIndex && text.charCodeAt(startIndex) > 32 /* SPACE */) {
16265 startIndex++;
16266 }
16267 return startIndex;
16268}
16269/**
16270 * Consumes all of the characters belonging to style key and token.
16271 *
16272 * @param text Text to scan
16273 * @param startIndex Starting index of character where the scan should start.
16274 * @param endIndex Ending index of character where the scan should end.
16275 * @returns Index after last style key character.
16276 */
16277function consumeStyleKey(text, startIndex, endIndex) {
16278 let ch;
16279 while (startIndex < endIndex &&
16280 ((ch = text.charCodeAt(startIndex)) === 45 /* DASH */ || ch === 95 /* UNDERSCORE */ ||
16281 ((ch & -33 /* UPPER_CASE */) >= 65 /* A */ && (ch & -33 /* UPPER_CASE */) <= 90 /* Z */) ||
16282 (ch >= 48 /* ZERO */ && ch <= 57 /* NINE */))) {
16283 startIndex++;
16284 }
16285 return startIndex;
16286}
16287/**
16288 * Consumes all whitespace and the separator `:` after the style key.
16289 *
16290 * @param text Text to scan
16291 * @param startIndex Starting index of character where the scan should start.
16292 * @param endIndex Ending index of character where the scan should end.
16293 * @returns Index after separator and surrounding whitespace.
16294 */
16295function consumeSeparator(text, startIndex, endIndex, separator) {
16296 startIndex = consumeWhitespace(text, startIndex, endIndex);
16297 if (startIndex < endIndex) {
16298 if (ngDevMode && text.charCodeAt(startIndex) !== separator) {
16299 malformedStyleError(text, String.fromCharCode(separator), startIndex);
16300 }
16301 startIndex++;
16302 }
16303 return startIndex;
16304}
16305/**
16306 * Consumes style value honoring `url()` and `""` text.
16307 *
16308 * @param text Text to scan
16309 * @param startIndex Starting index of character where the scan should start.
16310 * @param endIndex Ending index of character where the scan should end.
16311 * @returns Index after last style value character.
16312 */
16313function consumeStyleValue(text, startIndex, endIndex) {
16314 let ch1 = -1; // 1st previous character
16315 let ch2 = -1; // 2nd previous character
16316 let ch3 = -1; // 3rd previous character
16317 let i = startIndex;
16318 let lastChIndex = i;
16319 while (i < endIndex) {
16320 const ch = text.charCodeAt(i++);
16321 if (ch === 59 /* SEMI_COLON */) {
16322 return lastChIndex;
16323 }
16324 else if (ch === 34 /* DOUBLE_QUOTE */ || ch === 39 /* SINGLE_QUOTE */) {
16325 lastChIndex = i = consumeQuotedText(text, ch, i, endIndex);
16326 }
16327 else if (startIndex ===
16328 i - 4 && // We have seen only 4 characters so far "URL(" (Ignore "foo_URL()")
16329 ch3 === 85 /* U */ &&
16330 ch2 === 82 /* R */ && ch1 === 76 /* L */ && ch === 40 /* OPEN_PAREN */) {
16331 lastChIndex = i = consumeQuotedText(text, 41 /* CLOSE_PAREN */, i, endIndex);
16332 }
16333 else if (ch > 32 /* SPACE */) {
16334 // if we have a non-whitespace character then capture its location
16335 lastChIndex = i;
16336 }
16337 ch3 = ch2;
16338 ch2 = ch1;
16339 ch1 = ch & -33 /* UPPER_CASE */;
16340 }
16341 return lastChIndex;
16342}
16343/**
16344 * Consumes all of the quoted characters.
16345 *
16346 * @param text Text to scan
16347 * @param quoteCharCode CharCode of either `"` or `'` quote or `)` for `url(...)`.
16348 * @param startIndex Starting index of character where the scan should start.
16349 * @param endIndex Ending index of character where the scan should end.
16350 * @returns Index after quoted characters.
16351 */
16352function consumeQuotedText(text, quoteCharCode, startIndex, endIndex) {
16353 let ch1 = -1; // 1st previous character
16354 let index = startIndex;
16355 while (index < endIndex) {
16356 const ch = text.charCodeAt(index++);
16357 if (ch == quoteCharCode && ch1 !== 92 /* BACK_SLASH */) {
16358 return index;
16359 }
16360 if (ch == 92 /* BACK_SLASH */ && ch1 === 92 /* BACK_SLASH */) {
16361 // two back slashes cancel each other out. For example `"\\"` should properly end the
16362 // quotation. (It should not assume that the last `"` is escaped.)
16363 ch1 = 0;
16364 }
16365 else {
16366 ch1 = ch;
16367 }
16368 }
16369 throw ngDevMode ? malformedStyleError(text, String.fromCharCode(quoteCharCode), endIndex) :
16370 new Error();
16371}
16372function malformedStyleError(text, expecting, index) {
16373 ngDevMode && assertEqual(typeof text === 'string', true, 'String expected here');
16374 throw throwError(`Malformed style at location ${index} in string '` + text.substring(0, index) + '[>>' +
16375 text.substring(index, index + 1) + '<<]' + text.substr(index + 1) +
16376 `'. Expecting '${expecting}'.`);
16377}
16378
16379/**
16380 * @license
16381 * Copyright Google LLC All Rights Reserved.
16382 *
16383 * Use of this source code is governed by an MIT-style license that can be
16384 * found in the LICENSE file at https://angular.io/license
16385 */
16386/**
16387 * Update a style binding on an element with the provided value.
16388 *
16389 * If the style value is falsy then it will be removed from the element
16390 * (or assigned a different value depending if there are any styles placed
16391 * on the element with `styleMap` or any static styles that are
16392 * present from when the element was created with `styling`).
16393 *
16394 * Note that the styling element is updated as part of `stylingApply`.
16395 *
16396 * @param prop A valid CSS property.
16397 * @param value New value to write (`null` or an empty string to remove).
16398 * @param suffix Optional suffix. Used with scalar values to add unit such as `px`.
16399 *
16400 * Note that this will apply the provided style value to the host element if this function is called
16401 * within a host binding function.
16402 *
16403 * @codeGenApi
16404 */
16405function ɵɵstyleProp(prop, value, suffix) {
16406 checkStylingProperty(prop, value, suffix, false);
16407 return ɵɵstyleProp;
16408}
16409/**
16410 * Update a class binding on an element with the provided value.
16411 *
16412 * This instruction is meant to handle the `[class.foo]="exp"` case and,
16413 * therefore, the class binding itself must already be allocated using
16414 * `styling` within the creation block.
16415 *
16416 * @param prop A valid CSS class (only one).
16417 * @param value A true/false value which will turn the class on or off.
16418 *
16419 * Note that this will apply the provided class value to the host element if this function
16420 * is called within a host binding function.
16421 *
16422 * @codeGenApi
16423 */
16424function ɵɵclassProp(className, value) {
16425 checkStylingProperty(className, value, null, true);
16426 return ɵɵclassProp;
16427}
16428/**
16429 * Update style bindings using an object literal on an element.
16430 *
16431 * This instruction is meant to apply styling via the `[style]="exp"` template bindings.
16432 * When styles are applied to the element they will then be updated with respect to
16433 * any styles/classes set via `styleProp`. If any styles are set to falsy
16434 * then they will be removed from the element.
16435 *
16436 * Note that the styling instruction will not be applied until `stylingApply` is called.
16437 *
16438 * @param styles A key/value style map of the styles that will be applied to the given element.
16439 * Any missing styles (that have already been applied to the element beforehand) will be
16440 * removed (unset) from the element's styling.
16441 *
16442 * Note that this will apply the provided styleMap value to the host element if this function
16443 * is called within a host binding.
16444 *
16445 * @codeGenApi
16446 */
16447function ɵɵstyleMap(styles) {
16448 checkStylingMap(styleKeyValueArraySet, styleStringParser, styles, false);
16449}
16450/**
16451 * Parse text as style and add values to KeyValueArray.
16452 *
16453 * This code is pulled out to a separate function so that it can be tree shaken away if it is not
16454 * needed. It is only referenced from `ɵɵstyleMap`.
16455 *
16456 * @param keyValueArray KeyValueArray to add parsed values to.
16457 * @param text text to parse.
16458 */
16459function styleStringParser(keyValueArray, text) {
16460 for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i)) {
16461 styleKeyValueArraySet(keyValueArray, getLastParsedKey(text), getLastParsedValue(text));
16462 }
16463}
16464/**
16465 * Update class bindings using an object literal or class-string on an element.
16466 *
16467 * This instruction is meant to apply styling via the `[class]="exp"` template bindings.
16468 * When classes are applied to the element they will then be updated with
16469 * respect to any styles/classes set via `classProp`. If any
16470 * classes are set to falsy then they will be removed from the element.
16471 *
16472 * Note that the styling instruction will not be applied until `stylingApply` is called.
16473 * Note that this will the provided classMap value to the host element if this function is called
16474 * within a host binding.
16475 *
16476 * @param classes A key/value map or string of CSS classes that will be added to the
16477 * given element. Any missing classes (that have already been applied to the element
16478 * beforehand) will be removed (unset) from the element's list of CSS classes.
16479 *
16480 * @codeGenApi
16481 */
16482function ɵɵclassMap(classes) {
16483 checkStylingMap(keyValueArraySet, classStringParser, classes, true);
16484}
16485/**
16486 * Parse text as class and add values to KeyValueArray.
16487 *
16488 * This code is pulled out to a separate function so that it can be tree shaken away if it is not
16489 * needed. It is only referenced from `ɵɵclassMap`.
16490 *
16491 * @param keyValueArray KeyValueArray to add parsed values to.
16492 * @param text text to parse.
16493 */
16494function classStringParser(keyValueArray, text) {
16495 for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) {
16496 keyValueArraySet(keyValueArray, getLastParsedKey(text), true);
16497 }
16498}
16499/**
16500 * Common code between `ɵɵclassProp` and `ɵɵstyleProp`.
16501 *
16502 * @param prop property name.
16503 * @param value binding value.
16504 * @param suffix suffix for the property (e.g. `em` or `px`)
16505 * @param isClassBased `true` if `class` change (`false` if `style`)
16506 */
16507function checkStylingProperty(prop, value, suffix, isClassBased) {
16508 const lView = getLView();
16509 const tView = getTView();
16510 // Styling instructions use 2 slots per binding.
16511 // 1. one for the value / TStylingKey
16512 // 2. one for the intermittent-value / TStylingRange
16513 const bindingIndex = incrementBindingIndex(2);
16514 if (tView.firstUpdatePass) {
16515 stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased);
16516 }
16517 if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
16518 const tNode = tView.data[getSelectedIndex()];
16519 updateStyling(tView, tNode, lView, lView[RENDERER], prop, lView[bindingIndex + 1] = normalizeSuffix(value, suffix), isClassBased, bindingIndex);
16520 }
16521}
16522/**
16523 * Common code between `ɵɵclassMap` and `ɵɵstyleMap`.
16524 *
16525 * @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
16526 * function so that `style` can be processed. This is done for tree shaking purposes.
16527 * @param stringParser Parser used to parse `value` if `string`. (Passed in as `style` and `class`
16528 * have different parsers.)
16529 * @param value bound value from application
16530 * @param isClassBased `true` if `class` change (`false` if `style`)
16531 */
16532function checkStylingMap(keyValueArraySet, stringParser, value, isClassBased) {
16533 const tView = getTView();
16534 const bindingIndex = incrementBindingIndex(2);
16535 if (tView.firstUpdatePass) {
16536 stylingFirstUpdatePass(tView, null, bindingIndex, isClassBased);
16537 }
16538 const lView = getLView();
16539 if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
16540 // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the
16541 // if so as not to read unnecessarily.
16542 const tNode = tView.data[getSelectedIndex()];
16543 if (hasStylingInputShadow(tNode, isClassBased) && !isInHostBindings(tView, bindingIndex)) {
16544 if (ngDevMode) {
16545 // verify that if we are shadowing then `TData` is appropriately marked so that we skip
16546 // processing this binding in styling resolution.
16547 const tStylingKey = tView.data[bindingIndex];
16548 assertEqual(Array.isArray(tStylingKey) ? tStylingKey[1] : tStylingKey, false, 'Styling linked list shadow input should be marked as \'false\'');
16549 }
16550 // VE does not concatenate the static portion like we are doing here.
16551 // Instead VE just ignores the static completely if dynamic binding is present.
16552 // Because of locality we have already set the static portion because we don't know if there
16553 // is a dynamic portion until later. If we would ignore the static portion it would look like
16554 // the binding has removed it. This would confuse `[ngStyle]`/`[ngClass]` to do the wrong
16555 // thing as it would think that the static portion was removed. For this reason we
16556 // concatenate it so that `[ngStyle]`/`[ngClass]` can continue to work on changed.
16557 let staticPrefix = isClassBased ? tNode.classesWithoutHost : tNode.stylesWithoutHost;
16558 ngDevMode && isClassBased === false && staticPrefix !== null &&
16559 assertEqual(staticPrefix.endsWith(';'), true, 'Expecting static portion to end with \';\'');
16560 if (staticPrefix !== null) {
16561 // We want to make sure that falsy values of `value` become empty strings.
16562 value = concatStringsWithSpace(staticPrefix, value ? value : '');
16563 }
16564 // Given `<div [style] my-dir>` such that `my-dir` has `@Input('style')`.
16565 // This takes over the `[style]` binding. (Same for `[class]`)
16566 setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased);
16567 }
16568 else {
16569 updateStylingMap(tView, tNode, lView, lView[RENDERER], lView[bindingIndex + 1], lView[bindingIndex + 1] = toStylingKeyValueArray(keyValueArraySet, stringParser, value), isClassBased, bindingIndex);
16570 }
16571 }
16572}
16573/**
16574 * Determines when the binding is in `hostBindings` section
16575 *
16576 * @param tView Current `TView`
16577 * @param bindingIndex index of binding which we would like if it is in `hostBindings`
16578 */
16579function isInHostBindings(tView, bindingIndex) {
16580 // All host bindings are placed after the expando section.
16581 return bindingIndex >= tView.expandoStartIndex;
16582}
16583/**
16584 * Collects the necessary information to insert the binding into a linked list of style bindings
16585 * using `insertTStylingBinding`.
16586 *
16587 * @param tView `TView` where the binding linked list will be stored.
16588 * @param tStylingKey Property/key of the binding.
16589 * @param bindingIndex Index of binding associated with the `prop`
16590 * @param isClassBased `true` if `class` change (`false` if `style`)
16591 */
16592function stylingFirstUpdatePass(tView, tStylingKey, bindingIndex, isClassBased) {
16593 ngDevMode && assertFirstUpdatePass(tView);
16594 const tData = tView.data;
16595 if (tData[bindingIndex + 1] === null) {
16596 // The above check is necessary because we don't clear first update pass until first successful
16597 // (no exception) template execution. This prevents the styling instruction from double adding
16598 // itself to the list.
16599 // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the
16600 // if so as not to read unnecessarily.
16601 const tNode = tData[getSelectedIndex()];
16602 ngDevMode && assertDefined(tNode, 'TNode expected');
16603 const isHostBindings = isInHostBindings(tView, bindingIndex);
16604 if (hasStylingInputShadow(tNode, isClassBased) && tStylingKey === null && !isHostBindings) {
16605 // `tStylingKey === null` implies that we are either `[style]` or `[class]` binding.
16606 // If there is a directive which uses `@Input('style')` or `@Input('class')` than
16607 // we need to neutralize this binding since that directive is shadowing it.
16608 // We turn this into a noop by setting the key to `false`
16609 tStylingKey = false;
16610 }
16611 tStylingKey = wrapInStaticStylingKey(tData, tNode, tStylingKey, isClassBased);
16612 insertTStylingBinding(tData, tNode, tStylingKey, bindingIndex, isHostBindings, isClassBased);
16613 }
16614}
16615/**
16616 * Adds static styling information to the binding if applicable.
16617 *
16618 * The linked list of styles not only stores the list and keys, but also stores static styling
16619 * information on some of the keys. This function determines if the key should contain the styling
16620 * information and computes it.
16621 *
16622 * See `TStylingStatic` for more details.
16623 *
16624 * @param tData `TData` where the linked list is stored.
16625 * @param tNode `TNode` for which the styling is being computed.
16626 * @param stylingKey `TStylingKeyPrimitive` which may need to be wrapped into `TStylingKey`
16627 * @param isClassBased `true` if `class` (`false` if `style`)
16628 */
16629function wrapInStaticStylingKey(tData, tNode, stylingKey, isClassBased) {
16630 const hostDirectiveDef = getCurrentDirectiveDef(tData);
16631 let residual = isClassBased ? tNode.residualClasses : tNode.residualStyles;
16632 if (hostDirectiveDef === null) {
16633 // We are in template node.
16634 // If template node already had styling instruction then it has already collected the static
16635 // styling and there is no need to collect them again. We know that we are the first styling
16636 // instruction because the `TNode.*Bindings` points to 0 (nothing has been inserted yet).
16637 const isFirstStylingInstructionInTemplate = (isClassBased ? tNode.classBindings : tNode.styleBindings) === 0;
16638 if (isFirstStylingInstructionInTemplate) {
16639 // It would be nice to be able to get the statics from `mergeAttrs`, however, at this point
16640 // they are already merged and it would not be possible to figure which property belongs where
16641 // in the priority.
16642 stylingKey = collectStylingFromDirectives(null, tData, tNode, stylingKey, isClassBased);
16643 stylingKey = collectStylingFromTAttrs(stylingKey, tNode.attrs, isClassBased);
16644 // We know that if we have styling binding in template we can't have residual.
16645 residual = null;
16646 }
16647 }
16648 else {
16649 // We are in host binding node and there was no binding instruction in template node.
16650 // This means that we need to compute the residual.
16651 const directiveStylingLast = tNode.directiveStylingLast;
16652 const isFirstStylingInstructionInHostBinding = directiveStylingLast === -1 || tData[directiveStylingLast] !== hostDirectiveDef;
16653 if (isFirstStylingInstructionInHostBinding) {
16654 stylingKey =
16655 collectStylingFromDirectives(hostDirectiveDef, tData, tNode, stylingKey, isClassBased);
16656 if (residual === null) {
16657 // - If `null` than either:
16658 // - Template styling instruction already ran and it has consumed the static
16659 // styling into its `TStylingKey` and so there is no need to update residual. Instead
16660 // we need to update the `TStylingKey` associated with the first template node
16661 // instruction. OR
16662 // - Some other styling instruction ran and determined that there are no residuals
16663 let templateStylingKey = getTemplateHeadTStylingKey(tData, tNode, isClassBased);
16664 if (templateStylingKey !== undefined && Array.isArray(templateStylingKey)) {
16665 // Only recompute if `templateStylingKey` had static values. (If no static value found
16666 // then there is nothing to do since this operation can only produce less static keys, not
16667 // more.)
16668 templateStylingKey = collectStylingFromDirectives(null, tData, tNode, templateStylingKey[1] /* unwrap previous statics */, isClassBased);
16669 templateStylingKey =
16670 collectStylingFromTAttrs(templateStylingKey, tNode.attrs, isClassBased);
16671 setTemplateHeadTStylingKey(tData, tNode, isClassBased, templateStylingKey);
16672 }
16673 }
16674 else {
16675 // We only need to recompute residual if it is not `null`.
16676 // - If existing residual (implies there was no template styling). This means that some of
16677 // the statics may have moved from the residual to the `stylingKey` and so we have to
16678 // recompute.
16679 // - If `undefined` this is the first time we are running.
16680 residual = collectResidual(tData, tNode, isClassBased);
16681 }
16682 }
16683 }
16684 if (residual !== undefined) {
16685 isClassBased ? (tNode.residualClasses = residual) : (tNode.residualStyles = residual);
16686 }
16687 return stylingKey;
16688}
16689/**
16690 * Retrieve the `TStylingKey` for the template styling instruction.
16691 *
16692 * This is needed since `hostBinding` styling instructions are inserted after the template
16693 * instruction. While the template instruction needs to update the residual in `TNode` the
16694 * `hostBinding` instructions need to update the `TStylingKey` of the template instruction because
16695 * the template instruction is downstream from the `hostBindings` instructions.
16696 *
16697 * @param tData `TData` where the linked list is stored.
16698 * @param tNode `TNode` for which the styling is being computed.
16699 * @param isClassBased `true` if `class` (`false` if `style`)
16700 * @return `TStylingKey` if found or `undefined` if not found.
16701 */
16702function getTemplateHeadTStylingKey(tData, tNode, isClassBased) {
16703 const bindings = isClassBased ? tNode.classBindings : tNode.styleBindings;
16704 if (getTStylingRangeNext(bindings) === 0) {
16705 // There does not seem to be a styling instruction in the `template`.
16706 return undefined;
16707 }
16708 return tData[getTStylingRangePrev(bindings)];
16709}
16710/**
16711 * Update the `TStylingKey` of the first template instruction in `TNode`.
16712 *
16713 * Logically `hostBindings` styling instructions are of lower priority than that of the template.
16714 * However, they execute after the template styling instructions. This means that they get inserted
16715 * in front of the template styling instructions.
16716 *
16717 * If we have a template styling instruction and a new `hostBindings` styling instruction is
16718 * executed it means that it may need to steal static fields from the template instruction. This
16719 * method allows us to update the first template instruction `TStylingKey` with a new value.
16720 *
16721 * Assume:
16722 * ```
16723 * <div my-dir style="color: red" [style.color]="tmplExp"></div>
16724 *
16725 * @Directive({
16726 * host: {
16727 * 'style': 'width: 100px',
16728 * '[style.color]': 'dirExp',
16729 * }
16730 * })
16731 * class MyDir {}
16732 * ```
16733 *
16734 * when `[style.color]="tmplExp"` executes it creates this data structure.
16735 * ```
16736 * ['', 'color', 'color', 'red', 'width', '100px'],
16737 * ```
16738 *
16739 * The reason for this is that the template instruction does not know if there are styling
16740 * instructions and must assume that there are none and must collect all of the static styling.
16741 * (both
16742 * `color' and 'width`)
16743 *
16744 * When `'[style.color]': 'dirExp',` executes we need to insert a new data into the linked list.
16745 * ```
16746 * ['', 'color', 'width', '100px'], // newly inserted
16747 * ['', 'color', 'color', 'red', 'width', '100px'], // this is wrong
16748 * ```
16749 *
16750 * Notice that the template statics is now wrong as it incorrectly contains `width` so we need to
16751 * update it like so:
16752 * ```
16753 * ['', 'color', 'width', '100px'],
16754 * ['', 'color', 'color', 'red'], // UPDATE
16755 * ```
16756 *
16757 * @param tData `TData` where the linked list is stored.
16758 * @param tNode `TNode` for which the styling is being computed.
16759 * @param isClassBased `true` if `class` (`false` if `style`)
16760 * @param tStylingKey New `TStylingKey` which is replacing the old one.
16761 */
16762function setTemplateHeadTStylingKey(tData, tNode, isClassBased, tStylingKey) {
16763 const bindings = isClassBased ? tNode.classBindings : tNode.styleBindings;
16764 ngDevMode &&
16765 assertNotEqual(getTStylingRangeNext(bindings), 0, 'Expecting to have at least one template styling binding.');
16766 tData[getTStylingRangePrev(bindings)] = tStylingKey;
16767}
16768/**
16769 * Collect all static values after the current `TNode.directiveStylingLast` index.
16770 *
16771 * Collect the remaining styling information which has not yet been collected by an existing
16772 * styling instruction.
16773 *
16774 * @param tData `TData` where the `DirectiveDefs` are stored.
16775 * @param tNode `TNode` which contains the directive range.
16776 * @param isClassBased `true` if `class` (`false` if `style`)
16777 */
16778function collectResidual(tData, tNode, isClassBased) {
16779 let residual = undefined;
16780 const directiveEnd = tNode.directiveEnd;
16781 ngDevMode &&
16782 assertNotEqual(tNode.directiveStylingLast, -1, 'By the time this function gets called at least one hostBindings-node styling instruction must have executed.');
16783 // We add `1 + tNode.directiveStart` because we need to skip the current directive (as we are
16784 // collecting things after the last `hostBindings` directive which had a styling instruction.)
16785 for (let i = 1 + tNode.directiveStylingLast; i < directiveEnd; i++) {
16786 const attrs = tData[i].hostAttrs;
16787 residual = collectStylingFromTAttrs(residual, attrs, isClassBased);
16788 }
16789 return collectStylingFromTAttrs(residual, tNode.attrs, isClassBased);
16790}
16791/**
16792 * Collect the static styling information with lower priority than `hostDirectiveDef`.
16793 *
16794 * (This is opposite of residual styling.)
16795 *
16796 * @param hostDirectiveDef `DirectiveDef` for which we want to collect lower priority static
16797 * styling. (Or `null` if template styling)
16798 * @param tData `TData` where the linked list is stored.
16799 * @param tNode `TNode` for which the styling is being computed.
16800 * @param stylingKey Existing `TStylingKey` to update or wrap.
16801 * @param isClassBased `true` if `class` (`false` if `style`)
16802 */
16803function collectStylingFromDirectives(hostDirectiveDef, tData, tNode, stylingKey, isClassBased) {
16804 // We need to loop because there can be directives which have `hostAttrs` but don't have
16805 // `hostBindings` so this loop catches up to the current directive..
16806 let currentDirective = null;
16807 const directiveEnd = tNode.directiveEnd;
16808 let directiveStylingLast = tNode.directiveStylingLast;
16809 if (directiveStylingLast === -1) {
16810 directiveStylingLast = tNode.directiveStart;
16811 }
16812 else {
16813 directiveStylingLast++;
16814 }
16815 while (directiveStylingLast < directiveEnd) {
16816 currentDirective = tData[directiveStylingLast];
16817 ngDevMode && assertDefined(currentDirective, 'expected to be defined');
16818 stylingKey = collectStylingFromTAttrs(stylingKey, currentDirective.hostAttrs, isClassBased);
16819 if (currentDirective === hostDirectiveDef)
16820 break;
16821 directiveStylingLast++;
16822 }
16823 if (hostDirectiveDef !== null) {
16824 // we only advance the styling cursor if we are collecting data from host bindings.
16825 // Template executes before host bindings and so if we would update the index,
16826 // host bindings would not get their statics.
16827 tNode.directiveStylingLast = directiveStylingLast;
16828 }
16829 return stylingKey;
16830}
16831/**
16832 * Convert `TAttrs` into `TStylingStatic`.
16833 *
16834 * @param stylingKey existing `TStylingKey` to update or wrap.
16835 * @param attrs `TAttributes` to process.
16836 * @param isClassBased `true` if `class` (`false` if `style`)
16837 */
16838function collectStylingFromTAttrs(stylingKey, attrs, isClassBased) {
16839 const desiredMarker = isClassBased ? 1 /* Classes */ : 2 /* Styles */;
16840 let currentMarker = -1 /* ImplicitAttributes */;
16841 if (attrs !== null) {
16842 for (let i = 0; i < attrs.length; i++) {
16843 const item = attrs[i];
16844 if (typeof item === 'number') {
16845 currentMarker = item;
16846 }
16847 else {
16848 if (currentMarker === desiredMarker) {
16849 if (!Array.isArray(stylingKey)) {
16850 stylingKey = stylingKey === undefined ? [] : ['', stylingKey];
16851 }
16852 keyValueArraySet(stylingKey, item, isClassBased ? true : attrs[++i]);
16853 }
16854 }
16855 }
16856 }
16857 return stylingKey === undefined ? null : stylingKey;
16858}
16859/**
16860 * Convert user input to `KeyValueArray`.
16861 *
16862 * This function takes user input which could be `string`, Object literal, or iterable and converts
16863 * it into a consistent representation. The output of this is `KeyValueArray` (which is an array
16864 * where
16865 * even indexes contain keys and odd indexes contain values for those keys).
16866 *
16867 * The advantage of converting to `KeyValueArray` is that we can perform diff in an input
16868 * independent
16869 * way.
16870 * (ie we can compare `foo bar` to `['bar', 'baz'] and determine a set of changes which need to be
16871 * applied)
16872 *
16873 * The fact that `KeyValueArray` is sorted is very important because it allows us to compute the
16874 * difference in linear fashion without the need to allocate any additional data.
16875 *
16876 * For example if we kept this as a `Map` we would have to iterate over previous `Map` to determine
16877 * which values need to be deleted, over the new `Map` to determine additions, and we would have to
16878 * keep additional `Map` to keep track of duplicates or items which have not yet been visited.
16879 *
16880 * @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
16881 * function so that `style` can be processed. This is done
16882 * for tree shaking purposes.
16883 * @param stringParser The parser is passed in so that it will be tree shakable. See
16884 * `styleStringParser` and `classStringParser`
16885 * @param value The value to parse/convert to `KeyValueArray`
16886 */
16887function toStylingKeyValueArray(keyValueArraySet, stringParser, value) {
16888 if (value == null /*|| value === undefined */ || value === '')
16889 return EMPTY_ARRAY;
16890 const styleKeyValueArray = [];
16891 const unwrappedValue = unwrapSafeValue(value);
16892 if (Array.isArray(unwrappedValue)) {
16893 for (let i = 0; i < unwrappedValue.length; i++) {
16894 keyValueArraySet(styleKeyValueArray, unwrappedValue[i], true);
16895 }
16896 }
16897 else if (typeof unwrappedValue === 'object') {
16898 for (const key in unwrappedValue) {
16899 if (unwrappedValue.hasOwnProperty(key)) {
16900 keyValueArraySet(styleKeyValueArray, key, unwrappedValue[key]);
16901 }
16902 }
16903 }
16904 else if (typeof unwrappedValue === 'string') {
16905 stringParser(styleKeyValueArray, unwrappedValue);
16906 }
16907 else {
16908 ngDevMode &&
16909 throwError('Unsupported styling type ' + typeof unwrappedValue + ': ' + unwrappedValue);
16910 }
16911 return styleKeyValueArray;
16912}
16913/**
16914 * Set a `value` for a `key`.
16915 *
16916 * See: `keyValueArraySet` for details
16917 *
16918 * @param keyValueArray KeyValueArray to add to.
16919 * @param key Style key to add.
16920 * @param value The value to set.
16921 */
16922function styleKeyValueArraySet(keyValueArray, key, value) {
16923 keyValueArraySet(keyValueArray, key, unwrapSafeValue(value));
16924}
16925/**
16926 * Update map based styling.
16927 *
16928 * Map based styling could be anything which contains more than one binding. For example `string`,
16929 * or object literal. Dealing with all of these types would complicate the logic so
16930 * instead this function expects that the complex input is first converted into normalized
16931 * `KeyValueArray`. The advantage of normalization is that we get the values sorted, which makes it
16932 * very cheap to compute deltas between the previous and current value.
16933 *
16934 * @param tView Associated `TView.data` contains the linked list of binding priorities.
16935 * @param tNode `TNode` where the binding is located.
16936 * @param lView `LView` contains the values associated with other styling binding at this `TNode`.
16937 * @param renderer Renderer to use if any updates.
16938 * @param oldKeyValueArray Previous value represented as `KeyValueArray`
16939 * @param newKeyValueArray Current value represented as `KeyValueArray`
16940 * @param isClassBased `true` if `class` (`false` if `style`)
16941 * @param bindingIndex Binding index of the binding.
16942 */
16943function updateStylingMap(tView, tNode, lView, renderer, oldKeyValueArray, newKeyValueArray, isClassBased, bindingIndex) {
16944 if (oldKeyValueArray === NO_CHANGE) {
16945 // On first execution the oldKeyValueArray is NO_CHANGE => treat it as empty KeyValueArray.
16946 oldKeyValueArray = EMPTY_ARRAY;
16947 }
16948 let oldIndex = 0;
16949 let newIndex = 0;
16950 let oldKey = 0 < oldKeyValueArray.length ? oldKeyValueArray[0] : null;
16951 let newKey = 0 < newKeyValueArray.length ? newKeyValueArray[0] : null;
16952 while (oldKey !== null || newKey !== null) {
16953 ngDevMode && assertLessThan(oldIndex, 999, 'Are we stuck in infinite loop?');
16954 ngDevMode && assertLessThan(newIndex, 999, 'Are we stuck in infinite loop?');
16955 const oldValue = oldIndex < oldKeyValueArray.length ? oldKeyValueArray[oldIndex + 1] : undefined;
16956 const newValue = newIndex < newKeyValueArray.length ? newKeyValueArray[newIndex + 1] : undefined;
16957 let setKey = null;
16958 let setValue = undefined;
16959 if (oldKey === newKey) {
16960 // UPDATE: Keys are equal => new value is overwriting old value.
16961 oldIndex += 2;
16962 newIndex += 2;
16963 if (oldValue !== newValue) {
16964 setKey = newKey;
16965 setValue = newValue;
16966 }
16967 }
16968 else if (newKey === null || oldKey !== null && oldKey < newKey) {
16969 // DELETE: oldKey key is missing or we did not find the oldKey in the newValue
16970 // (because the keyValueArray is sorted and `newKey` is found later alphabetically).
16971 // `"background" < "color"` so we need to delete `"background"` because it is not found in the
16972 // new array.
16973 oldIndex += 2;
16974 setKey = oldKey;
16975 }
16976 else {
16977 // CREATE: newKey's is earlier alphabetically than oldKey's (or no oldKey) => we have new key.
16978 // `"color" > "background"` so we need to add `color` because it is in new array but not in
16979 // old array.
16980 ngDevMode && assertDefined(newKey, 'Expecting to have a valid key');
16981 newIndex += 2;
16982 setKey = newKey;
16983 setValue = newValue;
16984 }
16985 if (setKey !== null) {
16986 updateStyling(tView, tNode, lView, renderer, setKey, setValue, isClassBased, bindingIndex);
16987 }
16988 oldKey = oldIndex < oldKeyValueArray.length ? oldKeyValueArray[oldIndex] : null;
16989 newKey = newIndex < newKeyValueArray.length ? newKeyValueArray[newIndex] : null;
16990 }
16991}
16992/**
16993 * Update a simple (property name) styling.
16994 *
16995 * This function takes `prop` and updates the DOM to that value. The function takes the binding
16996 * value as well as binding priority into consideration to determine which value should be written
16997 * to DOM. (For example it may be determined that there is a higher priority overwrite which blocks
16998 * the DOM write, or if the value goes to `undefined` a lower priority overwrite may be consulted.)
16999 *
17000 * @param tView Associated `TView.data` contains the linked list of binding priorities.
17001 * @param tNode `TNode` where the binding is located.
17002 * @param lView `LView` contains the values associated with other styling binding at this `TNode`.
17003 * @param renderer Renderer to use if any updates.
17004 * @param prop Either style property name or a class name.
17005 * @param value Either style value for `prop` or `true`/`false` if `prop` is class.
17006 * @param isClassBased `true` if `class` (`false` if `style`)
17007 * @param bindingIndex Binding index of the binding.
17008 */
17009function updateStyling(tView, tNode, lView, renderer, prop, value, isClassBased, bindingIndex) {
17010 if (!(tNode.type & 3 /* AnyRNode */)) {
17011 // It is possible to have styling on non-elements (such as ng-container).
17012 // This is rare, but it does happen. In such a case, just ignore the binding.
17013 return;
17014 }
17015 const tData = tView.data;
17016 const tRange = tData[bindingIndex + 1];
17017 const higherPriorityValue = getTStylingRangeNextDuplicate(tRange) ?
17018 findStylingValue(tData, tNode, lView, prop, getTStylingRangeNext(tRange), isClassBased) :
17019 undefined;
17020 if (!isStylingValuePresent(higherPriorityValue)) {
17021 // We don't have a next duplicate, or we did not find a duplicate value.
17022 if (!isStylingValuePresent(value)) {
17023 // We should delete current value or restore to lower priority value.
17024 if (getTStylingRangePrevDuplicate(tRange)) {
17025 // We have a possible prev duplicate, let's retrieve it.
17026 value = findStylingValue(tData, null, lView, prop, bindingIndex, isClassBased);
17027 }
17028 }
17029 const rNode = getNativeByIndex(getSelectedIndex(), lView);
17030 applyStyling(renderer, isClassBased, rNode, prop, value);
17031 }
17032}
17033/**
17034 * Search for styling value with higher priority which is overwriting current value, or a
17035 * value of lower priority to which we should fall back if the value is `undefined`.
17036 *
17037 * When value is being applied at a location, related values need to be consulted.
17038 * - If there is a higher priority binding, we should be using that one instead.
17039 * For example `<div [style]="{color:exp1}" [style.color]="exp2">` change to `exp1`
17040 * requires that we check `exp2` to see if it is set to value other than `undefined`.
17041 * - If there is a lower priority binding and we are changing to `undefined`
17042 * For example `<div [style]="{color:exp1}" [style.color]="exp2">` change to `exp2` to
17043 * `undefined` requires that we check `exp1` (and static values) and use that as new value.
17044 *
17045 * NOTE: The styling stores two values.
17046 * 1. The raw value which came from the application is stored at `index + 0` location. (This value
17047 * is used for dirty checking).
17048 * 2. The normalized value is stored at `index + 1`.
17049 *
17050 * @param tData `TData` used for traversing the priority.
17051 * @param tNode `TNode` to use for resolving static styling. Also controls search direction.
17052 * - `TNode` search next and quit as soon as `isStylingValuePresent(value)` is true.
17053 * If no value found consult `tNode.residualStyle`/`tNode.residualClass` for default value.
17054 * - `null` search prev and go all the way to end. Return last value where
17055 * `isStylingValuePresent(value)` is true.
17056 * @param lView `LView` used for retrieving the actual values.
17057 * @param prop Property which we are interested in.
17058 * @param index Starting index in the linked list of styling bindings where the search should start.
17059 * @param isClassBased `true` if `class` (`false` if `style`)
17060 */
17061function findStylingValue(tData, tNode, lView, prop, index, isClassBased) {
17062 // `TNode` to use for resolving static styling. Also controls search direction.
17063 // - `TNode` search next and quit as soon as `isStylingValuePresent(value)` is true.
17064 // If no value found consult `tNode.residualStyle`/`tNode.residualClass` for default value.
17065 // - `null` search prev and go all the way to end. Return last value where
17066 // `isStylingValuePresent(value)` is true.
17067 const isPrevDirection = tNode === null;
17068 let value = undefined;
17069 while (index > 0) {
17070 const rawKey = tData[index];
17071 const containsStatics = Array.isArray(rawKey);
17072 // Unwrap the key if we contain static values.
17073 const key = containsStatics ? rawKey[1] : rawKey;
17074 const isStylingMap = key === null;
17075 let valueAtLViewIndex = lView[index + 1];
17076 if (valueAtLViewIndex === NO_CHANGE) {
17077 // In firstUpdatePass the styling instructions create a linked list of styling.
17078 // On subsequent passes it is possible for a styling instruction to try to read a binding
17079 // which
17080 // has not yet executed. In that case we will find `NO_CHANGE` and we should assume that
17081 // we have `undefined` (or empty array in case of styling-map instruction) instead. This
17082 // allows the resolution to apply the value (which may later be overwritten when the
17083 // binding actually executes.)
17084 valueAtLViewIndex = isStylingMap ? EMPTY_ARRAY : undefined;
17085 }
17086 let currentValue = isStylingMap ? keyValueArrayGet(valueAtLViewIndex, prop) :
17087 key === prop ? valueAtLViewIndex : undefined;
17088 if (containsStatics && !isStylingValuePresent(currentValue)) {
17089 currentValue = keyValueArrayGet(rawKey, prop);
17090 }
17091 if (isStylingValuePresent(currentValue)) {
17092 value = currentValue;
17093 if (isPrevDirection) {
17094 return value;
17095 }
17096 }
17097 const tRange = tData[index + 1];
17098 index = isPrevDirection ? getTStylingRangePrev(tRange) : getTStylingRangeNext(tRange);
17099 }
17100 if (tNode !== null) {
17101 // in case where we are going in next direction AND we did not find anything, we need to
17102 // consult residual styling
17103 let residual = isClassBased ? tNode.residualClasses : tNode.residualStyles;
17104 if (residual != null /** OR residual !=== undefined */) {
17105 value = keyValueArrayGet(residual, prop);
17106 }
17107 }
17108 return value;
17109}
17110/**
17111 * Determines if the binding value should be used (or if the value is 'undefined' and hence priority
17112 * resolution should be used.)
17113 *
17114 * @param value Binding style value.
17115 */
17116function isStylingValuePresent(value) {
17117 // Currently only `undefined` value is considered non-binding. That is `undefined` says I don't
17118 // have an opinion as to what this binding should be and you should consult other bindings by
17119 // priority to determine the valid value.
17120 // This is extracted into a single function so that we have a single place to control this.
17121 return value !== undefined;
17122}
17123/**
17124 * Normalizes and/or adds a suffix to the value.
17125 *
17126 * If value is `null`/`undefined` no suffix is added
17127 * @param value
17128 * @param suffix
17129 */
17130function normalizeSuffix(value, suffix) {
17131 if (value == null /** || value === undefined */) {
17132 // do nothing
17133 }
17134 else if (typeof suffix === 'string') {
17135 value = value + suffix;
17136 }
17137 else if (typeof value === 'object') {
17138 value = stringify(unwrapSafeValue(value));
17139 }
17140 return value;
17141}
17142/**
17143 * Tests if the `TNode` has input shadow.
17144 *
17145 * An input shadow is when a directive steals (shadows) the input by using `@Input('style')` or
17146 * `@Input('class')` as input.
17147 *
17148 * @param tNode `TNode` which we would like to see if it has shadow.
17149 * @param isClassBased `true` if `class` (`false` if `style`)
17150 */
17151function hasStylingInputShadow(tNode, isClassBased) {
17152 return (tNode.flags & (isClassBased ? 16 /* hasClassInput */ : 32 /* hasStyleInput */)) !== 0;
17153}
17154
17155/**
17156 * @license
17157 * Copyright Google LLC All Rights Reserved.
17158 *
17159 * Use of this source code is governed by an MIT-style license that can be
17160 * found in the LICENSE file at https://angular.io/license
17161 */
17162/**
17163 * Create static text node
17164 *
17165 * @param index Index of the node in the data array
17166 * @param value Static string value to write.
17167 *
17168 * @codeGenApi
17169 */
17170function ɵɵtext(index, value = '') {
17171 const lView = getLView();
17172 const tView = getTView();
17173 const adjustedIndex = index + HEADER_OFFSET;
17174 ngDevMode &&
17175 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'text nodes should be created before any bindings');
17176 ngDevMode && assertIndexInRange(lView, adjustedIndex);
17177 const tNode = tView.firstCreatePass ?
17178 getOrCreateTNode(tView, adjustedIndex, 1 /* Text */, value, null) :
17179 tView.data[adjustedIndex];
17180 const textNative = lView[adjustedIndex] = createTextNode(lView[RENDERER], value);
17181 appendChild(tView, lView, textNative, tNode);
17182 // Text nodes are self closing.
17183 setCurrentTNode(tNode, false);
17184}
17185
17186/**
17187 * @license
17188 * Copyright Google LLC All Rights Reserved.
17189 *
17190 * Use of this source code is governed by an MIT-style license that can be
17191 * found in the LICENSE file at https://angular.io/license
17192 */
17193/**
17194 *
17195 * Update text content with a lone bound value
17196 *
17197 * Used when a text node has 1 interpolated value in it, an no additional text
17198 * surrounds that interpolated value:
17199 *
17200 * ```html
17201 * <div>{{v0}}</div>
17202 * ```
17203 *
17204 * Its compiled representation is:
17205 *
17206 * ```ts
17207 * ɵɵtextInterpolate(v0);
17208 * ```
17209 * @returns itself, so that it may be chained.
17210 * @see textInterpolateV
17211 * @codeGenApi
17212 */
17213function ɵɵtextInterpolate(v0) {
17214 ɵɵtextInterpolate1('', v0, '');
17215 return ɵɵtextInterpolate;
17216}
17217/**
17218 *
17219 * Update text content with single bound value surrounded by other text.
17220 *
17221 * Used when a text node has 1 interpolated value in it:
17222 *
17223 * ```html
17224 * <div>prefix{{v0}}suffix</div>
17225 * ```
17226 *
17227 * Its compiled representation is:
17228 *
17229 * ```ts
17230 * ɵɵtextInterpolate1('prefix', v0, 'suffix');
17231 * ```
17232 * @returns itself, so that it may be chained.
17233 * @see textInterpolateV
17234 * @codeGenApi
17235 */
17236function ɵɵtextInterpolate1(prefix, v0, suffix) {
17237 const lView = getLView();
17238 const interpolated = interpolation1(lView, prefix, v0, suffix);
17239 if (interpolated !== NO_CHANGE) {
17240 textBindingInternal(lView, getSelectedIndex(), interpolated);
17241 }
17242 return ɵɵtextInterpolate1;
17243}
17244/**
17245 *
17246 * Update text content with 2 bound values surrounded by other text.
17247 *
17248 * Used when a text node has 2 interpolated values in it:
17249 *
17250 * ```html
17251 * <div>prefix{{v0}}-{{v1}}suffix</div>
17252 * ```
17253 *
17254 * Its compiled representation is:
17255 *
17256 * ```ts
17257 * ɵɵtextInterpolate2('prefix', v0, '-', v1, 'suffix');
17258 * ```
17259 * @returns itself, so that it may be chained.
17260 * @see textInterpolateV
17261 * @codeGenApi
17262 */
17263function ɵɵtextInterpolate2(prefix, v0, i0, v1, suffix) {
17264 const lView = getLView();
17265 const interpolated = interpolation2(lView, prefix, v0, i0, v1, suffix);
17266 if (interpolated !== NO_CHANGE) {
17267 textBindingInternal(lView, getSelectedIndex(), interpolated);
17268 }
17269 return ɵɵtextInterpolate2;
17270}
17271/**
17272 *
17273 * Update text content with 3 bound values surrounded by other text.
17274 *
17275 * Used when a text node has 3 interpolated values in it:
17276 *
17277 * ```html
17278 * <div>prefix{{v0}}-{{v1}}-{{v2}}suffix</div>
17279 * ```
17280 *
17281 * Its compiled representation is:
17282 *
17283 * ```ts
17284 * ɵɵtextInterpolate3(
17285 * 'prefix', v0, '-', v1, '-', v2, 'suffix');
17286 * ```
17287 * @returns itself, so that it may be chained.
17288 * @see textInterpolateV
17289 * @codeGenApi
17290 */
17291function ɵɵtextInterpolate3(prefix, v0, i0, v1, i1, v2, suffix) {
17292 const lView = getLView();
17293 const interpolated = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
17294 if (interpolated !== NO_CHANGE) {
17295 textBindingInternal(lView, getSelectedIndex(), interpolated);
17296 }
17297 return ɵɵtextInterpolate3;
17298}
17299/**
17300 *
17301 * Update text content with 4 bound values surrounded by other text.
17302 *
17303 * Used when a text node has 4 interpolated values in it:
17304 *
17305 * ```html
17306 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix</div>
17307 * ```
17308 *
17309 * Its compiled representation is:
17310 *
17311 * ```ts
17312 * ɵɵtextInterpolate4(
17313 * 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
17314 * ```
17315 * @returns itself, so that it may be chained.
17316 * @see ɵɵtextInterpolateV
17317 * @codeGenApi
17318 */
17319function ɵɵtextInterpolate4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
17320 const lView = getLView();
17321 const interpolated = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
17322 if (interpolated !== NO_CHANGE) {
17323 textBindingInternal(lView, getSelectedIndex(), interpolated);
17324 }
17325 return ɵɵtextInterpolate4;
17326}
17327/**
17328 *
17329 * Update text content with 5 bound values surrounded by other text.
17330 *
17331 * Used when a text node has 5 interpolated values in it:
17332 *
17333 * ```html
17334 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix</div>
17335 * ```
17336 *
17337 * Its compiled representation is:
17338 *
17339 * ```ts
17340 * ɵɵtextInterpolate5(
17341 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
17342 * ```
17343 * @returns itself, so that it may be chained.
17344 * @see textInterpolateV
17345 * @codeGenApi
17346 */
17347function ɵɵtextInterpolate5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
17348 const lView = getLView();
17349 const interpolated = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
17350 if (interpolated !== NO_CHANGE) {
17351 textBindingInternal(lView, getSelectedIndex(), interpolated);
17352 }
17353 return ɵɵtextInterpolate5;
17354}
17355/**
17356 *
17357 * Update text content with 6 bound values surrounded by other text.
17358 *
17359 * Used when a text node has 6 interpolated values in it:
17360 *
17361 * ```html
17362 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix</div>
17363 * ```
17364 *
17365 * Its compiled representation is:
17366 *
17367 * ```ts
17368 * ɵɵtextInterpolate6(
17369 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
17370 * ```
17371 *
17372 * @param i4 Static value used for concatenation only.
17373 * @param v5 Value checked for change. @returns itself, so that it may be chained.
17374 * @see textInterpolateV
17375 * @codeGenApi
17376 */
17377function ɵɵtextInterpolate6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
17378 const lView = getLView();
17379 const interpolated = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
17380 if (interpolated !== NO_CHANGE) {
17381 textBindingInternal(lView, getSelectedIndex(), interpolated);
17382 }
17383 return ɵɵtextInterpolate6;
17384}
17385/**
17386 *
17387 * Update text content with 7 bound values surrounded by other text.
17388 *
17389 * Used when a text node has 7 interpolated values in it:
17390 *
17391 * ```html
17392 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix</div>
17393 * ```
17394 *
17395 * Its compiled representation is:
17396 *
17397 * ```ts
17398 * ɵɵtextInterpolate7(
17399 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
17400 * ```
17401 * @returns itself, so that it may be chained.
17402 * @see textInterpolateV
17403 * @codeGenApi
17404 */
17405function ɵɵtextInterpolate7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
17406 const lView = getLView();
17407 const interpolated = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
17408 if (interpolated !== NO_CHANGE) {
17409 textBindingInternal(lView, getSelectedIndex(), interpolated);
17410 }
17411 return ɵɵtextInterpolate7;
17412}
17413/**
17414 *
17415 * Update text content with 8 bound values surrounded by other text.
17416 *
17417 * Used when a text node has 8 interpolated values in it:
17418 *
17419 * ```html
17420 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix</div>
17421 * ```
17422 *
17423 * Its compiled representation is:
17424 *
17425 * ```ts
17426 * ɵɵtextInterpolate8(
17427 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
17428 * ```
17429 * @returns itself, so that it may be chained.
17430 * @see textInterpolateV
17431 * @codeGenApi
17432 */
17433function ɵɵtextInterpolate8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
17434 const lView = getLView();
17435 const interpolated = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
17436 if (interpolated !== NO_CHANGE) {
17437 textBindingInternal(lView, getSelectedIndex(), interpolated);
17438 }
17439 return ɵɵtextInterpolate8;
17440}
17441/**
17442 * Update text content with 9 or more bound values other surrounded by text.
17443 *
17444 * Used when the number of interpolated values exceeds 8.
17445 *
17446 * ```html
17447 * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix</div>
17448 * ```
17449 *
17450 * Its compiled representation is:
17451 *
17452 * ```ts
17453 * ɵɵtextInterpolateV(
17454 * ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
17455 * 'suffix']);
17456 * ```
17457 *.
17458 * @param values The collection of values and the strings in between those values, beginning with
17459 * a string prefix and ending with a string suffix.
17460 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
17461 *
17462 * @returns itself, so that it may be chained.
17463 * @codeGenApi
17464 */
17465function ɵɵtextInterpolateV(values) {
17466 const lView = getLView();
17467 const interpolated = interpolationV(lView, values);
17468 if (interpolated !== NO_CHANGE) {
17469 textBindingInternal(lView, getSelectedIndex(), interpolated);
17470 }
17471 return ɵɵtextInterpolateV;
17472}
17473
17474/**
17475 * @license
17476 * Copyright Google LLC All Rights Reserved.
17477 *
17478 * Use of this source code is governed by an MIT-style license that can be
17479 * found in the LICENSE file at https://angular.io/license
17480 */
17481/**
17482 *
17483 * Update an interpolated class on an element with single bound value surrounded by text.
17484 *
17485 * Used when the value passed to a property has 1 interpolated value in it:
17486 *
17487 * ```html
17488 * <div class="prefix{{v0}}suffix"></div>
17489 * ```
17490 *
17491 * Its compiled representation is:
17492 *
17493 * ```ts
17494 * ɵɵclassMapInterpolate1('prefix', v0, 'suffix');
17495 * ```
17496 *
17497 * @param prefix Static value used for concatenation only.
17498 * @param v0 Value checked for change.
17499 * @param suffix Static value used for concatenation only.
17500 * @codeGenApi
17501 */
17502function ɵɵclassMapInterpolate1(prefix, v0, suffix) {
17503 const lView = getLView();
17504 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
17505 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17506}
17507/**
17508 *
17509 * Update an interpolated class on an element with 2 bound values surrounded by text.
17510 *
17511 * Used when the value passed to a property has 2 interpolated values in it:
17512 *
17513 * ```html
17514 * <div class="prefix{{v0}}-{{v1}}suffix"></div>
17515 * ```
17516 *
17517 * Its compiled representation is:
17518 *
17519 * ```ts
17520 * ɵɵclassMapInterpolate2('prefix', v0, '-', v1, 'suffix');
17521 * ```
17522 *
17523 * @param prefix Static value used for concatenation only.
17524 * @param v0 Value checked for change.
17525 * @param i0 Static value used for concatenation only.
17526 * @param v1 Value checked for change.
17527 * @param suffix Static value used for concatenation only.
17528 * @codeGenApi
17529 */
17530function ɵɵclassMapInterpolate2(prefix, v0, i0, v1, suffix) {
17531 const lView = getLView();
17532 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
17533 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17534}
17535/**
17536 *
17537 * Update an interpolated class on an element with 3 bound values surrounded by text.
17538 *
17539 * Used when the value passed to a property has 3 interpolated values in it:
17540 *
17541 * ```html
17542 * <div class="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
17543 * ```
17544 *
17545 * Its compiled representation is:
17546 *
17547 * ```ts
17548 * ɵɵclassMapInterpolate3(
17549 * 'prefix', v0, '-', v1, '-', v2, 'suffix');
17550 * ```
17551 *
17552 * @param prefix Static value used for concatenation only.
17553 * @param v0 Value checked for change.
17554 * @param i0 Static value used for concatenation only.
17555 * @param v1 Value checked for change.
17556 * @param i1 Static value used for concatenation only.
17557 * @param v2 Value checked for change.
17558 * @param suffix Static value used for concatenation only.
17559 * @codeGenApi
17560 */
17561function ɵɵclassMapInterpolate3(prefix, v0, i0, v1, i1, v2, suffix) {
17562 const lView = getLView();
17563 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
17564 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17565}
17566/**
17567 *
17568 * Update an interpolated class on an element with 4 bound values surrounded by text.
17569 *
17570 * Used when the value passed to a property has 4 interpolated values in it:
17571 *
17572 * ```html
17573 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
17574 * ```
17575 *
17576 * Its compiled representation is:
17577 *
17578 * ```ts
17579 * ɵɵclassMapInterpolate4(
17580 * 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
17581 * ```
17582 *
17583 * @param prefix Static value used for concatenation only.
17584 * @param v0 Value checked for change.
17585 * @param i0 Static value used for concatenation only.
17586 * @param v1 Value checked for change.
17587 * @param i1 Static value used for concatenation only.
17588 * @param v2 Value checked for change.
17589 * @param i2 Static value used for concatenation only.
17590 * @param v3 Value checked for change.
17591 * @param suffix Static value used for concatenation only.
17592 * @codeGenApi
17593 */
17594function ɵɵclassMapInterpolate4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
17595 const lView = getLView();
17596 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
17597 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17598}
17599/**
17600 *
17601 * Update an interpolated class on an element with 5 bound values surrounded by text.
17602 *
17603 * Used when the value passed to a property has 5 interpolated values in it:
17604 *
17605 * ```html
17606 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
17607 * ```
17608 *
17609 * Its compiled representation is:
17610 *
17611 * ```ts
17612 * ɵɵclassMapInterpolate5(
17613 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
17614 * ```
17615 *
17616 * @param prefix Static value used for concatenation only.
17617 * @param v0 Value checked for change.
17618 * @param i0 Static value used for concatenation only.
17619 * @param v1 Value checked for change.
17620 * @param i1 Static value used for concatenation only.
17621 * @param v2 Value checked for change.
17622 * @param i2 Static value used for concatenation only.
17623 * @param v3 Value checked for change.
17624 * @param i3 Static value used for concatenation only.
17625 * @param v4 Value checked for change.
17626 * @param suffix Static value used for concatenation only.
17627 * @codeGenApi
17628 */
17629function ɵɵclassMapInterpolate5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
17630 const lView = getLView();
17631 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
17632 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17633}
17634/**
17635 *
17636 * Update an interpolated class on an element with 6 bound values surrounded by text.
17637 *
17638 * Used when the value passed to a property has 6 interpolated values in it:
17639 *
17640 * ```html
17641 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
17642 * ```
17643 *
17644 * Its compiled representation is:
17645 *
17646 * ```ts
17647 * ɵɵclassMapInterpolate6(
17648 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
17649 * ```
17650 *
17651 * @param prefix Static value used for concatenation only.
17652 * @param v0 Value checked for change.
17653 * @param i0 Static value used for concatenation only.
17654 * @param v1 Value checked for change.
17655 * @param i1 Static value used for concatenation only.
17656 * @param v2 Value checked for change.
17657 * @param i2 Static value used for concatenation only.
17658 * @param v3 Value checked for change.
17659 * @param i3 Static value used for concatenation only.
17660 * @param v4 Value checked for change.
17661 * @param i4 Static value used for concatenation only.
17662 * @param v5 Value checked for change.
17663 * @param suffix Static value used for concatenation only.
17664 * @codeGenApi
17665 */
17666function ɵɵclassMapInterpolate6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
17667 const lView = getLView();
17668 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
17669 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17670}
17671/**
17672 *
17673 * Update an interpolated class on an element with 7 bound values surrounded by text.
17674 *
17675 * Used when the value passed to a property has 7 interpolated values in it:
17676 *
17677 * ```html
17678 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
17679 * ```
17680 *
17681 * Its compiled representation is:
17682 *
17683 * ```ts
17684 * ɵɵclassMapInterpolate7(
17685 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
17686 * ```
17687 *
17688 * @param prefix Static value used for concatenation only.
17689 * @param v0 Value checked for change.
17690 * @param i0 Static value used for concatenation only.
17691 * @param v1 Value checked for change.
17692 * @param i1 Static value used for concatenation only.
17693 * @param v2 Value checked for change.
17694 * @param i2 Static value used for concatenation only.
17695 * @param v3 Value checked for change.
17696 * @param i3 Static value used for concatenation only.
17697 * @param v4 Value checked for change.
17698 * @param i4 Static value used for concatenation only.
17699 * @param v5 Value checked for change.
17700 * @param i5 Static value used for concatenation only.
17701 * @param v6 Value checked for change.
17702 * @param suffix Static value used for concatenation only.
17703 * @codeGenApi
17704 */
17705function ɵɵclassMapInterpolate7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
17706 const lView = getLView();
17707 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
17708 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17709}
17710/**
17711 *
17712 * Update an interpolated class on an element with 8 bound values surrounded by text.
17713 *
17714 * Used when the value passed to a property has 8 interpolated values in it:
17715 *
17716 * ```html
17717 * <div class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
17718 * ```
17719 *
17720 * Its compiled representation is:
17721 *
17722 * ```ts
17723 * ɵɵclassMapInterpolate8(
17724 * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
17725 * ```
17726 *
17727 * @param prefix Static value used for concatenation only.
17728 * @param v0 Value checked for change.
17729 * @param i0 Static value used for concatenation only.
17730 * @param v1 Value checked for change.
17731 * @param i1 Static value used for concatenation only.
17732 * @param v2 Value checked for change.
17733 * @param i2 Static value used for concatenation only.
17734 * @param v3 Value checked for change.
17735 * @param i3 Static value used for concatenation only.
17736 * @param v4 Value checked for change.
17737 * @param i4 Static value used for concatenation only.
17738 * @param v5 Value checked for change.
17739 * @param i5 Static value used for concatenation only.
17740 * @param v6 Value checked for change.
17741 * @param i6 Static value used for concatenation only.
17742 * @param v7 Value checked for change.
17743 * @param suffix Static value used for concatenation only.
17744 * @codeGenApi
17745 */
17746function ɵɵclassMapInterpolate8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
17747 const lView = getLView();
17748 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
17749 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17750}
17751/**
17752 * Update an interpolated class on an element with 9 or more bound values surrounded by text.
17753 *
17754 * Used when the number of interpolated values exceeds 8.
17755 *
17756 * ```html
17757 * <div
17758 * class="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
17759 * ```
17760 *
17761 * Its compiled representation is:
17762 *
17763 * ```ts
17764 * ɵɵclassMapInterpolateV(
17765 * ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
17766 * 'suffix']);
17767 * ```
17768 *.
17769 * @param values The collection of values and the strings in-between those values, beginning with
17770 * a string prefix and ending with a string suffix.
17771 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
17772 * @codeGenApi
17773 */
17774function ɵɵclassMapInterpolateV(values) {
17775 const lView = getLView();
17776 const interpolatedValue = interpolationV(lView, values);
17777 checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17778}
17779
17780/**
17781 * @license
17782 * Copyright Google LLC All Rights Reserved.
17783 *
17784 * Use of this source code is governed by an MIT-style license that can be
17785 * found in the LICENSE file at https://angular.io/license
17786 */
17787/**
17788 *
17789 * Update an interpolated style on an element with single bound value surrounded by text.
17790 *
17791 * Used when the value passed to a property has 1 interpolated value in it:
17792 *
17793 * ```html
17794 * <div style="key: {{v0}}suffix"></div>
17795 * ```
17796 *
17797 * Its compiled representation is:
17798 *
17799 * ```ts
17800 * ɵɵstyleMapInterpolate1('key: ', v0, 'suffix');
17801 * ```
17802 *
17803 * @param prefix Static value used for concatenation only.
17804 * @param v0 Value checked for change.
17805 * @param suffix Static value used for concatenation only.
17806 * @codeGenApi
17807 */
17808function ɵɵstyleMapInterpolate1(prefix, v0, suffix) {
17809 const lView = getLView();
17810 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
17811 ɵɵstyleMap(interpolatedValue);
17812}
17813/**
17814 *
17815 * Update an interpolated style on an element with 2 bound values surrounded by text.
17816 *
17817 * Used when the value passed to a property has 2 interpolated values in it:
17818 *
17819 * ```html
17820 * <div style="key: {{v0}}; key1: {{v1}}suffix"></div>
17821 * ```
17822 *
17823 * Its compiled representation is:
17824 *
17825 * ```ts
17826 * ɵɵstyleMapInterpolate2('key: ', v0, '; key1: ', v1, 'suffix');
17827 * ```
17828 *
17829 * @param prefix Static value used for concatenation only.
17830 * @param v0 Value checked for change.
17831 * @param i0 Static value used for concatenation only.
17832 * @param v1 Value checked for change.
17833 * @param suffix Static value used for concatenation only.
17834 * @codeGenApi
17835 */
17836function ɵɵstyleMapInterpolate2(prefix, v0, i0, v1, suffix) {
17837 const lView = getLView();
17838 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
17839 ɵɵstyleMap(interpolatedValue);
17840}
17841/**
17842 *
17843 * Update an interpolated style on an element with 3 bound values surrounded by text.
17844 *
17845 * Used when the value passed to a property has 3 interpolated values in it:
17846 *
17847 * ```html
17848 * <div style="key: {{v0}}; key2: {{v1}}; key2: {{v2}}suffix"></div>
17849 * ```
17850 *
17851 * Its compiled representation is:
17852 *
17853 * ```ts
17854 * ɵɵstyleMapInterpolate3(
17855 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, 'suffix');
17856 * ```
17857 *
17858 * @param prefix Static value used for concatenation only.
17859 * @param v0 Value checked for change.
17860 * @param i0 Static value used for concatenation only.
17861 * @param v1 Value checked for change.
17862 * @param i1 Static value used for concatenation only.
17863 * @param v2 Value checked for change.
17864 * @param suffix Static value used for concatenation only.
17865 * @codeGenApi
17866 */
17867function ɵɵstyleMapInterpolate3(prefix, v0, i0, v1, i1, v2, suffix) {
17868 const lView = getLView();
17869 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
17870 ɵɵstyleMap(interpolatedValue);
17871}
17872/**
17873 *
17874 * Update an interpolated style on an element with 4 bound values surrounded by text.
17875 *
17876 * Used when the value passed to a property has 4 interpolated values in it:
17877 *
17878 * ```html
17879 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}suffix"></div>
17880 * ```
17881 *
17882 * Its compiled representation is:
17883 *
17884 * ```ts
17885 * ɵɵstyleMapInterpolate4(
17886 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, 'suffix');
17887 * ```
17888 *
17889 * @param prefix Static value used for concatenation only.
17890 * @param v0 Value checked for change.
17891 * @param i0 Static value used for concatenation only.
17892 * @param v1 Value checked for change.
17893 * @param i1 Static value used for concatenation only.
17894 * @param v2 Value checked for change.
17895 * @param i2 Static value used for concatenation only.
17896 * @param v3 Value checked for change.
17897 * @param suffix Static value used for concatenation only.
17898 * @codeGenApi
17899 */
17900function ɵɵstyleMapInterpolate4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
17901 const lView = getLView();
17902 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
17903 ɵɵstyleMap(interpolatedValue);
17904}
17905/**
17906 *
17907 * Update an interpolated style on an element with 5 bound values surrounded by text.
17908 *
17909 * Used when the value passed to a property has 5 interpolated values in it:
17910 *
17911 * ```html
17912 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}suffix"></div>
17913 * ```
17914 *
17915 * Its compiled representation is:
17916 *
17917 * ```ts
17918 * ɵɵstyleMapInterpolate5(
17919 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, 'suffix');
17920 * ```
17921 *
17922 * @param prefix Static value used for concatenation only.
17923 * @param v0 Value checked for change.
17924 * @param i0 Static value used for concatenation only.
17925 * @param v1 Value checked for change.
17926 * @param i1 Static value used for concatenation only.
17927 * @param v2 Value checked for change.
17928 * @param i2 Static value used for concatenation only.
17929 * @param v3 Value checked for change.
17930 * @param i3 Static value used for concatenation only.
17931 * @param v4 Value checked for change.
17932 * @param suffix Static value used for concatenation only.
17933 * @codeGenApi
17934 */
17935function ɵɵstyleMapInterpolate5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
17936 const lView = getLView();
17937 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
17938 ɵɵstyleMap(interpolatedValue);
17939}
17940/**
17941 *
17942 * Update an interpolated style on an element with 6 bound values surrounded by text.
17943 *
17944 * Used when the value passed to a property has 6 interpolated values in it:
17945 *
17946 * ```html
17947 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}};
17948 * key5: {{v5}}suffix"></div>
17949 * ```
17950 *
17951 * Its compiled representation is:
17952 *
17953 * ```ts
17954 * ɵɵstyleMapInterpolate6(
17955 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
17956 * 'suffix');
17957 * ```
17958 *
17959 * @param prefix Static value used for concatenation only.
17960 * @param v0 Value checked for change.
17961 * @param i0 Static value used for concatenation only.
17962 * @param v1 Value checked for change.
17963 * @param i1 Static value used for concatenation only.
17964 * @param v2 Value checked for change.
17965 * @param i2 Static value used for concatenation only.
17966 * @param v3 Value checked for change.
17967 * @param i3 Static value used for concatenation only.
17968 * @param v4 Value checked for change.
17969 * @param i4 Static value used for concatenation only.
17970 * @param v5 Value checked for change.
17971 * @param suffix Static value used for concatenation only.
17972 * @codeGenApi
17973 */
17974function ɵɵstyleMapInterpolate6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
17975 const lView = getLView();
17976 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
17977 ɵɵstyleMap(interpolatedValue);
17978}
17979/**
17980 *
17981 * Update an interpolated style on an element with 7 bound values surrounded by text.
17982 *
17983 * Used when the value passed to a property has 7 interpolated values in it:
17984 *
17985 * ```html
17986 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}; key5: {{v5}};
17987 * key6: {{v6}}suffix"></div>
17988 * ```
17989 *
17990 * Its compiled representation is:
17991 *
17992 * ```ts
17993 * ɵɵstyleMapInterpolate7(
17994 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
17995 * '; key6: ', v6, 'suffix');
17996 * ```
17997 *
17998 * @param prefix Static value used for concatenation only.
17999 * @param v0 Value checked for change.
18000 * @param i0 Static value used for concatenation only.
18001 * @param v1 Value checked for change.
18002 * @param i1 Static value used for concatenation only.
18003 * @param v2 Value checked for change.
18004 * @param i2 Static value used for concatenation only.
18005 * @param v3 Value checked for change.
18006 * @param i3 Static value used for concatenation only.
18007 * @param v4 Value checked for change.
18008 * @param i4 Static value used for concatenation only.
18009 * @param v5 Value checked for change.
18010 * @param i5 Static value used for concatenation only.
18011 * @param v6 Value checked for change.
18012 * @param suffix Static value used for concatenation only.
18013 * @codeGenApi
18014 */
18015function ɵɵstyleMapInterpolate7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
18016 const lView = getLView();
18017 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
18018 ɵɵstyleMap(interpolatedValue);
18019}
18020/**
18021 *
18022 * Update an interpolated style on an element with 8 bound values surrounded by text.
18023 *
18024 * Used when the value passed to a property has 8 interpolated values in it:
18025 *
18026 * ```html
18027 * <div style="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}; key5: {{v5}};
18028 * key6: {{v6}}; key7: {{v7}}suffix"></div>
18029 * ```
18030 *
18031 * Its compiled representation is:
18032 *
18033 * ```ts
18034 * ɵɵstyleMapInterpolate8(
18035 * 'key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
18036 * '; key6: ', v6, '; key7: ', v7, 'suffix');
18037 * ```
18038 *
18039 * @param prefix Static value used for concatenation only.
18040 * @param v0 Value checked for change.
18041 * @param i0 Static value used for concatenation only.
18042 * @param v1 Value checked for change.
18043 * @param i1 Static value used for concatenation only.
18044 * @param v2 Value checked for change.
18045 * @param i2 Static value used for concatenation only.
18046 * @param v3 Value checked for change.
18047 * @param i3 Static value used for concatenation only.
18048 * @param v4 Value checked for change.
18049 * @param i4 Static value used for concatenation only.
18050 * @param v5 Value checked for change.
18051 * @param i5 Static value used for concatenation only.
18052 * @param v6 Value checked for change.
18053 * @param i6 Static value used for concatenation only.
18054 * @param v7 Value checked for change.
18055 * @param suffix Static value used for concatenation only.
18056 * @codeGenApi
18057 */
18058function ɵɵstyleMapInterpolate8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
18059 const lView = getLView();
18060 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
18061 ɵɵstyleMap(interpolatedValue);
18062}
18063/**
18064 * Update an interpolated style on an element with 9 or more bound values surrounded by text.
18065 *
18066 * Used when the number of interpolated values exceeds 8.
18067 *
18068 * ```html
18069 * <div
18070 * class="key: {{v0}}; key1: {{v1}}; key2: {{v2}}; key3: {{v3}}; key4: {{v4}}; key5: {{v5}};
18071 * key6: {{v6}}; key7: {{v7}}; key8: {{v8}}; key9: {{v9}}suffix"></div>
18072 * ```
18073 *
18074 * Its compiled representation is:
18075 *
18076 * ```ts
18077 * ɵɵstyleMapInterpolateV(
18078 * ['key: ', v0, '; key1: ', v1, '; key2: ', v2, '; key3: ', v3, '; key4: ', v4, '; key5: ', v5,
18079 * '; key6: ', v6, '; key7: ', v7, '; key8: ', v8, '; key9: ', v9, 'suffix']);
18080 * ```
18081 *.
18082 * @param values The collection of values and the strings in-between those values, beginning with
18083 * a string prefix and ending with a string suffix.
18084 * (e.g. `['prefix', value0, '; key2: ', value1, '; key2: ', value2, ..., value99, 'suffix']`)
18085 * @codeGenApi
18086 */
18087function ɵɵstyleMapInterpolateV(values) {
18088 const lView = getLView();
18089 const interpolatedValue = interpolationV(lView, values);
18090 ɵɵstyleMap(interpolatedValue);
18091}
18092
18093/**
18094 * @license
18095 * Copyright Google LLC All Rights Reserved.
18096 *
18097 * Use of this source code is governed by an MIT-style license that can be
18098 * found in the LICENSE file at https://angular.io/license
18099 */
18100/**
18101 *
18102 * Update an interpolated style property on an element with single bound value surrounded by text.
18103 *
18104 * Used when the value passed to a property has 1 interpolated value in it:
18105 *
18106 * ```html
18107 * <div style.color="prefix{{v0}}suffix"></div>
18108 * ```
18109 *
18110 * Its compiled representation is:
18111 *
18112 * ```ts
18113 * ɵɵstylePropInterpolate1(0, 'prefix', v0, 'suffix');
18114 * ```
18115 *
18116 * @param styleIndex Index of style to update. This index value refers to the
18117 * index of the style in the style bindings array that was passed into
18118 * `styling`.
18119 * @param prefix Static value used for concatenation only.
18120 * @param v0 Value checked for change.
18121 * @param suffix Static value used for concatenation only.
18122 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18123 * @returns itself, so that it may be chained.
18124 * @codeGenApi
18125 */
18126function ɵɵstylePropInterpolate1(prop, prefix, v0, suffix, valueSuffix) {
18127 const lView = getLView();
18128 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
18129 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18130 return ɵɵstylePropInterpolate1;
18131}
18132/**
18133 *
18134 * Update an interpolated style property on an element with 2 bound values surrounded by text.
18135 *
18136 * Used when the value passed to a property has 2 interpolated values in it:
18137 *
18138 * ```html
18139 * <div style.color="prefix{{v0}}-{{v1}}suffix"></div>
18140 * ```
18141 *
18142 * Its compiled representation is:
18143 *
18144 * ```ts
18145 * ɵɵstylePropInterpolate2(0, 'prefix', v0, '-', v1, 'suffix');
18146 * ```
18147 *
18148 * @param styleIndex Index of style to update. This index value refers to the
18149 * index of the style in the style bindings array that was passed into
18150 * `styling`.
18151 * @param prefix Static value used for concatenation only.
18152 * @param v0 Value checked for change.
18153 * @param i0 Static value used for concatenation only.
18154 * @param v1 Value checked for change.
18155 * @param suffix Static value used for concatenation only.
18156 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18157 * @returns itself, so that it may be chained.
18158 * @codeGenApi
18159 */
18160function ɵɵstylePropInterpolate2(prop, prefix, v0, i0, v1, suffix, valueSuffix) {
18161 const lView = getLView();
18162 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
18163 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18164 return ɵɵstylePropInterpolate2;
18165}
18166/**
18167 *
18168 * Update an interpolated style property on an element with 3 bound values surrounded by text.
18169 *
18170 * Used when the value passed to a property has 3 interpolated values in it:
18171 *
18172 * ```html
18173 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
18174 * ```
18175 *
18176 * Its compiled representation is:
18177 *
18178 * ```ts
18179 * ɵɵstylePropInterpolate3(0, 'prefix', v0, '-', v1, '-', v2, 'suffix');
18180 * ```
18181 *
18182 * @param styleIndex Index of style to update. This index value refers to the
18183 * index of the style in the style bindings array that was passed into
18184 * `styling`.
18185 * @param prefix Static value used for concatenation only.
18186 * @param v0 Value checked for change.
18187 * @param i0 Static value used for concatenation only.
18188 * @param v1 Value checked for change.
18189 * @param i1 Static value used for concatenation only.
18190 * @param v2 Value checked for change.
18191 * @param suffix Static value used for concatenation only.
18192 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18193 * @returns itself, so that it may be chained.
18194 * @codeGenApi
18195 */
18196function ɵɵstylePropInterpolate3(prop, prefix, v0, i0, v1, i1, v2, suffix, valueSuffix) {
18197 const lView = getLView();
18198 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
18199 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18200 return ɵɵstylePropInterpolate3;
18201}
18202/**
18203 *
18204 * Update an interpolated style property on an element with 4 bound values surrounded by text.
18205 *
18206 * Used when the value passed to a property has 4 interpolated values in it:
18207 *
18208 * ```html
18209 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
18210 * ```
18211 *
18212 * Its compiled representation is:
18213 *
18214 * ```ts
18215 * ɵɵstylePropInterpolate4(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
18216 * ```
18217 *
18218 * @param styleIndex Index of style to update. This index value refers to the
18219 * index of the style in the style bindings array that was passed into
18220 * `styling`.
18221 * @param prefix Static value used for concatenation only.
18222 * @param v0 Value checked for change.
18223 * @param i0 Static value used for concatenation only.
18224 * @param v1 Value checked for change.
18225 * @param i1 Static value used for concatenation only.
18226 * @param v2 Value checked for change.
18227 * @param i2 Static value used for concatenation only.
18228 * @param v3 Value checked for change.
18229 * @param suffix Static value used for concatenation only.
18230 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18231 * @returns itself, so that it may be chained.
18232 * @codeGenApi
18233 */
18234function ɵɵstylePropInterpolate4(prop, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, valueSuffix) {
18235 const lView = getLView();
18236 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
18237 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18238 return ɵɵstylePropInterpolate4;
18239}
18240/**
18241 *
18242 * Update an interpolated style property on an element with 5 bound values surrounded by text.
18243 *
18244 * Used when the value passed to a property has 5 interpolated values in it:
18245 *
18246 * ```html
18247 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
18248 * ```
18249 *
18250 * Its compiled representation is:
18251 *
18252 * ```ts
18253 * ɵɵstylePropInterpolate5(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
18254 * ```
18255 *
18256 * @param styleIndex Index of style to update. This index value refers to the
18257 * index of the style in the style bindings array that was passed into
18258 * `styling`.
18259 * @param prefix Static value used for concatenation only.
18260 * @param v0 Value checked for change.
18261 * @param i0 Static value used for concatenation only.
18262 * @param v1 Value checked for change.
18263 * @param i1 Static value used for concatenation only.
18264 * @param v2 Value checked for change.
18265 * @param i2 Static value used for concatenation only.
18266 * @param v3 Value checked for change.
18267 * @param i3 Static value used for concatenation only.
18268 * @param v4 Value checked for change.
18269 * @param suffix Static value used for concatenation only.
18270 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18271 * @returns itself, so that it may be chained.
18272 * @codeGenApi
18273 */
18274function ɵɵstylePropInterpolate5(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, valueSuffix) {
18275 const lView = getLView();
18276 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
18277 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18278 return ɵɵstylePropInterpolate5;
18279}
18280/**
18281 *
18282 * Update an interpolated style property on an element with 6 bound values surrounded by text.
18283 *
18284 * Used when the value passed to a property has 6 interpolated values in it:
18285 *
18286 * ```html
18287 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
18288 * ```
18289 *
18290 * Its compiled representation is:
18291 *
18292 * ```ts
18293 * ɵɵstylePropInterpolate6(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
18294 * ```
18295 *
18296 * @param styleIndex Index of style to update. This index value refers to the
18297 * index of the style in the style bindings array that was passed into
18298 * `styling`.
18299 * @param prefix Static value used for concatenation only.
18300 * @param v0 Value checked for change.
18301 * @param i0 Static value used for concatenation only.
18302 * @param v1 Value checked for change.
18303 * @param i1 Static value used for concatenation only.
18304 * @param v2 Value checked for change.
18305 * @param i2 Static value used for concatenation only.
18306 * @param v3 Value checked for change.
18307 * @param i3 Static value used for concatenation only.
18308 * @param v4 Value checked for change.
18309 * @param i4 Static value used for concatenation only.
18310 * @param v5 Value checked for change.
18311 * @param suffix Static value used for concatenation only.
18312 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18313 * @returns itself, so that it may be chained.
18314 * @codeGenApi
18315 */
18316function ɵɵstylePropInterpolate6(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, valueSuffix) {
18317 const lView = getLView();
18318 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
18319 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18320 return ɵɵstylePropInterpolate6;
18321}
18322/**
18323 *
18324 * Update an interpolated style property on an element with 7 bound values surrounded by text.
18325 *
18326 * Used when the value passed to a property has 7 interpolated values in it:
18327 *
18328 * ```html
18329 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
18330 * ```
18331 *
18332 * Its compiled representation is:
18333 *
18334 * ```ts
18335 * ɵɵstylePropInterpolate7(
18336 * 0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
18337 * ```
18338 *
18339 * @param styleIndex Index of style to update. This index value refers to the
18340 * index of the style in the style bindings array that was passed into
18341 * `styling`.
18342 * @param prefix Static value used for concatenation only.
18343 * @param v0 Value checked for change.
18344 * @param i0 Static value used for concatenation only.
18345 * @param v1 Value checked for change.
18346 * @param i1 Static value used for concatenation only.
18347 * @param v2 Value checked for change.
18348 * @param i2 Static value used for concatenation only.
18349 * @param v3 Value checked for change.
18350 * @param i3 Static value used for concatenation only.
18351 * @param v4 Value checked for change.
18352 * @param i4 Static value used for concatenation only.
18353 * @param v5 Value checked for change.
18354 * @param i5 Static value used for concatenation only.
18355 * @param v6 Value checked for change.
18356 * @param suffix Static value used for concatenation only.
18357 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18358 * @returns itself, so that it may be chained.
18359 * @codeGenApi
18360 */
18361function ɵɵstylePropInterpolate7(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, valueSuffix) {
18362 const lView = getLView();
18363 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
18364 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18365 return ɵɵstylePropInterpolate7;
18366}
18367/**
18368 *
18369 * Update an interpolated style property on an element with 8 bound values surrounded by text.
18370 *
18371 * Used when the value passed to a property has 8 interpolated values in it:
18372 *
18373 * ```html
18374 * <div style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
18375 * ```
18376 *
18377 * Its compiled representation is:
18378 *
18379 * ```ts
18380 * ɵɵstylePropInterpolate8(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6,
18381 * '-', v7, 'suffix');
18382 * ```
18383 *
18384 * @param styleIndex Index of style to update. This index value refers to the
18385 * index of the style in the style bindings array that was passed into
18386 * `styling`.
18387 * @param prefix Static value used for concatenation only.
18388 * @param v0 Value checked for change.
18389 * @param i0 Static value used for concatenation only.
18390 * @param v1 Value checked for change.
18391 * @param i1 Static value used for concatenation only.
18392 * @param v2 Value checked for change.
18393 * @param i2 Static value used for concatenation only.
18394 * @param v3 Value checked for change.
18395 * @param i3 Static value used for concatenation only.
18396 * @param v4 Value checked for change.
18397 * @param i4 Static value used for concatenation only.
18398 * @param v5 Value checked for change.
18399 * @param i5 Static value used for concatenation only.
18400 * @param v6 Value checked for change.
18401 * @param i6 Static value used for concatenation only.
18402 * @param v7 Value checked for change.
18403 * @param suffix Static value used for concatenation only.
18404 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18405 * @returns itself, so that it may be chained.
18406 * @codeGenApi
18407 */
18408function ɵɵstylePropInterpolate8(prop, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, valueSuffix) {
18409 const lView = getLView();
18410 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
18411 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18412 return ɵɵstylePropInterpolate8;
18413}
18414/**
18415 * Update an interpolated style property on an element with 9 or more bound values surrounded by
18416 * text.
18417 *
18418 * Used when the number of interpolated values exceeds 8.
18419 *
18420 * ```html
18421 * <div
18422 * style.color="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix">
18423 * </div>
18424 * ```
18425 *
18426 * Its compiled representation is:
18427 *
18428 * ```ts
18429 * ɵɵstylePropInterpolateV(
18430 * 0, ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
18431 * 'suffix']);
18432 * ```
18433 *
18434 * @param styleIndex Index of style to update. This index value refers to the
18435 * index of the style in the style bindings array that was passed into
18436 * `styling`..
18437 * @param values The collection of values and the strings in-between those values, beginning with
18438 * a string prefix and ending with a string suffix.
18439 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
18440 * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
18441 * @returns itself, so that it may be chained.
18442 * @codeGenApi
18443 */
18444function ɵɵstylePropInterpolateV(prop, values, valueSuffix) {
18445 const lView = getLView();
18446 const interpolatedValue = interpolationV(lView, values);
18447 checkStylingProperty(prop, interpolatedValue, valueSuffix, false);
18448 return ɵɵstylePropInterpolateV;
18449}
18450
18451/**
18452 * @license
18453 * Copyright Google LLC All Rights Reserved.
18454 *
18455 * Use of this source code is governed by an MIT-style license that can be
18456 * found in the LICENSE file at https://angular.io/license
18457 */
18458/**
18459 * Update a property on a host element. Only applies to native node properties, not inputs.
18460 *
18461 * Operates on the element selected by index via the {@link select} instruction.
18462 *
18463 * @param propName Name of property. Because it is going to DOM, this is not subject to
18464 * renaming as part of minification.
18465 * @param value New value to write.
18466 * @param sanitizer An optional function used to sanitize the value.
18467 * @returns This function returns itself so that it may be chained
18468 * (e.g. `property('name', ctx.name)('title', ctx.title)`)
18469 *
18470 * @codeGenApi
18471 */
18472function ɵɵhostProperty(propName, value, sanitizer) {
18473 const lView = getLView();
18474 const bindingIndex = nextBindingIndex();
18475 if (bindingUpdated(lView, bindingIndex, value)) {
18476 const tView = getTView();
18477 const tNode = getSelectedTNode();
18478 elementPropertyInternal(tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, true);
18479 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
18480 }
18481 return ɵɵhostProperty;
18482}
18483/**
18484 * Updates a synthetic host binding (e.g. `[@foo]`) on a component or directive.
18485 *
18486 * This instruction is for compatibility purposes and is designed to ensure that a
18487 * synthetic host binding (e.g. `@HostBinding('@foo')`) properly gets rendered in
18488 * the component's renderer. Normally all host bindings are evaluated with the parent
18489 * component's renderer, but, in the case of animation @triggers, they need to be
18490 * evaluated with the sub component's renderer (because that's where the animation
18491 * triggers are defined).
18492 *
18493 * Do not use this instruction as a replacement for `elementProperty`. This instruction
18494 * only exists to ensure compatibility with the ViewEngine's host binding behavior.
18495 *
18496 * @param index The index of the element to update in the data array
18497 * @param propName Name of property. Because it is going to DOM, this is not subject to
18498 * renaming as part of minification.
18499 * @param value New value to write.
18500 * @param sanitizer An optional function used to sanitize the value.
18501 *
18502 * @codeGenApi
18503 */
18504function ɵɵsyntheticHostProperty(propName, value, sanitizer) {
18505 const lView = getLView();
18506 const bindingIndex = nextBindingIndex();
18507 if (bindingUpdated(lView, bindingIndex, value)) {
18508 const tView = getTView();
18509 const tNode = getSelectedTNode();
18510 const currentDef = getCurrentDirectiveDef(tView.data);
18511 const renderer = loadComponentRenderer(currentDef, tNode, lView);
18512 elementPropertyInternal(tView, tNode, lView, propName, value, renderer, sanitizer, true);
18513 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
18514 }
18515 return ɵɵsyntheticHostProperty;
18516}
18517
18518/**
18519 * @license
18520 * Copyright Google LLC All Rights Reserved.
18521 *
18522 * Use of this source code is governed by an MIT-style license that can be
18523 * found in the LICENSE file at https://angular.io/license
18524 */
18525/**
18526 * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
18527 */
18528if (typeof ngI18nClosureMode === 'undefined') {
18529 // These property accesses can be ignored because ngI18nClosureMode will be set to false
18530 // when optimizing code and the whole if statement will be dropped.
18531 // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
18532 // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
18533 (function () {
18534 // tslint:disable-next-line:no-toplevel-property-access
18535 _global['ngI18nClosureMode'] =
18536 // TODO(FW-1250): validate that this actually, you know, works.
18537 // tslint:disable-next-line:no-toplevel-property-access
18538 typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
18539 })();
18540}
18541
18542/**
18543 * @license
18544 * Copyright Google LLC All Rights Reserved.
18545 *
18546 * Use of this source code is governed by an MIT-style license that can be
18547 * found in the LICENSE file at https://angular.io/license
18548 */
18549// THIS CODE IS GENERATED - DO NOT MODIFY.
18550const u = undefined;
18551function plural(val) {
18552 const n = val, i = Math.floor(Math.abs(val)), v = val.toString().replace(/^[^.]*\.?/, '').length;
18553 if (i === 1 && v === 0)
18554 return 1;
18555 return 5;
18556}
18557var 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];
18558
18559/**
18560 * @license
18561 * Copyright Google LLC All Rights Reserved.
18562 *
18563 * Use of this source code is governed by an MIT-style license that can be
18564 * found in the LICENSE file at https://angular.io/license
18565 */
18566/**
18567 * This const is used to store the locale data registered with `registerLocaleData`
18568 */
18569let LOCALE_DATA = {};
18570/**
18571 * Register locale data to be used internally by Angular. See the
18572 * ["I18n guide"](guide/i18n-common-format-data-locale) to know how to import additional locale
18573 * data.
18574 *
18575 * The signature `registerLocaleData(data: any, extraData?: any)` is deprecated since v5.1
18576 */
18577function registerLocaleData(data, localeId, extraData) {
18578 if (typeof localeId !== 'string') {
18579 extraData = localeId;
18580 localeId = data[LocaleDataIndex.LocaleId];
18581 }
18582 localeId = localeId.toLowerCase().replace(/_/g, '-');
18583 LOCALE_DATA[localeId] = data;
18584 if (extraData) {
18585 LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData;
18586 }
18587}
18588/**
18589 * Finds the locale data for a given locale.
18590 *
18591 * @param locale The locale code.
18592 * @returns The locale data.
18593 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
18594 */
18595function findLocaleData(locale) {
18596 const normalizedLocale = normalizeLocale(locale);
18597 let match = getLocaleData(normalizedLocale);
18598 if (match) {
18599 return match;
18600 }
18601 // let's try to find a parent locale
18602 const parentLocale = normalizedLocale.split('-')[0];
18603 match = getLocaleData(parentLocale);
18604 if (match) {
18605 return match;
18606 }
18607 if (parentLocale === 'en') {
18608 return localeEn;
18609 }
18610 throw new Error(`Missing locale data for the locale "${locale}".`);
18611}
18612/**
18613 * Retrieves the default currency code for the given locale.
18614 *
18615 * The default is defined as the first currency which is still in use.
18616 *
18617 * @param locale The code of the locale whose currency code we want.
18618 * @returns The code of the default currency for the given locale.
18619 *
18620 */
18621function getLocaleCurrencyCode(locale) {
18622 const data = findLocaleData(locale);
18623 return data[LocaleDataIndex.CurrencyCode] || null;
18624}
18625/**
18626 * Retrieves the plural function used by ICU expressions to determine the plural case to use
18627 * for a given locale.
18628 * @param locale A locale code for the locale format rules to use.
18629 * @returns The plural function for the locale.
18630 * @see `NgPlural`
18631 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
18632 */
18633function getLocalePluralCase(locale) {
18634 const data = findLocaleData(locale);
18635 return data[LocaleDataIndex.PluralCase];
18636}
18637/**
18638 * Helper function to get the given `normalizedLocale` from `LOCALE_DATA`
18639 * or from the global `ng.common.locale`.
18640 */
18641function getLocaleData(normalizedLocale) {
18642 if (!(normalizedLocale in LOCALE_DATA)) {
18643 LOCALE_DATA[normalizedLocale] = _global.ng && _global.ng.common && _global.ng.common.locales &&
18644 _global.ng.common.locales[normalizedLocale];
18645 }
18646 return LOCALE_DATA[normalizedLocale];
18647}
18648/**
18649 * Helper function to remove all the locale data from `LOCALE_DATA`.
18650 */
18651function unregisterAllLocaleData() {
18652 LOCALE_DATA = {};
18653}
18654/**
18655 * Index of each type of locale data from the locale data array
18656 */
18657var LocaleDataIndex;
18658(function (LocaleDataIndex) {
18659 LocaleDataIndex[LocaleDataIndex["LocaleId"] = 0] = "LocaleId";
18660 LocaleDataIndex[LocaleDataIndex["DayPeriodsFormat"] = 1] = "DayPeriodsFormat";
18661 LocaleDataIndex[LocaleDataIndex["DayPeriodsStandalone"] = 2] = "DayPeriodsStandalone";
18662 LocaleDataIndex[LocaleDataIndex["DaysFormat"] = 3] = "DaysFormat";
18663 LocaleDataIndex[LocaleDataIndex["DaysStandalone"] = 4] = "DaysStandalone";
18664 LocaleDataIndex[LocaleDataIndex["MonthsFormat"] = 5] = "MonthsFormat";
18665 LocaleDataIndex[LocaleDataIndex["MonthsStandalone"] = 6] = "MonthsStandalone";
18666 LocaleDataIndex[LocaleDataIndex["Eras"] = 7] = "Eras";
18667 LocaleDataIndex[LocaleDataIndex["FirstDayOfWeek"] = 8] = "FirstDayOfWeek";
18668 LocaleDataIndex[LocaleDataIndex["WeekendRange"] = 9] = "WeekendRange";
18669 LocaleDataIndex[LocaleDataIndex["DateFormat"] = 10] = "DateFormat";
18670 LocaleDataIndex[LocaleDataIndex["TimeFormat"] = 11] = "TimeFormat";
18671 LocaleDataIndex[LocaleDataIndex["DateTimeFormat"] = 12] = "DateTimeFormat";
18672 LocaleDataIndex[LocaleDataIndex["NumberSymbols"] = 13] = "NumberSymbols";
18673 LocaleDataIndex[LocaleDataIndex["NumberFormats"] = 14] = "NumberFormats";
18674 LocaleDataIndex[LocaleDataIndex["CurrencyCode"] = 15] = "CurrencyCode";
18675 LocaleDataIndex[LocaleDataIndex["CurrencySymbol"] = 16] = "CurrencySymbol";
18676 LocaleDataIndex[LocaleDataIndex["CurrencyName"] = 17] = "CurrencyName";
18677 LocaleDataIndex[LocaleDataIndex["Currencies"] = 18] = "Currencies";
18678 LocaleDataIndex[LocaleDataIndex["Directionality"] = 19] = "Directionality";
18679 LocaleDataIndex[LocaleDataIndex["PluralCase"] = 20] = "PluralCase";
18680 LocaleDataIndex[LocaleDataIndex["ExtraData"] = 21] = "ExtraData";
18681})(LocaleDataIndex || (LocaleDataIndex = {}));
18682/**
18683 * Returns the canonical form of a locale name - lowercase with `_` replaced with `-`.
18684 */
18685function normalizeLocale(locale) {
18686 return locale.toLowerCase().replace(/_/g, '-');
18687}
18688
18689/**
18690 * @license
18691 * Copyright Google LLC All Rights Reserved.
18692 *
18693 * Use of this source code is governed by an MIT-style license that can be
18694 * found in the LICENSE file at https://angular.io/license
18695 */
18696const pluralMapping = ['zero', 'one', 'two', 'few', 'many'];
18697/**
18698 * Returns the plural case based on the locale
18699 */
18700function getPluralCase(value, locale) {
18701 const plural = getLocalePluralCase(locale)(parseInt(value, 10));
18702 const result = pluralMapping[plural];
18703 return (result !== undefined) ? result : 'other';
18704}
18705/**
18706 * The locale id that the application is using by default (for translations and ICU expressions).
18707 */
18708const DEFAULT_LOCALE_ID = 'en-US';
18709/**
18710 * USD currency code that the application uses by default for CurrencyPipe when no
18711 * DEFAULT_CURRENCY_CODE is provided.
18712 */
18713const USD_CURRENCY_CODE = 'USD';
18714
18715/**
18716 * @license
18717 * Copyright Google LLC All Rights Reserved.
18718 *
18719 * Use of this source code is governed by an MIT-style license that can be
18720 * found in the LICENSE file at https://angular.io/license
18721 */
18722/**
18723 * Marks that the next string is an element name.
18724 *
18725 * See `I18nMutateOpCodes` documentation.
18726 */
18727const ELEMENT_MARKER = {
18728 marker: 'element'
18729};
18730/**
18731 * Marks that the next string is comment text need for ICU.
18732 *
18733 * See `I18nMutateOpCodes` documentation.
18734 */
18735const ICU_MARKER = {
18736 marker: 'ICU'
18737};
18738/**
18739 * See `I18nCreateOpCodes`
18740 */
18741var I18nCreateOpCode;
18742(function (I18nCreateOpCode) {
18743 /**
18744 * Number of bits to shift index so that it can be combined with the `APPEND_EAGERLY` and
18745 * `COMMENT`.
18746 */
18747 I18nCreateOpCode[I18nCreateOpCode["SHIFT"] = 2] = "SHIFT";
18748 /**
18749 * Should the node be appended to parent imedditatly after creation.
18750 */
18751 I18nCreateOpCode[I18nCreateOpCode["APPEND_EAGERLY"] = 1] = "APPEND_EAGERLY";
18752 /**
18753 * If set the node should be comment (rather than a text) node.
18754 */
18755 I18nCreateOpCode[I18nCreateOpCode["COMMENT"] = 2] = "COMMENT";
18756})(I18nCreateOpCode || (I18nCreateOpCode = {}));
18757// Note: This hack is necessary so we don't erroneously get a circular dependency
18758// failure based on types.
18759const unusedValueExportToPlacateAjd$2 = 1;
18760
18761/**
18762 * @license
18763 * Copyright Google LLC All Rights Reserved.
18764 *
18765 * Use of this source code is governed by an MIT-style license that can be
18766 * found in the LICENSE file at https://angular.io/license
18767 */
18768/**
18769 * The locale id that the application is currently using (for translations and ICU expressions).
18770 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
18771 * but is now defined as a global value.
18772 */
18773let LOCALE_ID$1 = DEFAULT_LOCALE_ID;
18774/**
18775 * Sets the locale id that will be used for translations and ICU expressions.
18776 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
18777 * but is now defined as a global value.
18778 *
18779 * @param localeId
18780 */
18781function setLocaleId(localeId) {
18782 assertDefined(localeId, `Expected localeId to be defined`);
18783 if (typeof localeId === 'string') {
18784 LOCALE_ID$1 = localeId.toLowerCase().replace(/_/g, '-');
18785 }
18786}
18787/**
18788 * Gets the locale id that will be used for translations and ICU expressions.
18789 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
18790 * but is now defined as a global value.
18791 */
18792function getLocaleId() {
18793 return LOCALE_ID$1;
18794}
18795
18796/**
18797 * @license
18798 * Copyright Google LLC All Rights Reserved.
18799 *
18800 * Use of this source code is governed by an MIT-style license that can be
18801 * found in the LICENSE file at https://angular.io/license
18802 */
18803/**
18804 * Find a node in front of which `currentTNode` should be inserted (takes i18n into account).
18805 *
18806 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
18807 * takes `TNode.insertBeforeIndex` into account.
18808 *
18809 * @param parentTNode parent `TNode`
18810 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
18811 * @param lView current `LView`
18812 */
18813function getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView) {
18814 const tNodeInsertBeforeIndex = currentTNode.insertBeforeIndex;
18815 const insertBeforeIndex = Array.isArray(tNodeInsertBeforeIndex) ? tNodeInsertBeforeIndex[0] : tNodeInsertBeforeIndex;
18816 if (insertBeforeIndex === null) {
18817 return getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView);
18818 }
18819 else {
18820 ngDevMode && assertIndexInRange(lView, insertBeforeIndex);
18821 return unwrapRNode(lView[insertBeforeIndex]);
18822 }
18823}
18824/**
18825 * Process `TNode.insertBeforeIndex` by adding i18n text nodes.
18826 *
18827 * See `TNode.insertBeforeIndex`
18828 */
18829function processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRElement) {
18830 const tNodeInsertBeforeIndex = childTNode.insertBeforeIndex;
18831 if (Array.isArray(tNodeInsertBeforeIndex)) {
18832 // An array indicates that there are i18n nodes that need to be added as children of this
18833 // `childRNode`. These i18n nodes were created before this `childRNode` was available and so
18834 // only now can be added. The first element of the array is the normal index where we should
18835 // insert the `childRNode`. Additional elements are the extra nodes to be added as children of
18836 // `childRNode`.
18837 ngDevMode && assertDomNode(childRNode);
18838 let i18nParent = childRNode;
18839 let anchorRNode = null;
18840 if (!(childTNode.type & 3 /* AnyRNode */)) {
18841 anchorRNode = i18nParent;
18842 i18nParent = parentRElement;
18843 }
18844 if (i18nParent !== null && (childTNode.flags & 2 /* isComponentHost */) === 0) {
18845 for (let i = 1; i < tNodeInsertBeforeIndex.length; i++) {
18846 // No need to `unwrapRNode` because all of the indexes point to i18n text nodes.
18847 // see `assertDomNode` below.
18848 const i18nChild = lView[tNodeInsertBeforeIndex[i]];
18849 nativeInsertBefore(renderer, i18nParent, i18nChild, anchorRNode, false);
18850 }
18851 }
18852 }
18853}
18854
18855/**
18856 * @license
18857 * Copyright Google LLC All Rights Reserved.
18858 *
18859 * Use of this source code is governed by an MIT-style license that can be
18860 * found in the LICENSE file at https://angular.io/license
18861 */
18862/**
18863 * Add `tNode` to `previousTNodes` list and update relevant `TNode`s in `previousTNodes` list
18864 * `tNode.insertBeforeIndex`.
18865 *
18866 * Things to keep in mind:
18867 * 1. All i18n text nodes are encoded as `TNodeType.Element` and are created eagerly by the
18868 * `ɵɵi18nStart` instruction.
18869 * 2. All `TNodeType.Placeholder` `TNodes` are elements which will be created later by
18870 * `ɵɵelementStart` instruction.
18871 * 3. `ɵɵelementStart` instruction will create `TNode`s in the ascending `TNode.index` order. (So a
18872 * smaller index `TNode` is guaranteed to be created before a larger one)
18873 *
18874 * We use the above three invariants to determine `TNode.insertBeforeIndex`.
18875 *
18876 * In an ideal world `TNode.insertBeforeIndex` would always be `TNode.next.index`. However,
18877 * this will not work because `TNode.next.index` may be larger than `TNode.index` which means that
18878 * the next node is not yet created and therefore we can't insert in front of it.
18879 *
18880 * Rule1: `TNode.insertBeforeIndex = null` if `TNode.next === null` (Initial condition, as we don't
18881 * know if there will be further `TNode`s inserted after.)
18882 * Rule2: If `previousTNode` is created after the `tNode` being inserted, then
18883 * `previousTNode.insertBeforeNode = tNode.index` (So when a new `tNode` is added we check
18884 * previous to see if we can update its `insertBeforeTNode`)
18885 *
18886 * See `TNode.insertBeforeIndex` for more context.
18887 *
18888 * @param previousTNodes A list of previous TNodes so that we can easily traverse `TNode`s in
18889 * reverse order. (If `TNode` would have `previous` this would not be necessary.)
18890 * @param newTNode A TNode to add to the `previousTNodes` list.
18891 */
18892function addTNodeAndUpdateInsertBeforeIndex(previousTNodes, newTNode) {
18893 // Start with Rule1
18894 ngDevMode &&
18895 assertEqual(newTNode.insertBeforeIndex, null, 'We expect that insertBeforeIndex is not set');
18896 previousTNodes.push(newTNode);
18897 if (previousTNodes.length > 1) {
18898 for (let i = previousTNodes.length - 2; i >= 0; i--) {
18899 const existingTNode = previousTNodes[i];
18900 // Text nodes are created eagerly and so they don't need their `indexBeforeIndex` updated.
18901 // It is safe to ignore them.
18902 if (!isI18nText(existingTNode)) {
18903 if (isNewTNodeCreatedBefore(existingTNode, newTNode) &&
18904 getInsertBeforeIndex(existingTNode) === null) {
18905 // If it was created before us in time, (and it does not yet have `insertBeforeIndex`)
18906 // then add the `insertBeforeIndex`.
18907 setInsertBeforeIndex(existingTNode, newTNode.index);
18908 }
18909 }
18910 }
18911 }
18912}
18913function isI18nText(tNode) {
18914 return !(tNode.type & 64 /* Placeholder */);
18915}
18916function isNewTNodeCreatedBefore(existingTNode, newTNode) {
18917 return isI18nText(newTNode) || existingTNode.index > newTNode.index;
18918}
18919function getInsertBeforeIndex(tNode) {
18920 const index = tNode.insertBeforeIndex;
18921 return Array.isArray(index) ? index[0] : index;
18922}
18923function setInsertBeforeIndex(tNode, value) {
18924 const index = tNode.insertBeforeIndex;
18925 if (Array.isArray(index)) {
18926 // Array is stored if we have to insert child nodes. See `TNode.insertBeforeIndex`
18927 index[0] = value;
18928 }
18929 else {
18930 setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
18931 tNode.insertBeforeIndex = value;
18932 }
18933}
18934
18935/**
18936 * @license
18937 * Copyright Google LLC All Rights Reserved.
18938 *
18939 * Use of this source code is governed by an MIT-style license that can be
18940 * found in the LICENSE file at https://angular.io/license
18941 */
18942/**
18943 * Retrieve `TIcu` at a given `index`.
18944 *
18945 * The `TIcu` can be stored either directly (if it is nested ICU) OR
18946 * it is stored inside tho `TIcuContainer` if it is top level ICU.
18947 *
18948 * The reason for this is that the top level ICU need a `TNode` so that they are part of the render
18949 * tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
18950 * expressed (parent ICU may have selected a case which does not contain it.)
18951 *
18952 * @param tView Current `TView`.
18953 * @param index Index where the value should be read from.
18954 */
18955function getTIcu(tView, index) {
18956 const value = tView.data[index];
18957 if (value === null || typeof value === 'string')
18958 return null;
18959 if (ngDevMode &&
18960 !(value.hasOwnProperty('tViews') || value.hasOwnProperty('currentCaseLViewIndex'))) {
18961 throwError('We expect to get \'null\'|\'TIcu\'|\'TIcuContainer\', but got: ' + value);
18962 }
18963 // Here the `value.hasOwnProperty('currentCaseLViewIndex')` is a polymorphic read as it can be
18964 // either TIcu or TIcuContainerNode. This is not ideal, but we still think it is OK because it
18965 // will be just two cases which fits into the browser inline cache (inline cache can take up to
18966 // 4)
18967 const tIcu = value.hasOwnProperty('currentCaseLViewIndex') ? value :
18968 value.value;
18969 ngDevMode && assertTIcu(tIcu);
18970 return tIcu;
18971}
18972/**
18973 * Store `TIcu` at a give `index`.
18974 *
18975 * The `TIcu` can be stored either directly (if it is nested ICU) OR
18976 * it is stored inside tho `TIcuContainer` if it is top level ICU.
18977 *
18978 * The reason for this is that the top level ICU need a `TNode` so that they are part of the render
18979 * tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
18980 * expressed (parent ICU may have selected a case which does not contain it.)
18981 *
18982 * @param tView Current `TView`.
18983 * @param index Index where the value should be stored at in `Tview.data`
18984 * @param tIcu The TIcu to store.
18985 */
18986function setTIcu(tView, index, tIcu) {
18987 const tNode = tView.data[index];
18988 ngDevMode &&
18989 assertEqual(tNode === null || tNode.hasOwnProperty('tViews'), true, 'We expect to get \'null\'|\'TIcuContainer\'');
18990 if (tNode === null) {
18991 tView.data[index] = tIcu;
18992 }
18993 else {
18994 ngDevMode && assertTNodeType(tNode, 32 /* Icu */);
18995 tNode.value = tIcu;
18996 }
18997}
18998/**
18999 * Set `TNode.insertBeforeIndex` taking the `Array` into account.
19000 *
19001 * See `TNode.insertBeforeIndex`
19002 */
19003function setTNodeInsertBeforeIndex(tNode, index) {
19004 ngDevMode && assertTNode(tNode);
19005 let insertBeforeIndex = tNode.insertBeforeIndex;
19006 if (insertBeforeIndex === null) {
19007 setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
19008 insertBeforeIndex = tNode.insertBeforeIndex =
19009 [null /* may be updated to number later */, index];
19010 }
19011 else {
19012 assertEqual(Array.isArray(insertBeforeIndex), true, 'Expecting array here');
19013 insertBeforeIndex.push(index);
19014 }
19015}
19016/**
19017 * Create `TNode.type=TNodeType.Placeholder` node.
19018 *
19019 * See `TNodeType.Placeholder` for more information.
19020 */
19021function createTNodePlaceholder(tView, previousTNodes, index) {
19022 const tNode = createTNodeAtIndex(tView, index, 64 /* Placeholder */, null, null);
19023 addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tNode);
19024 return tNode;
19025}
19026/**
19027 * Returns current ICU case.
19028 *
19029 * ICU cases are stored as index into the `TIcu.cases`.
19030 * At times it is necessary to communicate that the ICU case just switched and that next ICU update
19031 * should update all bindings regardless of the mask. In such a case the we store negative numbers
19032 * for cases which have just been switched. This function removes the negative flag.
19033 */
19034function getCurrentICUCaseIndex(tIcu, lView) {
19035 const currentCase = lView[tIcu.currentCaseLViewIndex];
19036 return currentCase === null ? currentCase : (currentCase < 0 ? ~currentCase : currentCase);
19037}
19038function getParentFromIcuCreateOpCode(mergedCode) {
19039 return mergedCode >>> 17 /* SHIFT_PARENT */;
19040}
19041function getRefFromIcuCreateOpCode(mergedCode) {
19042 return (mergedCode & 131070 /* MASK_REF */) >>> 1 /* SHIFT_REF */;
19043}
19044function getInstructionFromIcuCreateOpCode(mergedCode) {
19045 return mergedCode & 1 /* MASK_INSTRUCTION */;
19046}
19047function icuCreateOpCode(opCode, parentIdx, refIdx) {
19048 ngDevMode && assertGreaterThanOrEqual(parentIdx, 0, 'Missing parent index');
19049 ngDevMode && assertGreaterThan(refIdx, 0, 'Missing ref index');
19050 return opCode | parentIdx << 17 /* SHIFT_PARENT */ | refIdx << 1 /* SHIFT_REF */;
19051}
19052
19053/**
19054 * @license
19055 * Copyright Google LLC All Rights Reserved.
19056 *
19057 * Use of this source code is governed by an MIT-style license that can be
19058 * found in the LICENSE file at https://angular.io/license
19059 */
19060/**
19061 * Keep track of which input bindings in `ɵɵi18nExp` have changed.
19062 *
19063 * This is used to efficiently update expressions in i18n only when the corresponding input has
19064 * changed.
19065 *
19066 * 1) Each bit represents which of the `ɵɵi18nExp` has changed.
19067 * 2) There are 32 bits allowed in JS.
19068 * 3) Bit 32 is special as it is shared for all changes past 32. (In other words if you have more
19069 * than 32 `ɵɵi18nExp` then all changes past 32nd `ɵɵi18nExp` will be mapped to same bit. This means
19070 * that we may end up changing more than we need to. But i18n expressions with 32 bindings is rare
19071 * so in practice it should not be an issue.)
19072 */
19073let changeMask = 0b0;
19074/**
19075 * Keeps track of which bit needs to be updated in `changeMask`
19076 *
19077 * This value gets incremented on every call to `ɵɵi18nExp`
19078 */
19079let changeMaskCounter = 0;
19080/**
19081 * Keep track of which input bindings in `ɵɵi18nExp` have changed.
19082 *
19083 * `setMaskBit` gets invoked by each call to `ɵɵi18nExp`.
19084 *
19085 * @param hasChange did `ɵɵi18nExp` detect a change.
19086 */
19087function setMaskBit(hasChange) {
19088 if (hasChange) {
19089 changeMask = changeMask | (1 << Math.min(changeMaskCounter, 31));
19090 }
19091 changeMaskCounter++;
19092}
19093function applyI18n(tView, lView, index) {
19094 if (changeMaskCounter > 0) {
19095 ngDevMode && assertDefined(tView, `tView should be defined`);
19096 const tI18n = tView.data[index];
19097 // When `index` points to an `ɵɵi18nAttributes` then we have an array otherwise `TI18n`
19098 const updateOpCodes = Array.isArray(tI18n) ? tI18n : tI18n.update;
19099 const bindingsStartIndex = getBindingIndex() - changeMaskCounter - 1;
19100 applyUpdateOpCodes(tView, lView, updateOpCodes, bindingsStartIndex, changeMask);
19101 }
19102 // Reset changeMask & maskBit to default for the next update cycle
19103 changeMask = 0b0;
19104 changeMaskCounter = 0;
19105}
19106/**
19107 * Apply `I18nCreateOpCodes` op-codes as stored in `TI18n.create`.
19108 *
19109 * Creates text (and comment) nodes which are internationalized.
19110 *
19111 * @param lView Current lView
19112 * @param createOpCodes Set of op-codes to apply
19113 * @param parentRNode Parent node (so that direct children can be added eagerly) or `null` if it is
19114 * a root node.
19115 * @param insertInFrontOf DOM node that should be used as an anchor.
19116 */
19117function applyCreateOpCodes(lView, createOpCodes, parentRNode, insertInFrontOf) {
19118 const renderer = lView[RENDERER];
19119 for (let i = 0; i < createOpCodes.length; i++) {
19120 const opCode = createOpCodes[i++];
19121 const text = createOpCodes[i];
19122 const isComment = (opCode & I18nCreateOpCode.COMMENT) === I18nCreateOpCode.COMMENT;
19123 const appendNow = (opCode & I18nCreateOpCode.APPEND_EAGERLY) === I18nCreateOpCode.APPEND_EAGERLY;
19124 const index = opCode >>> I18nCreateOpCode.SHIFT;
19125 let rNode = lView[index];
19126 if (rNode === null) {
19127 // We only create new DOM nodes if they don't already exist: If ICU switches case back to a
19128 // case which was already instantiated, no need to create new DOM nodes.
19129 rNode = lView[index] =
19130 isComment ? renderer.createComment(text) : createTextNode(renderer, text);
19131 }
19132 if (appendNow && parentRNode !== null) {
19133 nativeInsertBefore(renderer, parentRNode, rNode, insertInFrontOf, false);
19134 }
19135 }
19136}
19137/**
19138 * Apply `I18nMutateOpCodes` OpCodes.
19139 *
19140 * @param tView Current `TView`
19141 * @param mutableOpCodes Mutable OpCodes to process
19142 * @param lView Current `LView`
19143 * @param anchorRNode place where the i18n node should be inserted.
19144 */
19145function applyMutableOpCodes(tView, mutableOpCodes, lView, anchorRNode) {
19146 ngDevMode && assertDomNode(anchorRNode);
19147 const renderer = lView[RENDERER];
19148 // `rootIdx` represents the node into which all inserts happen.
19149 let rootIdx = null;
19150 // `rootRNode` represents the real node into which we insert. This can be different from
19151 // `lView[rootIdx]` if we have projection.
19152 // - null we don't have a parent (as can be the case in when we are inserting into a root of
19153 // LView which has no parent.)
19154 // - `RElement` The element representing the root after taking projection into account.
19155 let rootRNode;
19156 for (let i = 0; i < mutableOpCodes.length; i++) {
19157 const opCode = mutableOpCodes[i];
19158 if (typeof opCode == 'string') {
19159 const textNodeIndex = mutableOpCodes[++i];
19160 if (lView[textNodeIndex] === null) {
19161 ngDevMode && ngDevMode.rendererCreateTextNode++;
19162 ngDevMode && assertIndexInRange(lView, textNodeIndex);
19163 lView[textNodeIndex] = createTextNode(renderer, opCode);
19164 }
19165 }
19166 else if (typeof opCode == 'number') {
19167 switch (opCode & 1 /* MASK_INSTRUCTION */) {
19168 case 0 /* AppendChild */:
19169 const parentIdx = getParentFromIcuCreateOpCode(opCode);
19170 if (rootIdx === null) {
19171 // The first operation should save the `rootIdx` because the first operation
19172 // must insert into the root. (Only subsequent operations can insert into a dynamic
19173 // parent)
19174 rootIdx = parentIdx;
19175 rootRNode = nativeParentNode(renderer, anchorRNode);
19176 }
19177 let insertInFrontOf;
19178 let parentRNode;
19179 if (parentIdx === rootIdx) {
19180 insertInFrontOf = anchorRNode;
19181 parentRNode = rootRNode;
19182 }
19183 else {
19184 insertInFrontOf = null;
19185 parentRNode = unwrapRNode(lView[parentIdx]);
19186 }
19187 // FIXME(misko): Refactor with `processI18nText`
19188 if (parentRNode !== null) {
19189 // This can happen if the `LView` we are adding to is not attached to a parent `LView`.
19190 // In such a case there is no "root" we can attach to. This is fine, as we still need to
19191 // create the elements. When the `LView` gets later added to a parent these "root" nodes
19192 // get picked up and added.
19193 ngDevMode && assertDomNode(parentRNode);
19194 const refIdx = getRefFromIcuCreateOpCode(opCode);
19195 ngDevMode && assertGreaterThan(refIdx, HEADER_OFFSET, 'Missing ref');
19196 // `unwrapRNode` is not needed here as all of these point to RNodes as part of the i18n
19197 // which can't have components.
19198 const child = lView[refIdx];
19199 ngDevMode && assertDomNode(child);
19200 nativeInsertBefore(renderer, parentRNode, child, insertInFrontOf, false);
19201 const tIcu = getTIcu(tView, refIdx);
19202 if (tIcu !== null && typeof tIcu === 'object') {
19203 // If we just added a comment node which has ICU then that ICU may have already been
19204 // rendered and therefore we need to re-add it here.
19205 ngDevMode && assertTIcu(tIcu);
19206 const caseIndex = getCurrentICUCaseIndex(tIcu, lView);
19207 if (caseIndex !== null) {
19208 applyMutableOpCodes(tView, tIcu.create[caseIndex], lView, lView[tIcu.anchorIdx]);
19209 }
19210 }
19211 }
19212 break;
19213 case 1 /* Attr */:
19214 const elementNodeIndex = opCode >>> 1 /* SHIFT_REF */;
19215 const attrName = mutableOpCodes[++i];
19216 const attrValue = mutableOpCodes[++i];
19217 // This code is used for ICU expressions only, since we don't support
19218 // directives/components in ICUs, we don't need to worry about inputs here
19219 setElementAttribute(renderer, getNativeByIndex(elementNodeIndex, lView), null, null, attrName, attrValue, null);
19220 break;
19221 default:
19222 if (ngDevMode) {
19223 throw new RuntimeError(700 /* INVALID_I18N_STRUCTURE */, `Unable to determine the type of mutate operation for "${opCode}"`);
19224 }
19225 }
19226 }
19227 else {
19228 switch (opCode) {
19229 case ICU_MARKER:
19230 const commentValue = mutableOpCodes[++i];
19231 const commentNodeIndex = mutableOpCodes[++i];
19232 if (lView[commentNodeIndex] === null) {
19233 ngDevMode &&
19234 assertEqual(typeof commentValue, 'string', `Expected "${commentValue}" to be a comment node value`);
19235 ngDevMode && ngDevMode.rendererCreateComment++;
19236 ngDevMode && assertIndexInExpandoRange(lView, commentNodeIndex);
19237 const commentRNode = lView[commentNodeIndex] =
19238 createCommentNode(renderer, commentValue);
19239 // FIXME(misko): Attaching patch data is only needed for the root (Also add tests)
19240 attachPatchData(commentRNode, lView);
19241 }
19242 break;
19243 case ELEMENT_MARKER:
19244 const tagName = mutableOpCodes[++i];
19245 const elementNodeIndex = mutableOpCodes[++i];
19246 if (lView[elementNodeIndex] === null) {
19247 ngDevMode &&
19248 assertEqual(typeof tagName, 'string', `Expected "${tagName}" to be an element node tag name`);
19249 ngDevMode && ngDevMode.rendererCreateElement++;
19250 ngDevMode && assertIndexInExpandoRange(lView, elementNodeIndex);
19251 const elementRNode = lView[elementNodeIndex] =
19252 createElementNode(renderer, tagName, null);
19253 // FIXME(misko): Attaching patch data is only needed for the root (Also add tests)
19254 attachPatchData(elementRNode, lView);
19255 }
19256 break;
19257 default:
19258 ngDevMode &&
19259 throwError(`Unable to determine the type of mutate operation for "${opCode}"`);
19260 }
19261 }
19262 }
19263}
19264/**
19265 * Apply `I18nUpdateOpCodes` OpCodes
19266 *
19267 * @param tView Current `TView`
19268 * @param lView Current `LView`
19269 * @param updateOpCodes OpCodes to process
19270 * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
19271 * @param changeMask Each bit corresponds to a `ɵɵi18nExp` (Counting backwards from
19272 * `bindingsStartIndex`)
19273 */
19274function applyUpdateOpCodes(tView, lView, updateOpCodes, bindingsStartIndex, changeMask) {
19275 for (let i = 0; i < updateOpCodes.length; i++) {
19276 // bit code to check if we should apply the next update
19277 const checkBit = updateOpCodes[i];
19278 // Number of opCodes to skip until next set of update codes
19279 const skipCodes = updateOpCodes[++i];
19280 if (checkBit & changeMask) {
19281 // The value has been updated since last checked
19282 let value = '';
19283 for (let j = i + 1; j <= (i + skipCodes); j++) {
19284 const opCode = updateOpCodes[j];
19285 if (typeof opCode == 'string') {
19286 value += opCode;
19287 }
19288 else if (typeof opCode == 'number') {
19289 if (opCode < 0) {
19290 // Negative opCode represent `i18nExp` values offset.
19291 value += renderStringify(lView[bindingsStartIndex - opCode]);
19292 }
19293 else {
19294 const nodeIndex = (opCode >>> 2 /* SHIFT_REF */);
19295 switch (opCode & 3 /* MASK_OPCODE */) {
19296 case 1 /* Attr */:
19297 const propName = updateOpCodes[++j];
19298 const sanitizeFn = updateOpCodes[++j];
19299 const tNodeOrTagName = tView.data[nodeIndex];
19300 ngDevMode && assertDefined(tNodeOrTagName, 'Experting TNode or string');
19301 if (typeof tNodeOrTagName === 'string') {
19302 // IF we don't have a `TNode`, then we are an element in ICU (as ICU content does
19303 // not have TNode), in which case we know that there are no directives, and hence
19304 // we use attribute setting.
19305 setElementAttribute(lView[RENDERER], lView[nodeIndex], null, tNodeOrTagName, propName, value, sanitizeFn);
19306 }
19307 else {
19308 elementPropertyInternal(tView, tNodeOrTagName, lView, propName, value, lView[RENDERER], sanitizeFn, false);
19309 }
19310 break;
19311 case 0 /* Text */:
19312 const rText = lView[nodeIndex];
19313 rText !== null && updateTextNode(lView[RENDERER], rText, value);
19314 break;
19315 case 2 /* IcuSwitch */:
19316 applyIcuSwitchCase(tView, getTIcu(tView, nodeIndex), lView, value);
19317 break;
19318 case 3 /* IcuUpdate */:
19319 applyIcuUpdateCase(tView, getTIcu(tView, nodeIndex), bindingsStartIndex, lView);
19320 break;
19321 }
19322 }
19323 }
19324 }
19325 }
19326 else {
19327 const opCode = updateOpCodes[i + 1];
19328 if (opCode > 0 && (opCode & 3 /* MASK_OPCODE */) === 3 /* IcuUpdate */) {
19329 // Special case for the `icuUpdateCase`. It could be that the mask did not match, but
19330 // we still need to execute `icuUpdateCase` because the case has changed recently due to
19331 // previous `icuSwitchCase` instruction. (`icuSwitchCase` and `icuUpdateCase` always come in
19332 // pairs.)
19333 const nodeIndex = (opCode >>> 2 /* SHIFT_REF */);
19334 const tIcu = getTIcu(tView, nodeIndex);
19335 const currentIndex = lView[tIcu.currentCaseLViewIndex];
19336 if (currentIndex < 0) {
19337 applyIcuUpdateCase(tView, tIcu, bindingsStartIndex, lView);
19338 }
19339 }
19340 }
19341 i += skipCodes;
19342 }
19343}
19344/**
19345 * Apply OpCodes associated with updating an existing ICU.
19346 *
19347 * @param tView Current `TView`
19348 * @param tIcu Current `TIcu`
19349 * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
19350 * @param lView Current `LView`
19351 */
19352function applyIcuUpdateCase(tView, tIcu, bindingsStartIndex, lView) {
19353 ngDevMode && assertIndexInRange(lView, tIcu.currentCaseLViewIndex);
19354 let activeCaseIndex = lView[tIcu.currentCaseLViewIndex];
19355 if (activeCaseIndex !== null) {
19356 let mask = changeMask;
19357 if (activeCaseIndex < 0) {
19358 // Clear the flag.
19359 // Negative number means that the ICU was freshly created and we need to force the update.
19360 activeCaseIndex = lView[tIcu.currentCaseLViewIndex] = ~activeCaseIndex;
19361 // -1 is same as all bits on, which simulates creation since it marks all bits dirty
19362 mask = -1;
19363 }
19364 applyUpdateOpCodes(tView, lView, tIcu.update[activeCaseIndex], bindingsStartIndex, mask);
19365 }
19366}
19367/**
19368 * Apply OpCodes associated with switching a case on ICU.
19369 *
19370 * This involves tearing down existing case and than building up a new case.
19371 *
19372 * @param tView Current `TView`
19373 * @param tIcu Current `TIcu`
19374 * @param lView Current `LView`
19375 * @param value Value of the case to update to.
19376 */
19377function applyIcuSwitchCase(tView, tIcu, lView, value) {
19378 // Rebuild a new case for this ICU
19379 const caseIndex = getCaseIndex(tIcu, value);
19380 let activeCaseIndex = getCurrentICUCaseIndex(tIcu, lView);
19381 if (activeCaseIndex !== caseIndex) {
19382 applyIcuSwitchCaseRemove(tView, tIcu, lView);
19383 lView[tIcu.currentCaseLViewIndex] = caseIndex === null ? null : ~caseIndex;
19384 if (caseIndex !== null) {
19385 // Add the nodes for the new case
19386 const anchorRNode = lView[tIcu.anchorIdx];
19387 if (anchorRNode) {
19388 ngDevMode && assertDomNode(anchorRNode);
19389 applyMutableOpCodes(tView, tIcu.create[caseIndex], lView, anchorRNode);
19390 }
19391 }
19392 }
19393}
19394/**
19395 * Apply OpCodes associated with tearing ICU case.
19396 *
19397 * This involves tearing down existing case and than building up a new case.
19398 *
19399 * @param tView Current `TView`
19400 * @param tIcu Current `TIcu`
19401 * @param lView Current `LView`
19402 */
19403function applyIcuSwitchCaseRemove(tView, tIcu, lView) {
19404 let activeCaseIndex = getCurrentICUCaseIndex(tIcu, lView);
19405 if (activeCaseIndex !== null) {
19406 const removeCodes = tIcu.remove[activeCaseIndex];
19407 for (let i = 0; i < removeCodes.length; i++) {
19408 const nodeOrIcuIndex = removeCodes[i];
19409 if (nodeOrIcuIndex > 0) {
19410 // Positive numbers are `RNode`s.
19411 const rNode = getNativeByIndex(nodeOrIcuIndex, lView);
19412 rNode !== null && nativeRemoveNode(lView[RENDERER], rNode);
19413 }
19414 else {
19415 // Negative numbers are ICUs
19416 applyIcuSwitchCaseRemove(tView, getTIcu(tView, ~nodeOrIcuIndex), lView);
19417 }
19418 }
19419 }
19420}
19421/**
19422 * Returns the index of the current case of an ICU expression depending on the main binding value
19423 *
19424 * @param icuExpression
19425 * @param bindingValue The value of the main binding used by this ICU expression
19426 */
19427function getCaseIndex(icuExpression, bindingValue) {
19428 let index = icuExpression.cases.indexOf(bindingValue);
19429 if (index === -1) {
19430 switch (icuExpression.type) {
19431 case 1 /* plural */: {
19432 const resolvedCase = getPluralCase(bindingValue, getLocaleId());
19433 index = icuExpression.cases.indexOf(resolvedCase);
19434 if (index === -1 && resolvedCase !== 'other') {
19435 index = icuExpression.cases.indexOf('other');
19436 }
19437 break;
19438 }
19439 case 0 /* select */: {
19440 index = icuExpression.cases.indexOf('other');
19441 break;
19442 }
19443 }
19444 }
19445 return index === -1 ? null : index;
19446}
19447
19448/**
19449 * @license
19450 * Copyright Google LLC All Rights Reserved.
19451 *
19452 * Use of this source code is governed by an MIT-style license that can be
19453 * found in the LICENSE file at https://angular.io/license
19454 */
19455function loadIcuContainerVisitor() {
19456 const _stack = [];
19457 let _index = -1;
19458 let _lView;
19459 let _removes;
19460 /**
19461 * Retrieves a set of root nodes from `TIcu.remove`. Used by `TNodeType.ICUContainer`
19462 * to determine which root belong to the ICU.
19463 *
19464 * Example of usage.
19465 * ```
19466 * const nextRNode = icuContainerIteratorStart(tIcuContainerNode, lView);
19467 * let rNode: RNode|null;
19468 * while(rNode = nextRNode()) {
19469 * console.log(rNode);
19470 * }
19471 * ```
19472 *
19473 * @param tIcuContainerNode Current `TIcuContainerNode`
19474 * @param lView `LView` where the `RNode`s should be looked up.
19475 */
19476 function icuContainerIteratorStart(tIcuContainerNode, lView) {
19477 _lView = lView;
19478 while (_stack.length)
19479 _stack.pop();
19480 ngDevMode && assertTNodeForLView(tIcuContainerNode, lView);
19481 enterIcu(tIcuContainerNode.value, lView);
19482 return icuContainerIteratorNext;
19483 }
19484 function enterIcu(tIcu, lView) {
19485 _index = 0;
19486 const currentCase = getCurrentICUCaseIndex(tIcu, lView);
19487 if (currentCase !== null) {
19488 ngDevMode && assertNumberInRange(currentCase, 0, tIcu.cases.length - 1);
19489 _removes = tIcu.remove[currentCase];
19490 }
19491 else {
19492 _removes = EMPTY_ARRAY;
19493 }
19494 }
19495 function icuContainerIteratorNext() {
19496 if (_index < _removes.length) {
19497 const removeOpCode = _removes[_index++];
19498 ngDevMode && assertNumber(removeOpCode, 'Expecting OpCode number');
19499 if (removeOpCode > 0) {
19500 const rNode = _lView[removeOpCode];
19501 ngDevMode && assertDomNode(rNode);
19502 return rNode;
19503 }
19504 else {
19505 _stack.push(_index, _removes);
19506 // ICUs are represented by negative indices
19507 const tIcuIndex = ~removeOpCode;
19508 const tIcu = _lView[TVIEW].data[tIcuIndex];
19509 ngDevMode && assertTIcu(tIcu);
19510 enterIcu(tIcu, _lView);
19511 return icuContainerIteratorNext();
19512 }
19513 }
19514 else {
19515 if (_stack.length === 0) {
19516 return null;
19517 }
19518 else {
19519 _removes = _stack.pop();
19520 _index = _stack.pop();
19521 return icuContainerIteratorNext();
19522 }
19523 }
19524 }
19525 return icuContainerIteratorStart;
19526}
19527
19528/**
19529 * @license
19530 * Copyright Google LLC All Rights Reserved.
19531 *
19532 * Use of this source code is governed by an MIT-style license that can be
19533 * found in the LICENSE file at https://angular.io/license
19534 */
19535/**
19536 * Converts `I18nCreateOpCodes` array into a human readable format.
19537 *
19538 * This function is attached to the `I18nCreateOpCodes.debug` property if `ngDevMode` is enabled.
19539 * This function provides a human readable view of the opcodes. This is useful when debugging the
19540 * application as well as writing more readable tests.
19541 *
19542 * @param this `I18nCreateOpCodes` if attached as a method.
19543 * @param opcodes `I18nCreateOpCodes` if invoked as a function.
19544 */
19545function i18nCreateOpCodesToString(opcodes) {
19546 const createOpCodes = opcodes || (Array.isArray(this) ? this : []);
19547 let lines = [];
19548 for (let i = 0; i < createOpCodes.length; i++) {
19549 const opCode = createOpCodes[i++];
19550 const text = createOpCodes[i];
19551 const isComment = (opCode & I18nCreateOpCode.COMMENT) === I18nCreateOpCode.COMMENT;
19552 const appendNow = (opCode & I18nCreateOpCode.APPEND_EAGERLY) === I18nCreateOpCode.APPEND_EAGERLY;
19553 const index = opCode >>> I18nCreateOpCode.SHIFT;
19554 lines.push(`lView[${index}] = document.${isComment ? 'createComment' : 'createText'}(${JSON.stringify(text)});`);
19555 if (appendNow) {
19556 lines.push(`parent.appendChild(lView[${index}]);`);
19557 }
19558 }
19559 return lines;
19560}
19561/**
19562 * Converts `I18nUpdateOpCodes` array into a human readable format.
19563 *
19564 * This function is attached to the `I18nUpdateOpCodes.debug` property if `ngDevMode` is enabled.
19565 * This function provides a human readable view of the opcodes. This is useful when debugging the
19566 * application as well as writing more readable tests.
19567 *
19568 * @param this `I18nUpdateOpCodes` if attached as a method.
19569 * @param opcodes `I18nUpdateOpCodes` if invoked as a function.
19570 */
19571function i18nUpdateOpCodesToString(opcodes) {
19572 const parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
19573 let lines = [];
19574 function consumeOpCode(value) {
19575 const ref = value >>> 2 /* SHIFT_REF */;
19576 const opCode = value & 3 /* MASK_OPCODE */;
19577 switch (opCode) {
19578 case 0 /* Text */:
19579 return `(lView[${ref}] as Text).textContent = $$$`;
19580 case 1 /* Attr */:
19581 const attrName = parser.consumeString();
19582 const sanitizationFn = parser.consumeFunction();
19583 const value = sanitizationFn ? `(${sanitizationFn})($$$)` : '$$$';
19584 return `(lView[${ref}] as Element).setAttribute('${attrName}', ${value})`;
19585 case 2 /* IcuSwitch */:
19586 return `icuSwitchCase(${ref}, $$$)`;
19587 case 3 /* IcuUpdate */:
19588 return `icuUpdateCase(${ref})`;
19589 }
19590 throw new Error('unexpected OpCode');
19591 }
19592 while (parser.hasMore()) {
19593 let mask = parser.consumeNumber();
19594 let size = parser.consumeNumber();
19595 const end = parser.i + size;
19596 const statements = [];
19597 let statement = '';
19598 while (parser.i < end) {
19599 let value = parser.consumeNumberOrString();
19600 if (typeof value === 'string') {
19601 statement += value;
19602 }
19603 else if (value < 0) {
19604 // Negative numbers are ref indexes
19605 // Here `i` refers to current binding index. It is to signify that the value is relative,
19606 // rather than absolute.
19607 statement += '${lView[i' + value + ']}';
19608 }
19609 else {
19610 // Positive numbers are operations.
19611 const opCodeText = consumeOpCode(value);
19612 statements.push(opCodeText.replace('$$$', '`' + statement + '`') + ';');
19613 statement = '';
19614 }
19615 }
19616 lines.push(`if (mask & 0b${mask.toString(2)}) { ${statements.join(' ')} }`);
19617 }
19618 return lines;
19619}
19620/**
19621 * Converts `I18nCreateOpCodes` array into a human readable format.
19622 *
19623 * This function is attached to the `I18nCreateOpCodes.debug` if `ngDevMode` is enabled. This
19624 * function provides a human readable view of the opcodes. This is useful when debugging the
19625 * application as well as writing more readable tests.
19626 *
19627 * @param this `I18nCreateOpCodes` if attached as a method.
19628 * @param opcodes `I18nCreateOpCodes` if invoked as a function.
19629 */
19630function icuCreateOpCodesToString(opcodes) {
19631 const parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
19632 let lines = [];
19633 function consumeOpCode(opCode) {
19634 const parent = getParentFromIcuCreateOpCode(opCode);
19635 const ref = getRefFromIcuCreateOpCode(opCode);
19636 switch (getInstructionFromIcuCreateOpCode(opCode)) {
19637 case 0 /* AppendChild */:
19638 return `(lView[${parent}] as Element).appendChild(lView[${lastRef}])`;
19639 case 1 /* Attr */:
19640 return `(lView[${ref}] as Element).setAttribute("${parser.consumeString()}", "${parser.consumeString()}")`;
19641 }
19642 throw new Error('Unexpected OpCode: ' + getInstructionFromIcuCreateOpCode(opCode));
19643 }
19644 let lastRef = -1;
19645 while (parser.hasMore()) {
19646 let value = parser.consumeNumberStringOrMarker();
19647 if (value === ICU_MARKER) {
19648 const text = parser.consumeString();
19649 lastRef = parser.consumeNumber();
19650 lines.push(`lView[${lastRef}] = document.createComment("${text}")`);
19651 }
19652 else if (value === ELEMENT_MARKER) {
19653 const text = parser.consumeString();
19654 lastRef = parser.consumeNumber();
19655 lines.push(`lView[${lastRef}] = document.createElement("${text}")`);
19656 }
19657 else if (typeof value === 'string') {
19658 lastRef = parser.consumeNumber();
19659 lines.push(`lView[${lastRef}] = document.createTextNode("${value}")`);
19660 }
19661 else if (typeof value === 'number') {
19662 const line = consumeOpCode(value);
19663 line && lines.push(line);
19664 }
19665 else {
19666 throw new Error('Unexpected value');
19667 }
19668 }
19669 return lines;
19670}
19671/**
19672 * Converts `I18nRemoveOpCodes` array into a human readable format.
19673 *
19674 * This function is attached to the `I18nRemoveOpCodes.debug` if `ngDevMode` is enabled. This
19675 * function provides a human readable view of the opcodes. This is useful when debugging the
19676 * application as well as writing more readable tests.
19677 *
19678 * @param this `I18nRemoveOpCodes` if attached as a method.
19679 * @param opcodes `I18nRemoveOpCodes` if invoked as a function.
19680 */
19681function i18nRemoveOpCodesToString(opcodes) {
19682 const removeCodes = opcodes || (Array.isArray(this) ? this : []);
19683 let lines = [];
19684 for (let i = 0; i < removeCodes.length; i++) {
19685 const nodeOrIcuIndex = removeCodes[i];
19686 if (nodeOrIcuIndex > 0) {
19687 // Positive numbers are `RNode`s.
19688 lines.push(`remove(lView[${nodeOrIcuIndex}])`);
19689 }
19690 else {
19691 // Negative numbers are ICUs
19692 lines.push(`removeNestedICU(${~nodeOrIcuIndex})`);
19693 }
19694 }
19695 return lines;
19696}
19697class OpCodeParser {
19698 constructor(codes) {
19699 this.i = 0;
19700 this.codes = codes;
19701 }
19702 hasMore() {
19703 return this.i < this.codes.length;
19704 }
19705 consumeNumber() {
19706 let value = this.codes[this.i++];
19707 assertNumber(value, 'expecting number in OpCode');
19708 return value;
19709 }
19710 consumeString() {
19711 let value = this.codes[this.i++];
19712 assertString(value, 'expecting string in OpCode');
19713 return value;
19714 }
19715 consumeFunction() {
19716 let value = this.codes[this.i++];
19717 if (value === null || typeof value === 'function') {
19718 return value;
19719 }
19720 throw new Error('expecting function in OpCode');
19721 }
19722 consumeNumberOrString() {
19723 let value = this.codes[this.i++];
19724 if (typeof value === 'string') {
19725 return value;
19726 }
19727 assertNumber(value, 'expecting number or string in OpCode');
19728 return value;
19729 }
19730 consumeNumberStringOrMarker() {
19731 let value = this.codes[this.i++];
19732 if (typeof value === 'string' || typeof value === 'number' || value == ICU_MARKER ||
19733 value == ELEMENT_MARKER) {
19734 return value;
19735 }
19736 assertNumber(value, 'expecting number, string, ICU_MARKER or ELEMENT_MARKER in OpCode');
19737 return value;
19738 }
19739}
19740
19741/**
19742 * @license
19743 * Copyright Google LLC All Rights Reserved.
19744 *
19745 * Use of this source code is governed by an MIT-style license that can be
19746 * found in the LICENSE file at https://angular.io/license
19747 */
19748const BINDING_REGEXP = /�(\d+):?\d*�/gi;
19749const ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi;
19750const NESTED_ICU = /�(\d+)�/;
19751const ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/;
19752const MARKER = `�`;
19753const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
19754const PH_REGEXP = /�(\/?[#*]\d+):?\d*�/gi;
19755/**
19756 * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
19757 * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
19758 * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
19759 * and later on replaced by a space. We are re-implementing the same idea here, since translations
19760 * might contain this special character.
19761 */
19762const NGSP_UNICODE_REGEXP = /\uE500/g;
19763function replaceNgsp(value) {
19764 return value.replace(NGSP_UNICODE_REGEXP, ' ');
19765}
19766/**
19767 * Create dynamic nodes from i18n translation block.
19768 *
19769 * - Text nodes are created synchronously
19770 * - TNodes are linked into tree lazily
19771 *
19772 * @param tView Current `TView`
19773 * @parentTNodeIndex index to the parent TNode of this i18n block
19774 * @param lView Current `LView`
19775 * @param index Index of `ɵɵi18nStart` instruction.
19776 * @param message Message to translate.
19777 * @param subTemplateIndex Index into the sub template of message translation. (ie in case of
19778 * `ngIf`) (-1 otherwise)
19779 */
19780function i18nStartFirstCreatePass(tView, parentTNodeIndex, lView, index, message, subTemplateIndex) {
19781 const rootTNode = getCurrentParentTNode();
19782 const createOpCodes = [];
19783 const updateOpCodes = [];
19784 const existingTNodeStack = [[]];
19785 if (ngDevMode) {
19786 attachDebugGetter(createOpCodes, i18nCreateOpCodesToString);
19787 attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
19788 }
19789 message = getTranslationForTemplate(message, subTemplateIndex);
19790 const msgParts = replaceNgsp(message).split(PH_REGEXP);
19791 for (let i = 0; i < msgParts.length; i++) {
19792 let value = msgParts[i];
19793 if ((i & 1) === 0) {
19794 // Even indexes are text (including bindings & ICU expressions)
19795 const parts = i18nParseTextIntoPartsAndICU(value);
19796 for (let j = 0; j < parts.length; j++) {
19797 let part = parts[j];
19798 if ((j & 1) === 0) {
19799 // `j` is odd therefore `part` is string
19800 const text = part;
19801 ngDevMode && assertString(text, 'Parsed ICU part should be string');
19802 if (text !== '') {
19803 i18nStartFirstCreatePassProcessTextNode(tView, rootTNode, existingTNodeStack[0], createOpCodes, updateOpCodes, lView, text);
19804 }
19805 }
19806 else {
19807 // `j` is Even therefor `part` is an `ICUExpression`
19808 const icuExpression = part;
19809 // Verify that ICU expression has the right shape. Translations might contain invalid
19810 // constructions (while original messages were correct), so ICU parsing at runtime may
19811 // not succeed (thus `icuExpression` remains a string).
19812 // Note: we intentionally retain the error here by not using `ngDevMode`, because
19813 // the value can change based on the locale and users aren't guaranteed to hit
19814 // an invalid string while they're developing.
19815 if (typeof icuExpression !== 'object') {
19816 throw new Error(`Unable to parse ICU expression in "${message}" message.`);
19817 }
19818 const icuContainerTNode = createTNodeAndAddOpCode(tView, rootTNode, existingTNodeStack[0], lView, createOpCodes, ngDevMode ? `ICU ${index}:${icuExpression.mainBinding}` : '', true);
19819 const icuNodeIndex = icuContainerTNode.index;
19820 ngDevMode &&
19821 assertGreaterThanOrEqual(icuNodeIndex, HEADER_OFFSET, 'Index must be in absolute LView offset');
19822 icuStart(tView, lView, updateOpCodes, parentTNodeIndex, icuExpression, icuNodeIndex);
19823 }
19824 }
19825 }
19826 else {
19827 // Odd indexes are placeholders (elements and sub-templates)
19828 // At this point value is something like: '/#1:2' (originally coming from '�/#1:2�')
19829 const isClosing = value.charCodeAt(0) === 47 /* SLASH */;
19830 const type = value.charCodeAt(isClosing ? 1 : 0);
19831 ngDevMode && assertOneOf(type, 42 /* STAR */, 35 /* HASH */);
19832 const index = HEADER_OFFSET + Number.parseInt(value.substring((isClosing ? 2 : 1)));
19833 if (isClosing) {
19834 existingTNodeStack.shift();
19835 setCurrentTNode(getCurrentParentTNode(), false);
19836 }
19837 else {
19838 const tNode = createTNodePlaceholder(tView, existingTNodeStack[0], index);
19839 existingTNodeStack.unshift([]);
19840 setCurrentTNode(tNode, true);
19841 }
19842 }
19843 }
19844 tView.data[index] = {
19845 create: createOpCodes,
19846 update: updateOpCodes,
19847 };
19848}
19849/**
19850 * Allocate space in i18n Range add create OpCode instruction to create a text or comment node.
19851 *
19852 * @param tView Current `TView` needed to allocate space in i18n range.
19853 * @param rootTNode Root `TNode` of the i18n block. This node determines if the new TNode will be
19854 * added as part of the `i18nStart` instruction or as part of the `TNode.insertBeforeIndex`.
19855 * @param existingTNodes internal state for `addTNodeAndUpdateInsertBeforeIndex`.
19856 * @param lView Current `LView` needed to allocate space in i18n range.
19857 * @param createOpCodes Array storing `I18nCreateOpCodes` where new opCodes will be added.
19858 * @param text Text to be added when the `Text` or `Comment` node will be created.
19859 * @param isICU true if a `Comment` node for ICU (instead of `Text`) node should be created.
19860 */
19861function createTNodeAndAddOpCode(tView, rootTNode, existingTNodes, lView, createOpCodes, text, isICU) {
19862 const i18nNodeIdx = allocExpando(tView, lView, 1, null);
19863 let opCode = i18nNodeIdx << I18nCreateOpCode.SHIFT;
19864 let parentTNode = getCurrentParentTNode();
19865 if (rootTNode === parentTNode) {
19866 // FIXME(misko): A null `parentTNode` should represent when we fall of the `LView` boundary.
19867 // (there is no parent), but in some circumstances (because we are inconsistent about how we set
19868 // `previousOrParentTNode`) it could point to `rootTNode` So this is a work around.
19869 parentTNode = null;
19870 }
19871 if (parentTNode === null) {
19872 // If we don't have a parent that means that we can eagerly add nodes.
19873 // If we have a parent than these nodes can't be added now (as the parent has not been created
19874 // yet) and instead the `parentTNode` is responsible for adding it. See
19875 // `TNode.insertBeforeIndex`
19876 opCode |= I18nCreateOpCode.APPEND_EAGERLY;
19877 }
19878 if (isICU) {
19879 opCode |= I18nCreateOpCode.COMMENT;
19880 ensureIcuContainerVisitorLoaded(loadIcuContainerVisitor);
19881 }
19882 createOpCodes.push(opCode, text === null ? '' : text);
19883 // We store `{{?}}` so that when looking at debug `TNodeType.template` we can see where the
19884 // bindings are.
19885 const tNode = createTNodeAtIndex(tView, i18nNodeIdx, isICU ? 32 /* Icu */ : 1 /* Text */, text === null ? (ngDevMode ? '{{?}}' : '') : text, null);
19886 addTNodeAndUpdateInsertBeforeIndex(existingTNodes, tNode);
19887 const tNodeIdx = tNode.index;
19888 setCurrentTNode(tNode, false /* Text nodes are self closing */);
19889 if (parentTNode !== null && rootTNode !== parentTNode) {
19890 // We are a child of deeper node (rather than a direct child of `i18nStart` instruction.)
19891 // We have to make sure to add ourselves to the parent.
19892 setTNodeInsertBeforeIndex(parentTNode, tNodeIdx);
19893 }
19894 return tNode;
19895}
19896/**
19897 * Processes text node in i18n block.
19898 *
19899 * Text nodes can have:
19900 * - Create instruction in `createOpCodes` for creating the text node.
19901 * - Allocate spec for text node in i18n range of `LView`
19902 * - If contains binding:
19903 * - bindings => allocate space in i18n range of `LView` to store the binding value.
19904 * - populate `updateOpCodes` with update instructions.
19905 *
19906 * @param tView Current `TView`
19907 * @param rootTNode Root `TNode` of the i18n block. This node determines if the new TNode will
19908 * be added as part of the `i18nStart` instruction or as part of the
19909 * `TNode.insertBeforeIndex`.
19910 * @param existingTNodes internal state for `addTNodeAndUpdateInsertBeforeIndex`.
19911 * @param createOpCodes Location where the creation OpCodes will be stored.
19912 * @param lView Current `LView`
19913 * @param text The translated text (which may contain binding)
19914 */
19915function i18nStartFirstCreatePassProcessTextNode(tView, rootTNode, existingTNodes, createOpCodes, updateOpCodes, lView, text) {
19916 const hasBinding = text.match(BINDING_REGEXP);
19917 const tNode = createTNodeAndAddOpCode(tView, rootTNode, existingTNodes, lView, createOpCodes, hasBinding ? null : text, false);
19918 if (hasBinding) {
19919 generateBindingUpdateOpCodes(updateOpCodes, text, tNode.index, null, 0, null);
19920 }
19921}
19922/**
19923 * See `i18nAttributes` above.
19924 */
19925function i18nAttributesFirstPass(tView, index, values) {
19926 const previousElement = getCurrentTNode();
19927 const previousElementIndex = previousElement.index;
19928 const updateOpCodes = [];
19929 if (ngDevMode) {
19930 attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
19931 }
19932 if (tView.firstCreatePass && tView.data[index] === null) {
19933 for (let i = 0; i < values.length; i += 2) {
19934 const attrName = values[i];
19935 const message = values[i + 1];
19936 if (message !== '') {
19937 // Check if attribute value contains an ICU and throw an error if that's the case.
19938 // ICUs in element attributes are not supported.
19939 // Note: we intentionally retain the error here by not using `ngDevMode`, because
19940 // the `value` can change based on the locale and users aren't guaranteed to hit
19941 // an invalid string while they're developing.
19942 if (ICU_REGEXP.test(message)) {
19943 throw new Error(`ICU expressions are not supported in attributes. Message: "${message}".`);
19944 }
19945 // i18n attributes that hit this code path are guaranteed to have bindings, because
19946 // the compiler treats static i18n attributes as regular attribute bindings.
19947 // Since this may not be the first i18n attribute on this element we need to pass in how
19948 // many previous bindings there have already been.
19949 generateBindingUpdateOpCodes(updateOpCodes, message, previousElementIndex, attrName, countBindings(updateOpCodes), null);
19950 }
19951 }
19952 tView.data[index] = updateOpCodes;
19953 }
19954}
19955/**
19956 * Generate the OpCodes to update the bindings of a string.
19957 *
19958 * @param updateOpCodes Place where the update opcodes will be stored.
19959 * @param str The string containing the bindings.
19960 * @param destinationNode Index of the destination node which will receive the binding.
19961 * @param attrName Name of the attribute, if the string belongs to an attribute.
19962 * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary.
19963 * @param bindingStart The lView index of the next expression that can be bound via an opCode.
19964 * @returns The mask value for these bindings
19965 */
19966function generateBindingUpdateOpCodes(updateOpCodes, str, destinationNode, attrName, bindingStart, sanitizeFn) {
19967 ngDevMode &&
19968 assertGreaterThanOrEqual(destinationNode, HEADER_OFFSET, 'Index must be in absolute LView offset');
19969 const maskIndex = updateOpCodes.length; // Location of mask
19970 const sizeIndex = maskIndex + 1; // location of size for skipping
19971 updateOpCodes.push(null, null); // Alloc space for mask and size
19972 const startIndex = maskIndex + 2; // location of first allocation.
19973 if (ngDevMode) {
19974 attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
19975 }
19976 const textParts = str.split(BINDING_REGEXP);
19977 let mask = 0;
19978 for (let j = 0; j < textParts.length; j++) {
19979 const textValue = textParts[j];
19980 if (j & 1) {
19981 // Odd indexes are bindings
19982 const bindingIndex = bindingStart + parseInt(textValue, 10);
19983 updateOpCodes.push(-1 - bindingIndex);
19984 mask = mask | toMaskBit(bindingIndex);
19985 }
19986 else if (textValue !== '') {
19987 // Even indexes are text
19988 updateOpCodes.push(textValue);
19989 }
19990 }
19991 updateOpCodes.push(destinationNode << 2 /* SHIFT_REF */ |
19992 (attrName ? 1 /* Attr */ : 0 /* Text */));
19993 if (attrName) {
19994 updateOpCodes.push(attrName, sanitizeFn);
19995 }
19996 updateOpCodes[maskIndex] = mask;
19997 updateOpCodes[sizeIndex] = updateOpCodes.length - startIndex;
19998 return mask;
19999}
20000/**
20001 * Count the number of bindings in the given `opCodes`.
20002 *
20003 * It could be possible to speed this up, by passing the number of bindings found back from
20004 * `generateBindingUpdateOpCodes()` to `i18nAttributesFirstPass()` but this would then require more
20005 * complexity in the code and/or transient objects to be created.
20006 *
20007 * Since this function is only called once when the template is instantiated, is trivial in the
20008 * first instance (since `opCodes` will be an empty array), and it is not common for elements to
20009 * contain multiple i18n bound attributes, it seems like this is a reasonable compromise.
20010 */
20011function countBindings(opCodes) {
20012 let count = 0;
20013 for (let i = 0; i < opCodes.length; i++) {
20014 const opCode = opCodes[i];
20015 // Bindings are negative numbers.
20016 if (typeof opCode === 'number' && opCode < 0) {
20017 count++;
20018 }
20019 }
20020 return count;
20021}
20022/**
20023 * Convert binding index to mask bit.
20024 *
20025 * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make
20026 * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to
20027 * have more than 32 bindings this will be hit very rarely. The downside of hitting this corner
20028 * case is that we will execute binding code more often than necessary. (penalty of performance)
20029 */
20030function toMaskBit(bindingIndex) {
20031 return 1 << Math.min(bindingIndex, 31);
20032}
20033function isRootTemplateMessage(subTemplateIndex) {
20034 return subTemplateIndex === -1;
20035}
20036/**
20037 * Removes everything inside the sub-templates of a message.
20038 */
20039function removeInnerTemplateTranslation(message) {
20040 let match;
20041 let res = '';
20042 let index = 0;
20043 let inTemplate = false;
20044 let tagMatched;
20045 while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) {
20046 if (!inTemplate) {
20047 res += message.substring(index, match.index + match[0].length);
20048 tagMatched = match[1];
20049 inTemplate = true;
20050 }
20051 else {
20052 if (match[0] === `${MARKER}/*${tagMatched}${MARKER}`) {
20053 index = match.index;
20054 inTemplate = false;
20055 }
20056 }
20057 }
20058 ngDevMode &&
20059 assertEqual(inTemplate, false, `Tag mismatch: unable to find the end of the sub-template in the translation "${message}"`);
20060 res += message.substr(index);
20061 return res;
20062}
20063/**
20064 * Extracts a part of a message and removes the rest.
20065 *
20066 * This method is used for extracting a part of the message associated with a template. A
20067 * translated message can span multiple templates.
20068 *
20069 * Example:
20070 * ```
20071 * <div i18n>Translate <span *ngIf>me</span>!</div>
20072 * ```
20073 *
20074 * @param message The message to crop
20075 * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the
20076 * external template and removes all sub-templates.
20077 */
20078function getTranslationForTemplate(message, subTemplateIndex) {
20079 if (isRootTemplateMessage(subTemplateIndex)) {
20080 // We want the root template message, ignore all sub-templates
20081 return removeInnerTemplateTranslation(message);
20082 }
20083 else {
20084 // We want a specific sub-template
20085 const start = message.indexOf(`:${subTemplateIndex}${MARKER}`) + 2 + subTemplateIndex.toString().length;
20086 const end = message.search(new RegExp(`${MARKER}\\/\\*\\d+:${subTemplateIndex}${MARKER}`));
20087 return removeInnerTemplateTranslation(message.substring(start, end));
20088 }
20089}
20090/**
20091 * Generate the OpCodes for ICU expressions.
20092 *
20093 * @param icuExpression
20094 * @param index Index where the anchor is stored and an optional `TIcuContainerNode`
20095 * - `lView[anchorIdx]` points to a `Comment` node representing the anchor for the ICU.
20096 * - `tView.data[anchorIdx]` points to the `TIcuContainerNode` if ICU is root (`null` otherwise)
20097 */
20098function icuStart(tView, lView, updateOpCodes, parentIdx, icuExpression, anchorIdx) {
20099 ngDevMode && assertDefined(icuExpression, 'ICU expression must be defined');
20100 let bindingMask = 0;
20101 const tIcu = {
20102 type: icuExpression.type,
20103 currentCaseLViewIndex: allocExpando(tView, lView, 1, null),
20104 anchorIdx,
20105 cases: [],
20106 create: [],
20107 remove: [],
20108 update: []
20109 };
20110 addUpdateIcuSwitch(updateOpCodes, icuExpression, anchorIdx);
20111 setTIcu(tView, anchorIdx, tIcu);
20112 const values = icuExpression.values;
20113 for (let i = 0; i < values.length; i++) {
20114 // Each value is an array of strings & other ICU expressions
20115 const valueArr = values[i];
20116 const nestedIcus = [];
20117 for (let j = 0; j < valueArr.length; j++) {
20118 const value = valueArr[j];
20119 if (typeof value !== 'string') {
20120 // It is an nested ICU expression
20121 const icuIndex = nestedIcus.push(value) - 1;
20122 // Replace nested ICU expression by a comment node
20123 valueArr[j] = `<!--�${icuIndex}�-->`;
20124 }
20125 }
20126 bindingMask = parseIcuCase(tView, tIcu, lView, updateOpCodes, parentIdx, icuExpression.cases[i], valueArr.join(''), nestedIcus) |
20127 bindingMask;
20128 }
20129 if (bindingMask) {
20130 addUpdateIcuUpdate(updateOpCodes, bindingMask, anchorIdx);
20131 }
20132}
20133/**
20134 * Parses text containing an ICU expression and produces a JSON object for it.
20135 * Original code from closure library, modified for Angular.
20136 *
20137 * @param pattern Text containing an ICU expression that needs to be parsed.
20138 *
20139 */
20140function parseICUBlock(pattern) {
20141 const cases = [];
20142 const values = [];
20143 let icuType = 1 /* plural */;
20144 let mainBinding = 0;
20145 pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) {
20146 if (type === 'select') {
20147 icuType = 0 /* select */;
20148 }
20149 else {
20150 icuType = 1 /* plural */;
20151 }
20152 mainBinding = parseInt(binding.substr(1), 10);
20153 return '';
20154 });
20155 const parts = i18nParseTextIntoPartsAndICU(pattern);
20156 // Looking for (key block)+ sequence. One of the keys has to be "other".
20157 for (let pos = 0; pos < parts.length;) {
20158 let key = parts[pos++].trim();
20159 if (icuType === 1 /* plural */) {
20160 // Key can be "=x", we just want "x"
20161 key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1');
20162 }
20163 if (key.length) {
20164 cases.push(key);
20165 }
20166 const blocks = i18nParseTextIntoPartsAndICU(parts[pos++]);
20167 if (cases.length > values.length) {
20168 values.push(blocks);
20169 }
20170 }
20171 // TODO(ocombe): support ICU expressions in attributes, see #21615
20172 return { type: icuType, mainBinding: mainBinding, cases, values };
20173}
20174/**
20175 * Breaks pattern into strings and top level {...} blocks.
20176 * Can be used to break a message into text and ICU expressions, or to break an ICU expression
20177 * into keys and cases. Original code from closure library, modified for Angular.
20178 *
20179 * @param pattern (sub)Pattern to be broken.
20180 * @returns An `Array<string|IcuExpression>` where:
20181 * - odd positions: `string` => text between ICU expressions
20182 * - even positions: `ICUExpression` => ICU expression parsed into `ICUExpression` record.
20183 */
20184function i18nParseTextIntoPartsAndICU(pattern) {
20185 if (!pattern) {
20186 return [];
20187 }
20188 let prevPos = 0;
20189 const braceStack = [];
20190 const results = [];
20191 const braces = /[{}]/g;
20192 // lastIndex doesn't get set to 0 so we have to.
20193 braces.lastIndex = 0;
20194 let match;
20195 while (match = braces.exec(pattern)) {
20196 const pos = match.index;
20197 if (match[0] == '}') {
20198 braceStack.pop();
20199 if (braceStack.length == 0) {
20200 // End of the block.
20201 const block = pattern.substring(prevPos, pos);
20202 if (ICU_BLOCK_REGEXP.test(block)) {
20203 results.push(parseICUBlock(block));
20204 }
20205 else {
20206 results.push(block);
20207 }
20208 prevPos = pos + 1;
20209 }
20210 }
20211 else {
20212 if (braceStack.length == 0) {
20213 const substring = pattern.substring(prevPos, pos);
20214 results.push(substring);
20215 prevPos = pos + 1;
20216 }
20217 braceStack.push('{');
20218 }
20219 }
20220 const substring = pattern.substring(prevPos);
20221 results.push(substring);
20222 return results;
20223}
20224/**
20225 * Parses a node, its children and its siblings, and generates the mutate & update OpCodes.
20226 *
20227 */
20228function parseIcuCase(tView, tIcu, lView, updateOpCodes, parentIdx, caseName, unsafeCaseHtml, nestedIcus) {
20229 const create = [];
20230 const remove = [];
20231 const update = [];
20232 if (ngDevMode) {
20233 attachDebugGetter(create, icuCreateOpCodesToString);
20234 attachDebugGetter(remove, i18nRemoveOpCodesToString);
20235 attachDebugGetter(update, i18nUpdateOpCodesToString);
20236 }
20237 tIcu.cases.push(caseName);
20238 tIcu.create.push(create);
20239 tIcu.remove.push(remove);
20240 tIcu.update.push(update);
20241 const inertBodyHelper = getInertBodyHelper(getDocument());
20242 const inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeCaseHtml);
20243 ngDevMode && assertDefined(inertBodyElement, 'Unable to generate inert body element');
20244 const inertRootNode = getTemplateContent(inertBodyElement) || inertBodyElement;
20245 if (inertRootNode) {
20246 return walkIcuTree(tView, tIcu, lView, updateOpCodes, create, remove, update, inertRootNode, parentIdx, nestedIcus, 0);
20247 }
20248 else {
20249 return 0;
20250 }
20251}
20252function walkIcuTree(tView, tIcu, lView, sharedUpdateOpCodes, create, remove, update, parentNode, parentIdx, nestedIcus, depth) {
20253 let bindingMask = 0;
20254 let currentNode = parentNode.firstChild;
20255 while (currentNode) {
20256 const newIndex = allocExpando(tView, lView, 1, null);
20257 switch (currentNode.nodeType) {
20258 case Node.ELEMENT_NODE:
20259 const element = currentNode;
20260 const tagName = element.tagName.toLowerCase();
20261 if (VALID_ELEMENTS.hasOwnProperty(tagName)) {
20262 addCreateNodeAndAppend(create, ELEMENT_MARKER, tagName, parentIdx, newIndex);
20263 tView.data[newIndex] = tagName;
20264 const elAttrs = element.attributes;
20265 for (let i = 0; i < elAttrs.length; i++) {
20266 const attr = elAttrs.item(i);
20267 const lowerAttrName = attr.name.toLowerCase();
20268 const hasBinding = !!attr.value.match(BINDING_REGEXP);
20269 // we assume the input string is safe, unless it's using a binding
20270 if (hasBinding) {
20271 if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
20272 if (URI_ATTRS[lowerAttrName]) {
20273 generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, _sanitizeUrl);
20274 }
20275 else if (SRCSET_ATTRS[lowerAttrName]) {
20276 generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, sanitizeSrcset);
20277 }
20278 else {
20279 generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, null);
20280 }
20281 }
20282 else {
20283 ngDevMode &&
20284 console.warn(`WARNING: ignoring unsafe attribute value ` +
20285 `${lowerAttrName} on element ${tagName} ` +
20286 `(see https://g.co/ng/security#xss)`);
20287 }
20288 }
20289 else {
20290 addCreateAttribute(create, newIndex, attr);
20291 }
20292 }
20293 // Parse the children of this node (if any)
20294 bindingMask = walkIcuTree(tView, tIcu, lView, sharedUpdateOpCodes, create, remove, update, currentNode, newIndex, nestedIcus, depth + 1) |
20295 bindingMask;
20296 addRemoveNode(remove, newIndex, depth);
20297 }
20298 break;
20299 case Node.TEXT_NODE:
20300 const value = currentNode.textContent || '';
20301 const hasBinding = value.match(BINDING_REGEXP);
20302 addCreateNodeAndAppend(create, null, hasBinding ? '' : value, parentIdx, newIndex);
20303 addRemoveNode(remove, newIndex, depth);
20304 if (hasBinding) {
20305 bindingMask =
20306 generateBindingUpdateOpCodes(update, value, newIndex, null, 0, null) | bindingMask;
20307 }
20308 break;
20309 case Node.COMMENT_NODE:
20310 // Check if the comment node is a placeholder for a nested ICU
20311 const isNestedIcu = NESTED_ICU.exec(currentNode.textContent || '');
20312 if (isNestedIcu) {
20313 const nestedIcuIndex = parseInt(isNestedIcu[1], 10);
20314 const icuExpression = nestedIcus[nestedIcuIndex];
20315 // Create the comment node that will anchor the ICU expression
20316 addCreateNodeAndAppend(create, ICU_MARKER, ngDevMode ? `nested ICU ${nestedIcuIndex}` : '', parentIdx, newIndex);
20317 icuStart(tView, lView, sharedUpdateOpCodes, parentIdx, icuExpression, newIndex);
20318 addRemoveNestedIcu(remove, newIndex, depth);
20319 }
20320 break;
20321 }
20322 currentNode = currentNode.nextSibling;
20323 }
20324 return bindingMask;
20325}
20326function addRemoveNode(remove, index, depth) {
20327 if (depth === 0) {
20328 remove.push(index);
20329 }
20330}
20331function addRemoveNestedIcu(remove, index, depth) {
20332 if (depth === 0) {
20333 remove.push(~index); // remove ICU at `index`
20334 remove.push(index); // remove ICU comment at `index`
20335 }
20336}
20337function addUpdateIcuSwitch(update, icuExpression, index) {
20338 update.push(toMaskBit(icuExpression.mainBinding), 2, -1 - icuExpression.mainBinding, index << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */);
20339}
20340function addUpdateIcuUpdate(update, bindingMask, index) {
20341 update.push(bindingMask, 1, index << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */);
20342}
20343function addCreateNodeAndAppend(create, marker, text, appendToParentIdx, createAtIdx) {
20344 if (marker !== null) {
20345 create.push(marker);
20346 }
20347 create.push(text, createAtIdx, icuCreateOpCode(0 /* AppendChild */, appendToParentIdx, createAtIdx));
20348}
20349function addCreateAttribute(create, newIndex, attr) {
20350 create.push(newIndex << 1 /* SHIFT_REF */ | 1 /* Attr */, attr.name, attr.value);
20351}
20352
20353/**
20354 * @license
20355 * Copyright Google LLC All Rights Reserved.
20356 *
20357 * Use of this source code is governed by an MIT-style license that can be
20358 * found in the LICENSE file at https://angular.io/license
20359 */
20360// i18nPostprocess consts
20361const ROOT_TEMPLATE_ID = 0;
20362const PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/;
20363const PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g;
20364const PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g;
20365const PP_ICU_PLACEHOLDERS_REGEXP = /{([A-Z0-9_]+)}/g;
20366const PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g;
20367const PP_CLOSE_TEMPLATE_REGEXP = /\/\*/;
20368const PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/;
20369/**
20370 * Handles message string post-processing for internationalization.
20371 *
20372 * Handles message string post-processing by transforming it from intermediate
20373 * format (that might contain some markers that we need to replace) to the final
20374 * form, consumable by i18nStart instruction. Post processing steps include:
20375 *
20376 * 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�])
20377 * 2. Replace all ICU vars (like "VAR_PLURAL")
20378 * 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
20379 * 4. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�)
20380 * in case multiple ICUs have the same placeholder name
20381 *
20382 * @param message Raw translation string for post processing
20383 * @param replacements Set of replacements that should be applied
20384 *
20385 * @returns Transformed string that can be consumed by i18nStart instruction
20386 *
20387 * @codeGenApi
20388 */
20389function i18nPostprocess(message, replacements = {}) {
20390 /**
20391 * Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�]
20392 *
20393 * Note: due to the way we process nested templates (BFS), multi-value placeholders are typically
20394 * grouped by templates, for example: [�#5�|�#6�|�#1:1�|�#3:2�] where �#5� and �#6� belong to root
20395 * template, �#1:1� belong to nested template with index 1 and �#1:2� - nested template with index
20396 * 3. However in real templates the order might be different: i.e. �#1:1� and/or �#3:2� may go in
20397 * front of �#6�. The post processing step restores the right order by keeping track of the
20398 * template id stack and looks for placeholders that belong to the currently active template.
20399 */
20400 let result = message;
20401 if (PP_MULTI_VALUE_PLACEHOLDERS_REGEXP.test(message)) {
20402 const matches = {};
20403 const templateIdsStack = [ROOT_TEMPLATE_ID];
20404 result = result.replace(PP_PLACEHOLDERS_REGEXP, (m, phs, tmpl) => {
20405 const content = phs || tmpl;
20406 const placeholders = matches[content] || [];
20407 if (!placeholders.length) {
20408 content.split('|').forEach((placeholder) => {
20409 const match = placeholder.match(PP_TEMPLATE_ID_REGEXP);
20410 const templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID;
20411 const isCloseTemplateTag = PP_CLOSE_TEMPLATE_REGEXP.test(placeholder);
20412 placeholders.push([templateId, isCloseTemplateTag, placeholder]);
20413 });
20414 matches[content] = placeholders;
20415 }
20416 if (!placeholders.length) {
20417 throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
20418 }
20419 const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
20420 let idx = 0;
20421 // find placeholder index that matches current template id
20422 for (let i = 0; i < placeholders.length; i++) {
20423 if (placeholders[i][0] === currentTemplateId) {
20424 idx = i;
20425 break;
20426 }
20427 }
20428 // update template id stack based on the current tag extracted
20429 const [templateId, isCloseTemplateTag, placeholder] = placeholders[idx];
20430 if (isCloseTemplateTag) {
20431 templateIdsStack.pop();
20432 }
20433 else if (currentTemplateId !== templateId) {
20434 templateIdsStack.push(templateId);
20435 }
20436 // remove processed tag from the list
20437 placeholders.splice(idx, 1);
20438 return placeholder;
20439 });
20440 }
20441 // return current result if no replacements specified
20442 if (!Object.keys(replacements).length) {
20443 return result;
20444 }
20445 /**
20446 * Step 2: replace all ICU vars (like "VAR_PLURAL")
20447 */
20448 result = result.replace(PP_ICU_VARS_REGEXP, (match, start, key, _type, _idx, end) => {
20449 return replacements.hasOwnProperty(key) ? `${start}${replacements[key]}${end}` : match;
20450 });
20451 /**
20452 * Step 3: replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
20453 */
20454 result = result.replace(PP_ICU_PLACEHOLDERS_REGEXP, (match, key) => {
20455 return replacements.hasOwnProperty(key) ? replacements[key] : match;
20456 });
20457 /**
20458 * Step 4: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case
20459 * multiple ICUs have the same placeholder name
20460 */
20461 result = result.replace(PP_ICUS_REGEXP, (match, key) => {
20462 if (replacements.hasOwnProperty(key)) {
20463 const list = replacements[key];
20464 if (!list.length) {
20465 throw new Error(`i18n postprocess: unmatched ICU - ${match} with key: ${key}`);
20466 }
20467 return list.shift();
20468 }
20469 return match;
20470 });
20471 return result;
20472}
20473
20474/**
20475 * @license
20476 * Copyright Google LLC All Rights Reserved.
20477 *
20478 * Use of this source code is governed by an MIT-style license that can be
20479 * found in the LICENSE file at https://angular.io/license
20480 */
20481/**
20482 * Marks a block of text as translatable.
20483 *
20484 * The instructions `i18nStart` and `i18nEnd` mark the translation block in the template.
20485 * The translation `message` is the value which is locale specific. The translation string may
20486 * contain placeholders which associate inner elements and sub-templates within the translation.
20487 *
20488 * The translation `message` placeholders are:
20489 * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
20490 * interpolated into. The placeholder `index` points to the expression binding index. An optional
20491 * `block` that matches the sub-template in which it was declared.
20492 * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
20493 * and end of DOM element that were embedded in the original translation block. The placeholder
20494 * `index` points to the element index in the template instructions set. An optional `block` that
20495 * matches the sub-template in which it was declared.
20496 * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
20497 * split up and translated separately in each angular template function. The `index` points to the
20498 * `template` instruction index. A `block` that matches the sub-template in which it was declared.
20499 *
20500 * @param index A unique index of the translation in the static block.
20501 * @param messageIndex An index of the translation message from the `def.consts` array.
20502 * @param subTemplateIndex Optional sub-template index in the `message`.
20503 *
20504 * @codeGenApi
20505 */
20506function ɵɵi18nStart(index, messageIndex, subTemplateIndex = -1) {
20507 const tView = getTView();
20508 const lView = getLView();
20509 const adjustedIndex = HEADER_OFFSET + index;
20510 ngDevMode && assertDefined(tView, `tView should be defined`);
20511 const message = getConstant(tView.consts, messageIndex);
20512 const parentTNode = getCurrentParentTNode();
20513 if (tView.firstCreatePass) {
20514 i18nStartFirstCreatePass(tView, parentTNode === null ? 0 : parentTNode.index, lView, adjustedIndex, message, subTemplateIndex);
20515 }
20516 const tI18n = tView.data[adjustedIndex];
20517 const sameViewParentTNode = parentTNode === lView[T_HOST] ? null : parentTNode;
20518 const parentRNode = getClosestRElement(tView, sameViewParentTNode, lView);
20519 // If `parentTNode` is an `ElementContainer` than it has `<!--ng-container--->`.
20520 // When we do inserts we have to make sure to insert in front of `<!--ng-container--->`.
20521 const insertInFrontOf = parentTNode && (parentTNode.type & 8 /* ElementContainer */) ?
20522 lView[parentTNode.index] :
20523 null;
20524 applyCreateOpCodes(lView, tI18n.create, parentRNode, insertInFrontOf);
20525 setInI18nBlock(true);
20526}
20527/**
20528 * Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes
20529 * into the render tree, moves the placeholder nodes and removes the deleted nodes.
20530 *
20531 * @codeGenApi
20532 */
20533function ɵɵi18nEnd() {
20534 setInI18nBlock(false);
20535}
20536/**
20537 *
20538 * Use this instruction to create a translation block that doesn't contain any placeholder.
20539 * It calls both {@link i18nStart} and {@link i18nEnd} in one instruction.
20540 *
20541 * The translation `message` is the value which is locale specific. The translation string may
20542 * contain placeholders which associate inner elements and sub-templates within the translation.
20543 *
20544 * The translation `message` placeholders are:
20545 * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
20546 * interpolated into. The placeholder `index` points to the expression binding index. An optional
20547 * `block` that matches the sub-template in which it was declared.
20548 * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
20549 * and end of DOM element that were embedded in the original translation block. The placeholder
20550 * `index` points to the element index in the template instructions set. An optional `block` that
20551 * matches the sub-template in which it was declared.
20552 * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
20553 * split up and translated separately in each angular template function. The `index` points to the
20554 * `template` instruction index. A `block` that matches the sub-template in which it was declared.
20555 *
20556 * @param index A unique index of the translation in the static block.
20557 * @param messageIndex An index of the translation message from the `def.consts` array.
20558 * @param subTemplateIndex Optional sub-template index in the `message`.
20559 *
20560 * @codeGenApi
20561 */
20562function ɵɵi18n(index, messageIndex, subTemplateIndex) {
20563 ɵɵi18nStart(index, messageIndex, subTemplateIndex);
20564 ɵɵi18nEnd();
20565}
20566/**
20567 * Marks a list of attributes as translatable.
20568 *
20569 * @param index A unique index in the static block
20570 * @param values
20571 *
20572 * @codeGenApi
20573 */
20574function ɵɵi18nAttributes(index, attrsIndex) {
20575 const tView = getTView();
20576 ngDevMode && assertDefined(tView, `tView should be defined`);
20577 const attrs = getConstant(tView.consts, attrsIndex);
20578 i18nAttributesFirstPass(tView, index + HEADER_OFFSET, attrs);
20579}
20580/**
20581 * Stores the values of the bindings during each update cycle in order to determine if we need to
20582 * update the translated nodes.
20583 *
20584 * @param value The binding's value
20585 * @returns This function returns itself so that it may be chained
20586 * (e.g. `i18nExp(ctx.name)(ctx.title)`)
20587 *
20588 * @codeGenApi
20589 */
20590function ɵɵi18nExp(value) {
20591 const lView = getLView();
20592 setMaskBit(bindingUpdated(lView, nextBindingIndex(), value));
20593 return ɵɵi18nExp;
20594}
20595/**
20596 * Updates a translation block or an i18n attribute when the bindings have changed.
20597 *
20598 * @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes}
20599 * (i18n attribute) on which it should update the content.
20600 *
20601 * @codeGenApi
20602 */
20603function ɵɵi18nApply(index) {
20604 applyI18n(getTView(), getLView(), index + HEADER_OFFSET);
20605}
20606/**
20607 * Handles message string post-processing for internationalization.
20608 *
20609 * Handles message string post-processing by transforming it from intermediate
20610 * format (that might contain some markers that we need to replace) to the final
20611 * form, consumable by i18nStart instruction. Post processing steps include:
20612 *
20613 * 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�])
20614 * 2. Replace all ICU vars (like "VAR_PLURAL")
20615 * 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
20616 * 4. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�)
20617 * in case multiple ICUs have the same placeholder name
20618 *
20619 * @param message Raw translation string for post processing
20620 * @param replacements Set of replacements that should be applied
20621 *
20622 * @returns Transformed string that can be consumed by i18nStart instruction
20623 *
20624 * @codeGenApi
20625 */
20626function ɵɵi18nPostprocess(message, replacements = {}) {
20627 return i18nPostprocess(message, replacements);
20628}
20629
20630/**
20631 * @license
20632 * Copyright Google LLC All Rights Reserved.
20633 *
20634 * Use of this source code is governed by an MIT-style license that can be
20635 * found in the LICENSE file at https://angular.io/license
20636 */
20637
20638/**
20639 * @license
20640 * Copyright Google LLC All Rights Reserved.
20641 *
20642 * Use of this source code is governed by an MIT-style license that can be
20643 * found in the LICENSE file at https://angular.io/license
20644 */
20645/**
20646 * Resolves the providers which are defined in the DirectiveDef.
20647 *
20648 * When inserting the tokens and the factories in their respective arrays, we can assume that
20649 * this method is called first for the component (if any), and then for other directives on the same
20650 * node.
20651 * As a consequence,the providers are always processed in that order:
20652 * 1) The view providers of the component
20653 * 2) The providers of the component
20654 * 3) The providers of the other directives
20655 * This matches the structure of the injectables arrays of a view (for each node).
20656 * So the tokens and the factories can be pushed at the end of the arrays, except
20657 * in one case for multi providers.
20658 *
20659 * @param def the directive definition
20660 * @param providers: Array of `providers`.
20661 * @param viewProviders: Array of `viewProviders`.
20662 */
20663function providersResolver(def, providers, viewProviders) {
20664 const tView = getTView();
20665 if (tView.firstCreatePass) {
20666 const isComponent = isComponentDef(def);
20667 // The list of view providers is processed first, and the flags are updated
20668 resolveProvider(viewProviders, tView.data, tView.blueprint, isComponent, true);
20669 // Then, the list of providers is processed, and the flags are updated
20670 resolveProvider(providers, tView.data, tView.blueprint, isComponent, false);
20671 }
20672}
20673/**
20674 * Resolves a provider and publishes it to the DI system.
20675 */
20676function resolveProvider(provider, tInjectables, lInjectablesBlueprint, isComponent, isViewProvider) {
20677 provider = resolveForwardRef(provider);
20678 if (Array.isArray(provider)) {
20679 // Recursively call `resolveProvider`
20680 // Recursion is OK in this case because this code will not be in hot-path once we implement
20681 // cloning of the initial state.
20682 for (let i = 0; i < provider.length; i++) {
20683 resolveProvider(provider[i], tInjectables, lInjectablesBlueprint, isComponent, isViewProvider);
20684 }
20685 }
20686 else {
20687 const tView = getTView();
20688 const lView = getLView();
20689 let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider.provide);
20690 let providerFactory = providerToFactory(provider);
20691 const tNode = getCurrentTNode();
20692 const beginIndex = tNode.providerIndexes & 1048575 /* ProvidersStartIndexMask */;
20693 const endIndex = tNode.directiveStart;
20694 const cptViewProvidersCount = tNode.providerIndexes >> 20 /* CptViewProvidersCountShift */;
20695 if (isTypeProvider(provider) || !provider.multi) {
20696 // Single provider case: the factory is created and pushed immediately
20697 const factory = new NodeInjectorFactory(providerFactory, isViewProvider, ɵɵdirectiveInject);
20698 const existingFactoryIndex = indexOf(token, tInjectables, isViewProvider ? beginIndex : beginIndex + cptViewProvidersCount, endIndex);
20699 if (existingFactoryIndex === -1) {
20700 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, token);
20701 registerDestroyHooksIfSupported(tView, provider, tInjectables.length);
20702 tInjectables.push(token);
20703 tNode.directiveStart++;
20704 tNode.directiveEnd++;
20705 if (isViewProvider) {
20706 tNode.providerIndexes += 1048576 /* CptViewProvidersCountShifter */;
20707 }
20708 lInjectablesBlueprint.push(factory);
20709 lView.push(factory);
20710 }
20711 else {
20712 lInjectablesBlueprint[existingFactoryIndex] = factory;
20713 lView[existingFactoryIndex] = factory;
20714 }
20715 }
20716 else {
20717 // Multi provider case:
20718 // We create a multi factory which is going to aggregate all the values.
20719 // Since the output of such a factory depends on content or view injection,
20720 // we create two of them, which are linked together.
20721 //
20722 // The first one (for view providers) is always in the first block of the injectables array,
20723 // and the second one (for providers) is always in the second block.
20724 // This is important because view providers have higher priority. When a multi token
20725 // is being looked up, the view providers should be found first.
20726 // Note that it is not possible to have a multi factory in the third block (directive block).
20727 //
20728 // The algorithm to process multi providers is as follows:
20729 // 1) If the multi provider comes from the `viewProviders` of the component:
20730 // a) If the special view providers factory doesn't exist, it is created and pushed.
20731 // b) Else, the multi provider is added to the existing multi factory.
20732 // 2) If the multi provider comes from the `providers` of the component or of another
20733 // directive:
20734 // a) If the multi factory doesn't exist, it is created and provider pushed into it.
20735 // It is also linked to the multi factory for view providers, if it exists.
20736 // b) Else, the multi provider is added to the existing multi factory.
20737 const existingProvidersFactoryIndex = indexOf(token, tInjectables, beginIndex + cptViewProvidersCount, endIndex);
20738 const existingViewProvidersFactoryIndex = indexOf(token, tInjectables, beginIndex, beginIndex + cptViewProvidersCount);
20739 const doesProvidersFactoryExist = existingProvidersFactoryIndex >= 0 &&
20740 lInjectablesBlueprint[existingProvidersFactoryIndex];
20741 const doesViewProvidersFactoryExist = existingViewProvidersFactoryIndex >= 0 &&
20742 lInjectablesBlueprint[existingViewProvidersFactoryIndex];
20743 if (isViewProvider && !doesViewProvidersFactoryExist ||
20744 !isViewProvider && !doesProvidersFactoryExist) {
20745 // Cases 1.a and 2.a
20746 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, token);
20747 const factory = multiFactory(isViewProvider ? multiViewProvidersFactoryResolver : multiProvidersFactoryResolver, lInjectablesBlueprint.length, isViewProvider, isComponent, providerFactory);
20748 if (!isViewProvider && doesViewProvidersFactoryExist) {
20749 lInjectablesBlueprint[existingViewProvidersFactoryIndex].providerFactory = factory;
20750 }
20751 registerDestroyHooksIfSupported(tView, provider, tInjectables.length, 0);
20752 tInjectables.push(token);
20753 tNode.directiveStart++;
20754 tNode.directiveEnd++;
20755 if (isViewProvider) {
20756 tNode.providerIndexes += 1048576 /* CptViewProvidersCountShifter */;
20757 }
20758 lInjectablesBlueprint.push(factory);
20759 lView.push(factory);
20760 }
20761 else {
20762 // Cases 1.b and 2.b
20763 const indexInFactory = multiFactoryAdd(lInjectablesBlueprint[isViewProvider ? existingViewProvidersFactoryIndex :
20764 existingProvidersFactoryIndex], providerFactory, !isViewProvider && isComponent);
20765 registerDestroyHooksIfSupported(tView, provider, existingProvidersFactoryIndex > -1 ? existingProvidersFactoryIndex :
20766 existingViewProvidersFactoryIndex, indexInFactory);
20767 }
20768 if (!isViewProvider && isComponent && doesViewProvidersFactoryExist) {
20769 lInjectablesBlueprint[existingViewProvidersFactoryIndex].componentProviders++;
20770 }
20771 }
20772 }
20773}
20774/**
20775 * Registers the `ngOnDestroy` hook of a provider, if the provider supports destroy hooks.
20776 * @param tView `TView` in which to register the hook.
20777 * @param provider Provider whose hook should be registered.
20778 * @param contextIndex Index under which to find the context for the hook when it's being invoked.
20779 * @param indexInFactory Only required for `multi` providers. Index of the provider in the multi
20780 * provider factory.
20781 */
20782function registerDestroyHooksIfSupported(tView, provider, contextIndex, indexInFactory) {
20783 const providerIsTypeProvider = isTypeProvider(provider);
20784 const providerIsClassProvider = isClassProvider(provider);
20785 if (providerIsTypeProvider || providerIsClassProvider) {
20786 // Resolve forward references as `useClass` can hold a forward reference.
20787 const classToken = providerIsClassProvider ? resolveForwardRef(provider.useClass) : provider;
20788 const prototype = classToken.prototype;
20789 const ngOnDestroy = prototype.ngOnDestroy;
20790 if (ngOnDestroy) {
20791 const hooks = tView.destroyHooks || (tView.destroyHooks = []);
20792 if (!providerIsTypeProvider && provider.multi) {
20793 ngDevMode &&
20794 assertDefined(indexInFactory, 'indexInFactory when registering multi factory destroy hook');
20795 const existingCallbacksIndex = hooks.indexOf(contextIndex);
20796 if (existingCallbacksIndex === -1) {
20797 hooks.push(contextIndex, [indexInFactory, ngOnDestroy]);
20798 }
20799 else {
20800 hooks[existingCallbacksIndex + 1].push(indexInFactory, ngOnDestroy);
20801 }
20802 }
20803 else {
20804 hooks.push(contextIndex, ngOnDestroy);
20805 }
20806 }
20807 }
20808}
20809/**
20810 * Add a factory in a multi factory.
20811 * @returns Index at which the factory was inserted.
20812 */
20813function multiFactoryAdd(multiFactory, factory, isComponentProvider) {
20814 if (isComponentProvider) {
20815 multiFactory.componentProviders++;
20816 }
20817 return multiFactory.multi.push(factory) - 1;
20818}
20819/**
20820 * Returns the index of item in the array, but only in the begin to end range.
20821 */
20822function indexOf(item, arr, begin, end) {
20823 for (let i = begin; i < end; i++) {
20824 if (arr[i] === item)
20825 return i;
20826 }
20827 return -1;
20828}
20829/**
20830 * Use this with `multi` `providers`.
20831 */
20832function multiProvidersFactoryResolver(_, tData, lData, tNode) {
20833 return multiResolve(this.multi, []);
20834}
20835/**
20836 * Use this with `multi` `viewProviders`.
20837 *
20838 * This factory knows how to concatenate itself with the existing `multi` `providers`.
20839 */
20840function multiViewProvidersFactoryResolver(_, tData, lView, tNode) {
20841 const factories = this.multi;
20842 let result;
20843 if (this.providerFactory) {
20844 const componentCount = this.providerFactory.componentProviders;
20845 const multiProviders = getNodeInjectable(lView, lView[TVIEW], this.providerFactory.index, tNode);
20846 // Copy the section of the array which contains `multi` `providers` from the component
20847 result = multiProviders.slice(0, componentCount);
20848 // Insert the `viewProvider` instances.
20849 multiResolve(factories, result);
20850 // Copy the section of the array which contains `multi` `providers` from other directives
20851 for (let i = componentCount; i < multiProviders.length; i++) {
20852 result.push(multiProviders[i]);
20853 }
20854 }
20855 else {
20856 result = [];
20857 // Insert the `viewProvider` instances.
20858 multiResolve(factories, result);
20859 }
20860 return result;
20861}
20862/**
20863 * Maps an array of factories into an array of values.
20864 */
20865function multiResolve(factories, result) {
20866 for (let i = 0; i < factories.length; i++) {
20867 const factory = factories[i];
20868 result.push(factory());
20869 }
20870 return result;
20871}
20872/**
20873 * Creates a multi factory.
20874 */
20875function multiFactory(factoryFn, index, isViewProvider, isComponent, f) {
20876 const factory = new NodeInjectorFactory(factoryFn, isViewProvider, ɵɵdirectiveInject);
20877 factory.multi = [];
20878 factory.index = index;
20879 factory.componentProviders = 0;
20880 multiFactoryAdd(factory, f, isComponent && !isViewProvider);
20881 return factory;
20882}
20883
20884/**
20885 * This feature resolves the providers of a directive (or component),
20886 * and publish them into the DI system, making it visible to others for injection.
20887 *
20888 * For example:
20889 * ```ts
20890 * class ComponentWithProviders {
20891 * constructor(private greeter: GreeterDE) {}
20892 *
20893 * static ɵcmp = defineComponent({
20894 * type: ComponentWithProviders,
20895 * selectors: [['component-with-providers']],
20896 * factory: () => new ComponentWithProviders(directiveInject(GreeterDE as any)),
20897 * decls: 1,
20898 * vars: 1,
20899 * template: function(fs: RenderFlags, ctx: ComponentWithProviders) {
20900 * if (fs & RenderFlags.Create) {
20901 * ɵɵtext(0);
20902 * }
20903 * if (fs & RenderFlags.Update) {
20904 * ɵɵtextInterpolate(ctx.greeter.greet());
20905 * }
20906 * },
20907 * features: [ɵɵProvidersFeature([GreeterDE])]
20908 * });
20909 * }
20910 * ```
20911 *
20912 * @param definition
20913 *
20914 * @codeGenApi
20915 */
20916function ɵɵProvidersFeature(providers, viewProviders = []) {
20917 return (definition) => {
20918 definition.providersResolver =
20919 (def, processProvidersFn) => {
20920 return providersResolver(def, //
20921 processProvidersFn ? processProvidersFn(providers) : providers, //
20922 viewProviders);
20923 };
20924 };
20925}
20926
20927/**
20928 * @license
20929 * Copyright Google LLC All Rights Reserved.
20930 *
20931 * Use of this source code is governed by an MIT-style license that can be
20932 * found in the LICENSE file at https://angular.io/license
20933 */
20934/**
20935 * Represents a component created by a `ComponentFactory`.
20936 * Provides access to the component instance and related objects,
20937 * and provides the means of destroying the instance.
20938 *
20939 * @publicApi
20940 */
20941class ComponentRef$1 {
20942}
20943/**
20944 * Base class for a factory that can create a component dynamically.
20945 * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
20946 * Use the resulting `ComponentFactory.create()` method to create a component of that type.
20947 *
20948 * @see [Dynamic Components](guide/dynamic-component-loader)
20949 *
20950 * @publicApi
20951 *
20952 * @deprecated Angular no longer requires Component factories. Please use other APIs where
20953 * Component class can be used directly.
20954 */
20955class ComponentFactory$1 {
20956}
20957
20958/**
20959 * @license
20960 * Copyright Google LLC All Rights Reserved.
20961 *
20962 * Use of this source code is governed by an MIT-style license that can be
20963 * found in the LICENSE file at https://angular.io/license
20964 */
20965function noComponentFactoryError(component) {
20966 const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
20967 error[ERROR_COMPONENT] = component;
20968 return error;
20969}
20970const ERROR_COMPONENT = 'ngComponent';
20971function getComponent(error) {
20972 return error[ERROR_COMPONENT];
20973}
20974class _NullComponentFactoryResolver {
20975 resolveComponentFactory(component) {
20976 throw noComponentFactoryError(component);
20977 }
20978}
20979/**
20980 * A simple registry that maps `Components` to generated `ComponentFactory` classes
20981 * that can be used to create instances of components.
20982 * Use to obtain the factory for a given component type,
20983 * then use the factory's `create()` method to create a component of that type.
20984 *
20985 * Note: since v13, dynamic component creation via
20986 * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
20987 * does **not** require resolving component factory: component class can be used directly.
20988 *
20989 * @publicApi
20990 *
20991 * @deprecated Angular no longer requires Component factories. Please use other APIs where
20992 * Component class can be used directly.
20993 */
20994class ComponentFactoryResolver$1 {
20995}
20996ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
20997
20998/**
20999 * @license
21000 * Copyright Google LLC All Rights Reserved.
21001 *
21002 * Use of this source code is governed by an MIT-style license that can be
21003 * found in the LICENSE file at https://angular.io/license
21004 */
21005/**
21006 * Creates an ElementRef from the most recent node.
21007 *
21008 * @returns The ElementRef instance to use
21009 */
21010function injectElementRef() {
21011 return createElementRef(getCurrentTNode(), getLView());
21012}
21013/**
21014 * Creates an ElementRef given a node.
21015 *
21016 * @param tNode The node for which you'd like an ElementRef
21017 * @param lView The view to which the node belongs
21018 * @returns The ElementRef instance to use
21019 */
21020function createElementRef(tNode, lView) {
21021 return new ElementRef(getNativeByTNode(tNode, lView));
21022}
21023/**
21024 * A wrapper around a native element inside of a View.
21025 *
21026 * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
21027 * element.
21028 *
21029 * @security Permitting direct access to the DOM can make your application more vulnerable to
21030 * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
21031 * [Security Guide](https://g.co/ng/security).
21032 *
21033 * @publicApi
21034 */
21035// Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
21036// i.e. users have to ask for what they need. With that, we can build better analysis tools
21037// and could do better codegen in the future.
21038class ElementRef {
21039 constructor(nativeElement) {
21040 this.nativeElement = nativeElement;
21041 }
21042}
21043/**
21044 * @internal
21045 * @nocollapse
21046 */
21047ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
21048/**
21049 * Unwraps `ElementRef` and return the `nativeElement`.
21050 *
21051 * @param value value to unwrap
21052 * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
21053 */
21054function unwrapElementRef(value) {
21055 return value instanceof ElementRef ? value.nativeElement : value;
21056}
21057
21058/**
21059 * @license
21060 * Copyright Google LLC All Rights Reserved.
21061 *
21062 * Use of this source code is governed by an MIT-style license that can be
21063 * found in the LICENSE file at https://angular.io/license
21064 */
21065const Renderer2Interceptor = new InjectionToken('Renderer2Interceptor');
21066/**
21067 * Creates and initializes a custom renderer that implements the `Renderer2` base class.
21068 *
21069 * @publicApi
21070 */
21071class RendererFactory2 {
21072}
21073/**
21074 * Extend this base class to implement custom rendering. By default, Angular
21075 * renders a template into DOM. You can use custom rendering to intercept
21076 * rendering calls, or to render to something other than DOM.
21077 *
21078 * Create your custom renderer using `RendererFactory2`.
21079 *
21080 * Use a custom renderer to bypass Angular's templating and
21081 * make custom UI changes that can't be expressed declaratively.
21082 * For example if you need to set a property or an attribute whose name is
21083 * not statically known, use the `setProperty()` or
21084 * `setAttribute()` method.
21085 *
21086 * @publicApi
21087 */
21088class Renderer2 {
21089}
21090/**
21091 * @internal
21092 * @nocollapse
21093 */
21094Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
21095/** Returns a Renderer2 (or throws when application was bootstrapped with Renderer3) */
21096function getOrCreateRenderer2(lView) {
21097 const renderer = lView[RENDERER];
21098 if (ngDevMode && !isProceduralRenderer(renderer)) {
21099 throw new Error('Cannot inject Renderer2 when the application uses Renderer3!');
21100 }
21101 return renderer;
21102}
21103/** Injects a Renderer2 for the current component. */
21104function injectRenderer2() {
21105 // We need the Renderer to be based on the component that it's being injected into, however since
21106 // DI happens before we've entered its view, `getLView` will return the parent view instead.
21107 const lView = getLView();
21108 const tNode = getCurrentTNode();
21109 const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
21110 return getOrCreateRenderer2(isLView(nodeAtIndex) ? nodeAtIndex : lView);
21111}
21112
21113/**
21114 * @license
21115 * Copyright Google LLC All Rights Reserved.
21116 *
21117 * Use of this source code is governed by an MIT-style license that can be
21118 * found in the LICENSE file at https://angular.io/license
21119 */
21120/**
21121 * Sanitizer is used by the views to sanitize potentially dangerous values.
21122 *
21123 * @publicApi
21124 */
21125class Sanitizer {
21126}
21127/** @nocollapse */
21128Sanitizer.ɵprov = ɵɵdefineInjectable({
21129 token: Sanitizer,
21130 providedIn: 'root',
21131 factory: () => null,
21132});
21133
21134/**
21135 * @license
21136 * Copyright Google LLC All Rights Reserved.
21137 *
21138 * Use of this source code is governed by an MIT-style license that can be
21139 * found in the LICENSE file at https://angular.io/license
21140 */
21141/**
21142 * @description Represents the version of Angular
21143 *
21144 * @publicApi
21145 */
21146class Version {
21147 constructor(full) {
21148 this.full = full;
21149 this.major = full.split('.')[0];
21150 this.minor = full.split('.')[1];
21151 this.patch = full.split('.').slice(2).join('.');
21152 }
21153}
21154/**
21155 * @publicApi
21156 */
21157const VERSION = new Version('13.3.9');
21158
21159/**
21160 * @license
21161 * Copyright Google LLC All Rights Reserved.
21162 *
21163 * Use of this source code is governed by an MIT-style license that can be
21164 * found in the LICENSE file at https://angular.io/license
21165 */
21166// This default value is when checking the hierarchy for a token.
21167//
21168// It means both:
21169// - the token is not provided by the current injector,
21170// - only the element injectors should be checked (ie do not check module injectors
21171//
21172// mod1
21173// /
21174// el1 mod2
21175// \ /
21176// el2
21177//
21178// When requesting el2.injector.get(token), we should check in the following order and return the
21179// first found value:
21180// - el2.injector.get(token, default)
21181// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
21182// - mod2.injector.get(token, default)
21183const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
21184
21185/**
21186 * @license
21187 * Copyright Google LLC All Rights Reserved.
21188 *
21189 * Use of this source code is governed by an MIT-style license that can be
21190 * found in the LICENSE file at https://angular.io/license
21191 */
21192function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
21193 while (tNode !== null) {
21194 ngDevMode &&
21195 assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */ | 16 /* Projection */ | 32 /* Icu */);
21196 const lNode = lView[tNode.index];
21197 if (lNode !== null) {
21198 result.push(unwrapRNode(lNode));
21199 }
21200 // A given lNode can represent either a native node or a LContainer (when it is a host of a
21201 // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
21202 // from the views in this container.
21203 if (isLContainer(lNode)) {
21204 for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
21205 const lViewInAContainer = lNode[i];
21206 const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
21207 if (lViewFirstChildTNode !== null) {
21208 collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
21209 }
21210 }
21211 }
21212 const tNodeType = tNode.type;
21213 if (tNodeType & 8 /* ElementContainer */) {
21214 collectNativeNodes(tView, lView, tNode.child, result);
21215 }
21216 else if (tNodeType & 32 /* Icu */) {
21217 const nextRNode = icuContainerIterate(tNode, lView);
21218 let rNode;
21219 while (rNode = nextRNode()) {
21220 result.push(rNode);
21221 }
21222 }
21223 else if (tNodeType & 16 /* Projection */) {
21224 const nodesInSlot = getProjectionNodes(lView, tNode);
21225 if (Array.isArray(nodesInSlot)) {
21226 result.push(...nodesInSlot);
21227 }
21228 else {
21229 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
21230 ngDevMode && assertParentView(parentView);
21231 collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
21232 }
21233 }
21234 tNode = isProjection ? tNode.projectionNext : tNode.next;
21235 }
21236 return result;
21237}
21238
21239/**
21240 * @license
21241 * Copyright Google LLC All Rights Reserved.
21242 *
21243 * Use of this source code is governed by an MIT-style license that can be
21244 * found in the LICENSE file at https://angular.io/license
21245 */
21246class ViewRef$1 {
21247 constructor(
21248 /**
21249 * This represents `LView` associated with the component when ViewRef is a ChangeDetectorRef.
21250 *
21251 * When ViewRef is created for a dynamic component, this also represents the `LView` for the
21252 * component.
21253 *
21254 * For a "regular" ViewRef created for an embedded view, this is the `LView` for the embedded
21255 * view.
21256 *
21257 * @internal
21258 */
21259 _lView,
21260 /**
21261 * This represents the `LView` associated with the point where `ChangeDetectorRef` was
21262 * requested.
21263 *
21264 * This may be different from `_lView` if the `_cdRefInjectingView` is an embedded view.
21265 */
21266 _cdRefInjectingView) {
21267 this._lView = _lView;
21268 this._cdRefInjectingView = _cdRefInjectingView;
21269 this._appRef = null;
21270 this._attachedToViewContainer = false;
21271 }
21272 get rootNodes() {
21273 const lView = this._lView;
21274 const tView = lView[TVIEW];
21275 return collectNativeNodes(tView, lView, tView.firstChild, []);
21276 }
21277 get context() {
21278 return this._lView[CONTEXT];
21279 }
21280 set context(value) {
21281 this._lView[CONTEXT] = value;
21282 }
21283 get destroyed() {
21284 return (this._lView[FLAGS] & 256 /* Destroyed */) === 256 /* Destroyed */;
21285 }
21286 destroy() {
21287 if (this._appRef) {
21288 this._appRef.detachView(this);
21289 }
21290 else if (this._attachedToViewContainer) {
21291 const parent = this._lView[PARENT];
21292 if (isLContainer(parent)) {
21293 const viewRefs = parent[VIEW_REFS];
21294 const index = viewRefs ? viewRefs.indexOf(this) : -1;
21295 if (index > -1) {
21296 ngDevMode &&
21297 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.');
21298 detachView(parent, index);
21299 removeFromArray(viewRefs, index);
21300 }
21301 }
21302 this._attachedToViewContainer = false;
21303 }
21304 destroyLView(this._lView[TVIEW], this._lView);
21305 }
21306 onDestroy(callback) {
21307 storeCleanupWithContext(this._lView[TVIEW], this._lView, null, callback);
21308 }
21309 /**
21310 * Marks a view and all of its ancestors dirty.
21311 *
21312 * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is
21313 * checked when it needs to be re-rendered but the two normal triggers haven't marked it
21314 * dirty (i.e. inputs haven't changed and events haven't fired in the view).
21315 *
21316 * <!-- TODO: Add a link to a chapter on OnPush components -->
21317 *
21318 * @usageNotes
21319 * ### Example
21320 *
21321 * ```typescript
21322 * @Component({
21323 * selector: 'app-root',
21324 * template: `Number of ticks: {{numberOfTicks}}`
21325 * changeDetection: ChangeDetectionStrategy.OnPush,
21326 * })
21327 * class AppComponent {
21328 * numberOfTicks = 0;
21329 *
21330 * constructor(private ref: ChangeDetectorRef) {
21331 * setInterval(() => {
21332 * this.numberOfTicks++;
21333 * // the following is required, otherwise the view will not be updated
21334 * this.ref.markForCheck();
21335 * }, 1000);
21336 * }
21337 * }
21338 * ```
21339 */
21340 markForCheck() {
21341 markViewDirty(this._cdRefInjectingView || this._lView);
21342 }
21343 /**
21344 * Detaches the view from the change detection tree.
21345 *
21346 * Detached views will not be checked during change detection runs until they are
21347 * re-attached, even if they are dirty. `detach` can be used in combination with
21348 * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change
21349 * detection checks.
21350 *
21351 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
21352 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
21353 *
21354 * @usageNotes
21355 * ### Example
21356 *
21357 * The following example defines a component with a large list of readonly data.
21358 * Imagine the data changes constantly, many times per second. For performance reasons,
21359 * we want to check and update the list every five seconds. We can do that by detaching
21360 * the component's change detector and doing a local check every five seconds.
21361 *
21362 * ```typescript
21363 * class DataProvider {
21364 * // in a real application the returned data will be different every time
21365 * get data() {
21366 * return [1,2,3,4,5];
21367 * }
21368 * }
21369 *
21370 * @Component({
21371 * selector: 'giant-list',
21372 * template: `
21373 * <li *ngFor="let d of dataProvider.data">Data {{d}}</li>
21374 * `,
21375 * })
21376 * class GiantList {
21377 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {
21378 * ref.detach();
21379 * setInterval(() => {
21380 * this.ref.detectChanges();
21381 * }, 5000);
21382 * }
21383 * }
21384 *
21385 * @Component({
21386 * selector: 'app',
21387 * providers: [DataProvider],
21388 * template: `
21389 * <giant-list><giant-list>
21390 * `,
21391 * })
21392 * class App {
21393 * }
21394 * ```
21395 */
21396 detach() {
21397 this._lView[FLAGS] &= ~128 /* Attached */;
21398 }
21399 /**
21400 * Re-attaches a view to the change detection tree.
21401 *
21402 * This can be used to re-attach views that were previously detached from the tree
21403 * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default.
21404 *
21405 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
21406 *
21407 * @usageNotes
21408 * ### Example
21409 *
21410 * The following example creates a component displaying `live` data. The component will detach
21411 * its change detector from the main change detector tree when the component's live property
21412 * is set to false.
21413 *
21414 * ```typescript
21415 * class DataProvider {
21416 * data = 1;
21417 *
21418 * constructor() {
21419 * setInterval(() => {
21420 * this.data = this.data * 2;
21421 * }, 500);
21422 * }
21423 * }
21424 *
21425 * @Component({
21426 * selector: 'live-data',
21427 * inputs: ['live'],
21428 * template: 'Data: {{dataProvider.data}}'
21429 * })
21430 * class LiveData {
21431 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {}
21432 *
21433 * set live(value) {
21434 * if (value) {
21435 * this.ref.reattach();
21436 * } else {
21437 * this.ref.detach();
21438 * }
21439 * }
21440 * }
21441 *
21442 * @Component({
21443 * selector: 'app-root',
21444 * providers: [DataProvider],
21445 * template: `
21446 * Live Update: <input type="checkbox" [(ngModel)]="live">
21447 * <live-data [live]="live"><live-data>
21448 * `,
21449 * })
21450 * class AppComponent {
21451 * live = true;
21452 * }
21453 * ```
21454 */
21455 reattach() {
21456 this._lView[FLAGS] |= 128 /* Attached */;
21457 }
21458 /**
21459 * Checks the view and its children.
21460 *
21461 * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement
21462 * local change detection checks.
21463 *
21464 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
21465 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
21466 *
21467 * @usageNotes
21468 * ### Example
21469 *
21470 * The following example defines a component with a large list of readonly data.
21471 * Imagine, the data changes constantly, many times per second. For performance reasons,
21472 * we want to check and update the list every five seconds.
21473 *
21474 * We can do that by detaching the component's change detector and doing a local change detection
21475 * check every five seconds.
21476 *
21477 * See {@link ChangeDetectorRef#detach detach} for more information.
21478 */
21479 detectChanges() {
21480 detectChangesInternal(this._lView[TVIEW], this._lView, this.context);
21481 }
21482 /**
21483 * Checks the change detector and its children, and throws if any changes are detected.
21484 *
21485 * This is used in development mode to verify that running change detection doesn't
21486 * introduce other changes.
21487 */
21488 checkNoChanges() {
21489 if (ngDevMode) {
21490 checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
21491 }
21492 }
21493 attachToViewContainerRef() {
21494 if (this._appRef) {
21495 const errorMessage = ngDevMode ? 'This view is already attached directly to the ApplicationRef!' : '';
21496 throw new RuntimeError(902 /* VIEW_ALREADY_ATTACHED */, errorMessage);
21497 }
21498 this._attachedToViewContainer = true;
21499 }
21500 detachFromAppRef() {
21501 this._appRef = null;
21502 renderDetachView(this._lView[TVIEW], this._lView);
21503 }
21504 attachToAppRef(appRef) {
21505 if (this._attachedToViewContainer) {
21506 const errorMessage = ngDevMode ? 'This view is already attached to a ViewContainer!' : '';
21507 throw new RuntimeError(902 /* VIEW_ALREADY_ATTACHED */, errorMessage);
21508 }
21509 this._appRef = appRef;
21510 }
21511}
21512/** @internal */
21513class RootViewRef extends ViewRef$1 {
21514 constructor(_view) {
21515 super(_view);
21516 this._view = _view;
21517 }
21518 detectChanges() {
21519 detectChangesInRootView(this._view);
21520 }
21521 checkNoChanges() {
21522 if (ngDevMode) {
21523 checkNoChangesInRootView(this._view);
21524 }
21525 }
21526 get context() {
21527 return null;
21528 }
21529}
21530
21531/**
21532 * @license
21533 * Copyright Google LLC All Rights Reserved.
21534 *
21535 * Use of this source code is governed by an MIT-style license that can be
21536 * found in the LICENSE file at https://angular.io/license
21537 */
21538class ComponentFactoryResolver extends ComponentFactoryResolver$1 {
21539 /**
21540 * @param ngModule The NgModuleRef to which all resolved factories are bound.
21541 */
21542 constructor(ngModule) {
21543 super();
21544 this.ngModule = ngModule;
21545 }
21546 resolveComponentFactory(component) {
21547 ngDevMode && assertComponentType(component);
21548 const componentDef = getComponentDef(component);
21549 return new ComponentFactory(componentDef, this.ngModule);
21550 }
21551}
21552function toRefArray(map) {
21553 const array = [];
21554 for (let nonMinified in map) {
21555 if (map.hasOwnProperty(nonMinified)) {
21556 const minified = map[nonMinified];
21557 array.push({ propName: minified, templateName: nonMinified });
21558 }
21559 }
21560 return array;
21561}
21562function getNamespace(elementName) {
21563 const name = elementName.toLowerCase();
21564 return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null);
21565}
21566function createChainedInjector(rootViewInjector, moduleInjector) {
21567 return {
21568 get: (token, notFoundValue, flags) => {
21569 const value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
21570 if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
21571 notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
21572 // Return the value from the root element injector when
21573 // - it provides it
21574 // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
21575 // - the module injector should not be checked
21576 // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
21577 return value;
21578 }
21579 return moduleInjector.get(token, notFoundValue, flags);
21580 }
21581 };
21582}
21583/**
21584 * Render3 implementation of {@link viewEngine_ComponentFactory}.
21585 */
21586class ComponentFactory extends ComponentFactory$1 {
21587 /**
21588 * @param componentDef The component definition.
21589 * @param ngModule The NgModuleRef to which the factory is bound.
21590 */
21591 constructor(componentDef, ngModule) {
21592 super();
21593 this.componentDef = componentDef;
21594 this.ngModule = ngModule;
21595 this.componentType = componentDef.type;
21596 this.selector = stringifyCSSSelectorList(componentDef.selectors);
21597 this.ngContentSelectors =
21598 componentDef.ngContentSelectors ? componentDef.ngContentSelectors : [];
21599 this.isBoundToModule = !!ngModule;
21600 }
21601 get inputs() {
21602 return toRefArray(this.componentDef.inputs);
21603 }
21604 get outputs() {
21605 return toRefArray(this.componentDef.outputs);
21606 }
21607 create(injector, projectableNodes, rootSelectorOrNode, ngModule) {
21608 ngModule = ngModule || this.ngModule;
21609 const rootViewInjector = ngModule ? createChainedInjector(injector, ngModule.injector) : injector;
21610 const rendererFactory = rootViewInjector.get(RendererFactory2, domRendererFactory3);
21611 const sanitizer = rootViewInjector.get(Sanitizer, null);
21612 const hostRenderer = rendererFactory.createRenderer(null, this.componentDef);
21613 // Determine a tag name used for creating host elements when this component is created
21614 // dynamically. Default to 'div' if this component did not specify any tag name in its selector.
21615 const elementName = this.componentDef.selectors[0][0] || 'div';
21616 const hostRNode = rootSelectorOrNode ?
21617 locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) :
21618 createElementNode(rendererFactory.createRenderer(null, this.componentDef), elementName, getNamespace(elementName));
21619 const rootFlags = this.componentDef.onPush ? 64 /* Dirty */ | 512 /* IsRoot */ :
21620 16 /* CheckAlways */ | 512 /* IsRoot */;
21621 const rootContext = createRootContext();
21622 // Create the root view. Uses empty TView and ContentTemplate.
21623 const rootTView = createTView(0 /* Root */, null, null, 1, 0, null, null, null, null, null);
21624 const rootLView = createLView(null, rootTView, rootContext, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector);
21625 // rootView is the parent when bootstrapping
21626 // TODO(misko): it looks like we are entering view here but we don't really need to as
21627 // `renderView` does that. However as the code is written it is needed because
21628 // `createRootComponentView` and `createRootComponent` both read global state. Fixing those
21629 // issues would allow us to drop this.
21630 enterView(rootLView);
21631 let component;
21632 let tElementNode;
21633 try {
21634 const componentView = createRootComponentView(hostRNode, this.componentDef, rootLView, rendererFactory, hostRenderer);
21635 if (hostRNode) {
21636 if (rootSelectorOrNode) {
21637 setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]);
21638 }
21639 else {
21640 // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
21641 // is not defined), also apply attributes and classes extracted from component selector.
21642 // Extract attributes and classes from the first selector only to match VE behavior.
21643 const { attrs, classes } = extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
21644 if (attrs) {
21645 setUpAttributes(hostRenderer, hostRNode, attrs);
21646 }
21647 if (classes && classes.length > 0) {
21648 writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
21649 }
21650 }
21651 }
21652 tElementNode = getTNode(rootTView, HEADER_OFFSET);
21653 if (projectableNodes !== undefined) {
21654 const projection = tElementNode.projection = [];
21655 for (let i = 0; i < this.ngContentSelectors.length; i++) {
21656 const nodesforSlot = projectableNodes[i];
21657 // Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
21658 // case). Here we do normalize passed data structure to be an array of arrays to avoid
21659 // complex checks down the line.
21660 // We also normalize the length of the passed in projectable nodes (to match the number of
21661 // <ng-container> slots defined by a component).
21662 projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
21663 }
21664 }
21665 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
21666 // executed here?
21667 // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
21668 component = createRootComponent(componentView, this.componentDef, rootLView, rootContext, [LifecycleHooksFeature]);
21669 renderView(rootTView, rootLView, null);
21670 }
21671 finally {
21672 leaveView();
21673 }
21674 return new ComponentRef(this.componentType, component, createElementRef(tElementNode, rootLView), rootLView, tElementNode);
21675 }
21676}
21677const componentFactoryResolver = new ComponentFactoryResolver();
21678/**
21679 * Creates a ComponentFactoryResolver and stores it on the injector. Or, if the
21680 * ComponentFactoryResolver
21681 * already exists, retrieves the existing ComponentFactoryResolver.
21682 *
21683 * @returns The ComponentFactoryResolver instance to use
21684 */
21685function injectComponentFactoryResolver() {
21686 return componentFactoryResolver;
21687}
21688/**
21689 * Represents an instance of a Component created via a {@link ComponentFactory}.
21690 *
21691 * `ComponentRef` provides access to the Component Instance as well other objects related to this
21692 * Component Instance and allows you to destroy the Component Instance via the {@link #destroy}
21693 * method.
21694 *
21695 */
21696class ComponentRef extends ComponentRef$1 {
21697 constructor(componentType, instance, location, _rootLView, _tNode) {
21698 super();
21699 this.location = location;
21700 this._rootLView = _rootLView;
21701 this._tNode = _tNode;
21702 this.instance = instance;
21703 this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView);
21704 this.componentType = componentType;
21705 }
21706 get injector() {
21707 return new NodeInjector(this._tNode, this._rootLView);
21708 }
21709 destroy() {
21710 this.hostView.destroy();
21711 }
21712 onDestroy(callback) {
21713 this.hostView.onDestroy(callback);
21714 }
21715}
21716
21717/**
21718 * @license
21719 * Copyright Google LLC All Rights Reserved.
21720 *
21721 * Use of this source code is governed by an MIT-style license that can be
21722 * found in the LICENSE file at https://angular.io/license
21723 */
21724/**
21725 * Adds decorator, constructor, and property metadata to a given type via static metadata fields
21726 * on the type.
21727 *
21728 * These metadata fields can later be read with Angular's `ReflectionCapabilities` API.
21729 *
21730 * Calls to `setClassMetadata` can be guarded by ngDevMode, resulting in the metadata assignments
21731 * being tree-shaken away during production builds.
21732 */
21733function setClassMetadata(type, decorators, ctorParameters, propDecorators) {
21734 return noSideEffects(() => {
21735 const clazz = type;
21736 if (decorators !== null) {
21737 if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) {
21738 clazz.decorators.push(...decorators);
21739 }
21740 else {
21741 clazz.decorators = decorators;
21742 }
21743 }
21744 if (ctorParameters !== null) {
21745 // Rather than merging, clobber the existing parameters. If other projects exist which
21746 // use tsickle-style annotations and reflect over them in the same way, this could
21747 // cause issues, but that is vanishingly unlikely.
21748 clazz.ctorParameters = ctorParameters;
21749 }
21750 if (propDecorators !== null) {
21751 // The property decorator objects are merged as it is possible different fields have
21752 // different decorator types. Decorators on individual fields are not merged, as it's
21753 // also incredibly unlikely that a field will be decorated both with an Angular
21754 // decorator and a non-Angular decorator that's also been downleveled.
21755 if (clazz.hasOwnProperty('propDecorators') && clazz.propDecorators !== undefined) {
21756 clazz.propDecorators = { ...clazz.propDecorators, ...propDecorators };
21757 }
21758 else {
21759 clazz.propDecorators = propDecorators;
21760 }
21761 }
21762 });
21763}
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/**
21773 * Represents an instance of an `NgModule` created by an `NgModuleFactory`.
21774 * Provides access to the `NgModule` instance and related objects.
21775 *
21776 * @publicApi
21777 */
21778class NgModuleRef$1 {
21779}
21780/**
21781 * @publicApi
21782 *
21783 * @deprecated
21784 * This class was mostly used as a part of ViewEngine-based JIT API and is no longer needed in Ivy
21785 * JIT mode. See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes)
21786 * for additional context. Angular provides APIs that accept NgModule classes directly (such as
21787 * [PlatformRef.bootstrapModule](api/core/PlatformRef#bootstrapModule) and
21788 * [createNgModuleRef](api/core/createNgModuleRef)), consider switching to those APIs instead of
21789 * using factory-based ones.
21790 */
21791class NgModuleFactory$1 {
21792}
21793
21794/**
21795 * @license
21796 * Copyright Google LLC All Rights Reserved.
21797 *
21798 * Use of this source code is governed by an MIT-style license that can be
21799 * found in the LICENSE file at https://angular.io/license
21800 */
21801/**
21802 * Map of module-id to the corresponding NgModule.
21803 * - In pre Ivy we track NgModuleFactory,
21804 * - In post Ivy we track the NgModuleType
21805 */
21806const modules = new Map();
21807/**
21808 * Registers a loaded module. Should only be called from generated NgModuleFactory code.
21809 * @publicApi
21810 */
21811function registerModuleFactory(id, factory) {
21812 const existing = modules.get(id);
21813 assertSameOrNotExisting(id, existing && existing.moduleType, factory.moduleType);
21814 modules.set(id, factory);
21815}
21816function assertSameOrNotExisting(id, type, incoming) {
21817 if (type && type !== incoming) {
21818 throw new Error(`Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`);
21819 }
21820}
21821function registerNgModuleType(ngModuleType) {
21822 const visited = new Set();
21823 recurse(ngModuleType);
21824 function recurse(ngModuleType) {
21825 // The imports array of an NgModule must refer to other NgModules,
21826 // so an error is thrown if no module definition is available.
21827 const def = getNgModuleDef(ngModuleType, /* throwNotFound */ true);
21828 const id = def.id;
21829 if (id !== null) {
21830 const existing = modules.get(id);
21831 assertSameOrNotExisting(id, existing, ngModuleType);
21832 modules.set(id, ngModuleType);
21833 }
21834 const imports = maybeUnwrapFn(def.imports);
21835 for (const i of imports) {
21836 if (!visited.has(i)) {
21837 visited.add(i);
21838 recurse(i);
21839 }
21840 }
21841 }
21842}
21843function clearModulesForTest() {
21844 modules.clear();
21845}
21846function getRegisteredNgModuleType(id) {
21847 return (modules.get(id) || autoRegisterModuleById[id]);
21848}
21849
21850/**
21851 * @license
21852 * Copyright Google LLC All Rights Reserved.
21853 *
21854 * Use of this source code is governed by an MIT-style license that can be
21855 * found in the LICENSE file at https://angular.io/license
21856 */
21857/**
21858 * Returns a new NgModuleRef instance based on the NgModule class and parent injector provided.
21859 * @param ngModule NgModule class.
21860 * @param parentInjector Optional injector instance to use as a parent for the module injector. If
21861 * not provided, `NullInjector` will be used instead.
21862 * @publicApi
21863 */
21864function createNgModuleRef(ngModule, parentInjector) {
21865 return new NgModuleRef(ngModule, parentInjector ?? null);
21866}
21867class NgModuleRef extends NgModuleRef$1 {
21868 constructor(ngModuleType, _parent) {
21869 super();
21870 this._parent = _parent;
21871 // tslint:disable-next-line:require-internal-with-underscore
21872 this._bootstrapComponents = [];
21873 this.injector = this;
21874 this.destroyCbs = [];
21875 // When bootstrapping a module we have a dependency graph that looks like this:
21876 // ApplicationRef -> ComponentFactoryResolver -> NgModuleRef. The problem is that if the
21877 // module being resolved tries to inject the ComponentFactoryResolver, it'll create a
21878 // circular dependency which will result in a runtime error, because the injector doesn't
21879 // exist yet. We work around the issue by creating the ComponentFactoryResolver ourselves
21880 // and providing it, rather than letting the injector resolve it.
21881 this.componentFactoryResolver = new ComponentFactoryResolver(this);
21882 const ngModuleDef = getNgModuleDef(ngModuleType);
21883 ngDevMode &&
21884 assertDefined(ngModuleDef, `NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`);
21885 this._bootstrapComponents = maybeUnwrapFn(ngModuleDef.bootstrap);
21886 this._r3Injector = createInjectorWithoutInjectorInstances(ngModuleType, _parent, [
21887 { provide: NgModuleRef$1, useValue: this }, {
21888 provide: ComponentFactoryResolver$1,
21889 useValue: this.componentFactoryResolver
21890 }
21891 ], stringify(ngModuleType));
21892 // We need to resolve the injector types separately from the injector creation, because
21893 // the module might be trying to use this ref in its constructor for DI which will cause a
21894 // circular error that will eventually error out, because the injector isn't created yet.
21895 this._r3Injector._resolveInjectorDefTypes();
21896 this.instance = this.get(ngModuleType);
21897 }
21898 get(token, notFoundValue = Injector.THROW_IF_NOT_FOUND, injectFlags = InjectFlags.Default) {
21899 if (token === Injector || token === NgModuleRef$1 || token === INJECTOR) {
21900 return this;
21901 }
21902 return this._r3Injector.get(token, notFoundValue, injectFlags);
21903 }
21904 destroy() {
21905 ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
21906 const injector = this._r3Injector;
21907 !injector.destroyed && injector.destroy();
21908 this.destroyCbs.forEach(fn => fn());
21909 this.destroyCbs = null;
21910 }
21911 onDestroy(callback) {
21912 ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
21913 this.destroyCbs.push(callback);
21914 }
21915}
21916class NgModuleFactory extends NgModuleFactory$1 {
21917 constructor(moduleType) {
21918 super();
21919 this.moduleType = moduleType;
21920 const ngModuleDef = getNgModuleDef(moduleType);
21921 if (ngModuleDef !== null) {
21922 // Register the NgModule with Angular's module registry. The location (and hence timing) of
21923 // this call is critical to ensure this works correctly (modules get registered when expected)
21924 // without bloating bundles (modules are registered when otherwise not referenced).
21925 //
21926 // In View Engine, registration occurs in the .ngfactory.js file as a side effect. This has
21927 // several practical consequences:
21928 //
21929 // - If an .ngfactory file is not imported from, the module won't be registered (and can be
21930 // tree shaken).
21931 // - If an .ngfactory file is imported from, the module will be registered even if an instance
21932 // is not actually created (via `create` below).
21933 // - Since an .ngfactory file in View Engine references the .ngfactory files of the NgModule's
21934 // imports,
21935 //
21936 // In Ivy, things are a bit different. .ngfactory files still exist for compatibility, but are
21937 // not a required API to use - there are other ways to obtain an NgModuleFactory for a given
21938 // NgModule. Thus, relying on a side effect in the .ngfactory file is not sufficient. Instead,
21939 // the side effect of registration is added here, in the constructor of NgModuleFactory,
21940 // ensuring no matter how a factory is created, the module is registered correctly.
21941 //
21942 // An alternative would be to include the registration side effect inline following the actual
21943 // NgModule definition. This also has the correct timing, but breaks tree-shaking - modules
21944 // will be registered and retained even if they're otherwise never referenced.
21945 registerNgModuleType(moduleType);
21946 }
21947 }
21948 create(parentInjector) {
21949 return new NgModuleRef(this.moduleType, parentInjector);
21950 }
21951}
21952
21953/**
21954 * @license
21955 * Copyright Google LLC All Rights Reserved.
21956 *
21957 * Use of this source code is governed by an MIT-style license that can be
21958 * found in the LICENSE file at https://angular.io/license
21959 */
21960/**
21961 * Bindings for pure functions are stored after regular bindings.
21962 *
21963 * |-------decls------|---------vars---------| |----- hostVars (dir1) ------|
21964 * ------------------------------------------------------------------------------------------
21965 * | nodes/refs/pipes | bindings | fn slots | injector | dir1 | host bindings | host slots |
21966 * ------------------------------------------------------------------------------------------
21967 * ^ ^
21968 * TView.bindingStartIndex TView.expandoStartIndex
21969 *
21970 * Pure function instructions are given an offset from the binding root. Adding the offset to the
21971 * binding root gives the first index where the bindings are stored. In component views, the binding
21972 * root is the bindingStartIndex. In host bindings, the binding root is the expandoStartIndex +
21973 * any directive instances + any hostVars in directives evaluated before it.
21974 *
21975 * See VIEW_DATA.md for more information about host binding resolution.
21976 */
21977/**
21978 * If the value hasn't been saved, calls the pure function to store and return the
21979 * value. If it has been saved, returns the saved value.
21980 *
21981 * @param slotOffset the offset from binding root to the reserved slot
21982 * @param pureFn Function that returns a value
21983 * @param thisArg Optional calling context of pureFn
21984 * @returns value
21985 *
21986 * @codeGenApi
21987 */
21988function ɵɵpureFunction0(slotOffset, pureFn, thisArg) {
21989 const bindingIndex = getBindingRoot() + slotOffset;
21990 const lView = getLView();
21991 return lView[bindingIndex] === NO_CHANGE ?
21992 updateBinding(lView, bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) :
21993 getBinding(lView, bindingIndex);
21994}
21995/**
21996 * If the value of the provided exp has changed, calls the pure function to return
21997 * an updated value. Or if the value has not changed, returns cached value.
21998 *
21999 * @param slotOffset the offset from binding root to the reserved slot
22000 * @param pureFn Function that returns an updated value
22001 * @param exp Updated expression value
22002 * @param thisArg Optional calling context of pureFn
22003 * @returns Updated or cached value
22004 *
22005 * @codeGenApi
22006 */
22007function ɵɵpureFunction1(slotOffset, pureFn, exp, thisArg) {
22008 return pureFunction1Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp, thisArg);
22009}
22010/**
22011 * If the value of any provided exp has changed, calls the pure function to return
22012 * an updated value. Or if no values have changed, returns cached value.
22013 *
22014 * @param slotOffset the offset from binding root to the reserved slot
22015 * @param pureFn
22016 * @param exp1
22017 * @param exp2
22018 * @param thisArg Optional calling context of pureFn
22019 * @returns Updated or cached value
22020 *
22021 * @codeGenApi
22022 */
22023function ɵɵpureFunction2(slotOffset, pureFn, exp1, exp2, thisArg) {
22024 return pureFunction2Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, thisArg);
22025}
22026/**
22027 * If the value of any provided exp has changed, calls the pure function to return
22028 * an updated value. Or if no values have changed, returns cached value.
22029 *
22030 * @param slotOffset the offset from binding root to the reserved slot
22031 * @param pureFn
22032 * @param exp1
22033 * @param exp2
22034 * @param exp3
22035 * @param thisArg Optional calling context of pureFn
22036 * @returns Updated or cached value
22037 *
22038 * @codeGenApi
22039 */
22040function ɵɵpureFunction3(slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
22041 return pureFunction3Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, thisArg);
22042}
22043/**
22044 * If the value of any provided exp has changed, calls the pure function to return
22045 * an updated value. Or if no values have changed, returns cached value.
22046 *
22047 * @param slotOffset the offset from binding root to the reserved slot
22048 * @param pureFn
22049 * @param exp1
22050 * @param exp2
22051 * @param exp3
22052 * @param exp4
22053 * @param thisArg Optional calling context of pureFn
22054 * @returns Updated or cached value
22055 *
22056 * @codeGenApi
22057 */
22058function ɵɵpureFunction4(slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
22059 return pureFunction4Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg);
22060}
22061/**
22062 * If the value of any provided exp has changed, calls the pure function to return
22063 * an updated value. Or if no values have changed, returns cached value.
22064 *
22065 * @param slotOffset the offset from binding root to the reserved slot
22066 * @param pureFn
22067 * @param exp1
22068 * @param exp2
22069 * @param exp3
22070 * @param exp4
22071 * @param exp5
22072 * @param thisArg Optional calling context of pureFn
22073 * @returns Updated or cached value
22074 *
22075 * @codeGenApi
22076 */
22077function ɵɵpureFunction5(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, thisArg) {
22078 const bindingIndex = getBindingRoot() + slotOffset;
22079 const lView = getLView();
22080 const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22081 return bindingUpdated(lView, bindingIndex + 4, exp5) || different ?
22082 updateBinding(lView, bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
22083 pureFn(exp1, exp2, exp3, exp4, exp5)) :
22084 getBinding(lView, bindingIndex + 5);
22085}
22086/**
22087 * If the value of any provided exp has changed, calls the pure function to return
22088 * an updated value. Or if no values have changed, returns cached value.
22089 *
22090 * @param slotOffset the offset from binding root to the reserved slot
22091 * @param pureFn
22092 * @param exp1
22093 * @param exp2
22094 * @param exp3
22095 * @param exp4
22096 * @param exp5
22097 * @param exp6
22098 * @param thisArg Optional calling context of pureFn
22099 * @returns Updated or cached value
22100 *
22101 * @codeGenApi
22102 */
22103function ɵɵpureFunction6(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, thisArg) {
22104 const bindingIndex = getBindingRoot() + slotOffset;
22105 const lView = getLView();
22106 const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22107 return bindingUpdated2(lView, bindingIndex + 4, exp5, exp6) || different ?
22108 updateBinding(lView, bindingIndex + 6, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
22109 pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
22110 getBinding(lView, bindingIndex + 6);
22111}
22112/**
22113 * If the value of any provided exp has changed, calls the pure function to return
22114 * an updated value. Or if no values have changed, returns cached value.
22115 *
22116 * @param slotOffset the offset from binding root to the reserved slot
22117 * @param pureFn
22118 * @param exp1
22119 * @param exp2
22120 * @param exp3
22121 * @param exp4
22122 * @param exp5
22123 * @param exp6
22124 * @param exp7
22125 * @param thisArg Optional calling context of pureFn
22126 * @returns Updated or cached value
22127 *
22128 * @codeGenApi
22129 */
22130function ɵɵpureFunction7(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, thisArg) {
22131 const bindingIndex = getBindingRoot() + slotOffset;
22132 const lView = getLView();
22133 let different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22134 return bindingUpdated3(lView, bindingIndex + 4, exp5, exp6, exp7) || different ?
22135 updateBinding(lView, bindingIndex + 7, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
22136 pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
22137 getBinding(lView, bindingIndex + 7);
22138}
22139/**
22140 * If the value of any provided exp has changed, calls the pure function to return
22141 * an updated value. Or if no values have changed, returns cached value.
22142 *
22143 * @param slotOffset the offset from binding root to the reserved slot
22144 * @param pureFn
22145 * @param exp1
22146 * @param exp2
22147 * @param exp3
22148 * @param exp4
22149 * @param exp5
22150 * @param exp6
22151 * @param exp7
22152 * @param exp8
22153 * @param thisArg Optional calling context of pureFn
22154 * @returns Updated or cached value
22155 *
22156 * @codeGenApi
22157 */
22158function ɵɵpureFunction8(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8, thisArg) {
22159 const bindingIndex = getBindingRoot() + slotOffset;
22160 const lView = getLView();
22161 const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
22162 return bindingUpdated4(lView, bindingIndex + 4, exp5, exp6, exp7, exp8) || different ?
22163 updateBinding(lView, bindingIndex + 8, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
22164 pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
22165 getBinding(lView, bindingIndex + 8);
22166}
22167/**
22168 * pureFunction instruction that can support any number of bindings.
22169 *
22170 * If the value of any provided exp has changed, calls the pure function to return
22171 * an updated value. Or if no values have changed, returns cached value.
22172 *
22173 * @param slotOffset the offset from binding root to the reserved slot
22174 * @param pureFn A pure function that takes binding values and builds an object or array
22175 * containing those values.
22176 * @param exps An array of binding values
22177 * @param thisArg Optional calling context of pureFn
22178 * @returns Updated or cached value
22179 *
22180 * @codeGenApi
22181 */
22182function ɵɵpureFunctionV(slotOffset, pureFn, exps, thisArg) {
22183 return pureFunctionVInternal(getLView(), getBindingRoot(), slotOffset, pureFn, exps, thisArg);
22184}
22185/**
22186 * Results of a pure function invocation are stored in LView in a dedicated slot that is initialized
22187 * to NO_CHANGE. In rare situations a pure pipe might throw an exception on the very first
22188 * invocation and not produce any valid results. In this case LView would keep holding the NO_CHANGE
22189 * value. The NO_CHANGE is not something that we can use in expressions / bindings thus we convert
22190 * it to `undefined`.
22191 */
22192function getPureFunctionReturnValue(lView, returnValueIndex) {
22193 ngDevMode && assertIndexInRange(lView, returnValueIndex);
22194 const lastReturnValue = lView[returnValueIndex];
22195 return lastReturnValue === NO_CHANGE ? undefined : lastReturnValue;
22196}
22197/**
22198 * If the value of the provided exp has changed, calls the pure function to return
22199 * an updated value. Or if the value has not changed, returns cached value.
22200 *
22201 * @param lView LView in which the function is being executed.
22202 * @param bindingRoot Binding root index.
22203 * @param slotOffset the offset from binding root to the reserved slot
22204 * @param pureFn Function that returns an updated value
22205 * @param exp Updated expression value
22206 * @param thisArg Optional calling context of pureFn
22207 * @returns Updated or cached value
22208 */
22209function pureFunction1Internal(lView, bindingRoot, slotOffset, pureFn, exp, thisArg) {
22210 const bindingIndex = bindingRoot + slotOffset;
22211 return bindingUpdated(lView, bindingIndex, exp) ?
22212 updateBinding(lView, bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
22213 getPureFunctionReturnValue(lView, bindingIndex + 1);
22214}
22215/**
22216 * If the value of any provided exp has changed, calls the pure function to return
22217 * an updated value. Or if no values have changed, returns cached value.
22218 *
22219 * @param lView LView in which the function is being executed.
22220 * @param bindingRoot Binding root index.
22221 * @param slotOffset the offset from binding root to the reserved slot
22222 * @param pureFn
22223 * @param exp1
22224 * @param exp2
22225 * @param thisArg Optional calling context of pureFn
22226 * @returns Updated or cached value
22227 */
22228function pureFunction2Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, thisArg) {
22229 const bindingIndex = bindingRoot + slotOffset;
22230 return bindingUpdated2(lView, bindingIndex, exp1, exp2) ?
22231 updateBinding(lView, bindingIndex + 2, thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) :
22232 getPureFunctionReturnValue(lView, bindingIndex + 2);
22233}
22234/**
22235 * If the value of any provided exp has changed, calls the pure function to return
22236 * an updated value. Or if no values have changed, returns cached value.
22237 *
22238 * @param lView LView in which the function is being executed.
22239 * @param bindingRoot Binding root index.
22240 * @param slotOffset the offset from binding root to the reserved slot
22241 * @param pureFn
22242 * @param exp1
22243 * @param exp2
22244 * @param exp3
22245 * @param thisArg Optional calling context of pureFn
22246 * @returns Updated or cached value
22247 */
22248function pureFunction3Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
22249 const bindingIndex = bindingRoot + slotOffset;
22250 return bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) ?
22251 updateBinding(lView, bindingIndex + 3, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) :
22252 getPureFunctionReturnValue(lView, bindingIndex + 3);
22253}
22254/**
22255 * If the value of any provided exp has changed, calls the pure function to return
22256 * an updated value. Or if no values have changed, returns cached value.
22257 *
22258 * @param lView LView in which the function is being executed.
22259 * @param bindingRoot Binding root index.
22260 * @param slotOffset the offset from binding root to the reserved slot
22261 * @param pureFn
22262 * @param exp1
22263 * @param exp2
22264 * @param exp3
22265 * @param exp4
22266 * @param thisArg Optional calling context of pureFn
22267 * @returns Updated or cached value
22268 *
22269 */
22270function pureFunction4Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
22271 const bindingIndex = bindingRoot + slotOffset;
22272 return bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) ?
22273 updateBinding(lView, bindingIndex + 4, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) :
22274 getPureFunctionReturnValue(lView, bindingIndex + 4);
22275}
22276/**
22277 * pureFunction instruction that can support any number of bindings.
22278 *
22279 * If the value of any provided exp has changed, calls the pure function to return
22280 * an updated value. Or if no values have changed, returns cached value.
22281 *
22282 * @param lView LView in which the function is being executed.
22283 * @param bindingRoot Binding root index.
22284 * @param slotOffset the offset from binding root to the reserved slot
22285 * @param pureFn A pure function that takes binding values and builds an object or array
22286 * containing those values.
22287 * @param exps An array of binding values
22288 * @param thisArg Optional calling context of pureFn
22289 * @returns Updated or cached value
22290 */
22291function pureFunctionVInternal(lView, bindingRoot, slotOffset, pureFn, exps, thisArg) {
22292 let bindingIndex = bindingRoot + slotOffset;
22293 let different = false;
22294 for (let i = 0; i < exps.length; i++) {
22295 bindingUpdated(lView, bindingIndex++, exps[i]) && (different = true);
22296 }
22297 return different ? updateBinding(lView, bindingIndex, pureFn.apply(thisArg, exps)) :
22298 getPureFunctionReturnValue(lView, bindingIndex);
22299}
22300
22301/**
22302 * @license
22303 * Copyright Google LLC All Rights Reserved.
22304 *
22305 * Use of this source code is governed by an MIT-style license that can be
22306 * found in the LICENSE file at https://angular.io/license
22307 */
22308/**
22309 * Create a pipe.
22310 *
22311 * @param index Pipe index where the pipe will be stored.
22312 * @param pipeName The name of the pipe
22313 * @returns T the instance of the pipe.
22314 *
22315 * @codeGenApi
22316 */
22317function ɵɵpipe(index, pipeName) {
22318 const tView = getTView();
22319 let pipeDef;
22320 const adjustedIndex = index + HEADER_OFFSET;
22321 if (tView.firstCreatePass) {
22322 // The `getPipeDef` throws if a pipe with a given name is not found
22323 // (so we use non-null assertion below).
22324 pipeDef = getPipeDef(pipeName, tView.pipeRegistry);
22325 tView.data[adjustedIndex] = pipeDef;
22326 if (pipeDef.onDestroy) {
22327 (tView.destroyHooks || (tView.destroyHooks = [])).push(adjustedIndex, pipeDef.onDestroy);
22328 }
22329 }
22330 else {
22331 pipeDef = tView.data[adjustedIndex];
22332 }
22333 const pipeFactory = pipeDef.factory || (pipeDef.factory = getFactoryDef(pipeDef.type, true));
22334 const previousInjectImplementation = setInjectImplementation(ɵɵdirectiveInject);
22335 try {
22336 // DI for pipes is supposed to behave like directives when placed on a component
22337 // host node, which means that we have to disable access to `viewProviders`.
22338 const previousIncludeViewProviders = setIncludeViewProviders(false);
22339 const pipeInstance = pipeFactory();
22340 setIncludeViewProviders(previousIncludeViewProviders);
22341 store(tView, getLView(), adjustedIndex, pipeInstance);
22342 return pipeInstance;
22343 }
22344 finally {
22345 // we have to restore the injector implementation in finally, just in case the creation of the
22346 // pipe throws an error.
22347 setInjectImplementation(previousInjectImplementation);
22348 }
22349}
22350/**
22351 * Searches the pipe registry for a pipe with the given name. If one is found,
22352 * returns the pipe. Otherwise, an error is thrown because the pipe cannot be resolved.
22353 *
22354 * @param name Name of pipe to resolve
22355 * @param registry Full list of available pipes
22356 * @returns Matching PipeDef
22357 */
22358function getPipeDef(name, registry) {
22359 if (registry) {
22360 for (let i = registry.length - 1; i >= 0; i--) {
22361 const pipeDef = registry[i];
22362 if (name === pipeDef.name) {
22363 return pipeDef;
22364 }
22365 }
22366 }
22367 if (ngDevMode) {
22368 const lView = getLView();
22369 const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
22370 const context = declarationLView[CONTEXT];
22371 const component = context ? ` in the '${context.constructor.name}' component` : '';
22372 throw new RuntimeError(-302 /* PIPE_NOT_FOUND */, `The pipe '${name}' could not be found${component}!`);
22373 }
22374}
22375/**
22376 * Invokes a pipe with 1 arguments.
22377 *
22378 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
22379 * the pipe only when an input to the pipe changes.
22380 *
22381 * @param index Pipe index where the pipe was stored on creation.
22382 * @param slotOffset the offset in the reserved slot space
22383 * @param v1 1st argument to {@link PipeTransform#transform}.
22384 *
22385 * @codeGenApi
22386 */
22387function ɵɵpipeBind1(index, slotOffset, v1) {
22388 const adjustedIndex = index + HEADER_OFFSET;
22389 const lView = getLView();
22390 const pipeInstance = load(lView, adjustedIndex);
22391 return isPure(lView, adjustedIndex) ?
22392 pureFunction1Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) :
22393 pipeInstance.transform(v1);
22394}
22395/**
22396 * Invokes a pipe with 2 arguments.
22397 *
22398 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
22399 * the pipe only when an input to the pipe changes.
22400 *
22401 * @param index Pipe index where the pipe was stored on creation.
22402 * @param slotOffset the offset in the reserved slot space
22403 * @param v1 1st argument to {@link PipeTransform#transform}.
22404 * @param v2 2nd argument to {@link PipeTransform#transform}.
22405 *
22406 * @codeGenApi
22407 */
22408function ɵɵpipeBind2(index, slotOffset, v1, v2) {
22409 const adjustedIndex = index + HEADER_OFFSET;
22410 const lView = getLView();
22411 const pipeInstance = load(lView, adjustedIndex);
22412 return isPure(lView, adjustedIndex) ?
22413 pureFunction2Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, pipeInstance) :
22414 pipeInstance.transform(v1, v2);
22415}
22416/**
22417 * Invokes a pipe with 3 arguments.
22418 *
22419 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
22420 * the pipe only when an input to the pipe changes.
22421 *
22422 * @param index Pipe index where the pipe was stored on creation.
22423 * @param slotOffset the offset in the reserved slot space
22424 * @param v1 1st argument to {@link PipeTransform#transform}.
22425 * @param v2 2nd argument to {@link PipeTransform#transform}.
22426 * @param v3 4rd argument to {@link PipeTransform#transform}.
22427 *
22428 * @codeGenApi
22429 */
22430function ɵɵpipeBind3(index, slotOffset, v1, v2, v3) {
22431 const adjustedIndex = index + HEADER_OFFSET;
22432 const lView = getLView();
22433 const pipeInstance = load(lView, adjustedIndex);
22434 return isPure(lView, adjustedIndex) ?
22435 pureFunction3Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, pipeInstance) :
22436 pipeInstance.transform(v1, v2, v3);
22437}
22438/**
22439 * Invokes a pipe with 4 arguments.
22440 *
22441 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
22442 * the pipe only when an input to the pipe changes.
22443 *
22444 * @param index Pipe index where the pipe was stored on creation.
22445 * @param slotOffset the offset in the reserved slot space
22446 * @param v1 1st argument to {@link PipeTransform#transform}.
22447 * @param v2 2nd argument to {@link PipeTransform#transform}.
22448 * @param v3 3rd argument to {@link PipeTransform#transform}.
22449 * @param v4 4th argument to {@link PipeTransform#transform}.
22450 *
22451 * @codeGenApi
22452 */
22453function ɵɵpipeBind4(index, slotOffset, v1, v2, v3, v4) {
22454 const adjustedIndex = index + HEADER_OFFSET;
22455 const lView = getLView();
22456 const pipeInstance = load(lView, adjustedIndex);
22457 return isPure(lView, adjustedIndex) ? pureFunction4Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, v4, pipeInstance) :
22458 pipeInstance.transform(v1, v2, v3, v4);
22459}
22460/**
22461 * Invokes a pipe with variable number of arguments.
22462 *
22463 * This instruction acts as a guard to {@link PipeTransform#transform} invoking
22464 * the pipe only when an input to the pipe changes.
22465 *
22466 * @param index Pipe index where the pipe was stored on creation.
22467 * @param slotOffset the offset in the reserved slot space
22468 * @param values Array of arguments to pass to {@link PipeTransform#transform} method.
22469 *
22470 * @codeGenApi
22471 */
22472function ɵɵpipeBindV(index, slotOffset, values) {
22473 const adjustedIndex = index + HEADER_OFFSET;
22474 const lView = getLView();
22475 const pipeInstance = load(lView, adjustedIndex);
22476 return isPure(lView, adjustedIndex) ?
22477 pureFunctionVInternal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, values, pipeInstance) :
22478 pipeInstance.transform.apply(pipeInstance, values);
22479}
22480function isPure(lView, index) {
22481 return lView[TVIEW].data[index].pure;
22482}
22483
22484/**
22485 * @license
22486 * Copyright Google LLC All Rights Reserved.
22487 *
22488 * Use of this source code is governed by an MIT-style license that can be
22489 * found in the LICENSE file at https://angular.io/license
22490 */
22491class EventEmitter_ extends Subject {
22492 constructor(isAsync = false) {
22493 super();
22494 this.__isAsync = isAsync;
22495 }
22496 emit(value) {
22497 super.next(value);
22498 }
22499 subscribe(observerOrNext, error, complete) {
22500 let nextFn = observerOrNext;
22501 let errorFn = error || (() => null);
22502 let completeFn = complete;
22503 if (observerOrNext && typeof observerOrNext === 'object') {
22504 const observer = observerOrNext;
22505 nextFn = observer.next?.bind(observer);
22506 errorFn = observer.error?.bind(observer);
22507 completeFn = observer.complete?.bind(observer);
22508 }
22509 if (this.__isAsync) {
22510 errorFn = _wrapInTimeout(errorFn);
22511 if (nextFn) {
22512 nextFn = _wrapInTimeout(nextFn);
22513 }
22514 if (completeFn) {
22515 completeFn = _wrapInTimeout(completeFn);
22516 }
22517 }
22518 const sink = super.subscribe({ next: nextFn, error: errorFn, complete: completeFn });
22519 if (observerOrNext instanceof Subscription) {
22520 observerOrNext.add(sink);
22521 }
22522 return sink;
22523 }
22524}
22525function _wrapInTimeout(fn) {
22526 return (value) => {
22527 setTimeout(fn, undefined, value);
22528 };
22529}
22530/**
22531 * @publicApi
22532 */
22533const EventEmitter = EventEmitter_;
22534
22535/**
22536 * @license
22537 * Copyright Google LLC All Rights Reserved.
22538 *
22539 * Use of this source code is governed by an MIT-style license that can be
22540 * found in the LICENSE file at https://angular.io/license
22541 */
22542function symbolIterator() {
22543 return this._results[getSymbolIterator()]();
22544}
22545/**
22546 * An unmodifiable list of items that Angular keeps up to date when the state
22547 * of the application changes.
22548 *
22549 * The type of object that {@link ViewChildren}, {@link ContentChildren}, and {@link QueryList}
22550 * provide.
22551 *
22552 * Implements an iterable interface, therefore it can be used in both ES6
22553 * javascript `for (var i of items)` loops as well as in Angular templates with
22554 * `*ngFor="let i of myList"`.
22555 *
22556 * Changes can be observed by subscribing to the changes `Observable`.
22557 *
22558 * NOTE: In the future this class will implement an `Observable` interface.
22559 *
22560 * @usageNotes
22561 * ### Example
22562 * ```typescript
22563 * @Component({...})
22564 * class Container {
22565 * @ViewChildren(Item) items:QueryList<Item>;
22566 * }
22567 * ```
22568 *
22569 * @publicApi
22570 */
22571class QueryList {
22572 /**
22573 * @param emitDistinctChangesOnly Whether `QueryList.changes` should fire only when actual change
22574 * has occurred. Or if it should fire when query is recomputed. (recomputing could resolve in
22575 * the same result)
22576 */
22577 constructor(_emitDistinctChangesOnly = false) {
22578 this._emitDistinctChangesOnly = _emitDistinctChangesOnly;
22579 this.dirty = true;
22580 this._results = [];
22581 this._changesDetected = false;
22582 this._changes = null;
22583 this.length = 0;
22584 this.first = undefined;
22585 this.last = undefined;
22586 // This function should be declared on the prototype, but doing so there will cause the class
22587 // declaration to have side-effects and become not tree-shakable. For this reason we do it in
22588 // the constructor.
22589 // [getSymbolIterator()](): Iterator<T> { ... }
22590 const symbol = getSymbolIterator();
22591 const proto = QueryList.prototype;
22592 if (!proto[symbol])
22593 proto[symbol] = symbolIterator;
22594 }
22595 /**
22596 * Returns `Observable` of `QueryList` notifying the subscriber of changes.
22597 */
22598 get changes() {
22599 return this._changes || (this._changes = new EventEmitter());
22600 }
22601 /**
22602 * Returns the QueryList entry at `index`.
22603 */
22604 get(index) {
22605 return this._results[index];
22606 }
22607 /**
22608 * See
22609 * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
22610 */
22611 map(fn) {
22612 return this._results.map(fn);
22613 }
22614 /**
22615 * See
22616 * [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
22617 */
22618 filter(fn) {
22619 return this._results.filter(fn);
22620 }
22621 /**
22622 * See
22623 * [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
22624 */
22625 find(fn) {
22626 return this._results.find(fn);
22627 }
22628 /**
22629 * See
22630 * [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
22631 */
22632 reduce(fn, init) {
22633 return this._results.reduce(fn, init);
22634 }
22635 /**
22636 * See
22637 * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
22638 */
22639 forEach(fn) {
22640 this._results.forEach(fn);
22641 }
22642 /**
22643 * See
22644 * [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
22645 */
22646 some(fn) {
22647 return this._results.some(fn);
22648 }
22649 /**
22650 * Returns a copy of the internal results list as an Array.
22651 */
22652 toArray() {
22653 return this._results.slice();
22654 }
22655 toString() {
22656 return this._results.toString();
22657 }
22658 /**
22659 * Updates the stored data of the query list, and resets the `dirty` flag to `false`, so that
22660 * on change detection, it will not notify of changes to the queries, unless a new change
22661 * occurs.
22662 *
22663 * @param resultsTree The query results to store
22664 * @param identityAccessor Optional function for extracting stable object identity from a value
22665 * in the array. This function is executed for each element of the query result list while
22666 * comparing current query list with the new one (provided as a first argument of the `reset`
22667 * function) to detect if the lists are different. If the function is not provided, elements
22668 * are compared as is (without any pre-processing).
22669 */
22670 reset(resultsTree, identityAccessor) {
22671 // Cast to `QueryListInternal` so that we can mutate fields which are readonly for the usage of
22672 // QueryList (but not for QueryList itself.)
22673 const self = this;
22674 self.dirty = false;
22675 const newResultFlat = flatten(resultsTree);
22676 if (this._changesDetected = !arrayEquals(self._results, newResultFlat, identityAccessor)) {
22677 self._results = newResultFlat;
22678 self.length = newResultFlat.length;
22679 self.last = newResultFlat[this.length - 1];
22680 self.first = newResultFlat[0];
22681 }
22682 }
22683 /**
22684 * Triggers a change event by emitting on the `changes` {@link EventEmitter}.
22685 */
22686 notifyOnChanges() {
22687 if (this._changes && (this._changesDetected || !this._emitDistinctChangesOnly))
22688 this._changes.emit(this);
22689 }
22690 /** internal */
22691 setDirty() {
22692 this.dirty = true;
22693 }
22694 /** internal */
22695 destroy() {
22696 this.changes.complete();
22697 this.changes.unsubscribe();
22698 }
22699}
22700Symbol.iterator;
22701
22702/**
22703 * @license
22704 * Copyright Google LLC All Rights Reserved.
22705 *
22706 * Use of this source code is governed by an MIT-style license that can be
22707 * found in the LICENSE file at https://angular.io/license
22708 */
22709/**
22710 * Represents an embedded template that can be used to instantiate embedded views.
22711 * To instantiate embedded views based on a template, use the `ViewContainerRef`
22712 * method `createEmbeddedView()`.
22713 *
22714 * Access a `TemplateRef` instance by placing a directive on an `<ng-template>`
22715 * element (or directive prefixed with `*`). The `TemplateRef` for the embedded view
22716 * is injected into the constructor of the directive,
22717 * using the `TemplateRef` token.
22718 *
22719 * You can also use a `Query` to find a `TemplateRef` associated with
22720 * a component or a directive.
22721 *
22722 * @see `ViewContainerRef`
22723 * @see [Navigate the Component Tree with DI](guide/dependency-injection-navtree)
22724 *
22725 * @publicApi
22726 */
22727class TemplateRef {
22728}
22729/**
22730 * @internal
22731 * @nocollapse
22732 */
22733TemplateRef.__NG_ELEMENT_ID__ = injectTemplateRef;
22734const ViewEngineTemplateRef = TemplateRef;
22735// TODO(alxhub): combine interface and implementation. Currently this is challenging since something
22736// in g3 depends on them being separate.
22737const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
22738 constructor(_declarationLView, _declarationTContainer, elementRef) {
22739 super();
22740 this._declarationLView = _declarationLView;
22741 this._declarationTContainer = _declarationTContainer;
22742 this.elementRef = elementRef;
22743 }
22744 createEmbeddedView(context) {
22745 const embeddedTView = this._declarationTContainer.tViews;
22746 const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* CheckAlways */, null, embeddedTView.declTNode, null, null, null, null);
22747 const declarationLContainer = this._declarationLView[this._declarationTContainer.index];
22748 ngDevMode && assertLContainer(declarationLContainer);
22749 embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
22750 const declarationViewLQueries = this._declarationLView[QUERIES];
22751 if (declarationViewLQueries !== null) {
22752 embeddedLView[QUERIES] = declarationViewLQueries.createEmbeddedView(embeddedTView);
22753 }
22754 renderView(embeddedTView, embeddedLView, context);
22755 return new ViewRef$1(embeddedLView);
22756 }
22757};
22758/**
22759 * Creates a TemplateRef given a node.
22760 *
22761 * @returns The TemplateRef instance to use
22762 */
22763function injectTemplateRef() {
22764 return createTemplateRef(getCurrentTNode(), getLView());
22765}
22766/**
22767 * Creates a TemplateRef and stores it on the injector.
22768 *
22769 * @param hostTNode The node on which a TemplateRef is requested
22770 * @param hostLView The `LView` to which the node belongs
22771 * @returns The TemplateRef instance or null if we can't create a TemplateRef on a given node type
22772 */
22773function createTemplateRef(hostTNode, hostLView) {
22774 if (hostTNode.type & 4 /* Container */) {
22775 ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
22776 return new R3TemplateRef(hostLView, hostTNode, createElementRef(hostTNode, hostLView));
22777 }
22778 return null;
22779}
22780
22781/**
22782 * @license
22783 * Copyright Google LLC All Rights Reserved.
22784 *
22785 * Use of this source code is governed by an MIT-style license that can be
22786 * found in the LICENSE file at https://angular.io/license
22787 */
22788/**
22789 * Represents a container where one or more views can be attached to a component.
22790 *
22791 * Can contain *host views* (created by instantiating a
22792 * component with the `createComponent()` method), and *embedded views*
22793 * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
22794 *
22795 * A view container instance can contain other view containers,
22796 * creating a [view hierarchy](guide/glossary#view-tree).
22797 *
22798 * @see `ComponentRef`
22799 * @see `EmbeddedViewRef`
22800 *
22801 * @publicApi
22802 */
22803class ViewContainerRef {
22804}
22805/**
22806 * @internal
22807 * @nocollapse
22808 */
22809ViewContainerRef.__NG_ELEMENT_ID__ = injectViewContainerRef;
22810/**
22811 * Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
22812 * already exists, retrieves the existing ViewContainerRef.
22813 *
22814 * @returns The ViewContainerRef instance to use
22815 */
22816function injectViewContainerRef() {
22817 const previousTNode = getCurrentTNode();
22818 return createContainerRef(previousTNode, getLView());
22819}
22820const VE_ViewContainerRef = ViewContainerRef;
22821// TODO(alxhub): cleaning up this indirection triggers a subtle bug in Closure in g3. Once the fix
22822// for that lands, this can be cleaned up.
22823const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
22824 constructor(_lContainer, _hostTNode, _hostLView) {
22825 super();
22826 this._lContainer = _lContainer;
22827 this._hostTNode = _hostTNode;
22828 this._hostLView = _hostLView;
22829 }
22830 get element() {
22831 return createElementRef(this._hostTNode, this._hostLView);
22832 }
22833 get injector() {
22834 return new NodeInjector(this._hostTNode, this._hostLView);
22835 }
22836 /** @deprecated No replacement */
22837 get parentInjector() {
22838 const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostLView);
22839 if (hasParentInjector(parentLocation)) {
22840 const parentView = getParentInjectorView(parentLocation, this._hostLView);
22841 const injectorIndex = getParentInjectorIndex(parentLocation);
22842 ngDevMode && assertNodeInjector(parentView, injectorIndex);
22843 const parentTNode = parentView[TVIEW].data[injectorIndex + 8 /* TNODE */];
22844 return new NodeInjector(parentTNode, parentView);
22845 }
22846 else {
22847 return new NodeInjector(null, this._hostLView);
22848 }
22849 }
22850 clear() {
22851 while (this.length > 0) {
22852 this.remove(this.length - 1);
22853 }
22854 }
22855 get(index) {
22856 const viewRefs = getViewRefs(this._lContainer);
22857 return viewRefs !== null && viewRefs[index] || null;
22858 }
22859 get length() {
22860 return this._lContainer.length - CONTAINER_HEADER_OFFSET;
22861 }
22862 createEmbeddedView(templateRef, context, index) {
22863 const viewRef = templateRef.createEmbeddedView(context || {});
22864 this.insert(viewRef, index);
22865 return viewRef;
22866 }
22867 createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, ngModuleRef) {
22868 const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
22869 let index;
22870 // This function supports 2 signatures and we need to handle options correctly for both:
22871 // 1. When first argument is a Component type. This signature also requires extra
22872 // options to be provided as as object (more ergonomic option).
22873 // 2. First argument is a Component factory. In this case extra options are represented as
22874 // positional arguments. This signature is less ergonomic and will be deprecated.
22875 if (isComponentFactory) {
22876 if (ngDevMode) {
22877 assertEqual(typeof indexOrOptions !== 'object', true, 'It looks like Component factory was provided as the first argument ' +
22878 'and an options object as the second argument. This combination of arguments ' +
22879 'is incompatible. You can either change the first argument to provide Component ' +
22880 'type or change the second argument to be a number (representing an index at ' +
22881 'which to insert the new component\'s host view into this container)');
22882 }
22883 index = indexOrOptions;
22884 }
22885 else {
22886 if (ngDevMode) {
22887 assertDefined(getComponentDef(componentFactoryOrType), `Provided Component class doesn't contain Component definition. ` +
22888 `Please check whether provided class has @Component decorator.`);
22889 assertEqual(typeof indexOrOptions !== 'number', true, 'It looks like Component type was provided as the first argument ' +
22890 'and a number (representing an index at which to insert the new component\'s ' +
22891 'host view into this container as the second argument. This combination of arguments ' +
22892 'is incompatible. Please use an object as the second argument instead.');
22893 }
22894 const options = (indexOrOptions || {});
22895 index = options.index;
22896 injector = options.injector;
22897 projectableNodes = options.projectableNodes;
22898 ngModuleRef = options.ngModuleRef;
22899 }
22900 const componentFactory = isComponentFactory ?
22901 componentFactoryOrType :
22902 new ComponentFactory(getComponentDef(componentFactoryOrType));
22903 const contextInjector = injector || this.parentInjector;
22904 // If an `NgModuleRef` is not provided explicitly, try retrieving it from the DI tree.
22905 if (!ngModuleRef && componentFactory.ngModule == null) {
22906 // For the `ComponentFactory` case, entering this logic is very unlikely, since we expect that
22907 // an instance of a `ComponentFactory`, resolved via `ComponentFactoryResolver` would have an
22908 // `ngModule` field. This is possible in some test scenarios and potentially in some JIT-based
22909 // use-cases. For the `ComponentFactory` case we preserve backwards-compatibility and try
22910 // using a provided injector first, then fall back to the parent injector of this
22911 // `ViewContainerRef` instance.
22912 //
22913 // For the factory-less case, it's critical to establish a connection with the module
22914 // injector tree (by retrieving an instance of an `NgModuleRef` and accessing its injector),
22915 // so that a component can use DI tokens provided in MgModules. For this reason, we can not
22916 // rely on the provided injector, since it might be detached from the DI tree (for example, if
22917 // it was created via `Injector.create` without specifying a parent injector, or if an
22918 // injector is retrieved from an `NgModuleRef` created via `createNgModuleRef` using an
22919 // NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent
22920 // injector, which is normally connected to the DI tree, which includes module injector
22921 // subtree.
22922 const _injector = isComponentFactory ? contextInjector : this.parentInjector;
22923 // DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) ||
22924 // undefined` expression which seems to cause internal google apps to fail. This is documented
22925 // in the following internal bug issue: go/b/142967802
22926 const result = _injector.get(NgModuleRef$1, null);
22927 if (result) {
22928 ngModuleRef = result;
22929 }
22930 }
22931 const componentRef = componentFactory.create(contextInjector, projectableNodes, undefined, ngModuleRef);
22932 this.insert(componentRef.hostView, index);
22933 return componentRef;
22934 }
22935 insert(viewRef, index) {
22936 const lView = viewRef._lView;
22937 const tView = lView[TVIEW];
22938 if (ngDevMode && viewRef.destroyed) {
22939 throw new Error('Cannot insert a destroyed View in a ViewContainer!');
22940 }
22941 if (viewAttachedToContainer(lView)) {
22942 // If view is already attached, detach it first so we clean up references appropriately.
22943 const prevIdx = this.indexOf(viewRef);
22944 // A view might be attached either to this or a different container. The `prevIdx` for
22945 // those cases will be:
22946 // equal to -1 for views attached to this ViewContainerRef
22947 // >= 0 for views attached to a different ViewContainerRef
22948 if (prevIdx !== -1) {
22949 this.detach(prevIdx);
22950 }
22951 else {
22952 const prevLContainer = lView[PARENT];
22953 ngDevMode &&
22954 assertEqual(isLContainer(prevLContainer), true, 'An attached view should have its PARENT point to a container.');
22955 // We need to re-create a R3ViewContainerRef instance since those are not stored on
22956 // LView (nor anywhere else).
22957 const prevVCRef = new R3ViewContainerRef(prevLContainer, prevLContainer[T_HOST], prevLContainer[PARENT]);
22958 prevVCRef.detach(prevVCRef.indexOf(viewRef));
22959 }
22960 }
22961 // Logical operation of adding `LView` to `LContainer`
22962 const adjustedIdx = this._adjustIndex(index);
22963 const lContainer = this._lContainer;
22964 insertView(tView, lView, lContainer, adjustedIdx);
22965 // Physical operation of adding the DOM nodes.
22966 const beforeNode = getBeforeNodeForView(adjustedIdx, lContainer);
22967 const renderer = lView[RENDERER];
22968 const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
22969 if (parentRNode !== null) {
22970 addViewToContainer(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
22971 }
22972 viewRef.attachToViewContainerRef();
22973 addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
22974 return viewRef;
22975 }
22976 move(viewRef, newIndex) {
22977 if (ngDevMode && viewRef.destroyed) {
22978 throw new Error('Cannot move a destroyed View in a ViewContainer!');
22979 }
22980 return this.insert(viewRef, newIndex);
22981 }
22982 indexOf(viewRef) {
22983 const viewRefsArr = getViewRefs(this._lContainer);
22984 return viewRefsArr !== null ? viewRefsArr.indexOf(viewRef) : -1;
22985 }
22986 remove(index) {
22987 const adjustedIdx = this._adjustIndex(index, -1);
22988 const detachedView = detachView(this._lContainer, adjustedIdx);
22989 if (detachedView) {
22990 // Before destroying the view, remove it from the container's array of `ViewRef`s.
22991 // This ensures the view container length is updated before calling
22992 // `destroyLView`, which could recursively call view container methods that
22993 // rely on an accurate container length.
22994 // (e.g. a method on this view container being called by a child directive's OnDestroy
22995 // lifecycle hook)
22996 removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx);
22997 destroyLView(detachedView[TVIEW], detachedView);
22998 }
22999 }
23000 detach(index) {
23001 const adjustedIdx = this._adjustIndex(index, -1);
23002 const view = detachView(this._lContainer, adjustedIdx);
23003 const wasDetached = view && removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx) != null;
23004 return wasDetached ? new ViewRef$1(view) : null;
23005 }
23006 _adjustIndex(index, shift = 0) {
23007 if (index == null) {
23008 return this.length + shift;
23009 }
23010 if (ngDevMode) {
23011 assertGreaterThan(index, -1, `ViewRef index must be positive, got ${index}`);
23012 // +1 because it's legal to insert at the end.
23013 assertLessThan(index, this.length + 1 + shift, 'index');
23014 }
23015 return index;
23016 }
23017};
23018function getViewRefs(lContainer) {
23019 return lContainer[VIEW_REFS];
23020}
23021function getOrCreateViewRefs(lContainer) {
23022 return (lContainer[VIEW_REFS] || (lContainer[VIEW_REFS] = []));
23023}
23024/**
23025 * Creates a ViewContainerRef and stores it on the injector.
23026 *
23027 * @param ViewContainerRefToken The ViewContainerRef type
23028 * @param ElementRefToken The ElementRef type
23029 * @param hostTNode The node that is requesting a ViewContainerRef
23030 * @param hostLView The view to which the node belongs
23031 * @returns The ViewContainerRef instance to use
23032 */
23033function createContainerRef(hostTNode, hostLView) {
23034 ngDevMode && assertTNodeType(hostTNode, 12 /* AnyContainer */ | 3 /* AnyRNode */);
23035 let lContainer;
23036 const slotValue = hostLView[hostTNode.index];
23037 if (isLContainer(slotValue)) {
23038 // If the host is a container, we don't need to create a new LContainer
23039 lContainer = slotValue;
23040 }
23041 else {
23042 let commentNode;
23043 // If the host is an element container, the native host element is guaranteed to be a
23044 // comment and we can reuse that comment as anchor element for the new LContainer.
23045 // The comment node in question is already part of the DOM structure so we don't need to append
23046 // it again.
23047 if (hostTNode.type & 8 /* ElementContainer */) {
23048 commentNode = unwrapRNode(slotValue);
23049 }
23050 else {
23051 // If the host is a regular element, we have to insert a comment node manually which will
23052 // be used as an anchor when inserting elements. In this specific case we use low-level DOM
23053 // manipulation to insert it.
23054 const renderer = hostLView[RENDERER];
23055 ngDevMode && ngDevMode.rendererCreateComment++;
23056 commentNode = renderer.createComment(ngDevMode ? 'container' : '');
23057 const hostNative = getNativeByTNode(hostTNode, hostLView);
23058 const parentOfHostNative = nativeParentNode(renderer, hostNative);
23059 nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
23060 }
23061 hostLView[hostTNode.index] = lContainer =
23062 createLContainer(slotValue, hostLView, commentNode, hostTNode);
23063 addToViewTree(hostLView, lContainer);
23064 }
23065 return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
23066}
23067
23068/**
23069 * @license
23070 * Copyright Google LLC All Rights Reserved.
23071 *
23072 * Use of this source code is governed by an MIT-style license that can be
23073 * found in the LICENSE file at https://angular.io/license
23074 */
23075// Note: This hack is necessary so we don't erroneously get a circular dependency
23076// failure based on types.
23077const unusedValueExportToPlacateAjd$1 = 1;
23078
23079/**
23080 * @license
23081 * Copyright Google LLC All Rights Reserved.
23082 *
23083 * Use of this source code is governed by an MIT-style license that can be
23084 * found in the LICENSE file at https://angular.io/license
23085 */
23086// Note: This hack is necessary so we don't erroneously get a circular dependency
23087// failure based on types.
23088const unusedValueExportToPlacateAjd = 1;
23089
23090/**
23091 * @license
23092 * Copyright Google LLC All Rights Reserved.
23093 *
23094 * Use of this source code is governed by an MIT-style license that can be
23095 * found in the LICENSE file at https://angular.io/license
23096 */
23097const unusedValueToPlacateAjd = unusedValueExportToPlacateAjd$1 + unusedValueExportToPlacateAjd$5 + unusedValueExportToPlacateAjd$4 + unusedValueExportToPlacateAjd;
23098class LQuery_ {
23099 constructor(queryList) {
23100 this.queryList = queryList;
23101 this.matches = null;
23102 }
23103 clone() {
23104 return new LQuery_(this.queryList);
23105 }
23106 setDirty() {
23107 this.queryList.setDirty();
23108 }
23109}
23110class LQueries_ {
23111 constructor(queries = []) {
23112 this.queries = queries;
23113 }
23114 createEmbeddedView(tView) {
23115 const tQueries = tView.queries;
23116 if (tQueries !== null) {
23117 const noOfInheritedQueries = tView.contentQueries !== null ? tView.contentQueries[0] : tQueries.length;
23118 const viewLQueries = [];
23119 // An embedded view has queries propagated from a declaration view at the beginning of the
23120 // TQueries collection and up until a first content query declared in the embedded view. Only
23121 // propagated LQueries are created at this point (LQuery corresponding to declared content
23122 // queries will be instantiated from the content query instructions for each directive).
23123 for (let i = 0; i < noOfInheritedQueries; i++) {
23124 const tQuery = tQueries.getByIndex(i);
23125 const parentLQuery = this.queries[tQuery.indexInDeclarationView];
23126 viewLQueries.push(parentLQuery.clone());
23127 }
23128 return new LQueries_(viewLQueries);
23129 }
23130 return null;
23131 }
23132 insertView(tView) {
23133 this.dirtyQueriesWithMatches(tView);
23134 }
23135 detachView(tView) {
23136 this.dirtyQueriesWithMatches(tView);
23137 }
23138 dirtyQueriesWithMatches(tView) {
23139 for (let i = 0; i < this.queries.length; i++) {
23140 if (getTQuery(tView, i).matches !== null) {
23141 this.queries[i].setDirty();
23142 }
23143 }
23144 }
23145}
23146class TQueryMetadata_ {
23147 constructor(predicate, flags, read = null) {
23148 this.predicate = predicate;
23149 this.flags = flags;
23150 this.read = read;
23151 }
23152}
23153class TQueries_ {
23154 constructor(queries = []) {
23155 this.queries = queries;
23156 }
23157 elementStart(tView, tNode) {
23158 ngDevMode &&
23159 assertFirstCreatePass(tView, 'Queries should collect results on the first template pass only');
23160 for (let i = 0; i < this.queries.length; i++) {
23161 this.queries[i].elementStart(tView, tNode);
23162 }
23163 }
23164 elementEnd(tNode) {
23165 for (let i = 0; i < this.queries.length; i++) {
23166 this.queries[i].elementEnd(tNode);
23167 }
23168 }
23169 embeddedTView(tNode) {
23170 let queriesForTemplateRef = null;
23171 for (let i = 0; i < this.length; i++) {
23172 const childQueryIndex = queriesForTemplateRef !== null ? queriesForTemplateRef.length : 0;
23173 const tqueryClone = this.getByIndex(i).embeddedTView(tNode, childQueryIndex);
23174 if (tqueryClone) {
23175 tqueryClone.indexInDeclarationView = i;
23176 if (queriesForTemplateRef !== null) {
23177 queriesForTemplateRef.push(tqueryClone);
23178 }
23179 else {
23180 queriesForTemplateRef = [tqueryClone];
23181 }
23182 }
23183 }
23184 return queriesForTemplateRef !== null ? new TQueries_(queriesForTemplateRef) : null;
23185 }
23186 template(tView, tNode) {
23187 ngDevMode &&
23188 assertFirstCreatePass(tView, 'Queries should collect results on the first template pass only');
23189 for (let i = 0; i < this.queries.length; i++) {
23190 this.queries[i].template(tView, tNode);
23191 }
23192 }
23193 getByIndex(index) {
23194 ngDevMode && assertIndexInRange(this.queries, index);
23195 return this.queries[index];
23196 }
23197 get length() {
23198 return this.queries.length;
23199 }
23200 track(tquery) {
23201 this.queries.push(tquery);
23202 }
23203}
23204class TQuery_ {
23205 constructor(metadata, nodeIndex = -1) {
23206 this.metadata = metadata;
23207 this.matches = null;
23208 this.indexInDeclarationView = -1;
23209 this.crossesNgTemplate = false;
23210 /**
23211 * A flag indicating if a given query still applies to nodes it is crossing. We use this flag
23212 * (alongside with _declarationNodeIndex) to know when to stop applying content queries to
23213 * elements in a template.
23214 */
23215 this._appliesToNextNode = true;
23216 this._declarationNodeIndex = nodeIndex;
23217 }
23218 elementStart(tView, tNode) {
23219 if (this.isApplyingToNode(tNode)) {
23220 this.matchTNode(tView, tNode);
23221 }
23222 }
23223 elementEnd(tNode) {
23224 if (this._declarationNodeIndex === tNode.index) {
23225 this._appliesToNextNode = false;
23226 }
23227 }
23228 template(tView, tNode) {
23229 this.elementStart(tView, tNode);
23230 }
23231 embeddedTView(tNode, childQueryIndex) {
23232 if (this.isApplyingToNode(tNode)) {
23233 this.crossesNgTemplate = true;
23234 // A marker indicating a `<ng-template>` element (a placeholder for query results from
23235 // embedded views created based on this `<ng-template>`).
23236 this.addMatch(-tNode.index, childQueryIndex);
23237 return new TQuery_(this.metadata);
23238 }
23239 return null;
23240 }
23241 isApplyingToNode(tNode) {
23242 if (this._appliesToNextNode &&
23243 (this.metadata.flags & 1 /* descendants */) !== 1 /* descendants */) {
23244 const declarationNodeIdx = this._declarationNodeIndex;
23245 let parent = tNode.parent;
23246 // Determine if a given TNode is a "direct" child of a node on which a content query was
23247 // declared (only direct children of query's host node can match with the descendants: false
23248 // option). There are 3 main use-case / conditions to consider here:
23249 // - <needs-target><i #target></i></needs-target>: here <i #target> parent node is a query
23250 // host node;
23251 // - <needs-target><ng-template [ngIf]="true"><i #target></i></ng-template></needs-target>:
23252 // here <i #target> parent node is null;
23253 // - <needs-target><ng-container><i #target></i></ng-container></needs-target>: here we need
23254 // to go past `<ng-container>` to determine <i #target> parent node (but we shouldn't traverse
23255 // up past the query's host node!).
23256 while (parent !== null && (parent.type & 8 /* ElementContainer */) &&
23257 parent.index !== declarationNodeIdx) {
23258 parent = parent.parent;
23259 }
23260 return declarationNodeIdx === (parent !== null ? parent.index : -1);
23261 }
23262 return this._appliesToNextNode;
23263 }
23264 matchTNode(tView, tNode) {
23265 const predicate = this.metadata.predicate;
23266 if (Array.isArray(predicate)) {
23267 for (let i = 0; i < predicate.length; i++) {
23268 const name = predicate[i];
23269 this.matchTNodeWithReadOption(tView, tNode, getIdxOfMatchingSelector(tNode, name));
23270 // Also try matching the name to a provider since strings can be used as DI tokens too.
23271 this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, name, false, false));
23272 }
23273 }
23274 else {
23275 if (predicate === TemplateRef) {
23276 if (tNode.type & 4 /* Container */) {
23277 this.matchTNodeWithReadOption(tView, tNode, -1);
23278 }
23279 }
23280 else {
23281 this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, predicate, false, false));
23282 }
23283 }
23284 }
23285 matchTNodeWithReadOption(tView, tNode, nodeMatchIdx) {
23286 if (nodeMatchIdx !== null) {
23287 const read = this.metadata.read;
23288 if (read !== null) {
23289 if (read === ElementRef || read === ViewContainerRef ||
23290 read === TemplateRef && (tNode.type & 4 /* Container */)) {
23291 this.addMatch(tNode.index, -2);
23292 }
23293 else {
23294 const directiveOrProviderIdx = locateDirectiveOrProvider(tNode, tView, read, false, false);
23295 if (directiveOrProviderIdx !== null) {
23296 this.addMatch(tNode.index, directiveOrProviderIdx);
23297 }
23298 }
23299 }
23300 else {
23301 this.addMatch(tNode.index, nodeMatchIdx);
23302 }
23303 }
23304 }
23305 addMatch(tNodeIdx, matchIdx) {
23306 if (this.matches === null) {
23307 this.matches = [tNodeIdx, matchIdx];
23308 }
23309 else {
23310 this.matches.push(tNodeIdx, matchIdx);
23311 }
23312 }
23313}
23314/**
23315 * Iterates over local names for a given node and returns directive index
23316 * (or -1 if a local name points to an element).
23317 *
23318 * @param tNode static data of a node to check
23319 * @param selector selector to match
23320 * @returns directive index, -1 or null if a selector didn't match any of the local names
23321 */
23322function getIdxOfMatchingSelector(tNode, selector) {
23323 const localNames = tNode.localNames;
23324 if (localNames !== null) {
23325 for (let i = 0; i < localNames.length; i += 2) {
23326 if (localNames[i] === selector) {
23327 return localNames[i + 1];
23328 }
23329 }
23330 }
23331 return null;
23332}
23333function createResultByTNodeType(tNode, currentView) {
23334 if (tNode.type & (3 /* AnyRNode */ | 8 /* ElementContainer */)) {
23335 return createElementRef(tNode, currentView);
23336 }
23337 else if (tNode.type & 4 /* Container */) {
23338 return createTemplateRef(tNode, currentView);
23339 }
23340 return null;
23341}
23342function createResultForNode(lView, tNode, matchingIdx, read) {
23343 if (matchingIdx === -1) {
23344 // if read token and / or strategy is not specified, detect it using appropriate tNode type
23345 return createResultByTNodeType(tNode, lView);
23346 }
23347 else if (matchingIdx === -2) {
23348 // read a special token from a node injector
23349 return createSpecialToken(lView, tNode, read);
23350 }
23351 else {
23352 // read a token
23353 return getNodeInjectable(lView, lView[TVIEW], matchingIdx, tNode);
23354 }
23355}
23356function createSpecialToken(lView, tNode, read) {
23357 if (read === ElementRef) {
23358 return createElementRef(tNode, lView);
23359 }
23360 else if (read === TemplateRef) {
23361 return createTemplateRef(tNode, lView);
23362 }
23363 else if (read === ViewContainerRef) {
23364 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */);
23365 return createContainerRef(tNode, lView);
23366 }
23367 else {
23368 ngDevMode &&
23369 throwError(`Special token to read should be one of ElementRef, TemplateRef or ViewContainerRef but got ${stringify(read)}.`);
23370 }
23371}
23372/**
23373 * A helper function that creates query results for a given view. This function is meant to do the
23374 * processing once and only once for a given view instance (a set of results for a given view
23375 * doesn't change).
23376 */
23377function materializeViewResults(tView, lView, tQuery, queryIndex) {
23378 const lQuery = lView[QUERIES].queries[queryIndex];
23379 if (lQuery.matches === null) {
23380 const tViewData = tView.data;
23381 const tQueryMatches = tQuery.matches;
23382 const result = [];
23383 for (let i = 0; i < tQueryMatches.length; i += 2) {
23384 const matchedNodeIdx = tQueryMatches[i];
23385 if (matchedNodeIdx < 0) {
23386 // we at the <ng-template> marker which might have results in views created based on this
23387 // <ng-template> - those results will be in separate views though, so here we just leave
23388 // null as a placeholder
23389 result.push(null);
23390 }
23391 else {
23392 ngDevMode && assertIndexInRange(tViewData, matchedNodeIdx);
23393 const tNode = tViewData[matchedNodeIdx];
23394 result.push(createResultForNode(lView, tNode, tQueryMatches[i + 1], tQuery.metadata.read));
23395 }
23396 }
23397 lQuery.matches = result;
23398 }
23399 return lQuery.matches;
23400}
23401/**
23402 * A helper function that collects (already materialized) query results from a tree of views,
23403 * starting with a provided LView.
23404 */
23405function collectQueryResults(tView, lView, queryIndex, result) {
23406 const tQuery = tView.queries.getByIndex(queryIndex);
23407 const tQueryMatches = tQuery.matches;
23408 if (tQueryMatches !== null) {
23409 const lViewResults = materializeViewResults(tView, lView, tQuery, queryIndex);
23410 for (let i = 0; i < tQueryMatches.length; i += 2) {
23411 const tNodeIdx = tQueryMatches[i];
23412 if (tNodeIdx > 0) {
23413 result.push(lViewResults[i / 2]);
23414 }
23415 else {
23416 const childQueryIndex = tQueryMatches[i + 1];
23417 const declarationLContainer = lView[-tNodeIdx];
23418 ngDevMode && assertLContainer(declarationLContainer);
23419 // collect matches for views inserted in this container
23420 for (let i = CONTAINER_HEADER_OFFSET; i < declarationLContainer.length; i++) {
23421 const embeddedLView = declarationLContainer[i];
23422 if (embeddedLView[DECLARATION_LCONTAINER] === embeddedLView[PARENT]) {
23423 collectQueryResults(embeddedLView[TVIEW], embeddedLView, childQueryIndex, result);
23424 }
23425 }
23426 // collect matches for views created from this declaration container and inserted into
23427 // different containers
23428 if (declarationLContainer[MOVED_VIEWS] !== null) {
23429 const embeddedLViews = declarationLContainer[MOVED_VIEWS];
23430 for (let i = 0; i < embeddedLViews.length; i++) {
23431 const embeddedLView = embeddedLViews[i];
23432 collectQueryResults(embeddedLView[TVIEW], embeddedLView, childQueryIndex, result);
23433 }
23434 }
23435 }
23436 }
23437 }
23438 return result;
23439}
23440/**
23441 * Refreshes a query by combining matches from all active views and removing matches from deleted
23442 * views.
23443 *
23444 * @returns `true` if a query got dirty during change detection or if this is a static query
23445 * resolving in creation mode, `false` otherwise.
23446 *
23447 * @codeGenApi
23448 */
23449function ɵɵqueryRefresh(queryList) {
23450 const lView = getLView();
23451 const tView = getTView();
23452 const queryIndex = getCurrentQueryIndex();
23453 setCurrentQueryIndex(queryIndex + 1);
23454 const tQuery = getTQuery(tView, queryIndex);
23455 if (queryList.dirty &&
23456 (isCreationMode(lView) ===
23457 ((tQuery.metadata.flags & 2 /* isStatic */) === 2 /* isStatic */))) {
23458 if (tQuery.matches === null) {
23459 queryList.reset([]);
23460 }
23461 else {
23462 const result = tQuery.crossesNgTemplate ?
23463 collectQueryResults(tView, lView, queryIndex, []) :
23464 materializeViewResults(tView, lView, tQuery, queryIndex);
23465 queryList.reset(result, unwrapElementRef);
23466 queryList.notifyOnChanges();
23467 }
23468 return true;
23469 }
23470 return false;
23471}
23472/**
23473 * Creates new QueryList, stores the reference in LView and returns QueryList.
23474 *
23475 * @param predicate The type for which the query will search
23476 * @param flags Flags associated with the query
23477 * @param read What to save in the query
23478 *
23479 * @codeGenApi
23480 */
23481function ɵɵviewQuery(predicate, flags, read) {
23482 ngDevMode && assertNumber(flags, 'Expecting flags');
23483 const tView = getTView();
23484 if (tView.firstCreatePass) {
23485 createTQuery(tView, new TQueryMetadata_(predicate, flags, read), -1);
23486 if ((flags & 2 /* isStatic */) === 2 /* isStatic */) {
23487 tView.staticViewQueries = true;
23488 }
23489 }
23490 createLQuery(tView, getLView(), flags);
23491}
23492/**
23493 * Registers a QueryList, associated with a content query, for later refresh (part of a view
23494 * refresh).
23495 *
23496 * @param directiveIndex Current directive index
23497 * @param predicate The type for which the query will search
23498 * @param flags Flags associated with the query
23499 * @param read What to save in the query
23500 * @returns QueryList<T>
23501 *
23502 * @codeGenApi
23503 */
23504function ɵɵcontentQuery(directiveIndex, predicate, flags, read) {
23505 ngDevMode && assertNumber(flags, 'Expecting flags');
23506 const tView = getTView();
23507 if (tView.firstCreatePass) {
23508 const tNode = getCurrentTNode();
23509 createTQuery(tView, new TQueryMetadata_(predicate, flags, read), tNode.index);
23510 saveContentQueryAndDirectiveIndex(tView, directiveIndex);
23511 if ((flags & 2 /* isStatic */) === 2 /* isStatic */) {
23512 tView.staticContentQueries = true;
23513 }
23514 }
23515 createLQuery(tView, getLView(), flags);
23516}
23517/**
23518 * Loads a QueryList corresponding to the current view or content query.
23519 *
23520 * @codeGenApi
23521 */
23522function ɵɵloadQuery() {
23523 return loadQueryInternal(getLView(), getCurrentQueryIndex());
23524}
23525function loadQueryInternal(lView, queryIndex) {
23526 ngDevMode &&
23527 assertDefined(lView[QUERIES], 'LQueries should be defined when trying to load a query');
23528 ngDevMode && assertIndexInRange(lView[QUERIES].queries, queryIndex);
23529 return lView[QUERIES].queries[queryIndex].queryList;
23530}
23531function createLQuery(tView, lView, flags) {
23532 const queryList = new QueryList((flags & 4 /* emitDistinctChangesOnly */) === 4 /* emitDistinctChangesOnly */);
23533 storeCleanupWithContext(tView, lView, queryList, queryList.destroy);
23534 if (lView[QUERIES] === null)
23535 lView[QUERIES] = new LQueries_();
23536 lView[QUERIES].queries.push(new LQuery_(queryList));
23537}
23538function createTQuery(tView, metadata, nodeIndex) {
23539 if (tView.queries === null)
23540 tView.queries = new TQueries_();
23541 tView.queries.track(new TQuery_(metadata, nodeIndex));
23542}
23543function saveContentQueryAndDirectiveIndex(tView, directiveIndex) {
23544 const tViewContentQueries = tView.contentQueries || (tView.contentQueries = []);
23545 const lastSavedDirectiveIndex = tViewContentQueries.length ? tViewContentQueries[tViewContentQueries.length - 1] : -1;
23546 if (directiveIndex !== lastSavedDirectiveIndex) {
23547 tViewContentQueries.push(tView.queries.length - 1, directiveIndex);
23548 }
23549}
23550function getTQuery(tView, index) {
23551 ngDevMode && assertDefined(tView.queries, 'TQueries must be defined to retrieve a TQuery');
23552 return tView.queries.getByIndex(index);
23553}
23554
23555/**
23556 * @license
23557 * Copyright Google LLC All Rights Reserved.
23558 *
23559 * Use of this source code is governed by an MIT-style license that can be
23560 * found in the LICENSE file at https://angular.io/license
23561 */
23562/**
23563 * Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the
23564 * `<ng-template>` element.
23565 *
23566 * @codeGenApi
23567 */
23568function ɵɵtemplateRefExtractor(tNode, lView) {
23569 return createTemplateRef(tNode, lView);
23570}
23571
23572/**
23573 * @license
23574 * Copyright Google LLC All Rights Reserved.
23575 *
23576 * Use of this source code is governed by an MIT-style license that can be
23577 * found in the LICENSE file at https://angular.io/license
23578 */
23579
23580/**
23581 * @license
23582 * Copyright Google LLC All Rights Reserved.
23583 *
23584 * Use of this source code is governed by an MIT-style license that can be
23585 * found in the LICENSE file at https://angular.io/license
23586 */
23587/**
23588 * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
23589 *
23590 * This should be kept up to date with the public exports of @angular/core.
23591 */
23592const angularCoreEnv = (() => ({
23593 'ɵɵattribute': ɵɵattribute,
23594 'ɵɵattributeInterpolate1': ɵɵattributeInterpolate1,
23595 'ɵɵattributeInterpolate2': ɵɵattributeInterpolate2,
23596 'ɵɵattributeInterpolate3': ɵɵattributeInterpolate3,
23597 'ɵɵattributeInterpolate4': ɵɵattributeInterpolate4,
23598 'ɵɵattributeInterpolate5': ɵɵattributeInterpolate5,
23599 'ɵɵattributeInterpolate6': ɵɵattributeInterpolate6,
23600 'ɵɵattributeInterpolate7': ɵɵattributeInterpolate7,
23601 'ɵɵattributeInterpolate8': ɵɵattributeInterpolate8,
23602 'ɵɵattributeInterpolateV': ɵɵattributeInterpolateV,
23603 'ɵɵdefineComponent': ɵɵdefineComponent,
23604 'ɵɵdefineDirective': ɵɵdefineDirective,
23605 'ɵɵdefineInjectable': ɵɵdefineInjectable,
23606 'ɵɵdefineInjector': ɵɵdefineInjector,
23607 'ɵɵdefineNgModule': ɵɵdefineNgModule,
23608 'ɵɵdefinePipe': ɵɵdefinePipe,
23609 'ɵɵdirectiveInject': ɵɵdirectiveInject,
23610 'ɵɵgetInheritedFactory': ɵɵgetInheritedFactory,
23611 'ɵɵinject': ɵɵinject,
23612 'ɵɵinjectAttribute': ɵɵinjectAttribute,
23613 'ɵɵinvalidFactory': ɵɵinvalidFactory,
23614 'ɵɵinvalidFactoryDep': ɵɵinvalidFactoryDep,
23615 'ɵɵtemplateRefExtractor': ɵɵtemplateRefExtractor,
23616 'ɵɵNgOnChangesFeature': ɵɵNgOnChangesFeature,
23617 'ɵɵProvidersFeature': ɵɵProvidersFeature,
23618 'ɵɵCopyDefinitionFeature': ɵɵCopyDefinitionFeature,
23619 'ɵɵInheritDefinitionFeature': ɵɵInheritDefinitionFeature,
23620 'ɵɵnextContext': ɵɵnextContext,
23621 'ɵɵnamespaceHTML': ɵɵnamespaceHTML,
23622 'ɵɵnamespaceMathML': ɵɵnamespaceMathML,
23623 'ɵɵnamespaceSVG': ɵɵnamespaceSVG,
23624 'ɵɵenableBindings': ɵɵenableBindings,
23625 'ɵɵdisableBindings': ɵɵdisableBindings,
23626 'ɵɵelementStart': ɵɵelementStart,
23627 'ɵɵelementEnd': ɵɵelementEnd,
23628 'ɵɵelement': ɵɵelement,
23629 'ɵɵelementContainerStart': ɵɵelementContainerStart,
23630 'ɵɵelementContainerEnd': ɵɵelementContainerEnd,
23631 'ɵɵelementContainer': ɵɵelementContainer,
23632 'ɵɵpureFunction0': ɵɵpureFunction0,
23633 'ɵɵpureFunction1': ɵɵpureFunction1,
23634 'ɵɵpureFunction2': ɵɵpureFunction2,
23635 'ɵɵpureFunction3': ɵɵpureFunction3,
23636 'ɵɵpureFunction4': ɵɵpureFunction4,
23637 'ɵɵpureFunction5': ɵɵpureFunction5,
23638 'ɵɵpureFunction6': ɵɵpureFunction6,
23639 'ɵɵpureFunction7': ɵɵpureFunction7,
23640 'ɵɵpureFunction8': ɵɵpureFunction8,
23641 'ɵɵpureFunctionV': ɵɵpureFunctionV,
23642 'ɵɵgetCurrentView': ɵɵgetCurrentView,
23643 'ɵɵrestoreView': ɵɵrestoreView,
23644 'ɵɵlistener': ɵɵlistener,
23645 'ɵɵprojection': ɵɵprojection,
23646 'ɵɵsyntheticHostProperty': ɵɵsyntheticHostProperty,
23647 'ɵɵsyntheticHostListener': ɵɵsyntheticHostListener,
23648 'ɵɵpipeBind1': ɵɵpipeBind1,
23649 'ɵɵpipeBind2': ɵɵpipeBind2,
23650 'ɵɵpipeBind3': ɵɵpipeBind3,
23651 'ɵɵpipeBind4': ɵɵpipeBind4,
23652 'ɵɵpipeBindV': ɵɵpipeBindV,
23653 'ɵɵprojectionDef': ɵɵprojectionDef,
23654 'ɵɵhostProperty': ɵɵhostProperty,
23655 'ɵɵproperty': ɵɵproperty,
23656 'ɵɵpropertyInterpolate': ɵɵpropertyInterpolate,
23657 'ɵɵpropertyInterpolate1': ɵɵpropertyInterpolate1,
23658 'ɵɵpropertyInterpolate2': ɵɵpropertyInterpolate2,
23659 'ɵɵpropertyInterpolate3': ɵɵpropertyInterpolate3,
23660 'ɵɵpropertyInterpolate4': ɵɵpropertyInterpolate4,
23661 'ɵɵpropertyInterpolate5': ɵɵpropertyInterpolate5,
23662 'ɵɵpropertyInterpolate6': ɵɵpropertyInterpolate6,
23663 'ɵɵpropertyInterpolate7': ɵɵpropertyInterpolate7,
23664 'ɵɵpropertyInterpolate8': ɵɵpropertyInterpolate8,
23665 'ɵɵpropertyInterpolateV': ɵɵpropertyInterpolateV,
23666 'ɵɵpipe': ɵɵpipe,
23667 'ɵɵqueryRefresh': ɵɵqueryRefresh,
23668 'ɵɵviewQuery': ɵɵviewQuery,
23669 'ɵɵloadQuery': ɵɵloadQuery,
23670 'ɵɵcontentQuery': ɵɵcontentQuery,
23671 'ɵɵreference': ɵɵreference,
23672 'ɵɵclassMap': ɵɵclassMap,
23673 'ɵɵclassMapInterpolate1': ɵɵclassMapInterpolate1,
23674 'ɵɵclassMapInterpolate2': ɵɵclassMapInterpolate2,
23675 'ɵɵclassMapInterpolate3': ɵɵclassMapInterpolate3,
23676 'ɵɵclassMapInterpolate4': ɵɵclassMapInterpolate4,
23677 'ɵɵclassMapInterpolate5': ɵɵclassMapInterpolate5,
23678 'ɵɵclassMapInterpolate6': ɵɵclassMapInterpolate6,
23679 'ɵɵclassMapInterpolate7': ɵɵclassMapInterpolate7,
23680 'ɵɵclassMapInterpolate8': ɵɵclassMapInterpolate8,
23681 'ɵɵclassMapInterpolateV': ɵɵclassMapInterpolateV,
23682 'ɵɵstyleMap': ɵɵstyleMap,
23683 'ɵɵstyleMapInterpolate1': ɵɵstyleMapInterpolate1,
23684 'ɵɵstyleMapInterpolate2': ɵɵstyleMapInterpolate2,
23685 'ɵɵstyleMapInterpolate3': ɵɵstyleMapInterpolate3,
23686 'ɵɵstyleMapInterpolate4': ɵɵstyleMapInterpolate4,
23687 'ɵɵstyleMapInterpolate5': ɵɵstyleMapInterpolate5,
23688 'ɵɵstyleMapInterpolate6': ɵɵstyleMapInterpolate6,
23689 'ɵɵstyleMapInterpolate7': ɵɵstyleMapInterpolate7,
23690 'ɵɵstyleMapInterpolate8': ɵɵstyleMapInterpolate8,
23691 'ɵɵstyleMapInterpolateV': ɵɵstyleMapInterpolateV,
23692 'ɵɵstyleProp': ɵɵstyleProp,
23693 'ɵɵstylePropInterpolate1': ɵɵstylePropInterpolate1,
23694 'ɵɵstylePropInterpolate2': ɵɵstylePropInterpolate2,
23695 'ɵɵstylePropInterpolate3': ɵɵstylePropInterpolate3,
23696 'ɵɵstylePropInterpolate4': ɵɵstylePropInterpolate4,
23697 'ɵɵstylePropInterpolate5': ɵɵstylePropInterpolate5,
23698 'ɵɵstylePropInterpolate6': ɵɵstylePropInterpolate6,
23699 'ɵɵstylePropInterpolate7': ɵɵstylePropInterpolate7,
23700 'ɵɵstylePropInterpolate8': ɵɵstylePropInterpolate8,
23701 'ɵɵstylePropInterpolateV': ɵɵstylePropInterpolateV,
23702 'ɵɵclassProp': ɵɵclassProp,
23703 'ɵɵadvance': ɵɵadvance,
23704 'ɵɵtemplate': ɵɵtemplate,
23705 'ɵɵtext': ɵɵtext,
23706 'ɵɵtextInterpolate': ɵɵtextInterpolate,
23707 'ɵɵtextInterpolate1': ɵɵtextInterpolate1,
23708 'ɵɵtextInterpolate2': ɵɵtextInterpolate2,
23709 'ɵɵtextInterpolate3': ɵɵtextInterpolate3,
23710 'ɵɵtextInterpolate4': ɵɵtextInterpolate4,
23711 'ɵɵtextInterpolate5': ɵɵtextInterpolate5,
23712 'ɵɵtextInterpolate6': ɵɵtextInterpolate6,
23713 'ɵɵtextInterpolate7': ɵɵtextInterpolate7,
23714 'ɵɵtextInterpolate8': ɵɵtextInterpolate8,
23715 'ɵɵtextInterpolateV': ɵɵtextInterpolateV,
23716 'ɵɵi18n': ɵɵi18n,
23717 'ɵɵi18nAttributes': ɵɵi18nAttributes,
23718 'ɵɵi18nExp': ɵɵi18nExp,
23719 'ɵɵi18nStart': ɵɵi18nStart,
23720 'ɵɵi18nEnd': ɵɵi18nEnd,
23721 'ɵɵi18nApply': ɵɵi18nApply,
23722 'ɵɵi18nPostprocess': ɵɵi18nPostprocess,
23723 'ɵɵresolveWindow': ɵɵresolveWindow,
23724 'ɵɵresolveDocument': ɵɵresolveDocument,
23725 'ɵɵresolveBody': ɵɵresolveBody,
23726 'ɵɵsetComponentScope': ɵɵsetComponentScope,
23727 'ɵɵsetNgModuleScope': ɵɵsetNgModuleScope,
23728 'ɵɵsanitizeHtml': ɵɵsanitizeHtml,
23729 'ɵɵsanitizeStyle': ɵɵsanitizeStyle,
23730 'ɵɵsanitizeResourceUrl': ɵɵsanitizeResourceUrl,
23731 'ɵɵsanitizeScript': ɵɵsanitizeScript,
23732 'ɵɵsanitizeUrl': ɵɵsanitizeUrl,
23733 'ɵɵsanitizeUrlOrResourceUrl': ɵɵsanitizeUrlOrResourceUrl,
23734 'ɵɵtrustConstantHtml': ɵɵtrustConstantHtml,
23735 'ɵɵtrustConstantResourceUrl': ɵɵtrustConstantResourceUrl,
23736 'forwardRef': forwardRef,
23737 'resolveForwardRef': resolveForwardRef,
23738}))();
23739
23740let jitOptions = null;
23741function setJitOptions(options) {
23742 if (jitOptions !== null) {
23743 if (options.defaultEncapsulation !== jitOptions.defaultEncapsulation) {
23744 ngDevMode &&
23745 console.error('Provided value for `defaultEncapsulation` can not be changed once it has been set.');
23746 return;
23747 }
23748 if (options.preserveWhitespaces !== jitOptions.preserveWhitespaces) {
23749 ngDevMode &&
23750 console.error('Provided value for `preserveWhitespaces` can not be changed once it has been set.');
23751 return;
23752 }
23753 }
23754 jitOptions = options;
23755}
23756function getJitOptions() {
23757 return jitOptions;
23758}
23759function resetJitOptions() {
23760 jitOptions = null;
23761}
23762
23763/**
23764 * @license
23765 * Copyright Google LLC All Rights Reserved.
23766 *
23767 * Use of this source code is governed by an MIT-style license that can be
23768 * found in the LICENSE file at https://angular.io/license
23769 */
23770const moduleQueue = [];
23771/**
23772 * Enqueues moduleDef to be checked later to see if scope can be set on its
23773 * component declarations.
23774 */
23775function enqueueModuleForDelayedScoping(moduleType, ngModule) {
23776 moduleQueue.push({ moduleType, ngModule });
23777}
23778let flushingModuleQueue = false;
23779/**
23780 * Loops over queued module definitions, if a given module definition has all of its
23781 * declarations resolved, it dequeues that module definition and sets the scope on
23782 * its declarations.
23783 */
23784function flushModuleScopingQueueAsMuchAsPossible() {
23785 if (!flushingModuleQueue) {
23786 flushingModuleQueue = true;
23787 try {
23788 for (let i = moduleQueue.length - 1; i >= 0; i--) {
23789 const { moduleType, ngModule } = moduleQueue[i];
23790 if (ngModule.declarations && ngModule.declarations.every(isResolvedDeclaration)) {
23791 // dequeue
23792 moduleQueue.splice(i, 1);
23793 setScopeOnDeclaredComponents(moduleType, ngModule);
23794 }
23795 }
23796 }
23797 finally {
23798 flushingModuleQueue = false;
23799 }
23800 }
23801}
23802/**
23803 * Returns truthy if a declaration has resolved. If the declaration happens to be
23804 * an array of declarations, it will recurse to check each declaration in that array
23805 * (which may also be arrays).
23806 */
23807function isResolvedDeclaration(declaration) {
23808 if (Array.isArray(declaration)) {
23809 return declaration.every(isResolvedDeclaration);
23810 }
23811 return !!resolveForwardRef(declaration);
23812}
23813/**
23814 * Compiles a module in JIT mode.
23815 *
23816 * This function automatically gets called when a class has a `@NgModule` decorator.
23817 */
23818function compileNgModule(moduleType, ngModule = {}) {
23819 compileNgModuleDefs(moduleType, ngModule);
23820 // Because we don't know if all declarations have resolved yet at the moment the
23821 // NgModule decorator is executing, we're enqueueing the setting of module scope
23822 // on its declarations to be run at a later time when all declarations for the module,
23823 // including forward refs, have resolved.
23824 enqueueModuleForDelayedScoping(moduleType, ngModule);
23825}
23826/**
23827 * Compiles and adds the `ɵmod`, `ɵfac` and `ɵinj` properties to the module class.
23828 *
23829 * It's possible to compile a module via this API which will allow duplicate declarations in its
23830 * root.
23831 */
23832function compileNgModuleDefs(moduleType, ngModule, allowDuplicateDeclarationsInRoot = false) {
23833 ngDevMode && assertDefined(moduleType, 'Required value moduleType');
23834 ngDevMode && assertDefined(ngModule, 'Required value ngModule');
23835 const declarations = flatten(ngModule.declarations || EMPTY_ARRAY);
23836 let ngModuleDef = null;
23837 Object.defineProperty(moduleType, NG_MOD_DEF, {
23838 configurable: true,
23839 get: () => {
23840 if (ngModuleDef === null) {
23841 if (ngDevMode && ngModule.imports && ngModule.imports.indexOf(moduleType) > -1) {
23842 // We need to assert this immediately, because allowing it to continue will cause it to
23843 // go into an infinite loop before we've reached the point where we throw all the errors.
23844 throw new Error(`'${stringifyForError(moduleType)}' module can't import itself`);
23845 }
23846 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'NgModule', type: moduleType });
23847 ngModuleDef = compiler.compileNgModule(angularCoreEnv, `ng:///${moduleType.name}/ɵmod.js`, {
23848 type: moduleType,
23849 bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(resolveForwardRef),
23850 declarations: declarations.map(resolveForwardRef),
23851 imports: flatten(ngModule.imports || EMPTY_ARRAY)
23852 .map(resolveForwardRef)
23853 .map(expandModuleWithProviders),
23854 exports: flatten(ngModule.exports || EMPTY_ARRAY)
23855 .map(resolveForwardRef)
23856 .map(expandModuleWithProviders),
23857 schemas: ngModule.schemas ? flatten(ngModule.schemas) : null,
23858 id: ngModule.id || null,
23859 });
23860 // Set `schemas` on ngModuleDef to an empty array in JIT mode to indicate that runtime
23861 // should verify that there are no unknown elements in a template. In AOT mode, that check
23862 // happens at compile time and `schemas` information is not present on Component and Module
23863 // defs after compilation (so the check doesn't happen the second time at runtime).
23864 if (!ngModuleDef.schemas) {
23865 ngModuleDef.schemas = [];
23866 }
23867 }
23868 return ngModuleDef;
23869 }
23870 });
23871 let ngFactoryDef = null;
23872 Object.defineProperty(moduleType, NG_FACTORY_DEF, {
23873 get: () => {
23874 if (ngFactoryDef === null) {
23875 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'NgModule', type: moduleType });
23876 ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${moduleType.name}/ɵfac.js`, {
23877 name: moduleType.name,
23878 type: moduleType,
23879 deps: reflectDependencies(moduleType),
23880 target: compiler.FactoryTarget.NgModule,
23881 typeArgumentCount: 0,
23882 });
23883 }
23884 return ngFactoryDef;
23885 },
23886 // Make the property configurable in dev mode to allow overriding in tests
23887 configurable: !!ngDevMode,
23888 });
23889 let ngInjectorDef = null;
23890 Object.defineProperty(moduleType, NG_INJ_DEF, {
23891 get: () => {
23892 if (ngInjectorDef === null) {
23893 ngDevMode &&
23894 verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot);
23895 const meta = {
23896 name: moduleType.name,
23897 type: moduleType,
23898 providers: ngModule.providers || EMPTY_ARRAY,
23899 imports: [
23900 (ngModule.imports || EMPTY_ARRAY).map(resolveForwardRef),
23901 (ngModule.exports || EMPTY_ARRAY).map(resolveForwardRef),
23902 ],
23903 };
23904 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'NgModule', type: moduleType });
23905 ngInjectorDef =
23906 compiler.compileInjector(angularCoreEnv, `ng:///${moduleType.name}/ɵinj.js`, meta);
23907 }
23908 return ngInjectorDef;
23909 },
23910 // Make the property configurable in dev mode to allow overriding in tests
23911 configurable: !!ngDevMode,
23912 });
23913}
23914function verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot, importingModule) {
23915 if (verifiedNgModule.get(moduleType))
23916 return;
23917 verifiedNgModule.set(moduleType, true);
23918 moduleType = resolveForwardRef(moduleType);
23919 let ngModuleDef;
23920 if (importingModule) {
23921 ngModuleDef = getNgModuleDef(moduleType);
23922 if (!ngModuleDef) {
23923 throw new Error(`Unexpected value '${moduleType.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`);
23924 }
23925 }
23926 else {
23927 ngModuleDef = getNgModuleDef(moduleType, true);
23928 }
23929 const errors = [];
23930 const declarations = maybeUnwrapFn(ngModuleDef.declarations);
23931 const imports = maybeUnwrapFn(ngModuleDef.imports);
23932 flatten(imports).map(unwrapModuleWithProvidersImports).forEach(mod => {
23933 verifySemanticsOfNgModuleImport(mod, moduleType);
23934 verifySemanticsOfNgModuleDef(mod, false, moduleType);
23935 });
23936 const exports = maybeUnwrapFn(ngModuleDef.exports);
23937 declarations.forEach(verifyDeclarationsHaveDefinitions);
23938 declarations.forEach(verifyDirectivesHaveSelector);
23939 const combinedDeclarations = [
23940 ...declarations.map(resolveForwardRef),
23941 ...flatten(imports.map(computeCombinedExports)).map(resolveForwardRef),
23942 ];
23943 exports.forEach(verifyExportsAreDeclaredOrReExported);
23944 declarations.forEach(decl => verifyDeclarationIsUnique(decl, allowDuplicateDeclarationsInRoot));
23945 declarations.forEach(verifyComponentEntryComponentsIsPartOfNgModule);
23946 const ngModule = getAnnotation(moduleType, 'NgModule');
23947 if (ngModule) {
23948 ngModule.imports &&
23949 flatten(ngModule.imports).map(unwrapModuleWithProvidersImports).forEach(mod => {
23950 verifySemanticsOfNgModuleImport(mod, moduleType);
23951 verifySemanticsOfNgModuleDef(mod, false, moduleType);
23952 });
23953 ngModule.bootstrap && deepForEach(ngModule.bootstrap, verifyCorrectBootstrapType);
23954 ngModule.bootstrap && deepForEach(ngModule.bootstrap, verifyComponentIsPartOfNgModule);
23955 ngModule.entryComponents &&
23956 deepForEach(ngModule.entryComponents, verifyComponentIsPartOfNgModule);
23957 }
23958 // Throw Error if any errors were detected.
23959 if (errors.length) {
23960 throw new Error(errors.join('\n'));
23961 }
23962 ////////////////////////////////////////////////////////////////////////////////////////////////
23963 function verifyDeclarationsHaveDefinitions(type) {
23964 type = resolveForwardRef(type);
23965 const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef$1(type);
23966 if (!def) {
23967 errors.push(`Unexpected value '${stringifyForError(type)}' declared by the module '${stringifyForError(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`);
23968 }
23969 }
23970 function verifyDirectivesHaveSelector(type) {
23971 type = resolveForwardRef(type);
23972 const def = getDirectiveDef(type);
23973 if (!getComponentDef(type) && def && def.selectors.length == 0) {
23974 errors.push(`Directive ${stringifyForError(type)} has no selector, please add it!`);
23975 }
23976 }
23977 function verifyExportsAreDeclaredOrReExported(type) {
23978 type = resolveForwardRef(type);
23979 const kind = getComponentDef(type) && 'component' || getDirectiveDef(type) && 'directive' ||
23980 getPipeDef$1(type) && 'pipe';
23981 if (kind) {
23982 // only checked if we are declared as Component, Directive, or Pipe
23983 // Modules don't need to be declared or imported.
23984 if (combinedDeclarations.lastIndexOf(type) === -1) {
23985 // We are exporting something which we don't explicitly declare or import.
23986 errors.push(`Can't export ${kind} ${stringifyForError(type)} from ${stringifyForError(moduleType)} as it was neither declared nor imported!`);
23987 }
23988 }
23989 }
23990 function verifyDeclarationIsUnique(type, suppressErrors) {
23991 type = resolveForwardRef(type);
23992 const existingModule = ownerNgModule.get(type);
23993 if (existingModule && existingModule !== moduleType) {
23994 if (!suppressErrors) {
23995 const modules = [existingModule, moduleType].map(stringifyForError).sort();
23996 errors.push(`Type ${stringifyForError(type)} is part of the declarations of 2 modules: ${modules[0]} and ${modules[1]}! ` +
23997 `Please consider moving ${stringifyForError(type)} to a higher module that imports ${modules[0]} and ${modules[1]}. ` +
23998 `You can also create a new NgModule that exports and includes ${stringifyForError(type)} then import that NgModule in ${modules[0]} and ${modules[1]}.`);
23999 }
24000 }
24001 else {
24002 // Mark type as having owner.
24003 ownerNgModule.set(type, moduleType);
24004 }
24005 }
24006 function verifyComponentIsPartOfNgModule(type) {
24007 type = resolveForwardRef(type);
24008 const existingModule = ownerNgModule.get(type);
24009 if (!existingModule) {
24010 errors.push(`Component ${stringifyForError(type)} is not part of any NgModule or the module has not been imported into your module.`);
24011 }
24012 }
24013 function verifyCorrectBootstrapType(type) {
24014 type = resolveForwardRef(type);
24015 if (!getComponentDef(type)) {
24016 errors.push(`${stringifyForError(type)} cannot be used as an entry component.`);
24017 }
24018 }
24019 function verifyComponentEntryComponentsIsPartOfNgModule(type) {
24020 type = resolveForwardRef(type);
24021 if (getComponentDef(type)) {
24022 // We know we are component
24023 const component = getAnnotation(type, 'Component');
24024 if (component && component.entryComponents) {
24025 deepForEach(component.entryComponents, verifyComponentIsPartOfNgModule);
24026 }
24027 }
24028 }
24029 function verifySemanticsOfNgModuleImport(type, importingModule) {
24030 type = resolveForwardRef(type);
24031 if (getComponentDef(type) || getDirectiveDef(type)) {
24032 throw new Error(`Unexpected directive '${type.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`);
24033 }
24034 if (getPipeDef$1(type)) {
24035 throw new Error(`Unexpected pipe '${type.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`);
24036 }
24037 }
24038}
24039function unwrapModuleWithProvidersImports(typeOrWithProviders) {
24040 typeOrWithProviders = resolveForwardRef(typeOrWithProviders);
24041 return typeOrWithProviders.ngModule || typeOrWithProviders;
24042}
24043function getAnnotation(type, name) {
24044 let annotation = null;
24045 collect(type.__annotations__);
24046 collect(type.decorators);
24047 return annotation;
24048 function collect(annotations) {
24049 if (annotations) {
24050 annotations.forEach(readAnnotation);
24051 }
24052 }
24053 function readAnnotation(decorator) {
24054 if (!annotation) {
24055 const proto = Object.getPrototypeOf(decorator);
24056 if (proto.ngMetadataName == name) {
24057 annotation = decorator;
24058 }
24059 else if (decorator.type) {
24060 const proto = Object.getPrototypeOf(decorator.type);
24061 if (proto.ngMetadataName == name) {
24062 annotation = decorator.args[0];
24063 }
24064 }
24065 }
24066 }
24067}
24068/**
24069 * Keep track of compiled components. This is needed because in tests we often want to compile the
24070 * same component with more than one NgModule. This would cause an error unless we reset which
24071 * NgModule the component belongs to. We keep the list of compiled components here so that the
24072 * TestBed can reset it later.
24073 */
24074let ownerNgModule = new WeakMap();
24075let verifiedNgModule = new WeakMap();
24076function resetCompiledComponents() {
24077 ownerNgModule = new WeakMap();
24078 verifiedNgModule = new WeakMap();
24079 moduleQueue.length = 0;
24080}
24081/**
24082 * Computes the combined declarations of explicit declarations, as well as declarations inherited by
24083 * traversing the exports of imported modules.
24084 * @param type
24085 */
24086function computeCombinedExports(type) {
24087 type = resolveForwardRef(type);
24088 const ngModuleDef = getNgModuleDef(type, true);
24089 return [...flatten(maybeUnwrapFn(ngModuleDef.exports).map((type) => {
24090 const ngModuleDef = getNgModuleDef(type);
24091 if (ngModuleDef) {
24092 verifySemanticsOfNgModuleDef(type, false);
24093 return computeCombinedExports(type);
24094 }
24095 else {
24096 return type;
24097 }
24098 }))];
24099}
24100/**
24101 * Some declared components may be compiled asynchronously, and thus may not have their
24102 * ɵcmp set yet. If this is the case, then a reference to the module is written into
24103 * the `ngSelectorScope` property of the declared type.
24104 */
24105function setScopeOnDeclaredComponents(moduleType, ngModule) {
24106 const declarations = flatten(ngModule.declarations || EMPTY_ARRAY);
24107 const transitiveScopes = transitiveScopesFor(moduleType);
24108 declarations.forEach(declaration => {
24109 if (declaration.hasOwnProperty(NG_COMP_DEF)) {
24110 // A `ɵcmp` field exists - go ahead and patch the component directly.
24111 const component = declaration;
24112 const componentDef = getComponentDef(component);
24113 patchComponentDefWithScope(componentDef, transitiveScopes);
24114 }
24115 else if (!declaration.hasOwnProperty(NG_DIR_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) {
24116 // Set `ngSelectorScope` for future reference when the component compilation finishes.
24117 declaration.ngSelectorScope = moduleType;
24118 }
24119 });
24120}
24121/**
24122 * Patch the definition of a component with directives and pipes from the compilation scope of
24123 * a given module.
24124 */
24125function patchComponentDefWithScope(componentDef, transitiveScopes) {
24126 componentDef.directiveDefs = () => Array.from(transitiveScopes.compilation.directives)
24127 .map(dir => dir.hasOwnProperty(NG_COMP_DEF) ? getComponentDef(dir) : getDirectiveDef(dir))
24128 .filter(def => !!def);
24129 componentDef.pipeDefs = () => Array.from(transitiveScopes.compilation.pipes).map(pipe => getPipeDef$1(pipe));
24130 componentDef.schemas = transitiveScopes.schemas;
24131 // Since we avoid Components/Directives/Pipes recompiling in case there are no overrides, we
24132 // may face a problem where previously compiled defs available to a given Component/Directive
24133 // are cached in TView and may become stale (in case any of these defs gets recompiled). In
24134 // order to avoid this problem, we force fresh TView to be created.
24135 componentDef.tView = null;
24136}
24137/**
24138 * Compute the pair of transitive scopes (compilation scope and exported scope) for a given module.
24139 *
24140 * This operation is memoized and the result is cached on the module's definition. This function can
24141 * be called on modules with components that have not fully compiled yet, but the result should not
24142 * be used until they have.
24143 *
24144 * @param moduleType module that transitive scope should be calculated for.
24145 */
24146function transitiveScopesFor(moduleType) {
24147 if (!isNgModule(moduleType)) {
24148 throw new Error(`${moduleType.name} does not have a module def (ɵmod property)`);
24149 }
24150 const def = getNgModuleDef(moduleType);
24151 if (def.transitiveCompileScopes !== null) {
24152 return def.transitiveCompileScopes;
24153 }
24154 const scopes = {
24155 schemas: def.schemas || null,
24156 compilation: {
24157 directives: new Set(),
24158 pipes: new Set(),
24159 },
24160 exported: {
24161 directives: new Set(),
24162 pipes: new Set(),
24163 },
24164 };
24165 maybeUnwrapFn(def.imports).forEach((imported) => {
24166 const importedType = imported;
24167 if (!isNgModule(importedType)) {
24168 throw new Error(`Importing ${importedType.name} which does not have a ɵmod property`);
24169 }
24170 // When this module imports another, the imported module's exported directives and pipes are
24171 // added to the compilation scope of this module.
24172 const importedScope = transitiveScopesFor(importedType);
24173 importedScope.exported.directives.forEach(entry => scopes.compilation.directives.add(entry));
24174 importedScope.exported.pipes.forEach(entry => scopes.compilation.pipes.add(entry));
24175 });
24176 maybeUnwrapFn(def.declarations).forEach(declared => {
24177 const declaredWithDefs = declared;
24178 if (getPipeDef$1(declaredWithDefs)) {
24179 scopes.compilation.pipes.add(declared);
24180 }
24181 else {
24182 // Either declared has a ɵcmp or ɵdir, or it's a component which hasn't
24183 // had its template compiled yet. In either case, it gets added to the compilation's
24184 // directives.
24185 scopes.compilation.directives.add(declared);
24186 }
24187 });
24188 maybeUnwrapFn(def.exports).forEach((exported) => {
24189 const exportedType = exported;
24190 // Either the type is a module, a pipe, or a component/directive (which may not have a
24191 // ɵcmp as it might be compiled asynchronously).
24192 if (isNgModule(exportedType)) {
24193 // When this module exports another, the exported module's exported directives and pipes are
24194 // added to both the compilation and exported scopes of this module.
24195 const exportedScope = transitiveScopesFor(exportedType);
24196 exportedScope.exported.directives.forEach(entry => {
24197 scopes.compilation.directives.add(entry);
24198 scopes.exported.directives.add(entry);
24199 });
24200 exportedScope.exported.pipes.forEach(entry => {
24201 scopes.compilation.pipes.add(entry);
24202 scopes.exported.pipes.add(entry);
24203 });
24204 }
24205 else if (getPipeDef$1(exportedType)) {
24206 scopes.exported.pipes.add(exportedType);
24207 }
24208 else {
24209 scopes.exported.directives.add(exportedType);
24210 }
24211 });
24212 def.transitiveCompileScopes = scopes;
24213 return scopes;
24214}
24215function expandModuleWithProviders(value) {
24216 if (isModuleWithProviders(value)) {
24217 return value.ngModule;
24218 }
24219 return value;
24220}
24221function isModuleWithProviders(value) {
24222 return value.ngModule !== undefined;
24223}
24224function isNgModule(value) {
24225 return !!getNgModuleDef(value);
24226}
24227
24228/**
24229 * @license
24230 * Copyright Google LLC All Rights Reserved.
24231 *
24232 * Use of this source code is governed by an MIT-style license that can be
24233 * found in the LICENSE file at https://angular.io/license
24234 */
24235/**
24236 * Keep track of the compilation depth to avoid reentrancy issues during JIT compilation. This
24237 * matters in the following scenario:
24238 *
24239 * Consider a component 'A' that extends component 'B', both declared in module 'M'. During
24240 * the compilation of 'A' the definition of 'B' is requested to capture the inheritance chain,
24241 * potentially triggering compilation of 'B'. If this nested compilation were to trigger
24242 * `flushModuleScopingQueueAsMuchAsPossible` it may happen that module 'M' is still pending in the
24243 * queue, resulting in 'A' and 'B' to be patched with the NgModule scope. As the compilation of
24244 * 'A' is still in progress, this would introduce a circular dependency on its compilation. To avoid
24245 * this issue, the module scope queue is only flushed for compilations at the depth 0, to ensure
24246 * all compilations have finished.
24247 */
24248let compilationDepth = 0;
24249/**
24250 * Compile an Angular component according to its decorator metadata, and patch the resulting
24251 * component def (ɵcmp) onto the component type.
24252 *
24253 * Compilation may be asynchronous (due to the need to resolve URLs for the component template or
24254 * other resources, for example). In the event that compilation is not immediate, `compileComponent`
24255 * will enqueue resource resolution into a global queue and will fail to return the `ɵcmp`
24256 * until the global queue has been resolved with a call to `resolveComponentResources`.
24257 */
24258function compileComponent(type, metadata) {
24259 // Initialize ngDevMode. This must be the first statement in compileComponent.
24260 // See the `initNgDevMode` docstring for more information.
24261 (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
24262 let ngComponentDef = null;
24263 // Metadata may have resources which need to be resolved.
24264 maybeQueueResolutionOfComponentResources(type, metadata);
24265 // Note that we're using the same function as `Directive`, because that's only subset of metadata
24266 // that we need to create the ngFactoryDef. We're avoiding using the component metadata
24267 // because we'd have to resolve the asynchronous templates.
24268 addDirectiveFactoryDef(type, metadata);
24269 Object.defineProperty(type, NG_COMP_DEF, {
24270 get: () => {
24271 if (ngComponentDef === null) {
24272 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'component', type: type });
24273 if (componentNeedsResolution(metadata)) {
24274 const error = [`Component '${type.name}' is not resolved:`];
24275 if (metadata.templateUrl) {
24276 error.push(` - templateUrl: ${metadata.templateUrl}`);
24277 }
24278 if (metadata.styleUrls && metadata.styleUrls.length) {
24279 error.push(` - styleUrls: ${JSON.stringify(metadata.styleUrls)}`);
24280 }
24281 error.push(`Did you run and wait for 'resolveComponentResources()'?`);
24282 throw new Error(error.join('\n'));
24283 }
24284 // This const was called `jitOptions` previously but had to be renamed to `options` because
24285 // of a bug with Terser that caused optimized JIT builds to throw a `ReferenceError`.
24286 // This bug was investigated in https://github.com/angular/angular-cli/issues/17264.
24287 // We should not rename it back until https://github.com/terser/terser/issues/615 is fixed.
24288 const options = getJitOptions();
24289 let preserveWhitespaces = metadata.preserveWhitespaces;
24290 if (preserveWhitespaces === undefined) {
24291 if (options !== null && options.preserveWhitespaces !== undefined) {
24292 preserveWhitespaces = options.preserveWhitespaces;
24293 }
24294 else {
24295 preserveWhitespaces = false;
24296 }
24297 }
24298 let encapsulation = metadata.encapsulation;
24299 if (encapsulation === undefined) {
24300 if (options !== null && options.defaultEncapsulation !== undefined) {
24301 encapsulation = options.defaultEncapsulation;
24302 }
24303 else {
24304 encapsulation = ViewEncapsulation$1.Emulated;
24305 }
24306 }
24307 const templateUrl = metadata.templateUrl || `ng:///${type.name}/template.html`;
24308 const meta = {
24309 ...directiveMetadata(type, metadata),
24310 typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl),
24311 template: metadata.template || '',
24312 preserveWhitespaces,
24313 styles: metadata.styles || EMPTY_ARRAY,
24314 animations: metadata.animations,
24315 directives: [],
24316 changeDetection: metadata.changeDetection,
24317 pipes: new Map(),
24318 encapsulation,
24319 interpolation: metadata.interpolation,
24320 viewProviders: metadata.viewProviders || null,
24321 };
24322 compilationDepth++;
24323 try {
24324 if (meta.usesInheritance) {
24325 addDirectiveDefToUndecoratedParents(type);
24326 }
24327 ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
24328 }
24329 finally {
24330 // Ensure that the compilation depth is decremented even when the compilation failed.
24331 compilationDepth--;
24332 }
24333 if (compilationDepth === 0) {
24334 // When NgModule decorator executed, we enqueued the module definition such that
24335 // it would only dequeue and add itself as module scope to all of its declarations,
24336 // but only if if all of its declarations had resolved. This call runs the check
24337 // to see if any modules that are in the queue can be dequeued and add scope to
24338 // their declarations.
24339 flushModuleScopingQueueAsMuchAsPossible();
24340 }
24341 // If component compilation is async, then the @NgModule annotation which declares the
24342 // component may execute and set an ngSelectorScope property on the component type. This
24343 // allows the component to patch itself with directiveDefs from the module after it
24344 // finishes compiling.
24345 if (hasSelectorScope(type)) {
24346 const scopes = transitiveScopesFor(type.ngSelectorScope);
24347 patchComponentDefWithScope(ngComponentDef, scopes);
24348 }
24349 }
24350 return ngComponentDef;
24351 },
24352 // Make the property configurable in dev mode to allow overriding in tests
24353 configurable: !!ngDevMode,
24354 });
24355}
24356function hasSelectorScope(component) {
24357 return component.ngSelectorScope !== undefined;
24358}
24359/**
24360 * Compile an Angular directive according to its decorator metadata, and patch the resulting
24361 * directive def onto the component type.
24362 *
24363 * In the event that compilation is not immediate, `compileDirective` will return a `Promise` which
24364 * will resolve when compilation completes and the directive becomes usable.
24365 */
24366function compileDirective(type, directive) {
24367 let ngDirectiveDef = null;
24368 addDirectiveFactoryDef(type, directive || {});
24369 Object.defineProperty(type, NG_DIR_DEF, {
24370 get: () => {
24371 if (ngDirectiveDef === null) {
24372 // `directive` can be null in the case of abstract directives as a base class
24373 // that use `@Directive()` with no selector. In that case, pass empty object to the
24374 // `directiveMetadata` function instead of null.
24375 const meta = getDirectiveMetadata(type, directive || {});
24376 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'directive', type });
24377 ngDirectiveDef =
24378 compiler.compileDirective(angularCoreEnv, meta.sourceMapUrl, meta.metadata);
24379 }
24380 return ngDirectiveDef;
24381 },
24382 // Make the property configurable in dev mode to allow overriding in tests
24383 configurable: !!ngDevMode,
24384 });
24385}
24386function getDirectiveMetadata(type, metadata) {
24387 const name = type && type.name;
24388 const sourceMapUrl = `ng:///${name}/ɵdir.js`;
24389 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'directive', type });
24390 const facade = directiveMetadata(type, metadata);
24391 facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl);
24392 if (facade.usesInheritance) {
24393 addDirectiveDefToUndecoratedParents(type);
24394 }
24395 return { metadata: facade, sourceMapUrl };
24396}
24397function addDirectiveFactoryDef(type, metadata) {
24398 let ngFactoryDef = null;
24399 Object.defineProperty(type, NG_FACTORY_DEF, {
24400 get: () => {
24401 if (ngFactoryDef === null) {
24402 const meta = getDirectiveMetadata(type, metadata);
24403 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'directive', type });
24404 ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${type.name}/ɵfac.js`, {
24405 name: meta.metadata.name,
24406 type: meta.metadata.type,
24407 typeArgumentCount: 0,
24408 deps: reflectDependencies(type),
24409 target: compiler.FactoryTarget.Directive
24410 });
24411 }
24412 return ngFactoryDef;
24413 },
24414 // Make the property configurable in dev mode to allow overriding in tests
24415 configurable: !!ngDevMode,
24416 });
24417}
24418function extendsDirectlyFromObject(type) {
24419 return Object.getPrototypeOf(type.prototype) === Object.prototype;
24420}
24421/**
24422 * Extract the `R3DirectiveMetadata` for a particular directive (either a `Directive` or a
24423 * `Component`).
24424 */
24425function directiveMetadata(type, metadata) {
24426 // Reflect inputs and outputs.
24427 const reflect = getReflect();
24428 const propMetadata = reflect.ownPropMetadata(type);
24429 return {
24430 name: type.name,
24431 type: type,
24432 selector: metadata.selector !== undefined ? metadata.selector : null,
24433 host: metadata.host || EMPTY_OBJ,
24434 propMetadata: propMetadata,
24435 inputs: metadata.inputs || EMPTY_ARRAY,
24436 outputs: metadata.outputs || EMPTY_ARRAY,
24437 queries: extractQueriesMetadata(type, propMetadata, isContentQuery),
24438 lifecycle: { usesOnChanges: reflect.hasLifecycleHook(type, 'ngOnChanges') },
24439 typeSourceSpan: null,
24440 usesInheritance: !extendsDirectlyFromObject(type),
24441 exportAs: extractExportAs(metadata.exportAs),
24442 providers: metadata.providers || null,
24443 viewQueries: extractQueriesMetadata(type, propMetadata, isViewQuery)
24444 };
24445}
24446/**
24447 * Adds a directive definition to all parent classes of a type that don't have an Angular decorator.
24448 */
24449function addDirectiveDefToUndecoratedParents(type) {
24450 const objPrototype = Object.prototype;
24451 let parent = Object.getPrototypeOf(type.prototype).constructor;
24452 // Go up the prototype until we hit `Object`.
24453 while (parent && parent !== objPrototype) {
24454 // Since inheritance works if the class was annotated already, we only need to add
24455 // the def if there are no annotations and the def hasn't been created already.
24456 if (!getDirectiveDef(parent) && !getComponentDef(parent) &&
24457 shouldAddAbstractDirective(parent)) {
24458 compileDirective(parent, null);
24459 }
24460 parent = Object.getPrototypeOf(parent);
24461 }
24462}
24463function convertToR3QueryPredicate(selector) {
24464 return typeof selector === 'string' ? splitByComma(selector) : resolveForwardRef(selector);
24465}
24466function convertToR3QueryMetadata(propertyName, ann) {
24467 return {
24468 propertyName: propertyName,
24469 predicate: convertToR3QueryPredicate(ann.selector),
24470 descendants: ann.descendants,
24471 first: ann.first,
24472 read: ann.read ? ann.read : null,
24473 static: !!ann.static,
24474 emitDistinctChangesOnly: !!ann.emitDistinctChangesOnly,
24475 };
24476}
24477function extractQueriesMetadata(type, propMetadata, isQueryAnn) {
24478 const queriesMeta = [];
24479 for (const field in propMetadata) {
24480 if (propMetadata.hasOwnProperty(field)) {
24481 const annotations = propMetadata[field];
24482 annotations.forEach(ann => {
24483 if (isQueryAnn(ann)) {
24484 if (!ann.selector) {
24485 throw new Error(`Can't construct a query for the property "${field}" of ` +
24486 `"${stringifyForError(type)}" since the query selector wasn't defined.`);
24487 }
24488 if (annotations.some(isInputAnnotation)) {
24489 throw new Error(`Cannot combine @Input decorators with query decorators`);
24490 }
24491 queriesMeta.push(convertToR3QueryMetadata(field, ann));
24492 }
24493 });
24494 }
24495 }
24496 return queriesMeta;
24497}
24498function extractExportAs(exportAs) {
24499 return exportAs === undefined ? null : splitByComma(exportAs);
24500}
24501function isContentQuery(value) {
24502 const name = value.ngMetadataName;
24503 return name === 'ContentChild' || name === 'ContentChildren';
24504}
24505function isViewQuery(value) {
24506 const name = value.ngMetadataName;
24507 return name === 'ViewChild' || name === 'ViewChildren';
24508}
24509function isInputAnnotation(value) {
24510 return value.ngMetadataName === 'Input';
24511}
24512function splitByComma(value) {
24513 return value.split(',').map(piece => piece.trim());
24514}
24515const LIFECYCLE_HOOKS = [
24516 'ngOnChanges', 'ngOnInit', 'ngOnDestroy', 'ngDoCheck', 'ngAfterViewInit', 'ngAfterViewChecked',
24517 'ngAfterContentInit', 'ngAfterContentChecked'
24518];
24519function shouldAddAbstractDirective(type) {
24520 const reflect = getReflect();
24521 if (LIFECYCLE_HOOKS.some(hookName => reflect.hasLifecycleHook(type, hookName))) {
24522 return true;
24523 }
24524 const propMetadata = reflect.propMetadata(type);
24525 for (const field in propMetadata) {
24526 const annotations = propMetadata[field];
24527 for (let i = 0; i < annotations.length; i++) {
24528 const current = annotations[i];
24529 const metadataName = current.ngMetadataName;
24530 if (isInputAnnotation(current) || isContentQuery(current) || isViewQuery(current) ||
24531 metadataName === 'Output' || metadataName === 'HostBinding' ||
24532 metadataName === 'HostListener') {
24533 return true;
24534 }
24535 }
24536 }
24537 return false;
24538}
24539
24540/**
24541 * @license
24542 * Copyright Google LLC All Rights Reserved.
24543 *
24544 * Use of this source code is governed by an MIT-style license that can be
24545 * found in the LICENSE file at https://angular.io/license
24546 */
24547function compilePipe(type, meta) {
24548 let ngPipeDef = null;
24549 let ngFactoryDef = null;
24550 Object.defineProperty(type, NG_FACTORY_DEF, {
24551 get: () => {
24552 if (ngFactoryDef === null) {
24553 const metadata = getPipeMetadata(type, meta);
24554 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'pipe', type: metadata.type });
24555 ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${metadata.name}/ɵfac.js`, {
24556 name: metadata.name,
24557 type: metadata.type,
24558 typeArgumentCount: 0,
24559 deps: reflectDependencies(type),
24560 target: compiler.FactoryTarget.Pipe
24561 });
24562 }
24563 return ngFactoryDef;
24564 },
24565 // Make the property configurable in dev mode to allow overriding in tests
24566 configurable: !!ngDevMode,
24567 });
24568 Object.defineProperty(type, NG_PIPE_DEF, {
24569 get: () => {
24570 if (ngPipeDef === null) {
24571 const metadata = getPipeMetadata(type, meta);
24572 const compiler = getCompilerFacade({ usage: 0 /* Decorator */, kind: 'pipe', type: metadata.type });
24573 ngPipeDef =
24574 compiler.compilePipe(angularCoreEnv, `ng:///${metadata.name}/ɵpipe.js`, metadata);
24575 }
24576 return ngPipeDef;
24577 },
24578 // Make the property configurable in dev mode to allow overriding in tests
24579 configurable: !!ngDevMode,
24580 });
24581}
24582function getPipeMetadata(type, meta) {
24583 return {
24584 type: type,
24585 name: type.name,
24586 pipeName: meta.name,
24587 pure: meta.pure !== undefined ? meta.pure : true
24588 };
24589}
24590
24591/**
24592 * @license
24593 * Copyright Google LLC All Rights Reserved.
24594 *
24595 * Use of this source code is governed by an MIT-style license that can be
24596 * found in the LICENSE file at https://angular.io/license
24597 */
24598/**
24599 * Type of the Directive metadata.
24600 *
24601 * @publicApi
24602 */
24603const Directive = makeDecorator('Directive', (dir = {}) => dir, undefined, undefined, (type, meta) => compileDirective(type, meta));
24604/**
24605 * Component decorator and metadata.
24606 *
24607 * @Annotation
24608 * @publicApi
24609 */
24610const Component = makeDecorator('Component', (c = {}) => ({ changeDetection: ChangeDetectionStrategy.Default, ...c }), Directive, undefined, (type, meta) => compileComponent(type, meta));
24611/**
24612 * @Annotation
24613 * @publicApi
24614 */
24615const Pipe = makeDecorator('Pipe', (p) => ({ pure: true, ...p }), undefined, undefined, (type, meta) => compilePipe(type, meta));
24616/**
24617 * @Annotation
24618 * @publicApi
24619 */
24620const Input = makePropDecorator('Input', (bindingPropertyName) => ({ bindingPropertyName }));
24621/**
24622 * @Annotation
24623 * @publicApi
24624 */
24625const Output = makePropDecorator('Output', (bindingPropertyName) => ({ bindingPropertyName }));
24626/**
24627 * @Annotation
24628 * @publicApi
24629 */
24630const HostBinding = makePropDecorator('HostBinding', (hostPropertyName) => ({ hostPropertyName }));
24631/**
24632 * Decorator that binds a DOM event to a host listener and supplies configuration metadata.
24633 * Angular invokes the supplied handler method when the host element emits the specified event,
24634 * and updates the bound element with the result.
24635 *
24636 * If the handler method returns false, applies `preventDefault` on the bound element.
24637 *
24638 * @usageNotes
24639 *
24640 * The following example declares a directive
24641 * that attaches a click listener to a button and counts clicks.
24642 *
24643 * ```ts
24644 * @Directive({selector: 'button[counting]'})
24645 * class CountClicks {
24646 * numberOfClicks = 0;
24647 *
24648 * @HostListener('click', ['$event.target'])
24649 * onClick(btn) {
24650 * console.log('button', btn, 'number of clicks:', this.numberOfClicks++);
24651 * }
24652 * }
24653 *
24654 * @Component({
24655 * selector: 'app',
24656 * template: '<button counting>Increment</button>',
24657 * })
24658 * class App {}
24659 *
24660 * ```
24661 *
24662 * The following example registers another DOM event handler that listens for `Enter` key-press
24663 * events on the global `window`.
24664 * ``` ts
24665 * import { HostListener, Component } from "@angular/core";
24666 *
24667 * @Component({
24668 * selector: 'app',
24669 * template: `<h1>Hello, you have pressed enter {{counter}} number of times!</h1> Press enter key
24670 * to increment the counter.
24671 * <button (click)="resetCounter()">Reset Counter</button>`
24672 * })
24673 * class AppComponent {
24674 * counter = 0;
24675 * @HostListener('window:keydown.enter', ['$event'])
24676 * handleKeyDown(event: KeyboardEvent) {
24677 * this.counter++;
24678 * }
24679 * resetCounter() {
24680 * this.counter = 0;
24681 * }
24682 * }
24683 * ```
24684 * The list of valid key names for `keydown` and `keyup` events
24685 * can be found here:
24686 * https://www.w3.org/TR/DOM-Level-3-Events-key/#named-key-attribute-values
24687 *
24688 * Note that keys can also be combined, e.g. `@HostListener('keydown.shift.a')`.
24689 *
24690 * The global target names that can be used to prefix an event name are
24691 * `document:`, `window:` and `body:`.
24692 *
24693 * @Annotation
24694 * @publicApi
24695 */
24696const HostListener = makePropDecorator('HostListener', (eventName, args) => ({ eventName, args }));
24697
24698/**
24699 * @license
24700 * Copyright Google LLC All Rights Reserved.
24701 *
24702 * Use of this source code is governed by an MIT-style license that can be
24703 * found in the LICENSE file at https://angular.io/license
24704 */
24705/**
24706 * @Annotation
24707 * @publicApi
24708 */
24709const NgModule = makeDecorator('NgModule', (ngModule) => ngModule, undefined, undefined,
24710/**
24711 * Decorator that marks the following class as an NgModule, and supplies
24712 * configuration metadata for it.
24713 *
24714 * * The `declarations` and `entryComponents` options configure the compiler
24715 * with information about what belongs to the NgModule.
24716 * * The `providers` options configures the NgModule's injector to provide
24717 * dependencies the NgModule members.
24718 * * The `imports` and `exports` options bring in members from other modules, and make
24719 * this module's members available to others.
24720 */
24721(type, meta) => compileNgModule(type, meta));
24722
24723/**
24724 * @license
24725 * Copyright Google LLC All Rights Reserved.
24726 *
24727 * Use of this source code is governed by an MIT-style license that can be
24728 * found in the LICENSE file at https://angular.io/license
24729 */
24730
24731/**
24732 * @license
24733 * Copyright Google LLC All Rights Reserved.
24734 *
24735 * Use of this source code is governed by an MIT-style license that can be
24736 * found in the LICENSE file at https://angular.io/license
24737 */
24738
24739/**
24740 * @license
24741 * Copyright Google LLC All Rights Reserved.
24742 *
24743 * Use of this source code is governed by an MIT-style license that can be
24744 * found in the LICENSE file at https://angular.io/license
24745 */
24746function noop(...args) {
24747 // Do nothing.
24748}
24749
24750/**
24751 * @license
24752 * Copyright Google LLC All Rights Reserved.
24753 *
24754 * Use of this source code is governed by an MIT-style license that can be
24755 * found in the LICENSE file at https://angular.io/license
24756 */
24757/**
24758 * The existence of this constant (in this particular file) informs the Angular compiler that the
24759 * current program is actually @angular/core, which needs to be compiled specially.
24760 */
24761const ITS_JUST_ANGULAR = true;
24762
24763/**
24764 * A [DI token](guide/glossary#di-token "DI token definition") that you can use to provide
24765 * one or more initialization functions.
24766 *
24767 * The provided functions are injected at application startup and executed during
24768 * app initialization. If any of these functions returns a Promise or an Observable, initialization
24769 * does not complete until the Promise is resolved or the Observable is completed.
24770 *
24771 * You can, for example, create a factory function that loads language data
24772 * or an external configuration, and provide that function to the `APP_INITIALIZER` token.
24773 * The function is executed during the application bootstrap process,
24774 * and the needed data is available on startup.
24775 *
24776 * @see `ApplicationInitStatus`
24777 *
24778 * @usageNotes
24779 *
24780 * The following example illustrates how to configure a multi-provider using `APP_INITIALIZER` token
24781 * and a function returning a promise.
24782 *
24783 * ```
24784 * function initializeApp(): Promise<any> {
24785 * return new Promise((resolve, reject) => {
24786 * // Do some asynchronous stuff
24787 * resolve();
24788 * });
24789 * }
24790 *
24791 * @NgModule({
24792 * imports: [BrowserModule],
24793 * declarations: [AppComponent],
24794 * bootstrap: [AppComponent],
24795 * providers: [{
24796 * provide: APP_INITIALIZER,
24797 * useFactory: () => initializeApp,
24798 * multi: true
24799 * }]
24800 * })
24801 * export class AppModule {}
24802 * ```
24803 *
24804 * It's also possible to configure a multi-provider using `APP_INITIALIZER` token and a function
24805 * returning an observable, see an example below. Note: the `HttpClient` in this example is used for
24806 * demo purposes to illustrate how the factory function can work with other providers available
24807 * through DI.
24808 *
24809 * ```
24810 * function initializeAppFactory(httpClient: HttpClient): () => Observable<any> {
24811 * return () => httpClient.get("https://someUrl.com/api/user")
24812 * .pipe(
24813 * tap(user => { ... })
24814 * );
24815 * }
24816 *
24817 * @NgModule({
24818 * imports: [BrowserModule, HttpClientModule],
24819 * declarations: [AppComponent],
24820 * bootstrap: [AppComponent],
24821 * providers: [{
24822 * provide: APP_INITIALIZER,
24823 * useFactory: initializeAppFactory,
24824 * deps: [HttpClient],
24825 * multi: true
24826 * }]
24827 * })
24828 * export class AppModule {}
24829 * ```
24830 *
24831 * @publicApi
24832 */
24833const APP_INITIALIZER = new InjectionToken('Application Initializer');
24834/**
24835 * A class that reflects the state of running {@link APP_INITIALIZER} functions.
24836 *
24837 * @publicApi
24838 */
24839class ApplicationInitStatus {
24840 constructor(appInits) {
24841 this.appInits = appInits;
24842 this.resolve = noop;
24843 this.reject = noop;
24844 this.initialized = false;
24845 this.done = false;
24846 this.donePromise = new Promise((res, rej) => {
24847 this.resolve = res;
24848 this.reject = rej;
24849 });
24850 }
24851 /** @internal */
24852 runInitializers() {
24853 if (this.initialized) {
24854 return;
24855 }
24856 const asyncInitPromises = [];
24857 const complete = () => {
24858 this.done = true;
24859 this.resolve();
24860 };
24861 if (this.appInits) {
24862 for (let i = 0; i < this.appInits.length; i++) {
24863 const initResult = this.appInits[i]();
24864 if (isPromise(initResult)) {
24865 asyncInitPromises.push(initResult);
24866 }
24867 else if (isObservable(initResult)) {
24868 const observableAsPromise = new Promise((resolve, reject) => {
24869 initResult.subscribe({ complete: resolve, error: reject });
24870 });
24871 asyncInitPromises.push(observableAsPromise);
24872 }
24873 }
24874 }
24875 Promise.all(asyncInitPromises)
24876 .then(() => {
24877 complete();
24878 })
24879 .catch(e => {
24880 this.reject(e);
24881 });
24882 if (asyncInitPromises.length === 0) {
24883 complete();
24884 }
24885 this.initialized = true;
24886 }
24887}
24888ApplicationInitStatus.ɵfac = function ApplicationInitStatus_Factory(t) { return new (t || ApplicationInitStatus)(ɵɵinject(APP_INITIALIZER, 8)); };
24889ApplicationInitStatus.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationInitStatus, factory: ApplicationInitStatus.ɵfac, providedIn: 'root' });
24890(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
24891 type: Injectable,
24892 args: [{ providedIn: 'root' }]
24893 }], function () { return [{ type: undefined, decorators: [{
24894 type: Inject,
24895 args: [APP_INITIALIZER]
24896 }, {
24897 type: Optional
24898 }] }]; }, null); })();
24899
24900/**
24901 * @license
24902 * Copyright Google LLC All Rights Reserved.
24903 *
24904 * Use of this source code is governed by an MIT-style license that can be
24905 * found in the LICENSE file at https://angular.io/license
24906 */
24907/**
24908 * A [DI token](guide/glossary#di-token "DI token definition") representing a unique string ID, used
24909 * primarily for prefixing application attributes and CSS styles when
24910 * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used.
24911 *
24912 * BY default, the value is randomly generated and assigned to the application by Angular.
24913 * To provide a custom ID value, use a DI provider <!-- TODO: provider --> to configure
24914 * the root {@link Injector} that uses this token.
24915 *
24916 * @publicApi
24917 */
24918const APP_ID = new InjectionToken('AppId', {
24919 providedIn: 'root',
24920 factory: _appIdRandomProviderFactory,
24921});
24922function _appIdRandomProviderFactory() {
24923 return `${_randomChar()}${_randomChar()}${_randomChar()}`;
24924}
24925/**
24926 * Providers that generate a random `APP_ID_TOKEN`.
24927 * @publicApi
24928 */
24929const APP_ID_RANDOM_PROVIDER = {
24930 provide: APP_ID,
24931 useFactory: _appIdRandomProviderFactory,
24932 deps: [],
24933};
24934function _randomChar() {
24935 return String.fromCharCode(97 + Math.floor(Math.random() * 25));
24936}
24937/**
24938 * A function that is executed when a platform is initialized.
24939 * @publicApi
24940 */
24941const PLATFORM_INITIALIZER = new InjectionToken('Platform Initializer');
24942/**
24943 * A token that indicates an opaque platform ID.
24944 * @publicApi
24945 */
24946const PLATFORM_ID = new InjectionToken('Platform ID', {
24947 providedIn: 'platform',
24948 factory: () => 'unknown', // set a default platform name, when none set explicitly
24949});
24950/**
24951 * A [DI token](guide/glossary#di-token "DI token definition") that provides a set of callbacks to
24952 * be called for every component that is bootstrapped.
24953 *
24954 * Each callback must take a `ComponentRef` instance and return nothing.
24955 *
24956 * `(componentRef: ComponentRef) => void`
24957 *
24958 * @publicApi
24959 */
24960const APP_BOOTSTRAP_LISTENER = new InjectionToken('appBootstrapListener');
24961/**
24962 * A [DI token](guide/glossary#di-token "DI token definition") that indicates the root directory of
24963 * the application
24964 * @publicApi
24965 */
24966const PACKAGE_ROOT_URL = new InjectionToken('Application Packages Root URL');
24967
24968/**
24969 * @license
24970 * Copyright Google LLC All Rights Reserved.
24971 *
24972 * Use of this source code is governed by an MIT-style license that can be
24973 * found in the LICENSE file at https://angular.io/license
24974 */
24975class Console {
24976 log(message) {
24977 // tslint:disable-next-line:no-console
24978 console.log(message);
24979 }
24980 // Note: for reporting errors use `DOM.logError()` as it is platform specific
24981 warn(message) {
24982 // tslint:disable-next-line:no-console
24983 console.warn(message);
24984 }
24985}
24986Console.ɵfac = function Console_Factory(t) { return new (t || Console)(); };
24987Console.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Console, factory: Console.ɵfac, providedIn: 'platform' });
24988(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Console, [{
24989 type: Injectable,
24990 args: [{ providedIn: 'platform' }]
24991 }], null, null); })();
24992
24993/**
24994 * @license
24995 * Copyright Google LLC All Rights Reserved.
24996 *
24997 * Use of this source code is governed by an MIT-style license that can be
24998 * found in the LICENSE file at https://angular.io/license
24999 */
25000/**
25001 * Work out the locale from the potential global properties.
25002 *
25003 * * Closure Compiler: use `goog.LOCALE`.
25004 * * Ivy enabled: use `$localize.locale`
25005 */
25006function getGlobalLocale() {
25007 if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
25008 typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
25009 // * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
25010 // * In order to preserve backwards compatibility, we use Angular default value over
25011 // Closure Compiler's one.
25012 return goog.LOCALE;
25013 }
25014 else {
25015 // KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
25016 // COMPILE-TIME INLINER.
25017 //
25018 // * During compile time inlining of translations the expression will be replaced
25019 // with a string literal that is the current locale. Other forms of this expression are not
25020 // guaranteed to be replaced.
25021 //
25022 // * During runtime translation evaluation, the developer is required to set `$localize.locale`
25023 // if required, or just to provide their own `LOCALE_ID` provider.
25024 return (typeof $localize !== 'undefined' && $localize.locale) || DEFAULT_LOCALE_ID;
25025 }
25026}
25027/**
25028 * Provide this token to set the locale of your application.
25029 * It is used for i18n extraction, by i18n pipes (DatePipe, I18nPluralPipe, CurrencyPipe,
25030 * DecimalPipe and PercentPipe) and by ICU expressions.
25031 *
25032 * See the [i18n guide](guide/i18n-common-locale-id) for more information.
25033 *
25034 * @usageNotes
25035 * ### Example
25036 *
25037 * ```typescript
25038 * import { LOCALE_ID } from '@angular/core';
25039 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25040 * import { AppModule } from './app/app.module';
25041 *
25042 * platformBrowserDynamic().bootstrapModule(AppModule, {
25043 * providers: [{provide: LOCALE_ID, useValue: 'en-US' }]
25044 * });
25045 * ```
25046 *
25047 * @publicApi
25048 */
25049const LOCALE_ID = new InjectionToken('LocaleId', {
25050 providedIn: 'root',
25051 factory: () => inject(LOCALE_ID, InjectFlags.Optional | InjectFlags.SkipSelf) || getGlobalLocale(),
25052});
25053/**
25054 * Provide this token to set the default currency code your application uses for
25055 * CurrencyPipe when there is no currency code passed into it. This is only used by
25056 * CurrencyPipe and has no relation to locale currency. Defaults to USD if not configured.
25057 *
25058 * See the [i18n guide](guide/i18n-common-locale-id) for more information.
25059 *
25060 * <div class="alert is-helpful">
25061 *
25062 * **Deprecation notice:**
25063 *
25064 * The default currency code is currently always `USD` but this is deprecated from v9.
25065 *
25066 * **In v10 the default currency code will be taken from the current locale.**
25067 *
25068 * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in
25069 * your application `NgModule`:
25070 *
25071 * ```ts
25072 * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
25073 * ```
25074 *
25075 * </div>
25076 *
25077 * @usageNotes
25078 * ### Example
25079 *
25080 * ```typescript
25081 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25082 * import { AppModule } from './app/app.module';
25083 *
25084 * platformBrowserDynamic().bootstrapModule(AppModule, {
25085 * providers: [{provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' }]
25086 * });
25087 * ```
25088 *
25089 * @publicApi
25090 */
25091const DEFAULT_CURRENCY_CODE = new InjectionToken('DefaultCurrencyCode', {
25092 providedIn: 'root',
25093 factory: () => USD_CURRENCY_CODE,
25094});
25095/**
25096 * Use this token at bootstrap to provide the content of your translation file (`xtb`,
25097 * `xlf` or `xlf2`) when you want to translate your application in another language.
25098 *
25099 * See the [i18n guide](guide/i18n-common-merge) for more information.
25100 *
25101 * @usageNotes
25102 * ### Example
25103 *
25104 * ```typescript
25105 * import { TRANSLATIONS } from '@angular/core';
25106 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25107 * import { AppModule } from './app/app.module';
25108 *
25109 * // content of your translation file
25110 * const translations = '....';
25111 *
25112 * platformBrowserDynamic().bootstrapModule(AppModule, {
25113 * providers: [{provide: TRANSLATIONS, useValue: translations }]
25114 * });
25115 * ```
25116 *
25117 * @publicApi
25118 */
25119const TRANSLATIONS = new InjectionToken('Translations');
25120/**
25121 * Provide this token at bootstrap to set the format of your {@link TRANSLATIONS}: `xtb`,
25122 * `xlf` or `xlf2`.
25123 *
25124 * See the [i18n guide](guide/i18n-common-merge) for more information.
25125 *
25126 * @usageNotes
25127 * ### Example
25128 *
25129 * ```typescript
25130 * import { TRANSLATIONS_FORMAT } from '@angular/core';
25131 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25132 * import { AppModule } from './app/app.module';
25133 *
25134 * platformBrowserDynamic().bootstrapModule(AppModule, {
25135 * providers: [{provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }]
25136 * });
25137 * ```
25138 *
25139 * @publicApi
25140 */
25141const TRANSLATIONS_FORMAT = new InjectionToken('TranslationsFormat');
25142/**
25143 * Use this enum at bootstrap as an option of `bootstrapModule` to define the strategy
25144 * that the compiler should use in case of missing translations:
25145 * - Error: throw if you have missing translations.
25146 * - Warning (default): show a warning in the console and/or shell.
25147 * - Ignore: do nothing.
25148 *
25149 * See the [i18n guide](guide/i18n-common-merge#report-missing-translations) for more information.
25150 *
25151 * @usageNotes
25152 * ### Example
25153 * ```typescript
25154 * import { MissingTranslationStrategy } from '@angular/core';
25155 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
25156 * import { AppModule } from './app/app.module';
25157 *
25158 * platformBrowserDynamic().bootstrapModule(AppModule, {
25159 * missingTranslation: MissingTranslationStrategy.Error
25160 * });
25161 * ```
25162 *
25163 * @publicApi
25164 */
25165var MissingTranslationStrategy;
25166(function (MissingTranslationStrategy) {
25167 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
25168 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
25169 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
25170})(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
25171
25172/**
25173 * @license
25174 * Copyright Google LLC All Rights Reserved.
25175 *
25176 * Use of this source code is governed by an MIT-style license that can be
25177 * found in the LICENSE file at https://angular.io/license
25178 */
25179/**
25180 * Combination of NgModuleFactory and ComponentFactories.
25181 *
25182 * @publicApi
25183 *
25184 * @deprecated
25185 * Ivy JIT mode doesn't require accessing this symbol.
25186 * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
25187 * additional context.
25188 */
25189class ModuleWithComponentFactories {
25190 constructor(ngModuleFactory, componentFactories) {
25191 this.ngModuleFactory = ngModuleFactory;
25192 this.componentFactories = componentFactories;
25193 }
25194}
25195/**
25196 * Low-level service for running the angular compiler during runtime
25197 * to create {@link ComponentFactory}s, which
25198 * can later be used to create and render a Component instance.
25199 *
25200 * Each `@NgModule` provides an own `Compiler` to its injector,
25201 * that will use the directives/pipes of the ng module for compilation
25202 * of components.
25203 *
25204 * @publicApi
25205 *
25206 * @deprecated
25207 * Ivy JIT mode doesn't require accessing this symbol.
25208 * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
25209 * additional context.
25210 */
25211class Compiler {
25212 /**
25213 * Compiles the given NgModule and all of its components. All templates of the components listed
25214 * in `entryComponents` have to be inlined.
25215 */
25216 compileModuleSync(moduleType) {
25217 return new NgModuleFactory(moduleType);
25218 }
25219 /**
25220 * Compiles the given NgModule and all of its components
25221 */
25222 compileModuleAsync(moduleType) {
25223 return Promise.resolve(this.compileModuleSync(moduleType));
25224 }
25225 /**
25226 * Same as {@link #compileModuleSync} but also creates ComponentFactories for all components.
25227 */
25228 compileModuleAndAllComponentsSync(moduleType) {
25229 const ngModuleFactory = this.compileModuleSync(moduleType);
25230 const moduleDef = getNgModuleDef(moduleType);
25231 const componentFactories = maybeUnwrapFn(moduleDef.declarations)
25232 .reduce((factories, declaration) => {
25233 const componentDef = getComponentDef(declaration);
25234 componentDef && factories.push(new ComponentFactory(componentDef));
25235 return factories;
25236 }, []);
25237 return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
25238 }
25239 /**
25240 * Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components.
25241 */
25242 compileModuleAndAllComponentsAsync(moduleType) {
25243 return Promise.resolve(this.compileModuleAndAllComponentsSync(moduleType));
25244 }
25245 /**
25246 * Clears all caches.
25247 */
25248 clearCache() { }
25249 /**
25250 * Clears the cache for the given component/ngModule.
25251 */
25252 clearCacheFor(type) { }
25253 /**
25254 * Returns the id for a given NgModule, if one is defined and known to the compiler.
25255 */
25256 getModuleId(moduleType) {
25257 return undefined;
25258 }
25259}
25260Compiler.ɵfac = function Compiler_Factory(t) { return new (t || Compiler)(); };
25261Compiler.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Compiler, factory: Compiler.ɵfac, providedIn: 'root' });
25262(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Compiler, [{
25263 type: Injectable,
25264 args: [{ providedIn: 'root' }]
25265 }], null, null); })();
25266/**
25267 * Token to provide CompilerOptions in the platform injector.
25268 *
25269 * @publicApi
25270 */
25271const COMPILER_OPTIONS = new InjectionToken('compilerOptions');
25272/**
25273 * A factory for creating a Compiler
25274 *
25275 * @publicApi
25276 *
25277 * @deprecated
25278 * Ivy JIT mode doesn't require accessing this symbol.
25279 * See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
25280 * additional context.
25281 */
25282class CompilerFactory {
25283}
25284
25285/**
25286 * @license
25287 * Copyright Google LLC All Rights Reserved.
25288 *
25289 * Use of this source code is governed by an MIT-style license that can be
25290 * found in the LICENSE file at https://angular.io/license
25291 */
25292const promise = (() => Promise.resolve(0))();
25293function scheduleMicroTask(fn) {
25294 if (typeof Zone === 'undefined') {
25295 // use promise to schedule microTask instead of use Zone
25296 promise.then(() => {
25297 fn && fn.apply(null, null);
25298 });
25299 }
25300 else {
25301 Zone.current.scheduleMicroTask('scheduleMicrotask', fn);
25302 }
25303}
25304
25305/**
25306 * @license
25307 * Copyright Google LLC All Rights Reserved.
25308 *
25309 * Use of this source code is governed by an MIT-style license that can be
25310 * found in the LICENSE file at https://angular.io/license
25311 */
25312function getNativeRequestAnimationFrame() {
25313 let nativeRequestAnimationFrame = _global['requestAnimationFrame'];
25314 let nativeCancelAnimationFrame = _global['cancelAnimationFrame'];
25315 if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
25316 // use unpatched version of requestAnimationFrame(native delegate) if possible
25317 // to avoid another Change detection
25318 const unpatchedRequestAnimationFrame = nativeRequestAnimationFrame[Zone.__symbol__('OriginalDelegate')];
25319 if (unpatchedRequestAnimationFrame) {
25320 nativeRequestAnimationFrame = unpatchedRequestAnimationFrame;
25321 }
25322 const unpatchedCancelAnimationFrame = nativeCancelAnimationFrame[Zone.__symbol__('OriginalDelegate')];
25323 if (unpatchedCancelAnimationFrame) {
25324 nativeCancelAnimationFrame = unpatchedCancelAnimationFrame;
25325 }
25326 }
25327 return { nativeRequestAnimationFrame, nativeCancelAnimationFrame };
25328}
25329
25330/**
25331 * @license
25332 * Copyright Google LLC All Rights Reserved.
25333 *
25334 * Use of this source code is governed by an MIT-style license that can be
25335 * found in the LICENSE file at https://angular.io/license
25336 */
25337/**
25338 * An injectable service for executing work inside or outside of the Angular zone.
25339 *
25340 * The most common use of this service is to optimize performance when starting a work consisting of
25341 * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
25342 * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
25343 * can reenter the Angular zone via {@link #run}.
25344 *
25345 * <!-- TODO: add/fix links to:
25346 * - docs explaining zones and the use of zones in Angular and change-detection
25347 * - link to runOutsideAngular/run (throughout this file!)
25348 * -->
25349 *
25350 * @usageNotes
25351 * ### Example
25352 *
25353 * ```
25354 * import {Component, NgZone} from '@angular/core';
25355 * import {NgIf} from '@angular/common';
25356 *
25357 * @Component({
25358 * selector: 'ng-zone-demo',
25359 * template: `
25360 * <h2>Demo: NgZone</h2>
25361 *
25362 * <p>Progress: {{progress}}%</p>
25363 * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
25364 *
25365 * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
25366 * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
25367 * `,
25368 * })
25369 * export class NgZoneDemo {
25370 * progress: number = 0;
25371 * label: string;
25372 *
25373 * constructor(private _ngZone: NgZone) {}
25374 *
25375 * // Loop inside the Angular zone
25376 * // so the UI DOES refresh after each setTimeout cycle
25377 * processWithinAngularZone() {
25378 * this.label = 'inside';
25379 * this.progress = 0;
25380 * this._increaseProgress(() => console.log('Inside Done!'));
25381 * }
25382 *
25383 * // Loop outside of the Angular zone
25384 * // so the UI DOES NOT refresh after each setTimeout cycle
25385 * processOutsideOfAngularZone() {
25386 * this.label = 'outside';
25387 * this.progress = 0;
25388 * this._ngZone.runOutsideAngular(() => {
25389 * this._increaseProgress(() => {
25390 * // reenter the Angular zone and display done
25391 * this._ngZone.run(() => { console.log('Outside Done!'); });
25392 * });
25393 * });
25394 * }
25395 *
25396 * _increaseProgress(doneCallback: () => void) {
25397 * this.progress += 1;
25398 * console.log(`Current progress: ${this.progress}%`);
25399 *
25400 * if (this.progress < 100) {
25401 * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
25402 * } else {
25403 * doneCallback();
25404 * }
25405 * }
25406 * }
25407 * ```
25408 *
25409 * @publicApi
25410 */
25411class NgZone {
25412 constructor({ enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false }) {
25413 this.hasPendingMacrotasks = false;
25414 this.hasPendingMicrotasks = false;
25415 /**
25416 * Whether there are no outstanding microtasks or macrotasks.
25417 */
25418 this.isStable = true;
25419 /**
25420 * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
25421 */
25422 this.onUnstable = new EventEmitter(false);
25423 /**
25424 * Notifies when there is no more microtasks enqueued in the current VM Turn.
25425 * This is a hint for Angular to do change detection, which may enqueue more microtasks.
25426 * For this reason this event can fire multiple times per VM Turn.
25427 */
25428 this.onMicrotaskEmpty = new EventEmitter(false);
25429 /**
25430 * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
25431 * implies we are about to relinquish VM turn.
25432 * This event gets called just once.
25433 */
25434 this.onStable = new EventEmitter(false);
25435 /**
25436 * Notifies that an error has been delivered.
25437 */
25438 this.onError = new EventEmitter(false);
25439 if (typeof Zone == 'undefined') {
25440 throw new Error(`In this configuration Angular requires Zone.js`);
25441 }
25442 Zone.assertZonePatched();
25443 const self = this;
25444 self._nesting = 0;
25445 self._outer = self._inner = Zone.current;
25446 if (Zone['TaskTrackingZoneSpec']) {
25447 self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']);
25448 }
25449 if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
25450 self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
25451 }
25452 // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
25453 // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
25454 self.shouldCoalesceEventChangeDetection =
25455 !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
25456 self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
25457 self.lastRequestAnimationFrameId = -1;
25458 self.nativeRequestAnimationFrame = getNativeRequestAnimationFrame().nativeRequestAnimationFrame;
25459 forkInnerZoneWithAngularBehavior(self);
25460 }
25461 static isInAngularZone() {
25462 // Zone needs to be checked, because this method might be called even when NoopNgZone is used.
25463 return typeof Zone !== 'undefined' && Zone.current.get('isAngularZone') === true;
25464 }
25465 static assertInAngularZone() {
25466 if (!NgZone.isInAngularZone()) {
25467 throw new Error('Expected to be in Angular Zone, but it is not!');
25468 }
25469 }
25470 static assertNotInAngularZone() {
25471 if (NgZone.isInAngularZone()) {
25472 throw new Error('Expected to not be in Angular Zone, but it is!');
25473 }
25474 }
25475 /**
25476 * Executes the `fn` function synchronously within the Angular zone and returns value returned by
25477 * the function.
25478 *
25479 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
25480 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
25481 *
25482 * Any future tasks or microtasks scheduled from within this function will continue executing from
25483 * within the Angular zone.
25484 *
25485 * If a synchronous error happens it will be rethrown and not reported via `onError`.
25486 */
25487 run(fn, applyThis, applyArgs) {
25488 return this._inner.run(fn, applyThis, applyArgs);
25489 }
25490 /**
25491 * Executes the `fn` function synchronously within the Angular zone as a task and returns value
25492 * returned by the function.
25493 *
25494 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
25495 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
25496 *
25497 * Any future tasks or microtasks scheduled from within this function will continue executing from
25498 * within the Angular zone.
25499 *
25500 * If a synchronous error happens it will be rethrown and not reported via `onError`.
25501 */
25502 runTask(fn, applyThis, applyArgs, name) {
25503 const zone = this._inner;
25504 const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
25505 try {
25506 return zone.runTask(task, applyThis, applyArgs);
25507 }
25508 finally {
25509 zone.cancelTask(task);
25510 }
25511 }
25512 /**
25513 * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
25514 * rethrown.
25515 */
25516 runGuarded(fn, applyThis, applyArgs) {
25517 return this._inner.runGuarded(fn, applyThis, applyArgs);
25518 }
25519 /**
25520 * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
25521 * the function.
25522 *
25523 * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
25524 * work that
25525 * doesn't trigger Angular change-detection or is subject to Angular's error handling.
25526 *
25527 * Any future tasks or microtasks scheduled from within this function will continue executing from
25528 * outside of the Angular zone.
25529 *
25530 * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
25531 */
25532 runOutsideAngular(fn) {
25533 return this._outer.run(fn);
25534 }
25535}
25536const EMPTY_PAYLOAD = {};
25537function checkStable(zone) {
25538 // TODO: @JiaLiPassion, should check zone.isCheckStableRunning to prevent
25539 // re-entry. The case is:
25540 //
25541 // @Component({...})
25542 // export class AppComponent {
25543 // constructor(private ngZone: NgZone) {
25544 // this.ngZone.onStable.subscribe(() => {
25545 // this.ngZone.run(() => console.log('stable'););
25546 // });
25547 // }
25548 //
25549 // The onStable subscriber run another function inside ngZone
25550 // which causes `checkStable()` re-entry.
25551 // But this fix causes some issues in g3, so this fix will be
25552 // launched in another PR.
25553 if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
25554 try {
25555 zone._nesting++;
25556 zone.onMicrotaskEmpty.emit(null);
25557 }
25558 finally {
25559 zone._nesting--;
25560 if (!zone.hasPendingMicrotasks) {
25561 try {
25562 zone.runOutsideAngular(() => zone.onStable.emit(null));
25563 }
25564 finally {
25565 zone.isStable = true;
25566 }
25567 }
25568 }
25569 }
25570}
25571function delayChangeDetectionForEvents(zone) {
25572 /**
25573 * We also need to check _nesting here
25574 * Consider the following case with shouldCoalesceRunChangeDetection = true
25575 *
25576 * ngZone.run(() => {});
25577 * ngZone.run(() => {});
25578 *
25579 * We want the two `ngZone.run()` only trigger one change detection
25580 * when shouldCoalesceRunChangeDetection is true.
25581 * And because in this case, change detection run in async way(requestAnimationFrame),
25582 * so we also need to check the _nesting here to prevent multiple
25583 * change detections.
25584 */
25585 if (zone.isCheckStableRunning || zone.lastRequestAnimationFrameId !== -1) {
25586 return;
25587 }
25588 zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(_global, () => {
25589 // This is a work around for https://github.com/angular/angular/issues/36839.
25590 // The core issue is that when event coalescing is enabled it is possible for microtasks
25591 // to get flushed too early (As is the case with `Promise.then`) between the
25592 // coalescing eventTasks.
25593 //
25594 // To workaround this we schedule a "fake" eventTask before we process the
25595 // coalescing eventTasks. The benefit of this is that the "fake" container eventTask
25596 // will prevent the microtasks queue from getting drained in between the coalescing
25597 // eventTask execution.
25598 if (!zone.fakeTopEventTask) {
25599 zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
25600 zone.lastRequestAnimationFrameId = -1;
25601 updateMicroTaskStatus(zone);
25602 zone.isCheckStableRunning = true;
25603 checkStable(zone);
25604 zone.isCheckStableRunning = false;
25605 }, undefined, () => { }, () => { });
25606 }
25607 zone.fakeTopEventTask.invoke();
25608 });
25609 updateMicroTaskStatus(zone);
25610}
25611function forkInnerZoneWithAngularBehavior(zone) {
25612 const delayChangeDetectionForEventsDelegate = () => {
25613 delayChangeDetectionForEvents(zone);
25614 };
25615 zone._inner = zone._inner.fork({
25616 name: 'angular',
25617 properties: { 'isAngularZone': true },
25618 onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
25619 try {
25620 onEnter(zone);
25621 return delegate.invokeTask(target, task, applyThis, applyArgs);
25622 }
25623 finally {
25624 if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
25625 zone.shouldCoalesceRunChangeDetection) {
25626 delayChangeDetectionForEventsDelegate();
25627 }
25628 onLeave(zone);
25629 }
25630 },
25631 onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
25632 try {
25633 onEnter(zone);
25634 return delegate.invoke(target, callback, applyThis, applyArgs, source);
25635 }
25636 finally {
25637 if (zone.shouldCoalesceRunChangeDetection) {
25638 delayChangeDetectionForEventsDelegate();
25639 }
25640 onLeave(zone);
25641 }
25642 },
25643 onHasTask: (delegate, current, target, hasTaskState) => {
25644 delegate.hasTask(target, hasTaskState);
25645 if (current === target) {
25646 // We are only interested in hasTask events which originate from our zone
25647 // (A child hasTask event is not interesting to us)
25648 if (hasTaskState.change == 'microTask') {
25649 zone._hasPendingMicrotasks = hasTaskState.microTask;
25650 updateMicroTaskStatus(zone);
25651 checkStable(zone);
25652 }
25653 else if (hasTaskState.change == 'macroTask') {
25654 zone.hasPendingMacrotasks = hasTaskState.macroTask;
25655 }
25656 }
25657 },
25658 onHandleError: (delegate, current, target, error) => {
25659 delegate.handleError(target, error);
25660 zone.runOutsideAngular(() => zone.onError.emit(error));
25661 return false;
25662 }
25663 });
25664}
25665function updateMicroTaskStatus(zone) {
25666 if (zone._hasPendingMicrotasks ||
25667 ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
25668 zone.lastRequestAnimationFrameId !== -1)) {
25669 zone.hasPendingMicrotasks = true;
25670 }
25671 else {
25672 zone.hasPendingMicrotasks = false;
25673 }
25674}
25675function onEnter(zone) {
25676 zone._nesting++;
25677 if (zone.isStable) {
25678 zone.isStable = false;
25679 zone.onUnstable.emit(null);
25680 }
25681}
25682function onLeave(zone) {
25683 zone._nesting--;
25684 checkStable(zone);
25685}
25686/**
25687 * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
25688 * to framework to perform rendering.
25689 */
25690class NoopNgZone {
25691 constructor() {
25692 this.hasPendingMicrotasks = false;
25693 this.hasPendingMacrotasks = false;
25694 this.isStable = true;
25695 this.onUnstable = new EventEmitter();
25696 this.onMicrotaskEmpty = new EventEmitter();
25697 this.onStable = new EventEmitter();
25698 this.onError = new EventEmitter();
25699 }
25700 run(fn, applyThis, applyArgs) {
25701 return fn.apply(applyThis, applyArgs);
25702 }
25703 runGuarded(fn, applyThis, applyArgs) {
25704 return fn.apply(applyThis, applyArgs);
25705 }
25706 runOutsideAngular(fn) {
25707 return fn();
25708 }
25709 runTask(fn, applyThis, applyArgs, name) {
25710 return fn.apply(applyThis, applyArgs);
25711 }
25712}
25713
25714/**
25715 * @license
25716 * Copyright Google LLC All Rights Reserved.
25717 *
25718 * Use of this source code is governed by an MIT-style license that can be
25719 * found in the LICENSE file at https://angular.io/license
25720 */
25721/**
25722 * The Testability service provides testing hooks that can be accessed from
25723 * the browser. Each bootstrapped Angular application on the page will have
25724 * an instance of Testability.
25725 * @publicApi
25726 */
25727class Testability {
25728 constructor(_ngZone) {
25729 this._ngZone = _ngZone;
25730 this._pendingCount = 0;
25731 this._isZoneStable = true;
25732 /**
25733 * Whether any work was done since the last 'whenStable' callback. This is
25734 * useful to detect if this could have potentially destabilized another
25735 * component while it is stabilizing.
25736 * @internal
25737 */
25738 this._didWork = false;
25739 this._callbacks = [];
25740 this.taskTrackingZone = null;
25741 this._watchAngularEvents();
25742 _ngZone.run(() => {
25743 this.taskTrackingZone =
25744 typeof Zone == 'undefined' ? null : Zone.current.get('TaskTrackingZone');
25745 });
25746 }
25747 _watchAngularEvents() {
25748 this._ngZone.onUnstable.subscribe({
25749 next: () => {
25750 this._didWork = true;
25751 this._isZoneStable = false;
25752 }
25753 });
25754 this._ngZone.runOutsideAngular(() => {
25755 this._ngZone.onStable.subscribe({
25756 next: () => {
25757 NgZone.assertNotInAngularZone();
25758 scheduleMicroTask(() => {
25759 this._isZoneStable = true;
25760 this._runCallbacksIfReady();
25761 });
25762 }
25763 });
25764 });
25765 }
25766 /**
25767 * Increases the number of pending request
25768 * @deprecated pending requests are now tracked with zones.
25769 */
25770 increasePendingRequestCount() {
25771 this._pendingCount += 1;
25772 this._didWork = true;
25773 return this._pendingCount;
25774 }
25775 /**
25776 * Decreases the number of pending request
25777 * @deprecated pending requests are now tracked with zones
25778 */
25779 decreasePendingRequestCount() {
25780 this._pendingCount -= 1;
25781 if (this._pendingCount < 0) {
25782 throw new Error('pending async requests below zero');
25783 }
25784 this._runCallbacksIfReady();
25785 return this._pendingCount;
25786 }
25787 /**
25788 * Whether an associated application is stable
25789 */
25790 isStable() {
25791 return this._isZoneStable && this._pendingCount === 0 && !this._ngZone.hasPendingMacrotasks;
25792 }
25793 _runCallbacksIfReady() {
25794 if (this.isStable()) {
25795 // Schedules the call backs in a new frame so that it is always async.
25796 scheduleMicroTask(() => {
25797 while (this._callbacks.length !== 0) {
25798 let cb = this._callbacks.pop();
25799 clearTimeout(cb.timeoutId);
25800 cb.doneCb(this._didWork);
25801 }
25802 this._didWork = false;
25803 });
25804 }
25805 else {
25806 // Still not stable, send updates.
25807 let pending = this.getPendingTasks();
25808 this._callbacks = this._callbacks.filter((cb) => {
25809 if (cb.updateCb && cb.updateCb(pending)) {
25810 clearTimeout(cb.timeoutId);
25811 return false;
25812 }
25813 return true;
25814 });
25815 this._didWork = true;
25816 }
25817 }
25818 getPendingTasks() {
25819 if (!this.taskTrackingZone) {
25820 return [];
25821 }
25822 // Copy the tasks data so that we don't leak tasks.
25823 return this.taskTrackingZone.macroTasks.map((t) => {
25824 return {
25825 source: t.source,
25826 // From TaskTrackingZone:
25827 // https://github.com/angular/zone.js/blob/master/lib/zone-spec/task-tracking.ts#L40
25828 creationLocation: t.creationLocation,
25829 data: t.data
25830 };
25831 });
25832 }
25833 addCallback(cb, timeout, updateCb) {
25834 let timeoutId = -1;
25835 if (timeout && timeout > 0) {
25836 timeoutId = setTimeout(() => {
25837 this._callbacks = this._callbacks.filter((cb) => cb.timeoutId !== timeoutId);
25838 cb(this._didWork, this.getPendingTasks());
25839 }, timeout);
25840 }
25841 this._callbacks.push({ doneCb: cb, timeoutId: timeoutId, updateCb: updateCb });
25842 }
25843 /**
25844 * Wait for the application to be stable with a timeout. If the timeout is reached before that
25845 * happens, the callback receives a list of the macro tasks that were pending, otherwise null.
25846 *
25847 * @param doneCb The callback to invoke when Angular is stable or the timeout expires
25848 * whichever comes first.
25849 * @param timeout Optional. The maximum time to wait for Angular to become stable. If not
25850 * specified, whenStable() will wait forever.
25851 * @param updateCb Optional. If specified, this callback will be invoked whenever the set of
25852 * pending macrotasks changes. If this callback returns true doneCb will not be invoked
25853 * and no further updates will be issued.
25854 */
25855 whenStable(doneCb, timeout, updateCb) {
25856 if (updateCb && !this.taskTrackingZone) {
25857 throw new Error('Task tracking zone is required when passing an update callback to ' +
25858 'whenStable(). Is "zone.js/plugins/task-tracking" loaded?');
25859 }
25860 // These arguments are 'Function' above to keep the public API simple.
25861 this.addCallback(doneCb, timeout, updateCb);
25862 this._runCallbacksIfReady();
25863 }
25864 /**
25865 * Get the number of pending requests
25866 * @deprecated pending requests are now tracked with zones
25867 */
25868 getPendingRequestCount() {
25869 return this._pendingCount;
25870 }
25871 /**
25872 * Find providers by name
25873 * @param using The root element to search from
25874 * @param provider The name of binding variable
25875 * @param exactMatch Whether using exactMatch
25876 */
25877 findProviders(using, provider, exactMatch) {
25878 // TODO(juliemr): implement.
25879 return [];
25880 }
25881}
25882Testability.ɵfac = function Testability_Factory(t) { return new (t || Testability)(ɵɵinject(NgZone)); };
25883Testability.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Testability, factory: Testability.ɵfac });
25884(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Testability, [{
25885 type: Injectable
25886 }], function () { return [{ type: NgZone }]; }, null); })();
25887/**
25888 * A global registry of {@link Testability} instances for specific elements.
25889 * @publicApi
25890 */
25891class TestabilityRegistry {
25892 constructor() {
25893 /** @internal */
25894 this._applications = new Map();
25895 _testabilityGetter.addToWindow(this);
25896 }
25897 /**
25898 * Registers an application with a testability hook so that it can be tracked
25899 * @param token token of application, root element
25900 * @param testability Testability hook
25901 */
25902 registerApplication(token, testability) {
25903 this._applications.set(token, testability);
25904 }
25905 /**
25906 * Unregisters an application.
25907 * @param token token of application, root element
25908 */
25909 unregisterApplication(token) {
25910 this._applications.delete(token);
25911 }
25912 /**
25913 * Unregisters all applications
25914 */
25915 unregisterAllApplications() {
25916 this._applications.clear();
25917 }
25918 /**
25919 * Get a testability hook associated with the application
25920 * @param elem root element
25921 */
25922 getTestability(elem) {
25923 return this._applications.get(elem) || null;
25924 }
25925 /**
25926 * Get all registered testabilities
25927 */
25928 getAllTestabilities() {
25929 return Array.from(this._applications.values());
25930 }
25931 /**
25932 * Get all registered applications(root elements)
25933 */
25934 getAllRootElements() {
25935 return Array.from(this._applications.keys());
25936 }
25937 /**
25938 * Find testability of a node in the Tree
25939 * @param elem node
25940 * @param findInAncestors whether finding testability in ancestors if testability was not found in
25941 * current node
25942 */
25943 findTestabilityInTree(elem, findInAncestors = true) {
25944 return _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors);
25945 }
25946}
25947TestabilityRegistry.ɵfac = function TestabilityRegistry_Factory(t) { return new (t || TestabilityRegistry)(); };
25948TestabilityRegistry.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: TestabilityRegistry, factory: TestabilityRegistry.ɵfac, providedIn: 'platform' });
25949(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(TestabilityRegistry, [{
25950 type: Injectable,
25951 args: [{ providedIn: 'platform' }]
25952 }], function () { return []; }, null); })();
25953class _NoopGetTestability {
25954 addToWindow(registry) { }
25955 findTestabilityInTree(registry, elem, findInAncestors) {
25956 return null;
25957 }
25958}
25959/**
25960 * Set the {@link GetTestability} implementation used by the Angular testing framework.
25961 * @publicApi
25962 */
25963function setTestabilityGetter(getter) {
25964 _testabilityGetter = getter;
25965}
25966let _testabilityGetter = new _NoopGetTestability();
25967
25968/**
25969 * @license
25970 * Copyright Google LLC All Rights Reserved.
25971 *
25972 * Use of this source code is governed by an MIT-style license that can be
25973 * found in the LICENSE file at https://angular.io/license
25974 */
25975let _platformInjector = null;
25976/**
25977 * Internal token to indicate whether having multiple bootstrapped platform should be allowed (only
25978 * one bootstrapped platform is allowed by default). This token helps to support SSR scenarios.
25979 */
25980const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken');
25981/**
25982 * Internal token that allows to register extra callbacks that should be invoked during the
25983 * `PlatformRef.destroy` operation. This token is needed to avoid a direct reference to the
25984 * `PlatformRef` class (i.e. register the callback via `PlatformRef.onDestroy`), thus making the
25985 * entire class tree-shakeable.
25986 */
25987const PLATFORM_ON_DESTROY = new InjectionToken('PlatformOnDestroy');
25988function compileNgModuleFactory(injector, options, moduleType) {
25989 ngDevMode && assertNgModuleType(moduleType);
25990 const moduleFactory = new NgModuleFactory(moduleType);
25991 // All of the logic below is irrelevant for AOT-compiled code.
25992 if (typeof ngJitMode !== 'undefined' && !ngJitMode) {
25993 return Promise.resolve(moduleFactory);
25994 }
25995 const compilerOptions = injector.get(COMPILER_OPTIONS, []).concat(options);
25996 // Configure the compiler to use the provided options. This call may fail when multiple modules
25997 // are bootstrapped with incompatible options, as a component can only be compiled according to
25998 // a single set of options.
25999 setJitOptions({
26000 defaultEncapsulation: _lastDefined(compilerOptions.map(opts => opts.defaultEncapsulation)),
26001 preserveWhitespaces: _lastDefined(compilerOptions.map(opts => opts.preserveWhitespaces)),
26002 });
26003 if (isComponentResourceResolutionQueueEmpty()) {
26004 return Promise.resolve(moduleFactory);
26005 }
26006 const compilerProviders = _mergeArrays(compilerOptions.map(o => o.providers));
26007 // In case there are no compiler providers, we just return the module factory as
26008 // there won't be any resource loader. This can happen with Ivy, because AOT compiled
26009 // modules can be still passed through "bootstrapModule". In that case we shouldn't
26010 // unnecessarily require the JIT compiler.
26011 if (compilerProviders.length === 0) {
26012 return Promise.resolve(moduleFactory);
26013 }
26014 const compiler = getCompilerFacade({
26015 usage: 0 /* Decorator */,
26016 kind: 'NgModule',
26017 type: moduleType,
26018 });
26019 const compilerInjector = Injector.create({ providers: compilerProviders });
26020 const resourceLoader = compilerInjector.get(compiler.ResourceLoader);
26021 // The resource loader can also return a string while the "resolveComponentResources"
26022 // always expects a promise. Therefore we need to wrap the returned value in a promise.
26023 return resolveComponentResources(url => Promise.resolve(resourceLoader.get(url)))
26024 .then(() => moduleFactory);
26025}
26026function publishDefaultGlobalUtils() {
26027 ngDevMode && publishDefaultGlobalUtils$1();
26028}
26029function isBoundToModule(cf) {
26030 return cf.isBoundToModule;
26031}
26032/**
26033 * A token for third-party components that can register themselves with NgProbe.
26034 *
26035 * @publicApi
26036 */
26037class NgProbeToken {
26038 constructor(name, token) {
26039 this.name = name;
26040 this.token = token;
26041 }
26042}
26043/**
26044 * Creates a platform.
26045 * Platforms must be created on launch using this function.
26046 *
26047 * @publicApi
26048 */
26049function createPlatform(injector) {
26050 if (_platformInjector && !_platformInjector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
26051 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
26052 'There can be only one platform. Destroy the previous one to create a new one.' :
26053 '';
26054 throw new RuntimeError(400 /* MULTIPLE_PLATFORMS */, errorMessage);
26055 }
26056 publishDefaultGlobalUtils();
26057 _platformInjector = injector;
26058 const platform = injector.get(PlatformRef);
26059 const inits = injector.get(PLATFORM_INITIALIZER, null);
26060 if (inits)
26061 inits.forEach(initFn => initFn());
26062 return platform;
26063}
26064/**
26065 * Creates a factory for a platform. Can be used to provide or override `Providers` specific to
26066 * your application's runtime needs, such as `PLATFORM_INITIALIZER` and `PLATFORM_ID`.
26067 * @param parentPlatformFactory Another platform factory to modify. Allows you to compose factories
26068 * to build up configurations that might be required by different libraries or parts of the
26069 * application.
26070 * @param name Identifies the new platform factory.
26071 * @param providers A set of dependency providers for platforms created with the new factory.
26072 *
26073 * @publicApi
26074 */
26075function createPlatformFactory(parentPlatformFactory, name, providers = []) {
26076 const desc = `Platform: ${name}`;
26077 const marker = new InjectionToken(desc);
26078 return (extraProviders = []) => {
26079 let platform = getPlatform();
26080 if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
26081 const platformProviders = [
26082 ...providers,
26083 ...extraProviders,
26084 { provide: marker, useValue: true }
26085 ];
26086 if (parentPlatformFactory) {
26087 parentPlatformFactory(platformProviders);
26088 }
26089 else {
26090 createPlatform(createPlatformInjector(platformProviders, desc));
26091 }
26092 }
26093 return assertPlatform(marker);
26094 };
26095}
26096/**
26097 * Checks that there is currently a platform that contains the given token as a provider.
26098 *
26099 * @publicApi
26100 */
26101function assertPlatform(requiredToken) {
26102 const platform = getPlatform();
26103 if (!platform) {
26104 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ? 'No platform exists!' : '';
26105 throw new RuntimeError(401 /* PLATFORM_NOT_FOUND */, errorMessage);
26106 }
26107 if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
26108 !platform.injector.get(requiredToken, null)) {
26109 throw new RuntimeError(400 /* MULTIPLE_PLATFORMS */, 'A platform with a different configuration has been created. Please destroy it first.');
26110 }
26111 return platform;
26112}
26113/**
26114 * Helper function to create an instance of a platform injector (that maintains the 'platform'
26115 * scope).
26116 */
26117function createPlatformInjector(providers = [], name) {
26118 return Injector.create({
26119 name,
26120 providers: [
26121 { provide: INJECTOR_SCOPE, useValue: 'platform' },
26122 { provide: PLATFORM_ON_DESTROY, useValue: () => _platformInjector = null },
26123 ...providers
26124 ],
26125 });
26126}
26127/**
26128 * Destroys the current Angular platform and all Angular applications on the page.
26129 * Destroys all modules and listeners registered with the platform.
26130 *
26131 * @publicApi
26132 */
26133function destroyPlatform() {
26134 getPlatform()?.destroy();
26135}
26136/**
26137 * Returns the current platform.
26138 *
26139 * @publicApi
26140 */
26141function getPlatform() {
26142 return _platformInjector?.get(PlatformRef) ?? null;
26143}
26144/**
26145 * The Angular platform is the entry point for Angular on a web page.
26146 * Each page has exactly one platform. Services (such as reflection) which are common
26147 * to every Angular application running on the page are bound in its scope.
26148 * A page's platform is initialized implicitly when a platform is created using a platform
26149 * factory such as `PlatformBrowser`, or explicitly by calling the `createPlatform()` function.
26150 *
26151 * @publicApi
26152 */
26153class PlatformRef {
26154 /** @internal */
26155 constructor(_injector) {
26156 this._injector = _injector;
26157 this._modules = [];
26158 this._destroyListeners = [];
26159 this._destroyed = false;
26160 }
26161 /**
26162 * Creates an instance of an `@NgModule` for the given platform.
26163 *
26164 * @deprecated Passing NgModule factories as the `PlatformRef.bootstrapModuleFactory` function
26165 * argument is deprecated. Use the `PlatformRef.bootstrapModule` API instead.
26166 */
26167 bootstrapModuleFactory(moduleFactory, options) {
26168 // Note: We need to create the NgZone _before_ we instantiate the module,
26169 // as instantiating the module creates some providers eagerly.
26170 // So we create a mini parent injector that just contains the new NgZone and
26171 // pass that as parent to the NgModuleFactory.
26172 const ngZoneOption = options ? options.ngZone : undefined;
26173 const ngZoneEventCoalescing = (options && options.ngZoneEventCoalescing) || false;
26174 const ngZoneRunCoalescing = (options && options.ngZoneRunCoalescing) || false;
26175 const ngZone = getNgZone(ngZoneOption, { ngZoneEventCoalescing, ngZoneRunCoalescing });
26176 const providers = [{ provide: NgZone, useValue: ngZone }];
26177 // Note: Create ngZoneInjector within ngZone.run so that all of the instantiated services are
26178 // created within the Angular zone
26179 // Do not try to replace ngZone.run with ApplicationRef#run because ApplicationRef would then be
26180 // created outside of the Angular zone.
26181 return ngZone.run(() => {
26182 const ngZoneInjector = Injector.create({ providers: providers, parent: this.injector, name: moduleFactory.moduleType.name });
26183 const moduleRef = moduleFactory.create(ngZoneInjector);
26184 const exceptionHandler = moduleRef.injector.get(ErrorHandler, null);
26185 if (!exceptionHandler) {
26186 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
26187 'No ErrorHandler. Is platform module (BrowserModule) included?' :
26188 '';
26189 throw new RuntimeError(402 /* ERROR_HANDLER_NOT_FOUND */, errorMessage);
26190 }
26191 ngZone.runOutsideAngular(() => {
26192 const subscription = ngZone.onError.subscribe({
26193 next: (error) => {
26194 exceptionHandler.handleError(error);
26195 }
26196 });
26197 moduleRef.onDestroy(() => {
26198 remove(this._modules, moduleRef);
26199 subscription.unsubscribe();
26200 });
26201 });
26202 return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
26203 const initStatus = moduleRef.injector.get(ApplicationInitStatus);
26204 initStatus.runInitializers();
26205 return initStatus.donePromise.then(() => {
26206 // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy
26207 const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
26208 setLocaleId(localeId || DEFAULT_LOCALE_ID);
26209 this._moduleDoBootstrap(moduleRef);
26210 return moduleRef;
26211 });
26212 });
26213 });
26214 }
26215 /**
26216 * Creates an instance of an `@NgModule` for a given platform.
26217 *
26218 * @usageNotes
26219 * ### Simple Example
26220 *
26221 * ```typescript
26222 * @NgModule({
26223 * imports: [BrowserModule]
26224 * })
26225 * class MyModule {}
26226 *
26227 * let moduleRef = platformBrowser().bootstrapModule(MyModule);
26228 * ```
26229 *
26230 */
26231 bootstrapModule(moduleType, compilerOptions = []) {
26232 const options = optionsReducer({}, compilerOptions);
26233 return compileNgModuleFactory(this.injector, options, moduleType)
26234 .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
26235 }
26236 _moduleDoBootstrap(moduleRef) {
26237 const appRef = moduleRef.injector.get(ApplicationRef);
26238 if (moduleRef._bootstrapComponents.length > 0) {
26239 moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
26240 }
26241 else if (moduleRef.instance.ngDoBootstrap) {
26242 moduleRef.instance.ngDoBootstrap(appRef);
26243 }
26244 else {
26245 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
26246 `The module ${stringify(moduleRef.instance.constructor)} was bootstrapped, ` +
26247 `but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
26248 `Please define one of these.` :
26249 '';
26250 throw new RuntimeError(403 /* BOOTSTRAP_COMPONENTS_NOT_FOUND */, errorMessage);
26251 }
26252 this._modules.push(moduleRef);
26253 }
26254 /**
26255 * Registers a listener to be called when the platform is destroyed.
26256 */
26257 onDestroy(callback) {
26258 this._destroyListeners.push(callback);
26259 }
26260 /**
26261 * Retrieves the platform {@link Injector}, which is the parent injector for
26262 * every Angular application on the page and provides singleton providers.
26263 */
26264 get injector() {
26265 return this._injector;
26266 }
26267 /**
26268 * Destroys the current Angular platform and all Angular applications on the page.
26269 * Destroys all modules and listeners registered with the platform.
26270 */
26271 destroy() {
26272 if (this._destroyed) {
26273 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
26274 'The platform has already been destroyed!' :
26275 '';
26276 throw new RuntimeError(404 /* ALREADY_DESTROYED_PLATFORM */, errorMessage);
26277 }
26278 this._modules.slice().forEach(module => module.destroy());
26279 this._destroyListeners.forEach(listener => listener());
26280 const destroyListener = this._injector.get(PLATFORM_ON_DESTROY, null);
26281 destroyListener?.();
26282 this._destroyed = true;
26283 }
26284 get destroyed() {
26285 return this._destroyed;
26286 }
26287}
26288PlatformRef.ɵfac = function PlatformRef_Factory(t) { return new (t || PlatformRef)(ɵɵinject(Injector)); };
26289PlatformRef.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: PlatformRef, factory: PlatformRef.ɵfac, providedIn: 'platform' });
26290(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PlatformRef, [{
26291 type: Injectable,
26292 args: [{ providedIn: 'platform' }]
26293 }], function () { return [{ type: Injector }]; }, null); })();
26294function getNgZone(ngZoneOption, extra) {
26295 let ngZone;
26296 if (ngZoneOption === 'noop') {
26297 ngZone = new NoopNgZone();
26298 }
26299 else {
26300 ngZone = (ngZoneOption === 'zone.js' ? undefined : ngZoneOption) || new NgZone({
26301 enableLongStackTrace: typeof ngDevMode === 'undefined' ? false : !!ngDevMode,
26302 shouldCoalesceEventChangeDetection: !!extra?.ngZoneEventCoalescing,
26303 shouldCoalesceRunChangeDetection: !!extra?.ngZoneRunCoalescing
26304 });
26305 }
26306 return ngZone;
26307}
26308function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
26309 try {
26310 const result = callback();
26311 if (isPromise(result)) {
26312 return result.catch((e) => {
26313 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
26314 // rethrow as the exception handler might not do it
26315 throw e;
26316 });
26317 }
26318 return result;
26319 }
26320 catch (e) {
26321 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
26322 // rethrow as the exception handler might not do it
26323 throw e;
26324 }
26325}
26326function optionsReducer(dst, objs) {
26327 if (Array.isArray(objs)) {
26328 dst = objs.reduce(optionsReducer, dst);
26329 }
26330 else {
26331 dst = { ...dst, ...objs };
26332 }
26333 return dst;
26334}
26335/**
26336 * A reference to an Angular application running on a page.
26337 *
26338 * @usageNotes
26339 *
26340 * {@a is-stable-examples}
26341 * ### isStable examples and caveats
26342 *
26343 * Note two important points about `isStable`, demonstrated in the examples below:
26344 * - the application will never be stable if you start any kind
26345 * of recurrent asynchronous task when the application starts
26346 * (for example for a polling process, started with a `setInterval`, a `setTimeout`
26347 * or using RxJS operators like `interval`);
26348 * - the `isStable` Observable runs outside of the Angular zone.
26349 *
26350 * Let's imagine that you start a recurrent task
26351 * (here incrementing a counter, using RxJS `interval`),
26352 * and at the same time subscribe to `isStable`.
26353 *
26354 * ```
26355 * constructor(appRef: ApplicationRef) {
26356 * appRef.isStable.pipe(
26357 * filter(stable => stable)
26358 * ).subscribe(() => console.log('App is stable now');
26359 * interval(1000).subscribe(counter => console.log(counter));
26360 * }
26361 * ```
26362 * In this example, `isStable` will never emit `true`,
26363 * and the trace "App is stable now" will never get logged.
26364 *
26365 * If you want to execute something when the app is stable,
26366 * you have to wait for the application to be stable
26367 * before starting your polling process.
26368 *
26369 * ```
26370 * constructor(appRef: ApplicationRef) {
26371 * appRef.isStable.pipe(
26372 * first(stable => stable),
26373 * tap(stable => console.log('App is stable now')),
26374 * switchMap(() => interval(1000))
26375 * ).subscribe(counter => console.log(counter));
26376 * }
26377 * ```
26378 * In this example, the trace "App is stable now" will be logged
26379 * and then the counter starts incrementing every second.
26380 *
26381 * Note also that this Observable runs outside of the Angular zone,
26382 * which means that the code in the subscription
26383 * to this Observable will not trigger the change detection.
26384 *
26385 * Let's imagine that instead of logging the counter value,
26386 * you update a field of your component
26387 * and display it in its template.
26388 *
26389 * ```
26390 * constructor(appRef: ApplicationRef) {
26391 * appRef.isStable.pipe(
26392 * first(stable => stable),
26393 * switchMap(() => interval(1000))
26394 * ).subscribe(counter => this.value = counter);
26395 * }
26396 * ```
26397 * As the `isStable` Observable runs outside the zone,
26398 * the `value` field will be updated properly,
26399 * but the template will not be refreshed!
26400 *
26401 * You'll have to manually trigger the change detection to update the template.
26402 *
26403 * ```
26404 * constructor(appRef: ApplicationRef, cd: ChangeDetectorRef) {
26405 * appRef.isStable.pipe(
26406 * first(stable => stable),
26407 * switchMap(() => interval(1000))
26408 * ).subscribe(counter => {
26409 * this.value = counter;
26410 * cd.detectChanges();
26411 * });
26412 * }
26413 * ```
26414 *
26415 * Or make the subscription callback run inside the zone.
26416 *
26417 * ```
26418 * constructor(appRef: ApplicationRef, zone: NgZone) {
26419 * appRef.isStable.pipe(
26420 * first(stable => stable),
26421 * switchMap(() => interval(1000))
26422 * ).subscribe(counter => zone.run(() => this.value = counter));
26423 * }
26424 * ```
26425 *
26426 * @publicApi
26427 */
26428class ApplicationRef {
26429 /** @internal */
26430 constructor(_zone, _injector, _exceptionHandler, _initStatus) {
26431 this._zone = _zone;
26432 this._injector = _injector;
26433 this._exceptionHandler = _exceptionHandler;
26434 this._initStatus = _initStatus;
26435 /** @internal */
26436 this._bootstrapListeners = [];
26437 this._views = [];
26438 this._runningTick = false;
26439 this._stable = true;
26440 /**
26441 * Get a list of component types registered to this application.
26442 * This list is populated even before the component is created.
26443 */
26444 this.componentTypes = [];
26445 /**
26446 * Get a list of components registered to this application.
26447 */
26448 this.components = [];
26449 this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({
26450 next: () => {
26451 this._zone.run(() => {
26452 this.tick();
26453 });
26454 }
26455 });
26456 const isCurrentlyStable = new Observable((observer) => {
26457 this._stable = this._zone.isStable && !this._zone.hasPendingMacrotasks &&
26458 !this._zone.hasPendingMicrotasks;
26459 this._zone.runOutsideAngular(() => {
26460 observer.next(this._stable);
26461 observer.complete();
26462 });
26463 });
26464 const isStable = new Observable((observer) => {
26465 // Create the subscription to onStable outside the Angular Zone so that
26466 // the callback is run outside the Angular Zone.
26467 let stableSub;
26468 this._zone.runOutsideAngular(() => {
26469 stableSub = this._zone.onStable.subscribe(() => {
26470 NgZone.assertNotInAngularZone();
26471 // Check whether there are no pending macro/micro tasks in the next tick
26472 // to allow for NgZone to update the state.
26473 scheduleMicroTask(() => {
26474 if (!this._stable && !this._zone.hasPendingMacrotasks &&
26475 !this._zone.hasPendingMicrotasks) {
26476 this._stable = true;
26477 observer.next(true);
26478 }
26479 });
26480 });
26481 });
26482 const unstableSub = this._zone.onUnstable.subscribe(() => {
26483 NgZone.assertInAngularZone();
26484 if (this._stable) {
26485 this._stable = false;
26486 this._zone.runOutsideAngular(() => {
26487 observer.next(false);
26488 });
26489 }
26490 });
26491 return () => {
26492 stableSub.unsubscribe();
26493 unstableSub.unsubscribe();
26494 };
26495 });
26496 this.isStable =
26497 merge$1(isCurrentlyStable, isStable.pipe(share()));
26498 }
26499 /**
26500 * Bootstrap a component onto the element identified by its selector or, optionally, to a
26501 * specified element.
26502 *
26503 * @usageNotes
26504 * ### Bootstrap process
26505 *
26506 * When bootstrapping a component, Angular mounts it onto a target DOM element
26507 * and kicks off automatic change detection. The target DOM element can be
26508 * provided using the `rootSelectorOrNode` argument.
26509 *
26510 * If the target DOM element is not provided, Angular tries to find one on a page
26511 * using the `selector` of the component that is being bootstrapped
26512 * (first matched element is used).
26513 *
26514 * ### Example
26515 *
26516 * Generally, we define the component to bootstrap in the `bootstrap` array of `NgModule`,
26517 * but it requires us to know the component while writing the application code.
26518 *
26519 * Imagine a situation where we have to wait for an API call to decide about the component to
26520 * bootstrap. We can use the `ngDoBootstrap` hook of the `NgModule` and call this method to
26521 * dynamically bootstrap a component.
26522 *
26523 * {@example core/ts/platform/platform.ts region='componentSelector'}
26524 *
26525 * Optionally, a component can be mounted onto a DOM element that does not match the
26526 * selector of the bootstrapped component.
26527 *
26528 * In the following example, we are providing a CSS selector to match the target element.
26529 *
26530 * {@example core/ts/platform/platform.ts region='cssSelector'}
26531 *
26532 * While in this example, we are providing reference to a DOM node.
26533 *
26534 * {@example core/ts/platform/platform.ts region='domNode'}
26535 */
26536 bootstrap(componentOrFactory, rootSelectorOrNode) {
26537 if (!this._initStatus.done) {
26538 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
26539 'Cannot bootstrap as there are still asynchronous initializers running. ' +
26540 'Bootstrap components in the `ngDoBootstrap` method of the root module.' :
26541 '';
26542 throw new RuntimeError(405 /* ASYNC_INITIALIZERS_STILL_RUNNING */, errorMessage);
26543 }
26544 let componentFactory;
26545 if (componentOrFactory instanceof ComponentFactory$1) {
26546 componentFactory = componentOrFactory;
26547 }
26548 else {
26549 const resolver = this._injector.get(ComponentFactoryResolver$1);
26550 componentFactory = resolver.resolveComponentFactory(componentOrFactory);
26551 }
26552 this.componentTypes.push(componentFactory.componentType);
26553 // Create a factory associated with the current module if it's not bound to some other
26554 const ngModule = isBoundToModule(componentFactory) ? undefined : this._injector.get(NgModuleRef$1);
26555 const selectorOrNode = rootSelectorOrNode || componentFactory.selector;
26556 const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);
26557 const nativeElement = compRef.location.nativeElement;
26558 const testability = compRef.injector.get(Testability, null);
26559 const testabilityRegistry = testability && compRef.injector.get(TestabilityRegistry);
26560 if (testability && testabilityRegistry) {
26561 testabilityRegistry.registerApplication(nativeElement, testability);
26562 }
26563 compRef.onDestroy(() => {
26564 this.detachView(compRef.hostView);
26565 remove(this.components, compRef);
26566 if (testabilityRegistry) {
26567 testabilityRegistry.unregisterApplication(nativeElement);
26568 }
26569 });
26570 this._loadComponent(compRef);
26571 if (typeof ngDevMode === 'undefined' || ngDevMode) {
26572 const _console = this._injector.get(Console);
26573 _console.log(`Angular is running in development mode. Call enableProdMode() to enable production mode.`);
26574 }
26575 return compRef;
26576 }
26577 /**
26578 * Invoke this method to explicitly process change detection and its side-effects.
26579 *
26580 * In development mode, `tick()` also performs a second change detection cycle to ensure that no
26581 * further changes are detected. If additional changes are picked up during this second cycle,
26582 * bindings in the app have side-effects that cannot be resolved in a single change detection
26583 * pass.
26584 * In this case, Angular throws an error, since an Angular application can only have one change
26585 * detection pass during which all change detection must complete.
26586 */
26587 tick() {
26588 if (this._runningTick) {
26589 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
26590 'ApplicationRef.tick is called recursively' :
26591 '';
26592 throw new RuntimeError(101 /* RECURSIVE_APPLICATION_REF_TICK */, errorMessage);
26593 }
26594 try {
26595 this._runningTick = true;
26596 for (let view of this._views) {
26597 view.detectChanges();
26598 }
26599 if (typeof ngDevMode === 'undefined' || ngDevMode) {
26600 for (let view of this._views) {
26601 view.checkNoChanges();
26602 }
26603 }
26604 }
26605 catch (e) {
26606 // Attention: Don't rethrow as it could cancel subscriptions to Observables!
26607 this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));
26608 }
26609 finally {
26610 this._runningTick = false;
26611 }
26612 }
26613 /**
26614 * Attaches a view so that it will be dirty checked.
26615 * The view will be automatically detached when it is destroyed.
26616 * This will throw if the view is already attached to a ViewContainer.
26617 */
26618 attachView(viewRef) {
26619 const view = viewRef;
26620 this._views.push(view);
26621 view.attachToAppRef(this);
26622 }
26623 /**
26624 * Detaches a view from dirty checking again.
26625 */
26626 detachView(viewRef) {
26627 const view = viewRef;
26628 remove(this._views, view);
26629 view.detachFromAppRef();
26630 }
26631 _loadComponent(componentRef) {
26632 this.attachView(componentRef.hostView);
26633 this.tick();
26634 this.components.push(componentRef);
26635 // Get the listeners lazily to prevent DI cycles.
26636 const listeners = this._injector.get(APP_BOOTSTRAP_LISTENER, []).concat(this._bootstrapListeners);
26637 listeners.forEach((listener) => listener(componentRef));
26638 }
26639 /** @internal */
26640 ngOnDestroy() {
26641 this._views.slice().forEach((view) => view.destroy());
26642 this._onMicrotaskEmptySubscription.unsubscribe();
26643 }
26644 /**
26645 * Returns the number of attached views.
26646 */
26647 get viewCount() {
26648 return this._views.length;
26649 }
26650}
26651ApplicationRef.ɵfac = function ApplicationRef_Factory(t) { return new (t || ApplicationRef)(ɵɵinject(NgZone), ɵɵinject(Injector), ɵɵinject(ErrorHandler), ɵɵinject(ApplicationInitStatus)); };
26652ApplicationRef.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationRef, factory: ApplicationRef.ɵfac, providedIn: 'root' });
26653(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationRef, [{
26654 type: Injectable,
26655 args: [{ providedIn: 'root' }]
26656 }], function () { return [{ type: NgZone }, { type: Injector }, { type: ErrorHandler }, { type: ApplicationInitStatus }]; }, null); })();
26657function remove(list, el) {
26658 const index = list.indexOf(el);
26659 if (index > -1) {
26660 list.splice(index, 1);
26661 }
26662}
26663function _lastDefined(args) {
26664 for (let i = args.length - 1; i >= 0; i--) {
26665 if (args[i] !== undefined) {
26666 return args[i];
26667 }
26668 }
26669 return undefined;
26670}
26671function _mergeArrays(parts) {
26672 const result = [];
26673 parts.forEach((part) => part && result.push(...part));
26674 return result;
26675}
26676
26677/**
26678 * @license
26679 * Copyright Google LLC All Rights Reserved.
26680 *
26681 * Use of this source code is governed by an MIT-style license that can be
26682 * found in the LICENSE file at https://angular.io/license
26683 */
26684/**
26685 * This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
26686 *
26687 * For more information on how to run and debug tests with either Ivy or View Engine (legacy),
26688 * please see [BAZEL.md](./docs/BAZEL.md).
26689 */
26690let _devMode = true;
26691let _runModeLocked = false;
26692/**
26693 * Returns whether Angular is in development mode. After called once,
26694 * the value is locked and won't change any more.
26695 *
26696 * By default, this is true, unless a user calls `enableProdMode` before calling this.
26697 *
26698 * @publicApi
26699 */
26700function isDevMode() {
26701 _runModeLocked = true;
26702 return _devMode;
26703}
26704/**
26705 * Disable Angular's development mode, which turns off assertions and other
26706 * checks within the framework.
26707 *
26708 * One important assertion this disables verifies that a change detection pass
26709 * does not result in additional changes to any bindings (also known as
26710 * unidirectional data flow).
26711 *
26712 * @publicApi
26713 */
26714function enableProdMode() {
26715 if (_runModeLocked) {
26716 throw new Error('Cannot enable prod mode after platform setup.');
26717 }
26718 // The below check is there so when ngDevMode is set via terser
26719 // `global['ngDevMode'] = false;` is also dropped.
26720 if (typeof ngDevMode === undefined || !!ngDevMode) {
26721 _global['ngDevMode'] = false;
26722 }
26723 _devMode = false;
26724}
26725
26726/**
26727 * @license
26728 * Copyright Google LLC All Rights Reserved.
26729 *
26730 * Use of this source code is governed by an MIT-style license that can be
26731 * found in the LICENSE file at https://angular.io/license
26732 */
26733
26734/**
26735 * @license
26736 * Copyright Google LLC All Rights Reserved.
26737 *
26738 * Use of this source code is governed by an MIT-style license that can be
26739 * found in the LICENSE file at https://angular.io/license
26740 */
26741
26742/**
26743 * @license
26744 * Copyright Google LLC All Rights Reserved.
26745 *
26746 * Use of this source code is governed by an MIT-style license that can be
26747 * found in the LICENSE file at https://angular.io/license
26748 */
26749/**
26750 * Returns the NgModuleFactory with the given id (specified using [@NgModule.id
26751 * field](api/core/NgModule#id)), if it exists and has been loaded. Factories for NgModules that do
26752 * not specify an `id` cannot be retrieved. Throws if an NgModule cannot be found.
26753 * @publicApi
26754 * @deprecated Use `getNgModuleById` instead.
26755 */
26756function getModuleFactory(id) {
26757 const type = getRegisteredNgModuleType(id);
26758 if (!type)
26759 throw noModuleError(id);
26760 return new NgModuleFactory(type);
26761}
26762/**
26763 * Returns the NgModule class with the given id (specified using [@NgModule.id
26764 * field](api/core/NgModule#id)), if it exists and has been loaded. Classes for NgModules that do
26765 * not specify an `id` cannot be retrieved. Throws if an NgModule cannot be found.
26766 * @publicApi
26767 */
26768function getNgModuleById(id) {
26769 const type = getRegisteredNgModuleType(id);
26770 if (!type)
26771 throw noModuleError(id);
26772 return type;
26773}
26774function noModuleError(id) {
26775 return new Error(`No module with ID ${id} loaded`);
26776}
26777
26778/**
26779 * @license
26780 * Copyright Google LLC All Rights Reserved.
26781 *
26782 * Use of this source code is governed by an MIT-style license that can be
26783 * found in the LICENSE file at https://angular.io/license
26784 */
26785/**
26786 * Base class that provides change detection functionality.
26787 * A change-detection tree collects all views that are to be checked for changes.
26788 * Use the methods to add and remove views from the tree, initiate change-detection,
26789 * and explicitly mark views as _dirty_, meaning that they have changed and need to be re-rendered.
26790 *
26791 * @see [Using change detection hooks](guide/lifecycle-hooks#using-change-detection-hooks)
26792 * @see [Defining custom change detection](guide/lifecycle-hooks#defining-custom-change-detection)
26793 *
26794 * @usageNotes
26795 *
26796 * The following examples demonstrate how to modify default change-detection behavior
26797 * to perform explicit detection when needed.
26798 *
26799 * ### Use `markForCheck()` with `CheckOnce` strategy
26800 *
26801 * The following example sets the `OnPush` change-detection strategy for a component
26802 * (`CheckOnce`, rather than the default `CheckAlways`), then forces a second check
26803 * after an interval. See [live demo](https://plnkr.co/edit/GC512b?p=preview).
26804 *
26805 * <code-example path="core/ts/change_detect/change-detection.ts"
26806 * region="mark-for-check"></code-example>
26807 *
26808 * ### Detach change detector to limit how often check occurs
26809 *
26810 * The following example defines a component with a large list of read-only data
26811 * that is expected to change constantly, many times per second.
26812 * To improve performance, we want to check and update the list
26813 * less often than the changes actually occur. To do that, we detach
26814 * the component's change detector and perform an explicit local check every five seconds.
26815 *
26816 * <code-example path="core/ts/change_detect/change-detection.ts" region="detach"></code-example>
26817 *
26818 *
26819 * ### Reattaching a detached component
26820 *
26821 * The following example creates a component displaying live data.
26822 * The component detaches its change detector from the main change detector tree
26823 * when the `live` property is set to false, and reattaches it when the property
26824 * becomes true.
26825 *
26826 * <code-example path="core/ts/change_detect/change-detection.ts" region="reattach"></code-example>
26827 *
26828 * @publicApi
26829 */
26830class ChangeDetectorRef {
26831}
26832/**
26833 * @internal
26834 * @nocollapse
26835 */
26836ChangeDetectorRef.__NG_ELEMENT_ID__ = injectChangeDetectorRef;
26837/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
26838function injectChangeDetectorRef(flags) {
26839 return createViewRef(getCurrentTNode(), getLView(), (flags & 16 /* ForPipe */) === 16 /* ForPipe */);
26840}
26841/**
26842 * Creates a ViewRef and stores it on the injector as ChangeDetectorRef (public alias).
26843 *
26844 * @param tNode The node that is requesting a ChangeDetectorRef
26845 * @param lView The view to which the node belongs
26846 * @param isPipe Whether the view is being injected into a pipe.
26847 * @returns The ChangeDetectorRef to use
26848 */
26849function createViewRef(tNode, lView, isPipe) {
26850 if (isComponentHost(tNode) && !isPipe) {
26851 // The LView represents the location where the component is declared.
26852 // Instead we want the LView for the component View and so we need to look it up.
26853 const componentView = getComponentLViewByIndex(tNode.index, lView); // look down
26854 return new ViewRef$1(componentView, componentView);
26855 }
26856 else if (tNode.type & (3 /* AnyRNode */ | 12 /* AnyContainer */ | 32 /* Icu */)) {
26857 // The LView represents the location where the injection is requested from.
26858 // We need to locate the containing LView (in case where the `lView` is an embedded view)
26859 const hostComponentView = lView[DECLARATION_COMPONENT_VIEW]; // look up
26860 return new ViewRef$1(hostComponentView, lView);
26861 }
26862 return null;
26863}
26864
26865/**
26866 * @license
26867 * Copyright Google LLC All Rights Reserved.
26868 *
26869 * Use of this source code is governed by an MIT-style license that can be
26870 * found in the LICENSE file at https://angular.io/license
26871 */
26872/**
26873 * Represents an Angular [view](guide/glossary#view "Definition").
26874 *
26875 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
26876 *
26877 * @publicApi
26878 */
26879class ViewRef extends ChangeDetectorRef {
26880}
26881/**
26882 * Represents an Angular [view](guide/glossary#view) in a view container.
26883 * An [embedded view](guide/glossary#view-tree) can be referenced from a component
26884 * other than the hosting component whose template defines it, or it can be defined
26885 * independently by a `TemplateRef`.
26886 *
26887 * Properties of elements in a view can change, but the structure (number and order) of elements in
26888 * a view cannot. Change the structure of elements by inserting, moving, or
26889 * removing nested views in a view container.
26890 *
26891 * @see `ViewContainerRef`
26892 *
26893 * @usageNotes
26894 *
26895 * The following template breaks down into two separate `TemplateRef` instances,
26896 * an outer one and an inner one.
26897 *
26898 * ```
26899 * Count: {{items.length}}
26900 * <ul>
26901 * <li *ngFor="let item of items">{{item}}</li>
26902 * </ul>
26903 * ```
26904 *
26905 * This is the outer `TemplateRef`:
26906 *
26907 * ```
26908 * Count: {{items.length}}
26909 * <ul>
26910 * <ng-template ngFor let-item [ngForOf]="items"></ng-template>
26911 * </ul>
26912 * ```
26913 *
26914 * This is the inner `TemplateRef`:
26915 *
26916 * ```
26917 * <li>{{item}}</li>
26918 * ```
26919 *
26920 * The outer and inner `TemplateRef` instances are assembled into views as follows:
26921 *
26922 * ```
26923 * <!-- ViewRef: outer-0 -->
26924 * Count: 2
26925 * <ul>
26926 * <ng-template view-container-ref></ng-template>
26927 * <!-- ViewRef: inner-1 --><li>first</li><!-- /ViewRef: inner-1 -->
26928 * <!-- ViewRef: inner-2 --><li>second</li><!-- /ViewRef: inner-2 -->
26929 * </ul>
26930 * <!-- /ViewRef: outer-0 -->
26931 * ```
26932 * @publicApi
26933 */
26934class EmbeddedViewRef extends ViewRef {
26935}
26936
26937/**
26938 * @license
26939 * Copyright Google LLC All Rights Reserved.
26940 *
26941 * Use of this source code is governed by an MIT-style license that can be
26942 * found in the LICENSE file at https://angular.io/license
26943 */
26944
26945/**
26946 * @license
26947 * Copyright Google LLC All Rights Reserved.
26948 *
26949 * Use of this source code is governed by an MIT-style license that can be
26950 * found in the LICENSE file at https://angular.io/license
26951 */
26952// This file exists for easily patching NgModuleFactoryLoader in g3
26953var ng_module_factory_loader_impl = {};
26954
26955/**
26956 * @license
26957 * Copyright Google LLC All Rights Reserved.
26958 *
26959 * Use of this source code is governed by an MIT-style license that can be
26960 * found in the LICENSE file at https://angular.io/license
26961 */
26962/**
26963 * @publicApi
26964 */
26965class DebugEventListener {
26966 constructor(name, callback) {
26967 this.name = name;
26968 this.callback = callback;
26969 }
26970}
26971/**
26972 * @publicApi
26973 */
26974function asNativeElements(debugEls) {
26975 return debugEls.map((el) => el.nativeElement);
26976}
26977/**
26978 * @publicApi
26979 */
26980class DebugNode {
26981 constructor(nativeNode) {
26982 this.nativeNode = nativeNode;
26983 }
26984 /**
26985 * The `DebugElement` parent. Will be `null` if this is the root element.
26986 */
26987 get parent() {
26988 const parent = this.nativeNode.parentNode;
26989 return parent ? new DebugElement(parent) : null;
26990 }
26991 /**
26992 * The host dependency injector. For example, the root element's component instance injector.
26993 */
26994 get injector() {
26995 return getInjector(this.nativeNode);
26996 }
26997 /**
26998 * The element's own component instance, if it has one.
26999 */
27000 get componentInstance() {
27001 const nativeElement = this.nativeNode;
27002 return nativeElement &&
27003 (getComponent$1(nativeElement) || getOwningComponent(nativeElement));
27004 }
27005 /**
27006 * An object that provides parent context for this element. Often an ancestor component instance
27007 * that governs this element.
27008 *
27009 * When an element is repeated within *ngFor, the context is an `NgForOf` whose `$implicit`
27010 * property is the value of the row instance value. For example, the `hero` in `*ngFor="let hero
27011 * of heroes"`.
27012 */
27013 get context() {
27014 return getComponent$1(this.nativeNode) || getContext(this.nativeNode);
27015 }
27016 /**
27017 * The callbacks attached to the component's @Output properties and/or the element's event
27018 * properties.
27019 */
27020 get listeners() {
27021 return getListeners(this.nativeNode).filter(listener => listener.type === 'dom');
27022 }
27023 /**
27024 * Dictionary of objects associated with template local variables (e.g. #foo), keyed by the local
27025 * variable name.
27026 */
27027 get references() {
27028 return getLocalRefs(this.nativeNode);
27029 }
27030 /**
27031 * This component's injector lookup tokens. Includes the component itself plus the tokens that the
27032 * component lists in its providers metadata.
27033 */
27034 get providerTokens() {
27035 return getInjectionTokens(this.nativeNode);
27036 }
27037}
27038/**
27039 * @publicApi
27040 *
27041 * @see [Component testing scenarios](guide/testing-components-scenarios)
27042 * @see [Basics of testing components](guide/testing-components-basics)
27043 * @see [Testing utility APIs](guide/testing-utility-apis)
27044 */
27045class DebugElement extends DebugNode {
27046 constructor(nativeNode) {
27047 ngDevMode && assertDomNode(nativeNode);
27048 super(nativeNode);
27049 }
27050 /**
27051 * The underlying DOM element at the root of the component.
27052 */
27053 get nativeElement() {
27054 return this.nativeNode.nodeType == Node.ELEMENT_NODE ? this.nativeNode : null;
27055 }
27056 /**
27057 * The element tag name, if it is an element.
27058 */
27059 get name() {
27060 const context = getLContext(this.nativeNode);
27061 if (context !== null) {
27062 const lView = context.lView;
27063 const tData = lView[TVIEW].data;
27064 const tNode = tData[context.nodeIndex];
27065 return tNode.value;
27066 }
27067 else {
27068 return this.nativeNode.nodeName;
27069 }
27070 }
27071 /**
27072 * Gets a map of property names to property values for an element.
27073 *
27074 * This map includes:
27075 * - Regular property bindings (e.g. `[id]="id"`)
27076 * - Host property bindings (e.g. `host: { '[id]': "id" }`)
27077 * - Interpolated property bindings (e.g. `id="{{ value }}")
27078 *
27079 * It does not include:
27080 * - input property bindings (e.g. `[myCustomInput]="value"`)
27081 * - attribute bindings (e.g. `[attr.role]="menu"`)
27082 */
27083 get properties() {
27084 const context = getLContext(this.nativeNode);
27085 if (context === null) {
27086 return {};
27087 }
27088 const lView = context.lView;
27089 const tData = lView[TVIEW].data;
27090 const tNode = tData[context.nodeIndex];
27091 const properties = {};
27092 // Collect properties from the DOM.
27093 copyDomProperties(this.nativeElement, properties);
27094 // Collect properties from the bindings. This is needed for animation renderer which has
27095 // synthetic properties which don't get reflected into the DOM.
27096 collectPropertyBindings(properties, tNode, lView, tData);
27097 return properties;
27098 }
27099 /**
27100 * A map of attribute names to attribute values for an element.
27101 */
27102 get attributes() {
27103 const attributes = {};
27104 const element = this.nativeElement;
27105 if (!element) {
27106 return attributes;
27107 }
27108 const context = getLContext(element);
27109 if (context === null) {
27110 return {};
27111 }
27112 const lView = context.lView;
27113 const tNodeAttrs = lView[TVIEW].data[context.nodeIndex].attrs;
27114 const lowercaseTNodeAttrs = [];
27115 // For debug nodes we take the element's attribute directly from the DOM since it allows us
27116 // to account for ones that weren't set via bindings (e.g. ViewEngine keeps track of the ones
27117 // that are set through `Renderer2`). The problem is that the browser will lowercase all names,
27118 // however since we have the attributes already on the TNode, we can preserve the case by going
27119 // through them once, adding them to the `attributes` map and putting their lower-cased name
27120 // into an array. Afterwards when we're going through the native DOM attributes, we can check
27121 // whether we haven't run into an attribute already through the TNode.
27122 if (tNodeAttrs) {
27123 let i = 0;
27124 while (i < tNodeAttrs.length) {
27125 const attrName = tNodeAttrs[i];
27126 // Stop as soon as we hit a marker. We only care about the regular attributes. Everything
27127 // else will be handled below when we read the final attributes off the DOM.
27128 if (typeof attrName !== 'string')
27129 break;
27130 const attrValue = tNodeAttrs[i + 1];
27131 attributes[attrName] = attrValue;
27132 lowercaseTNodeAttrs.push(attrName.toLowerCase());
27133 i += 2;
27134 }
27135 }
27136 const eAttrs = element.attributes;
27137 for (let i = 0; i < eAttrs.length; i++) {
27138 const attr = eAttrs[i];
27139 const lowercaseName = attr.name.toLowerCase();
27140 // Make sure that we don't assign the same attribute both in its
27141 // case-sensitive form and the lower-cased one from the browser.
27142 if (lowercaseTNodeAttrs.indexOf(lowercaseName) === -1) {
27143 // Save the lowercase name to align the behavior between browsers.
27144 // IE preserves the case, while all other browser convert it to lower case.
27145 attributes[lowercaseName] = attr.value;
27146 }
27147 }
27148 return attributes;
27149 }
27150 /**
27151 * The inline styles of the DOM element.
27152 *
27153 * Will be `null` if there is no `style` property on the underlying DOM element.
27154 *
27155 * @see [ElementCSSInlineStyle](https://developer.mozilla.org/en-US/docs/Web/API/ElementCSSInlineStyle/style)
27156 */
27157 get styles() {
27158 if (this.nativeElement && this.nativeElement.style) {
27159 return this.nativeElement.style;
27160 }
27161 return {};
27162 }
27163 /**
27164 * A map containing the class names on the element as keys.
27165 *
27166 * This map is derived from the `className` property of the DOM element.
27167 *
27168 * Note: The values of this object will always be `true`. The class key will not appear in the KV
27169 * object if it does not exist on the element.
27170 *
27171 * @see [Element.className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className)
27172 */
27173 get classes() {
27174 const result = {};
27175 const element = this.nativeElement;
27176 // SVG elements return an `SVGAnimatedString` instead of a plain string for the `className`.
27177 const className = element.className;
27178 const classes = typeof className !== 'string' ? className.baseVal.split(' ') : className.split(' ');
27179 classes.forEach((value) => result[value] = true);
27180 return result;
27181 }
27182 /**
27183 * The `childNodes` of the DOM element as a `DebugNode` array.
27184 *
27185 * @see [Node.childNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes)
27186 */
27187 get childNodes() {
27188 const childNodes = this.nativeNode.childNodes;
27189 const children = [];
27190 for (let i = 0; i < childNodes.length; i++) {
27191 const element = childNodes[i];
27192 children.push(getDebugNode(element));
27193 }
27194 return children;
27195 }
27196 /**
27197 * The immediate `DebugElement` children. Walk the tree by descending through `children`.
27198 */
27199 get children() {
27200 const nativeElement = this.nativeElement;
27201 if (!nativeElement)
27202 return [];
27203 const childNodes = nativeElement.children;
27204 const children = [];
27205 for (let i = 0; i < childNodes.length; i++) {
27206 const element = childNodes[i];
27207 children.push(getDebugNode(element));
27208 }
27209 return children;
27210 }
27211 /**
27212 * @returns the first `DebugElement` that matches the predicate at any depth in the subtree.
27213 */
27214 query(predicate) {
27215 const results = this.queryAll(predicate);
27216 return results[0] || null;
27217 }
27218 /**
27219 * @returns All `DebugElement` matches for the predicate at any depth in the subtree.
27220 */
27221 queryAll(predicate) {
27222 const matches = [];
27223 _queryAll(this, predicate, matches, true);
27224 return matches;
27225 }
27226 /**
27227 * @returns All `DebugNode` matches for the predicate at any depth in the subtree.
27228 */
27229 queryAllNodes(predicate) {
27230 const matches = [];
27231 _queryAll(this, predicate, matches, false);
27232 return matches;
27233 }
27234 /**
27235 * Triggers the event by its name if there is a corresponding listener in the element's
27236 * `listeners` collection.
27237 *
27238 * If the event lacks a listener or there's some other problem, consider
27239 * calling `nativeElement.dispatchEvent(eventObject)`.
27240 *
27241 * @param eventName The name of the event to trigger
27242 * @param eventObj The _event object_ expected by the handler
27243 *
27244 * @see [Testing components scenarios](guide/testing-components-scenarios#trigger-event-handler)
27245 */
27246 triggerEventHandler(eventName, eventObj) {
27247 const node = this.nativeNode;
27248 const invokedListeners = [];
27249 this.listeners.forEach(listener => {
27250 if (listener.name === eventName) {
27251 const callback = listener.callback;
27252 callback.call(node, eventObj);
27253 invokedListeners.push(callback);
27254 }
27255 });
27256 // We need to check whether `eventListeners` exists, because it's something
27257 // that Zone.js only adds to `EventTarget` in browser environments.
27258 if (typeof node.eventListeners === 'function') {
27259 // Note that in Ivy we wrap event listeners with a call to `event.preventDefault` in some
27260 // cases. We use '__ngUnwrap__' as a special token that gives us access to the actual event
27261 // listener.
27262 node.eventListeners(eventName).forEach((listener) => {
27263 // In order to ensure that we can detect the special __ngUnwrap__ token described above, we
27264 // use `toString` on the listener and see if it contains the token. We use this approach to
27265 // ensure that it still worked with compiled code since it cannot remove or rename string
27266 // literals. We also considered using a special function name (i.e. if(listener.name ===
27267 // special)) but that was more cumbersome and we were also concerned the compiled code could
27268 // strip the name, turning the condition in to ("" === "") and always returning true.
27269 if (listener.toString().indexOf('__ngUnwrap__') !== -1) {
27270 const unwrappedListener = listener('__ngUnwrap__');
27271 return invokedListeners.indexOf(unwrappedListener) === -1 &&
27272 unwrappedListener.call(node, eventObj);
27273 }
27274 });
27275 }
27276 }
27277}
27278function copyDomProperties(element, properties) {
27279 if (element) {
27280 // Skip own properties (as those are patched)
27281 let obj = Object.getPrototypeOf(element);
27282 const NodePrototype = Node.prototype;
27283 while (obj !== null && obj !== NodePrototype) {
27284 const descriptors = Object.getOwnPropertyDescriptors(obj);
27285 for (let key in descriptors) {
27286 if (!key.startsWith('__') && !key.startsWith('on')) {
27287 // don't include properties starting with `__` and `on`.
27288 // `__` are patched values which should not be included.
27289 // `on` are listeners which also should not be included.
27290 const value = element[key];
27291 if (isPrimitiveValue(value)) {
27292 properties[key] = value;
27293 }
27294 }
27295 }
27296 obj = Object.getPrototypeOf(obj);
27297 }
27298 }
27299}
27300function isPrimitiveValue(value) {
27301 return typeof value === 'string' || typeof value === 'boolean' || typeof value === 'number' ||
27302 value === null;
27303}
27304function _queryAll(parentElement, predicate, matches, elementsOnly) {
27305 const context = getLContext(parentElement.nativeNode);
27306 if (context !== null) {
27307 const parentTNode = context.lView[TVIEW].data[context.nodeIndex];
27308 _queryNodeChildren(parentTNode, context.lView, predicate, matches, elementsOnly, parentElement.nativeNode);
27309 }
27310 else {
27311 // If the context is null, then `parentElement` was either created with Renderer2 or native DOM
27312 // APIs.
27313 _queryNativeNodeDescendants(parentElement.nativeNode, predicate, matches, elementsOnly);
27314 }
27315}
27316/**
27317 * Recursively match the current TNode against the predicate, and goes on with the next ones.
27318 *
27319 * @param tNode the current TNode
27320 * @param lView the LView of this TNode
27321 * @param predicate the predicate to match
27322 * @param matches the list of positive matches
27323 * @param elementsOnly whether only elements should be searched
27324 * @param rootNativeNode the root native node on which predicate should not be matched
27325 */
27326function _queryNodeChildren(tNode, lView, predicate, matches, elementsOnly, rootNativeNode) {
27327 ngDevMode && assertTNodeForLView(tNode, lView);
27328 const nativeNode = getNativeByTNodeOrNull(tNode, lView);
27329 // For each type of TNode, specific logic is executed.
27330 if (tNode.type & (3 /* AnyRNode */ | 8 /* ElementContainer */)) {
27331 // Case 1: the TNode is an element
27332 // The native node has to be checked.
27333 _addQueryMatch(nativeNode, predicate, matches, elementsOnly, rootNativeNode);
27334 if (isComponentHost(tNode)) {
27335 // If the element is the host of a component, then all nodes in its view have to be processed.
27336 // Note: the component's content (tNode.child) will be processed from the insertion points.
27337 const componentView = getComponentLViewByIndex(tNode.index, lView);
27338 if (componentView && componentView[TVIEW].firstChild) {
27339 _queryNodeChildren(componentView[TVIEW].firstChild, componentView, predicate, matches, elementsOnly, rootNativeNode);
27340 }
27341 }
27342 else {
27343 if (tNode.child) {
27344 // Otherwise, its children have to be processed.
27345 _queryNodeChildren(tNode.child, lView, predicate, matches, elementsOnly, rootNativeNode);
27346 }
27347 // We also have to query the DOM directly in order to catch elements inserted through
27348 // Renderer2. Note that this is __not__ optimal, because we're walking similar trees multiple
27349 // times. ViewEngine could do it more efficiently, because all the insertions go through
27350 // Renderer2, however that's not the case in Ivy. This approach is being used because:
27351 // 1. Matching the ViewEngine behavior would mean potentially introducing a depedency
27352 // from `Renderer2` to Ivy which could bring Ivy code into ViewEngine.
27353 // 2. We would have to make `Renderer3` "know" about debug nodes.
27354 // 3. It allows us to capture nodes that were inserted directly via the DOM.
27355 nativeNode && _queryNativeNodeDescendants(nativeNode, predicate, matches, elementsOnly);
27356 }
27357 // In all cases, if a dynamic container exists for this node, each view inside it has to be
27358 // processed.
27359 const nodeOrContainer = lView[tNode.index];
27360 if (isLContainer(nodeOrContainer)) {
27361 _queryNodeChildrenInContainer(nodeOrContainer, predicate, matches, elementsOnly, rootNativeNode);
27362 }
27363 }
27364 else if (tNode.type & 4 /* Container */) {
27365 // Case 2: the TNode is a container
27366 // The native node has to be checked.
27367 const lContainer = lView[tNode.index];
27368 _addQueryMatch(lContainer[NATIVE], predicate, matches, elementsOnly, rootNativeNode);
27369 // Each view inside the container has to be processed.
27370 _queryNodeChildrenInContainer(lContainer, predicate, matches, elementsOnly, rootNativeNode);
27371 }
27372 else if (tNode.type & 16 /* Projection */) {
27373 // Case 3: the TNode is a projection insertion point (i.e. a <ng-content>).
27374 // The nodes projected at this location all need to be processed.
27375 const componentView = lView[DECLARATION_COMPONENT_VIEW];
27376 const componentHost = componentView[T_HOST];
27377 const head = componentHost.projection[tNode.projection];
27378 if (Array.isArray(head)) {
27379 for (let nativeNode of head) {
27380 _addQueryMatch(nativeNode, predicate, matches, elementsOnly, rootNativeNode);
27381 }
27382 }
27383 else if (head) {
27384 const nextLView = componentView[PARENT];
27385 const nextTNode = nextLView[TVIEW].data[head.index];
27386 _queryNodeChildren(nextTNode, nextLView, predicate, matches, elementsOnly, rootNativeNode);
27387 }
27388 }
27389 else if (tNode.child) {
27390 // Case 4: the TNode is a view.
27391 _queryNodeChildren(tNode.child, lView, predicate, matches, elementsOnly, rootNativeNode);
27392 }
27393 // We don't want to go to the next sibling of the root node.
27394 if (rootNativeNode !== nativeNode) {
27395 // To determine the next node to be processed, we need to use the next or the projectionNext
27396 // link, depending on whether the current node has been projected.
27397 const nextTNode = (tNode.flags & 4 /* isProjected */) ? tNode.projectionNext : tNode.next;
27398 if (nextTNode) {
27399 _queryNodeChildren(nextTNode, lView, predicate, matches, elementsOnly, rootNativeNode);
27400 }
27401 }
27402}
27403/**
27404 * Process all TNodes in a given container.
27405 *
27406 * @param lContainer the container to be processed
27407 * @param predicate the predicate to match
27408 * @param matches the list of positive matches
27409 * @param elementsOnly whether only elements should be searched
27410 * @param rootNativeNode the root native node on which predicate should not be matched
27411 */
27412function _queryNodeChildrenInContainer(lContainer, predicate, matches, elementsOnly, rootNativeNode) {
27413 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
27414 const childView = lContainer[i];
27415 const firstChild = childView[TVIEW].firstChild;
27416 if (firstChild) {
27417 _queryNodeChildren(firstChild, childView, predicate, matches, elementsOnly, rootNativeNode);
27418 }
27419 }
27420}
27421/**
27422 * Match the current native node against the predicate.
27423 *
27424 * @param nativeNode the current native node
27425 * @param predicate the predicate to match
27426 * @param matches the list of positive matches
27427 * @param elementsOnly whether only elements should be searched
27428 * @param rootNativeNode the root native node on which predicate should not be matched
27429 */
27430function _addQueryMatch(nativeNode, predicate, matches, elementsOnly, rootNativeNode) {
27431 if (rootNativeNode !== nativeNode) {
27432 const debugNode = getDebugNode(nativeNode);
27433 if (!debugNode) {
27434 return;
27435 }
27436 // Type of the "predicate and "matches" array are set based on the value of
27437 // the "elementsOnly" parameter. TypeScript is not able to properly infer these
27438 // types with generics, so we manually cast the parameters accordingly.
27439 if (elementsOnly && (debugNode instanceof DebugElement) && predicate(debugNode) &&
27440 matches.indexOf(debugNode) === -1) {
27441 matches.push(debugNode);
27442 }
27443 else if (!elementsOnly && predicate(debugNode) &&
27444 matches.indexOf(debugNode) === -1) {
27445 matches.push(debugNode);
27446 }
27447 }
27448}
27449/**
27450 * Match all the descendants of a DOM node against a predicate.
27451 *
27452 * @param nativeNode the current native node
27453 * @param predicate the predicate to match
27454 * @param matches the list where matches are stored
27455 * @param elementsOnly whether only elements should be searched
27456 */
27457function _queryNativeNodeDescendants(parentNode, predicate, matches, elementsOnly) {
27458 const nodes = parentNode.childNodes;
27459 const length = nodes.length;
27460 for (let i = 0; i < length; i++) {
27461 const node = nodes[i];
27462 const debugNode = getDebugNode(node);
27463 if (debugNode) {
27464 if (elementsOnly && (debugNode instanceof DebugElement) && predicate(debugNode) &&
27465 matches.indexOf(debugNode) === -1) {
27466 matches.push(debugNode);
27467 }
27468 else if (!elementsOnly && predicate(debugNode) &&
27469 matches.indexOf(debugNode) === -1) {
27470 matches.push(debugNode);
27471 }
27472 _queryNativeNodeDescendants(node, predicate, matches, elementsOnly);
27473 }
27474 }
27475}
27476/**
27477 * Iterates through the property bindings for a given node and generates
27478 * a map of property names to values. This map only contains property bindings
27479 * defined in templates, not in host bindings.
27480 */
27481function collectPropertyBindings(properties, tNode, lView, tData) {
27482 let bindingIndexes = tNode.propertyBindings;
27483 if (bindingIndexes !== null) {
27484 for (let i = 0; i < bindingIndexes.length; i++) {
27485 const bindingIndex = bindingIndexes[i];
27486 const propMetadata = tData[bindingIndex];
27487 const metadataParts = propMetadata.split(INTERPOLATION_DELIMITER);
27488 const propertyName = metadataParts[0];
27489 if (metadataParts.length > 1) {
27490 let value = metadataParts[1];
27491 for (let j = 1; j < metadataParts.length - 1; j++) {
27492 value += renderStringify(lView[bindingIndex + j - 1]) + metadataParts[j + 1];
27493 }
27494 properties[propertyName] = value;
27495 }
27496 else {
27497 properties[propertyName] = lView[bindingIndex];
27498 }
27499 }
27500 }
27501}
27502// Need to keep the nodes in a global Map so that multiple angular apps are supported.
27503const _nativeNodeToDebugNode = new Map();
27504const NG_DEBUG_PROPERTY = '__ng_debug__';
27505/**
27506 * @publicApi
27507 */
27508function getDebugNode(nativeNode) {
27509 if (nativeNode instanceof Node) {
27510 if (!(nativeNode.hasOwnProperty(NG_DEBUG_PROPERTY))) {
27511 nativeNode[NG_DEBUG_PROPERTY] = nativeNode.nodeType == Node.ELEMENT_NODE ?
27512 new DebugElement(nativeNode) :
27513 new DebugNode(nativeNode);
27514 }
27515 return nativeNode[NG_DEBUG_PROPERTY];
27516 }
27517 return null;
27518}
27519// TODO: cleanup all references to this function and remove it.
27520function getDebugNodeR2(_nativeNode) {
27521 return null;
27522}
27523function getAllDebugNodes() {
27524 return Array.from(_nativeNodeToDebugNode.values());
27525}
27526function indexDebugNode(node) {
27527 _nativeNodeToDebugNode.set(node.nativeNode, node);
27528}
27529function removeDebugNodeFromIndex(node) {
27530 _nativeNodeToDebugNode.delete(node.nativeNode);
27531}
27532
27533/**
27534 * @license
27535 * Copyright Google LLC All Rights Reserved.
27536 *
27537 * Use of this source code is governed by an MIT-style license that can be
27538 * found in the LICENSE file at https://angular.io/license
27539 */
27540class DefaultIterableDifferFactory {
27541 constructor() { }
27542 supports(obj) {
27543 return isListLikeIterable(obj);
27544 }
27545 create(trackByFn) {
27546 return new DefaultIterableDiffer(trackByFn);
27547 }
27548}
27549const trackByIdentity = (index, item) => item;
27550/**
27551 * @deprecated v4.0.0 - Should not be part of public API.
27552 * @publicApi
27553 */
27554class DefaultIterableDiffer {
27555 constructor(trackByFn) {
27556 this.length = 0;
27557 // Keeps track of the used records at any point in time (during & across `_check()` calls)
27558 this._linkedRecords = null;
27559 // Keeps track of the removed records at any point in time during `_check()` calls.
27560 this._unlinkedRecords = null;
27561 this._previousItHead = null;
27562 this._itHead = null;
27563 this._itTail = null;
27564 this._additionsHead = null;
27565 this._additionsTail = null;
27566 this._movesHead = null;
27567 this._movesTail = null;
27568 this._removalsHead = null;
27569 this._removalsTail = null;
27570 // Keeps track of records where custom track by is the same, but item identity has changed
27571 this._identityChangesHead = null;
27572 this._identityChangesTail = null;
27573 this._trackByFn = trackByFn || trackByIdentity;
27574 }
27575 forEachItem(fn) {
27576 let record;
27577 for (record = this._itHead; record !== null; record = record._next) {
27578 fn(record);
27579 }
27580 }
27581 forEachOperation(fn) {
27582 let nextIt = this._itHead;
27583 let nextRemove = this._removalsHead;
27584 let addRemoveOffset = 0;
27585 let moveOffsets = null;
27586 while (nextIt || nextRemove) {
27587 // Figure out which is the next record to process
27588 // Order: remove, add, move
27589 const record = !nextRemove ||
27590 nextIt &&
27591 nextIt.currentIndex <
27592 getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
27593 nextIt :
27594 nextRemove;
27595 const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets);
27596 const currentIndex = record.currentIndex;
27597 // consume the item, and adjust the addRemoveOffset and update moveDistance if necessary
27598 if (record === nextRemove) {
27599 addRemoveOffset--;
27600 nextRemove = nextRemove._nextRemoved;
27601 }
27602 else {
27603 nextIt = nextIt._next;
27604 if (record.previousIndex == null) {
27605 addRemoveOffset++;
27606 }
27607 else {
27608 // INVARIANT: currentIndex < previousIndex
27609 if (!moveOffsets)
27610 moveOffsets = [];
27611 const localMovePreviousIndex = adjPreviousIndex - addRemoveOffset;
27612 const localCurrentIndex = currentIndex - addRemoveOffset;
27613 if (localMovePreviousIndex != localCurrentIndex) {
27614 for (let i = 0; i < localMovePreviousIndex; i++) {
27615 const offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0);
27616 const index = offset + i;
27617 if (localCurrentIndex <= index && index < localMovePreviousIndex) {
27618 moveOffsets[i] = offset + 1;
27619 }
27620 }
27621 const previousIndex = record.previousIndex;
27622 moveOffsets[previousIndex] = localCurrentIndex - localMovePreviousIndex;
27623 }
27624 }
27625 }
27626 if (adjPreviousIndex !== currentIndex) {
27627 fn(record, adjPreviousIndex, currentIndex);
27628 }
27629 }
27630 }
27631 forEachPreviousItem(fn) {
27632 let record;
27633 for (record = this._previousItHead; record !== null; record = record._nextPrevious) {
27634 fn(record);
27635 }
27636 }
27637 forEachAddedItem(fn) {
27638 let record;
27639 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
27640 fn(record);
27641 }
27642 }
27643 forEachMovedItem(fn) {
27644 let record;
27645 for (record = this._movesHead; record !== null; record = record._nextMoved) {
27646 fn(record);
27647 }
27648 }
27649 forEachRemovedItem(fn) {
27650 let record;
27651 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
27652 fn(record);
27653 }
27654 }
27655 forEachIdentityChange(fn) {
27656 let record;
27657 for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) {
27658 fn(record);
27659 }
27660 }
27661 diff(collection) {
27662 if (collection == null)
27663 collection = [];
27664 if (!isListLikeIterable(collection)) {
27665 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
27666 `Error trying to diff '${stringify(collection)}'. Only arrays and iterables are allowed` :
27667 '';
27668 throw new RuntimeError(900 /* INVALID_DIFFER_INPUT */, errorMessage);
27669 }
27670 if (this.check(collection)) {
27671 return this;
27672 }
27673 else {
27674 return null;
27675 }
27676 }
27677 onDestroy() { }
27678 check(collection) {
27679 this._reset();
27680 let record = this._itHead;
27681 let mayBeDirty = false;
27682 let index;
27683 let item;
27684 let itemTrackBy;
27685 if (Array.isArray(collection)) {
27686 this.length = collection.length;
27687 for (let index = 0; index < this.length; index++) {
27688 item = collection[index];
27689 itemTrackBy = this._trackByFn(index, item);
27690 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
27691 record = this._mismatch(record, item, itemTrackBy, index);
27692 mayBeDirty = true;
27693 }
27694 else {
27695 if (mayBeDirty) {
27696 // TODO(misko): can we limit this to duplicates only?
27697 record = this._verifyReinsertion(record, item, itemTrackBy, index);
27698 }
27699 if (!Object.is(record.item, item))
27700 this._addIdentityChange(record, item);
27701 }
27702 record = record._next;
27703 }
27704 }
27705 else {
27706 index = 0;
27707 iterateListLike(collection, (item) => {
27708 itemTrackBy = this._trackByFn(index, item);
27709 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
27710 record = this._mismatch(record, item, itemTrackBy, index);
27711 mayBeDirty = true;
27712 }
27713 else {
27714 if (mayBeDirty) {
27715 // TODO(misko): can we limit this to duplicates only?
27716 record = this._verifyReinsertion(record, item, itemTrackBy, index);
27717 }
27718 if (!Object.is(record.item, item))
27719 this._addIdentityChange(record, item);
27720 }
27721 record = record._next;
27722 index++;
27723 });
27724 this.length = index;
27725 }
27726 this._truncate(record);
27727 this.collection = collection;
27728 return this.isDirty;
27729 }
27730 /* CollectionChanges is considered dirty if it has any additions, moves, removals, or identity
27731 * changes.
27732 */
27733 get isDirty() {
27734 return this._additionsHead !== null || this._movesHead !== null ||
27735 this._removalsHead !== null || this._identityChangesHead !== null;
27736 }
27737 /**
27738 * Reset the state of the change objects to show no changes. This means set previousKey to
27739 * currentKey, and clear all of the queues (additions, moves, removals).
27740 * Set the previousIndexes of moved and added items to their currentIndexes
27741 * Reset the list of additions, moves and removals
27742 *
27743 * @internal
27744 */
27745 _reset() {
27746 if (this.isDirty) {
27747 let record;
27748 for (record = this._previousItHead = this._itHead; record !== null; record = record._next) {
27749 record._nextPrevious = record._next;
27750 }
27751 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
27752 record.previousIndex = record.currentIndex;
27753 }
27754 this._additionsHead = this._additionsTail = null;
27755 for (record = this._movesHead; record !== null; record = record._nextMoved) {
27756 record.previousIndex = record.currentIndex;
27757 }
27758 this._movesHead = this._movesTail = null;
27759 this._removalsHead = this._removalsTail = null;
27760 this._identityChangesHead = this._identityChangesTail = null;
27761 // TODO(vicb): when assert gets supported
27762 // assert(!this.isDirty);
27763 }
27764 }
27765 /**
27766 * This is the core function which handles differences between collections.
27767 *
27768 * - `record` is the record which we saw at this position last time. If null then it is a new
27769 * item.
27770 * - `item` is the current item in the collection
27771 * - `index` is the position of the item in the collection
27772 *
27773 * @internal
27774 */
27775 _mismatch(record, item, itemTrackBy, index) {
27776 // The previous record after which we will append the current one.
27777 let previousRecord;
27778 if (record === null) {
27779 previousRecord = this._itTail;
27780 }
27781 else {
27782 previousRecord = record._prev;
27783 // Remove the record from the collection since we know it does not match the item.
27784 this._remove(record);
27785 }
27786 // See if we have evicted the item, which used to be at some anterior position of _itHead list.
27787 record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
27788 if (record !== null) {
27789 // It is an item which we have evicted earlier: reinsert it back into the list.
27790 // But first we need to check if identity changed, so we can update in view if necessary.
27791 if (!Object.is(record.item, item))
27792 this._addIdentityChange(record, item);
27793 this._reinsertAfter(record, previousRecord, index);
27794 }
27795 else {
27796 // Attempt to see if the item is at some posterior position of _itHead list.
27797 record = this._linkedRecords === null ? null : this._linkedRecords.get(itemTrackBy, index);
27798 if (record !== null) {
27799 // We have the item in _itHead at/after `index` position. We need to move it forward in the
27800 // collection.
27801 // But first we need to check if identity changed, so we can update in view if necessary.
27802 if (!Object.is(record.item, item))
27803 this._addIdentityChange(record, item);
27804 this._moveAfter(record, previousRecord, index);
27805 }
27806 else {
27807 // It is a new item: add it.
27808 record =
27809 this._addAfter(new IterableChangeRecord_(item, itemTrackBy), previousRecord, index);
27810 }
27811 }
27812 return record;
27813 }
27814 /**
27815 * This check is only needed if an array contains duplicates. (Short circuit of nothing dirty)
27816 *
27817 * Use case: `[a, a]` => `[b, a, a]`
27818 *
27819 * If we did not have this check then the insertion of `b` would:
27820 * 1) evict first `a`
27821 * 2) insert `b` at `0` index.
27822 * 3) leave `a` at index `1` as is. <-- this is wrong!
27823 * 3) reinsert `a` at index 2. <-- this is wrong!
27824 *
27825 * The correct behavior is:
27826 * 1) evict first `a`
27827 * 2) insert `b` at `0` index.
27828 * 3) reinsert `a` at index 1.
27829 * 3) move `a` at from `1` to `2`.
27830 *
27831 *
27832 * Double check that we have not evicted a duplicate item. We need to check if the item type may
27833 * have already been removed:
27834 * The insertion of b will evict the first 'a'. If we don't reinsert it now it will be reinserted
27835 * at the end. Which will show up as the two 'a's switching position. This is incorrect, since a
27836 * better way to think of it is as insert of 'b' rather then switch 'a' with 'b' and then add 'a'
27837 * at the end.
27838 *
27839 * @internal
27840 */
27841 _verifyReinsertion(record, item, itemTrackBy, index) {
27842 let reinsertRecord = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
27843 if (reinsertRecord !== null) {
27844 record = this._reinsertAfter(reinsertRecord, record._prev, index);
27845 }
27846 else if (record.currentIndex != index) {
27847 record.currentIndex = index;
27848 this._addToMoves(record, index);
27849 }
27850 return record;
27851 }
27852 /**
27853 * Get rid of any excess {@link IterableChangeRecord_}s from the previous collection
27854 *
27855 * - `record` The first excess {@link IterableChangeRecord_}.
27856 *
27857 * @internal
27858 */
27859 _truncate(record) {
27860 // Anything after that needs to be removed;
27861 while (record !== null) {
27862 const nextRecord = record._next;
27863 this._addToRemovals(this._unlink(record));
27864 record = nextRecord;
27865 }
27866 if (this._unlinkedRecords !== null) {
27867 this._unlinkedRecords.clear();
27868 }
27869 if (this._additionsTail !== null) {
27870 this._additionsTail._nextAdded = null;
27871 }
27872 if (this._movesTail !== null) {
27873 this._movesTail._nextMoved = null;
27874 }
27875 if (this._itTail !== null) {
27876 this._itTail._next = null;
27877 }
27878 if (this._removalsTail !== null) {
27879 this._removalsTail._nextRemoved = null;
27880 }
27881 if (this._identityChangesTail !== null) {
27882 this._identityChangesTail._nextIdentityChange = null;
27883 }
27884 }
27885 /** @internal */
27886 _reinsertAfter(record, prevRecord, index) {
27887 if (this._unlinkedRecords !== null) {
27888 this._unlinkedRecords.remove(record);
27889 }
27890 const prev = record._prevRemoved;
27891 const next = record._nextRemoved;
27892 if (prev === null) {
27893 this._removalsHead = next;
27894 }
27895 else {
27896 prev._nextRemoved = next;
27897 }
27898 if (next === null) {
27899 this._removalsTail = prev;
27900 }
27901 else {
27902 next._prevRemoved = prev;
27903 }
27904 this._insertAfter(record, prevRecord, index);
27905 this._addToMoves(record, index);
27906 return record;
27907 }
27908 /** @internal */
27909 _moveAfter(record, prevRecord, index) {
27910 this._unlink(record);
27911 this._insertAfter(record, prevRecord, index);
27912 this._addToMoves(record, index);
27913 return record;
27914 }
27915 /** @internal */
27916 _addAfter(record, prevRecord, index) {
27917 this._insertAfter(record, prevRecord, index);
27918 if (this._additionsTail === null) {
27919 // TODO(vicb):
27920 // assert(this._additionsHead === null);
27921 this._additionsTail = this._additionsHead = record;
27922 }
27923 else {
27924 // TODO(vicb):
27925 // assert(_additionsTail._nextAdded === null);
27926 // assert(record._nextAdded === null);
27927 this._additionsTail = this._additionsTail._nextAdded = record;
27928 }
27929 return record;
27930 }
27931 /** @internal */
27932 _insertAfter(record, prevRecord, index) {
27933 // TODO(vicb):
27934 // assert(record != prevRecord);
27935 // assert(record._next === null);
27936 // assert(record._prev === null);
27937 const next = prevRecord === null ? this._itHead : prevRecord._next;
27938 // TODO(vicb):
27939 // assert(next != record);
27940 // assert(prevRecord != record);
27941 record._next = next;
27942 record._prev = prevRecord;
27943 if (next === null) {
27944 this._itTail = record;
27945 }
27946 else {
27947 next._prev = record;
27948 }
27949 if (prevRecord === null) {
27950 this._itHead = record;
27951 }
27952 else {
27953 prevRecord._next = record;
27954 }
27955 if (this._linkedRecords === null) {
27956 this._linkedRecords = new _DuplicateMap();
27957 }
27958 this._linkedRecords.put(record);
27959 record.currentIndex = index;
27960 return record;
27961 }
27962 /** @internal */
27963 _remove(record) {
27964 return this._addToRemovals(this._unlink(record));
27965 }
27966 /** @internal */
27967 _unlink(record) {
27968 if (this._linkedRecords !== null) {
27969 this._linkedRecords.remove(record);
27970 }
27971 const prev = record._prev;
27972 const next = record._next;
27973 // TODO(vicb):
27974 // assert((record._prev = null) === null);
27975 // assert((record._next = null) === null);
27976 if (prev === null) {
27977 this._itHead = next;
27978 }
27979 else {
27980 prev._next = next;
27981 }
27982 if (next === null) {
27983 this._itTail = prev;
27984 }
27985 else {
27986 next._prev = prev;
27987 }
27988 return record;
27989 }
27990 /** @internal */
27991 _addToMoves(record, toIndex) {
27992 // TODO(vicb):
27993 // assert(record._nextMoved === null);
27994 if (record.previousIndex === toIndex) {
27995 return record;
27996 }
27997 if (this._movesTail === null) {
27998 // TODO(vicb):
27999 // assert(_movesHead === null);
28000 this._movesTail = this._movesHead = record;
28001 }
28002 else {
28003 // TODO(vicb):
28004 // assert(_movesTail._nextMoved === null);
28005 this._movesTail = this._movesTail._nextMoved = record;
28006 }
28007 return record;
28008 }
28009 _addToRemovals(record) {
28010 if (this._unlinkedRecords === null) {
28011 this._unlinkedRecords = new _DuplicateMap();
28012 }
28013 this._unlinkedRecords.put(record);
28014 record.currentIndex = null;
28015 record._nextRemoved = null;
28016 if (this._removalsTail === null) {
28017 // TODO(vicb):
28018 // assert(_removalsHead === null);
28019 this._removalsTail = this._removalsHead = record;
28020 record._prevRemoved = null;
28021 }
28022 else {
28023 // TODO(vicb):
28024 // assert(_removalsTail._nextRemoved === null);
28025 // assert(record._nextRemoved === null);
28026 record._prevRemoved = this._removalsTail;
28027 this._removalsTail = this._removalsTail._nextRemoved = record;
28028 }
28029 return record;
28030 }
28031 /** @internal */
28032 _addIdentityChange(record, item) {
28033 record.item = item;
28034 if (this._identityChangesTail === null) {
28035 this._identityChangesTail = this._identityChangesHead = record;
28036 }
28037 else {
28038 this._identityChangesTail = this._identityChangesTail._nextIdentityChange = record;
28039 }
28040 return record;
28041 }
28042}
28043class IterableChangeRecord_ {
28044 constructor(item, trackById) {
28045 this.item = item;
28046 this.trackById = trackById;
28047 this.currentIndex = null;
28048 this.previousIndex = null;
28049 /** @internal */
28050 this._nextPrevious = null;
28051 /** @internal */
28052 this._prev = null;
28053 /** @internal */
28054 this._next = null;
28055 /** @internal */
28056 this._prevDup = null;
28057 /** @internal */
28058 this._nextDup = null;
28059 /** @internal */
28060 this._prevRemoved = null;
28061 /** @internal */
28062 this._nextRemoved = null;
28063 /** @internal */
28064 this._nextAdded = null;
28065 /** @internal */
28066 this._nextMoved = null;
28067 /** @internal */
28068 this._nextIdentityChange = null;
28069 }
28070}
28071// A linked list of IterableChangeRecords with the same IterableChangeRecord_.item
28072class _DuplicateItemRecordList {
28073 constructor() {
28074 /** @internal */
28075 this._head = null;
28076 /** @internal */
28077 this._tail = null;
28078 }
28079 /**
28080 * Append the record to the list of duplicates.
28081 *
28082 * Note: by design all records in the list of duplicates hold the same value in record.item.
28083 */
28084 add(record) {
28085 if (this._head === null) {
28086 this._head = this._tail = record;
28087 record._nextDup = null;
28088 record._prevDup = null;
28089 }
28090 else {
28091 // TODO(vicb):
28092 // assert(record.item == _head.item ||
28093 // record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN);
28094 this._tail._nextDup = record;
28095 record._prevDup = this._tail;
28096 record._nextDup = null;
28097 this._tail = record;
28098 }
28099 }
28100 // Returns a IterableChangeRecord_ having IterableChangeRecord_.trackById == trackById and
28101 // IterableChangeRecord_.currentIndex >= atOrAfterIndex
28102 get(trackById, atOrAfterIndex) {
28103 let record;
28104 for (record = this._head; record !== null; record = record._nextDup) {
28105 if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex) &&
28106 Object.is(record.trackById, trackById)) {
28107 return record;
28108 }
28109 }
28110 return null;
28111 }
28112 /**
28113 * Remove one {@link IterableChangeRecord_} from the list of duplicates.
28114 *
28115 * Returns whether the list of duplicates is empty.
28116 */
28117 remove(record) {
28118 // TODO(vicb):
28119 // assert(() {
28120 // // verify that the record being removed is in the list.
28121 // for (IterableChangeRecord_ cursor = _head; cursor != null; cursor = cursor._nextDup) {
28122 // if (identical(cursor, record)) return true;
28123 // }
28124 // return false;
28125 //});
28126 const prev = record._prevDup;
28127 const next = record._nextDup;
28128 if (prev === null) {
28129 this._head = next;
28130 }
28131 else {
28132 prev._nextDup = next;
28133 }
28134 if (next === null) {
28135 this._tail = prev;
28136 }
28137 else {
28138 next._prevDup = prev;
28139 }
28140 return this._head === null;
28141 }
28142}
28143class _DuplicateMap {
28144 constructor() {
28145 this.map = new Map();
28146 }
28147 put(record) {
28148 const key = record.trackById;
28149 let duplicates = this.map.get(key);
28150 if (!duplicates) {
28151 duplicates = new _DuplicateItemRecordList();
28152 this.map.set(key, duplicates);
28153 }
28154 duplicates.add(record);
28155 }
28156 /**
28157 * Retrieve the `value` using key. Because the IterableChangeRecord_ value may be one which we
28158 * have already iterated over, we use the `atOrAfterIndex` to pretend it is not there.
28159 *
28160 * Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we
28161 * have any more `a`s needs to return the second `a`.
28162 */
28163 get(trackById, atOrAfterIndex) {
28164 const key = trackById;
28165 const recordList = this.map.get(key);
28166 return recordList ? recordList.get(trackById, atOrAfterIndex) : null;
28167 }
28168 /**
28169 * Removes a {@link IterableChangeRecord_} from the list of duplicates.
28170 *
28171 * The list of duplicates also is removed from the map if it gets empty.
28172 */
28173 remove(record) {
28174 const key = record.trackById;
28175 const recordList = this.map.get(key);
28176 // Remove the list of duplicates when it gets empty
28177 if (recordList.remove(record)) {
28178 this.map.delete(key);
28179 }
28180 return record;
28181 }
28182 get isEmpty() {
28183 return this.map.size === 0;
28184 }
28185 clear() {
28186 this.map.clear();
28187 }
28188}
28189function getPreviousIndex(item, addRemoveOffset, moveOffsets) {
28190 const previousIndex = item.previousIndex;
28191 if (previousIndex === null)
28192 return previousIndex;
28193 let moveOffset = 0;
28194 if (moveOffsets && previousIndex < moveOffsets.length) {
28195 moveOffset = moveOffsets[previousIndex];
28196 }
28197 return previousIndex + addRemoveOffset + moveOffset;
28198}
28199
28200/**
28201 * @license
28202 * Copyright Google LLC All Rights Reserved.
28203 *
28204 * Use of this source code is governed by an MIT-style license that can be
28205 * found in the LICENSE file at https://angular.io/license
28206 */
28207class DefaultKeyValueDifferFactory {
28208 constructor() { }
28209 supports(obj) {
28210 return obj instanceof Map || isJsObject(obj);
28211 }
28212 create() {
28213 return new DefaultKeyValueDiffer();
28214 }
28215}
28216class DefaultKeyValueDiffer {
28217 constructor() {
28218 this._records = new Map();
28219 this._mapHead = null;
28220 // _appendAfter is used in the check loop
28221 this._appendAfter = null;
28222 this._previousMapHead = null;
28223 this._changesHead = null;
28224 this._changesTail = null;
28225 this._additionsHead = null;
28226 this._additionsTail = null;
28227 this._removalsHead = null;
28228 this._removalsTail = null;
28229 }
28230 get isDirty() {
28231 return this._additionsHead !== null || this._changesHead !== null ||
28232 this._removalsHead !== null;
28233 }
28234 forEachItem(fn) {
28235 let record;
28236 for (record = this._mapHead; record !== null; record = record._next) {
28237 fn(record);
28238 }
28239 }
28240 forEachPreviousItem(fn) {
28241 let record;
28242 for (record = this._previousMapHead; record !== null; record = record._nextPrevious) {
28243 fn(record);
28244 }
28245 }
28246 forEachChangedItem(fn) {
28247 let record;
28248 for (record = this._changesHead; record !== null; record = record._nextChanged) {
28249 fn(record);
28250 }
28251 }
28252 forEachAddedItem(fn) {
28253 let record;
28254 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
28255 fn(record);
28256 }
28257 }
28258 forEachRemovedItem(fn) {
28259 let record;
28260 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
28261 fn(record);
28262 }
28263 }
28264 diff(map) {
28265 if (!map) {
28266 map = new Map();
28267 }
28268 else if (!(map instanceof Map || isJsObject(map))) {
28269 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
28270 `Error trying to diff '${stringify(map)}'. Only maps and objects are allowed` :
28271 '';
28272 throw new RuntimeError(900 /* INVALID_DIFFER_INPUT */, errorMessage);
28273 }
28274 return this.check(map) ? this : null;
28275 }
28276 onDestroy() { }
28277 /**
28278 * Check the current state of the map vs the previous.
28279 * The algorithm is optimised for when the keys do no change.
28280 */
28281 check(map) {
28282 this._reset();
28283 let insertBefore = this._mapHead;
28284 this._appendAfter = null;
28285 this._forEach(map, (value, key) => {
28286 if (insertBefore && insertBefore.key === key) {
28287 this._maybeAddToChanges(insertBefore, value);
28288 this._appendAfter = insertBefore;
28289 insertBefore = insertBefore._next;
28290 }
28291 else {
28292 const record = this._getOrCreateRecordForKey(key, value);
28293 insertBefore = this._insertBeforeOrAppend(insertBefore, record);
28294 }
28295 });
28296 // Items remaining at the end of the list have been deleted
28297 if (insertBefore) {
28298 if (insertBefore._prev) {
28299 insertBefore._prev._next = null;
28300 }
28301 this._removalsHead = insertBefore;
28302 for (let record = insertBefore; record !== null; record = record._nextRemoved) {
28303 if (record === this._mapHead) {
28304 this._mapHead = null;
28305 }
28306 this._records.delete(record.key);
28307 record._nextRemoved = record._next;
28308 record.previousValue = record.currentValue;
28309 record.currentValue = null;
28310 record._prev = null;
28311 record._next = null;
28312 }
28313 }
28314 // Make sure tails have no next records from previous runs
28315 if (this._changesTail)
28316 this._changesTail._nextChanged = null;
28317 if (this._additionsTail)
28318 this._additionsTail._nextAdded = null;
28319 return this.isDirty;
28320 }
28321 /**
28322 * Inserts a record before `before` or append at the end of the list when `before` is null.
28323 *
28324 * Notes:
28325 * - This method appends at `this._appendAfter`,
28326 * - This method updates `this._appendAfter`,
28327 * - The return value is the new value for the insertion pointer.
28328 */
28329 _insertBeforeOrAppend(before, record) {
28330 if (before) {
28331 const prev = before._prev;
28332 record._next = before;
28333 record._prev = prev;
28334 before._prev = record;
28335 if (prev) {
28336 prev._next = record;
28337 }
28338 if (before === this._mapHead) {
28339 this._mapHead = record;
28340 }
28341 this._appendAfter = before;
28342 return before;
28343 }
28344 if (this._appendAfter) {
28345 this._appendAfter._next = record;
28346 record._prev = this._appendAfter;
28347 }
28348 else {
28349 this._mapHead = record;
28350 }
28351 this._appendAfter = record;
28352 return null;
28353 }
28354 _getOrCreateRecordForKey(key, value) {
28355 if (this._records.has(key)) {
28356 const record = this._records.get(key);
28357 this._maybeAddToChanges(record, value);
28358 const prev = record._prev;
28359 const next = record._next;
28360 if (prev) {
28361 prev._next = next;
28362 }
28363 if (next) {
28364 next._prev = prev;
28365 }
28366 record._next = null;
28367 record._prev = null;
28368 return record;
28369 }
28370 const record = new KeyValueChangeRecord_(key);
28371 this._records.set(key, record);
28372 record.currentValue = value;
28373 this._addToAdditions(record);
28374 return record;
28375 }
28376 /** @internal */
28377 _reset() {
28378 if (this.isDirty) {
28379 let record;
28380 // let `_previousMapHead` contain the state of the map before the changes
28381 this._previousMapHead = this._mapHead;
28382 for (record = this._previousMapHead; record !== null; record = record._next) {
28383 record._nextPrevious = record._next;
28384 }
28385 // Update `record.previousValue` with the value of the item before the changes
28386 // We need to update all changed items (that's those which have been added and changed)
28387 for (record = this._changesHead; record !== null; record = record._nextChanged) {
28388 record.previousValue = record.currentValue;
28389 }
28390 for (record = this._additionsHead; record != null; record = record._nextAdded) {
28391 record.previousValue = record.currentValue;
28392 }
28393 this._changesHead = this._changesTail = null;
28394 this._additionsHead = this._additionsTail = null;
28395 this._removalsHead = null;
28396 }
28397 }
28398 // Add the record or a given key to the list of changes only when the value has actually changed
28399 _maybeAddToChanges(record, newValue) {
28400 if (!Object.is(newValue, record.currentValue)) {
28401 record.previousValue = record.currentValue;
28402 record.currentValue = newValue;
28403 this._addToChanges(record);
28404 }
28405 }
28406 _addToAdditions(record) {
28407 if (this._additionsHead === null) {
28408 this._additionsHead = this._additionsTail = record;
28409 }
28410 else {
28411 this._additionsTail._nextAdded = record;
28412 this._additionsTail = record;
28413 }
28414 }
28415 _addToChanges(record) {
28416 if (this._changesHead === null) {
28417 this._changesHead = this._changesTail = record;
28418 }
28419 else {
28420 this._changesTail._nextChanged = record;
28421 this._changesTail = record;
28422 }
28423 }
28424 /** @internal */
28425 _forEach(obj, fn) {
28426 if (obj instanceof Map) {
28427 obj.forEach(fn);
28428 }
28429 else {
28430 Object.keys(obj).forEach(k => fn(obj[k], k));
28431 }
28432 }
28433}
28434class KeyValueChangeRecord_ {
28435 constructor(key) {
28436 this.key = key;
28437 this.previousValue = null;
28438 this.currentValue = null;
28439 /** @internal */
28440 this._nextPrevious = null;
28441 /** @internal */
28442 this._next = null;
28443 /** @internal */
28444 this._prev = null;
28445 /** @internal */
28446 this._nextAdded = null;
28447 /** @internal */
28448 this._nextRemoved = null;
28449 /** @internal */
28450 this._nextChanged = null;
28451 }
28452}
28453
28454/**
28455 * @license
28456 * Copyright Google LLC All Rights Reserved.
28457 *
28458 * Use of this source code is governed by an MIT-style license that can be
28459 * found in the LICENSE file at https://angular.io/license
28460 */
28461function defaultIterableDiffersFactory() {
28462 return new IterableDiffers([new DefaultIterableDifferFactory()]);
28463}
28464/**
28465 * A repository of different iterable diffing strategies used by NgFor, NgClass, and others.
28466 *
28467 * @publicApi
28468 */
28469class IterableDiffers {
28470 constructor(factories) {
28471 this.factories = factories;
28472 }
28473 static create(factories, parent) {
28474 if (parent != null) {
28475 const copied = parent.factories.slice();
28476 factories = factories.concat(copied);
28477 }
28478 return new IterableDiffers(factories);
28479 }
28480 /**
28481 * Takes an array of {@link IterableDifferFactory} and returns a provider used to extend the
28482 * inherited {@link IterableDiffers} instance with the provided factories and return a new
28483 * {@link IterableDiffers} instance.
28484 *
28485 * @usageNotes
28486 * ### Example
28487 *
28488 * The following example shows how to extend an existing list of factories,
28489 * which will only be applied to the injector for this component and its children.
28490 * This step is all that's required to make a new {@link IterableDiffer} available.
28491 *
28492 * ```
28493 * @Component({
28494 * viewProviders: [
28495 * IterableDiffers.extend([new ImmutableListDiffer()])
28496 * ]
28497 * })
28498 * ```
28499 */
28500 static extend(factories) {
28501 return {
28502 provide: IterableDiffers,
28503 useFactory: (parent) => {
28504 // if parent is null, it means that we are in the root injector and we have just overridden
28505 // the default injection mechanism for IterableDiffers, in such a case just assume
28506 // `defaultIterableDiffersFactory`.
28507 return IterableDiffers.create(factories, parent || defaultIterableDiffersFactory());
28508 },
28509 // Dependency technically isn't optional, but we can provide a better error message this way.
28510 deps: [[IterableDiffers, new SkipSelf(), new Optional()]]
28511 };
28512 }
28513 find(iterable) {
28514 const factory = this.factories.find(f => f.supports(iterable));
28515 if (factory != null) {
28516 return factory;
28517 }
28518 else {
28519 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
28520 `Cannot find a differ supporting object '${iterable}' of type '${getTypeNameForDebugging(iterable)}'` :
28521 '';
28522 throw new RuntimeError(901 /* NO_SUPPORTING_DIFFER_FACTORY */, errorMessage);
28523 }
28524 }
28525}
28526/** @nocollapse */
28527IterableDiffers.ɵprov = ɵɵdefineInjectable({ token: IterableDiffers, providedIn: 'root', factory: defaultIterableDiffersFactory });
28528function getTypeNameForDebugging(type) {
28529 return type['name'] || typeof type;
28530}
28531
28532/**
28533 * @license
28534 * Copyright Google LLC All Rights Reserved.
28535 *
28536 * Use of this source code is governed by an MIT-style license that can be
28537 * found in the LICENSE file at https://angular.io/license
28538 */
28539function defaultKeyValueDiffersFactory() {
28540 return new KeyValueDiffers([new DefaultKeyValueDifferFactory()]);
28541}
28542/**
28543 * A repository of different Map diffing strategies used by NgClass, NgStyle, and others.
28544 *
28545 * @publicApi
28546 */
28547class KeyValueDiffers {
28548 constructor(factories) {
28549 this.factories = factories;
28550 }
28551 static create(factories, parent) {
28552 if (parent) {
28553 const copied = parent.factories.slice();
28554 factories = factories.concat(copied);
28555 }
28556 return new KeyValueDiffers(factories);
28557 }
28558 /**
28559 * Takes an array of {@link KeyValueDifferFactory} and returns a provider used to extend the
28560 * inherited {@link KeyValueDiffers} instance with the provided factories and return a new
28561 * {@link KeyValueDiffers} instance.
28562 *
28563 * @usageNotes
28564 * ### Example
28565 *
28566 * The following example shows how to extend an existing list of factories,
28567 * which will only be applied to the injector for this component and its children.
28568 * This step is all that's required to make a new {@link KeyValueDiffer} available.
28569 *
28570 * ```
28571 * @Component({
28572 * viewProviders: [
28573 * KeyValueDiffers.extend([new ImmutableMapDiffer()])
28574 * ]
28575 * })
28576 * ```
28577 */
28578 static extend(factories) {
28579 return {
28580 provide: KeyValueDiffers,
28581 useFactory: (parent) => {
28582 // if parent is null, it means that we are in the root injector and we have just overridden
28583 // the default injection mechanism for KeyValueDiffers, in such a case just assume
28584 // `defaultKeyValueDiffersFactory`.
28585 return KeyValueDiffers.create(factories, parent || defaultKeyValueDiffersFactory());
28586 },
28587 // Dependency technically isn't optional, but we can provide a better error message this way.
28588 deps: [[KeyValueDiffers, new SkipSelf(), new Optional()]]
28589 };
28590 }
28591 find(kv) {
28592 const factory = this.factories.find(f => f.supports(kv));
28593 if (factory) {
28594 return factory;
28595 }
28596 const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
28597 `Cannot find a differ supporting object '${kv}'` :
28598 '';
28599 throw new RuntimeError(901 /* NO_SUPPORTING_DIFFER_FACTORY */, errorMessage);
28600 }
28601}
28602/** @nocollapse */
28603KeyValueDiffers.ɵprov = ɵɵdefineInjectable({ token: KeyValueDiffers, providedIn: 'root', factory: defaultKeyValueDiffersFactory });
28604
28605/**
28606 * @license
28607 * Copyright Google LLC All Rights Reserved.
28608 *
28609 * Use of this source code is governed by an MIT-style license that can be
28610 * found in the LICENSE file at https://angular.io/license
28611 */
28612/**
28613 * Structural diffing for `Object`s and `Map`s.
28614 */
28615const keyValDiff = [new DefaultKeyValueDifferFactory()];
28616/**
28617 * Structural diffing for `Iterable` types such as `Array`s.
28618 */
28619const iterableDiff = [new DefaultIterableDifferFactory()];
28620const defaultIterableDiffers = new IterableDiffers(iterableDiff);
28621const defaultKeyValueDiffers = new KeyValueDiffers(keyValDiff);
28622
28623/**
28624 * @license
28625 * Copyright Google LLC All Rights Reserved.
28626 *
28627 * Use of this source code is governed by an MIT-style license that can be
28628 * found in the LICENSE file at https://angular.io/license
28629 */
28630
28631/**
28632 * @license
28633 * Copyright Google LLC All Rights Reserved.
28634 *
28635 * Use of this source code is governed by an MIT-style license that can be
28636 * found in the LICENSE file at https://angular.io/license
28637 */
28638/**
28639 * This platform has to be included in any other platform
28640 *
28641 * @publicApi
28642 */
28643const platformCore = createPlatformFactory(null, 'core', []);
28644
28645/**
28646 * @license
28647 * Copyright Google LLC All Rights Reserved.
28648 *
28649 * Use of this source code is governed by an MIT-style license that can be
28650 * found in the LICENSE file at https://angular.io/license
28651 */
28652/**
28653 * Re-exported by `BrowserModule`, which is included automatically in the root
28654 * `AppModule` when you create a new app with the CLI `new` command. Eagerly injects
28655 * `ApplicationRef` to instantiate it.
28656 *
28657 * @publicApi
28658 */
28659class ApplicationModule {
28660 // Inject ApplicationRef to make it eager...
28661 constructor(appRef) { }
28662}
28663ApplicationModule.ɵfac = function ApplicationModule_Factory(t) { return new (t || ApplicationModule)(ɵɵinject(ApplicationRef)); };
28664ApplicationModule.ɵmod = /*@__PURE__*/ ɵɵdefineNgModule({ type: ApplicationModule });
28665ApplicationModule.ɵinj = /*@__PURE__*/ ɵɵdefineInjector({});
28666(function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationModule, [{
28667 type: NgModule
28668 }], function () { return [{ type: ApplicationRef }]; }, null); })();
28669
28670/**
28671 * @license
28672 * Copyright Google LLC All Rights Reserved.
28673 *
28674 * Use of this source code is governed by an MIT-style license that can be
28675 * found in the LICENSE file at https://angular.io/license
28676 */
28677// TODO(alxhub): allows tests to compile, can be removed when tests have been updated.
28678const ɵivyEnabled = true;
28679
28680/**
28681 * @license
28682 * Copyright Google LLC All Rights Reserved.
28683 *
28684 * Use of this source code is governed by an MIT-style license that can be
28685 * found in the LICENSE file at https://angular.io/license
28686 */
28687/**
28688 * Compiles a partial directive declaration object into a full directive definition object.
28689 *
28690 * @codeGenApi
28691 */
28692function ɵɵngDeclareDirective(decl) {
28693 const compiler = getCompilerFacade({ usage: 1 /* PartialDeclaration */, kind: 'directive', type: decl.type });
28694 return compiler.compileDirectiveDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl);
28695}
28696/**
28697 * Evaluates the class metadata declaration.
28698 *
28699 * @codeGenApi
28700 */
28701function ɵɵngDeclareClassMetadata(decl) {
28702 setClassMetadata(decl.type, decl.decorators, decl.ctorParameters ?? null, decl.propDecorators ?? null);
28703}
28704/**
28705 * Compiles a partial component declaration object into a full component definition object.
28706 *
28707 * @codeGenApi
28708 */
28709function ɵɵngDeclareComponent(decl) {
28710 const compiler = getCompilerFacade({ usage: 1 /* PartialDeclaration */, kind: 'component', type: decl.type });
28711 return compiler.compileComponentDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵcmp.js`, decl);
28712}
28713/**
28714 * Compiles a partial pipe declaration object into a full pipe definition object.
28715 *
28716 * @codeGenApi
28717 */
28718function ɵɵngDeclareFactory(decl) {
28719 const compiler = getCompilerFacade({
28720 usage: 1 /* PartialDeclaration */,
28721 kind: getFactoryKind(decl.target),
28722 type: decl.type
28723 });
28724 return compiler.compileFactoryDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl);
28725}
28726function getFactoryKind(target) {
28727 switch (target) {
28728 case FactoryTarget.Directive:
28729 return 'directive';
28730 case FactoryTarget.Component:
28731 return 'component';
28732 case FactoryTarget.Injectable:
28733 return 'injectable';
28734 case FactoryTarget.Pipe:
28735 return 'pipe';
28736 case FactoryTarget.NgModule:
28737 return 'NgModule';
28738 }
28739}
28740/**
28741 * Compiles a partial injectable declaration object into a full injectable definition object.
28742 *
28743 * @codeGenApi
28744 */
28745function ɵɵngDeclareInjectable(decl) {
28746 const compiler = getCompilerFacade({ usage: 1 /* PartialDeclaration */, kind: 'injectable', type: decl.type });
28747 return compiler.compileInjectableDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵprov.js`, decl);
28748}
28749/**
28750 * Compiles a partial injector declaration object into a full injector definition object.
28751 *
28752 * @codeGenApi
28753 */
28754function ɵɵngDeclareInjector(decl) {
28755 const compiler = getCompilerFacade({ usage: 1 /* PartialDeclaration */, kind: 'NgModule', type: decl.type });
28756 return compiler.compileInjectorDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵinj.js`, decl);
28757}
28758/**
28759 * Compiles a partial NgModule declaration object into a full NgModule definition object.
28760 *
28761 * @codeGenApi
28762 */
28763function ɵɵngDeclareNgModule(decl) {
28764 const compiler = getCompilerFacade({ usage: 1 /* PartialDeclaration */, kind: 'NgModule', type: decl.type });
28765 return compiler.compileNgModuleDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵmod.js`, decl);
28766}
28767/**
28768 * Compiles a partial pipe declaration object into a full pipe definition object.
28769 *
28770 * @codeGenApi
28771 */
28772function ɵɵngDeclarePipe(decl) {
28773 const compiler = getCompilerFacade({ usage: 1 /* PartialDeclaration */, kind: 'pipe', type: decl.type });
28774 return compiler.compilePipeDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵpipe.js`, decl);
28775}
28776
28777/**
28778 * @license
28779 * Copyright Google LLC All Rights Reserved.
28780 *
28781 * Use of this source code is governed by an MIT-style license that can be
28782 * found in the LICENSE file at https://angular.io/license
28783 */
28784// clang-format on
28785
28786/**
28787 * @license
28788 * Copyright Google LLC All Rights Reserved.
28789 *
28790 * Use of this source code is governed by an MIT-style license that can be
28791 * found in the LICENSE file at https://angular.io/license
28792 */
28793if (typeof ngDevMode !== 'undefined' && ngDevMode) {
28794 // This helper is to give a reasonable error message to people upgrading to v9 that have not yet
28795 // installed `@angular/localize` in their app.
28796 // tslint:disable-next-line: no-toplevel-property-access
28797 _global.$localize = _global.$localize || function () {
28798 throw new Error('It looks like your application or one of its dependencies is using i18n.\n' +
28799 'Angular 9 introduced a global `$localize()` function that needs to be loaded.\n' +
28800 'Please run `ng add @angular/localize` from the Angular CLI.\n' +
28801 '(For non-CLI projects, add `import \'@angular/localize/init\';` to your `polyfills.ts` file.\n' +
28802 'For server-side rendering applications add the import to your `main.server.ts` file.)');
28803 };
28804}
28805
28806/**
28807 * @license
28808 * Copyright Google LLC All Rights Reserved.
28809 *
28810 * Use of this source code is governed by an MIT-style license that can be
28811 * found in the LICENSE file at https://angular.io/license
28812 */
28813// This file only reexports content of the `src` folder. Keep it that way.
28814
28815/**
28816 * @license
28817 * Copyright Google LLC All Rights Reserved.
28818 *
28819 * Use of this source code is governed by an MIT-style license that can be
28820 * found in the LICENSE file at https://angular.io/license
28821 */
28822
28823/**
28824 * Generated bundle index. Do not edit.
28825 */
28826
28827export { ANALYZE_FOR_ENTRY_COMPONENTS, 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, ElementRef, EmbeddedViewRef, 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, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, 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, 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, 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, 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, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, isBoundToModule as ɵisBoundToModule, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy, isListLikeIterable as ɵisListLikeIterable, isObservable as ɵisObservable, isPromise as ɵisPromise, 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, registerNgModuleType as ɵregisterNgModuleType, renderComponent as ɵrenderComponent, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, setClassMetadata as ɵsetClassMetadata, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setLocaleId as ɵsetLocaleId, 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, ɵɵ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, ɵɵ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 };
28828//# sourceMappingURL=core.mjs.map