UNPKG

1.03 MBJavaScriptView Raw
1/**
2 * @license Angular v15.1.5
3 * (c) 2010-2022 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { getDebugNode, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, NgZone, Compiler, COMPILER_OPTIONS, ɵNgModuleFactory, ɵisEnvironmentProviders, ModuleWithComponentFactories, ɵconvertToBitFlags, Injector as Injector$1, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, EnvironmentInjector as EnvironmentInjector$1, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
8import { __awaiter } from 'tslib';
9import { ResourceLoader } from '@angular/compiler';
10import { Subject, Subscription } from 'rxjs';
11
12/**
13 * Wraps a test function in an asynchronous test zone. The test will automatically
14 * complete when all asynchronous calls within this zone are done. Can be used
15 * to wrap an {@link inject} call.
16 *
17 * Example:
18 *
19 * ```
20 * it('...', waitForAsync(inject([AClass], (object) => {
21 * object.doSomething.then(() => {
22 * expect(...);
23 * })
24 * });
25 * ```
26 *
27 * @publicApi
28 */
29function waitForAsync(fn) {
30 const _Zone = typeof Zone !== 'undefined' ? Zone : null;
31 if (!_Zone) {
32 return function () {
33 return Promise.reject('Zone is needed for the waitForAsync() test helper but could not be found. ' +
34 'Please make sure that your environment includes zone.js');
35 };
36 }
37 const asyncTest = _Zone && _Zone[_Zone.__symbol__('asyncTest')];
38 if (typeof asyncTest === 'function') {
39 return asyncTest(fn);
40 }
41 return function () {
42 return Promise.reject('zone-testing.js is needed for the async() test helper but could not be found. ' +
43 'Please make sure that your environment includes zone.js/testing');
44 };
45}
46/**
47 * @deprecated use `waitForAsync()`, (expected removal in v12)
48 * @see {@link waitForAsync}
49 * @publicApi
50 * */
51function async(fn) {
52 return waitForAsync(fn);
53}
54
55/**
56 * Fixture for debugging and testing a component.
57 *
58 * @publicApi
59 */
60class ComponentFixture {
61 constructor(componentRef, ngZone, _autoDetect) {
62 this.componentRef = componentRef;
63 this.ngZone = ngZone;
64 this._autoDetect = _autoDetect;
65 this._isStable = true;
66 this._isDestroyed = false;
67 this._resolve = null;
68 this._promise = null;
69 this._onUnstableSubscription = null;
70 this._onStableSubscription = null;
71 this._onMicrotaskEmptySubscription = null;
72 this._onErrorSubscription = null;
73 this.changeDetectorRef = componentRef.changeDetectorRef;
74 this.elementRef = componentRef.location;
75 this.debugElement = getDebugNode(this.elementRef.nativeElement);
76 this.componentInstance = componentRef.instance;
77 this.nativeElement = this.elementRef.nativeElement;
78 this.componentRef = componentRef;
79 this.ngZone = ngZone;
80 if (ngZone) {
81 // Create subscriptions outside the NgZone so that the callbacks run oustide
82 // of NgZone.
83 ngZone.runOutsideAngular(() => {
84 this._onUnstableSubscription = ngZone.onUnstable.subscribe({
85 next: () => {
86 this._isStable = false;
87 }
88 });
89 this._onMicrotaskEmptySubscription = ngZone.onMicrotaskEmpty.subscribe({
90 next: () => {
91 if (this._autoDetect) {
92 // Do a change detection run with checkNoChanges set to true to check
93 // there are no changes on the second run.
94 this.detectChanges(true);
95 }
96 }
97 });
98 this._onStableSubscription = ngZone.onStable.subscribe({
99 next: () => {
100 this._isStable = true;
101 // Check whether there is a pending whenStable() completer to resolve.
102 if (this._promise !== null) {
103 // If so check whether there are no pending macrotasks before resolving.
104 // Do this check in the next tick so that ngZone gets a chance to update the state of
105 // pending macrotasks.
106 scheduleMicroTask(() => {
107 if (!ngZone.hasPendingMacrotasks) {
108 if (this._promise !== null) {
109 this._resolve(true);
110 this._resolve = null;
111 this._promise = null;
112 }
113 }
114 });
115 }
116 }
117 });
118 this._onErrorSubscription = ngZone.onError.subscribe({
119 next: (error) => {
120 throw error;
121 }
122 });
123 });
124 }
125 }
126 _tick(checkNoChanges) {
127 this.changeDetectorRef.detectChanges();
128 if (checkNoChanges) {
129 this.checkNoChanges();
130 }
131 }
132 /**
133 * Trigger a change detection cycle for the component.
134 */
135 detectChanges(checkNoChanges = true) {
136 if (this.ngZone != null) {
137 // Run the change detection inside the NgZone so that any async tasks as part of the change
138 // detection are captured by the zone and can be waited for in isStable.
139 this.ngZone.run(() => {
140 this._tick(checkNoChanges);
141 });
142 }
143 else {
144 // Running without zone. Just do the change detection.
145 this._tick(checkNoChanges);
146 }
147 }
148 /**
149 * Do a change detection run to make sure there were no changes.
150 */
151 checkNoChanges() {
152 this.changeDetectorRef.checkNoChanges();
153 }
154 /**
155 * Set whether the fixture should autodetect changes.
156 *
157 * Also runs detectChanges once so that any existing change is detected.
158 */
159 autoDetectChanges(autoDetect = true) {
160 if (this.ngZone == null) {
161 throw new Error('Cannot call autoDetectChanges when ComponentFixtureNoNgZone is set');
162 }
163 this._autoDetect = autoDetect;
164 this.detectChanges();
165 }
166 /**
167 * Return whether the fixture is currently stable or has async tasks that have not been completed
168 * yet.
169 */
170 isStable() {
171 return this._isStable && !this.ngZone.hasPendingMacrotasks;
172 }
173 /**
174 * Get a promise that resolves when the fixture is stable.
175 *
176 * This can be used to resume testing after events have triggered asynchronous activity or
177 * asynchronous change detection.
178 */
179 whenStable() {
180 if (this.isStable()) {
181 return Promise.resolve(false);
182 }
183 else if (this._promise !== null) {
184 return this._promise;
185 }
186 else {
187 this._promise = new Promise(res => {
188 this._resolve = res;
189 });
190 return this._promise;
191 }
192 }
193 _getRenderer() {
194 if (this._renderer === undefined) {
195 this._renderer = this.componentRef.injector.get(RendererFactory2$1, null);
196 }
197 return this._renderer;
198 }
199 /**
200 * Get a promise that resolves when the ui state is stable following animations.
201 */
202 whenRenderingDone() {
203 const renderer = this._getRenderer();
204 if (renderer && renderer.whenRenderingDone) {
205 return renderer.whenRenderingDone();
206 }
207 return this.whenStable();
208 }
209 /**
210 * Trigger component destruction.
211 */
212 destroy() {
213 if (!this._isDestroyed) {
214 this.componentRef.destroy();
215 if (this._onUnstableSubscription != null) {
216 this._onUnstableSubscription.unsubscribe();
217 this._onUnstableSubscription = null;
218 }
219 if (this._onStableSubscription != null) {
220 this._onStableSubscription.unsubscribe();
221 this._onStableSubscription = null;
222 }
223 if (this._onMicrotaskEmptySubscription != null) {
224 this._onMicrotaskEmptySubscription.unsubscribe();
225 this._onMicrotaskEmptySubscription = null;
226 }
227 if (this._onErrorSubscription != null) {
228 this._onErrorSubscription.unsubscribe();
229 this._onErrorSubscription = null;
230 }
231 this._isDestroyed = true;
232 }
233 }
234}
235function scheduleMicroTask(fn) {
236 Zone.current.scheduleMicroTask('scheduleMicrotask', fn);
237}
238
239const _Zone = typeof Zone !== 'undefined' ? Zone : null;
240const fakeAsyncTestModule = _Zone && _Zone[_Zone.__symbol__('fakeAsyncTest')];
241const fakeAsyncTestModuleNotLoadedErrorMessage = `zone-testing.js is needed for the fakeAsync() test helper but could not be found.
242 Please make sure that your environment includes zone.js/testing`;
243/**
244 * Clears out the shared fake async zone for a test.
245 * To be called in a global `beforeEach`.
246 *
247 * @publicApi
248 */
249function resetFakeAsyncZone() {
250 if (fakeAsyncTestModule) {
251 return fakeAsyncTestModule.resetFakeAsyncZone();
252 }
253 throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);
254}
255/**
256 * Wraps a function to be executed in the `fakeAsync` zone:
257 * - Microtasks are manually executed by calling `flushMicrotasks()`.
258 * - Timers are synchronous; `tick()` simulates the asynchronous passage of time.
259 *
260 * If there are any pending timers at the end of the function, an exception is thrown.
261 *
262 * Can be used to wrap `inject()` calls.
263 *
264 * @param fn The function that you want to wrap in the `fakeAysnc` zone.
265 *
266 * @usageNotes
267 * ### Example
268 *
269 * {@example core/testing/ts/fake_async.ts region='basic'}
270 *
271 *
272 * @returns The function wrapped to be executed in the `fakeAsync` zone.
273 * Any arguments passed when calling this returned function will be passed through to the `fn`
274 * function in the parameters when it is called.
275 *
276 * @publicApi
277 */
278function fakeAsync(fn) {
279 if (fakeAsyncTestModule) {
280 return fakeAsyncTestModule.fakeAsync(fn);
281 }
282 throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);
283}
284/**
285 * Simulates the asynchronous passage of time for the timers in the `fakeAsync` zone.
286 *
287 * The microtasks queue is drained at the very start of this function and after any timer callback
288 * has been executed.
289 *
290 * @param millis The number of milliseconds to advance the virtual timer.
291 * @param tickOptions The options to pass to the `tick()` function.
292 *
293 * @usageNotes
294 *
295 * The `tick()` option is a flag called `processNewMacroTasksSynchronously`,
296 * which determines whether or not to invoke new macroTasks.
297 *
298 * If you provide a `tickOptions` object, but do not specify a
299 * `processNewMacroTasksSynchronously` property (`tick(100, {})`),
300 * then `processNewMacroTasksSynchronously` defaults to true.
301 *
302 * If you omit the `tickOptions` parameter (`tick(100))`), then
303 * `tickOptions` defaults to `{processNewMacroTasksSynchronously: true}`.
304 *
305 * ### Example
306 *
307 * {@example core/testing/ts/fake_async.ts region='basic'}
308 *
309 * The following example includes a nested timeout (new macroTask), and
310 * the `tickOptions` parameter is allowed to default. In this case,
311 * `processNewMacroTasksSynchronously` defaults to true, and the nested
312 * function is executed on each tick.
313 *
314 * ```
315 * it ('test with nested setTimeout', fakeAsync(() => {
316 * let nestedTimeoutInvoked = false;
317 * function funcWithNestedTimeout() {
318 * setTimeout(() => {
319 * nestedTimeoutInvoked = true;
320 * });
321 * };
322 * setTimeout(funcWithNestedTimeout);
323 * tick();
324 * expect(nestedTimeoutInvoked).toBe(true);
325 * }));
326 * ```
327 *
328 * In the following case, `processNewMacroTasksSynchronously` is explicitly
329 * set to false, so the nested timeout function is not invoked.
330 *
331 * ```
332 * it ('test with nested setTimeout', fakeAsync(() => {
333 * let nestedTimeoutInvoked = false;
334 * function funcWithNestedTimeout() {
335 * setTimeout(() => {
336 * nestedTimeoutInvoked = true;
337 * });
338 * };
339 * setTimeout(funcWithNestedTimeout);
340 * tick(0, {processNewMacroTasksSynchronously: false});
341 * expect(nestedTimeoutInvoked).toBe(false);
342 * }));
343 * ```
344 *
345 *
346 * @publicApi
347 */
348function tick(millis = 0, tickOptions = {
349 processNewMacroTasksSynchronously: true
350}) {
351 if (fakeAsyncTestModule) {
352 return fakeAsyncTestModule.tick(millis, tickOptions);
353 }
354 throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);
355}
356/**
357 * Flushes any pending microtasks and simulates the asynchronous passage of time for the timers in
358 * the `fakeAsync` zone by
359 * draining the macrotask queue until it is empty.
360 *
361 * @param maxTurns The maximum number of times the scheduler attempts to clear its queue before
362 * throwing an error.
363 * @returns The simulated time elapsed, in milliseconds.
364 *
365 * @publicApi
366 */
367function flush(maxTurns) {
368 if (fakeAsyncTestModule) {
369 return fakeAsyncTestModule.flush(maxTurns);
370 }
371 throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);
372}
373/**
374 * Discard all remaining periodic tasks.
375 *
376 * @publicApi
377 */
378function discardPeriodicTasks() {
379 if (fakeAsyncTestModule) {
380 return fakeAsyncTestModule.discardPeriodicTasks();
381 }
382 throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);
383}
384/**
385 * Flush any pending microtasks.
386 *
387 * @publicApi
388 */
389function flushMicrotasks() {
390 if (fakeAsyncTestModule) {
391 return fakeAsyncTestModule.flushMicrotasks();
392 }
393 throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);
394}
395
396/** Whether test modules should be torn down by default. */
397const TEARDOWN_TESTING_MODULE_ON_DESTROY_DEFAULT = true;
398/** Whether unknown elements in templates should throw by default. */
399const THROW_ON_UNKNOWN_ELEMENTS_DEFAULT = false;
400/** Whether unknown properties in templates should throw by default. */
401const THROW_ON_UNKNOWN_PROPERTIES_DEFAULT = false;
402/**
403 * An abstract class for inserting the root test component element in a platform independent way.
404 *
405 * @publicApi
406 */
407class TestComponentRenderer {
408 insertRootElement(rootElementId) { }
409 removeAllRootElements() { }
410}
411/**
412 * @publicApi
413 */
414const ComponentFixtureAutoDetect = new InjectionToken$1('ComponentFixtureAutoDetect');
415/**
416 * @publicApi
417 */
418const ComponentFixtureNoNgZone = new InjectionToken$1('ComponentFixtureNoNgZone');
419
420/**
421 * Used to resolve resource URLs on `@Component` when used with JIT compilation.
422 *
423 * Example:
424 * ```
425 * @Component({
426 * selector: 'my-comp',
427 * templateUrl: 'my-comp.html', // This requires asynchronous resolution
428 * })
429 * class MyComponent{
430 * }
431 *
432 * // Calling `renderComponent` will fail because `renderComponent` is a synchronous process
433 * // and `MyComponent`'s `@Component.templateUrl` needs to be resolved asynchronously.
434 *
435 * // Calling `resolveComponentResources()` will resolve `@Component.templateUrl` into
436 * // `@Component.template`, which allows `renderComponent` to proceed in a synchronous manner.
437 *
438 * // Use browser's `fetch()` function as the default resource resolution strategy.
439 * resolveComponentResources(fetch).then(() => {
440 * // After resolution all URLs have been converted into `template` strings.
441 * renderComponent(MyComponent);
442 * });
443 *
444 * ```
445 *
446 * NOTE: In AOT the resolution happens during compilation, and so there should be no need
447 * to call this method outside JIT mode.
448 *
449 * @param resourceResolver a function which is responsible for returning a `Promise` to the
450 * contents of the resolved URL. Browser's `fetch()` method is a good default implementation.
451 */
452function resolveComponentResources(resourceResolver) {
453 // Store all promises which are fetching the resources.
454 const componentResolved = [];
455 // Cache so that we don't fetch the same resource more than once.
456 const urlMap = new Map();
457 function cachedResourceResolve(url) {
458 let promise = urlMap.get(url);
459 if (!promise) {
460 const resp = resourceResolver(url);
461 urlMap.set(url, promise = resp.then(unwrapResponse));
462 }
463 return promise;
464 }
465 componentResourceResolutionQueue.forEach((component, type) => {
466 const promises = [];
467 if (component.templateUrl) {
468 promises.push(cachedResourceResolve(component.templateUrl).then((template) => {
469 component.template = template;
470 }));
471 }
472 const styleUrls = component.styleUrls;
473 const styles = component.styles || (component.styles = []);
474 const styleOffset = component.styles.length;
475 styleUrls && styleUrls.forEach((styleUrl, index) => {
476 styles.push(''); // pre-allocate array.
477 promises.push(cachedResourceResolve(styleUrl).then((style) => {
478 styles[styleOffset + index] = style;
479 styleUrls.splice(styleUrls.indexOf(styleUrl), 1);
480 if (styleUrls.length == 0) {
481 component.styleUrls = undefined;
482 }
483 }));
484 });
485 const fullyResolved = Promise.all(promises).then(() => componentDefResolved(type));
486 componentResolved.push(fullyResolved);
487 });
488 clearResolutionOfComponentResourcesQueue();
489 return Promise.all(componentResolved).then(() => undefined);
490}
491let componentResourceResolutionQueue = new Map();
492// Track when existing ɵcmp for a Type is waiting on resources.
493const componentDefPendingResolution = new Set();
494function maybeQueueResolutionOfComponentResources(type, metadata) {
495 if (componentNeedsResolution(metadata)) {
496 componentResourceResolutionQueue.set(type, metadata);
497 componentDefPendingResolution.add(type);
498 }
499}
500function isComponentDefPendingResolution(type) {
501 return componentDefPendingResolution.has(type);
502}
503function componentNeedsResolution(component) {
504 return !!((component.templateUrl && !component.hasOwnProperty('template')) ||
505 component.styleUrls && component.styleUrls.length);
506}
507function clearResolutionOfComponentResourcesQueue() {
508 const old = componentResourceResolutionQueue;
509 componentResourceResolutionQueue = new Map();
510 return old;
511}
512function restoreComponentResolutionQueue(queue) {
513 componentDefPendingResolution.clear();
514 queue.forEach((_, type) => componentDefPendingResolution.add(type));
515 componentResourceResolutionQueue = queue;
516}
517function isComponentResourceResolutionQueueEmpty() {
518 return componentResourceResolutionQueue.size === 0;
519}
520function unwrapResponse(response) {
521 return typeof response == 'string' ? response : response.text();
522}
523function componentDefResolved(type) {
524 componentDefPendingResolution.delete(type);
525}
526
527// Always use __globalThis if available, which is the spec-defined global variable across all
528// environments, then fallback to __global first, because in Node tests both __global and
529// __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof
530// checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
531// https://github.com/terser/terser/issues/250.
532const _global$1 = ( /* @__PURE__ */(() => (typeof globalThis !== 'undefined' && globalThis) ||
533 (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
534 (typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
535 self instanceof WorkerGlobalScope && self))());
536
537var FactoryTarget;
538(function (FactoryTarget) {
539 FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
540 FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
541 FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
542 FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
543 FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
544})(FactoryTarget || (FactoryTarget = {}));
545var R3TemplateDependencyKind;
546(function (R3TemplateDependencyKind) {
547 R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive";
548 R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe";
549 R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule";
550})(R3TemplateDependencyKind || (R3TemplateDependencyKind = {}));
551var ViewEncapsulation$1;
552(function (ViewEncapsulation) {
553 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
554 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
555 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
556 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
557})(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
558
559function getCompilerFacade(request) {
560 const globalNg = _global$1['ng'];
561 if (globalNg && globalNg.ɵcompilerFacade) {
562 return globalNg.ɵcompilerFacade;
563 }
564 if (typeof ngDevMode === 'undefined' || ngDevMode) {
565 // Log the type as an error so that a developer can easily navigate to the type from the
566 // console.
567 console.error(`JIT compilation failed for ${request.kind}`, request.type);
568 let message = `The ${request.kind} '${request
569 .type.name}' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.\n\n`;
570 if (request.usage === 1 /* JitCompilerUsage.PartialDeclaration */) {
571 message += `The ${request.kind} is part of a library that has been partially compiled.\n`;
572 message +=
573 `However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.\n`;
574 message += '\n';
575 message +=
576 `Ideally, the library is processed using the Angular Linker to become fully AOT compiled.\n`;
577 }
578 else {
579 message +=
580 `JIT compilation is discouraged for production use-cases! Consider using AOT mode instead.\n`;
581 }
582 message +=
583 `Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',\n`;
584 message +=
585 `or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`;
586 throw new Error(message);
587 }
588 else {
589 throw new Error('JIT compiler unavailable');
590 }
591}
592
593function getClosureSafeProperty(objWithPropertyToExtract) {
594 for (let key in objWithPropertyToExtract) {
595 if (objWithPropertyToExtract[key] === getClosureSafeProperty) {
596 return key;
597 }
598 }
599 throw Error('Could not find renamed property on target object.');
600}
601/**
602 * Sets properties on a target object from a source object, but only if
603 * the property doesn't already exist on the target object.
604 * @param target The target to set properties on
605 * @param source The source of the property keys and values to set
606 */
607function fillProperties(target, source) {
608 for (const key in source) {
609 if (source.hasOwnProperty(key) && !target.hasOwnProperty(key)) {
610 target[key] = source[key];
611 }
612 }
613}
614
615function stringify(token) {
616 if (typeof token === 'string') {
617 return token;
618 }
619 if (Array.isArray(token)) {
620 return '[' + token.map(stringify).join(', ') + ']';
621 }
622 if (token == null) {
623 return '' + token;
624 }
625 if (token.overriddenName) {
626 return `${token.overriddenName}`;
627 }
628 if (token.name) {
629 return `${token.name}`;
630 }
631 const res = token.toString();
632 if (res == null) {
633 return '' + res;
634 }
635 const newLineIndex = res.indexOf('\n');
636 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
637}
638/**
639 * Concatenates two strings with separator, allocating new strings only when necessary.
640 *
641 * @param before before string.
642 * @param separator separator string.
643 * @param after after string.
644 * @returns concatenated string.
645 */
646function concatStringsWithSpace(before, after) {
647 return (before == null || before === '') ?
648 (after === null ? '' : after) :
649 ((after == null || after === '') ? before : before + ' ' + after);
650}
651
652const __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty });
653/**
654 * Allows to refer to references which are not yet defined.
655 *
656 * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
657 * DI is declared, but not yet defined. It is also used when the `token` which we use when creating
658 * a query is not yet defined.
659 *
660 * @usageNotes
661 * ### Example
662 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'}
663 * @publicApi
664 */
665function forwardRef(forwardRefFn) {
666 forwardRefFn.__forward_ref__ = forwardRef;
667 forwardRefFn.toString = function () {
668 return stringify(this());
669 };
670 return forwardRefFn;
671}
672/**
673 * Lazily retrieves the reference value from a forwardRef.
674 *
675 * Acts as the identity function when given a non-forward-ref value.
676 *
677 * @usageNotes
678 * ### Example
679 *
680 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'}
681 *
682 * @see `forwardRef`
683 * @publicApi
684 */
685function resolveForwardRef(type) {
686 return isForwardRef(type) ? type() : type;
687}
688/** Checks whether a function is wrapped by a `forwardRef`. */
689function isForwardRef(fn) {
690 return typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
691 fn.__forward_ref__ === forwardRef;
692}
693
694/**
695 * Construct an injectable definition which defines how a token will be constructed by the DI
696 * system, and in which injectors (if any) it will be available.
697 *
698 * This should be assigned to a static `ɵprov` field on a type, which will then be an
699 * `InjectableType`.
700 *
701 * Options:
702 * * `providedIn` determines which injectors will include the injectable, by either associating it
703 * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
704 * provided in the `'root'` injector, which will be the application-level injector in most apps.
705 * * `factory` gives the zero argument function which will create an instance of the injectable.
706 * The factory can call `inject` to access the `Injector` and request injection of dependencies.
707 *
708 * @codeGenApi
709 * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
710 */
711function ɵɵdefineInjectable(opts) {
712 return {
713 token: opts.token,
714 providedIn: opts.providedIn || null,
715 factory: opts.factory,
716 value: undefined,
717 };
718}
719/**
720 * @deprecated in v8, delete after v10. This API should be used only by generated code, and that
721 * code should now use ɵɵdefineInjectable instead.
722 * @publicApi
723 */
724const defineInjectable = ɵɵdefineInjectable;
725/**
726 * Construct an `InjectorDef` which configures an injector.
727 *
728 * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
729 * `InjectorType`.
730 *
731 * Options:
732 *
733 * * `providers`: an optional array of providers to add to the injector. Each provider must
734 * either have a factory or point to a type which has a `ɵprov` static property (the
735 * type must be an `InjectableType`).
736 * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
737 * whose providers will also be added to the injector. Locally provided types will override
738 * providers from imports.
739 *
740 * @codeGenApi
741 */
742function ɵɵdefineInjector(options) {
743 return { providers: options.providers || [], imports: options.imports || [] };
744}
745/**
746 * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
747 * inherited value.
748 *
749 * @param type A type which may have its own (non-inherited) `ɵprov`.
750 */
751function getInjectableDef(type) {
752 return getOwnDefinition(type, NG_PROV_DEF) || getOwnDefinition(type, NG_INJECTABLE_DEF);
753}
754function isInjectable(type) {
755 return getInjectableDef(type) !== null;
756}
757/**
758 * Return definition only if it is defined directly on `type` and is not inherited from a base
759 * class of `type`.
760 */
761function getOwnDefinition(type, field) {
762 return type.hasOwnProperty(field) ? type[field] : null;
763}
764/**
765 * Read the injectable def (`ɵprov`) for `type` or read the `ɵprov` from one of its ancestors.
766 *
767 * @param type A type which may have `ɵprov`, via inheritance.
768 *
769 * @deprecated Will be removed in a future version of Angular, where an error will occur in the
770 * scenario if we find the `ɵprov` on an ancestor only.
771 */
772function getInheritedInjectableDef(type) {
773 const def = type && (type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF]);
774 if (def) {
775 const typeName = getTypeName(type);
776 // TODO(FW-1307): Re-add ngDevMode when closure can handle it
777 // ngDevMode &&
778 console.warn(`DEPRECATED: DI is instantiating a token "${typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` +
779 `This will become an error in a future version of Angular. Please add @Injectable() to the "${typeName}" class.`);
780 return def;
781 }
782 else {
783 return null;
784 }
785}
786/** Gets the name of a type, accounting for some cross-browser differences. */
787function getTypeName(type) {
788 // `Function.prototype.name` behaves differently between IE and other browsers. In most browsers
789 // it'll always return the name of the function itself, no matter how many other functions it
790 // inherits from. On IE the function doesn't have its own `name` property, but it takes it from
791 // the lowest level in the prototype chain. E.g. if we have `class Foo extends Parent` most
792 // browsers will evaluate `Foo.name` to `Foo` while IE will return `Parent`. We work around
793 // the issue by converting the function to a string and parsing its name out that way via a regex.
794 if (type.hasOwnProperty('name')) {
795 return type.name;
796 }
797 const match = ('' + type).match(/^function\s*([^\s(]+)/);
798 return match === null ? '' : match[1];
799}
800/**
801 * Read the injector def type in a way which is immune to accidentally reading inherited value.
802 *
803 * @param type type which may have an injector def (`ɵinj`)
804 */
805function getInjectorDef(type) {
806 return type && (type.hasOwnProperty(NG_INJ_DEF) || type.hasOwnProperty(NG_INJECTOR_DEF)) ?
807 type[NG_INJ_DEF] :
808 null;
809}
810const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty });
811const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty });
812// We need to keep these around so we can read off old defs if new defs are unavailable
813const NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty });
814const NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty });
815
816/**
817 * Base URL for the error details page.
818 *
819 * Keep this constant in sync across:
820 * - packages/compiler-cli/src/ngtsc/diagnostics/src/error_details_base_url.ts
821 * - packages/core/src/error_details_base_url.ts
822 */
823const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors';
824/**
825 * URL for the XSS security documentation.
826 */
827const XSS_SECURITY_URL = 'https://g.co/ng/security#xss';
828
829/**
830 * Class that represents a runtime error.
831 * Formats and outputs the error message in a consistent way.
832 *
833 * Example:
834 * ```
835 * throw new RuntimeError(
836 * RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED,
837 * ngDevMode && 'Injector has already been destroyed.');
838 * ```
839 *
840 * Note: the `message` argument contains a descriptive error message as a string in development
841 * mode (when the `ngDevMode` is defined). In production mode (after tree-shaking pass), the
842 * `message` argument becomes `false`, thus we account for it in the typings and the runtime logic.
843 */
844class RuntimeError extends Error {
845 constructor(code, message) {
846 super(formatRuntimeError(code, message));
847 this.code = code;
848 }
849}
850/**
851 * Called to format a runtime error.
852 * See additional info on the `message` argument type in the `RuntimeError` class description.
853 */
854function formatRuntimeError(code, message) {
855 // Error code might be a negative number, which is a special marker that instructs the logic to
856 // generate a link to the error details page on angular.io.
857 // We also prepend `0` to non-compile-time errors.
858 const fullCode = `NG0${Math.abs(code)}`;
859 let errorMessage = `${fullCode}${message ? ': ' + message.trim() : ''}`;
860 if (ngDevMode && code < 0) {
861 const addPeriodSeparator = !errorMessage.match(/[.,;!?]$/);
862 const separator = addPeriodSeparator ? '.' : '';
863 errorMessage =
864 `${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
865 }
866 return errorMessage;
867}
868
869/**
870 * @description
871 *
872 * Represents a type that a Component or other object is instances of.
873 *
874 * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is represented by
875 * the `MyCustomComponent` constructor function.
876 *
877 * @publicApi
878 */
879const Type = Function;
880function isType(v) {
881 return typeof v === 'function';
882}
883
884// The functions in this file verify that the assumptions we are making
885function assertNumber(actual, msg) {
886 if (!(typeof actual === 'number')) {
887 throwError(msg, typeof actual, 'number', '===');
888 }
889}
890function assertNumberInRange(actual, minInclusive, maxInclusive) {
891 assertNumber(actual, 'Expected a number');
892 assertLessThanOrEqual(actual, maxInclusive, 'Expected number to be less than or equal to');
893 assertGreaterThanOrEqual(actual, minInclusive, 'Expected number to be greater than or equal to');
894}
895function assertString(actual, msg) {
896 if (!(typeof actual === 'string')) {
897 throwError(msg, actual === null ? 'null' : typeof actual, 'string', '===');
898 }
899}
900function assertFunction(actual, msg) {
901 if (!(typeof actual === 'function')) {
902 throwError(msg, actual === null ? 'null' : typeof actual, 'function', '===');
903 }
904}
905function assertEqual(actual, expected, msg) {
906 if (!(actual == expected)) {
907 throwError(msg, actual, expected, '==');
908 }
909}
910function assertNotEqual(actual, expected, msg) {
911 if (!(actual != expected)) {
912 throwError(msg, actual, expected, '!=');
913 }
914}
915function assertSame(actual, expected, msg) {
916 if (!(actual === expected)) {
917 throwError(msg, actual, expected, '===');
918 }
919}
920function assertNotSame(actual, expected, msg) {
921 if (!(actual !== expected)) {
922 throwError(msg, actual, expected, '!==');
923 }
924}
925function assertLessThan(actual, expected, msg) {
926 if (!(actual < expected)) {
927 throwError(msg, actual, expected, '<');
928 }
929}
930function assertLessThanOrEqual(actual, expected, msg) {
931 if (!(actual <= expected)) {
932 throwError(msg, actual, expected, '<=');
933 }
934}
935function assertGreaterThan(actual, expected, msg) {
936 if (!(actual > expected)) {
937 throwError(msg, actual, expected, '>');
938 }
939}
940function assertGreaterThanOrEqual(actual, expected, msg) {
941 if (!(actual >= expected)) {
942 throwError(msg, actual, expected, '>=');
943 }
944}
945function assertNotDefined(actual, msg) {
946 if (actual != null) {
947 throwError(msg, actual, null, '==');
948 }
949}
950function assertDefined(actual, msg) {
951 if (actual == null) {
952 throwError(msg, actual, null, '!=');
953 }
954}
955function throwError(msg, actual, expected, comparison) {
956 throw new Error(`ASSERTION ERROR: ${msg}` +
957 (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
958}
959function assertDomNode(node) {
960 // If we're in a worker, `Node` will not be defined.
961 if (!(typeof Node !== 'undefined' && node instanceof Node) &&
962 !(typeof node === 'object' && node != null &&
963 node.constructor.name === 'WebWorkerRenderNode')) {
964 throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
965 }
966}
967function assertIndexInRange(arr, index) {
968 assertDefined(arr, 'Array must be defined.');
969 const maxLen = arr.length;
970 if (index < 0 || index >= maxLen) {
971 throwError(`Index expected to be less than ${maxLen} but got ${index}`);
972 }
973}
974function assertOneOf(value, ...validValues) {
975 if (validValues.indexOf(value) !== -1)
976 return true;
977 throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${JSON.stringify(value)}.`);
978}
979
980/**
981 * Determines if the contents of two arrays is identical
982 *
983 * @param a first array
984 * @param b second array
985 * @param identityAccessor Optional function for extracting stable object identity from a value in
986 * the array.
987 */
988function arrayEquals(a, b, identityAccessor) {
989 if (a.length !== b.length)
990 return false;
991 for (let i = 0; i < a.length; i++) {
992 let valueA = a[i];
993 let valueB = b[i];
994 if (identityAccessor) {
995 valueA = identityAccessor(valueA);
996 valueB = identityAccessor(valueB);
997 }
998 if (valueB !== valueA) {
999 return false;
1000 }
1001 }
1002 return true;
1003}
1004/**
1005 * Flattens an array.
1006 */
1007function flatten$1(list) {
1008 return list.flat(Number.POSITIVE_INFINITY);
1009}
1010function deepForEach(input, fn) {
1011 input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value));
1012}
1013function addToArray(arr, index, value) {
1014 // perf: array.push is faster than array.splice!
1015 if (index >= arr.length) {
1016 arr.push(value);
1017 }
1018 else {
1019 arr.splice(index, 0, value);
1020 }
1021}
1022function removeFromArray(arr, index) {
1023 // perf: array.pop is faster than array.splice!
1024 if (index >= arr.length - 1) {
1025 return arr.pop();
1026 }
1027 else {
1028 return arr.splice(index, 1)[0];
1029 }
1030}
1031function newArray(size, value) {
1032 const list = [];
1033 for (let i = 0; i < size; i++) {
1034 list.push(value);
1035 }
1036 return list;
1037}
1038/**
1039 * Remove item from array (Same as `Array.splice()` but faster.)
1040 *
1041 * `Array.splice()` is not as fast because it has to allocate an array for the elements which were
1042 * removed. This causes memory pressure and slows down code when most of the time we don't
1043 * care about the deleted items array.
1044 *
1045 * https://jsperf.com/fast-array-splice (About 20x faster)
1046 *
1047 * @param array Array to splice
1048 * @param index Index of element in array to remove.
1049 * @param count Number of items to remove.
1050 */
1051function arraySplice(array, index, count) {
1052 const length = array.length - count;
1053 while (index < length) {
1054 array[index] = array[index + count];
1055 index++;
1056 }
1057 while (count--) {
1058 array.pop(); // shrink the array
1059 }
1060}
1061/**
1062 * Same as `Array.splice(index, 0, value)` but faster.
1063 *
1064 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
1065 * removed. This causes memory pressure and slows down code when most of the time we don't
1066 * care about the deleted items array.
1067 *
1068 * @param array Array to splice.
1069 * @param index Index in array where the `value` should be added.
1070 * @param value Value to add to array.
1071 */
1072function arrayInsert(array, index, value) {
1073 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
1074 let end = array.length;
1075 while (end > index) {
1076 const previousEnd = end - 1;
1077 array[end] = array[previousEnd];
1078 end = previousEnd;
1079 }
1080 array[index] = value;
1081}
1082/**
1083 * Same as `Array.splice2(index, 0, value1, value2)` but faster.
1084 *
1085 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
1086 * removed. This causes memory pressure and slows down code when most of the time we don't
1087 * care about the deleted items array.
1088 *
1089 * @param array Array to splice.
1090 * @param index Index in array where the `value` should be added.
1091 * @param value1 Value to add to array.
1092 * @param value2 Value to add to array.
1093 */
1094function arrayInsert2(array, index, value1, value2) {
1095 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
1096 let end = array.length;
1097 if (end == index) {
1098 // inserting at the end.
1099 array.push(value1, value2);
1100 }
1101 else if (end === 1) {
1102 // corner case when we have less items in array than we have items to insert.
1103 array.push(value2, array[0]);
1104 array[0] = value1;
1105 }
1106 else {
1107 end--;
1108 array.push(array[end - 1], array[end]);
1109 while (end > index) {
1110 const previousEnd = end - 2;
1111 array[end] = array[previousEnd];
1112 end--;
1113 }
1114 array[index] = value1;
1115 array[index + 1] = value2;
1116 }
1117}
1118/**
1119 * Get an index of an `value` in a sorted `array`.
1120 *
1121 * NOTE:
1122 * - This uses binary search algorithm for fast removals.
1123 *
1124 * @param array A sorted array to binary search.
1125 * @param value The value to look for.
1126 * @returns index of the value.
1127 * - positive index if value found.
1128 * - negative index if value not found. (`~index` to get the value where it should have been
1129 * located)
1130 */
1131function arrayIndexOfSorted(array, value) {
1132 return _arrayIndexOfSorted(array, value, 0);
1133}
1134/**
1135 * Set a `value` for a `key`.
1136 *
1137 * @param keyValueArray to modify.
1138 * @param key The key to locate or create.
1139 * @param value The value to set for a `key`.
1140 * @returns index (always even) of where the value vas set.
1141 */
1142function keyValueArraySet(keyValueArray, key, value) {
1143 let index = keyValueArrayIndexOf(keyValueArray, key);
1144 if (index >= 0) {
1145 // if we found it set it.
1146 keyValueArray[index | 1] = value;
1147 }
1148 else {
1149 index = ~index;
1150 arrayInsert2(keyValueArray, index, key, value);
1151 }
1152 return index;
1153}
1154/**
1155 * Retrieve a `value` for a `key` (on `undefined` if not found.)
1156 *
1157 * @param keyValueArray to search.
1158 * @param key The key to locate.
1159 * @return The `value` stored at the `key` location or `undefined if not found.
1160 */
1161function keyValueArrayGet(keyValueArray, key) {
1162 const index = keyValueArrayIndexOf(keyValueArray, key);
1163 if (index >= 0) {
1164 // if we found it retrieve it.
1165 return keyValueArray[index | 1];
1166 }
1167 return undefined;
1168}
1169/**
1170 * Retrieve a `key` index value in the array or `-1` if not found.
1171 *
1172 * @param keyValueArray to search.
1173 * @param key The key to locate.
1174 * @returns index of where the key is (or should have been.)
1175 * - positive (even) index if key found.
1176 * - negative index if key not found. (`~index` (even) to get the index where it should have
1177 * been inserted.)
1178 */
1179function keyValueArrayIndexOf(keyValueArray, key) {
1180 return _arrayIndexOfSorted(keyValueArray, key, 1);
1181}
1182/**
1183 * Delete a `key` (and `value`) from the `KeyValueArray`.
1184 *
1185 * @param keyValueArray to modify.
1186 * @param key The key to locate or delete (if exist).
1187 * @returns index of where the key was (or should have been.)
1188 * - positive (even) index if key found and deleted.
1189 * - negative index if key not found. (`~index` (even) to get the index where it should have
1190 * been.)
1191 */
1192function keyValueArrayDelete(keyValueArray, key) {
1193 const index = keyValueArrayIndexOf(keyValueArray, key);
1194 if (index >= 0) {
1195 // if we found it remove it.
1196 arraySplice(keyValueArray, index, 2);
1197 }
1198 return index;
1199}
1200/**
1201 * INTERNAL: Get an index of an `value` in a sorted `array` by grouping search by `shift`.
1202 *
1203 * NOTE:
1204 * - This uses binary search algorithm for fast removals.
1205 *
1206 * @param array A sorted array to binary search.
1207 * @param value The value to look for.
1208 * @param shift grouping shift.
1209 * - `0` means look at every location
1210 * - `1` means only look at every other (even) location (the odd locations are to be ignored as
1211 * they are values.)
1212 * @returns index of the value.
1213 * - positive index if value found.
1214 * - negative index if value not found. (`~index` to get the value where it should have been
1215 * inserted)
1216 */
1217function _arrayIndexOfSorted(array, value, shift) {
1218 ngDevMode && assertEqual(Array.isArray(array), true, 'Expecting an array');
1219 let start = 0;
1220 let end = array.length >> shift;
1221 while (end !== start) {
1222 const middle = start + ((end - start) >> 1); // find the middle.
1223 const current = array[middle << shift];
1224 if (value === current) {
1225 return (middle << shift);
1226 }
1227 else if (current > value) {
1228 end = middle;
1229 }
1230 else {
1231 start = middle + 1; // We already searched middle so make it non-inclusive by adding 1
1232 }
1233 }
1234 return ~(end << shift);
1235}
1236
1237/**
1238 * Convince closure compiler that the wrapped function has no side-effects.
1239 *
1240 * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to
1241 * allow us to execute a function but have closure compiler mark the call as no-side-effects.
1242 * It is important that the return value for the `noSideEffects` function be assigned
1243 * to something which is retained otherwise the call to `noSideEffects` will be removed by closure
1244 * compiler.
1245 */
1246function noSideEffects(fn) {
1247 return { toString: fn }.toString();
1248}
1249
1250const ANNOTATIONS = '__annotations__';
1251const PARAMETERS = '__parameters__';
1252const PROP_METADATA = '__prop__metadata__';
1253/**
1254 * @suppress {globalThis}
1255 */
1256function makeDecorator(name, props, parentClass, additionalProcessing, typeFn) {
1257 return noSideEffects(() => {
1258 const metaCtor = makeMetadataCtor(props);
1259 function DecoratorFactory(...args) {
1260 if (this instanceof DecoratorFactory) {
1261 metaCtor.call(this, ...args);
1262 return this;
1263 }
1264 const annotationInstance = new DecoratorFactory(...args);
1265 return function TypeDecorator(cls) {
1266 if (typeFn)
1267 typeFn(cls, ...args);
1268 // Use of Object.defineProperty is important since it creates non-enumerable property which
1269 // prevents the property is copied during subclassing.
1270 const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
1271 cls[ANNOTATIONS] :
1272 Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
1273 annotations.push(annotationInstance);
1274 if (additionalProcessing)
1275 additionalProcessing(cls);
1276 return cls;
1277 };
1278 }
1279 if (parentClass) {
1280 DecoratorFactory.prototype = Object.create(parentClass.prototype);
1281 }
1282 DecoratorFactory.prototype.ngMetadataName = name;
1283 DecoratorFactory.annotationCls = DecoratorFactory;
1284 return DecoratorFactory;
1285 });
1286}
1287function makeMetadataCtor(props) {
1288 return function ctor(...args) {
1289 if (props) {
1290 const values = props(...args);
1291 for (const propName in values) {
1292 this[propName] = values[propName];
1293 }
1294 }
1295 };
1296}
1297function makeParamDecorator(name, props, parentClass) {
1298 return noSideEffects(() => {
1299 const metaCtor = makeMetadataCtor(props);
1300 function ParamDecoratorFactory(...args) {
1301 if (this instanceof ParamDecoratorFactory) {
1302 metaCtor.apply(this, args);
1303 return this;
1304 }
1305 const annotationInstance = new ParamDecoratorFactory(...args);
1306 ParamDecorator.annotation = annotationInstance;
1307 return ParamDecorator;
1308 function ParamDecorator(cls, unusedKey, index) {
1309 // Use of Object.defineProperty is important since it creates non-enumerable property which
1310 // prevents the property is copied during subclassing.
1311 const parameters = cls.hasOwnProperty(PARAMETERS) ?
1312 cls[PARAMETERS] :
1313 Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS];
1314 // there might be gaps if some in between parameters do not have annotations.
1315 // we pad with nulls.
1316 while (parameters.length <= index) {
1317 parameters.push(null);
1318 }
1319 (parameters[index] = parameters[index] || []).push(annotationInstance);
1320 return cls;
1321 }
1322 }
1323 if (parentClass) {
1324 ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
1325 }
1326 ParamDecoratorFactory.prototype.ngMetadataName = name;
1327 ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
1328 return ParamDecoratorFactory;
1329 });
1330}
1331function makePropDecorator(name, props, parentClass, additionalProcessing) {
1332 return noSideEffects(() => {
1333 const metaCtor = makeMetadataCtor(props);
1334 function PropDecoratorFactory(...args) {
1335 if (this instanceof PropDecoratorFactory) {
1336 metaCtor.apply(this, args);
1337 return this;
1338 }
1339 const decoratorInstance = new PropDecoratorFactory(...args);
1340 function PropDecorator(target, name) {
1341 const constructor = target.constructor;
1342 // Use of Object.defineProperty is important because it creates a non-enumerable property
1343 // which prevents the property from being copied during subclassing.
1344 const meta = constructor.hasOwnProperty(PROP_METADATA) ?
1345 constructor[PROP_METADATA] :
1346 Object.defineProperty(constructor, PROP_METADATA, { value: {} })[PROP_METADATA];
1347 meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
1348 meta[name].unshift(decoratorInstance);
1349 if (additionalProcessing)
1350 additionalProcessing(target, name, ...args);
1351 }
1352 return PropDecorator;
1353 }
1354 if (parentClass) {
1355 PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
1356 }
1357 PropDecoratorFactory.prototype.ngMetadataName = name;
1358 PropDecoratorFactory.annotationCls = PropDecoratorFactory;
1359 return PropDecoratorFactory;
1360 });
1361}
1362
1363/*
1364 * #########################
1365 * Attention: These Regular expressions have to hold even if the code is minified!
1366 * ##########################
1367 */
1368/**
1369 * Regular expression that detects pass-through constructors for ES5 output. This Regex
1370 * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
1371 * it intends to capture the pattern where existing constructors have been downleveled from
1372 * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
1373 *
1374 * ```
1375 * function MyClass() {
1376 * var _this = _super.apply(this, arguments) || this;
1377 * ```
1378 *
1379 * downleveled to ES5 with `downlevelIteration` for TypeScript < 4.2:
1380 * ```
1381 * function MyClass() {
1382 * var _this = _super.apply(this, __spread(arguments)) || this;
1383 * ```
1384 *
1385 * or downleveled to ES5 with `downlevelIteration` for TypeScript >= 4.2:
1386 * ```
1387 * function MyClass() {
1388 * var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
1389 * ```
1390 *
1391 * More details can be found in: https://github.com/angular/angular/issues/38453.
1392 */
1393const ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|(?:[^()]+\(\[\],)?[^()]+\(arguments\).*)\)/;
1394/** Regular expression that detects ES2015 classes which extend from other classes. */
1395const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
1396/**
1397 * Regular expression that detects ES2015 classes which extend from other classes and
1398 * have an explicit constructor defined.
1399 */
1400const ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
1401/**
1402 * Regular expression that detects ES2015 classes which extend from other classes
1403 * and inherit a constructor.
1404 */
1405const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{[^}]*super\(\.\.\.arguments\)/;
1406/**
1407 * Determine whether a stringified type is a class which delegates its constructor
1408 * to its parent.
1409 *
1410 * This is not trivial since compiled code can actually contain a constructor function
1411 * even if the original source code did not. For instance, when the child class contains
1412 * an initialized instance property.
1413 */
1414function isDelegateCtor(typeStr) {
1415 return ES5_DELEGATE_CTOR.test(typeStr) ||
1416 ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
1417 (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
1418}
1419class ReflectionCapabilities {
1420 constructor(reflect) {
1421 this._reflect = reflect || _global$1['Reflect'];
1422 }
1423 factory(t) {
1424 return (...args) => new t(...args);
1425 }
1426 /** @internal */
1427 _zipTypesAndAnnotations(paramTypes, paramAnnotations) {
1428 let result;
1429 if (typeof paramTypes === 'undefined') {
1430 result = newArray(paramAnnotations.length);
1431 }
1432 else {
1433 result = newArray(paramTypes.length);
1434 }
1435 for (let i = 0; i < result.length; i++) {
1436 // TS outputs Object for parameters without types, while Traceur omits
1437 // the annotations. For now we preserve the Traceur behavior to aid
1438 // migration, but this can be revisited.
1439 if (typeof paramTypes === 'undefined') {
1440 result[i] = [];
1441 }
1442 else if (paramTypes[i] && paramTypes[i] != Object) {
1443 result[i] = [paramTypes[i]];
1444 }
1445 else {
1446 result[i] = [];
1447 }
1448 if (paramAnnotations && paramAnnotations[i] != null) {
1449 result[i] = result[i].concat(paramAnnotations[i]);
1450 }
1451 }
1452 return result;
1453 }
1454 _ownParameters(type, parentCtor) {
1455 const typeStr = type.toString();
1456 // If we have no decorators, we only have function.length as metadata.
1457 // In that case, to detect whether a child class declared an own constructor or not,
1458 // we need to look inside of that constructor to check whether it is
1459 // just calling the parent.
1460 // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
1461 // that sets 'design:paramtypes' to []
1462 // if a class inherits from another class but has no ctor declared itself.
1463 if (isDelegateCtor(typeStr)) {
1464 return null;
1465 }
1466 // Prefer the direct API.
1467 if (type.parameters && type.parameters !== parentCtor.parameters) {
1468 return type.parameters;
1469 }
1470 // API of tsickle for lowering decorators to properties on the class.
1471 const tsickleCtorParams = type.ctorParameters;
1472 if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
1473 // Newer tsickle uses a function closure
1474 // Retain the non-function case for compatibility with older tsickle
1475 const ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
1476 const paramTypes = ctorParameters.map((ctorParam) => ctorParam && ctorParam.type);
1477 const paramAnnotations = ctorParameters.map((ctorParam) => ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
1478 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
1479 }
1480 // API for metadata created by invoking the decorators.
1481 const paramAnnotations = type.hasOwnProperty(PARAMETERS) && type[PARAMETERS];
1482 const paramTypes = this._reflect && this._reflect.getOwnMetadata &&
1483 this._reflect.getOwnMetadata('design:paramtypes', type);
1484 if (paramTypes || paramAnnotations) {
1485 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
1486 }
1487 // If a class has no decorators, at least create metadata
1488 // based on function.length.
1489 // Note: We know that this is a real constructor as we checked
1490 // the content of the constructor above.
1491 return newArray(type.length);
1492 }
1493 parameters(type) {
1494 // Note: only report metadata if we have at least one class decorator
1495 // to stay in sync with the static reflector.
1496 if (!isType(type)) {
1497 return [];
1498 }
1499 const parentCtor = getParentCtor(type);
1500 let parameters = this._ownParameters(type, parentCtor);
1501 if (!parameters && parentCtor !== Object) {
1502 parameters = this.parameters(parentCtor);
1503 }
1504 return parameters || [];
1505 }
1506 _ownAnnotations(typeOrFunc, parentCtor) {
1507 // Prefer the direct API.
1508 if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
1509 let annotations = typeOrFunc.annotations;
1510 if (typeof annotations === 'function' && annotations.annotations) {
1511 annotations = annotations.annotations;
1512 }
1513 return annotations;
1514 }
1515 // API of tsickle for lowering decorators to properties on the class.
1516 if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) {
1517 return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators);
1518 }
1519 // API for metadata created by invoking the decorators.
1520 if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
1521 return typeOrFunc[ANNOTATIONS];
1522 }
1523 return null;
1524 }
1525 annotations(typeOrFunc) {
1526 if (!isType(typeOrFunc)) {
1527 return [];
1528 }
1529 const parentCtor = getParentCtor(typeOrFunc);
1530 const ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
1531 const parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
1532 return parentAnnotations.concat(ownAnnotations);
1533 }
1534 _ownPropMetadata(typeOrFunc, parentCtor) {
1535 // Prefer the direct API.
1536 if (typeOrFunc.propMetadata &&
1537 typeOrFunc.propMetadata !== parentCtor.propMetadata) {
1538 let propMetadata = typeOrFunc.propMetadata;
1539 if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
1540 propMetadata = propMetadata.propMetadata;
1541 }
1542 return propMetadata;
1543 }
1544 // API of tsickle for lowering decorators to properties on the class.
1545 if (typeOrFunc.propDecorators &&
1546 typeOrFunc.propDecorators !== parentCtor.propDecorators) {
1547 const propDecorators = typeOrFunc.propDecorators;
1548 const propMetadata = {};
1549 Object.keys(propDecorators).forEach(prop => {
1550 propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
1551 });
1552 return propMetadata;
1553 }
1554 // API for metadata created by invoking the decorators.
1555 if (typeOrFunc.hasOwnProperty(PROP_METADATA)) {
1556 return typeOrFunc[PROP_METADATA];
1557 }
1558 return null;
1559 }
1560 propMetadata(typeOrFunc) {
1561 if (!isType(typeOrFunc)) {
1562 return {};
1563 }
1564 const parentCtor = getParentCtor(typeOrFunc);
1565 const propMetadata = {};
1566 if (parentCtor !== Object) {
1567 const parentPropMetadata = this.propMetadata(parentCtor);
1568 Object.keys(parentPropMetadata).forEach((propName) => {
1569 propMetadata[propName] = parentPropMetadata[propName];
1570 });
1571 }
1572 const ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
1573 if (ownPropMetadata) {
1574 Object.keys(ownPropMetadata).forEach((propName) => {
1575 const decorators = [];
1576 if (propMetadata.hasOwnProperty(propName)) {
1577 decorators.push(...propMetadata[propName]);
1578 }
1579 decorators.push(...ownPropMetadata[propName]);
1580 propMetadata[propName] = decorators;
1581 });
1582 }
1583 return propMetadata;
1584 }
1585 ownPropMetadata(typeOrFunc) {
1586 if (!isType(typeOrFunc)) {
1587 return {};
1588 }
1589 return this._ownPropMetadata(typeOrFunc, getParentCtor(typeOrFunc)) || {};
1590 }
1591 hasLifecycleHook(type, lcProperty) {
1592 return type instanceof Type && lcProperty in type.prototype;
1593 }
1594}
1595function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
1596 if (!decoratorInvocations) {
1597 return [];
1598 }
1599 return decoratorInvocations.map(decoratorInvocation => {
1600 const decoratorType = decoratorInvocation.type;
1601 const annotationCls = decoratorType.annotationCls;
1602 const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
1603 return new annotationCls(...annotationArgs);
1604 });
1605}
1606function getParentCtor(ctor) {
1607 const parentProto = ctor.prototype ? Object.getPrototypeOf(ctor.prototype) : null;
1608 const parentCtor = parentProto ? parentProto.constructor : null;
1609 // Note: We always use `Object` as the null value
1610 // to simplify checking later on.
1611 return parentCtor || Object;
1612}
1613
1614function ngDevModeResetPerfCounters() {
1615 const locationString = typeof location !== 'undefined' ? location.toString() : '';
1616 const newCounters = {
1617 namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1,
1618 firstCreatePass: 0,
1619 tNode: 0,
1620 tView: 0,
1621 rendererCreateTextNode: 0,
1622 rendererSetText: 0,
1623 rendererCreateElement: 0,
1624 rendererAddEventListener: 0,
1625 rendererSetAttribute: 0,
1626 rendererRemoveAttribute: 0,
1627 rendererSetProperty: 0,
1628 rendererSetClassName: 0,
1629 rendererAddClass: 0,
1630 rendererRemoveClass: 0,
1631 rendererSetStyle: 0,
1632 rendererRemoveStyle: 0,
1633 rendererDestroy: 0,
1634 rendererDestroyNode: 0,
1635 rendererMoveNode: 0,
1636 rendererRemoveNode: 0,
1637 rendererAppendChild: 0,
1638 rendererInsertBefore: 0,
1639 rendererCreateComment: 0,
1640 };
1641 // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
1642 const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
1643 _global$1['ngDevMode'] = allowNgDevModeTrue && newCounters;
1644 return newCounters;
1645}
1646/**
1647 * This function checks to see if the `ngDevMode` has been set. If yes,
1648 * then we honor it, otherwise we default to dev mode with additional checks.
1649 *
1650 * The idea is that unless we are doing production build where we explicitly
1651 * set `ngDevMode == false` we should be helping the developer by providing
1652 * as much early warning and errors as possible.
1653 *
1654 * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions
1655 * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode
1656 * is defined for the entire instruction set.
1657 *
1658 * When checking `ngDevMode` on toplevel, always init it before referencing it
1659 * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can
1660 * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595.
1661 *
1662 * Details on possible values for `ngDevMode` can be found on its docstring.
1663 *
1664 * NOTE:
1665 * - changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`.
1666 */
1667function initNgDevMode() {
1668 // The below checks are to ensure that calling `initNgDevMode` multiple times does not
1669 // reset the counters.
1670 // If the `ngDevMode` is not an object, then it means we have not created the perf counters
1671 // yet.
1672 if (typeof ngDevMode === 'undefined' || ngDevMode) {
1673 if (typeof ngDevMode !== 'object') {
1674 ngDevModeResetPerfCounters();
1675 }
1676 return typeof ngDevMode !== 'undefined' && !!ngDevMode;
1677 }
1678 return false;
1679}
1680
1681function isEnvironmentProviders(value) {
1682 return value && !!value.ɵproviders;
1683}
1684
1685/**
1686 * Used for stringify render output in Ivy.
1687 * Important! This function is very performance-sensitive and we should
1688 * be extra careful not to introduce megamorphic reads in it.
1689 * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations.
1690 */
1691function renderStringify(value) {
1692 if (typeof value === 'string')
1693 return value;
1694 if (value == null)
1695 return '';
1696 // Use `String` so that it invokes the `toString` method of the value. Note that this
1697 // appears to be faster than calling `value.toString` (see `render_stringify` benchmark).
1698 return String(value);
1699}
1700/**
1701 * Used to stringify a value so that it can be displayed in an error message.
1702 * Important! This function contains a megamorphic read and should only be
1703 * used for error messages.
1704 */
1705function stringifyForError(value) {
1706 if (typeof value === 'function')
1707 return value.name || value.toString();
1708 if (typeof value === 'object' && value != null && typeof value.type === 'function') {
1709 return value.type.name || value.type.toString();
1710 }
1711 return renderStringify(value);
1712}
1713
1714/** Called when directives inject each other (creating a circular dependency) */
1715function throwCyclicDependencyError(token, path) {
1716 const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
1717 throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, `Circular dependency in DI detected for ${token}${depPath}`);
1718}
1719function throwMixedMultiProviderError() {
1720 throw new Error(`Cannot mix multi providers and regular providers`);
1721}
1722function throwInvalidProviderError(ngModuleType, providers, provider) {
1723 if (ngModuleType && providers) {
1724 const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...');
1725 throw new Error(`Invalid provider for the NgModule '${stringify(ngModuleType)}' - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`);
1726 }
1727 else if (isEnvironmentProviders(provider)) {
1728 if (provider.ɵfromNgModule) {
1729 throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, `Invalid providers from 'importProvidersFrom' present in a non-environment injector. 'importProvidersFrom' can't be used for component providers.`);
1730 }
1731 else {
1732 throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, `Invalid providers present in a non-environment injector. 'EnvironmentProviders' can't be used for component providers.`);
1733 }
1734 }
1735 else {
1736 throw new Error('Invalid provider');
1737 }
1738}
1739/** Throws an error when a token is not found in DI. */
1740function throwProviderNotFoundError(token, injectorName) {
1741 const injectorDetails = injectorName ? ` in ${injectorName}` : '';
1742 throw new RuntimeError(-201 /* RuntimeErrorCode.PROVIDER_NOT_FOUND */, ngDevMode && `No provider for ${stringifyForError(token)} found${injectorDetails}`);
1743}
1744
1745/**
1746 * Injection flags for DI.
1747 *
1748 * @publicApi
1749 * @deprecated use an options object for `inject` instead.
1750 */
1751var InjectFlags;
1752(function (InjectFlags) {
1753 // TODO(alxhub): make this 'const' (and remove `InternalInjectFlags` enum) when ngc no longer
1754 // writes exports of it into ngfactory files.
1755 /** Check self and check parent injector if needed */
1756 InjectFlags[InjectFlags["Default"] = 0] = "Default";
1757 /**
1758 * Specifies that an injector should retrieve a dependency from any injector until reaching the
1759 * host element of the current component. (Only used with Element Injector)
1760 */
1761 InjectFlags[InjectFlags["Host"] = 1] = "Host";
1762 /** Don't ascend to ancestors of the node requesting injection. */
1763 InjectFlags[InjectFlags["Self"] = 2] = "Self";
1764 /** Skip the node that is requesting injection. */
1765 InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf";
1766 /** Inject `defaultValue` instead if token not found. */
1767 InjectFlags[InjectFlags["Optional"] = 8] = "Optional";
1768})(InjectFlags || (InjectFlags = {}));
1769
1770/**
1771 * Current implementation of inject.
1772 *
1773 * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
1774 * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
1775 * way for two reasons:
1776 * 1. `Injector` should not depend on ivy logic.
1777 * 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
1778 */
1779let _injectImplementation;
1780function getInjectImplementation() {
1781 return _injectImplementation;
1782}
1783/**
1784 * Sets the current inject implementation.
1785 */
1786function setInjectImplementation(impl) {
1787 const previous = _injectImplementation;
1788 _injectImplementation = impl;
1789 return previous;
1790}
1791/**
1792 * Injects `root` tokens in limp mode.
1793 *
1794 * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
1795 * `"root"`. This is known as the limp mode injection. In such case the value is stored in the
1796 * injectable definition.
1797 */
1798function injectRootLimpMode(token, notFoundValue, flags) {
1799 const injectableDef = getInjectableDef(token);
1800 if (injectableDef && injectableDef.providedIn == 'root') {
1801 return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
1802 injectableDef.value;
1803 }
1804 if (flags & InjectFlags.Optional)
1805 return null;
1806 if (notFoundValue !== undefined)
1807 return notFoundValue;
1808 throwProviderNotFoundError(stringify(token), 'Injector');
1809}
1810/**
1811 * Assert that `_injectImplementation` is not `fn`.
1812 *
1813 * This is useful, to prevent infinite recursion.
1814 *
1815 * @param fn Function which it should not equal to
1816 */
1817function assertInjectImplementationNotEqual(fn) {
1818 ngDevMode &&
1819 assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion');
1820}
1821
1822const _THROW_IF_NOT_FOUND = {};
1823const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
1824/*
1825 * Name of a property (that we patch onto DI decorator), which is used as an annotation of which
1826 * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators
1827 * in the code, thus making them tree-shakable.
1828 */
1829const DI_DECORATOR_FLAG = '__NG_DI_FLAG__';
1830const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath';
1831const NG_TOKEN_PATH = 'ngTokenPath';
1832const NEW_LINE = /\n/gm;
1833const NO_NEW_LINE = 'ɵ';
1834const SOURCE = '__source';
1835/**
1836 * Current injector value used by `inject`.
1837 * - `undefined`: it is an error to call `inject`
1838 * - `null`: `inject` can be called but there is no injector (limp-mode).
1839 * - Injector instance: Use the injector for resolution.
1840 */
1841let _currentInjector = undefined;
1842function setCurrentInjector(injector) {
1843 const former = _currentInjector;
1844 _currentInjector = injector;
1845 return former;
1846}
1847function injectInjectorOnly(token, flags = InjectFlags.Default) {
1848 if (_currentInjector === undefined) {
1849 throw new RuntimeError(-203 /* RuntimeErrorCode.MISSING_INJECTION_CONTEXT */, ngDevMode &&
1850 `inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with \`EnvironmentInjector#runInContext\`.`);
1851 }
1852 else if (_currentInjector === null) {
1853 return injectRootLimpMode(token, undefined, flags);
1854 }
1855 else {
1856 return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
1857 }
1858}
1859function ɵɵinject(token, flags = InjectFlags.Default) {
1860 return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef(token), flags);
1861}
1862/**
1863 * Throws an error indicating that a factory function could not be generated by the compiler for a
1864 * particular class.
1865 *
1866 * The name of the class is not mentioned here, but will be in the generated factory function name
1867 * and thus in the stack trace.
1868 *
1869 * @codeGenApi
1870 */
1871function ɵɵinvalidFactoryDep(index) {
1872 throw new RuntimeError(202 /* RuntimeErrorCode.INVALID_FACTORY_DEPENDENCY */, ngDevMode &&
1873 `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${index} of the parameter list is invalid.
1874This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.
1875
1876Please 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.`);
1877}
1878/**
1879 * Injects a token from the currently active injector.
1880 * `inject` is only supported during instantiation of a dependency by the DI system. It can be used
1881 * during:
1882 * - Construction (via the `constructor`) of a class being instantiated by the DI system, such
1883 * as an `@Injectable` or `@Component`.
1884 * - In the initializer for fields of such classes.
1885 * - In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`.
1886 * - In the `factory` function specified for an `InjectionToken`.
1887 *
1888 * @param token A token that represents a dependency that should be injected.
1889 * @param flags Optional flags that control how injection is executed.
1890 * The flags correspond to injection strategies that can be specified with
1891 * parameter decorators `@Host`, `@Self`, `@SkipSelf`, and `@Optional`.
1892 * @returns the injected value if operation is successful, `null` otherwise.
1893 * @throws if called outside of a supported context.
1894 *
1895 * @usageNotes
1896 * In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a
1897 * field initializer:
1898 *
1899 * ```typescript
1900 * @Injectable({providedIn: 'root'})
1901 * export class Car {
1902 * radio: Radio|undefined;
1903 * // OK: field initializer
1904 * spareTyre = inject(Tyre);
1905 *
1906 * constructor() {
1907 * // OK: constructor body
1908 * this.radio = inject(Radio);
1909 * }
1910 * }
1911 * ```
1912 *
1913 * It is also legal to call `inject` from a provider's factory:
1914 *
1915 * ```typescript
1916 * providers: [
1917 * {provide: Car, useFactory: () => {
1918 * // OK: a class factory
1919 * const engine = inject(Engine);
1920 * return new Car(engine);
1921 * }}
1922 * ]
1923 * ```
1924 *
1925 * Calls to the `inject()` function outside of the class creation context will result in error. Most
1926 * notably, calls to `inject()` are disallowed after a class instance was created, in methods
1927 * (including lifecycle hooks):
1928 *
1929 * ```typescript
1930 * @Component({ ... })
1931 * export class CarComponent {
1932 * ngOnInit() {
1933 * // ERROR: too late, the component instance was already created
1934 * const engine = inject(Engine);
1935 * engine.start();
1936 * }
1937 * }
1938 * ```
1939 *
1940 * @publicApi
1941 */
1942function inject$1(token, flags = InjectFlags.Default) {
1943 return ɵɵinject(token, convertToBitFlags(flags));
1944}
1945// Converts object-based DI flags (`InjectOptions`) to bit flags (`InjectFlags`).
1946function convertToBitFlags(flags) {
1947 if (typeof flags === 'undefined' || typeof flags === 'number') {
1948 return flags;
1949 }
1950 // While TypeScript doesn't accept it without a cast, bitwise OR with false-y values in
1951 // JavaScript is a no-op. We can use that for a very codesize-efficient conversion from
1952 // `InjectOptions` to `InjectFlags`.
1953 return (0 /* InternalInjectFlags.Default */ | // comment to force a line break in the formatter
1954 (flags.optional && 8 /* InternalInjectFlags.Optional */) |
1955 (flags.host && 1 /* InternalInjectFlags.Host */) |
1956 (flags.self && 2 /* InternalInjectFlags.Self */) |
1957 (flags.skipSelf && 4 /* InternalInjectFlags.SkipSelf */));
1958}
1959function injectArgs(types) {
1960 const args = [];
1961 for (let i = 0; i < types.length; i++) {
1962 const arg = resolveForwardRef(types[i]);
1963 if (Array.isArray(arg)) {
1964 if (arg.length === 0) {
1965 throw new RuntimeError(900 /* RuntimeErrorCode.INVALID_DIFFER_INPUT */, ngDevMode && 'Arguments array must have arguments.');
1966 }
1967 let type = undefined;
1968 let flags = InjectFlags.Default;
1969 for (let j = 0; j < arg.length; j++) {
1970 const meta = arg[j];
1971 const flag = getInjectFlag(meta);
1972 if (typeof flag === 'number') {
1973 // Special case when we handle @Inject decorator.
1974 if (flag === -1 /* DecoratorFlags.Inject */) {
1975 type = meta.token;
1976 }
1977 else {
1978 flags |= flag;
1979 }
1980 }
1981 else {
1982 type = meta;
1983 }
1984 }
1985 args.push(ɵɵinject(type, flags));
1986 }
1987 else {
1988 args.push(ɵɵinject(arg));
1989 }
1990 }
1991 return args;
1992}
1993/**
1994 * Attaches a given InjectFlag to a given decorator using monkey-patching.
1995 * Since DI decorators can be used in providers `deps` array (when provider is configured using
1996 * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we
1997 * attach the flag to make it available both as a static property and as a field on decorator
1998 * instance.
1999 *
2000 * @param decorator Provided DI decorator.
2001 * @param flag InjectFlag that should be applied.
2002 */
2003function attachInjectFlag(decorator, flag) {
2004 decorator[DI_DECORATOR_FLAG] = flag;
2005 decorator.prototype[DI_DECORATOR_FLAG] = flag;
2006 return decorator;
2007}
2008/**
2009 * Reads monkey-patched property that contains InjectFlag attached to a decorator.
2010 *
2011 * @param token Token that may contain monkey-patched DI flags property.
2012 */
2013function getInjectFlag(token) {
2014 return token[DI_DECORATOR_FLAG];
2015}
2016function catchInjectorError(e, token, injectorErrorName, source) {
2017 const tokenPath = e[NG_TEMP_TOKEN_PATH];
2018 if (token[SOURCE]) {
2019 tokenPath.unshift(token[SOURCE]);
2020 }
2021 e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source);
2022 e[NG_TOKEN_PATH] = tokenPath;
2023 e[NG_TEMP_TOKEN_PATH] = null;
2024 throw e;
2025}
2026function formatError(text, obj, injectorErrorName, source = null) {
2027 text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.slice(2) : text;
2028 let context = stringify(obj);
2029 if (Array.isArray(obj)) {
2030 context = obj.map(stringify).join(' -> ');
2031 }
2032 else if (typeof obj === 'object') {
2033 let parts = [];
2034 for (let key in obj) {
2035 if (obj.hasOwnProperty(key)) {
2036 let value = obj[key];
2037 parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value)));
2038 }
2039 }
2040 context = `{${parts.join(', ')}}`;
2041 }
2042 return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
2043}
2044
2045/**
2046 * Inject decorator and metadata.
2047 *
2048 * @Annotation
2049 * @publicApi
2050 */
2051const Inject = attachInjectFlag(
2052// Disable tslint because `DecoratorFlags` is a const enum which gets inlined.
2053// tslint:disable-next-line: no-toplevel-property-access
2054makeParamDecorator('Inject', (token) => ({ token })), -1 /* DecoratorFlags.Inject */);
2055/**
2056 * Optional decorator and metadata.
2057 *
2058 * @Annotation
2059 * @publicApi
2060 */
2061const Optional =
2062// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
2063// tslint:disable-next-line: no-toplevel-property-access
2064attachInjectFlag(makeParamDecorator('Optional'), 8 /* InternalInjectFlags.Optional */);
2065/**
2066 * Self decorator and metadata.
2067 *
2068 * @Annotation
2069 * @publicApi
2070 */
2071const Self =
2072// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
2073// tslint:disable-next-line: no-toplevel-property-access
2074attachInjectFlag(makeParamDecorator('Self'), 2 /* InternalInjectFlags.Self */);
2075/**
2076 * `SkipSelf` decorator and metadata.
2077 *
2078 * @Annotation
2079 * @publicApi
2080 */
2081const SkipSelf =
2082// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
2083// tslint:disable-next-line: no-toplevel-property-access
2084attachInjectFlag(makeParamDecorator('SkipSelf'), 4 /* InternalInjectFlags.SkipSelf */);
2085/**
2086 * Host decorator and metadata.
2087 *
2088 * @Annotation
2089 * @publicApi
2090 */
2091const Host =
2092// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
2093// tslint:disable-next-line: no-toplevel-property-access
2094attachInjectFlag(makeParamDecorator('Host'), 1 /* InternalInjectFlags.Host */);
2095
2096/**
2097 * The strategy that the default change detector uses to detect changes.
2098 * When set, takes effect the next time change detection is triggered.
2099 *
2100 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
2101 *
2102 * @publicApi
2103 */
2104var ChangeDetectionStrategy;
2105(function (ChangeDetectionStrategy) {
2106 /**
2107 * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated
2108 * until reactivated by setting the strategy to `Default` (`CheckAlways`).
2109 * Change detection can still be explicitly invoked.
2110 * This strategy applies to all child directives and cannot be overridden.
2111 */
2112 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
2113 /**
2114 * Use the default `CheckAlways` strategy, in which change detection is automatic until
2115 * explicitly deactivated.
2116 */
2117 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
2118})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
2119/**
2120 * Defines the possible states of the default change detector.
2121 * @see `ChangeDetectorRef`
2122 */
2123var ChangeDetectorStatus;
2124(function (ChangeDetectorStatus) {
2125 /**
2126 * A state in which, after calling `detectChanges()`, the change detector
2127 * state becomes `Checked`, and must be explicitly invoked or reactivated.
2128 */
2129 ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce";
2130 /**
2131 * A state in which change detection is skipped until the change detector mode
2132 * becomes `CheckOnce`.
2133 */
2134 ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked";
2135 /**
2136 * A state in which change detection continues automatically until explicitly
2137 * deactivated.
2138 */
2139 ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways";
2140 /**
2141 * A state in which a change detector sub tree is not a part of the main tree and
2142 * should be skipped.
2143 */
2144 ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached";
2145 /**
2146 * Indicates that the change detector encountered an error checking a binding
2147 * or calling a directive lifecycle method and is now in an inconsistent state. Change
2148 * detectors in this state do not detect changes.
2149 */
2150 ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored";
2151 /**
2152 * Indicates that the change detector has been destroyed.
2153 */
2154 ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed";
2155})(ChangeDetectorStatus || (ChangeDetectorStatus = {}));
2156/**
2157 * Reports whether a given strategy is currently the default for change detection.
2158 * @param changeDetectionStrategy The strategy to check.
2159 * @returns True if the given strategy is the current default, false otherwise.
2160 * @see `ChangeDetectorStatus`
2161 * @see `ChangeDetectorRef`
2162 */
2163function isDefaultChangeDetectionStrategy(changeDetectionStrategy) {
2164 return changeDetectionStrategy == null ||
2165 changeDetectionStrategy === ChangeDetectionStrategy.Default;
2166}
2167
2168/**
2169 * Defines the CSS styles encapsulation policies for the {@link Component} decorator's
2170 * `encapsulation` option.
2171 *
2172 * See {@link Component#encapsulation encapsulation}.
2173 *
2174 * @usageNotes
2175 * ### Example
2176 *
2177 * {@example core/ts/metadata/encapsulation.ts region='longform'}
2178 *
2179 * @publicApi
2180 */
2181var ViewEncapsulation;
2182(function (ViewEncapsulation) {
2183 // TODO: consider making `ViewEncapsulation` a `const enum` instead. See
2184 // https://github.com/angular/angular/issues/44119 for additional information.
2185 /**
2186 * Emulates a native Shadow DOM encapsulation behavior by adding a specific attribute to the
2187 * component's host element and applying the same attribute to all the CSS selectors provided
2188 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls}.
2189 *
2190 * This is the default option.
2191 */
2192 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
2193 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
2194 /**
2195 * Doesn't provide any sort of CSS style encapsulation, meaning that all the styles provided
2196 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls} are applicable
2197 * to any HTML element of the application regardless of their host Component.
2198 */
2199 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
2200 /**
2201 * Uses the browser's native Shadow DOM API to encapsulate CSS styles, meaning that it creates
2202 * a ShadowRoot for the component's host element which is then used to encapsulate
2203 * all the Component's styling.
2204 */
2205 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
2206})(ViewEncapsulation || (ViewEncapsulation = {}));
2207
2208/**
2209 * This file contains reuseable "empty" symbols that can be used as default return values
2210 * in different parts of the rendering code. Because the same symbols are returned, this
2211 * allows for identity checks against these values to be consistently used by the framework
2212 * code.
2213 */
2214const EMPTY_OBJ = {};
2215const EMPTY_ARRAY = [];
2216// freezing the values prevents any code from accidentally inserting new values in
2217if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
2218 // These property accesses can be ignored because ngDevMode will be set to false
2219 // when optimizing code and the whole if statement will be dropped.
2220 // tslint:disable-next-line:no-toplevel-property-access
2221 Object.freeze(EMPTY_OBJ);
2222 // tslint:disable-next-line:no-toplevel-property-access
2223 Object.freeze(EMPTY_ARRAY);
2224}
2225
2226const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty });
2227const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty });
2228const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty });
2229const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty });
2230const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty });
2231/**
2232 * If a directive is diPublic, bloomAdd sets a property on the type with this constant as
2233 * the key and the directive's unique ID as the value. This allows us to map directives to their
2234 * bloom filter bit for DI.
2235 */
2236// TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified.
2237const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty });
2238
2239/** Counter used to generate unique IDs for component definitions. */
2240let componentDefCount = 0;
2241/**
2242 * Create a component definition object.
2243 *
2244 *
2245 * # Example
2246 * ```
2247 * class MyDirective {
2248 * // Generated by Angular Template Compiler
2249 * // [Symbol] syntax will not be supported by TypeScript until v2.7
2250 * static ɵcmp = defineComponent({
2251 * ...
2252 * });
2253 * }
2254 * ```
2255 * @codeGenApi
2256 */
2257function ɵɵdefineComponent(componentDefinition) {
2258 return noSideEffects(() => {
2259 // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
2260 // See the `initNgDevMode` docstring for more information.
2261 (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
2262 const type = componentDefinition.type;
2263 const standalone = componentDefinition.standalone === true;
2264 const declaredInputs = {};
2265 const def = {
2266 type: type,
2267 providersResolver: null,
2268 decls: componentDefinition.decls,
2269 vars: componentDefinition.vars,
2270 factory: null,
2271 template: componentDefinition.template || null,
2272 consts: componentDefinition.consts || null,
2273 ngContentSelectors: componentDefinition.ngContentSelectors,
2274 hostBindings: componentDefinition.hostBindings || null,
2275 hostVars: componentDefinition.hostVars || 0,
2276 hostAttrs: componentDefinition.hostAttrs || null,
2277 contentQueries: componentDefinition.contentQueries || null,
2278 declaredInputs: declaredInputs,
2279 inputs: null,
2280 outputs: null,
2281 exportAs: componentDefinition.exportAs || null,
2282 onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
2283 directiveDefs: null,
2284 pipeDefs: null,
2285 standalone,
2286 dependencies: standalone && componentDefinition.dependencies || null,
2287 getStandaloneInjector: null,
2288 selectors: componentDefinition.selectors || EMPTY_ARRAY,
2289 viewQuery: componentDefinition.viewQuery || null,
2290 features: componentDefinition.features || null,
2291 data: componentDefinition.data || {},
2292 encapsulation: componentDefinition.encapsulation || ViewEncapsulation.Emulated,
2293 id: `c${componentDefCount++}`,
2294 styles: componentDefinition.styles || EMPTY_ARRAY,
2295 _: null,
2296 setInput: null,
2297 schemas: componentDefinition.schemas || null,
2298 tView: null,
2299 findHostDirectiveDefs: null,
2300 hostDirectives: null,
2301 };
2302 const dependencies = componentDefinition.dependencies;
2303 const feature = componentDefinition.features;
2304 def.inputs = invertObject(componentDefinition.inputs, declaredInputs),
2305 def.outputs = invertObject(componentDefinition.outputs),
2306 feature && feature.forEach((fn) => fn(def));
2307 def.directiveDefs = dependencies ?
2308 (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
2309 .map(extractDirectiveDef)
2310 .filter(nonNull)) :
2311 null;
2312 def.pipeDefs = dependencies ?
2313 (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
2314 .map(getPipeDef$1)
2315 .filter(nonNull)) :
2316 null;
2317 return def;
2318 });
2319}
2320/**
2321 * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
2322 * definition, when generating a direct reference in the component file would otherwise create an
2323 * import cycle.
2324 *
2325 * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
2326 *
2327 * @codeGenApi
2328 */
2329function ɵɵsetComponentScope(type, directives, pipes) {
2330 const def = type.ɵcmp;
2331 def.directiveDefs = () => (typeof directives === 'function' ? directives() : directives).map(extractDirectiveDef);
2332 def.pipeDefs = () => (typeof pipes === 'function' ? pipes() : pipes).map(getPipeDef$1);
2333}
2334function extractDirectiveDef(type) {
2335 return getComponentDef$1(type) || getDirectiveDef(type);
2336}
2337function nonNull(value) {
2338 return value !== null;
2339}
2340/**
2341 * @codeGenApi
2342 */
2343function ɵɵdefineNgModule(def) {
2344 return noSideEffects(() => {
2345 const res = {
2346 type: def.type,
2347 bootstrap: def.bootstrap || EMPTY_ARRAY,
2348 declarations: def.declarations || EMPTY_ARRAY,
2349 imports: def.imports || EMPTY_ARRAY,
2350 exports: def.exports || EMPTY_ARRAY,
2351 transitiveCompileScopes: null,
2352 schemas: def.schemas || null,
2353 id: def.id || null,
2354 };
2355 return res;
2356 });
2357}
2358/**
2359 * Adds the module metadata that is necessary to compute the module's transitive scope to an
2360 * existing module definition.
2361 *
2362 * Scope metadata of modules is not used in production builds, so calls to this function can be
2363 * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
2364 * to become eligible for tree-shaking as well.
2365 *
2366 * @codeGenApi
2367 */
2368function ɵɵsetNgModuleScope(type, scope) {
2369 return noSideEffects(() => {
2370 const ngModuleDef = getNgModuleDef(type, true);
2371 ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
2372 ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
2373 ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
2374 });
2375}
2376/**
2377 * Inverts an inputs or outputs lookup such that the keys, which were the
2378 * minified keys, are part of the values, and the values are parsed so that
2379 * the publicName of the property is the new key
2380 *
2381 * e.g. for
2382 *
2383 * ```
2384 * class Comp {
2385 * @Input()
2386 * propName1: string;
2387 *
2388 * @Input('publicName2')
2389 * declaredPropName2: number;
2390 * }
2391 * ```
2392 *
2393 * will be serialized as
2394 *
2395 * ```
2396 * {
2397 * propName1: 'propName1',
2398 * declaredPropName2: ['publicName2', 'declaredPropName2'],
2399 * }
2400 * ```
2401 *
2402 * which is than translated by the minifier as:
2403 *
2404 * ```
2405 * {
2406 * minifiedPropName1: 'propName1',
2407 * minifiedPropName2: ['publicName2', 'declaredPropName2'],
2408 * }
2409 * ```
2410 *
2411 * becomes: (public name => minifiedName)
2412 *
2413 * ```
2414 * {
2415 * 'propName1': 'minifiedPropName1',
2416 * 'publicName2': 'minifiedPropName2',
2417 * }
2418 * ```
2419 *
2420 * Optionally the function can take `secondary` which will result in: (public name => declared name)
2421 *
2422 * ```
2423 * {
2424 * 'propName1': 'propName1',
2425 * 'publicName2': 'declaredPropName2',
2426 * }
2427 * ```
2428 *
2429
2430 */
2431function invertObject(obj, secondary) {
2432 if (obj == null)
2433 return EMPTY_OBJ;
2434 const newLookup = {};
2435 for (const minifiedKey in obj) {
2436 if (obj.hasOwnProperty(minifiedKey)) {
2437 let publicName = obj[minifiedKey];
2438 let declaredName = publicName;
2439 if (Array.isArray(publicName)) {
2440 declaredName = publicName[1];
2441 publicName = publicName[0];
2442 }
2443 newLookup[publicName] = minifiedKey;
2444 if (secondary) {
2445 (secondary[publicName] = declaredName);
2446 }
2447 }
2448 }
2449 return newLookup;
2450}
2451/**
2452 * Create a directive definition object.
2453 *
2454 * # Example
2455 * ```ts
2456 * class MyDirective {
2457 * // Generated by Angular Template Compiler
2458 * // [Symbol] syntax will not be supported by TypeScript until v2.7
2459 * static ɵdir = ɵɵdefineDirective({
2460 * ...
2461 * });
2462 * }
2463 * ```
2464 *
2465 * @codeGenApi
2466 */
2467const ɵɵdefineDirective = ɵɵdefineComponent;
2468/**
2469 * Create a pipe definition object.
2470 *
2471 * # Example
2472 * ```
2473 * class MyPipe implements PipeTransform {
2474 * // Generated by Angular Template Compiler
2475 * static ɵpipe = definePipe({
2476 * ...
2477 * });
2478 * }
2479 * ```
2480 * @param pipeDef Pipe definition generated by the compiler
2481 *
2482 * @codeGenApi
2483 */
2484function ɵɵdefinePipe(pipeDef) {
2485 return {
2486 type: pipeDef.type,
2487 name: pipeDef.name,
2488 factory: null,
2489 pure: pipeDef.pure !== false,
2490 standalone: pipeDef.standalone === true,
2491 onDestroy: pipeDef.type.prototype.ngOnDestroy || null
2492 };
2493}
2494/**
2495 * The following getter methods retrieve the definition from the type. Currently the retrieval
2496 * honors inheritance, but in the future we may change the rule to require that definitions are
2497 * explicit. This would require some sort of migration strategy.
2498 */
2499function getComponentDef$1(type) {
2500 return type[NG_COMP_DEF] || null;
2501}
2502function getDirectiveDef(type) {
2503 return type[NG_DIR_DEF] || null;
2504}
2505function getPipeDef$1(type) {
2506 return type[NG_PIPE_DEF] || null;
2507}
2508/**
2509 * Checks whether a given Component, Directive or Pipe is marked as standalone.
2510 * This will return false if passed anything other than a Component, Directive, or Pipe class
2511 * See this guide for additional information: https://angular.io/guide/standalone-components
2512 *
2513 * @param type A reference to a Component, Directive or Pipe.
2514 * @publicApi
2515 */
2516function isStandalone(type) {
2517 const def = getComponentDef$1(type) || getDirectiveDef(type) || getPipeDef$1(type);
2518 return def !== null ? def.standalone : false;
2519}
2520function getNgModuleDef(type, throwNotFound) {
2521 const ngModuleDef = type[NG_MOD_DEF] || null;
2522 if (!ngModuleDef && throwNotFound === true) {
2523 throw new Error(`Type ${stringify(type)} does not have 'ɵmod' property.`);
2524 }
2525 return ngModuleDef;
2526}
2527
2528/**
2529 * Special location which allows easy identification of type. If we have an array which was
2530 * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
2531 * `LContainer`.
2532 */
2533const TYPE = 1;
2534/**
2535 * Below are constants for LContainer indices to help us look up LContainer members
2536 * without having to remember the specific indices.
2537 * Uglify will inline these when minifying so there shouldn't be a cost.
2538 */
2539/**
2540 * Flag to signify that this `LContainer` may have transplanted views which need to be change
2541 * detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
2542 *
2543 * This flag, once set, is never unset for the `LContainer`. This means that when unset we can skip
2544 * a lot of work in `refreshEmbeddedViews`. But when set we still need to verify
2545 * that the `MOVED_VIEWS` are transplanted and on-push.
2546 */
2547const HAS_TRANSPLANTED_VIEWS = 2;
2548// PARENT, NEXT, TRANSPLANTED_VIEWS_TO_REFRESH are indices 3, 4, and 5
2549// As we already have these constants in LView, we don't need to re-create them.
2550// T_HOST is index 6
2551// We already have this constants in LView, we don't need to re-create it.
2552const NATIVE = 7;
2553const VIEW_REFS = 8;
2554const MOVED_VIEWS = 9;
2555/**
2556 * Size of LContainer's header. Represents the index after which all views in the
2557 * container will be inserted. We need to keep a record of current views so we know
2558 * which views are already in the DOM (and don't need to be re-added) and so we can
2559 * remove views from the DOM when they are no longer required.
2560 */
2561const CONTAINER_HEADER_OFFSET = 10;
2562// Note: This hack is necessary so we don't erroneously get a circular dependency
2563// failure based on types.
2564const unusedValueExportToPlacateAjd$4 = 1;
2565
2566// Below are constants for LView indices to help us look up LView members
2567// without having to remember the specific indices.
2568// Uglify will inline these when minifying so there shouldn't be a cost.
2569const HOST = 0;
2570const TVIEW = 1;
2571const FLAGS = 2;
2572const PARENT = 3;
2573const NEXT = 4;
2574const TRANSPLANTED_VIEWS_TO_REFRESH = 5;
2575const T_HOST = 6;
2576const CLEANUP = 7;
2577const CONTEXT = 8;
2578const INJECTOR$1 = 9;
2579const RENDERER_FACTORY = 10;
2580const RENDERER = 11;
2581const SANITIZER = 12;
2582const CHILD_HEAD = 13;
2583const CHILD_TAIL = 14;
2584// FIXME(misko): Investigate if the three declarations aren't all same thing.
2585const DECLARATION_VIEW = 15;
2586const DECLARATION_COMPONENT_VIEW = 16;
2587const DECLARATION_LCONTAINER = 17;
2588const PREORDER_HOOK_FLAGS = 18;
2589const QUERIES = 19;
2590const ID = 20;
2591const EMBEDDED_VIEW_INJECTOR = 21;
2592/**
2593 * Size of LView's header. Necessary to adjust for it when setting slots.
2594 *
2595 * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
2596 * instruction index into `LView` index. All other indexes should be in the `LView` index space and
2597 * there should be no need to refer to `HEADER_OFFSET` anywhere else.
2598 */
2599const HEADER_OFFSET = 22;
2600// Note: This hack is necessary so we don't erroneously get a circular dependency
2601// failure based on types.
2602const unusedValueExportToPlacateAjd$3 = 1;
2603
2604/**
2605 * True if `value` is `LView`.
2606 * @param value wrapped value of `RNode`, `LView`, `LContainer`
2607 */
2608function isLView(value) {
2609 return Array.isArray(value) && typeof value[TYPE] === 'object';
2610}
2611/**
2612 * True if `value` is `LContainer`.
2613 * @param value wrapped value of `RNode`, `LView`, `LContainer`
2614 */
2615function isLContainer(value) {
2616 return Array.isArray(value) && value[TYPE] === true;
2617}
2618function isContentQueryHost(tNode) {
2619 return (tNode.flags & 4 /* TNodeFlags.hasContentQuery */) !== 0;
2620}
2621function isComponentHost(tNode) {
2622 return tNode.componentOffset > -1;
2623}
2624function isDirectiveHost(tNode) {
2625 return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
2626}
2627function isComponentDef(def) {
2628 return def.template !== null;
2629}
2630function isRootView(target) {
2631 return (target[FLAGS] & 256 /* LViewFlags.IsRoot */) !== 0;
2632}
2633
2634// [Assert functions do not constraint type when they are guarded by a truthy
2635// expression.](https://github.com/microsoft/TypeScript/issues/37295)
2636function assertTNodeForLView(tNode, lView) {
2637 assertTNodeForTView(tNode, lView[TVIEW]);
2638}
2639function assertTNodeForTView(tNode, tView) {
2640 assertTNode(tNode);
2641 tNode.hasOwnProperty('tView_') &&
2642 assertEqual(tNode.tView_, tView, 'This TNode does not belong to this TView.');
2643}
2644function assertTNode(tNode) {
2645 assertDefined(tNode, 'TNode must be defined');
2646 if (!(tNode && typeof tNode === 'object' && tNode.hasOwnProperty('directiveStylingLast'))) {
2647 throwError('Not of type TNode, got: ' + tNode);
2648 }
2649}
2650function assertTIcu(tIcu) {
2651 assertDefined(tIcu, 'Expected TIcu to be defined');
2652 if (!(typeof tIcu.currentCaseLViewIndex === 'number')) {
2653 throwError('Object is not of TIcu type.');
2654 }
2655}
2656function assertComponentType(actual, msg = 'Type passed in is not ComponentType, it does not have \'ɵcmp\' property.') {
2657 if (!getComponentDef$1(actual)) {
2658 throwError(msg);
2659 }
2660}
2661function assertNgModuleType(actual, msg = 'Type passed in is not NgModuleType, it does not have \'ɵmod\' property.') {
2662 if (!getNgModuleDef(actual)) {
2663 throwError(msg);
2664 }
2665}
2666function assertCurrentTNodeIsParent(isParent) {
2667 assertEqual(isParent, true, 'currentTNode should be a parent');
2668}
2669function assertHasParent(tNode) {
2670 assertDefined(tNode, 'currentTNode should exist!');
2671 assertDefined(tNode.parent, 'currentTNode should have a parent');
2672}
2673function assertLContainer(value) {
2674 assertDefined(value, 'LContainer must be defined');
2675 assertEqual(isLContainer(value), true, 'Expecting LContainer');
2676}
2677function assertLViewOrUndefined(value) {
2678 value && assertEqual(isLView(value), true, 'Expecting LView or undefined or null');
2679}
2680function assertLView(value) {
2681 assertDefined(value, 'LView must be defined');
2682 assertEqual(isLView(value), true, 'Expecting LView');
2683}
2684function assertFirstCreatePass(tView, errMessage) {
2685 assertEqual(tView.firstCreatePass, true, errMessage || 'Should only be called in first create pass.');
2686}
2687function assertFirstUpdatePass(tView, errMessage) {
2688 assertEqual(tView.firstUpdatePass, true, errMessage || 'Should only be called in first update pass.');
2689}
2690/**
2691 * This is a basic sanity check that an object is probably a directive def. DirectiveDef is
2692 * an interface, so we can't do a direct instanceof check.
2693 */
2694function assertDirectiveDef(obj) {
2695 if (obj.type === undefined || obj.selectors == undefined || obj.inputs === undefined) {
2696 throwError(`Expected a DirectiveDef/ComponentDef and this object does not seem to have the expected shape.`);
2697 }
2698}
2699function assertIndexInDeclRange(lView, index) {
2700 const tView = lView[1];
2701 assertBetween(HEADER_OFFSET, tView.bindingStartIndex, index);
2702}
2703function assertIndexInExpandoRange(lView, index) {
2704 const tView = lView[1];
2705 assertBetween(tView.expandoStartIndex, lView.length, index);
2706}
2707function assertBetween(lower, upper, index) {
2708 if (!(lower <= index && index < upper)) {
2709 throwError(`Index out of range (expecting ${lower} <= ${index} < ${upper})`);
2710 }
2711}
2712function assertProjectionSlots(lView, errMessage) {
2713 assertDefined(lView[DECLARATION_COMPONENT_VIEW], 'Component views should exist.');
2714 assertDefined(lView[DECLARATION_COMPONENT_VIEW][T_HOST].projection, errMessage ||
2715 'Components with projection nodes (<ng-content>) must have projection slots defined.');
2716}
2717function assertParentView(lView, errMessage) {
2718 assertDefined(lView, errMessage || 'Component views should always have a parent view (component\'s host view)');
2719}
2720/**
2721 * This is a basic sanity check that the `injectorIndex` seems to point to what looks like a
2722 * NodeInjector data structure.
2723 *
2724 * @param lView `LView` which should be checked.
2725 * @param injectorIndex index into the `LView` where the `NodeInjector` is expected.
2726 */
2727function assertNodeInjector(lView, injectorIndex) {
2728 assertIndexInExpandoRange(lView, injectorIndex);
2729 assertIndexInExpandoRange(lView, injectorIndex + 8 /* NodeInjectorOffset.PARENT */);
2730 assertNumber(lView[injectorIndex + 0], 'injectorIndex should point to a bloom filter');
2731 assertNumber(lView[injectorIndex + 1], 'injectorIndex should point to a bloom filter');
2732 assertNumber(lView[injectorIndex + 2], 'injectorIndex should point to a bloom filter');
2733 assertNumber(lView[injectorIndex + 3], 'injectorIndex should point to a bloom filter');
2734 assertNumber(lView[injectorIndex + 4], 'injectorIndex should point to a bloom filter');
2735 assertNumber(lView[injectorIndex + 5], 'injectorIndex should point to a bloom filter');
2736 assertNumber(lView[injectorIndex + 6], 'injectorIndex should point to a bloom filter');
2737 assertNumber(lView[injectorIndex + 7], 'injectorIndex should point to a bloom filter');
2738 assertNumber(lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */], 'injectorIndex should point to parent injector');
2739}
2740
2741function getFactoryDef(type, throwNotFound) {
2742 const hasFactoryDef = type.hasOwnProperty(NG_FACTORY_DEF);
2743 if (!hasFactoryDef && throwNotFound === true && ngDevMode) {
2744 throw new Error(`Type ${stringify(type)} does not have 'ɵfac' property.`);
2745 }
2746 return hasFactoryDef ? type[NG_FACTORY_DEF] : null;
2747}
2748
2749/**
2750 * Represents a basic change from a previous to a new value for a single
2751 * property on a directive instance. Passed as a value in a
2752 * {@link SimpleChanges} object to the `ngOnChanges` hook.
2753 *
2754 * @see `OnChanges`
2755 *
2756 * @publicApi
2757 */
2758class SimpleChange {
2759 constructor(previousValue, currentValue, firstChange) {
2760 this.previousValue = previousValue;
2761 this.currentValue = currentValue;
2762 this.firstChange = firstChange;
2763 }
2764 /**
2765 * Check whether the new value is the first value assigned.
2766 */
2767 isFirstChange() {
2768 return this.firstChange;
2769 }
2770}
2771
2772/**
2773 * The NgOnChangesFeature decorates a component with support for the ngOnChanges
2774 * lifecycle hook, so it should be included in any component that implements
2775 * that hook.
2776 *
2777 * If the component or directive uses inheritance, the NgOnChangesFeature MUST
2778 * be included as a feature AFTER {@link InheritDefinitionFeature}, otherwise
2779 * inherited properties will not be propagated to the ngOnChanges lifecycle
2780 * hook.
2781 *
2782 * Example usage:
2783 *
2784 * ```
2785 * static ɵcmp = defineComponent({
2786 * ...
2787 * inputs: {name: 'publicName'},
2788 * features: [NgOnChangesFeature]
2789 * });
2790 * ```
2791 *
2792 * @codeGenApi
2793 */
2794function ɵɵNgOnChangesFeature() {
2795 return NgOnChangesFeatureImpl;
2796}
2797function NgOnChangesFeatureImpl(definition) {
2798 if (definition.type.prototype.ngOnChanges) {
2799 definition.setInput = ngOnChangesSetInput;
2800 }
2801 return rememberChangeHistoryAndInvokeOnChangesHook;
2802}
2803// This option ensures that the ngOnChanges lifecycle hook will be inherited
2804// from superclasses (in InheritDefinitionFeature).
2805/** @nocollapse */
2806// tslint:disable-next-line:no-toplevel-property-access
2807ɵɵNgOnChangesFeature.ngInherit = true;
2808/**
2809 * This is a synthetic lifecycle hook which gets inserted into `TView.preOrderHooks` to simulate
2810 * `ngOnChanges`.
2811 *
2812 * The hook reads the `NgSimpleChangesStore` data from the component instance and if changes are
2813 * found it invokes `ngOnChanges` on the component instance.
2814 *
2815 * @param this Component instance. Because this function gets inserted into `TView.preOrderHooks`,
2816 * it is guaranteed to be called with component instance.
2817 */
2818function rememberChangeHistoryAndInvokeOnChangesHook() {
2819 const simpleChangesStore = getSimpleChangesStore(this);
2820 const current = simpleChangesStore === null || simpleChangesStore === void 0 ? void 0 : simpleChangesStore.current;
2821 if (current) {
2822 const previous = simpleChangesStore.previous;
2823 if (previous === EMPTY_OBJ) {
2824 simpleChangesStore.previous = current;
2825 }
2826 else {
2827 // New changes are copied to the previous store, so that we don't lose history for inputs
2828 // which were not changed this time
2829 for (let key in current) {
2830 previous[key] = current[key];
2831 }
2832 }
2833 simpleChangesStore.current = null;
2834 this.ngOnChanges(current);
2835 }
2836}
2837function ngOnChangesSetInput(instance, value, publicName, privateName) {
2838 const declaredName = this.declaredInputs[publicName];
2839 ngDevMode && assertString(declaredName, 'Name of input in ngOnChanges has to be a string');
2840 const simpleChangesStore = getSimpleChangesStore(instance) ||
2841 setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
2842 const current = simpleChangesStore.current || (simpleChangesStore.current = {});
2843 const previous = simpleChangesStore.previous;
2844 const previousChange = previous[declaredName];
2845 current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
2846 instance[privateName] = value;
2847}
2848const SIMPLE_CHANGES_STORE = '__ngSimpleChanges__';
2849function getSimpleChangesStore(instance) {
2850 return instance[SIMPLE_CHANGES_STORE] || null;
2851}
2852function setSimpleChangesStore(instance, store) {
2853 return instance[SIMPLE_CHANGES_STORE] = store;
2854}
2855
2856let profilerCallback = null;
2857/**
2858 * Sets the callback function which will be invoked before and after performing certain actions at
2859 * runtime (for example, before and after running change detection).
2860 *
2861 * Warning: this function is *INTERNAL* and should not be relied upon in application's code.
2862 * The contract of the function might be changed in any release and/or the function can be removed
2863 * completely.
2864 *
2865 * @param profiler function provided by the caller or null value to disable profiling.
2866 */
2867const setProfiler = (profiler) => {
2868 profilerCallback = profiler;
2869};
2870/**
2871 * Profiler function which wraps user code executed by the runtime.
2872 *
2873 * @param event ProfilerEvent corresponding to the execution context
2874 * @param instance component instance
2875 * @param hookOrListener lifecycle hook function or output listener. The value depends on the
2876 * execution context
2877 * @returns
2878 */
2879const profiler = function (event, instance, hookOrListener) {
2880 if (profilerCallback != null /* both `null` and `undefined` */) {
2881 profilerCallback(event, instance, hookOrListener);
2882 }
2883};
2884
2885const SVG_NAMESPACE = 'svg';
2886const MATH_ML_NAMESPACE = 'math';
2887
2888/**
2889 * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
2890 * in same location in `LView`. This is because we don't want to pre-allocate space for it
2891 * because the storage is sparse. This file contains utilities for dealing with such data types.
2892 *
2893 * How do we know what is stored at a given location in `LView`.
2894 * - `Array.isArray(value) === false` => `RNode` (The normal storage value)
2895 * - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value.
2896 * - `typeof value[TYPE] === 'object'` => `LView`
2897 * - This happens when we have a component at a given location
2898 * - `typeof value[TYPE] === true` => `LContainer`
2899 * - This happens when we have `LContainer` binding at a given location.
2900 *
2901 *
2902 * NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.
2903 */
2904/**
2905 * Returns `RNode`.
2906 * @param value wrapped value of `RNode`, `LView`, `LContainer`
2907 */
2908function unwrapRNode(value) {
2909 while (Array.isArray(value)) {
2910 value = value[HOST];
2911 }
2912 return value;
2913}
2914/**
2915 * Returns `LView` or `null` if not found.
2916 * @param value wrapped value of `RNode`, `LView`, `LContainer`
2917 */
2918function unwrapLView(value) {
2919 while (Array.isArray(value)) {
2920 // This check is same as `isLView()` but we don't call at as we don't want to call
2921 // `Array.isArray()` twice and give JITer more work for inlining.
2922 if (typeof value[TYPE] === 'object')
2923 return value;
2924 value = value[HOST];
2925 }
2926 return null;
2927}
2928/**
2929 * Retrieves an element value from the provided `viewData`, by unwrapping
2930 * from any containers, component views, or style contexts.
2931 */
2932function getNativeByIndex(index, lView) {
2933 ngDevMode && assertIndexInRange(lView, index);
2934 ngDevMode && assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Expected to be past HEADER_OFFSET');
2935 return unwrapRNode(lView[index]);
2936}
2937/**
2938 * Retrieve an `RNode` for a given `TNode` and `LView`.
2939 *
2940 * This function guarantees in dev mode to retrieve a non-null `RNode`.
2941 *
2942 * @param tNode
2943 * @param lView
2944 */
2945function getNativeByTNode(tNode, lView) {
2946 ngDevMode && assertTNodeForLView(tNode, lView);
2947 ngDevMode && assertIndexInRange(lView, tNode.index);
2948 const node = unwrapRNode(lView[tNode.index]);
2949 return node;
2950}
2951/**
2952 * Retrieve an `RNode` or `null` for a given `TNode` and `LView`.
2953 *
2954 * Some `TNode`s don't have associated `RNode`s. For example `Projection`
2955 *
2956 * @param tNode
2957 * @param lView
2958 */
2959function getNativeByTNodeOrNull(tNode, lView) {
2960 const index = tNode === null ? -1 : tNode.index;
2961 if (index !== -1) {
2962 ngDevMode && assertTNodeForLView(tNode, lView);
2963 const node = unwrapRNode(lView[index]);
2964 return node;
2965 }
2966 return null;
2967}
2968// fixme(misko): The return Type should be `TNode|null`
2969function getTNode(tView, index) {
2970 ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
2971 ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode');
2972 const tNode = tView.data[index];
2973 ngDevMode && tNode !== null && assertTNode(tNode);
2974 return tNode;
2975}
2976/** Retrieves a value from any `LView` or `TData`. */
2977function load(view, index) {
2978 ngDevMode && assertIndexInRange(view, index);
2979 return view[index];
2980}
2981function getComponentLViewByIndex(nodeIndex, hostView) {
2982 // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
2983 ngDevMode && assertIndexInRange(hostView, nodeIndex);
2984 const slotValue = hostView[nodeIndex];
2985 const lView = isLView(slotValue) ? slotValue : slotValue[HOST];
2986 return lView;
2987}
2988/** Checks whether a given view is in creation mode */
2989function isCreationMode(view) {
2990 return (view[FLAGS] & 4 /* LViewFlags.CreationMode */) === 4 /* LViewFlags.CreationMode */;
2991}
2992/**
2993 * Returns a boolean for whether the view is attached to the change detection tree.
2994 *
2995 * Note: This determines whether a view should be checked, not whether it's inserted
2996 * into a container. For that, you'll want `viewAttachedToContainer` below.
2997 */
2998function viewAttachedToChangeDetector(view) {
2999 return (view[FLAGS] & 64 /* LViewFlags.Attached */) === 64 /* LViewFlags.Attached */;
3000}
3001/** Returns a boolean for whether the view is attached to a container. */
3002function viewAttachedToContainer(view) {
3003 return isLContainer(view[PARENT]);
3004}
3005function getConstant(consts, index) {
3006 if (index === null || index === undefined)
3007 return null;
3008 ngDevMode && assertIndexInRange(consts, index);
3009 return consts[index];
3010}
3011/**
3012 * Resets the pre-order hook flags of the view.
3013 * @param lView the LView on which the flags are reset
3014 */
3015function resetPreOrderHookFlags(lView) {
3016 lView[PREORDER_HOOK_FLAGS] = 0;
3017}
3018/**
3019 * Updates the `TRANSPLANTED_VIEWS_TO_REFRESH` counter on the `LContainer` as well as the parents
3020 * whose
3021 * 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
3022 * or
3023 * 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
3024 */
3025function updateTransplantedViewCount(lContainer, amount) {
3026 lContainer[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
3027 let viewOrContainer = lContainer;
3028 let parent = lContainer[PARENT];
3029 while (parent !== null &&
3030 ((amount === 1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 1) ||
3031 (amount === -1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 0))) {
3032 parent[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
3033 viewOrContainer = parent;
3034 parent = parent[PARENT];
3035 }
3036}
3037
3038const instructionState = {
3039 lFrame: createLFrame(null),
3040 bindingsEnabled: true,
3041};
3042/**
3043 * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
3044 *
3045 * Necessary to support ChangeDetectorRef.checkNoChanges().
3046 *
3047 * The `checkNoChanges` function is invoked only in ngDevMode=true and verifies that no unintended
3048 * changes exist in the change detector or its children.
3049 */
3050let _isInCheckNoChangesMode = false;
3051/**
3052 * Returns true if the instruction state stack is empty.
3053 *
3054 * Intended to be called from tests only (tree shaken otherwise).
3055 */
3056function specOnlyIsInstructionStateEmpty() {
3057 return instructionState.lFrame.parent === null;
3058}
3059function getElementDepthCount() {
3060 return instructionState.lFrame.elementDepthCount;
3061}
3062function increaseElementDepthCount() {
3063 instructionState.lFrame.elementDepthCount++;
3064}
3065function decreaseElementDepthCount() {
3066 instructionState.lFrame.elementDepthCount--;
3067}
3068function getBindingsEnabled() {
3069 return instructionState.bindingsEnabled;
3070}
3071/**
3072 * Enables directive matching on elements.
3073 *
3074 * * Example:
3075 * ```
3076 * <my-comp my-directive>
3077 * Should match component / directive.
3078 * </my-comp>
3079 * <div ngNonBindable>
3080 * <!-- ɵɵdisableBindings() -->
3081 * <my-comp my-directive>
3082 * Should not match component / directive because we are in ngNonBindable.
3083 * </my-comp>
3084 * <!-- ɵɵenableBindings() -->
3085 * </div>
3086 * ```
3087 *
3088 * @codeGenApi
3089 */
3090function ɵɵenableBindings() {
3091 instructionState.bindingsEnabled = true;
3092}
3093/**
3094 * Disables directive matching on element.
3095 *
3096 * * Example:
3097 * ```
3098 * <my-comp my-directive>
3099 * Should match component / directive.
3100 * </my-comp>
3101 * <div ngNonBindable>
3102 * <!-- ɵɵdisableBindings() -->
3103 * <my-comp my-directive>
3104 * Should not match component / directive because we are in ngNonBindable.
3105 * </my-comp>
3106 * <!-- ɵɵenableBindings() -->
3107 * </div>
3108 * ```
3109 *
3110 * @codeGenApi
3111 */
3112function ɵɵdisableBindings() {
3113 instructionState.bindingsEnabled = false;
3114}
3115/**
3116 * Return the current `LView`.
3117 */
3118function getLView() {
3119 return instructionState.lFrame.lView;
3120}
3121/**
3122 * Return the current `TView`.
3123 */
3124function getTView() {
3125 return instructionState.lFrame.tView;
3126}
3127/**
3128 * Restores `contextViewData` to the given OpaqueViewState instance.
3129 *
3130 * Used in conjunction with the getCurrentView() instruction to save a snapshot
3131 * of the current view and restore it when listeners are invoked. This allows
3132 * walking the declaration view tree in listeners to get vars from parent views.
3133 *
3134 * @param viewToRestore The OpaqueViewState instance to restore.
3135 * @returns Context of the restored OpaqueViewState instance.
3136 *
3137 * @codeGenApi
3138 */
3139function ɵɵrestoreView(viewToRestore) {
3140 instructionState.lFrame.contextLView = viewToRestore;
3141 return viewToRestore[CONTEXT];
3142}
3143/**
3144 * Clears the view set in `ɵɵrestoreView` from memory. Returns the passed in
3145 * value so that it can be used as a return value of an instruction.
3146 *
3147 * @codeGenApi
3148 */
3149function ɵɵresetView(value) {
3150 instructionState.lFrame.contextLView = null;
3151 return value;
3152}
3153function getCurrentTNode() {
3154 let currentTNode = getCurrentTNodePlaceholderOk();
3155 while (currentTNode !== null && currentTNode.type === 64 /* TNodeType.Placeholder */) {
3156 currentTNode = currentTNode.parent;
3157 }
3158 return currentTNode;
3159}
3160function getCurrentTNodePlaceholderOk() {
3161 return instructionState.lFrame.currentTNode;
3162}
3163function getCurrentParentTNode() {
3164 const lFrame = instructionState.lFrame;
3165 const currentTNode = lFrame.currentTNode;
3166 return lFrame.isParent ? currentTNode : currentTNode.parent;
3167}
3168function setCurrentTNode(tNode, isParent) {
3169 ngDevMode && tNode && assertTNodeForTView(tNode, instructionState.lFrame.tView);
3170 const lFrame = instructionState.lFrame;
3171 lFrame.currentTNode = tNode;
3172 lFrame.isParent = isParent;
3173}
3174function isCurrentTNodeParent() {
3175 return instructionState.lFrame.isParent;
3176}
3177function setCurrentTNodeAsNotParent() {
3178 instructionState.lFrame.isParent = false;
3179}
3180function getContextLView() {
3181 const contextLView = instructionState.lFrame.contextLView;
3182 ngDevMode && assertDefined(contextLView, 'contextLView must be defined.');
3183 return contextLView;
3184}
3185function isInCheckNoChangesMode() {
3186 !ngDevMode && throwError('Must never be called in production mode');
3187 return _isInCheckNoChangesMode;
3188}
3189function setIsInCheckNoChangesMode(mode) {
3190 !ngDevMode && throwError('Must never be called in production mode');
3191 _isInCheckNoChangesMode = mode;
3192}
3193// top level variables should not be exported for performance reasons (PERF_NOTES.md)
3194function getBindingRoot() {
3195 const lFrame = instructionState.lFrame;
3196 let index = lFrame.bindingRootIndex;
3197 if (index === -1) {
3198 index = lFrame.bindingRootIndex = lFrame.tView.bindingStartIndex;
3199 }
3200 return index;
3201}
3202function getBindingIndex() {
3203 return instructionState.lFrame.bindingIndex;
3204}
3205function setBindingIndex(value) {
3206 return instructionState.lFrame.bindingIndex = value;
3207}
3208function nextBindingIndex() {
3209 return instructionState.lFrame.bindingIndex++;
3210}
3211function incrementBindingIndex(count) {
3212 const lFrame = instructionState.lFrame;
3213 const index = lFrame.bindingIndex;
3214 lFrame.bindingIndex = lFrame.bindingIndex + count;
3215 return index;
3216}
3217function isInI18nBlock() {
3218 return instructionState.lFrame.inI18n;
3219}
3220function setInI18nBlock(isInI18nBlock) {
3221 instructionState.lFrame.inI18n = isInI18nBlock;
3222}
3223/**
3224 * Set a new binding root index so that host template functions can execute.
3225 *
3226 * Bindings inside the host template are 0 index. But because we don't know ahead of time
3227 * how many host bindings we have we can't pre-compute them. For this reason they are all
3228 * 0 index and we just shift the root so that they match next available location in the LView.
3229 *
3230 * @param bindingRootIndex Root index for `hostBindings`
3231 * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive
3232 * whose `hostBindings` are being processed.
3233 */
3234function setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex) {
3235 const lFrame = instructionState.lFrame;
3236 lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex;
3237 setCurrentDirectiveIndex(currentDirectiveIndex);
3238}
3239/**
3240 * When host binding is executing this points to the directive index.
3241 * `TView.data[getCurrentDirectiveIndex()]` is `DirectiveDef`
3242 * `LView[getCurrentDirectiveIndex()]` is directive instance.
3243 */
3244function getCurrentDirectiveIndex() {
3245 return instructionState.lFrame.currentDirectiveIndex;
3246}
3247/**
3248 * Sets an index of a directive whose `hostBindings` are being processed.
3249 *
3250 * @param currentDirectiveIndex `TData` index where current directive instance can be found.
3251 */
3252function setCurrentDirectiveIndex(currentDirectiveIndex) {
3253 instructionState.lFrame.currentDirectiveIndex = currentDirectiveIndex;
3254}
3255/**
3256 * Retrieve the current `DirectiveDef` which is active when `hostBindings` instruction is being
3257 * executed.
3258 *
3259 * @param tData Current `TData` where the `DirectiveDef` will be looked up at.
3260 */
3261function getCurrentDirectiveDef(tData) {
3262 const currentDirectiveIndex = instructionState.lFrame.currentDirectiveIndex;
3263 return currentDirectiveIndex === -1 ? null : tData[currentDirectiveIndex];
3264}
3265function getCurrentQueryIndex() {
3266 return instructionState.lFrame.currentQueryIndex;
3267}
3268function setCurrentQueryIndex(value) {
3269 instructionState.lFrame.currentQueryIndex = value;
3270}
3271/**
3272 * Returns a `TNode` of the location where the current `LView` is declared at.
3273 *
3274 * @param lView an `LView` that we want to find parent `TNode` for.
3275 */
3276function getDeclarationTNode(lView) {
3277 const tView = lView[TVIEW];
3278 // Return the declaration parent for embedded views
3279 if (tView.type === 2 /* TViewType.Embedded */) {
3280 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
3281 return tView.declTNode;
3282 }
3283 // Components don't have `TView.declTNode` because each instance of component could be
3284 // inserted in different location, hence `TView.declTNode` is meaningless.
3285 // Falling back to `T_HOST` in case we cross component boundary.
3286 if (tView.type === 1 /* TViewType.Component */) {
3287 return lView[T_HOST];
3288 }
3289 // Remaining TNode type is `TViewType.Root` which doesn't have a parent TNode.
3290 return null;
3291}
3292/**
3293 * This is a light weight version of the `enterView` which is needed by the DI system.
3294 *
3295 * @param lView `LView` location of the DI context.
3296 * @param tNode `TNode` for DI context
3297 * @param flags DI context flags. if `SkipSelf` flag is set than we walk up the declaration
3298 * tree from `tNode` until we find parent declared `TElementNode`.
3299 * @returns `true` if we have successfully entered DI associated with `tNode` (or with declared
3300 * `TNode` if `flags` has `SkipSelf`). Failing to enter DI implies that no associated
3301 * `NodeInjector` can be found and we should instead use `ModuleInjector`.
3302 * - If `true` than this call must be fallowed by `leaveDI`
3303 * - If `false` than this call failed and we should NOT call `leaveDI`
3304 */
3305function enterDI(lView, tNode, flags) {
3306 ngDevMode && assertLViewOrUndefined(lView);
3307 if (flags & InjectFlags.SkipSelf) {
3308 ngDevMode && assertTNodeForTView(tNode, lView[TVIEW]);
3309 let parentTNode = tNode;
3310 let parentLView = lView;
3311 while (true) {
3312 ngDevMode && assertDefined(parentTNode, 'Parent TNode should be defined');
3313 parentTNode = parentTNode.parent;
3314 if (parentTNode === null && !(flags & InjectFlags.Host)) {
3315 parentTNode = getDeclarationTNode(parentLView);
3316 if (parentTNode === null)
3317 break;
3318 // In this case, a parent exists and is definitely an element. So it will definitely
3319 // have an existing lView as the declaration view, which is why we can assume it's defined.
3320 ngDevMode && assertDefined(parentLView, 'Parent LView should be defined');
3321 parentLView = parentLView[DECLARATION_VIEW];
3322 // In Ivy there are Comment nodes that correspond to ngIf and NgFor embedded directives
3323 // We want to skip those and look only at Elements and ElementContainers to ensure
3324 // we're looking at true parent nodes, and not content or other types.
3325 if (parentTNode.type & (2 /* TNodeType.Element */ | 8 /* TNodeType.ElementContainer */)) {
3326 break;
3327 }
3328 }
3329 else {
3330 break;
3331 }
3332 }
3333 if (parentTNode === null) {
3334 // If we failed to find a parent TNode this means that we should use module injector.
3335 return false;
3336 }
3337 else {
3338 tNode = parentTNode;
3339 lView = parentLView;
3340 }
3341 }
3342 ngDevMode && assertTNodeForLView(tNode, lView);
3343 const lFrame = instructionState.lFrame = allocLFrame();
3344 lFrame.currentTNode = tNode;
3345 lFrame.lView = lView;
3346 return true;
3347}
3348/**
3349 * Swap the current lView with a new lView.
3350 *
3351 * For performance reasons we store the lView in the top level of the module.
3352 * This way we minimize the number of properties to read. Whenever a new view
3353 * is entered we have to store the lView for later, and when the view is
3354 * exited the state has to be restored
3355 *
3356 * @param newView New lView to become active
3357 * @returns the previously active lView;
3358 */
3359function enterView(newView) {
3360 ngDevMode && assertNotEqual(newView[0], newView[1], '????');
3361 ngDevMode && assertLViewOrUndefined(newView);
3362 const newLFrame = allocLFrame();
3363 if (ngDevMode) {
3364 assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
3365 assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
3366 assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
3367 assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
3368 assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
3369 assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
3370 assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
3371 assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
3372 assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
3373 }
3374 const tView = newView[TVIEW];
3375 instructionState.lFrame = newLFrame;
3376 ngDevMode && tView.firstChild && assertTNodeForTView(tView.firstChild, tView);
3377 newLFrame.currentTNode = tView.firstChild;
3378 newLFrame.lView = newView;
3379 newLFrame.tView = tView;
3380 newLFrame.contextLView = newView;
3381 newLFrame.bindingIndex = tView.bindingStartIndex;
3382 newLFrame.inI18n = false;
3383}
3384/**
3385 * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure.
3386 */
3387function allocLFrame() {
3388 const currentLFrame = instructionState.lFrame;
3389 const childLFrame = currentLFrame === null ? null : currentLFrame.child;
3390 const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame;
3391 return newLFrame;
3392}
3393function createLFrame(parent) {
3394 const lFrame = {
3395 currentTNode: null,
3396 isParent: true,
3397 lView: null,
3398 tView: null,
3399 selectedIndex: -1,
3400 contextLView: null,
3401 elementDepthCount: 0,
3402 currentNamespace: null,
3403 currentDirectiveIndex: -1,
3404 bindingRootIndex: -1,
3405 bindingIndex: -1,
3406 currentQueryIndex: 0,
3407 parent: parent,
3408 child: null,
3409 inI18n: false,
3410 };
3411 parent !== null && (parent.child = lFrame); // link the new LFrame for reuse.
3412 return lFrame;
3413}
3414/**
3415 * A lightweight version of leave which is used with DI.
3416 *
3417 * This function only resets `currentTNode` and `LView` as those are the only properties
3418 * used with DI (`enterDI()`).
3419 *
3420 * NOTE: This function is reexported as `leaveDI`. However `leaveDI` has return type of `void` where
3421 * as `leaveViewLight` has `LFrame`. This is so that `leaveViewLight` can be used in `leaveView`.
3422 */
3423function leaveViewLight() {
3424 const oldLFrame = instructionState.lFrame;
3425 instructionState.lFrame = oldLFrame.parent;
3426 oldLFrame.currentTNode = null;
3427 oldLFrame.lView = null;
3428 return oldLFrame;
3429}
3430/**
3431 * This is a lightweight version of the `leaveView` which is needed by the DI system.
3432 *
3433 * NOTE: this function is an alias so that we can change the type of the function to have `void`
3434 * return type.
3435 */
3436const leaveDI = leaveViewLight;
3437/**
3438 * Leave the current `LView`
3439 *
3440 * This pops the `LFrame` with the associated `LView` from the stack.
3441 *
3442 * IMPORTANT: We must zero out the `LFrame` values here otherwise they will be retained. This is
3443 * because for performance reasons we don't release `LFrame` but rather keep it for next use.
3444 */
3445function leaveView() {
3446 const oldLFrame = leaveViewLight();
3447 oldLFrame.isParent = true;
3448 oldLFrame.tView = null;
3449 oldLFrame.selectedIndex = -1;
3450 oldLFrame.contextLView = null;
3451 oldLFrame.elementDepthCount = 0;
3452 oldLFrame.currentDirectiveIndex = -1;
3453 oldLFrame.currentNamespace = null;
3454 oldLFrame.bindingRootIndex = -1;
3455 oldLFrame.bindingIndex = -1;
3456 oldLFrame.currentQueryIndex = 0;
3457}
3458function nextContextImpl(level) {
3459 const contextLView = instructionState.lFrame.contextLView =
3460 walkUpViews(level, instructionState.lFrame.contextLView);
3461 return contextLView[CONTEXT];
3462}
3463function walkUpViews(nestingLevel, currentView) {
3464 while (nestingLevel > 0) {
3465 ngDevMode &&
3466 assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.');
3467 currentView = currentView[DECLARATION_VIEW];
3468 nestingLevel--;
3469 }
3470 return currentView;
3471}
3472/**
3473 * Gets the currently selected element index.
3474 *
3475 * Used with {@link property} instruction (and more in the future) to identify the index in the
3476 * current `LView` to act on.
3477 */
3478function getSelectedIndex() {
3479 return instructionState.lFrame.selectedIndex;
3480}
3481/**
3482 * Sets the most recent index passed to {@link select}
3483 *
3484 * Used with {@link property} instruction (and more in the future) to identify the index in the
3485 * current `LView` to act on.
3486 *
3487 * (Note that if an "exit function" was set earlier (via `setElementExitFn()`) then that will be
3488 * run if and when the provided `index` value is different from the current selected index value.)
3489 */
3490function setSelectedIndex(index) {
3491 ngDevMode && index !== -1 &&
3492 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
3493 ngDevMode &&
3494 assertLessThan(index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView');
3495 instructionState.lFrame.selectedIndex = index;
3496}
3497/**
3498 * Gets the `tNode` that represents currently selected element.
3499 */
3500function getSelectedTNode() {
3501 const lFrame = instructionState.lFrame;
3502 return getTNode(lFrame.tView, lFrame.selectedIndex);
3503}
3504/**
3505 * Sets the namespace used to create elements to `'http://www.w3.org/2000/svg'` in global state.
3506 *
3507 * @codeGenApi
3508 */
3509function ɵɵnamespaceSVG() {
3510 instructionState.lFrame.currentNamespace = SVG_NAMESPACE;
3511}
3512/**
3513 * Sets the namespace used to create elements to `'http://www.w3.org/1998/MathML/'` in global state.
3514 *
3515 * @codeGenApi
3516 */
3517function ɵɵnamespaceMathML() {
3518 instructionState.lFrame.currentNamespace = MATH_ML_NAMESPACE;
3519}
3520/**
3521 * Sets the namespace used to create elements to `null`, which forces element creation to use
3522 * `createElement` rather than `createElementNS`.
3523 *
3524 * @codeGenApi
3525 */
3526function ɵɵnamespaceHTML() {
3527 namespaceHTMLInternal();
3528}
3529/**
3530 * Sets the namespace used to create elements to `null`, which forces element creation to use
3531 * `createElement` rather than `createElementNS`.
3532 */
3533function namespaceHTMLInternal() {
3534 instructionState.lFrame.currentNamespace = null;
3535}
3536function getNamespace$1() {
3537 return instructionState.lFrame.currentNamespace;
3538}
3539
3540/**
3541 * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`.
3542 *
3543 * Must be run *only* on the first template pass.
3544 *
3545 * Sets up the pre-order hooks on the provided `tView`,
3546 * see {@link HookData} for details about the data structure.
3547 *
3548 * @param directiveIndex The index of the directive in LView
3549 * @param directiveDef The definition containing the hooks to setup in tView
3550 * @param tView The current TView
3551 */
3552function registerPreOrderHooks(directiveIndex, directiveDef, tView) {
3553 ngDevMode && assertFirstCreatePass(tView);
3554 const { ngOnChanges, ngOnInit, ngDoCheck } = directiveDef.type.prototype;
3555 if (ngOnChanges) {
3556 const wrappedOnChanges = NgOnChangesFeatureImpl(directiveDef);
3557 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, wrappedOnChanges);
3558 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = []))
3559 .push(directiveIndex, wrappedOnChanges);
3560 }
3561 if (ngOnInit) {
3562 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(0 - directiveIndex, ngOnInit);
3563 }
3564 if (ngDoCheck) {
3565 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, ngDoCheck);
3566 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, ngDoCheck);
3567 }
3568}
3569/**
3570 *
3571 * Loops through the directives on the provided `tNode` and queues hooks to be
3572 * run that are not initialization hooks.
3573 *
3574 * Should be executed during `elementEnd()` and similar to
3575 * preserve hook execution order. Content, view, and destroy hooks for projected
3576 * components and directives must be called *before* their hosts.
3577 *
3578 * Sets up the content, view, and destroy hooks on the provided `tView`,
3579 * see {@link HookData} for details about the data structure.
3580 *
3581 * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up
3582 * separately at `elementStart`.
3583 *
3584 * @param tView The current TView
3585 * @param tNode The TNode whose directives are to be searched for hooks to queue
3586 */
3587function registerPostOrderHooks(tView, tNode) {
3588 ngDevMode && assertFirstCreatePass(tView);
3589 // It's necessary to loop through the directives at elementEnd() (rather than processing in
3590 // directiveCreate) so we can preserve the current hook order. Content, view, and destroy
3591 // hooks for projected components and directives must be called *before* their hosts.
3592 for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) {
3593 const directiveDef = tView.data[i];
3594 ngDevMode && assertDefined(directiveDef, 'Expecting DirectiveDef');
3595 const lifecycleHooks = directiveDef.type.prototype;
3596 const { ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked, ngOnDestroy } = lifecycleHooks;
3597 if (ngAfterContentInit) {
3598 (tView.contentHooks || (tView.contentHooks = [])).push(-i, ngAfterContentInit);
3599 }
3600 if (ngAfterContentChecked) {
3601 (tView.contentHooks || (tView.contentHooks = [])).push(i, ngAfterContentChecked);
3602 (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, ngAfterContentChecked);
3603 }
3604 if (ngAfterViewInit) {
3605 (tView.viewHooks || (tView.viewHooks = [])).push(-i, ngAfterViewInit);
3606 }
3607 if (ngAfterViewChecked) {
3608 (tView.viewHooks || (tView.viewHooks = [])).push(i, ngAfterViewChecked);
3609 (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, ngAfterViewChecked);
3610 }
3611 if (ngOnDestroy != null) {
3612 (tView.destroyHooks || (tView.destroyHooks = [])).push(i, ngOnDestroy);
3613 }
3614 }
3615}
3616/**
3617 * Executing hooks requires complex logic as we need to deal with 2 constraints.
3618 *
3619 * 1. Init hooks (ngOnInit, ngAfterContentInit, ngAfterViewInit) must all be executed once and only
3620 * once, across many change detection cycles. This must be true even if some hooks throw, or if
3621 * some recursively trigger a change detection cycle.
3622 * To solve that, it is required to track the state of the execution of these init hooks.
3623 * This is done by storing and maintaining flags in the view: the {@link InitPhaseState},
3624 * and the index within that phase. They can be seen as a cursor in the following structure:
3625 * [[onInit1, onInit2], [afterContentInit1], [afterViewInit1, afterViewInit2, afterViewInit3]]
3626 * They are are stored as flags in LView[FLAGS].
3627 *
3628 * 2. Pre-order hooks can be executed in batches, because of the select instruction.
3629 * To be able to pause and resume their execution, we also need some state about the hook's array
3630 * that is being processed:
3631 * - the index of the next hook to be executed
3632 * - the number of init hooks already found in the processed part of the array
3633 * They are are stored as flags in LView[PREORDER_HOOK_FLAGS].
3634 */
3635/**
3636 * Executes pre-order check hooks ( OnChanges, DoChanges) given a view where all the init hooks were
3637 * executed once. This is a light version of executeInitAndCheckPreOrderHooks where we can skip read
3638 * / write of the init-hooks related flags.
3639 * @param lView The LView where hooks are defined
3640 * @param hooks Hooks to be run
3641 * @param nodeIndex 3 cases depending on the value:
3642 * - undefined: all hooks from the array should be executed (post-order case)
3643 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
3644 * flushing the remaining hooks)
3645 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
3646 * case, when executing select(number))
3647 */
3648function executeCheckHooks(lView, hooks, nodeIndex) {
3649 callHooks(lView, hooks, 3 /* InitPhaseState.InitPhaseCompleted */, nodeIndex);
3650}
3651/**
3652 * Executes post-order init and check hooks (one of AfterContentInit, AfterContentChecked,
3653 * AfterViewInit, AfterViewChecked) given a view where there are pending init hooks to be executed.
3654 * @param lView The LView where hooks are defined
3655 * @param hooks Hooks to be run
3656 * @param initPhase A phase for which hooks should be run
3657 * @param nodeIndex 3 cases depending on the value:
3658 * - undefined: all hooks from the array should be executed (post-order case)
3659 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
3660 * flushing the remaining hooks)
3661 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
3662 * case, when executing select(number))
3663 */
3664function executeInitAndCheckHooks(lView, hooks, initPhase, nodeIndex) {
3665 ngDevMode &&
3666 assertNotEqual(initPhase, 3 /* InitPhaseState.InitPhaseCompleted */, 'Init pre-order hooks should not be called more than once');
3667 if ((lView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
3668 callHooks(lView, hooks, initPhase, nodeIndex);
3669 }
3670}
3671function incrementInitPhaseFlags(lView, initPhase) {
3672 ngDevMode &&
3673 assertNotEqual(initPhase, 3 /* InitPhaseState.InitPhaseCompleted */, 'Init hooks phase should not be incremented after all init hooks have been run.');
3674 let flags = lView[FLAGS];
3675 if ((flags & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
3676 flags &= 2047 /* LViewFlags.IndexWithinInitPhaseReset */;
3677 flags += 1 /* LViewFlags.InitPhaseStateIncrementer */;
3678 lView[FLAGS] = flags;
3679 }
3680}
3681/**
3682 * Calls lifecycle hooks with their contexts, skipping init hooks if it's not
3683 * the first LView pass
3684 *
3685 * @param currentView The current view
3686 * @param arr The array in which the hooks are found
3687 * @param initPhaseState the current state of the init phase
3688 * @param currentNodeIndex 3 cases depending on the value:
3689 * - undefined: all hooks from the array should be executed (post-order case)
3690 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
3691 * flushing the remaining hooks)
3692 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
3693 * case, when executing select(number))
3694 */
3695function callHooks(currentView, arr, initPhase, currentNodeIndex) {
3696 ngDevMode &&
3697 assertEqual(isInCheckNoChangesMode(), false, 'Hooks should never be run when in check no changes mode.');
3698 const startIndex = currentNodeIndex !== undefined ?
3699 (currentView[PREORDER_HOOK_FLAGS] & 65535 /* PreOrderHookFlags.IndexOfTheNextPreOrderHookMaskMask */) :
3700 0;
3701 const nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1;
3702 const max = arr.length - 1; // Stop the loop at length - 1, because we look for the hook at i + 1
3703 let lastNodeIndexFound = 0;
3704 for (let i = startIndex; i < max; i++) {
3705 const hook = arr[i + 1];
3706 if (typeof hook === 'number') {
3707 lastNodeIndexFound = arr[i];
3708 if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) {
3709 break;
3710 }
3711 }
3712 else {
3713 const isInitHook = arr[i] < 0;
3714 if (isInitHook)
3715 currentView[PREORDER_HOOK_FLAGS] += 65536 /* PreOrderHookFlags.NumberOfInitHooksCalledIncrementer */;
3716 if (lastNodeIndexFound < nodeIndexLimit || nodeIndexLimit == -1) {
3717 callHook(currentView, initPhase, arr, i);
3718 currentView[PREORDER_HOOK_FLAGS] =
3719 (currentView[PREORDER_HOOK_FLAGS] & 4294901760 /* PreOrderHookFlags.NumberOfInitHooksCalledMask */) + i +
3720 2;
3721 }
3722 i++;
3723 }
3724 }
3725}
3726/**
3727 * Execute one hook against the current `LView`.
3728 *
3729 * @param currentView The current view
3730 * @param initPhaseState the current state of the init phase
3731 * @param arr The array in which the hooks are found
3732 * @param i The current index within the hook data array
3733 */
3734function callHook(currentView, initPhase, arr, i) {
3735 const isInitHook = arr[i] < 0;
3736 const hook = arr[i + 1];
3737 const directiveIndex = isInitHook ? -arr[i] : arr[i];
3738 const directive = currentView[directiveIndex];
3739 if (isInitHook) {
3740 const indexWithintInitPhase = currentView[FLAGS] >> 11 /* LViewFlags.IndexWithinInitPhaseShift */;
3741 // The init phase state must be always checked here as it may have been recursively updated.
3742 if (indexWithintInitPhase <
3743 (currentView[PREORDER_HOOK_FLAGS] >> 16 /* PreOrderHookFlags.NumberOfInitHooksCalledShift */) &&
3744 (currentView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
3745 currentView[FLAGS] += 2048 /* LViewFlags.IndexWithinInitPhaseIncrementer */;
3746 profiler(4 /* ProfilerEvent.LifecycleHookStart */, directive, hook);
3747 try {
3748 hook.call(directive);
3749 }
3750 finally {
3751 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, directive, hook);
3752 }
3753 }
3754 }
3755 else {
3756 profiler(4 /* ProfilerEvent.LifecycleHookStart */, directive, hook);
3757 try {
3758 hook.call(directive);
3759 }
3760 finally {
3761 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, directive, hook);
3762 }
3763 }
3764}
3765
3766const NO_PARENT_INJECTOR = -1;
3767/**
3768 * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in
3769 * `TView.data`. This allows us to store information about the current node's tokens (which
3770 * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
3771 * shared, so they live in `LView`).
3772 *
3773 * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter
3774 * determines whether a directive is available on the associated node or not. This prevents us
3775 * from searching the directives array at this level unless it's probable the directive is in it.
3776 *
3777 * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
3778 *
3779 * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed
3780 * using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
3781 * will differ based on where it is flattened into the main array, so it's not possible to know
3782 * the indices ahead of time and save their types here. The interfaces are still included here
3783 * for documentation purposes.
3784 *
3785 * export interface LInjector extends Array<any> {
3786 *
3787 * // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
3788 * [0]: number;
3789 *
3790 * // Cumulative bloom for directive IDs 32-63
3791 * [1]: number;
3792 *
3793 * // Cumulative bloom for directive IDs 64-95
3794 * [2]: number;
3795 *
3796 * // Cumulative bloom for directive IDs 96-127
3797 * [3]: number;
3798 *
3799 * // Cumulative bloom for directive IDs 128-159
3800 * [4]: number;
3801 *
3802 * // Cumulative bloom for directive IDs 160 - 191
3803 * [5]: number;
3804 *
3805 * // Cumulative bloom for directive IDs 192 - 223
3806 * [6]: number;
3807 *
3808 * // Cumulative bloom for directive IDs 224 - 255
3809 * [7]: number;
3810 *
3811 * // We need to store a reference to the injector's parent so DI can keep looking up
3812 * // the injector tree until it finds the dependency it's looking for.
3813 * [PARENT_INJECTOR]: number;
3814 * }
3815 *
3816 * export interface TInjector extends Array<any> {
3817 *
3818 * // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
3819 * [0]: number;
3820 *
3821 * // Shared node bloom for directive IDs 32-63
3822 * [1]: number;
3823 *
3824 * // Shared node bloom for directive IDs 64-95
3825 * [2]: number;
3826 *
3827 * // Shared node bloom for directive IDs 96-127
3828 * [3]: number;
3829 *
3830 * // Shared node bloom for directive IDs 128-159
3831 * [4]: number;
3832 *
3833 * // Shared node bloom for directive IDs 160 - 191
3834 * [5]: number;
3835 *
3836 * // Shared node bloom for directive IDs 192 - 223
3837 * [6]: number;
3838 *
3839 * // Shared node bloom for directive IDs 224 - 255
3840 * [7]: number;
3841 *
3842 * // Necessary to find directive indices for a particular node.
3843 * [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
3844 * }
3845 */
3846/**
3847 * Factory for creating instances of injectors in the NodeInjector.
3848 *
3849 * This factory is complicated by the fact that it can resolve `multi` factories as well.
3850 *
3851 * NOTE: Some of the fields are optional which means that this class has two hidden classes.
3852 * - One without `multi` support (most common)
3853 * - One with `multi` values, (rare).
3854 *
3855 * Since VMs can cache up to 4 inline hidden classes this is OK.
3856 *
3857 * - Single factory: Only `resolving` and `factory` is defined.
3858 * - `providers` factory: `componentProviders` is a number and `index = -1`.
3859 * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`.
3860 */
3861class NodeInjectorFactory {
3862 constructor(
3863 /**
3864 * Factory to invoke in order to create a new instance.
3865 */
3866 factory,
3867 /**
3868 * Set to `true` if the token is declared in `viewProviders` (or if it is component).
3869 */
3870 isViewProvider, injectImplementation) {
3871 this.factory = factory;
3872 /**
3873 * Marker set to true during factory invocation to see if we get into recursive loop.
3874 * Recursive loop causes an error to be displayed.
3875 */
3876 this.resolving = false;
3877 ngDevMode && assertDefined(factory, 'Factory not specified');
3878 ngDevMode && assertEqual(typeof factory, 'function', 'Expected factory function.');
3879 this.canSeeViewProviders = isViewProvider;
3880 this.injectImpl = injectImplementation;
3881 }
3882}
3883function isFactory(obj) {
3884 return obj instanceof NodeInjectorFactory;
3885}
3886// Note: This hack is necessary so we don't erroneously get a circular dependency
3887// failure based on types.
3888const unusedValueExportToPlacateAjd$2 = 1;
3889
3890/**
3891 * Converts `TNodeType` into human readable text.
3892 * Make sure this matches with `TNodeType`
3893 */
3894function toTNodeTypeAsString(tNodeType) {
3895 let text = '';
3896 (tNodeType & 1 /* TNodeType.Text */) && (text += '|Text');
3897 (tNodeType & 2 /* TNodeType.Element */) && (text += '|Element');
3898 (tNodeType & 4 /* TNodeType.Container */) && (text += '|Container');
3899 (tNodeType & 8 /* TNodeType.ElementContainer */) && (text += '|ElementContainer');
3900 (tNodeType & 16 /* TNodeType.Projection */) && (text += '|Projection');
3901 (tNodeType & 32 /* TNodeType.Icu */) && (text += '|IcuContainer');
3902 (tNodeType & 64 /* TNodeType.Placeholder */) && (text += '|Placeholder');
3903 return text.length > 0 ? text.substring(1) : text;
3904}
3905// Note: This hack is necessary so we don't erroneously get a circular dependency
3906// failure based on types.
3907const unusedValueExportToPlacateAjd$1 = 1;
3908/**
3909 * Returns `true` if the `TNode` has a directive which has `@Input()` for `class` binding.
3910 *
3911 * ```
3912 * <div my-dir [class]="exp"></div>
3913 * ```
3914 * and
3915 * ```
3916 * @Directive({
3917 * })
3918 * class MyDirective {
3919 * @Input()
3920 * class: string;
3921 * }
3922 * ```
3923 *
3924 * In the above case it is necessary to write the reconciled styling information into the
3925 * directive's input.
3926 *
3927 * @param tNode
3928 */
3929function hasClassInput(tNode) {
3930 return (tNode.flags & 8 /* TNodeFlags.hasClassInput */) !== 0;
3931}
3932/**
3933 * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
3934 *
3935 * ```
3936 * <div my-dir [style]="exp"></div>
3937 * ```
3938 * and
3939 * ```
3940 * @Directive({
3941 * })
3942 * class MyDirective {
3943 * @Input()
3944 * class: string;
3945 * }
3946 * ```
3947 *
3948 * In the above case it is necessary to write the reconciled styling information into the
3949 * directive's input.
3950 *
3951 * @param tNode
3952 */
3953function hasStyleInput(tNode) {
3954 return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
3955}
3956
3957function assertTNodeType(tNode, expectedTypes, message) {
3958 assertDefined(tNode, 'should be called with a TNode');
3959 if ((tNode.type & expectedTypes) === 0) {
3960 throwError(message ||
3961 `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
3962 }
3963}
3964function assertPureTNodeType(type) {
3965 if (!(type === 2 /* TNodeType.Element */ || //
3966 type === 1 /* TNodeType.Text */ || //
3967 type === 4 /* TNodeType.Container */ || //
3968 type === 8 /* TNodeType.ElementContainer */ || //
3969 type === 32 /* TNodeType.Icu */ || //
3970 type === 16 /* TNodeType.Projection */ || //
3971 type === 64 /* TNodeType.Placeholder */)) {
3972 throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
3973 }
3974}
3975
3976/**
3977 * Assigns all attribute values to the provided element via the inferred renderer.
3978 *
3979 * This function accepts two forms of attribute entries:
3980 *
3981 * default: (key, value):
3982 * attrs = [key1, value1, key2, value2]
3983 *
3984 * namespaced: (NAMESPACE_MARKER, uri, name, value)
3985 * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
3986 *
3987 * The `attrs` array can contain a mix of both the default and namespaced entries.
3988 * The "default" values are set without a marker, but if the function comes across
3989 * a marker value then it will attempt to set a namespaced value. If the marker is
3990 * not of a namespaced value then the function will quit and return the index value
3991 * where it stopped during the iteration of the attrs array.
3992 *
3993 * See [AttributeMarker] to understand what the namespace marker value is.
3994 *
3995 * Note that this instruction does not support assigning style and class values to
3996 * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
3997 * are applied to an element.
3998 * @param renderer The renderer to be used
3999 * @param native The element that the attributes will be assigned to
4000 * @param attrs The attribute array of values that will be assigned to the element
4001 * @returns the index value that was last accessed in the attributes array
4002 */
4003function setUpAttributes(renderer, native, attrs) {
4004 let i = 0;
4005 while (i < attrs.length) {
4006 const value = attrs[i];
4007 if (typeof value === 'number') {
4008 // only namespaces are supported. Other value types (such as style/class
4009 // entries) are not supported in this function.
4010 if (value !== 0 /* AttributeMarker.NamespaceURI */) {
4011 break;
4012 }
4013 // we just landed on the marker value ... therefore
4014 // we should skip to the next entry
4015 i++;
4016 const namespaceURI = attrs[i++];
4017 const attrName = attrs[i++];
4018 const attrVal = attrs[i++];
4019 ngDevMode && ngDevMode.rendererSetAttribute++;
4020 renderer.setAttribute(native, attrName, attrVal, namespaceURI);
4021 }
4022 else {
4023 // attrName is string;
4024 const attrName = value;
4025 const attrVal = attrs[++i];
4026 // Standard attributes
4027 ngDevMode && ngDevMode.rendererSetAttribute++;
4028 if (isAnimationProp(attrName)) {
4029 renderer.setProperty(native, attrName, attrVal);
4030 }
4031 else {
4032 renderer.setAttribute(native, attrName, attrVal);
4033 }
4034 i++;
4035 }
4036 }
4037 // another piece of code may iterate over the same attributes array. Therefore
4038 // it may be helpful to return the exact spot where the attributes array exited
4039 // whether by running into an unsupported marker or if all the static values were
4040 // iterated over.
4041 return i;
4042}
4043/**
4044 * Test whether the given value is a marker that indicates that the following
4045 * attribute values in a `TAttributes` array are only the names of attributes,
4046 * and not name-value pairs.
4047 * @param marker The attribute marker to test.
4048 * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
4049 */
4050function isNameOnlyAttributeMarker(marker) {
4051 return marker === 3 /* AttributeMarker.Bindings */ || marker === 4 /* AttributeMarker.Template */ ||
4052 marker === 6 /* AttributeMarker.I18n */;
4053}
4054function isAnimationProp(name) {
4055 // Perf note: accessing charCodeAt to check for the first character of a string is faster as
4056 // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
4057 // charCodeAt doesn't allocate memory to return a substring.
4058 return name.charCodeAt(0) === 64 /* CharCode.AT_SIGN */;
4059}
4060/**
4061 * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
4062 *
4063 * This merge function keeps the order of attrs same.
4064 *
4065 * @param dst Location of where the merged `TAttributes` should end up.
4066 * @param src `TAttributes` which should be appended to `dst`
4067 */
4068function mergeHostAttrs(dst, src) {
4069 if (src === null || src.length === 0) {
4070 // do nothing
4071 }
4072 else if (dst === null || dst.length === 0) {
4073 // We have source, but dst is empty, just make a copy.
4074 dst = src.slice();
4075 }
4076 else {
4077 let srcMarker = -1 /* AttributeMarker.ImplicitAttributes */;
4078 for (let i = 0; i < src.length; i++) {
4079 const item = src[i];
4080 if (typeof item === 'number') {
4081 srcMarker = item;
4082 }
4083 else {
4084 if (srcMarker === 0 /* AttributeMarker.NamespaceURI */) {
4085 // Case where we need to consume `key1`, `key2`, `value` items.
4086 }
4087 else if (srcMarker === -1 /* AttributeMarker.ImplicitAttributes */ ||
4088 srcMarker === 2 /* AttributeMarker.Styles */) {
4089 // Case where we have to consume `key1` and `value` only.
4090 mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
4091 }
4092 else {
4093 // Case where we have to consume `key1` only.
4094 mergeHostAttribute(dst, srcMarker, item, null, null);
4095 }
4096 }
4097 }
4098 }
4099 return dst;
4100}
4101/**
4102 * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
4103 *
4104 * @param dst `TAttributes` to append to.
4105 * @param marker Region where the `key`/`value` should be added.
4106 * @param key1 Key to add to `TAttributes`
4107 * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
4108 * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
4109 */
4110function mergeHostAttribute(dst, marker, key1, key2, value) {
4111 let i = 0;
4112 // Assume that new markers will be inserted at the end.
4113 let markerInsertPosition = dst.length;
4114 // scan until correct type.
4115 if (marker === -1 /* AttributeMarker.ImplicitAttributes */) {
4116 markerInsertPosition = -1;
4117 }
4118 else {
4119 while (i < dst.length) {
4120 const dstValue = dst[i++];
4121 if (typeof dstValue === 'number') {
4122 if (dstValue === marker) {
4123 markerInsertPosition = -1;
4124 break;
4125 }
4126 else if (dstValue > marker) {
4127 // We need to save this as we want the markers to be inserted in specific order.
4128 markerInsertPosition = i - 1;
4129 break;
4130 }
4131 }
4132 }
4133 }
4134 // search until you find place of insertion
4135 while (i < dst.length) {
4136 const item = dst[i];
4137 if (typeof item === 'number') {
4138 // since `i` started as the index after the marker, we did not find it if we are at the next
4139 // marker
4140 break;
4141 }
4142 else if (item === key1) {
4143 // We already have same token
4144 if (key2 === null) {
4145 if (value !== null) {
4146 dst[i + 1] = value;
4147 }
4148 return;
4149 }
4150 else if (key2 === dst[i + 1]) {
4151 dst[i + 2] = value;
4152 return;
4153 }
4154 }
4155 // Increment counter.
4156 i++;
4157 if (key2 !== null)
4158 i++;
4159 if (value !== null)
4160 i++;
4161 }
4162 // insert at location.
4163 if (markerInsertPosition !== -1) {
4164 dst.splice(markerInsertPosition, 0, marker);
4165 i = markerInsertPosition + 1;
4166 }
4167 dst.splice(i++, 0, key1);
4168 if (key2 !== null) {
4169 dst.splice(i++, 0, key2);
4170 }
4171 if (value !== null) {
4172 dst.splice(i++, 0, value);
4173 }
4174}
4175
4176/// Parent Injector Utils ///////////////////////////////////////////////////////////////
4177function hasParentInjector(parentLocation) {
4178 return parentLocation !== NO_PARENT_INJECTOR;
4179}
4180function getParentInjectorIndex(parentLocation) {
4181 ngDevMode && assertNumber(parentLocation, 'Number expected');
4182 ngDevMode && assertNotEqual(parentLocation, -1, 'Not a valid state.');
4183 const parentInjectorIndex = parentLocation & 32767 /* RelativeInjectorLocationFlags.InjectorIndexMask */;
4184 ngDevMode &&
4185 assertGreaterThan(parentInjectorIndex, HEADER_OFFSET, 'Parent injector must be pointing past HEADER_OFFSET.');
4186 return parentLocation & 32767 /* RelativeInjectorLocationFlags.InjectorIndexMask */;
4187}
4188function getParentInjectorViewOffset(parentLocation) {
4189 return parentLocation >> 16 /* RelativeInjectorLocationFlags.ViewOffsetShift */;
4190}
4191/**
4192 * Unwraps a parent injector location number to find the view offset from the current injector,
4193 * then walks up the declaration view tree until the view is found that contains the parent
4194 * injector.
4195 *
4196 * @param location The location of the parent injector, which contains the view offset
4197 * @param startView The LView instance from which to start walking up the view tree
4198 * @returns The LView instance that contains the parent injector
4199 */
4200function getParentInjectorView(location, startView) {
4201 let viewOffset = getParentInjectorViewOffset(location);
4202 let parentView = startView;
4203 // For most cases, the parent injector can be found on the host node (e.g. for component
4204 // or container), but we must keep the loop here to support the rarer case of deeply nested
4205 // <ng-template> tags or inline views, where the parent injector might live many views
4206 // above the child injector.
4207 while (viewOffset > 0) {
4208 parentView = parentView[DECLARATION_VIEW];
4209 viewOffset--;
4210 }
4211 return parentView;
4212}
4213
4214/**
4215 * Defines if the call to `inject` should include `viewProviders` in its resolution.
4216 *
4217 * This is set to true when we try to instantiate a component. This value is reset in
4218 * `getNodeInjectable` to a value which matches the declaration location of the token about to be
4219 * instantiated. This is done so that if we are injecting a token which was declared outside of
4220 * `viewProviders` we don't accidentally pull `viewProviders` in.
4221 *
4222 * Example:
4223 *
4224 * ```
4225 * @Injectable()
4226 * class MyService {
4227 * constructor(public value: String) {}
4228 * }
4229 *
4230 * @Component({
4231 * providers: [
4232 * MyService,
4233 * {provide: String, value: 'providers' }
4234 * ]
4235 * viewProviders: [
4236 * {provide: String, value: 'viewProviders'}
4237 * ]
4238 * })
4239 * class MyComponent {
4240 * constructor(myService: MyService, value: String) {
4241 * // We expect that Component can see into `viewProviders`.
4242 * expect(value).toEqual('viewProviders');
4243 * // `MyService` was not declared in `viewProviders` hence it can't see it.
4244 * expect(myService.value).toEqual('providers');
4245 * }
4246 * }
4247 *
4248 * ```
4249 */
4250let includeViewProviders = true;
4251function setIncludeViewProviders(v) {
4252 const oldValue = includeViewProviders;
4253 includeViewProviders = v;
4254 return oldValue;
4255}
4256/**
4257 * The number of slots in each bloom filter (used by DI). The larger this number, the fewer
4258 * directives that will share slots, and thus, the fewer false positives when checking for
4259 * the existence of a directive.
4260 */
4261const BLOOM_SIZE = 256;
4262const BLOOM_MASK = BLOOM_SIZE - 1;
4263/**
4264 * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits,
4265 * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash
4266 * number.
4267 */
4268const BLOOM_BUCKET_BITS = 5;
4269/** Counter used to generate unique IDs for directives. */
4270let nextNgElementId = 0;
4271/** Value used when something wasn't found by an injector. */
4272const NOT_FOUND = {};
4273/**
4274 * Registers this directive as present in its node's injector by flipping the directive's
4275 * corresponding bit in the injector's bloom filter.
4276 *
4277 * @param injectorIndex The index of the node injector where this token should be registered
4278 * @param tView The TView for the injector's bloom filters
4279 * @param type The directive token to register
4280 */
4281function bloomAdd(injectorIndex, tView, type) {
4282 ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
4283 let id;
4284 if (typeof type === 'string') {
4285 id = type.charCodeAt(0) || 0;
4286 }
4287 else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
4288 id = type[NG_ELEMENT_ID];
4289 }
4290 // Set a unique ID on the directive type, so if something tries to inject the directive,
4291 // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
4292 if (id == null) {
4293 id = type[NG_ELEMENT_ID] = nextNgElementId++;
4294 }
4295 // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
4296 // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
4297 const bloomHash = id & BLOOM_MASK;
4298 // Create a mask that targets the specific bit associated with the directive.
4299 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
4300 // to bit positions 0 - 31 in a 32 bit integer.
4301 const mask = 1 << bloomHash;
4302 // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`.
4303 // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask
4304 // should be written to.
4305 tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask;
4306}
4307/**
4308 * Creates (or gets an existing) injector for a given element or container.
4309 *
4310 * @param tNode for which an injector should be retrieved / created.
4311 * @param lView View where the node is stored
4312 * @returns Node injector
4313 */
4314function getOrCreateNodeInjectorForNode(tNode, lView) {
4315 const existingInjectorIndex = getInjectorIndex(tNode, lView);
4316 if (existingInjectorIndex !== -1) {
4317 return existingInjectorIndex;
4318 }
4319 const tView = lView[TVIEW];
4320 if (tView.firstCreatePass) {
4321 tNode.injectorIndex = lView.length;
4322 insertBloom(tView.data, tNode); // foundation for node bloom
4323 insertBloom(lView, null); // foundation for cumulative bloom
4324 insertBloom(tView.blueprint, null);
4325 }
4326 const parentLoc = getParentInjectorLocation(tNode, lView);
4327 const injectorIndex = tNode.injectorIndex;
4328 // If a parent injector can't be found, its location is set to -1.
4329 // In that case, we don't need to set up a cumulative bloom
4330 if (hasParentInjector(parentLoc)) {
4331 const parentIndex = getParentInjectorIndex(parentLoc);
4332 const parentLView = getParentInjectorView(parentLoc, lView);
4333 const parentData = parentLView[TVIEW].data;
4334 // Creates a cumulative bloom filter that merges the parent's bloom filter
4335 // and its own cumulative bloom (which contains tokens for all ancestors)
4336 for (let i = 0; i < 8 /* NodeInjectorOffset.BLOOM_SIZE */; i++) {
4337 lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
4338 }
4339 }
4340 lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */] = parentLoc;
4341 return injectorIndex;
4342}
4343function insertBloom(arr, footer) {
4344 arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
4345}
4346function getInjectorIndex(tNode, lView) {
4347 if (tNode.injectorIndex === -1 ||
4348 // If the injector index is the same as its parent's injector index, then the index has been
4349 // copied down from the parent node. No injector has been created yet on this node.
4350 (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
4351 // After the first template pass, the injector index might exist but the parent values
4352 // might not have been calculated yet for this instance
4353 lView[tNode.injectorIndex + 8 /* NodeInjectorOffset.PARENT */] === null) {
4354 return -1;
4355 }
4356 else {
4357 ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
4358 return tNode.injectorIndex;
4359 }
4360}
4361/**
4362 * Finds the index of the parent injector, with a view offset if applicable. Used to set the
4363 * parent injector initially.
4364 *
4365 * @returns Returns a number that is the combination of the number of LViews that we have to go up
4366 * to find the LView containing the parent inject AND the index of the injector within that LView.
4367 */
4368function getParentInjectorLocation(tNode, lView) {
4369 if (tNode.parent && tNode.parent.injectorIndex !== -1) {
4370 // If we have a parent `TNode` and there is an injector associated with it we are done, because
4371 // the parent injector is within the current `LView`.
4372 return tNode.parent.injectorIndex; // ViewOffset is 0
4373 }
4374 // When parent injector location is computed it may be outside of the current view. (ie it could
4375 // be pointing to a declared parent location). This variable stores number of declaration parents
4376 // we need to walk up in order to find the parent injector location.
4377 let declarationViewOffset = 0;
4378 let parentTNode = null;
4379 let lViewCursor = lView;
4380 // The parent injector is not in the current `LView`. We will have to walk the declared parent
4381 // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
4382 // `NodeInjector`.
4383 while (lViewCursor !== null) {
4384 parentTNode = getTNodeFromLView(lViewCursor);
4385 if (parentTNode === null) {
4386 // If we have no parent, than we are done.
4387 return NO_PARENT_INJECTOR;
4388 }
4389 ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]);
4390 // Every iteration of the loop requires that we go to the declared parent.
4391 declarationViewOffset++;
4392 lViewCursor = lViewCursor[DECLARATION_VIEW];
4393 if (parentTNode.injectorIndex !== -1) {
4394 // We found a NodeInjector which points to something.
4395 return (parentTNode.injectorIndex |
4396 (declarationViewOffset << 16 /* RelativeInjectorLocationFlags.ViewOffsetShift */));
4397 }
4398 }
4399 return NO_PARENT_INJECTOR;
4400}
4401/**
4402 * Makes a type or an injection token public to the DI system by adding it to an
4403 * injector's bloom filter.
4404 *
4405 * @param di The node injector in which a directive will be added
4406 * @param token The type or the injection token to be made public
4407 */
4408function diPublicInInjector(injectorIndex, tView, token) {
4409 bloomAdd(injectorIndex, tView, token);
4410}
4411/**
4412 * Inject static attribute value into directive constructor.
4413 *
4414 * This method is used with `factory` functions which are generated as part of
4415 * `defineDirective` or `defineComponent`. The method retrieves the static value
4416 * of an attribute. (Dynamic attributes are not supported since they are not resolved
4417 * at the time of injection and can change over time.)
4418 *
4419 * # Example
4420 * Given:
4421 * ```
4422 * @Component(...)
4423 * class MyComponent {
4424 * constructor(@Attribute('title') title: string) { ... }
4425 * }
4426 * ```
4427 * When instantiated with
4428 * ```
4429 * <my-component title="Hello"></my-component>
4430 * ```
4431 *
4432 * Then factory method generated is:
4433 * ```
4434 * MyComponent.ɵcmp = defineComponent({
4435 * factory: () => new MyComponent(injectAttribute('title'))
4436 * ...
4437 * })
4438 * ```
4439 *
4440 * @publicApi
4441 */
4442function injectAttributeImpl(tNode, attrNameToInject) {
4443 ngDevMode && assertTNodeType(tNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */);
4444 ngDevMode && assertDefined(tNode, 'expecting tNode');
4445 if (attrNameToInject === 'class') {
4446 return tNode.classes;
4447 }
4448 if (attrNameToInject === 'style') {
4449 return tNode.styles;
4450 }
4451 const attrs = tNode.attrs;
4452 if (attrs) {
4453 const attrsLength = attrs.length;
4454 let i = 0;
4455 while (i < attrsLength) {
4456 const value = attrs[i];
4457 // If we hit a `Bindings` or `Template` marker then we are done.
4458 if (isNameOnlyAttributeMarker(value))
4459 break;
4460 // Skip namespaced attributes
4461 if (value === 0 /* AttributeMarker.NamespaceURI */) {
4462 // we skip the next two values
4463 // as namespaced attributes looks like
4464 // [..., AttributeMarker.NamespaceURI, 'http://someuri.com/test', 'test:exist',
4465 // 'existValue', ...]
4466 i = i + 2;
4467 }
4468 else if (typeof value === 'number') {
4469 // Skip to the first value of the marked attribute.
4470 i++;
4471 while (i < attrsLength && typeof attrs[i] === 'string') {
4472 i++;
4473 }
4474 }
4475 else if (value === attrNameToInject) {
4476 return attrs[i + 1];
4477 }
4478 else {
4479 i = i + 2;
4480 }
4481 }
4482 }
4483 return null;
4484}
4485function notFoundValueOrThrow(notFoundValue, token, flags) {
4486 if ((flags & InjectFlags.Optional) || notFoundValue !== undefined) {
4487 return notFoundValue;
4488 }
4489 else {
4490 throwProviderNotFoundError(token, 'NodeInjector');
4491 }
4492}
4493/**
4494 * Returns the value associated to the given token from the ModuleInjector or throws exception
4495 *
4496 * @param lView The `LView` that contains the `tNode`
4497 * @param token The token to look for
4498 * @param flags Injection flags
4499 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
4500 * @returns the value from the injector or throws an exception
4501 */
4502function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) {
4503 if ((flags & InjectFlags.Optional) && notFoundValue === undefined) {
4504 // This must be set or the NullInjector will throw for optional deps
4505 notFoundValue = null;
4506 }
4507 if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
4508 const moduleInjector = lView[INJECTOR$1];
4509 // switch to `injectInjectorOnly` implementation for module injector, since module injector
4510 // should not have access to Component/Directive DI scope (that may happen through
4511 // `directiveInject` implementation)
4512 const previousInjectImplementation = setInjectImplementation(undefined);
4513 try {
4514 if (moduleInjector) {
4515 return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
4516 }
4517 else {
4518 return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
4519 }
4520 }
4521 finally {
4522 setInjectImplementation(previousInjectImplementation);
4523 }
4524 }
4525 return notFoundValueOrThrow(notFoundValue, token, flags);
4526}
4527/**
4528 * Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
4529 *
4530 * Look for the injector providing the token by walking up the node injector tree and then
4531 * the module injector tree.
4532 *
4533 * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom
4534 * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`)
4535 *
4536 * @param tNode The Node where the search for the injector should start
4537 * @param lView The `LView` that contains the `tNode`
4538 * @param token The token to look for
4539 * @param flags Injection flags
4540 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
4541 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
4542 */
4543function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) {
4544 if (tNode !== null) {
4545 // If the view or any of its ancestors have an embedded
4546 // view injector, we have to look it up there first.
4547 if (lView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) {
4548 const embeddedInjectorValue = lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, NOT_FOUND);
4549 if (embeddedInjectorValue !== NOT_FOUND) {
4550 return embeddedInjectorValue;
4551 }
4552 }
4553 // Otherwise try the node injector.
4554 const value = lookupTokenUsingNodeInjector(tNode, lView, token, flags, NOT_FOUND);
4555 if (value !== NOT_FOUND) {
4556 return value;
4557 }
4558 }
4559 // Finally, fall back to the module injector.
4560 return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
4561}
4562/**
4563 * Returns the value associated to the given token from the node injector.
4564 *
4565 * @param tNode The Node where the search for the injector should start
4566 * @param lView The `LView` that contains the `tNode`
4567 * @param token The token to look for
4568 * @param flags Injection flags
4569 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
4570 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
4571 */
4572function lookupTokenUsingNodeInjector(tNode, lView, token, flags, notFoundValue) {
4573 const bloomHash = bloomHashBitOrFactory(token);
4574 // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
4575 // so just call the factory function to create it.
4576 if (typeof bloomHash === 'function') {
4577 if (!enterDI(lView, tNode, flags)) {
4578 // Failed to enter DI, try module injector instead. If a token is injected with the @Host
4579 // flag, the module injector is not searched for that token in Ivy.
4580 return (flags & InjectFlags.Host) ?
4581 notFoundValueOrThrow(notFoundValue, token, flags) :
4582 lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
4583 }
4584 try {
4585 const value = bloomHash(flags);
4586 if (value == null && !(flags & InjectFlags.Optional)) {
4587 throwProviderNotFoundError(token);
4588 }
4589 else {
4590 return value;
4591 }
4592 }
4593 finally {
4594 leaveDI();
4595 }
4596 }
4597 else if (typeof bloomHash === 'number') {
4598 // A reference to the previous injector TView that was found while climbing the element
4599 // injector tree. This is used to know if viewProviders can be accessed on the current
4600 // injector.
4601 let previousTView = null;
4602 let injectorIndex = getInjectorIndex(tNode, lView);
4603 let parentLocation = NO_PARENT_INJECTOR;
4604 let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
4605 // If we should skip this injector, or if there is no injector on this node, start by
4606 // searching the parent injector.
4607 if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
4608 parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
4609 lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */];
4610 if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
4611 injectorIndex = -1;
4612 }
4613 else {
4614 previousTView = lView[TVIEW];
4615 injectorIndex = getParentInjectorIndex(parentLocation);
4616 lView = getParentInjectorView(parentLocation, lView);
4617 }
4618 }
4619 // Traverse up the injector tree until we find a potential match or until we know there
4620 // *isn't* a match.
4621 while (injectorIndex !== -1) {
4622 ngDevMode && assertNodeInjector(lView, injectorIndex);
4623 // Check the current injector. If it matches, see if it contains token.
4624 const tView = lView[TVIEW];
4625 ngDevMode &&
4626 assertTNodeForLView(tView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */], lView);
4627 if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
4628 // At this point, we have an injector which *may* contain the token, so we step through
4629 // the providers and directives associated with the injector's corresponding node to get
4630 // the instance.
4631 const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode);
4632 if (instance !== NOT_FOUND) {
4633 return instance;
4634 }
4635 }
4636 parentLocation = lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */];
4637 if (parentLocation !== NO_PARENT_INJECTOR &&
4638 shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */] === hostTElementNode) &&
4639 bloomHasToken(bloomHash, injectorIndex, lView)) {
4640 // The def wasn't found anywhere on this node, so it was a false positive.
4641 // Traverse up the tree and continue searching.
4642 previousTView = tView;
4643 injectorIndex = getParentInjectorIndex(parentLocation);
4644 lView = getParentInjectorView(parentLocation, lView);
4645 }
4646 else {
4647 // If we should not search parent OR If the ancestor bloom filter value does not have the
4648 // bit corresponding to the directive we can give up on traversing up to find the specific
4649 // injector.
4650 injectorIndex = -1;
4651 }
4652 }
4653 }
4654 return notFoundValue;
4655}
4656function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) {
4657 const currentTView = lView[TVIEW];
4658 const tNode = currentTView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
4659 // First, we need to determine if view providers can be accessed by the starting element.
4660 // There are two possibilities
4661 const canAccessViewProviders = previousTView == null ?
4662 // 1) This is the first invocation `previousTView == null` which means that we are at the
4663 // `TNode` of where injector is starting to look. In such a case the only time we are allowed
4664 // to look into the ViewProviders is if:
4665 // - we are on a component
4666 // - AND the injector set `includeViewProviders` to true (implying that the token can see
4667 // ViewProviders because it is the Component or a Service which itself was declared in
4668 // ViewProviders)
4669 (isComponentHost(tNode) && includeViewProviders) :
4670 // 2) `previousTView != null` which means that we are now walking across the parent nodes.
4671 // In such a case we are only allowed to look into the ViewProviders if:
4672 // - We just crossed from child View to Parent View `previousTView != currentTView`
4673 // - AND the parent TNode is an Element.
4674 // This means that we just came from the Component's View and therefore are allowed to see
4675 // into the ViewProviders.
4676 (previousTView != currentTView && ((tNode.type & 3 /* TNodeType.AnyRNode */) !== 0));
4677 // This special case happens when there is a @host on the inject and when we are searching
4678 // on the host element node.
4679 const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode;
4680 const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase);
4681 if (injectableIdx !== null) {
4682 return getNodeInjectable(lView, currentTView, injectableIdx, tNode);
4683 }
4684 else {
4685 return NOT_FOUND;
4686 }
4687}
4688/**
4689 * Searches for the given token among the node's directives and providers.
4690 *
4691 * @param tNode TNode on which directives are present.
4692 * @param tView The tView we are currently processing
4693 * @param token Provider token or type of a directive to look for.
4694 * @param canAccessViewProviders Whether view providers should be considered.
4695 * @param isHostSpecialCase Whether the host special case applies.
4696 * @returns Index of a found directive or provider, or null when none found.
4697 */
4698function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) {
4699 const nodeProviderIndexes = tNode.providerIndexes;
4700 const tInjectables = tView.data;
4701 const injectablesStart = nodeProviderIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */;
4702 const directivesStart = tNode.directiveStart;
4703 const directiveEnd = tNode.directiveEnd;
4704 const cptViewProvidersCount = nodeProviderIndexes >> 20 /* TNodeProviderIndexes.CptViewProvidersCountShift */;
4705 const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount;
4706 // When the host special case applies, only the viewProviders and the component are visible
4707 const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd;
4708 for (let i = startingIndex; i < endIndex; i++) {
4709 const providerTokenOrDef = tInjectables[i];
4710 if (i < directivesStart && token === providerTokenOrDef ||
4711 i >= directivesStart && providerTokenOrDef.type === token) {
4712 return i;
4713 }
4714 }
4715 if (isHostSpecialCase) {
4716 const dirDef = tInjectables[directivesStart];
4717 if (dirDef && isComponentDef(dirDef) && dirDef.type === token) {
4718 return directivesStart;
4719 }
4720 }
4721 return null;
4722}
4723/**
4724 * Retrieve or instantiate the injectable from the `LView` at particular `index`.
4725 *
4726 * This function checks to see if the value has already been instantiated and if so returns the
4727 * cached `injectable`. Otherwise if it detects that the value is still a factory it
4728 * instantiates the `injectable` and caches the value.
4729 */
4730function getNodeInjectable(lView, tView, index, tNode) {
4731 let value = lView[index];
4732 const tData = tView.data;
4733 if (isFactory(value)) {
4734 const factory = value;
4735 if (factory.resolving) {
4736 throwCyclicDependencyError(stringifyForError(tData[index]));
4737 }
4738 const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
4739 factory.resolving = true;
4740 const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
4741 const success = enterDI(lView, tNode, InjectFlags.Default);
4742 ngDevMode &&
4743 assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.');
4744 try {
4745 value = lView[index] = factory.factory(undefined, tData, lView, tNode);
4746 // This code path is hit for both directives and providers.
4747 // For perf reasons, we want to avoid searching for hooks on providers.
4748 // It does no harm to try (the hooks just won't exist), but the extra
4749 // checks are unnecessary and this is a hot path. So we check to see
4750 // if the index of the dependency is in the directive range for this
4751 // tNode. If it's not, we know it's a provider and skip hook registration.
4752 if (tView.firstCreatePass && index >= tNode.directiveStart) {
4753 ngDevMode && assertDirectiveDef(tData[index]);
4754 registerPreOrderHooks(index, tData[index], tView);
4755 }
4756 }
4757 finally {
4758 previousInjectImplementation !== null &&
4759 setInjectImplementation(previousInjectImplementation);
4760 setIncludeViewProviders(previousIncludeViewProviders);
4761 factory.resolving = false;
4762 leaveDI();
4763 }
4764 }
4765 return value;
4766}
4767/**
4768 * Returns the bit in an injector's bloom filter that should be used to determine whether or not
4769 * the directive might be provided by the injector.
4770 *
4771 * When a directive is public, it is added to the bloom filter and given a unique ID that can be
4772 * retrieved on the Type. When the directive isn't public or the token is not a directive `null`
4773 * is returned as the node injector can not possibly provide that token.
4774 *
4775 * @param token the injection token
4776 * @returns the matching bit to check in the bloom filter or `null` if the token is not known.
4777 * When the returned value is negative then it represents special values such as `Injector`.
4778 */
4779function bloomHashBitOrFactory(token) {
4780 ngDevMode && assertDefined(token, 'token must be defined');
4781 if (typeof token === 'string') {
4782 return token.charCodeAt(0) || 0;
4783 }
4784 const tokenId =
4785 // First check with `hasOwnProperty` so we don't get an inherited ID.
4786 token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined;
4787 // Negative token IDs are used for special objects such as `Injector`
4788 if (typeof tokenId === 'number') {
4789 if (tokenId >= 0) {
4790 return tokenId & BLOOM_MASK;
4791 }
4792 else {
4793 ngDevMode &&
4794 assertEqual(tokenId, -1 /* InjectorMarkers.Injector */, 'Expecting to get Special Injector Id');
4795 return createNodeInjector;
4796 }
4797 }
4798 else {
4799 return tokenId;
4800 }
4801}
4802function bloomHasToken(bloomHash, injectorIndex, injectorView) {
4803 // Create a mask that targets the specific bit associated with the directive we're looking for.
4804 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
4805 // to bit positions 0 - 31 in a 32 bit integer.
4806 const mask = 1 << bloomHash;
4807 // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of
4808 // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset
4809 // that should be used.
4810 const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)];
4811 // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
4812 // this injector is a potential match.
4813 return !!(value & mask);
4814}
4815/** Returns true if flags prevent parent injector from being searched for tokens */
4816function shouldSearchParent(flags, isFirstHostTNode) {
4817 return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode);
4818}
4819class NodeInjector {
4820 constructor(_tNode, _lView) {
4821 this._tNode = _tNode;
4822 this._lView = _lView;
4823 }
4824 get(token, notFoundValue, flags) {
4825 return getOrCreateInjectable(this._tNode, this._lView, token, convertToBitFlags(flags), notFoundValue);
4826 }
4827}
4828/** Creates a `NodeInjector` for the current node. */
4829function createNodeInjector() {
4830 return new NodeInjector(getCurrentTNode(), getLView());
4831}
4832/**
4833 * @codeGenApi
4834 */
4835function ɵɵgetInheritedFactory(type) {
4836 return noSideEffects(() => {
4837 const ownConstructor = type.prototype.constructor;
4838 const ownFactory = ownConstructor[NG_FACTORY_DEF] || getFactoryOf(ownConstructor);
4839 const objectPrototype = Object.prototype;
4840 let parent = Object.getPrototypeOf(type.prototype).constructor;
4841 // Go up the prototype until we hit `Object`.
4842 while (parent && parent !== objectPrototype) {
4843 const factory = parent[NG_FACTORY_DEF] || getFactoryOf(parent);
4844 // If we hit something that has a factory and the factory isn't the same as the type,
4845 // we've found the inherited factory. Note the check that the factory isn't the type's
4846 // own factory is redundant in most cases, but if the user has custom decorators on the
4847 // class, this lookup will start one level down in the prototype chain, causing us to
4848 // find the own factory first and potentially triggering an infinite loop downstream.
4849 if (factory && factory !== ownFactory) {
4850 return factory;
4851 }
4852 parent = Object.getPrototypeOf(parent);
4853 }
4854 // There is no factory defined. Either this was improper usage of inheritance
4855 // (no Angular decorator on the superclass) or there is no constructor at all
4856 // in the inheritance chain. Since the two cases cannot be distinguished, the
4857 // latter has to be assumed.
4858 return t => new t();
4859 });
4860}
4861function getFactoryOf(type) {
4862 if (isForwardRef(type)) {
4863 return () => {
4864 const factory = getFactoryOf(resolveForwardRef(type));
4865 return factory && factory();
4866 };
4867 }
4868 return getFactoryDef(type);
4869}
4870/**
4871 * Returns a value from the closest embedded or node injector.
4872 *
4873 * @param tNode The Node where the search for the injector should start
4874 * @param lView The `LView` that contains the `tNode`
4875 * @param token The token to look for
4876 * @param flags Injection flags
4877 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
4878 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
4879 */
4880function lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, notFoundValue) {
4881 let currentTNode = tNode;
4882 let currentLView = lView;
4883 // When an LView with an embedded view injector is inserted, it'll likely be interlaced with
4884 // nodes who may have injectors (e.g. node injector -> embedded view injector -> node injector).
4885 // Since the bloom filters for the node injectors have already been constructed and we don't
4886 // have a way of extracting the records from an injector, the only way to maintain the correct
4887 // hierarchy when resolving the value is to walk it node-by-node while attempting to resolve
4888 // the token at each level.
4889 while (currentTNode !== null && currentLView !== null &&
4890 (currentLView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) &&
4891 !(currentLView[FLAGS] & 256 /* LViewFlags.IsRoot */)) {
4892 ngDevMode && assertTNodeForLView(currentTNode, currentLView);
4893 // Note that this lookup on the node injector is using the `Self` flag, because
4894 // we don't want the node injector to look at any parent injectors since we
4895 // may hit the embedded view injector first.
4896 const nodeInjectorValue = lookupTokenUsingNodeInjector(currentTNode, currentLView, token, flags | InjectFlags.Self, NOT_FOUND);
4897 if (nodeInjectorValue !== NOT_FOUND) {
4898 return nodeInjectorValue;
4899 }
4900 // Has an explicit type due to a TS bug: https://github.com/microsoft/TypeScript/issues/33191
4901 let parentTNode = currentTNode.parent;
4902 // `TNode.parent` includes the parent within the current view only. If it doesn't exist,
4903 // it means that we've hit the view boundary and we need to go up to the next view.
4904 if (!parentTNode) {
4905 // Before we go to the next LView, check if the token exists on the current embedded injector.
4906 const embeddedViewInjector = currentLView[EMBEDDED_VIEW_INJECTOR];
4907 if (embeddedViewInjector) {
4908 const embeddedViewInjectorValue = embeddedViewInjector.get(token, NOT_FOUND, flags);
4909 if (embeddedViewInjectorValue !== NOT_FOUND) {
4910 return embeddedViewInjectorValue;
4911 }
4912 }
4913 // Otherwise keep going up the tree.
4914 parentTNode = getTNodeFromLView(currentLView);
4915 currentLView = currentLView[DECLARATION_VIEW];
4916 }
4917 currentTNode = parentTNode;
4918 }
4919 return notFoundValue;
4920}
4921/** Gets the TNode associated with an LView inside of the declaration view. */
4922function getTNodeFromLView(lView) {
4923 const tView = lView[TVIEW];
4924 const tViewType = tView.type;
4925 // The parent pointer differs based on `TView.type`.
4926 if (tViewType === 2 /* TViewType.Embedded */) {
4927 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
4928 return tView.declTNode;
4929 }
4930 else if (tViewType === 1 /* TViewType.Component */) {
4931 // Components don't have `TView.declTNode` because each instance of component could be
4932 // inserted in different location, hence `TView.declTNode` is meaningless.
4933 return lView[T_HOST];
4934 }
4935 return null;
4936}
4937
4938/**
4939 * Facade for the attribute injection from DI.
4940 *
4941 * @codeGenApi
4942 */
4943function ɵɵinjectAttribute(attrNameToInject) {
4944 return injectAttributeImpl(getCurrentTNode(), attrNameToInject);
4945}
4946
4947/**
4948 * Attribute decorator and metadata.
4949 *
4950 * @Annotation
4951 * @publicApi
4952 */
4953const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName) }));
4954
4955let _reflect = null;
4956function getReflect() {
4957 return (_reflect = _reflect || new ReflectionCapabilities());
4958}
4959function reflectDependencies(type) {
4960 return convertDependencies(getReflect().parameters(type));
4961}
4962function convertDependencies(deps) {
4963 return deps.map(dep => reflectDependency(dep));
4964}
4965function reflectDependency(dep) {
4966 const meta = {
4967 token: null,
4968 attribute: null,
4969 host: false,
4970 optional: false,
4971 self: false,
4972 skipSelf: false,
4973 };
4974 if (Array.isArray(dep) && dep.length > 0) {
4975 for (let j = 0; j < dep.length; j++) {
4976 const param = dep[j];
4977 if (param === undefined) {
4978 // param may be undefined if type of dep is not set by ngtsc
4979 continue;
4980 }
4981 const proto = Object.getPrototypeOf(param);
4982 if (param instanceof Optional || proto.ngMetadataName === 'Optional') {
4983 meta.optional = true;
4984 }
4985 else if (param instanceof SkipSelf || proto.ngMetadataName === 'SkipSelf') {
4986 meta.skipSelf = true;
4987 }
4988 else if (param instanceof Self || proto.ngMetadataName === 'Self') {
4989 meta.self = true;
4990 }
4991 else if (param instanceof Host || proto.ngMetadataName === 'Host') {
4992 meta.host = true;
4993 }
4994 else if (param instanceof Inject) {
4995 meta.token = param.token;
4996 }
4997 else if (param instanceof Attribute) {
4998 if (param.attributeName === undefined) {
4999 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Attribute name must be defined.`);
5000 }
5001 meta.attribute = param.attributeName;
5002 }
5003 else {
5004 meta.token = param;
5005 }
5006 }
5007 }
5008 else if (dep === undefined || (Array.isArray(dep) && dep.length === 0)) {
5009 meta.token = null;
5010 }
5011 else {
5012 meta.token = dep;
5013 }
5014 return meta;
5015}
5016
5017/**
5018 * Map of module-id to the corresponding NgModule.
5019 */
5020const modules = new Map();
5021/**
5022 * Whether to check for duplicate NgModule registrations.
5023 *
5024 * This can be disabled for testing.
5025 */
5026let checkForDuplicateNgModules = true;
5027function assertSameOrNotExisting(id, type, incoming) {
5028 if (type && type !== incoming && checkForDuplicateNgModules) {
5029 throw new Error(`Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`);
5030 }
5031}
5032/**
5033 * Adds the given NgModule type to Angular's NgModule registry.
5034 *
5035 * This is generated as a side-effect of NgModule compilation. Note that the `id` is passed in
5036 * explicitly and not read from the NgModule definition. This is for two reasons: it avoids a
5037 * megamorphic read, and in JIT there's a chicken-and-egg problem where the NgModule may not be
5038 * fully resolved when it's registered.
5039 *
5040 * @codeGenApi
5041 */
5042function registerNgModuleType(ngModuleType, id) {
5043 const existing = modules.get(id) || null;
5044 assertSameOrNotExisting(id, existing, ngModuleType);
5045 modules.set(id, ngModuleType);
5046}
5047function clearModulesForTest() {
5048 modules.clear();
5049}
5050function getRegisteredNgModuleType(id) {
5051 return modules.get(id);
5052}
5053/**
5054 * Control whether the NgModule registration system enforces that each NgModule type registered has
5055 * a unique id.
5056 *
5057 * This is useful for testing as the NgModule registry cannot be properly reset between tests with
5058 * Angular's current API.
5059 */
5060function setAllowDuplicateNgModuleIdsForTest(allowDuplicates) {
5061 checkForDuplicateNgModules = !allowDuplicates;
5062}
5063
5064/**
5065 *
5066 * @codeGenApi
5067 */
5068function ɵɵresolveWindow(element) {
5069 return element.ownerDocument.defaultView;
5070}
5071/**
5072 *
5073 * @codeGenApi
5074 */
5075function ɵɵresolveDocument(element) {
5076 return element.ownerDocument;
5077}
5078/**
5079 *
5080 * @codeGenApi
5081 */
5082function ɵɵresolveBody(element) {
5083 return element.ownerDocument.body;
5084}
5085/**
5086 * The special delimiter we use to separate property names, prefixes, and suffixes
5087 * in property binding metadata. See storeBindingMetadata().
5088 *
5089 * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter
5090 * because it is a very uncommon character that is unlikely to be part of a user's
5091 * property names or interpolation strings. If it is in fact used in a property
5092 * binding, DebugElement.properties will not return the correct value for that
5093 * binding. However, there should be no runtime effect for real applications.
5094 *
5095 * This character is typically rendered as a question mark inside of a diamond.
5096 * See https://en.wikipedia.org/wiki/Specials_(Unicode_block)
5097 *
5098 */
5099const INTERPOLATION_DELIMITER = `�`;
5100/**
5101 * Unwrap a value which might be behind a closure (for forward declaration reasons).
5102 */
5103function maybeUnwrapFn$1(value) {
5104 if (value instanceof Function) {
5105 return value();
5106 }
5107 else {
5108 return value;
5109 }
5110}
5111
5112/**
5113 * Defines a schema that allows an NgModule to contain the following:
5114 * - Non-Angular elements named with dash case (`-`).
5115 * - Element properties named with dash case (`-`).
5116 * Dash case is the naming convention for custom elements.
5117 *
5118 * @publicApi
5119 */
5120const CUSTOM_ELEMENTS_SCHEMA = {
5121 name: 'custom-elements'
5122};
5123/**
5124 * Defines a schema that allows any property on any element.
5125 *
5126 * This schema allows you to ignore the errors related to any unknown elements or properties in a
5127 * template. The usage of this schema is generally discouraged because it prevents useful validation
5128 * and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
5129 *
5130 * @publicApi
5131 */
5132const NO_ERRORS_SCHEMA = {
5133 name: 'no-errors-schema'
5134};
5135
5136let shouldThrowErrorOnUnknownElement = false;
5137/**
5138 * Sets a strict mode for JIT-compiled components to throw an error on unknown elements,
5139 * instead of just logging the error.
5140 * (for AOT-compiled ones this check happens at build time).
5141 */
5142function ɵsetUnknownElementStrictMode(shouldThrow) {
5143 shouldThrowErrorOnUnknownElement = shouldThrow;
5144}
5145/**
5146 * Gets the current value of the strict mode.
5147 */
5148function ɵgetUnknownElementStrictMode() {
5149 return shouldThrowErrorOnUnknownElement;
5150}
5151let shouldThrowErrorOnUnknownProperty = false;
5152/**
5153 * Sets a strict mode for JIT-compiled components to throw an error on unknown properties,
5154 * instead of just logging the error.
5155 * (for AOT-compiled ones this check happens at build time).
5156 */
5157function ɵsetUnknownPropertyStrictMode(shouldThrow) {
5158 shouldThrowErrorOnUnknownProperty = shouldThrow;
5159}
5160/**
5161 * Gets the current value of the strict mode.
5162 */
5163function ɵgetUnknownPropertyStrictMode() {
5164 return shouldThrowErrorOnUnknownProperty;
5165}
5166/**
5167 * Validates that the element is known at runtime and produces
5168 * an error if it's not the case.
5169 * This check is relevant for JIT-compiled components (for AOT-compiled
5170 * ones this check happens at build time).
5171 *
5172 * The element is considered known if either:
5173 * - it's a known HTML element
5174 * - it's a known custom element
5175 * - the element matches any directive
5176 * - the element is allowed by one of the schemas
5177 *
5178 * @param element Element to validate
5179 * @param lView An `LView` that represents a current component that is being rendered
5180 * @param tagName Name of the tag to check
5181 * @param schemas Array of schemas
5182 * @param hasDirectives Boolean indicating that the element matches any directive
5183 */
5184function validateElementIsKnown(element, lView, tagName, schemas, hasDirectives) {
5185 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
5186 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
5187 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
5188 // execute the check below.
5189 if (schemas === null)
5190 return;
5191 // If the element matches any directive, it's considered as valid.
5192 if (!hasDirectives && tagName !== null) {
5193 // The element is unknown if it's an instance of HTMLUnknownElement, or it isn't registered
5194 // as a custom element. Note that unknown elements with a dash in their name won't be instances
5195 // of HTMLUnknownElement in browsers that support web components.
5196 const isUnknown =
5197 // Note that we can't check for `typeof HTMLUnknownElement === 'function'`,
5198 // because while most browsers return 'function', IE returns 'object'.
5199 (typeof HTMLUnknownElement !== 'undefined' && HTMLUnknownElement &&
5200 element instanceof HTMLUnknownElement) ||
5201 (typeof customElements !== 'undefined' && tagName.indexOf('-') > -1 &&
5202 !customElements.get(tagName));
5203 if (isUnknown && !matchingSchemas(schemas, tagName)) {
5204 const isHostStandalone = isHostComponentStandalone(lView);
5205 const templateLocation = getTemplateLocationDetails(lView);
5206 const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
5207 let message = `'${tagName}' is not a known element${templateLocation}:\n`;
5208 message += `1. If '${tagName}' is an Angular component, then verify that it is ${isHostStandalone ? 'included in the \'@Component.imports\' of this component' :
5209 'a part of an @NgModule where this component is declared'}.\n`;
5210 if (tagName && tagName.indexOf('-') > -1) {
5211 message +=
5212 `2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${schemas} of this component to suppress this message.`;
5213 }
5214 else {
5215 message +=
5216 `2. To allow any element add 'NO_ERRORS_SCHEMA' to the ${schemas} of this component.`;
5217 }
5218 if (shouldThrowErrorOnUnknownElement) {
5219 throw new RuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message);
5220 }
5221 else {
5222 console.error(formatRuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message));
5223 }
5224 }
5225 }
5226}
5227/**
5228 * Validates that the property of the element is known at runtime and returns
5229 * false if it's not the case.
5230 * This check is relevant for JIT-compiled components (for AOT-compiled
5231 * ones this check happens at build time).
5232 *
5233 * The property is considered known if either:
5234 * - it's a known property of the element
5235 * - the element is allowed by one of the schemas
5236 * - the property is used for animations
5237 *
5238 * @param element Element to validate
5239 * @param propName Name of the property to check
5240 * @param tagName Name of the tag hosting the property
5241 * @param schemas Array of schemas
5242 */
5243function isPropertyValid(element, propName, tagName, schemas) {
5244 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
5245 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
5246 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
5247 // execute the check below.
5248 if (schemas === null)
5249 return true;
5250 // The property is considered valid if the element matches the schema, it exists on the element,
5251 // or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
5252 if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
5253 return true;
5254 }
5255 // Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
5256 // need to account for both here, while being careful with `typeof null` also returning 'object'.
5257 return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
5258}
5259/**
5260 * Logs or throws an error that a property is not supported on an element.
5261 *
5262 * @param propName Name of the invalid property
5263 * @param tagName Name of the tag hosting the property
5264 * @param nodeType Type of the node hosting the property
5265 * @param lView An `LView` that represents a current component
5266 */
5267function handleUnknownPropertyError(propName, tagName, nodeType, lView) {
5268 // Special-case a situation when a structural directive is applied to
5269 // an `<ng-template>` element, for example: `<ng-template *ngIf="true">`.
5270 // In this case the compiler generates the `ɵɵtemplate` instruction with
5271 // the `null` as the tagName. The directive matching logic at runtime relies
5272 // on this effect (see `isInlineTemplate`), thus using the 'ng-template' as
5273 // a default value of the `tNode.value` is not feasible at this moment.
5274 if (!tagName && nodeType === 4 /* TNodeType.Container */) {
5275 tagName = 'ng-template';
5276 }
5277 const isHostStandalone = isHostComponentStandalone(lView);
5278 const templateLocation = getTemplateLocationDetails(lView);
5279 let message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'${templateLocation}.`;
5280 const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
5281 const importLocation = isHostStandalone ?
5282 'included in the \'@Component.imports\' of this component' :
5283 'a part of an @NgModule where this component is declared';
5284 if (KNOWN_CONTROL_FLOW_DIRECTIVES.has(propName)) {
5285 // Most likely this is a control flow directive (such as `*ngIf`) used in
5286 // a template, but the directive or the `CommonModule` is not imported.
5287 const correspondingImport = KNOWN_CONTROL_FLOW_DIRECTIVES.get(propName);
5288 message += `\nIf the '${propName}' is an Angular control flow directive, ` +
5289 `please make sure that either the '${correspondingImport}' directive or the 'CommonModule' is ${importLocation}.`;
5290 }
5291 else {
5292 // May be an Angular component, which is not imported/declared?
5293 message += `\n1. If '${tagName}' is an Angular component and it has the ` +
5294 `'${propName}' input, then verify that it is ${importLocation}.`;
5295 // May be a Web Component?
5296 if (tagName && tagName.indexOf('-') > -1) {
5297 message += `\n2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' ` +
5298 `to the ${schemas} of this component to suppress this message.`;
5299 message += `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
5300 `the ${schemas} of this component.`;
5301 }
5302 else {
5303 // If it's expected, the error can be suppressed by the `NO_ERRORS_SCHEMA` schema.
5304 message += `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
5305 `the ${schemas} of this component.`;
5306 }
5307 }
5308 reportUnknownPropertyError(message);
5309}
5310function reportUnknownPropertyError(message) {
5311 if (shouldThrowErrorOnUnknownProperty) {
5312 throw new RuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message);
5313 }
5314 else {
5315 console.error(formatRuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message));
5316 }
5317}
5318/**
5319 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
5320 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
5321 * be too slow for production mode and also it relies on the constructor function being available.
5322 *
5323 * Gets a reference to the host component def (where a current component is declared).
5324 *
5325 * @param lView An `LView` that represents a current component that is being rendered.
5326 */
5327function getDeclarationComponentDef(lView) {
5328 !ngDevMode && throwError('Must never be called in production mode');
5329 const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
5330 const context = declarationLView[CONTEXT];
5331 // Unable to obtain a context.
5332 if (!context)
5333 return null;
5334 return context.constructor ? getComponentDef$1(context.constructor) : null;
5335}
5336/**
5337 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
5338 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
5339 * be too slow for production mode.
5340 *
5341 * Checks if the current component is declared inside of a standalone component template.
5342 *
5343 * @param lView An `LView` that represents a current component that is being rendered.
5344 */
5345function isHostComponentStandalone(lView) {
5346 !ngDevMode && throwError('Must never be called in production mode');
5347 const componentDef = getDeclarationComponentDef(lView);
5348 // Treat host component as non-standalone if we can't obtain the def.
5349 return !!(componentDef === null || componentDef === void 0 ? void 0 : componentDef.standalone);
5350}
5351/**
5352 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
5353 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
5354 * be too slow for production mode.
5355 *
5356 * Constructs a string describing the location of the host component template. The function is used
5357 * in dev mode to produce error messages.
5358 *
5359 * @param lView An `LView` that represents a current component that is being rendered.
5360 */
5361function getTemplateLocationDetails(lView) {
5362 var _a;
5363 !ngDevMode && throwError('Must never be called in production mode');
5364 const hostComponentDef = getDeclarationComponentDef(lView);
5365 const componentClassName = (_a = hostComponentDef === null || hostComponentDef === void 0 ? void 0 : hostComponentDef.type) === null || _a === void 0 ? void 0 : _a.name;
5366 return componentClassName ? ` (used in the '${componentClassName}' component template)` : '';
5367}
5368/**
5369 * The set of known control flow directives and their corresponding imports.
5370 * We use this set to produce a more precises error message with a note
5371 * that the `CommonModule` should also be included.
5372 */
5373const KNOWN_CONTROL_FLOW_DIRECTIVES = new Map([
5374 ['ngIf', 'NgIf'], ['ngFor', 'NgFor'], ['ngSwitchCase', 'NgSwitchCase'],
5375 ['ngSwitchDefault', 'NgSwitchDefault']
5376]);
5377/**
5378 * Returns true if the tag name is allowed by specified schemas.
5379 * @param schemas Array of schemas
5380 * @param tagName Name of the tag
5381 */
5382function matchingSchemas(schemas, tagName) {
5383 if (schemas !== null) {
5384 for (let i = 0; i < schemas.length; i++) {
5385 const schema = schemas[i];
5386 if (schema === NO_ERRORS_SCHEMA ||
5387 schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
5388 return true;
5389 }
5390 }
5391 }
5392 return false;
5393}
5394
5395/**
5396 * Flags for renderer-specific style modifiers.
5397 * @publicApi
5398 */
5399var RendererStyleFlags2;
5400(function (RendererStyleFlags2) {
5401 // TODO(misko): This needs to be refactored into a separate file so that it can be imported from
5402 // `node_manipulation.ts` Currently doing the import cause resolution order to change and fails
5403 // the tests. The work around is to have hard coded value in `node_manipulation.ts` for now.
5404 /**
5405 * Marks a style as important.
5406 */
5407 RendererStyleFlags2[RendererStyleFlags2["Important"] = 1] = "Important";
5408 /**
5409 * Marks a style as using dash case naming (this-is-dash-case).
5410 */
5411 RendererStyleFlags2[RendererStyleFlags2["DashCase"] = 2] = "DashCase";
5412})(RendererStyleFlags2 || (RendererStyleFlags2 = {}));
5413
5414/**
5415 * Disallowed strings in the comment.
5416 *
5417 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
5418 */
5419const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
5420/**
5421 * Delimiter in the disallowed strings which needs to be wrapped with zero with character.
5422 */
5423const COMMENT_DELIMITER = /(<|>)/;
5424const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
5425/**
5426 * Escape the content of comment strings so that it can be safely inserted into a comment node.
5427 *
5428 * The issue is that HTML does not specify any way to escape comment end text inside the comment.
5429 * Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
5430 * "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
5431 * can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
5432 *
5433 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
5434 *
5435 * ```
5436 * div.innerHTML = div.innerHTML
5437 * ```
5438 *
5439 * One would expect that the above code would be safe to do, but it turns out that because comment
5440 * text is not escaped, the comment may contain text which will prematurely close the comment
5441 * opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
5442 * may contain such text and expect them to be safe.)
5443 *
5444 * This function escapes the comment text by looking for comment delimiters (`<` and `>`) and
5445 * surrounding them with `_>_` where the `_` is a zero width space `\u200B`. The result is that if a
5446 * comment contains any of the comment start/end delimiters (such as `<!--`, `-->` or `--!>`) the
5447 * text it will render normally but it will not cause the HTML parser to close/open the comment.
5448 *
5449 * @param value text to make safe for comment node by escaping the comment open/close character
5450 * sequence.
5451 */
5452function escapeCommentText(value) {
5453 return value.replace(COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED));
5454}
5455
5456// Keeps track of the currently-active LViews.
5457const TRACKED_LVIEWS = new Map();
5458// Used for generating unique IDs for LViews.
5459let uniqueIdCounter = 0;
5460/** Gets a unique ID that can be assigned to an LView. */
5461function getUniqueLViewId() {
5462 return uniqueIdCounter++;
5463}
5464/** Starts tracking an LView. */
5465function registerLView(lView) {
5466 ngDevMode && assertNumber(lView[ID], 'LView must have an ID in order to be registered');
5467 TRACKED_LVIEWS.set(lView[ID], lView);
5468}
5469/** Gets an LView by its unique ID. */
5470function getLViewById(id) {
5471 ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number');
5472 return TRACKED_LVIEWS.get(id) || null;
5473}
5474/** Stops tracking an LView. */
5475function unregisterLView(lView) {
5476 ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID');
5477 TRACKED_LVIEWS.delete(lView[ID]);
5478}
5479
5480/**
5481 * The internal view context which is specific to a given DOM element, directive or
5482 * component instance. Each value in here (besides the LView and element node details)
5483 * can be present, null or undefined. If undefined then it implies the value has not been
5484 * looked up yet, otherwise, if null, then a lookup was executed and nothing was found.
5485 *
5486 * Each value will get filled when the respective value is examined within the getContext
5487 * function. The component, element and each directive instance will share the same instance
5488 * of the context.
5489 */
5490class LContext {
5491 /** Component's parent view data. */
5492 get lView() {
5493 return getLViewById(this.lViewId);
5494 }
5495 constructor(
5496 /**
5497 * ID of the component's parent view data.
5498 */
5499 lViewId,
5500 /**
5501 * The index instance of the node.
5502 */
5503 nodeIndex,
5504 /**
5505 * The instance of the DOM node that is attached to the lNode.
5506 */
5507 native) {
5508 this.lViewId = lViewId;
5509 this.nodeIndex = nodeIndex;
5510 this.native = native;
5511 }
5512}
5513
5514/**
5515 * Returns the matching `LContext` data for a given DOM node, directive or component instance.
5516 *
5517 * This function will examine the provided DOM element, component, or directive instance\'s
5518 * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched
5519 * value will be that of the newly created `LContext`.
5520 *
5521 * If the monkey-patched value is the `LView` instance then the context value for that
5522 * target will be created and the monkey-patch reference will be updated. Therefore when this
5523 * function is called it may mutate the provided element\'s, component\'s or any of the associated
5524 * directive\'s monkey-patch values.
5525 *
5526 * If the monkey-patch value is not detected then the code will walk up the DOM until an element
5527 * is found which contains a monkey-patch reference. When that occurs then the provided element
5528 * will be updated with a new context (which is then returned). If the monkey-patch value is not
5529 * detected for a component/directive instance then it will throw an error (all components and
5530 * directives should be automatically monkey-patched by ivy).
5531 *
5532 * @param target Component, Directive or DOM Node.
5533 */
5534function getLContext(target) {
5535 let mpValue = readPatchedData(target);
5536 if (mpValue) {
5537 // only when it's an array is it considered an LView instance
5538 // ... otherwise it's an already constructed LContext instance
5539 if (isLView(mpValue)) {
5540 const lView = mpValue;
5541 let nodeIndex;
5542 let component = undefined;
5543 let directives = undefined;
5544 if (isComponentInstance(target)) {
5545 nodeIndex = findViaComponent(lView, target);
5546 if (nodeIndex == -1) {
5547 throw new Error('The provided component was not found in the application');
5548 }
5549 component = target;
5550 }
5551 else if (isDirectiveInstance(target)) {
5552 nodeIndex = findViaDirective(lView, target);
5553 if (nodeIndex == -1) {
5554 throw new Error('The provided directive was not found in the application');
5555 }
5556 directives = getDirectivesAtNodeIndex(nodeIndex, lView);
5557 }
5558 else {
5559 nodeIndex = findViaNativeElement(lView, target);
5560 if (nodeIndex == -1) {
5561 return null;
5562 }
5563 }
5564 // the goal is not to fill the entire context full of data because the lookups
5565 // are expensive. Instead, only the target data (the element, component, container, ICU
5566 // expression or directive details) are filled into the context. If called multiple times
5567 // with different target values then the missing target data will be filled in.
5568 const native = unwrapRNode(lView[nodeIndex]);
5569 const existingCtx = readPatchedData(native);
5570 const context = (existingCtx && !Array.isArray(existingCtx)) ?
5571 existingCtx :
5572 createLContext(lView, nodeIndex, native);
5573 // only when the component has been discovered then update the monkey-patch
5574 if (component && context.component === undefined) {
5575 context.component = component;
5576 attachPatchData(context.component, context);
5577 }
5578 // only when the directives have been discovered then update the monkey-patch
5579 if (directives && context.directives === undefined) {
5580 context.directives = directives;
5581 for (let i = 0; i < directives.length; i++) {
5582 attachPatchData(directives[i], context);
5583 }
5584 }
5585 attachPatchData(context.native, context);
5586 mpValue = context;
5587 }
5588 }
5589 else {
5590 const rElement = target;
5591 ngDevMode && assertDomNode(rElement);
5592 // if the context is not found then we need to traverse upwards up the DOM
5593 // to find the nearest element that has already been monkey patched with data
5594 let parent = rElement;
5595 while (parent = parent.parentNode) {
5596 const parentContext = readPatchedData(parent);
5597 if (parentContext) {
5598 const lView = Array.isArray(parentContext) ? parentContext : parentContext.lView;
5599 // the edge of the app was also reached here through another means
5600 // (maybe because the DOM was changed manually).
5601 if (!lView) {
5602 return null;
5603 }
5604 const index = findViaNativeElement(lView, rElement);
5605 if (index >= 0) {
5606 const native = unwrapRNode(lView[index]);
5607 const context = createLContext(lView, index, native);
5608 attachPatchData(native, context);
5609 mpValue = context;
5610 break;
5611 }
5612 }
5613 }
5614 }
5615 return mpValue || null;
5616}
5617/**
5618 * Creates an empty instance of a `LContext` context
5619 */
5620function createLContext(lView, nodeIndex, native) {
5621 return new LContext(lView[ID], nodeIndex, native);
5622}
5623/**
5624 * Takes a component instance and returns the view for that component.
5625 *
5626 * @param componentInstance
5627 * @returns The component's view
5628 */
5629function getComponentViewByInstance(componentInstance) {
5630 let patchedData = readPatchedData(componentInstance);
5631 let lView;
5632 if (isLView(patchedData)) {
5633 const contextLView = patchedData;
5634 const nodeIndex = findViaComponent(contextLView, componentInstance);
5635 lView = getComponentLViewByIndex(nodeIndex, contextLView);
5636 const context = createLContext(contextLView, nodeIndex, lView[HOST]);
5637 context.component = componentInstance;
5638 attachPatchData(componentInstance, context);
5639 attachPatchData(context.native, context);
5640 }
5641 else {
5642 const context = patchedData;
5643 const contextLView = context.lView;
5644 ngDevMode && assertLView(contextLView);
5645 lView = getComponentLViewByIndex(context.nodeIndex, contextLView);
5646 }
5647 return lView;
5648}
5649/**
5650 * This property will be monkey-patched on elements, components and directives.
5651 */
5652const MONKEY_PATCH_KEY_NAME = '__ngContext__';
5653/**
5654 * Assigns the given data to the given target (which could be a component,
5655 * directive or DOM node instance) using monkey-patching.
5656 */
5657function attachPatchData(target, data) {
5658 ngDevMode && assertDefined(target, 'Target expected');
5659 // Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this
5660 // for `LView`, because we have control over when an `LView` is created and destroyed, whereas
5661 // we can't know when to remove an `LContext`.
5662 if (isLView(data)) {
5663 target[MONKEY_PATCH_KEY_NAME] = data[ID];
5664 registerLView(data);
5665 }
5666 else {
5667 target[MONKEY_PATCH_KEY_NAME] = data;
5668 }
5669}
5670/**
5671 * Returns the monkey-patch value data present on the target (which could be
5672 * a component, directive or a DOM node).
5673 */
5674function readPatchedData(target) {
5675 ngDevMode && assertDefined(target, 'Target expected');
5676 const data = target[MONKEY_PATCH_KEY_NAME];
5677 return (typeof data === 'number') ? getLViewById(data) : data || null;
5678}
5679function readPatchedLView(target) {
5680 const value = readPatchedData(target);
5681 if (value) {
5682 return (isLView(value) ? value : value.lView);
5683 }
5684 return null;
5685}
5686function isComponentInstance(instance) {
5687 return instance && instance.constructor && instance.constructor.ɵcmp;
5688}
5689function isDirectiveInstance(instance) {
5690 return instance && instance.constructor && instance.constructor.ɵdir;
5691}
5692/**
5693 * Locates the element within the given LView and returns the matching index
5694 */
5695function findViaNativeElement(lView, target) {
5696 const tView = lView[TVIEW];
5697 for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
5698 if (unwrapRNode(lView[i]) === target) {
5699 return i;
5700 }
5701 }
5702 return -1;
5703}
5704/**
5705 * Locates the next tNode (child, sibling or parent).
5706 */
5707function traverseNextElement(tNode) {
5708 if (tNode.child) {
5709 return tNode.child;
5710 }
5711 else if (tNode.next) {
5712 return tNode.next;
5713 }
5714 else {
5715 // Let's take the following template: <div><span>text</span></div><component/>
5716 // After checking the text node, we need to find the next parent that has a "next" TNode,
5717 // in this case the parent `div`, so that we can find the component.
5718 while (tNode.parent && !tNode.parent.next) {
5719 tNode = tNode.parent;
5720 }
5721 return tNode.parent && tNode.parent.next;
5722 }
5723}
5724/**
5725 * Locates the component within the given LView and returns the matching index
5726 */
5727function findViaComponent(lView, componentInstance) {
5728 const componentIndices = lView[TVIEW].components;
5729 if (componentIndices) {
5730 for (let i = 0; i < componentIndices.length; i++) {
5731 const elementComponentIndex = componentIndices[i];
5732 const componentView = getComponentLViewByIndex(elementComponentIndex, lView);
5733 if (componentView[CONTEXT] === componentInstance) {
5734 return elementComponentIndex;
5735 }
5736 }
5737 }
5738 else {
5739 const rootComponentView = getComponentLViewByIndex(HEADER_OFFSET, lView);
5740 const rootComponent = rootComponentView[CONTEXT];
5741 if (rootComponent === componentInstance) {
5742 // we are dealing with the root element here therefore we know that the
5743 // element is the very first element after the HEADER data in the lView
5744 return HEADER_OFFSET;
5745 }
5746 }
5747 return -1;
5748}
5749/**
5750 * Locates the directive within the given LView and returns the matching index
5751 */
5752function findViaDirective(lView, directiveInstance) {
5753 // if a directive is monkey patched then it will (by default)
5754 // have a reference to the LView of the current view. The
5755 // element bound to the directive being search lives somewhere
5756 // in the view data. We loop through the nodes and check their
5757 // list of directives for the instance.
5758 let tNode = lView[TVIEW].firstChild;
5759 while (tNode) {
5760 const directiveIndexStart = tNode.directiveStart;
5761 const directiveIndexEnd = tNode.directiveEnd;
5762 for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
5763 if (lView[i] === directiveInstance) {
5764 return tNode.index;
5765 }
5766 }
5767 tNode = traverseNextElement(tNode);
5768 }
5769 return -1;
5770}
5771/**
5772 * Returns a list of directives applied to a node at a specific index. The list includes
5773 * directives matched by selector and any host directives, but it excludes components.
5774 * Use `getComponentAtNodeIndex` to find the component applied to a node.
5775 *
5776 * @param nodeIndex The node index
5777 * @param lView The target view data
5778 */
5779function getDirectivesAtNodeIndex(nodeIndex, lView) {
5780 const tNode = lView[TVIEW].data[nodeIndex];
5781 if (tNode.directiveStart === 0)
5782 return EMPTY_ARRAY;
5783 const results = [];
5784 for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
5785 const directiveInstance = lView[i];
5786 if (!isComponentInstance(directiveInstance)) {
5787 results.push(directiveInstance);
5788 }
5789 }
5790 return results;
5791}
5792function getComponentAtNodeIndex(nodeIndex, lView) {
5793 const tNode = lView[TVIEW].data[nodeIndex];
5794 const { directiveStart, componentOffset } = tNode;
5795 return componentOffset > -1 ? lView[directiveStart + componentOffset] : null;
5796}
5797/**
5798 * Returns a map of local references (local reference name => element or directive instance) that
5799 * exist on a given element.
5800 */
5801function discoverLocalRefs(lView, nodeIndex) {
5802 const tNode = lView[TVIEW].data[nodeIndex];
5803 if (tNode && tNode.localNames) {
5804 const result = {};
5805 let localIndex = tNode.index + 1;
5806 for (let i = 0; i < tNode.localNames.length; i += 2) {
5807 result[tNode.localNames[i]] = lView[localIndex];
5808 localIndex++;
5809 }
5810 return result;
5811 }
5812 return null;
5813}
5814
5815let _icuContainerIterate;
5816/**
5817 * Iterator which provides ability to visit all of the `TIcuContainerNode` root `RNode`s.
5818 */
5819function icuContainerIterate(tIcuContainerNode, lView) {
5820 return _icuContainerIterate(tIcuContainerNode, lView);
5821}
5822/**
5823 * Ensures that `IcuContainerVisitor`'s implementation is present.
5824 *
5825 * This function is invoked when i18n instruction comes across an ICU. The purpose is to allow the
5826 * bundler to tree shake ICU logic and only load it if ICU instruction is executed.
5827 */
5828function ensureIcuContainerVisitorLoaded(loader) {
5829 if (_icuContainerIterate === undefined) {
5830 // Do not inline this function. We want to keep `ensureIcuContainerVisitorLoaded` light, so it
5831 // can be inlined into call-site.
5832 _icuContainerIterate = loader();
5833 }
5834}
5835
5836/**
5837 * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of
5838 * that LContainer, which is an LView
5839 * @param lView the lView whose parent to get
5840 */
5841function getLViewParent(lView) {
5842 ngDevMode && assertLView(lView);
5843 const parent = lView[PARENT];
5844 return isLContainer(parent) ? parent[PARENT] : parent;
5845}
5846/**
5847 * Retrieve the root view from any component or `LView` by walking the parent `LView` until
5848 * reaching the root `LView`.
5849 *
5850 * @param componentOrLView any component or `LView`
5851 */
5852function getRootView(componentOrLView) {
5853 ngDevMode && assertDefined(componentOrLView, 'component');
5854 let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView);
5855 while (lView && !(lView[FLAGS] & 256 /* LViewFlags.IsRoot */)) {
5856 lView = getLViewParent(lView);
5857 }
5858 ngDevMode && assertLView(lView);
5859 return lView;
5860}
5861/**
5862 * Returns the context information associated with the application where the target is situated. It
5863 * does this by walking the parent views until it gets to the root view, then getting the context
5864 * off of that.
5865 *
5866 * @param viewOrComponent the `LView` or component to get the root context for.
5867 */
5868function getRootContext(viewOrComponent) {
5869 const rootView = getRootView(viewOrComponent);
5870 ngDevMode &&
5871 assertDefined(rootView[CONTEXT], 'Root view has no context. Perhaps it is disconnected?');
5872 return rootView[CONTEXT];
5873}
5874/**
5875 * Gets the first `LContainer` in the LView or `null` if none exists.
5876 */
5877function getFirstLContainer(lView) {
5878 return getNearestLContainer(lView[CHILD_HEAD]);
5879}
5880/**
5881 * Gets the next `LContainer` that is a sibling of the given container.
5882 */
5883function getNextLContainer(container) {
5884 return getNearestLContainer(container[NEXT]);
5885}
5886function getNearestLContainer(viewOrContainer) {
5887 while (viewOrContainer !== null && !isLContainer(viewOrContainer)) {
5888 viewOrContainer = viewOrContainer[NEXT];
5889 }
5890 return viewOrContainer;
5891}
5892
5893/**
5894 * NOTE: for performance reasons, the possible actions are inlined within the function instead of
5895 * being passed as an argument.
5896 */
5897function applyToElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
5898 // If this slot was allocated for a text node dynamically created by i18n, the text node itself
5899 // won't be created until i18nApply() in the update block, so this node should be skipped.
5900 // For more info, see "ICU expressions should work inside an ngTemplateOutlet inside an ngFor"
5901 // in `i18n_spec.ts`.
5902 if (lNodeToHandle != null) {
5903 let lContainer;
5904 let isComponent = false;
5905 // We are expecting an RNode, but in the case of a component or LContainer the `RNode` is
5906 // wrapped in an array which needs to be unwrapped. We need to know if it is a component and if
5907 // it has LContainer so that we can process all of those cases appropriately.
5908 if (isLContainer(lNodeToHandle)) {
5909 lContainer = lNodeToHandle;
5910 }
5911 else if (isLView(lNodeToHandle)) {
5912 isComponent = true;
5913 ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView');
5914 lNodeToHandle = lNodeToHandle[HOST];
5915 }
5916 const rNode = unwrapRNode(lNodeToHandle);
5917 if (action === 0 /* WalkTNodeTreeAction.Create */ && parent !== null) {
5918 if (beforeNode == null) {
5919 nativeAppendChild(renderer, parent, rNode);
5920 }
5921 else {
5922 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
5923 }
5924 }
5925 else if (action === 1 /* WalkTNodeTreeAction.Insert */ && parent !== null) {
5926 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
5927 }
5928 else if (action === 2 /* WalkTNodeTreeAction.Detach */) {
5929 nativeRemoveNode(renderer, rNode, isComponent);
5930 }
5931 else if (action === 3 /* WalkTNodeTreeAction.Destroy */) {
5932 ngDevMode && ngDevMode.rendererDestroyNode++;
5933 renderer.destroyNode(rNode);
5934 }
5935 if (lContainer != null) {
5936 applyContainer(renderer, action, lContainer, parent, beforeNode);
5937 }
5938 }
5939}
5940function createTextNode(renderer, value) {
5941 ngDevMode && ngDevMode.rendererCreateTextNode++;
5942 ngDevMode && ngDevMode.rendererSetText++;
5943 return renderer.createText(value);
5944}
5945function updateTextNode(renderer, rNode, value) {
5946 ngDevMode && ngDevMode.rendererSetText++;
5947 renderer.setValue(rNode, value);
5948}
5949function createCommentNode(renderer, value) {
5950 ngDevMode && ngDevMode.rendererCreateComment++;
5951 return renderer.createComment(escapeCommentText(value));
5952}
5953/**
5954 * Creates a native element from a tag name, using a renderer.
5955 * @param renderer A renderer to use
5956 * @param name the tag name
5957 * @param namespace Optional namespace for element.
5958 * @returns the element created
5959 */
5960function createElementNode(renderer, name, namespace) {
5961 ngDevMode && ngDevMode.rendererCreateElement++;
5962 return renderer.createElement(name, namespace);
5963}
5964/**
5965 * Removes all DOM elements associated with a view.
5966 *
5967 * Because some root nodes of the view may be containers, we sometimes need
5968 * to propagate deeply into the nested containers to remove all elements in the
5969 * views beneath it.
5970 *
5971 * @param tView The `TView' of the `LView` from which elements should be added or removed
5972 * @param lView The view from which elements should be added or removed
5973 */
5974function removeViewFromContainer(tView, lView) {
5975 const renderer = lView[RENDERER];
5976 applyView(tView, lView, renderer, 2 /* WalkTNodeTreeAction.Detach */, null, null);
5977 lView[HOST] = null;
5978 lView[T_HOST] = null;
5979}
5980/**
5981 * Adds all DOM elements associated with a view.
5982 *
5983 * Because some root nodes of the view may be containers, we sometimes need
5984 * to propagate deeply into the nested containers to add all elements in the
5985 * views beneath it.
5986 *
5987 * @param tView The `TView' of the `LView` from which elements should be added or removed
5988 * @param parentTNode The `TNode` where the `LView` should be attached to.
5989 * @param renderer Current renderer to use for DOM manipulations.
5990 * @param lView The view from which elements should be added or removed
5991 * @param parentNativeNode The parent `RElement` where it should be inserted into.
5992 * @param beforeNode The node before which elements should be added, if insert mode
5993 */
5994function addViewToContainer(tView, parentTNode, renderer, lView, parentNativeNode, beforeNode) {
5995 lView[HOST] = parentNativeNode;
5996 lView[T_HOST] = parentTNode;
5997 applyView(tView, lView, renderer, 1 /* WalkTNodeTreeAction.Insert */, parentNativeNode, beforeNode);
5998}
5999/**
6000 * Detach a `LView` from the DOM by detaching its nodes.
6001 *
6002 * @param tView The `TView' of the `LView` to be detached
6003 * @param lView the `LView` to be detached.
6004 */
6005function renderDetachView(tView, lView) {
6006 applyView(tView, lView, lView[RENDERER], 2 /* WalkTNodeTreeAction.Detach */, null, null);
6007}
6008/**
6009 * Traverses down and up the tree of views and containers to remove listeners and
6010 * call onDestroy callbacks.
6011 *
6012 * Notes:
6013 * - Because it's used for onDestroy calls, it needs to be bottom-up.
6014 * - Must process containers instead of their views to avoid splicing
6015 * when views are destroyed and re-added.
6016 * - Using a while loop because it's faster than recursion
6017 * - Destroy only called on movement to sibling or movement to parent (laterally or up)
6018 *
6019 * @param rootView The view to destroy
6020 */
6021function destroyViewTree(rootView) {
6022 // If the view has no children, we can clean it up and return early.
6023 let lViewOrLContainer = rootView[CHILD_HEAD];
6024 if (!lViewOrLContainer) {
6025 return cleanUpView(rootView[TVIEW], rootView);
6026 }
6027 while (lViewOrLContainer) {
6028 let next = null;
6029 if (isLView(lViewOrLContainer)) {
6030 // If LView, traverse down to child.
6031 next = lViewOrLContainer[CHILD_HEAD];
6032 }
6033 else {
6034 ngDevMode && assertLContainer(lViewOrLContainer);
6035 // If container, traverse down to its first LView.
6036 const firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET];
6037 if (firstView)
6038 next = firstView;
6039 }
6040 if (!next) {
6041 // Only clean up view when moving to the side or up, as destroy hooks
6042 // should be called in order from the bottom up.
6043 while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) {
6044 if (isLView(lViewOrLContainer)) {
6045 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
6046 }
6047 lViewOrLContainer = lViewOrLContainer[PARENT];
6048 }
6049 if (lViewOrLContainer === null)
6050 lViewOrLContainer = rootView;
6051 if (isLView(lViewOrLContainer)) {
6052 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
6053 }
6054 next = lViewOrLContainer && lViewOrLContainer[NEXT];
6055 }
6056 lViewOrLContainer = next;
6057 }
6058}
6059/**
6060 * Inserts a view into a container.
6061 *
6062 * This adds the view to the container's array of active views in the correct
6063 * position. It also adds the view's elements to the DOM if the container isn't a
6064 * root node of another view (in that case, the view's elements will be added when
6065 * the container's parent view is added later).
6066 *
6067 * @param tView The `TView' of the `LView` to insert
6068 * @param lView The view to insert
6069 * @param lContainer The container into which the view should be inserted
6070 * @param index Which index in the container to insert the child view into
6071 */
6072function insertView(tView, lView, lContainer, index) {
6073 ngDevMode && assertLView(lView);
6074 ngDevMode && assertLContainer(lContainer);
6075 const indexInContainer = CONTAINER_HEADER_OFFSET + index;
6076 const containerLength = lContainer.length;
6077 if (index > 0) {
6078 // This is a new view, we need to add it to the children.
6079 lContainer[indexInContainer - 1][NEXT] = lView;
6080 }
6081 if (index < containerLength - CONTAINER_HEADER_OFFSET) {
6082 lView[NEXT] = lContainer[indexInContainer];
6083 addToArray(lContainer, CONTAINER_HEADER_OFFSET + index, lView);
6084 }
6085 else {
6086 lContainer.push(lView);
6087 lView[NEXT] = null;
6088 }
6089 lView[PARENT] = lContainer;
6090 // track views where declaration and insertion points are different
6091 const declarationLContainer = lView[DECLARATION_LCONTAINER];
6092 if (declarationLContainer !== null && lContainer !== declarationLContainer) {
6093 trackMovedView(declarationLContainer, lView);
6094 }
6095 // notify query that a new view has been added
6096 const lQueries = lView[QUERIES];
6097 if (lQueries !== null) {
6098 lQueries.insertView(tView);
6099 }
6100 // Sets the attached flag
6101 lView[FLAGS] |= 64 /* LViewFlags.Attached */;
6102}
6103/**
6104 * Track views created from the declaration container (TemplateRef) and inserted into a
6105 * different LContainer.
6106 */
6107function trackMovedView(declarationContainer, lView) {
6108 ngDevMode && assertDefined(lView, 'LView required');
6109 ngDevMode && assertLContainer(declarationContainer);
6110 const movedViews = declarationContainer[MOVED_VIEWS];
6111 const insertedLContainer = lView[PARENT];
6112 ngDevMode && assertLContainer(insertedLContainer);
6113 const insertedComponentLView = insertedLContainer[PARENT][DECLARATION_COMPONENT_VIEW];
6114 ngDevMode && assertDefined(insertedComponentLView, 'Missing insertedComponentLView');
6115 const declaredComponentLView = lView[DECLARATION_COMPONENT_VIEW];
6116 ngDevMode && assertDefined(declaredComponentLView, 'Missing declaredComponentLView');
6117 if (declaredComponentLView !== insertedComponentLView) {
6118 // At this point the declaration-component is not same as insertion-component; this means that
6119 // this is a transplanted view. Mark the declared lView as having transplanted views so that
6120 // those views can participate in CD.
6121 declarationContainer[HAS_TRANSPLANTED_VIEWS] = true;
6122 }
6123 if (movedViews === null) {
6124 declarationContainer[MOVED_VIEWS] = [lView];
6125 }
6126 else {
6127 movedViews.push(lView);
6128 }
6129}
6130function detachMovedView(declarationContainer, lView) {
6131 ngDevMode && assertLContainer(declarationContainer);
6132 ngDevMode &&
6133 assertDefined(declarationContainer[MOVED_VIEWS], 'A projected view should belong to a non-empty projected views collection');
6134 const movedViews = declarationContainer[MOVED_VIEWS];
6135 const declarationViewIndex = movedViews.indexOf(lView);
6136 const insertionLContainer = lView[PARENT];
6137 ngDevMode && assertLContainer(insertionLContainer);
6138 // If the view was marked for refresh but then detached before it was checked (where the flag
6139 // would be cleared and the counter decremented), we need to decrement the view counter here
6140 // instead.
6141 if (lView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
6142 lView[FLAGS] &= ~512 /* LViewFlags.RefreshTransplantedView */;
6143 updateTransplantedViewCount(insertionLContainer, -1);
6144 }
6145 movedViews.splice(declarationViewIndex, 1);
6146}
6147/**
6148 * Detaches a view from a container.
6149 *
6150 * This method removes the view from the container's array of active views. It also
6151 * removes the view's elements from the DOM.
6152 *
6153 * @param lContainer The container from which to detach a view
6154 * @param removeIndex The index of the view to detach
6155 * @returns Detached LView instance.
6156 */
6157function detachView(lContainer, removeIndex) {
6158 if (lContainer.length <= CONTAINER_HEADER_OFFSET)
6159 return;
6160 const indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
6161 const viewToDetach = lContainer[indexInContainer];
6162 if (viewToDetach) {
6163 const declarationLContainer = viewToDetach[DECLARATION_LCONTAINER];
6164 if (declarationLContainer !== null && declarationLContainer !== lContainer) {
6165 detachMovedView(declarationLContainer, viewToDetach);
6166 }
6167 if (removeIndex > 0) {
6168 lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT];
6169 }
6170 const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
6171 removeViewFromContainer(viewToDetach[TVIEW], viewToDetach);
6172 // notify query that a view has been removed
6173 const lQueries = removedLView[QUERIES];
6174 if (lQueries !== null) {
6175 lQueries.detachView(removedLView[TVIEW]);
6176 }
6177 viewToDetach[PARENT] = null;
6178 viewToDetach[NEXT] = null;
6179 // Unsets the attached flag
6180 viewToDetach[FLAGS] &= ~64 /* LViewFlags.Attached */;
6181 }
6182 return viewToDetach;
6183}
6184/**
6185 * A standalone function which destroys an LView,
6186 * conducting clean up (e.g. removing listeners, calling onDestroys).
6187 *
6188 * @param tView The `TView' of the `LView` to be destroyed
6189 * @param lView The view to be destroyed.
6190 */
6191function destroyLView(tView, lView) {
6192 if (!(lView[FLAGS] & 128 /* LViewFlags.Destroyed */)) {
6193 const renderer = lView[RENDERER];
6194 if (renderer.destroyNode) {
6195 applyView(tView, lView, renderer, 3 /* WalkTNodeTreeAction.Destroy */, null, null);
6196 }
6197 destroyViewTree(lView);
6198 }
6199}
6200/**
6201 * Calls onDestroys hooks for all directives and pipes in a given view and then removes all
6202 * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks
6203 * can be propagated to @Output listeners.
6204 *
6205 * @param tView `TView` for the `LView` to clean up.
6206 * @param lView The LView to clean up
6207 */
6208function cleanUpView(tView, lView) {
6209 if (!(lView[FLAGS] & 128 /* LViewFlags.Destroyed */)) {
6210 // Usually the Attached flag is removed when the view is detached from its parent, however
6211 // if it's a root view, the flag won't be unset hence why we're also removing on destroy.
6212 lView[FLAGS] &= ~64 /* LViewFlags.Attached */;
6213 // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
6214 // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
6215 // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
6216 // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
6217 // really more of an "afterDestroy" hook if you think about it.
6218 lView[FLAGS] |= 128 /* LViewFlags.Destroyed */;
6219 executeOnDestroys(tView, lView);
6220 processCleanups(tView, lView);
6221 // For component views only, the local renderer is destroyed at clean up time.
6222 if (lView[TVIEW].type === 1 /* TViewType.Component */) {
6223 ngDevMode && ngDevMode.rendererDestroy++;
6224 lView[RENDERER].destroy();
6225 }
6226 const declarationContainer = lView[DECLARATION_LCONTAINER];
6227 // we are dealing with an embedded view that is still inserted into a container
6228 if (declarationContainer !== null && isLContainer(lView[PARENT])) {
6229 // and this is a projected view
6230 if (declarationContainer !== lView[PARENT]) {
6231 detachMovedView(declarationContainer, lView);
6232 }
6233 // For embedded views still attached to a container: remove query result from this view.
6234 const lQueries = lView[QUERIES];
6235 if (lQueries !== null) {
6236 lQueries.detachView(tView);
6237 }
6238 }
6239 // Unregister the view once everything else has been cleaned up.
6240 unregisterLView(lView);
6241 }
6242}
6243/** Removes listeners and unsubscribes from output subscriptions */
6244function processCleanups(tView, lView) {
6245 const tCleanup = tView.cleanup;
6246 const lCleanup = lView[CLEANUP];
6247 // `LCleanup` contains both share information with `TCleanup` as well as instance specific
6248 // information appended at the end. We need to know where the end of the `TCleanup` information
6249 // is, and we track this with `lastLCleanupIndex`.
6250 let lastLCleanupIndex = -1;
6251 if (tCleanup !== null) {
6252 for (let i = 0; i < tCleanup.length - 1; i += 2) {
6253 if (typeof tCleanup[i] === 'string') {
6254 // This is a native DOM listener. It will occupy 4 entries in the TCleanup array (hence i +=
6255 // 2 at the end of this block).
6256 const targetIdx = tCleanup[i + 3];
6257 ngDevMode && assertNumber(targetIdx, 'cleanup target must be a number');
6258 if (targetIdx >= 0) {
6259 // unregister
6260 lCleanup[lastLCleanupIndex = targetIdx]();
6261 }
6262 else {
6263 // Subscription
6264 lCleanup[lastLCleanupIndex = -targetIdx].unsubscribe();
6265 }
6266 i += 2;
6267 }
6268 else {
6269 // This is a cleanup function that is grouped with the index of its context
6270 const context = lCleanup[lastLCleanupIndex = tCleanup[i + 1]];
6271 tCleanup[i].call(context);
6272 }
6273 }
6274 }
6275 if (lCleanup !== null) {
6276 for (let i = lastLCleanupIndex + 1; i < lCleanup.length; i++) {
6277 const instanceCleanupFn = lCleanup[i];
6278 ngDevMode && assertFunction(instanceCleanupFn, 'Expecting instance cleanup function.');
6279 instanceCleanupFn();
6280 }
6281 lView[CLEANUP] = null;
6282 }
6283}
6284/** Calls onDestroy hooks for this view */
6285function executeOnDestroys(tView, lView) {
6286 let destroyHooks;
6287 if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
6288 for (let i = 0; i < destroyHooks.length; i += 2) {
6289 const context = lView[destroyHooks[i]];
6290 // Only call the destroy hook if the context has been requested.
6291 if (!(context instanceof NodeInjectorFactory)) {
6292 const toCall = destroyHooks[i + 1];
6293 if (Array.isArray(toCall)) {
6294 for (let j = 0; j < toCall.length; j += 2) {
6295 const callContext = context[toCall[j]];
6296 const hook = toCall[j + 1];
6297 profiler(4 /* ProfilerEvent.LifecycleHookStart */, callContext, hook);
6298 try {
6299 hook.call(callContext);
6300 }
6301 finally {
6302 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, callContext, hook);
6303 }
6304 }
6305 }
6306 else {
6307 profiler(4 /* ProfilerEvent.LifecycleHookStart */, context, toCall);
6308 try {
6309 toCall.call(context);
6310 }
6311 finally {
6312 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, context, toCall);
6313 }
6314 }
6315 }
6316 }
6317 }
6318}
6319/**
6320 * Returns a native element if a node can be inserted into the given parent.
6321 *
6322 * There are two reasons why we may not be able to insert a element immediately.
6323 * - Projection: When creating a child content element of a component, we have to skip the
6324 * insertion because the content of a component will be projected.
6325 * `<component><content>delayed due to projection</content></component>`
6326 * - Parent container is disconnected: This can happen when we are inserting a view into
6327 * parent container, which itself is disconnected. For example the parent container is part
6328 * of a View which has not be inserted or is made for projection but has not been inserted
6329 * into destination.
6330 *
6331 * @param tView: Current `TView`.
6332 * @param tNode: `TNode` for which we wish to retrieve render parent.
6333 * @param lView: Current `LView`.
6334 */
6335function getParentRElement(tView, tNode, lView) {
6336 return getClosestRElement(tView, tNode.parent, lView);
6337}
6338/**
6339 * Get closest `RElement` or `null` if it can't be found.
6340 *
6341 * If `TNode` is `TNodeType.Element` => return `RElement` at `LView[tNode.index]` location.
6342 * If `TNode` is `TNodeType.ElementContainer|IcuContain` => return the parent (recursively).
6343 * If `TNode` is `null` then return host `RElement`:
6344 * - return `null` if projection
6345 * - return `null` if parent container is disconnected (we have no parent.)
6346 *
6347 * @param tView: Current `TView`.
6348 * @param tNode: `TNode` for which we wish to retrieve `RElement` (or `null` if host element is
6349 * needed).
6350 * @param lView: Current `LView`.
6351 * @returns `null` if the `RElement` can't be determined at this time (no parent / projection)
6352 */
6353function getClosestRElement(tView, tNode, lView) {
6354 let parentTNode = tNode;
6355 // Skip over element and ICU containers as those are represented by a comment node and
6356 // can't be used as a render parent.
6357 while (parentTNode !== null &&
6358 (parentTNode.type & (8 /* TNodeType.ElementContainer */ | 32 /* TNodeType.Icu */))) {
6359 tNode = parentTNode;
6360 parentTNode = tNode.parent;
6361 }
6362 // If the parent tNode is null, then we are inserting across views: either into an embedded view
6363 // or a component view.
6364 if (parentTNode === null) {
6365 // We are inserting a root element of the component view into the component host element and
6366 // it should always be eager.
6367 return lView[HOST];
6368 }
6369 else {
6370 ngDevMode && assertTNodeType(parentTNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
6371 const { componentOffset } = parentTNode;
6372 if (componentOffset > -1) {
6373 ngDevMode && assertTNodeForLView(parentTNode, lView);
6374 const { encapsulation } = tView.data[parentTNode.directiveStart + componentOffset];
6375 // We've got a parent which is an element in the current view. We just need to verify if the
6376 // parent element is not a component. Component's content nodes are not inserted immediately
6377 // because they will be projected, and so doing insert at this point would be wasteful.
6378 // Since the projection would then move it to its final destination. Note that we can't
6379 // make this assumption when using the Shadow DOM, because the native projection placeholders
6380 // (<content> or <slot>) have to be in place as elements are being inserted.
6381 if (encapsulation === ViewEncapsulation.None ||
6382 encapsulation === ViewEncapsulation.Emulated) {
6383 return null;
6384 }
6385 }
6386 return getNativeByTNode(parentTNode, lView);
6387 }
6388}
6389/**
6390 * Inserts a native node before another native node for a given parent.
6391 * This is a utility function that can be used when native nodes were determined.
6392 */
6393function nativeInsertBefore(renderer, parent, child, beforeNode, isMove) {
6394 ngDevMode && ngDevMode.rendererInsertBefore++;
6395 renderer.insertBefore(parent, child, beforeNode, isMove);
6396}
6397function nativeAppendChild(renderer, parent, child) {
6398 ngDevMode && ngDevMode.rendererAppendChild++;
6399 ngDevMode && assertDefined(parent, 'parent node must be defined');
6400 renderer.appendChild(parent, child);
6401}
6402function nativeAppendOrInsertBefore(renderer, parent, child, beforeNode, isMove) {
6403 if (beforeNode !== null) {
6404 nativeInsertBefore(renderer, parent, child, beforeNode, isMove);
6405 }
6406 else {
6407 nativeAppendChild(renderer, parent, child);
6408 }
6409}
6410/** Removes a node from the DOM given its native parent. */
6411function nativeRemoveChild(renderer, parent, child, isHostElement) {
6412 renderer.removeChild(parent, child, isHostElement);
6413}
6414/** Checks if an element is a `<template>` node. */
6415function isTemplateNode(node) {
6416 return node.tagName === 'TEMPLATE' && node.content !== undefined;
6417}
6418/**
6419 * Returns a native parent of a given native node.
6420 */
6421function nativeParentNode(renderer, node) {
6422 return renderer.parentNode(node);
6423}
6424/**
6425 * Returns a native sibling of a given native node.
6426 */
6427function nativeNextSibling(renderer, node) {
6428 return renderer.nextSibling(node);
6429}
6430/**
6431 * Find a node in front of which `currentTNode` should be inserted.
6432 *
6433 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
6434 * takes `TNode.insertBeforeIndex` into account if i18n code has been invoked.
6435 *
6436 * @param parentTNode parent `TNode`
6437 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
6438 * @param lView current `LView`
6439 */
6440function getInsertInFrontOfRNode(parentTNode, currentTNode, lView) {
6441 return _getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView);
6442}
6443/**
6444 * Find a node in front of which `currentTNode` should be inserted. (Does not take i18n into
6445 * account)
6446 *
6447 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
6448 * does not take `TNode.insertBeforeIndex` into account.
6449 *
6450 * @param parentTNode parent `TNode`
6451 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
6452 * @param lView current `LView`
6453 */
6454function getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView) {
6455 if (parentTNode.type & (8 /* TNodeType.ElementContainer */ | 32 /* TNodeType.Icu */)) {
6456 return getNativeByTNode(parentTNode, lView);
6457 }
6458 return null;
6459}
6460/**
6461 * Tree shakable boundary for `getInsertInFrontOfRNodeWithI18n` function.
6462 *
6463 * This function will only be set if i18n code runs.
6464 */
6465let _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithNoI18n;
6466/**
6467 * Tree shakable boundary for `processI18nInsertBefore` function.
6468 *
6469 * This function will only be set if i18n code runs.
6470 */
6471let _processI18nInsertBefore;
6472function setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore) {
6473 _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithI18n;
6474 _processI18nInsertBefore = processI18nInsertBefore;
6475}
6476/**
6477 * Appends the `child` native node (or a collection of nodes) to the `parent`.
6478 *
6479 * @param tView The `TView' to be appended
6480 * @param lView The current LView
6481 * @param childRNode The native child (or children) that should be appended
6482 * @param childTNode The TNode of the child element
6483 */
6484function appendChild(tView, lView, childRNode, childTNode) {
6485 const parentRNode = getParentRElement(tView, childTNode, lView);
6486 const renderer = lView[RENDERER];
6487 const parentTNode = childTNode.parent || lView[T_HOST];
6488 const anchorNode = getInsertInFrontOfRNode(parentTNode, childTNode, lView);
6489 if (parentRNode != null) {
6490 if (Array.isArray(childRNode)) {
6491 for (let i = 0; i < childRNode.length; i++) {
6492 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode[i], anchorNode, false);
6493 }
6494 }
6495 else {
6496 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode, anchorNode, false);
6497 }
6498 }
6499 _processI18nInsertBefore !== undefined &&
6500 _processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRNode);
6501}
6502/**
6503 * Returns the first native node for a given LView, starting from the provided TNode.
6504 *
6505 * Native nodes are returned in the order in which those appear in the native tree (DOM).
6506 */
6507function getFirstNativeNode(lView, tNode) {
6508 if (tNode !== null) {
6509 ngDevMode &&
6510 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 32 /* TNodeType.Icu */ | 16 /* TNodeType.Projection */);
6511 const tNodeType = tNode.type;
6512 if (tNodeType & 3 /* TNodeType.AnyRNode */) {
6513 return getNativeByTNode(tNode, lView);
6514 }
6515 else if (tNodeType & 4 /* TNodeType.Container */) {
6516 return getBeforeNodeForView(-1, lView[tNode.index]);
6517 }
6518 else if (tNodeType & 8 /* TNodeType.ElementContainer */) {
6519 const elIcuContainerChild = tNode.child;
6520 if (elIcuContainerChild !== null) {
6521 return getFirstNativeNode(lView, elIcuContainerChild);
6522 }
6523 else {
6524 const rNodeOrLContainer = lView[tNode.index];
6525 if (isLContainer(rNodeOrLContainer)) {
6526 return getBeforeNodeForView(-1, rNodeOrLContainer);
6527 }
6528 else {
6529 return unwrapRNode(rNodeOrLContainer);
6530 }
6531 }
6532 }
6533 else if (tNodeType & 32 /* TNodeType.Icu */) {
6534 let nextRNode = icuContainerIterate(tNode, lView);
6535 let rNode = nextRNode();
6536 // If the ICU container has no nodes, than we use the ICU anchor as the node.
6537 return rNode || unwrapRNode(lView[tNode.index]);
6538 }
6539 else {
6540 const projectionNodes = getProjectionNodes(lView, tNode);
6541 if (projectionNodes !== null) {
6542 if (Array.isArray(projectionNodes)) {
6543 return projectionNodes[0];
6544 }
6545 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
6546 ngDevMode && assertParentView(parentView);
6547 return getFirstNativeNode(parentView, projectionNodes);
6548 }
6549 else {
6550 return getFirstNativeNode(lView, tNode.next);
6551 }
6552 }
6553 }
6554 return null;
6555}
6556function getProjectionNodes(lView, tNode) {
6557 if (tNode !== null) {
6558 const componentView = lView[DECLARATION_COMPONENT_VIEW];
6559 const componentHost = componentView[T_HOST];
6560 const slotIdx = tNode.projection;
6561 ngDevMode && assertProjectionSlots(lView);
6562 return componentHost.projection[slotIdx];
6563 }
6564 return null;
6565}
6566function getBeforeNodeForView(viewIndexInContainer, lContainer) {
6567 const nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1;
6568 if (nextViewIndex < lContainer.length) {
6569 const lView = lContainer[nextViewIndex];
6570 const firstTNodeOfView = lView[TVIEW].firstChild;
6571 if (firstTNodeOfView !== null) {
6572 return getFirstNativeNode(lView, firstTNodeOfView);
6573 }
6574 }
6575 return lContainer[NATIVE];
6576}
6577/**
6578 * Removes a native node itself using a given renderer. To remove the node we are looking up its
6579 * parent from the native tree as not all platforms / browsers support the equivalent of
6580 * node.remove().
6581 *
6582 * @param renderer A renderer to be used
6583 * @param rNode The native node that should be removed
6584 * @param isHostElement A flag indicating if a node to be removed is a host of a component.
6585 */
6586function nativeRemoveNode(renderer, rNode, isHostElement) {
6587 ngDevMode && ngDevMode.rendererRemoveNode++;
6588 const nativeParent = nativeParentNode(renderer, rNode);
6589 if (nativeParent) {
6590 nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
6591 }
6592}
6593/**
6594 * Performs the operation of `action` on the node. Typically this involves inserting or removing
6595 * nodes on the LView or projection boundary.
6596 */
6597function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode, isProjection) {
6598 while (tNode != null) {
6599 ngDevMode && assertTNodeForLView(tNode, lView);
6600 ngDevMode &&
6601 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
6602 const rawSlotValue = lView[tNode.index];
6603 const tNodeType = tNode.type;
6604 if (isProjection) {
6605 if (action === 0 /* WalkTNodeTreeAction.Create */) {
6606 rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
6607 tNode.flags |= 2 /* TNodeFlags.isProjected */;
6608 }
6609 }
6610 if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
6611 if (tNodeType & 8 /* TNodeType.ElementContainer */) {
6612 applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
6613 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
6614 }
6615 else if (tNodeType & 32 /* TNodeType.Icu */) {
6616 const nextRNode = icuContainerIterate(tNode, lView);
6617 let rNode;
6618 while (rNode = nextRNode()) {
6619 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
6620 }
6621 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
6622 }
6623 else if (tNodeType & 16 /* TNodeType.Projection */) {
6624 applyProjectionRecursive(renderer, action, lView, tNode, parentRElement, beforeNode);
6625 }
6626 else {
6627 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
6628 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
6629 }
6630 }
6631 tNode = isProjection ? tNode.projectionNext : tNode.next;
6632 }
6633}
6634function applyView(tView, lView, renderer, action, parentRElement, beforeNode) {
6635 applyNodes(renderer, action, tView.firstChild, lView, parentRElement, beforeNode, false);
6636}
6637/**
6638 * `applyProjection` performs operation on the projection.
6639 *
6640 * Inserting a projection requires us to locate the projected nodes from the parent component. The
6641 * complication is that those nodes themselves could be re-projected from their parent component.
6642 *
6643 * @param tView The `TView` of `LView` which needs to be inserted, detached, destroyed
6644 * @param lView The `LView` which needs to be inserted, detached, destroyed.
6645 * @param tProjectionNode node to project
6646 */
6647function applyProjection(tView, lView, tProjectionNode) {
6648 const renderer = lView[RENDERER];
6649 const parentRNode = getParentRElement(tView, tProjectionNode, lView);
6650 const parentTNode = tProjectionNode.parent || lView[T_HOST];
6651 let beforeNode = getInsertInFrontOfRNode(parentTNode, tProjectionNode, lView);
6652 applyProjectionRecursive(renderer, 0 /* WalkTNodeTreeAction.Create */, lView, tProjectionNode, parentRNode, beforeNode);
6653}
6654/**
6655 * `applyProjectionRecursive` performs operation on the projection specified by `action` (insert,
6656 * detach, destroy)
6657 *
6658 * Inserting a projection requires us to locate the projected nodes from the parent component. The
6659 * complication is that those nodes themselves could be re-projected from their parent component.
6660 *
6661 * @param renderer Render to use
6662 * @param action action to perform (insert, detach, destroy)
6663 * @param lView The LView which needs to be inserted, detached, destroyed.
6664 * @param tProjectionNode node to project
6665 * @param parentRElement parent DOM element for insertion/removal.
6666 * @param beforeNode Before which node the insertions should happen.
6667 */
6668function applyProjectionRecursive(renderer, action, lView, tProjectionNode, parentRElement, beforeNode) {
6669 const componentLView = lView[DECLARATION_COMPONENT_VIEW];
6670 const componentNode = componentLView[T_HOST];
6671 ngDevMode &&
6672 assertEqual(typeof tProjectionNode.projection, 'number', 'expecting projection index');
6673 const nodeToProjectOrRNodes = componentNode.projection[tProjectionNode.projection];
6674 if (Array.isArray(nodeToProjectOrRNodes)) {
6675 // This should not exist, it is a bit of a hack. When we bootstrap a top level node and we
6676 // need to support passing projectable nodes, so we cheat and put them in the TNode
6677 // of the Host TView. (Yes we put instance info at the T Level). We can get away with it
6678 // because we know that that TView is not shared and therefore it will not be a problem.
6679 // This should be refactored and cleaned up.
6680 for (let i = 0; i < nodeToProjectOrRNodes.length; i++) {
6681 const rNode = nodeToProjectOrRNodes[i];
6682 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
6683 }
6684 }
6685 else {
6686 let nodeToProject = nodeToProjectOrRNodes;
6687 const projectedComponentLView = componentLView[PARENT];
6688 applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
6689 }
6690}
6691/**
6692 * `applyContainer` performs an operation on the container and its views as specified by
6693 * `action` (insert, detach, destroy)
6694 *
6695 * Inserting a Container is complicated by the fact that the container may have Views which
6696 * themselves have containers or projections.
6697 *
6698 * @param renderer Renderer to use
6699 * @param action action to perform (insert, detach, destroy)
6700 * @param lContainer The LContainer which needs to be inserted, detached, destroyed.
6701 * @param parentRElement parent DOM element for insertion/removal.
6702 * @param beforeNode Before which node the insertions should happen.
6703 */
6704function applyContainer(renderer, action, lContainer, parentRElement, beforeNode) {
6705 ngDevMode && assertLContainer(lContainer);
6706 const anchor = lContainer[NATIVE]; // LContainer has its own before node.
6707 const native = unwrapRNode(lContainer);
6708 // An LContainer can be created dynamically on any node by injecting ViewContainerRef.
6709 // Asking for a ViewContainerRef on an element will result in a creation of a separate anchor
6710 // node (comment in the DOM) that will be different from the LContainer's host node. In this
6711 // particular case we need to execute action on 2 nodes:
6712 // - container's host node (this is done in the executeActionOnElementOrContainer)
6713 // - container's host node (this is done here)
6714 if (anchor !== native) {
6715 // This is very strange to me (Misko). I would expect that the native is same as anchor. I
6716 // don't see a reason why they should be different, but they are.
6717 //
6718 // If they are we need to process the second anchor as well.
6719 applyToElementOrContainer(action, renderer, parentRElement, anchor, beforeNode);
6720 }
6721 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
6722 const lView = lContainer[i];
6723 applyView(lView[TVIEW], lView, renderer, action, parentRElement, anchor);
6724 }
6725}
6726/**
6727 * Writes class/style to element.
6728 *
6729 * @param renderer Renderer to use.
6730 * @param isClassBased `true` if it should be written to `class` (`false` to write to `style`)
6731 * @param rNode The Node to write to.
6732 * @param prop Property to write to. This would be the class/style name.
6733 * @param value Value to write. If `null`/`undefined`/`false` this is considered a remove (set/add
6734 * otherwise).
6735 */
6736function applyStyling(renderer, isClassBased, rNode, prop, value) {
6737 if (isClassBased) {
6738 // We actually want JS true/false here because any truthy value should add the class
6739 if (!value) {
6740 ngDevMode && ngDevMode.rendererRemoveClass++;
6741 renderer.removeClass(rNode, prop);
6742 }
6743 else {
6744 ngDevMode && ngDevMode.rendererAddClass++;
6745 renderer.addClass(rNode, prop);
6746 }
6747 }
6748 else {
6749 let flags = prop.indexOf('-') === -1 ? undefined : RendererStyleFlags2.DashCase;
6750 if (value == null /** || value === undefined */) {
6751 ngDevMode && ngDevMode.rendererRemoveStyle++;
6752 renderer.removeStyle(rNode, prop, flags);
6753 }
6754 else {
6755 // A value is important if it ends with `!important`. The style
6756 // parser strips any semicolons at the end of the value.
6757 const isImportant = typeof value === 'string' ? value.endsWith('!important') : false;
6758 if (isImportant) {
6759 // !important has to be stripped from the value for it to be valid.
6760 value = value.slice(0, -10);
6761 flags |= RendererStyleFlags2.Important;
6762 }
6763 ngDevMode && ngDevMode.rendererSetStyle++;
6764 renderer.setStyle(rNode, prop, value, flags);
6765 }
6766 }
6767}
6768/**
6769 * Write `cssText` to `RElement`.
6770 *
6771 * This function does direct write without any reconciliation. Used for writing initial values, so
6772 * that static styling values do not pull in the style parser.
6773 *
6774 * @param renderer Renderer to use
6775 * @param element The element which needs to be updated.
6776 * @param newValue The new class list to write.
6777 */
6778function writeDirectStyle(renderer, element, newValue) {
6779 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
6780 renderer.setAttribute(element, 'style', newValue);
6781 ngDevMode && ngDevMode.rendererSetStyle++;
6782}
6783/**
6784 * Write `className` to `RElement`.
6785 *
6786 * This function does direct write without any reconciliation. Used for writing initial values, so
6787 * that static styling values do not pull in the style parser.
6788 *
6789 * @param renderer Renderer to use
6790 * @param element The element which needs to be updated.
6791 * @param newValue The new class list to write.
6792 */
6793function writeDirectClass(renderer, element, newValue) {
6794 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
6795 if (newValue === '') {
6796 // There are tests in `google3` which expect `element.getAttribute('class')` to be `null`.
6797 renderer.removeAttribute(element, 'class');
6798 }
6799 else {
6800 renderer.setAttribute(element, 'class', newValue);
6801 }
6802 ngDevMode && ngDevMode.rendererSetClassName++;
6803}
6804/** Sets up the static DOM attributes on an `RNode`. */
6805function setupStaticAttributes(renderer, element, tNode) {
6806 const { mergedAttrs, classes, styles } = tNode;
6807 if (mergedAttrs !== null) {
6808 setUpAttributes(renderer, element, mergedAttrs);
6809 }
6810 if (classes !== null) {
6811 writeDirectClass(renderer, element, classes);
6812 }
6813 if (styles !== null) {
6814 writeDirectStyle(renderer, element, styles);
6815 }
6816}
6817
6818/**
6819 * @fileoverview
6820 * A module to facilitate use of a Trusted Types policy internally within
6821 * Angular. It lazily constructs the Trusted Types policy, providing helper
6822 * utilities for promoting strings to Trusted Types. When Trusted Types are not
6823 * available, strings are used as a fallback.
6824 * @security All use of this module is security-sensitive and should go through
6825 * security review.
6826 */
6827/**
6828 * The Trusted Types policy, or null if Trusted Types are not
6829 * enabled/supported, or undefined if the policy has not been created yet.
6830 */
6831let policy$1;
6832/**
6833 * Returns the Trusted Types policy, or null if Trusted Types are not
6834 * enabled/supported. The first call to this function will create the policy.
6835 */
6836function getPolicy$1() {
6837 if (policy$1 === undefined) {
6838 policy$1 = null;
6839 if (_global$1.trustedTypes) {
6840 try {
6841 policy$1 = _global$1.trustedTypes.createPolicy('angular', {
6842 createHTML: (s) => s,
6843 createScript: (s) => s,
6844 createScriptURL: (s) => s,
6845 });
6846 }
6847 catch (_a) {
6848 // trustedTypes.createPolicy throws if called with a name that is
6849 // already registered, even in report-only mode. Until the API changes,
6850 // catch the error not to break the applications functionally. In such
6851 // cases, the code will fall back to using strings.
6852 }
6853 }
6854 }
6855 return policy$1;
6856}
6857/**
6858 * Unsafely promote a string to a TrustedHTML, falling back to strings when
6859 * Trusted Types are not available.
6860 * @security This is a security-sensitive function; any use of this function
6861 * must go through security review. In particular, it must be assured that the
6862 * provided string will never cause an XSS vulnerability if used in a context
6863 * that will be interpreted as HTML by a browser, e.g. when assigning to
6864 * element.innerHTML.
6865 */
6866function trustedHTMLFromString(html) {
6867 var _a;
6868 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createHTML(html)) || html;
6869}
6870/**
6871 * Unsafely promote a string to a TrustedScript, falling back to strings when
6872 * Trusted Types are not available.
6873 * @security In particular, it must be assured that the provided string will
6874 * never cause an XSS vulnerability if used in a context that will be
6875 * interpreted and executed as a script by a browser, e.g. when calling eval.
6876 */
6877function trustedScriptFromString(script) {
6878 var _a;
6879 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
6880}
6881/**
6882 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
6883 * when Trusted Types are not available.
6884 * @security This is a security-sensitive function; any use of this function
6885 * must go through security review. In particular, it must be assured that the
6886 * provided string will never cause an XSS vulnerability if used in a context
6887 * that will cause a browser to load and execute a resource, e.g. when
6888 * assigning to script.src.
6889 */
6890function trustedScriptURLFromString(url) {
6891 var _a;
6892 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScriptURL(url)) || url;
6893}
6894/**
6895 * Unsafely call the Function constructor with the given string arguments. It
6896 * is only available in development mode, and should be stripped out of
6897 * production code.
6898 * @security This is a security-sensitive function; any use of this function
6899 * must go through security review. In particular, it must be assured that it
6900 * is only called from development code, as use in production code can lead to
6901 * XSS vulnerabilities.
6902 */
6903function newTrustedFunctionForDev(...args) {
6904 if (typeof ngDevMode === 'undefined') {
6905 throw new Error('newTrustedFunctionForDev should never be called in production');
6906 }
6907 if (!_global$1.trustedTypes) {
6908 // In environments that don't support Trusted Types, fall back to the most
6909 // straightforward implementation:
6910 return new Function(...args);
6911 }
6912 // Chrome currently does not support passing TrustedScript to the Function
6913 // constructor. The following implements the workaround proposed on the page
6914 // below, where the Chromium bug is also referenced:
6915 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
6916 const fnArgs = args.slice(0, -1).join(',');
6917 const fnBody = args[args.length - 1];
6918 const body = `(function anonymous(${fnArgs}
6919) { ${fnBody}
6920})`;
6921 // Using eval directly confuses the compiler and prevents this module from
6922 // being stripped out of JS binaries even if not used. The global['eval']
6923 // indirection fixes that.
6924 const fn = _global$1['eval'](trustedScriptFromString(body));
6925 if (fn.bind === undefined) {
6926 // Workaround for a browser bug that only exists in Chrome 83, where passing
6927 // a TrustedScript to eval just returns the TrustedScript back without
6928 // evaluating it. In that case, fall back to the most straightforward
6929 // implementation:
6930 return new Function(...args);
6931 }
6932 // To completely mimic the behavior of calling "new Function", two more
6933 // things need to happen:
6934 // 1. Stringifying the resulting function should return its source code
6935 fn.toString = () => body;
6936 // 2. When calling the resulting function, `this` should refer to `global`
6937 return fn.bind(_global$1);
6938 // When Trusted Types support in Function constructors is widely available,
6939 // the implementation of this function can be simplified to:
6940 // return new Function(...args.map(a => trustedScriptFromString(a)));
6941}
6942
6943/**
6944 * Validation function invoked at runtime for each binding that might potentially
6945 * represent a security-sensitive attribute of an <iframe>.
6946 * See `IFRAME_SECURITY_SENSITIVE_ATTRS` in the
6947 * `packages/compiler/src/schema/dom_security_schema.ts` script for the full list
6948 * of such attributes.
6949 *
6950 * @codeGenApi
6951 */
6952function ɵɵvalidateIframeAttribute(attrValue, tagName, attrName) {
6953 const lView = getLView();
6954 const tNode = getSelectedTNode();
6955 const element = getNativeByTNode(tNode, lView);
6956 // Restrict any dynamic bindings of security-sensitive attributes/properties
6957 // on an <iframe> for security reasons.
6958 if (tNode.type === 2 /* TNodeType.Element */ && tagName.toLowerCase() === 'iframe') {
6959 const iframe = element;
6960 // Unset previously applied `src` and `srcdoc` if we come across a situation when
6961 // a security-sensitive attribute is set later via an attribute/property binding.
6962 iframe.src = '';
6963 iframe.srcdoc = trustedHTMLFromString('');
6964 // Also remove the <iframe> from the document.
6965 nativeRemoveNode(lView[RENDERER], iframe);
6966 const errorMessage = ngDevMode &&
6967 `Angular has detected that the \`${attrName}\` was applied ` +
6968 `as a binding to an <iframe>${getTemplateLocationDetails(lView)}. ` +
6969 `For security reasons, the \`${attrName}\` can be set on an <iframe> ` +
6970 `as a static attribute only. \n` +
6971 `To fix this, switch the \`${attrName}\` binding to a static attribute ` +
6972 `in a template or in host bindings section.`;
6973 throw new RuntimeError(-910 /* RuntimeErrorCode.UNSAFE_IFRAME_ATTRS */, errorMessage);
6974 }
6975 return attrValue;
6976}
6977
6978/**
6979 * Most of the use of `document` in Angular is from within the DI system so it is possible to simply
6980 * inject the `DOCUMENT` token and are done.
6981 *
6982 * Ivy is special because it does not rely upon the DI and must get hold of the document some other
6983 * way.
6984 *
6985 * The solution is to define `getDocument()` and `setDocument()` top-level functions for ivy.
6986 * Wherever ivy needs the global document, it calls `getDocument()` instead.
6987 *
6988 * When running ivy outside of a browser environment, it is necessary to call `setDocument()` to
6989 * tell ivy what the global `document` is.
6990 *
6991 * Angular does this for us in each of the standard platforms (`Browser`, `Server`, and `WebWorker`)
6992 * by calling `setDocument()` when providing the `DOCUMENT` token.
6993 */
6994let DOCUMENT = undefined;
6995/**
6996 * Tell ivy what the `document` is for this platform.
6997 *
6998 * It is only necessary to call this if the current platform is not a browser.
6999 *
7000 * @param document The object representing the global `document` in this environment.
7001 */
7002function setDocument(document) {
7003 DOCUMENT = document;
7004}
7005/**
7006 * Access the object that represents the `document` for this platform.
7007 *
7008 * Ivy calls this whenever it needs to access the `document` object.
7009 * For example to create the renderer or to do sanitization.
7010 */
7011function getDocument() {
7012 if (DOCUMENT !== undefined) {
7013 return DOCUMENT;
7014 }
7015 else if (typeof document !== 'undefined') {
7016 return document;
7017 }
7018 // No "document" can be found. This should only happen if we are running ivy outside Angular and
7019 // the current platform is not a browser. Since this is not a supported scenario at the moment
7020 // this should not happen in Angular apps.
7021 // Once we support running ivy outside of Angular we will need to publish `setDocument()` as a
7022 // public API. Meanwhile we just return `undefined` and let the application fail.
7023 return undefined;
7024}
7025
7026/**
7027 * @fileoverview
7028 * A module to facilitate use of a Trusted Types policy internally within
7029 * Angular specifically for bypassSecurityTrust* and custom sanitizers. It
7030 * lazily constructs the Trusted Types policy, providing helper utilities for
7031 * promoting strings to Trusted Types. When Trusted Types are not available,
7032 * strings are used as a fallback.
7033 * @security All use of this module is security-sensitive and should go through
7034 * security review.
7035 */
7036/**
7037 * The Trusted Types policy, or null if Trusted Types are not
7038 * enabled/supported, or undefined if the policy has not been created yet.
7039 */
7040let policy;
7041/**
7042 * Returns the Trusted Types policy, or null if Trusted Types are not
7043 * enabled/supported. The first call to this function will create the policy.
7044 */
7045function getPolicy() {
7046 if (policy === undefined) {
7047 policy = null;
7048 if (_global$1.trustedTypes) {
7049 try {
7050 policy = _global$1.trustedTypes
7051 .createPolicy('angular#unsafe-bypass', {
7052 createHTML: (s) => s,
7053 createScript: (s) => s,
7054 createScriptURL: (s) => s,
7055 });
7056 }
7057 catch (_a) {
7058 // trustedTypes.createPolicy throws if called with a name that is
7059 // already registered, even in report-only mode. Until the API changes,
7060 // catch the error not to break the applications functionally. In such
7061 // cases, the code will fall back to using strings.
7062 }
7063 }
7064 }
7065 return policy;
7066}
7067/**
7068 * Unsafely promote a string to a TrustedHTML, falling back to strings when
7069 * Trusted Types are not available.
7070 * @security This is a security-sensitive function; any use of this function
7071 * must go through security review. In particular, it must be assured that it
7072 * is only passed strings that come directly from custom sanitizers or the
7073 * bypassSecurityTrust* functions.
7074 */
7075function trustedHTMLFromStringBypass(html) {
7076 var _a;
7077 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createHTML(html)) || html;
7078}
7079/**
7080 * Unsafely promote a string to a TrustedScript, falling back to strings when
7081 * Trusted Types are not available.
7082 * @security This is a security-sensitive function; any use of this function
7083 * must go through security review. In particular, it must be assured that it
7084 * is only passed strings that come directly from custom sanitizers or the
7085 * bypassSecurityTrust* functions.
7086 */
7087function trustedScriptFromStringBypass(script) {
7088 var _a;
7089 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
7090}
7091/**
7092 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
7093 * when Trusted Types are not available.
7094 * @security This is a security-sensitive function; any use of this function
7095 * must go through security review. In particular, it must be assured that it
7096 * is only passed strings that come directly from custom sanitizers or the
7097 * bypassSecurityTrust* functions.
7098 */
7099function trustedScriptURLFromStringBypass(url) {
7100 var _a;
7101 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScriptURL(url)) || url;
7102}
7103
7104class SafeValueImpl {
7105 constructor(changingThisBreaksApplicationSecurity) {
7106 this.changingThisBreaksApplicationSecurity = changingThisBreaksApplicationSecurity;
7107 }
7108 toString() {
7109 return `SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity}` +
7110 ` (see ${XSS_SECURITY_URL})`;
7111 }
7112}
7113class SafeHtmlImpl extends SafeValueImpl {
7114 getTypeName() {
7115 return "HTML" /* BypassType.Html */;
7116 }
7117}
7118class SafeStyleImpl extends SafeValueImpl {
7119 getTypeName() {
7120 return "Style" /* BypassType.Style */;
7121 }
7122}
7123class SafeScriptImpl extends SafeValueImpl {
7124 getTypeName() {
7125 return "Script" /* BypassType.Script */;
7126 }
7127}
7128class SafeUrlImpl extends SafeValueImpl {
7129 getTypeName() {
7130 return "URL" /* BypassType.Url */;
7131 }
7132}
7133class SafeResourceUrlImpl extends SafeValueImpl {
7134 getTypeName() {
7135 return "ResourceURL" /* BypassType.ResourceUrl */;
7136 }
7137}
7138function unwrapSafeValue(value) {
7139 return value instanceof SafeValueImpl ? value.changingThisBreaksApplicationSecurity :
7140 value;
7141}
7142function allowSanitizationBypassAndThrow(value, type) {
7143 const actualType = getSanitizationBypassType(value);
7144 if (actualType != null && actualType !== type) {
7145 // Allow ResourceURLs in URL contexts, they are strictly more trusted.
7146 if (actualType === "ResourceURL" /* BypassType.ResourceUrl */ && type === "URL" /* BypassType.Url */)
7147 return true;
7148 throw new Error(`Required a safe ${type}, got a ${actualType} (see ${XSS_SECURITY_URL})`);
7149 }
7150 return actualType === type;
7151}
7152function getSanitizationBypassType(value) {
7153 return value instanceof SafeValueImpl && value.getTypeName() || null;
7154}
7155/**
7156 * Mark `html` string as trusted.
7157 *
7158 * This function wraps the trusted string in `String` and brands it in a way which makes it
7159 * recognizable to {@link htmlSanitizer} to be trusted implicitly.
7160 *
7161 * @param trustedHtml `html` string which needs to be implicitly trusted.
7162 * @returns a `html` which has been branded to be implicitly trusted.
7163 */
7164function bypassSanitizationTrustHtml(trustedHtml) {
7165 return new SafeHtmlImpl(trustedHtml);
7166}
7167/**
7168 * Mark `style` string as trusted.
7169 *
7170 * This function wraps the trusted string in `String` and brands it in a way which makes it
7171 * recognizable to {@link styleSanitizer} to be trusted implicitly.
7172 *
7173 * @param trustedStyle `style` string which needs to be implicitly trusted.
7174 * @returns a `style` hich has been branded to be implicitly trusted.
7175 */
7176function bypassSanitizationTrustStyle(trustedStyle) {
7177 return new SafeStyleImpl(trustedStyle);
7178}
7179/**
7180 * Mark `script` string as trusted.
7181 *
7182 * This function wraps the trusted string in `String` and brands it in a way which makes it
7183 * recognizable to {@link scriptSanitizer} to be trusted implicitly.
7184 *
7185 * @param trustedScript `script` string which needs to be implicitly trusted.
7186 * @returns a `script` which has been branded to be implicitly trusted.
7187 */
7188function bypassSanitizationTrustScript(trustedScript) {
7189 return new SafeScriptImpl(trustedScript);
7190}
7191/**
7192 * Mark `url` string as trusted.
7193 *
7194 * This function wraps the trusted string in `String` and brands it in a way which makes it
7195 * recognizable to {@link urlSanitizer} to be trusted implicitly.
7196 *
7197 * @param trustedUrl `url` string which needs to be implicitly trusted.
7198 * @returns a `url` which has been branded to be implicitly trusted.
7199 */
7200function bypassSanitizationTrustUrl(trustedUrl) {
7201 return new SafeUrlImpl(trustedUrl);
7202}
7203/**
7204 * Mark `url` string as trusted.
7205 *
7206 * This function wraps the trusted string in `String` and brands it in a way which makes it
7207 * recognizable to {@link resourceUrlSanitizer} to be trusted implicitly.
7208 *
7209 * @param trustedResourceUrl `url` string which needs to be implicitly trusted.
7210 * @returns a `url` which has been branded to be implicitly trusted.
7211 */
7212function bypassSanitizationTrustResourceUrl(trustedResourceUrl) {
7213 return new SafeResourceUrlImpl(trustedResourceUrl);
7214}
7215
7216/**
7217 * This helper is used to get hold of an inert tree of DOM elements containing dirty HTML
7218 * that needs sanitizing.
7219 * Depending upon browser support we use one of two strategies for doing this.
7220 * Default: DOMParser strategy
7221 * Fallback: InertDocument strategy
7222 */
7223function getInertBodyHelper(defaultDoc) {
7224 const inertDocumentHelper = new InertDocumentHelper(defaultDoc);
7225 return isDOMParserAvailable() ? new DOMParserHelper(inertDocumentHelper) : inertDocumentHelper;
7226}
7227/**
7228 * Uses DOMParser to create and fill an inert body element.
7229 * This is the default strategy used in browsers that support it.
7230 */
7231class DOMParserHelper {
7232 constructor(inertDocumentHelper) {
7233 this.inertDocumentHelper = inertDocumentHelper;
7234 }
7235 getInertBodyElement(html) {
7236 // We add these extra elements to ensure that the rest of the content is parsed as expected
7237 // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the
7238 // `<head>` tag. Note that the `<body>` tag is closed implicitly to prevent unclosed tags
7239 // in `html` from consuming the otherwise explicit `</body>` tag.
7240 html = '<body><remove></remove>' + html;
7241 try {
7242 const body = new window.DOMParser()
7243 .parseFromString(trustedHTMLFromString(html), 'text/html')
7244 .body;
7245 if (body === null) {
7246 // In some browsers (e.g. Mozilla/5.0 iPad AppleWebKit Mobile) the `body` property only
7247 // becomes available in the following tick of the JS engine. In that case we fall back to
7248 // the `inertDocumentHelper` instead.
7249 return this.inertDocumentHelper.getInertBodyElement(html);
7250 }
7251 body.removeChild(body.firstChild);
7252 return body;
7253 }
7254 catch (_a) {
7255 return null;
7256 }
7257 }
7258}
7259/**
7260 * Use an HTML5 `template` element, if supported, or an inert body element created via
7261 * `createHtmlDocument` to create and fill an inert DOM element.
7262 * This is the fallback strategy if the browser does not support DOMParser.
7263 */
7264class InertDocumentHelper {
7265 constructor(defaultDoc) {
7266 this.defaultDoc = defaultDoc;
7267 this.inertDocument = this.defaultDoc.implementation.createHTMLDocument('sanitization-inert');
7268 if (this.inertDocument.body == null) {
7269 // usually there should be only one body element in the document, but IE doesn't have any, so
7270 // we need to create one.
7271 const inertHtml = this.inertDocument.createElement('html');
7272 this.inertDocument.appendChild(inertHtml);
7273 const inertBodyElement = this.inertDocument.createElement('body');
7274 inertHtml.appendChild(inertBodyElement);
7275 }
7276 }
7277 getInertBodyElement(html) {
7278 // Prefer using <template> element if supported.
7279 const templateEl = this.inertDocument.createElement('template');
7280 if ('content' in templateEl) {
7281 templateEl.innerHTML = trustedHTMLFromString(html);
7282 return templateEl;
7283 }
7284 // Note that previously we used to do something like `this.inertDocument.body.innerHTML = html`
7285 // and we returned the inert `body` node. This was changed, because IE seems to treat setting
7286 // `innerHTML` on an inserted element differently, compared to one that hasn't been inserted
7287 // yet. In particular, IE appears to split some of the text into multiple text nodes rather
7288 // than keeping them in a single one which ends up messing with Ivy's i18n parsing further
7289 // down the line. This has been worked around by creating a new inert `body` and using it as
7290 // the root node in which we insert the HTML.
7291 const inertBody = this.inertDocument.createElement('body');
7292 inertBody.innerHTML = trustedHTMLFromString(html);
7293 // Support: IE 11 only
7294 // strip custom-namespaced attributes on IE<=11
7295 if (this.defaultDoc.documentMode) {
7296 this.stripCustomNsAttrs(inertBody);
7297 }
7298 return inertBody;
7299 }
7300 /**
7301 * When IE11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1'
7302 * attribute to declare ns1 namespace and prefixes the attribute with 'ns1' (e.g.
7303 * 'ns1:xlink:foo').
7304 *
7305 * This is undesirable since we don't want to allow any of these custom attributes. This method
7306 * strips them all.
7307 */
7308 stripCustomNsAttrs(el) {
7309 const elAttrs = el.attributes;
7310 // loop backwards so that we can support removals.
7311 for (let i = elAttrs.length - 1; 0 < i; i--) {
7312 const attrib = elAttrs.item(i);
7313 const attrName = attrib.name;
7314 if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) {
7315 el.removeAttribute(attrName);
7316 }
7317 }
7318 let childNode = el.firstChild;
7319 while (childNode) {
7320 if (childNode.nodeType === Node.ELEMENT_NODE)
7321 this.stripCustomNsAttrs(childNode);
7322 childNode = childNode.nextSibling;
7323 }
7324 }
7325}
7326/**
7327 * We need to determine whether the DOMParser exists in the global context and
7328 * supports parsing HTML; HTML parsing support is not as wide as other formats, see
7329 * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility.
7330 *
7331 * @suppress {uselessCode}
7332 */
7333function isDOMParserAvailable() {
7334 try {
7335 return !!new window.DOMParser().parseFromString(trustedHTMLFromString(''), 'text/html');
7336 }
7337 catch (_a) {
7338 return false;
7339 }
7340}
7341
7342/**
7343 * A pattern that recognizes a commonly useful subset of URLs that are safe.
7344 *
7345 * This regular expression matches a subset of URLs that will not cause script
7346 * execution if used in URL context within a HTML document. Specifically, this
7347 * regular expression matches if (comment from here on and regex copied from
7348 * Soy's EscapingConventions):
7349 * (1) Either an allowed protocol (http, https, mailto or ftp).
7350 * (2) or no protocol. A protocol must be followed by a colon. The below
7351 * allows that by allowing colons only after one of the characters [/?#].
7352 * A colon after a hash (#) must be in the fragment.
7353 * Otherwise, a colon after a (?) must be in a query.
7354 * Otherwise, a colon after a single solidus (/) must be in a path.
7355 * Otherwise, a colon after a double solidus (//) must be in the authority
7356 * (before port).
7357 *
7358 * The pattern disallows &, used in HTML entity declarations before
7359 * one of the characters in [/?#]. This disallows HTML entities used in the
7360 * protocol name, which should never happen, e.g. "h&#116;tp" for "http".
7361 * It also disallows HTML entities in the first path part of a relative path,
7362 * e.g. "foo&lt;bar/baz". Our existing escaping functions should not produce
7363 * that. More importantly, it disallows masking of a colon,
7364 * e.g. "javascript&#58;...".
7365 *
7366 * This regular expression was taken from the Closure sanitization library.
7367 */
7368const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|data|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi;
7369function _sanitizeUrl(url) {
7370 url = String(url);
7371 if (url.match(SAFE_URL_PATTERN))
7372 return url;
7373 if (typeof ngDevMode === 'undefined' || ngDevMode) {
7374 console.warn(`WARNING: sanitizing unsafe URL value ${url} (see ${XSS_SECURITY_URL})`);
7375 }
7376 return 'unsafe:' + url;
7377}
7378
7379function tagSet(tags) {
7380 const res = {};
7381 for (const t of tags.split(','))
7382 res[t] = true;
7383 return res;
7384}
7385function merge(...sets) {
7386 const res = {};
7387 for (const s of sets) {
7388 for (const v in s) {
7389 if (s.hasOwnProperty(v))
7390 res[v] = true;
7391 }
7392 }
7393 return res;
7394}
7395// Good source of info about elements and attributes
7396// https://html.spec.whatwg.org/#semantics
7397// https://simon.html5.org/html-elements
7398// Safe Void Elements - HTML5
7399// https://html.spec.whatwg.org/#void-elements
7400const VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr');
7401// Elements that you can, intentionally, leave open (and which close themselves)
7402// https://html.spec.whatwg.org/#optional-tags
7403const OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr');
7404const OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt');
7405const OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS);
7406// Safe Block Elements - HTML5
7407const BLOCK_ELEMENTS = merge(OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet('address,article,' +
7408 'aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
7409 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul'));
7410// Inline Elements - HTML5
7411const INLINE_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet('a,abbr,acronym,audio,b,' +
7412 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' +
7413 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video'));
7414const VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS);
7415// Attributes that have href and hence need to be sanitized
7416const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
7417const HTML_ATTRS = tagSet('abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' +
7418 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' +
7419 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' +
7420 'scope,scrolling,shape,size,sizes,span,srclang,srcset,start,summary,tabindex,target,title,translate,type,usemap,' +
7421 'valign,value,vspace,width');
7422// Accessibility attributes as per WAI-ARIA 1.1 (W3C Working Draft 14 December 2018)
7423const ARIA_ATTRS = tagSet('aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,' +
7424 'aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,' +
7425 'aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,' +
7426 'aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,' +
7427 'aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,' +
7428 'aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,' +
7429 'aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext');
7430// NB: This currently consciously doesn't support SVG. SVG sanitization has had several security
7431// issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via
7432// innerHTML is required, SVG attributes should be added here.
7433// NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those
7434// can be sanitized, but they increase security surface area without a legitimate use case, so they
7435// are left out here.
7436const VALID_ATTRS = merge(URI_ATTRS, HTML_ATTRS, ARIA_ATTRS);
7437// Elements whose content should not be traversed/preserved, if the elements themselves are invalid.
7438//
7439// Typically, `<invalid>Some content</invalid>` would traverse (and in this case preserve)
7440// `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we
7441// don't want to preserve the content, if the elements themselves are going to be removed.
7442const SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template');
7443/**
7444 * SanitizingHtmlSerializer serializes a DOM fragment, stripping out any unsafe elements and unsafe
7445 * attributes.
7446 */
7447class SanitizingHtmlSerializer {
7448 constructor() {
7449 // Explicitly track if something was stripped, to avoid accidentally warning of sanitization just
7450 // because characters were re-encoded.
7451 this.sanitizedSomething = false;
7452 this.buf = [];
7453 }
7454 sanitizeChildren(el) {
7455 // This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters.
7456 // However this code never accesses properties off of `document` before deleting its contents
7457 // again, so it shouldn't be vulnerable to DOM clobbering.
7458 let current = el.firstChild;
7459 let traverseContent = true;
7460 while (current) {
7461 if (current.nodeType === Node.ELEMENT_NODE) {
7462 traverseContent = this.startElement(current);
7463 }
7464 else if (current.nodeType === Node.TEXT_NODE) {
7465 this.chars(current.nodeValue);
7466 }
7467 else {
7468 // Strip non-element, non-text nodes.
7469 this.sanitizedSomething = true;
7470 }
7471 if (traverseContent && current.firstChild) {
7472 current = current.firstChild;
7473 continue;
7474 }
7475 while (current) {
7476 // Leaving the element. Walk up and to the right, closing tags as we go.
7477 if (current.nodeType === Node.ELEMENT_NODE) {
7478 this.endElement(current);
7479 }
7480 let next = this.checkClobberedElement(current, current.nextSibling);
7481 if (next) {
7482 current = next;
7483 break;
7484 }
7485 current = this.checkClobberedElement(current, current.parentNode);
7486 }
7487 }
7488 return this.buf.join('');
7489 }
7490 /**
7491 * Sanitizes an opening element tag (if valid) and returns whether the element's contents should
7492 * be traversed. Element content must always be traversed (even if the element itself is not
7493 * valid/safe), unless the element is one of `SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS`.
7494 *
7495 * @param element The element to sanitize.
7496 * @return True if the element's contents should be traversed.
7497 */
7498 startElement(element) {
7499 const tagName = element.nodeName.toLowerCase();
7500 if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
7501 this.sanitizedSomething = true;
7502 return !SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS.hasOwnProperty(tagName);
7503 }
7504 this.buf.push('<');
7505 this.buf.push(tagName);
7506 const elAttrs = element.attributes;
7507 for (let i = 0; i < elAttrs.length; i++) {
7508 const elAttr = elAttrs.item(i);
7509 const attrName = elAttr.name;
7510 const lower = attrName.toLowerCase();
7511 if (!VALID_ATTRS.hasOwnProperty(lower)) {
7512 this.sanitizedSomething = true;
7513 continue;
7514 }
7515 let value = elAttr.value;
7516 // TODO(martinprobst): Special case image URIs for data:image/...
7517 if (URI_ATTRS[lower])
7518 value = _sanitizeUrl(value);
7519 this.buf.push(' ', attrName, '="', encodeEntities(value), '"');
7520 }
7521 this.buf.push('>');
7522 return true;
7523 }
7524 endElement(current) {
7525 const tagName = current.nodeName.toLowerCase();
7526 if (VALID_ELEMENTS.hasOwnProperty(tagName) && !VOID_ELEMENTS.hasOwnProperty(tagName)) {
7527 this.buf.push('</');
7528 this.buf.push(tagName);
7529 this.buf.push('>');
7530 }
7531 }
7532 chars(chars) {
7533 this.buf.push(encodeEntities(chars));
7534 }
7535 checkClobberedElement(node, nextNode) {
7536 if (nextNode &&
7537 (node.compareDocumentPosition(nextNode) &
7538 Node.DOCUMENT_POSITION_CONTAINED_BY) === Node.DOCUMENT_POSITION_CONTAINED_BY) {
7539 throw new Error(`Failed to sanitize html because the element is clobbered: ${node.outerHTML}`);
7540 }
7541 return nextNode;
7542 }
7543}
7544// Regular Expressions for parsing tags and attributes
7545const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
7546// ! to ~ is the ASCII range.
7547const NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
7548/**
7549 * Escapes all potentially dangerous characters, so that the
7550 * resulting string can be safely inserted into attribute or
7551 * element text.
7552 * @param value
7553 */
7554function encodeEntities(value) {
7555 return value.replace(/&/g, '&amp;')
7556 .replace(SURROGATE_PAIR_REGEXP, function (match) {
7557 const hi = match.charCodeAt(0);
7558 const low = match.charCodeAt(1);
7559 return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
7560 })
7561 .replace(NON_ALPHANUMERIC_REGEXP, function (match) {
7562 return '&#' + match.charCodeAt(0) + ';';
7563 })
7564 .replace(/</g, '&lt;')
7565 .replace(/>/g, '&gt;');
7566}
7567let inertBodyHelper;
7568/**
7569 * Sanitizes the given unsafe, untrusted HTML fragment, and returns HTML text that is safe to add to
7570 * the DOM in a browser environment.
7571 */
7572function _sanitizeHtml(defaultDoc, unsafeHtmlInput) {
7573 let inertBodyElement = null;
7574 try {
7575 inertBodyHelper = inertBodyHelper || getInertBodyHelper(defaultDoc);
7576 // Make sure unsafeHtml is actually a string (TypeScript types are not enforced at runtime).
7577 let unsafeHtml = unsafeHtmlInput ? String(unsafeHtmlInput) : '';
7578 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
7579 // mXSS protection. Repeatedly parse the document to make sure it stabilizes, so that a browser
7580 // trying to auto-correct incorrect HTML cannot cause formerly inert HTML to become dangerous.
7581 let mXSSAttempts = 5;
7582 let parsedHtml = unsafeHtml;
7583 do {
7584 if (mXSSAttempts === 0) {
7585 throw new Error('Failed to sanitize html because the input is unstable');
7586 }
7587 mXSSAttempts--;
7588 unsafeHtml = parsedHtml;
7589 parsedHtml = inertBodyElement.innerHTML;
7590 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
7591 } while (unsafeHtml !== parsedHtml);
7592 const sanitizer = new SanitizingHtmlSerializer();
7593 const safeHtml = sanitizer.sanitizeChildren(getTemplateContent(inertBodyElement) || inertBodyElement);
7594 if ((typeof ngDevMode === 'undefined' || ngDevMode) && sanitizer.sanitizedSomething) {
7595 console.warn(`WARNING: sanitizing HTML stripped some content, see ${XSS_SECURITY_URL}`);
7596 }
7597 return trustedHTMLFromString(safeHtml);
7598 }
7599 finally {
7600 // In case anything goes wrong, clear out inertElement to reset the entire DOM structure.
7601 if (inertBodyElement) {
7602 const parent = getTemplateContent(inertBodyElement) || inertBodyElement;
7603 while (parent.firstChild) {
7604 parent.removeChild(parent.firstChild);
7605 }
7606 }
7607 }
7608}
7609function getTemplateContent(el) {
7610 return 'content' in el /** Microsoft/TypeScript#21517 */ && isTemplateElement(el) ?
7611 el.content :
7612 null;
7613}
7614function isTemplateElement(el) {
7615 return el.nodeType === Node.ELEMENT_NODE && el.nodeName === 'TEMPLATE';
7616}
7617
7618/**
7619 * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
7620 * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
7621 * handled.
7622 *
7623 * See DomSanitizer for more details on security in Angular applications.
7624 *
7625 * @publicApi
7626 */
7627var SecurityContext;
7628(function (SecurityContext) {
7629 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
7630 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
7631 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
7632 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
7633 SecurityContext[SecurityContext["URL"] = 4] = "URL";
7634 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
7635})(SecurityContext || (SecurityContext = {}));
7636
7637/**
7638 * An `html` sanitizer which converts untrusted `html` **string** into trusted string by removing
7639 * dangerous content.
7640 *
7641 * This method parses the `html` and locates potentially dangerous content (such as urls and
7642 * javascript) and removes it.
7643 *
7644 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustHtml}.
7645 *
7646 * @param unsafeHtml untrusted `html`, typically from the user.
7647 * @returns `html` string which is safe to display to user, because all of the dangerous javascript
7648 * and urls have been removed.
7649 *
7650 * @codeGenApi
7651 */
7652function ɵɵsanitizeHtml(unsafeHtml) {
7653 const sanitizer = getSanitizer();
7654 if (sanitizer) {
7655 return trustedHTMLFromStringBypass(sanitizer.sanitize(SecurityContext.HTML, unsafeHtml) || '');
7656 }
7657 if (allowSanitizationBypassAndThrow(unsafeHtml, "HTML" /* BypassType.Html */)) {
7658 return trustedHTMLFromStringBypass(unwrapSafeValue(unsafeHtml));
7659 }
7660 return _sanitizeHtml(getDocument(), renderStringify(unsafeHtml));
7661}
7662/**
7663 * A `style` sanitizer which converts untrusted `style` **string** into trusted string by removing
7664 * dangerous content.
7665 *
7666 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustStyle}.
7667 *
7668 * @param unsafeStyle untrusted `style`, typically from the user.
7669 * @returns `style` string which is safe to bind to the `style` properties.
7670 *
7671 * @codeGenApi
7672 */
7673function ɵɵsanitizeStyle(unsafeStyle) {
7674 const sanitizer = getSanitizer();
7675 if (sanitizer) {
7676 return sanitizer.sanitize(SecurityContext.STYLE, unsafeStyle) || '';
7677 }
7678 if (allowSanitizationBypassAndThrow(unsafeStyle, "Style" /* BypassType.Style */)) {
7679 return unwrapSafeValue(unsafeStyle);
7680 }
7681 return renderStringify(unsafeStyle);
7682}
7683/**
7684 * A `url` sanitizer which converts untrusted `url` **string** into trusted string by removing
7685 * dangerous
7686 * content.
7687 *
7688 * This method parses the `url` and locates potentially dangerous content (such as javascript) and
7689 * removes it.
7690 *
7691 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustUrl}.
7692 *
7693 * @param unsafeUrl untrusted `url`, typically from the user.
7694 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
7695 * all of the dangerous javascript has been removed.
7696 *
7697 * @codeGenApi
7698 */
7699function ɵɵsanitizeUrl(unsafeUrl) {
7700 const sanitizer = getSanitizer();
7701 if (sanitizer) {
7702 return sanitizer.sanitize(SecurityContext.URL, unsafeUrl) || '';
7703 }
7704 if (allowSanitizationBypassAndThrow(unsafeUrl, "URL" /* BypassType.Url */)) {
7705 return unwrapSafeValue(unsafeUrl);
7706 }
7707 return _sanitizeUrl(renderStringify(unsafeUrl));
7708}
7709/**
7710 * A `url` sanitizer which only lets trusted `url`s through.
7711 *
7712 * This passes only `url`s marked trusted by calling {@link bypassSanitizationTrustResourceUrl}.
7713 *
7714 * @param unsafeResourceUrl untrusted `url`, typically from the user.
7715 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
7716 * only trusted `url`s have been allowed to pass.
7717 *
7718 * @codeGenApi
7719 */
7720function ɵɵsanitizeResourceUrl(unsafeResourceUrl) {
7721 const sanitizer = getSanitizer();
7722 if (sanitizer) {
7723 return trustedScriptURLFromStringBypass(sanitizer.sanitize(SecurityContext.RESOURCE_URL, unsafeResourceUrl) || '');
7724 }
7725 if (allowSanitizationBypassAndThrow(unsafeResourceUrl, "ResourceURL" /* BypassType.ResourceUrl */)) {
7726 return trustedScriptURLFromStringBypass(unwrapSafeValue(unsafeResourceUrl));
7727 }
7728 throw new RuntimeError(904 /* RuntimeErrorCode.UNSAFE_VALUE_IN_RESOURCE_URL */, ngDevMode && `unsafe value used in a resource URL context (see ${XSS_SECURITY_URL})`);
7729}
7730/**
7731 * A `script` sanitizer which only lets trusted javascript through.
7732 *
7733 * This passes only `script`s marked trusted by calling {@link
7734 * bypassSanitizationTrustScript}.
7735 *
7736 * @param unsafeScript untrusted `script`, typically from the user.
7737 * @returns `url` string which is safe to bind to the `<script>` element such as `<img src>`,
7738 * because only trusted `scripts` have been allowed to pass.
7739 *
7740 * @codeGenApi
7741 */
7742function ɵɵsanitizeScript(unsafeScript) {
7743 const sanitizer = getSanitizer();
7744 if (sanitizer) {
7745 return trustedScriptFromStringBypass(sanitizer.sanitize(SecurityContext.SCRIPT, unsafeScript) || '');
7746 }
7747 if (allowSanitizationBypassAndThrow(unsafeScript, "Script" /* BypassType.Script */)) {
7748 return trustedScriptFromStringBypass(unwrapSafeValue(unsafeScript));
7749 }
7750 throw new RuntimeError(905 /* RuntimeErrorCode.UNSAFE_VALUE_IN_SCRIPT */, ngDevMode && 'unsafe value used in a script context');
7751}
7752/**
7753 * A template tag function for promoting the associated constant literal to a
7754 * TrustedHTML. Interpolation is explicitly not allowed.
7755 *
7756 * @param html constant template literal containing trusted HTML.
7757 * @returns TrustedHTML wrapping `html`.
7758 *
7759 * @security This is a security-sensitive function and should only be used to
7760 * convert constant values of attributes and properties found in
7761 * application-provided Angular templates to TrustedHTML.
7762 *
7763 * @codeGenApi
7764 */
7765function ɵɵtrustConstantHtml(html) {
7766 // The following runtime check ensures that the function was called as a
7767 // template tag (e.g. ɵɵtrustConstantHtml`content`), without any interpolation
7768 // (e.g. not ɵɵtrustConstantHtml`content ${variable}`). A TemplateStringsArray
7769 // is an array with a `raw` property that is also an array. The associated
7770 // template literal has no interpolation if and only if the length of the
7771 // TemplateStringsArray is 1.
7772 if (ngDevMode && (!Array.isArray(html) || !Array.isArray(html.raw) || html.length !== 1)) {
7773 throw new Error(`Unexpected interpolation in trusted HTML constant: ${html.join('?')}`);
7774 }
7775 return trustedHTMLFromString(html[0]);
7776}
7777/**
7778 * A template tag function for promoting the associated constant literal to a
7779 * TrustedScriptURL. Interpolation is explicitly not allowed.
7780 *
7781 * @param url constant template literal containing a trusted script URL.
7782 * @returns TrustedScriptURL wrapping `url`.
7783 *
7784 * @security This is a security-sensitive function and should only be used to
7785 * convert constant values of attributes and properties found in
7786 * application-provided Angular templates to TrustedScriptURL.
7787 *
7788 * @codeGenApi
7789 */
7790function ɵɵtrustConstantResourceUrl(url) {
7791 // The following runtime check ensures that the function was called as a
7792 // template tag (e.g. ɵɵtrustConstantResourceUrl`content`), without any
7793 // interpolation (e.g. not ɵɵtrustConstantResourceUrl`content ${variable}`). A
7794 // TemplateStringsArray is an array with a `raw` property that is also an
7795 // array. The associated template literal has no interpolation if and only if
7796 // the length of the TemplateStringsArray is 1.
7797 if (ngDevMode && (!Array.isArray(url) || !Array.isArray(url.raw) || url.length !== 1)) {
7798 throw new Error(`Unexpected interpolation in trusted URL constant: ${url.join('?')}`);
7799 }
7800 return trustedScriptURLFromString(url[0]);
7801}
7802/**
7803 * Detects which sanitizer to use for URL property, based on tag name and prop name.
7804 *
7805 * The rules are based on the RESOURCE_URL context config from
7806 * `packages/compiler/src/schema/dom_security_schema.ts`.
7807 * If tag and prop names don't match Resource URL schema, use URL sanitizer.
7808 */
7809function getUrlSanitizer(tag, prop) {
7810 if ((prop === 'src' &&
7811 (tag === 'embed' || tag === 'frame' || tag === 'iframe' || tag === 'media' ||
7812 tag === 'script')) ||
7813 (prop === 'href' && (tag === 'base' || tag === 'link'))) {
7814 return ɵɵsanitizeResourceUrl;
7815 }
7816 return ɵɵsanitizeUrl;
7817}
7818/**
7819 * Sanitizes URL, selecting sanitizer function based on tag and property names.
7820 *
7821 * This function is used in case we can't define security context at compile time, when only prop
7822 * name is available. This happens when we generate host bindings for Directives/Components. The
7823 * host element is unknown at compile time, so we defer calculation of specific sanitizer to
7824 * runtime.
7825 *
7826 * @param unsafeUrl untrusted `url`, typically from the user.
7827 * @param tag target element tag name.
7828 * @param prop name of the property that contains the value.
7829 * @returns `url` string which is safe to bind.
7830 *
7831 * @codeGenApi
7832 */
7833function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl, tag, prop) {
7834 return getUrlSanitizer(tag, prop)(unsafeUrl);
7835}
7836function validateAgainstEventProperties(name) {
7837 if (name.toLowerCase().startsWith('on')) {
7838 const errorMessage = `Binding to event property '${name}' is disallowed for security reasons, ` +
7839 `please use (${name.slice(2)})=...` +
7840 `\nIf '${name}' is a directive input, make sure the directive is imported by the` +
7841 ` current module.`;
7842 throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
7843 }
7844}
7845function validateAgainstEventAttributes(name) {
7846 if (name.toLowerCase().startsWith('on')) {
7847 const errorMessage = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
7848 `please use (${name.slice(2)})=...`;
7849 throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
7850 }
7851}
7852function getSanitizer() {
7853 const lView = getLView();
7854 return lView && lView[SANITIZER];
7855}
7856
7857/**
7858 * Creates a token that can be used in a DI Provider.
7859 *
7860 * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
7861 * runtime representation) such as when injecting an interface, callable type, array or
7862 * parameterized type.
7863 *
7864 * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
7865 * the `Injector`. This provides an additional level of type safety.
7866 *
7867 * ```
7868 * interface MyInterface {...}
7869 * const myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
7870 * // myInterface is inferred to be MyInterface.
7871 * ```
7872 *
7873 * When creating an `InjectionToken`, you can optionally specify a factory function which returns
7874 * (possibly by creating) a default value of the parameterized type `T`. This sets up the
7875 * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
7876 * application's root injector. If the factory function, which takes zero arguments, needs to inject
7877 * dependencies, it can do so using the `inject` function.
7878 * As you can see in the Tree-shakable InjectionToken example below.
7879 *
7880 * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
7881 * overrides the above behavior and marks the token as belonging to a particular `@NgModule` (note:
7882 * this option is now deprecated). As mentioned above, `'root'` is the default value for
7883 * `providedIn`.
7884 *
7885 * The `providedIn: NgModule` and `providedIn: 'any'` options are deprecated.
7886 *
7887 * @usageNotes
7888 * ### Basic Examples
7889 *
7890 * ### Plain InjectionToken
7891 *
7892 * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
7893 *
7894 * ### Tree-shakable InjectionToken
7895 *
7896 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
7897 *
7898 *
7899 * @publicApi
7900 */
7901class InjectionToken {
7902 /**
7903 * @param _desc Description for the token,
7904 * used only for debugging purposes,
7905 * it should but does not need to be unique
7906 * @param options Options for the token's usage, as described above
7907 */
7908 constructor(_desc, options) {
7909 this._desc = _desc;
7910 /** @internal */
7911 this.ngMetadataName = 'InjectionToken';
7912 this.ɵprov = undefined;
7913 if (typeof options == 'number') {
7914 (typeof ngDevMode === 'undefined' || ngDevMode) &&
7915 assertLessThan(options, 0, 'Only negative numbers are supported here');
7916 // This is a special hack to assign __NG_ELEMENT_ID__ to this instance.
7917 // See `InjectorMarkers`
7918 this.__NG_ELEMENT_ID__ = options;
7919 }
7920 else if (options !== undefined) {
7921 this.ɵprov = ɵɵdefineInjectable({
7922 token: this,
7923 providedIn: options.providedIn || 'root',
7924 factory: options.factory,
7925 });
7926 }
7927 }
7928 /**
7929 * @internal
7930 */
7931 get multi() {
7932 return this;
7933 }
7934 toString() {
7935 return `InjectionToken ${this._desc}`;
7936 }
7937}
7938
7939/**
7940 * A multi-provider token for initialization functions that will run upon construction of an
7941 * environment injector.
7942 *
7943 * @publicApi
7944 */
7945const ENVIRONMENT_INITIALIZER = new InjectionToken('ENVIRONMENT_INITIALIZER');
7946
7947/**
7948 * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors.
7949 *
7950 * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a
7951 * project.
7952 *
7953 * @publicApi
7954 */
7955const INJECTOR = new InjectionToken('INJECTOR',
7956// Disable tslint because this is const enum which gets inlined not top level prop access.
7957// tslint:disable-next-line: no-toplevel-property-access
7958-1 /* InjectorMarkers.Injector */);
7959
7960const INJECTOR_DEF_TYPES = new InjectionToken('INJECTOR_DEF_TYPES');
7961
7962class NullInjector {
7963 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
7964 if (notFoundValue === THROW_IF_NOT_FOUND) {
7965 const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`);
7966 error.name = 'NullInjectorError';
7967 throw error;
7968 }
7969 return notFoundValue;
7970 }
7971}
7972
7973/**
7974 * Wrap an array of `Provider`s into `EnvironmentProviders`, preventing them from being accidentally
7975 * referenced in `@Component in a component injector.
7976 */
7977function makeEnvironmentProviders(providers) {
7978 return {
7979 ɵproviders: providers,
7980 };
7981}
7982/**
7983 * Collects providers from all NgModules and standalone components, including transitively imported
7984 * ones.
7985 *
7986 * Providers extracted via `importProvidersFrom` are only usable in an application injector or
7987 * another environment injector (such as a route injector). They should not be used in component
7988 * providers.
7989 *
7990 * More information about standalone components can be found in [this
7991 * guide](guide/standalone-components).
7992 *
7993 * @usageNotes
7994 * The results of the `importProvidersFrom` call can be used in the `bootstrapApplication` call:
7995 *
7996 * ```typescript
7997 * await bootstrapApplication(RootComponent, {
7998 * providers: [
7999 * importProvidersFrom(NgModuleOne, NgModuleTwo)
8000 * ]
8001 * });
8002 * ```
8003 *
8004 * You can also use the `importProvidersFrom` results in the `providers` field of a route, when a
8005 * standalone component is used:
8006 *
8007 * ```typescript
8008 * export const ROUTES: Route[] = [
8009 * {
8010 * path: 'foo',
8011 * providers: [
8012 * importProvidersFrom(NgModuleOne, NgModuleTwo)
8013 * ],
8014 * component: YourStandaloneComponent
8015 * }
8016 * ];
8017 * ```
8018 *
8019 * @returns Collected providers from the specified list of types.
8020 * @publicApi
8021 */
8022function importProvidersFrom(...sources) {
8023 return {
8024 ɵproviders: internalImportProvidersFrom(true, sources),
8025 ɵfromNgModule: true,
8026 };
8027}
8028function internalImportProvidersFrom(checkForStandaloneCmp, ...sources) {
8029 const providersOut = [];
8030 const dedup = new Set(); // already seen types
8031 let injectorTypesWithProviders;
8032 deepForEach(sources, source => {
8033 if ((typeof ngDevMode === 'undefined' || ngDevMode) && checkForStandaloneCmp) {
8034 const cmpDef = getComponentDef$1(source);
8035 if (cmpDef === null || cmpDef === void 0 ? void 0 : cmpDef.standalone) {
8036 throw new RuntimeError(800 /* RuntimeErrorCode.IMPORT_PROVIDERS_FROM_STANDALONE */, `Importing providers supports NgModule or ModuleWithProviders but got a standalone component "${stringifyForError(source)}"`);
8037 }
8038 }
8039 // Narrow `source` to access the internal type analogue for `ModuleWithProviders`.
8040 const internalSource = source;
8041 if (walkProviderTree(internalSource, providersOut, [], dedup)) {
8042 injectorTypesWithProviders || (injectorTypesWithProviders = []);
8043 injectorTypesWithProviders.push(internalSource);
8044 }
8045 });
8046 // Collect all providers from `ModuleWithProviders` types.
8047 if (injectorTypesWithProviders !== undefined) {
8048 processInjectorTypesWithProviders(injectorTypesWithProviders, providersOut);
8049 }
8050 return providersOut;
8051}
8052/**
8053 * Collects all providers from the list of `ModuleWithProviders` and appends them to the provided
8054 * array.
8055 */
8056function processInjectorTypesWithProviders(typesWithProviders, providersOut) {
8057 for (let i = 0; i < typesWithProviders.length; i++) {
8058 const { ngModule, providers } = typesWithProviders[i];
8059 deepForEachProvider(providers, provider => {
8060 ngDevMode && validateProvider(provider, providers || EMPTY_ARRAY, ngModule);
8061 providersOut.push(provider);
8062 });
8063 }
8064}
8065/**
8066 * The logic visits an `InjectorType`, an `InjectorTypeWithProviders`, or a standalone
8067 * `ComponentType`, and all of its transitive providers and collects providers.
8068 *
8069 * If an `InjectorTypeWithProviders` that declares providers besides the type is specified,
8070 * the function will return "true" to indicate that the providers of the type definition need
8071 * to be processed. This allows us to process providers of injector types after all imports of
8072 * an injector definition are processed. (following View Engine semantics: see FW-1349)
8073 */
8074function walkProviderTree(container, providersOut, parents, dedup) {
8075 container = resolveForwardRef(container);
8076 if (!container)
8077 return false;
8078 // The actual type which had the definition. Usually `container`, but may be an unwrapped type
8079 // from `InjectorTypeWithProviders`.
8080 let defType = null;
8081 let injDef = getInjectorDef(container);
8082 const cmpDef = !injDef && getComponentDef$1(container);
8083 if (!injDef && !cmpDef) {
8084 // `container` is not an injector type or a component type. It might be:
8085 // * An `InjectorTypeWithProviders` that wraps an injector type.
8086 // * A standalone directive or pipe that got pulled in from a standalone component's
8087 // dependencies.
8088 // Try to unwrap it as an `InjectorTypeWithProviders` first.
8089 const ngModule = container.ngModule;
8090 injDef = getInjectorDef(ngModule);
8091 if (injDef) {
8092 defType = ngModule;
8093 }
8094 else {
8095 // Not a component or injector type, so ignore it.
8096 return false;
8097 }
8098 }
8099 else if (cmpDef && !cmpDef.standalone) {
8100 return false;
8101 }
8102 else {
8103 defType = container;
8104 }
8105 // Check for circular dependencies.
8106 if (ngDevMode && parents.indexOf(defType) !== -1) {
8107 const defName = stringify(defType);
8108 const path = parents.map(stringify);
8109 throwCyclicDependencyError(defName, path);
8110 }
8111 // Check for multiple imports of the same module
8112 const isDuplicate = dedup.has(defType);
8113 if (cmpDef) {
8114 if (isDuplicate) {
8115 // This component definition has already been processed.
8116 return false;
8117 }
8118 dedup.add(defType);
8119 if (cmpDef.dependencies) {
8120 const deps = typeof cmpDef.dependencies === 'function' ? cmpDef.dependencies() : cmpDef.dependencies;
8121 for (const dep of deps) {
8122 walkProviderTree(dep, providersOut, parents, dedup);
8123 }
8124 }
8125 }
8126 else if (injDef) {
8127 // First, include providers from any imports.
8128 if (injDef.imports != null && !isDuplicate) {
8129 // Before processing defType's imports, add it to the set of parents. This way, if it ends
8130 // up deeply importing itself, this can be detected.
8131 ngDevMode && parents.push(defType);
8132 // Add it to the set of dedups. This way we can detect multiple imports of the same module
8133 dedup.add(defType);
8134 let importTypesWithProviders;
8135 try {
8136 deepForEach(injDef.imports, imported => {
8137 if (walkProviderTree(imported, providersOut, parents, dedup)) {
8138 importTypesWithProviders || (importTypesWithProviders = []);
8139 // If the processed import is an injector type with providers, we store it in the
8140 // list of import types with providers, so that we can process those afterwards.
8141 importTypesWithProviders.push(imported);
8142 }
8143 });
8144 }
8145 finally {
8146 // Remove it from the parents set when finished.
8147 ngDevMode && parents.pop();
8148 }
8149 // Imports which are declared with providers (TypeWithProviders) need to be processed
8150 // after all imported modules are processed. This is similar to how View Engine
8151 // processes/merges module imports in the metadata resolver. See: FW-1349.
8152 if (importTypesWithProviders !== undefined) {
8153 processInjectorTypesWithProviders(importTypesWithProviders, providersOut);
8154 }
8155 }
8156 if (!isDuplicate) {
8157 // Track the InjectorType and add a provider for it.
8158 // It's important that this is done after the def's imports.
8159 const factory = getFactoryDef(defType) || (() => new defType());
8160 // Append extra providers to make more info available for consumers (to retrieve an injector
8161 // type), as well as internally (to calculate an injection scope correctly and eagerly
8162 // instantiate a `defType` when an injector is created).
8163 providersOut.push(
8164 // Provider to create `defType` using its factory.
8165 { provide: defType, useFactory: factory, deps: EMPTY_ARRAY },
8166 // Make this `defType` available to an internal logic that calculates injector scope.
8167 { provide: INJECTOR_DEF_TYPES, useValue: defType, multi: true },
8168 // Provider to eagerly instantiate `defType` via `ENVIRONMENT_INITIALIZER`.
8169 { provide: ENVIRONMENT_INITIALIZER, useValue: () => ɵɵinject(defType), multi: true } //
8170 );
8171 }
8172 // Next, include providers listed on the definition itself.
8173 const defProviders = injDef.providers;
8174 if (defProviders != null && !isDuplicate) {
8175 const injectorType = container;
8176 deepForEachProvider(defProviders, provider => {
8177 ngDevMode && validateProvider(provider, defProviders, injectorType);
8178 providersOut.push(provider);
8179 });
8180 }
8181 }
8182 else {
8183 // Should not happen, but just in case.
8184 return false;
8185 }
8186 return (defType !== container &&
8187 container.providers !== undefined);
8188}
8189function validateProvider(provider, providers, containerType) {
8190 if (isTypeProvider(provider) || isValueProvider(provider) || isFactoryProvider(provider) ||
8191 isExistingProvider(provider)) {
8192 return;
8193 }
8194 // Here we expect the provider to be a `useClass` provider (by elimination).
8195 const classRef = resolveForwardRef(provider && (provider.useClass || provider.provide));
8196 if (!classRef) {
8197 throwInvalidProviderError(containerType, providers, provider);
8198 }
8199}
8200function deepForEachProvider(providers, fn) {
8201 for (let provider of providers) {
8202 if (isEnvironmentProviders(provider)) {
8203 provider = provider.ɵproviders;
8204 }
8205 if (Array.isArray(provider)) {
8206 deepForEachProvider(provider, fn);
8207 }
8208 else {
8209 fn(provider);
8210 }
8211 }
8212}
8213const USE_VALUE$1 = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
8214function isValueProvider(value) {
8215 return value !== null && typeof value == 'object' && USE_VALUE$1 in value;
8216}
8217function isExistingProvider(value) {
8218 return !!(value && value.useExisting);
8219}
8220function isFactoryProvider(value) {
8221 return !!(value && value.useFactory);
8222}
8223function isTypeProvider(value) {
8224 return typeof value === 'function';
8225}
8226function isClassProvider(value) {
8227 return !!value.useClass;
8228}
8229
8230/**
8231 * An internal token whose presence in an injector indicates that the injector should treat itself
8232 * as a root scoped injector when processing requests for unknown tokens which may indicate
8233 * they are provided in the root scope.
8234 */
8235const INJECTOR_SCOPE = new InjectionToken('Set Injector scope.');
8236
8237/**
8238 * Marker which indicates that a value has not yet been created from the factory function.
8239 */
8240const NOT_YET = {};
8241/**
8242 * Marker which indicates that the factory function for a token is in the process of being called.
8243 *
8244 * If the injector is asked to inject a token with its value set to CIRCULAR, that indicates
8245 * injection of a dependency has recursively attempted to inject the original token, and there is
8246 * a circular dependency among the providers.
8247 */
8248const CIRCULAR = {};
8249/**
8250 * A lazily initialized NullInjector.
8251 */
8252let NULL_INJECTOR$1 = undefined;
8253function getNullInjector() {
8254 if (NULL_INJECTOR$1 === undefined) {
8255 NULL_INJECTOR$1 = new NullInjector();
8256 }
8257 return NULL_INJECTOR$1;
8258}
8259/**
8260 * An `Injector` that's part of the environment injector hierarchy, which exists outside of the
8261 * component tree.
8262 */
8263class EnvironmentInjector {
8264}
8265class R3Injector extends EnvironmentInjector {
8266 /**
8267 * Flag indicating that this injector was previously destroyed.
8268 */
8269 get destroyed() {
8270 return this._destroyed;
8271 }
8272 constructor(providers, parent, source, scopes) {
8273 super();
8274 this.parent = parent;
8275 this.source = source;
8276 this.scopes = scopes;
8277 /**
8278 * Map of tokens to records which contain the instances of those tokens.
8279 * - `null` value implies that we don't have the record. Used by tree-shakable injectors
8280 * to prevent further searches.
8281 */
8282 this.records = new Map();
8283 /**
8284 * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks.
8285 */
8286 this._ngOnDestroyHooks = new Set();
8287 this._onDestroyHooks = [];
8288 this._destroyed = false;
8289 // Start off by creating Records for every provider.
8290 forEachSingleProvider(providers, provider => this.processProvider(provider));
8291 // Make sure the INJECTOR token provides this injector.
8292 this.records.set(INJECTOR, makeRecord(undefined, this));
8293 // And `EnvironmentInjector` if the current injector is supposed to be env-scoped.
8294 if (scopes.has('environment')) {
8295 this.records.set(EnvironmentInjector, makeRecord(undefined, this));
8296 }
8297 // Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide
8298 // any injectable scoped to APP_ROOT_SCOPE.
8299 const record = this.records.get(INJECTOR_SCOPE);
8300 if (record != null && typeof record.value === 'string') {
8301 this.scopes.add(record.value);
8302 }
8303 this.injectorDefTypes =
8304 new Set(this.get(INJECTOR_DEF_TYPES.multi, EMPTY_ARRAY, InjectFlags.Self));
8305 }
8306 /**
8307 * Destroy the injector and release references to every instance or provider associated with it.
8308 *
8309 * Also calls the `OnDestroy` lifecycle hooks of every instance that was created for which a
8310 * hook was found.
8311 */
8312 destroy() {
8313 this.assertNotDestroyed();
8314 // Set destroyed = true first, in case lifecycle hooks re-enter destroy().
8315 this._destroyed = true;
8316 try {
8317 // Call all the lifecycle hooks.
8318 for (const service of this._ngOnDestroyHooks) {
8319 service.ngOnDestroy();
8320 }
8321 for (const hook of this._onDestroyHooks) {
8322 hook();
8323 }
8324 }
8325 finally {
8326 // Release all references.
8327 this.records.clear();
8328 this._ngOnDestroyHooks.clear();
8329 this.injectorDefTypes.clear();
8330 this._onDestroyHooks.length = 0;
8331 }
8332 }
8333 onDestroy(callback) {
8334 this._onDestroyHooks.push(callback);
8335 }
8336 runInContext(fn) {
8337 this.assertNotDestroyed();
8338 const previousInjector = setCurrentInjector(this);
8339 const previousInjectImplementation = setInjectImplementation(undefined);
8340 try {
8341 return fn();
8342 }
8343 finally {
8344 setCurrentInjector(previousInjector);
8345 setInjectImplementation(previousInjectImplementation);
8346 }
8347 }
8348 get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
8349 this.assertNotDestroyed();
8350 flags = convertToBitFlags(flags);
8351 // Set the injection context.
8352 const previousInjector = setCurrentInjector(this);
8353 const previousInjectImplementation = setInjectImplementation(undefined);
8354 try {
8355 // Check for the SkipSelf flag.
8356 if (!(flags & InjectFlags.SkipSelf)) {
8357 // SkipSelf isn't set, check if the record belongs to this injector.
8358 let record = this.records.get(token);
8359 if (record === undefined) {
8360 // No record, but maybe the token is scoped to this injector. Look for an injectable
8361 // def with a scope matching this injector.
8362 const def = couldBeInjectableType(token) && getInjectableDef(token);
8363 if (def && this.injectableDefInScope(def)) {
8364 // Found an injectable def and it's scoped to this injector. Pretend as if it was here
8365 // all along.
8366 record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET);
8367 }
8368 else {
8369 record = null;
8370 }
8371 this.records.set(token, record);
8372 }
8373 // If a record was found, get the instance for it and return it.
8374 if (record != null /* NOT null || undefined */) {
8375 return this.hydrate(token, record);
8376 }
8377 }
8378 // Select the next injector based on the Self flag - if self is set, the next injector is
8379 // the NullInjector, otherwise it's the parent.
8380 const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector();
8381 // Set the notFoundValue based on the Optional flag - if optional is set and notFoundValue
8382 // is undefined, the value is null, otherwise it's the notFoundValue.
8383 notFoundValue = (flags & InjectFlags.Optional) && notFoundValue === THROW_IF_NOT_FOUND ?
8384 null :
8385 notFoundValue;
8386 return nextInjector.get(token, notFoundValue);
8387 }
8388 catch (e) {
8389 if (e.name === 'NullInjectorError') {
8390 const path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || [];
8391 path.unshift(stringify(token));
8392 if (previousInjector) {
8393 // We still have a parent injector, keep throwing
8394 throw e;
8395 }
8396 else {
8397 // Format & throw the final error message when we don't have any previous injector
8398 return catchInjectorError(e, token, 'R3InjectorError', this.source);
8399 }
8400 }
8401 else {
8402 throw e;
8403 }
8404 }
8405 finally {
8406 // Lastly, restore the previous injection context.
8407 setInjectImplementation(previousInjectImplementation);
8408 setCurrentInjector(previousInjector);
8409 }
8410 }
8411 /** @internal */
8412 resolveInjectorInitializers() {
8413 const previousInjector = setCurrentInjector(this);
8414 const previousInjectImplementation = setInjectImplementation(undefined);
8415 try {
8416 const initializers = this.get(ENVIRONMENT_INITIALIZER.multi, EMPTY_ARRAY, InjectFlags.Self);
8417 if (ngDevMode && !Array.isArray(initializers)) {
8418 throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `ENVIRONMENT_INITIALIZER` token value ' +
8419 `(expected an array, but got ${typeof initializers}). ` +
8420 'Please check that the `ENVIRONMENT_INITIALIZER` token is configured as a ' +
8421 '`multi: true` provider.');
8422 }
8423 for (const initializer of initializers) {
8424 initializer();
8425 }
8426 }
8427 finally {
8428 setCurrentInjector(previousInjector);
8429 setInjectImplementation(previousInjectImplementation);
8430 }
8431 }
8432 toString() {
8433 const tokens = [];
8434 const records = this.records;
8435 for (const token of records.keys()) {
8436 tokens.push(stringify(token));
8437 }
8438 return `R3Injector[${tokens.join(', ')}]`;
8439 }
8440 assertNotDestroyed() {
8441 if (this._destroyed) {
8442 throw new RuntimeError(205 /* RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED */, ngDevMode && 'Injector has already been destroyed.');
8443 }
8444 }
8445 /**
8446 * Process a `SingleProvider` and add it.
8447 */
8448 processProvider(provider) {
8449 // Determine the token from the provider. Either it's its own token, or has a {provide: ...}
8450 // property.
8451 provider = resolveForwardRef(provider);
8452 let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider && provider.provide);
8453 // Construct a `Record` for the provider.
8454 const record = providerToRecord(provider);
8455 if (!isTypeProvider(provider) && provider.multi === true) {
8456 // If the provider indicates that it's a multi-provider, process it specially.
8457 // First check whether it's been defined already.
8458 let multiRecord = this.records.get(token);
8459 if (multiRecord) {
8460 // It has. Throw a nice error if
8461 if (ngDevMode && multiRecord.multi === undefined) {
8462 throwMixedMultiProviderError();
8463 }
8464 }
8465 else {
8466 multiRecord = makeRecord(undefined, NOT_YET, true);
8467 multiRecord.factory = () => injectArgs(multiRecord.multi);
8468 this.records.set(token, multiRecord);
8469 }
8470 token = provider;
8471 multiRecord.multi.push(provider);
8472 }
8473 else {
8474 const existing = this.records.get(token);
8475 if (ngDevMode && existing && existing.multi !== undefined) {
8476 throwMixedMultiProviderError();
8477 }
8478 }
8479 this.records.set(token, record);
8480 }
8481 hydrate(token, record) {
8482 if (ngDevMode && record.value === CIRCULAR) {
8483 throwCyclicDependencyError(stringify(token));
8484 }
8485 else if (record.value === NOT_YET) {
8486 record.value = CIRCULAR;
8487 record.value = record.factory();
8488 }
8489 if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) {
8490 this._ngOnDestroyHooks.add(record.value);
8491 }
8492 return record.value;
8493 }
8494 injectableDefInScope(def) {
8495 if (!def.providedIn) {
8496 return false;
8497 }
8498 const providedIn = resolveForwardRef(def.providedIn);
8499 if (typeof providedIn === 'string') {
8500 return providedIn === 'any' || (this.scopes.has(providedIn));
8501 }
8502 else {
8503 return this.injectorDefTypes.has(providedIn);
8504 }
8505 }
8506}
8507function injectableDefOrInjectorDefFactory(token) {
8508 // Most tokens will have an injectable def directly on them, which specifies a factory directly.
8509 const injectableDef = getInjectableDef(token);
8510 const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token);
8511 if (factory !== null) {
8512 return factory;
8513 }
8514 // InjectionTokens should have an injectable def (ɵprov) and thus should be handled above.
8515 // If it's missing that, it's an error.
8516 if (token instanceof InjectionToken) {
8517 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Token ${stringify(token)} is missing a ɵprov definition.`);
8518 }
8519 // Undecorated types can sometimes be created if they have no constructor arguments.
8520 if (token instanceof Function) {
8521 return getUndecoratedInjectableFactory(token);
8522 }
8523 // There was no way to resolve a factory for this token.
8524 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && 'unreachable');
8525}
8526function getUndecoratedInjectableFactory(token) {
8527 // If the token has parameters then it has dependencies that we cannot resolve implicitly.
8528 const paramLength = token.length;
8529 if (paramLength > 0) {
8530 const args = newArray(paramLength, '?');
8531 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Can't resolve all parameters for ${stringify(token)}: (${args.join(', ')}).`);
8532 }
8533 // The constructor function appears to have no parameters.
8534 // This might be because it inherits from a super-class. In which case, use an injectable
8535 // def from an ancestor if there is one.
8536 // Otherwise this really is a simple class with no dependencies, so return a factory that
8537 // just instantiates the zero-arg constructor.
8538 const inheritedInjectableDef = getInheritedInjectableDef(token);
8539 if (inheritedInjectableDef !== null) {
8540 return () => inheritedInjectableDef.factory(token);
8541 }
8542 else {
8543 return () => new token();
8544 }
8545}
8546function providerToRecord(provider) {
8547 if (isValueProvider(provider)) {
8548 return makeRecord(undefined, provider.useValue);
8549 }
8550 else {
8551 const factory = providerToFactory(provider);
8552 return makeRecord(factory, NOT_YET);
8553 }
8554}
8555/**
8556 * Converts a `SingleProvider` into a factory function.
8557 *
8558 * @param provider provider to convert to factory
8559 */
8560function providerToFactory(provider, ngModuleType, providers) {
8561 let factory = undefined;
8562 if (ngDevMode && isEnvironmentProviders(provider)) {
8563 throwInvalidProviderError(undefined, providers, provider);
8564 }
8565 if (isTypeProvider(provider)) {
8566 const unwrappedProvider = resolveForwardRef(provider);
8567 return getFactoryDef(unwrappedProvider) || injectableDefOrInjectorDefFactory(unwrappedProvider);
8568 }
8569 else {
8570 if (isValueProvider(provider)) {
8571 factory = () => resolveForwardRef(provider.useValue);
8572 }
8573 else if (isFactoryProvider(provider)) {
8574 factory = () => provider.useFactory(...injectArgs(provider.deps || []));
8575 }
8576 else if (isExistingProvider(provider)) {
8577 factory = () => ɵɵinject(resolveForwardRef(provider.useExisting));
8578 }
8579 else {
8580 const classRef = resolveForwardRef(provider &&
8581 (provider.useClass || provider.provide));
8582 if (ngDevMode && !classRef) {
8583 throwInvalidProviderError(ngModuleType, providers, provider);
8584 }
8585 if (hasDeps(provider)) {
8586 factory = () => new (classRef)(...injectArgs(provider.deps));
8587 }
8588 else {
8589 return getFactoryDef(classRef) || injectableDefOrInjectorDefFactory(classRef);
8590 }
8591 }
8592 }
8593 return factory;
8594}
8595function makeRecord(factory, value, multi = false) {
8596 return {
8597 factory: factory,
8598 value: value,
8599 multi: multi ? [] : undefined,
8600 };
8601}
8602function hasDeps(value) {
8603 return !!value.deps;
8604}
8605function hasOnDestroy(value) {
8606 return value !== null && typeof value === 'object' &&
8607 typeof value.ngOnDestroy === 'function';
8608}
8609function couldBeInjectableType(value) {
8610 return (typeof value === 'function') ||
8611 (typeof value === 'object' && value instanceof InjectionToken);
8612}
8613function forEachSingleProvider(providers, fn) {
8614 for (const provider of providers) {
8615 if (Array.isArray(provider)) {
8616 forEachSingleProvider(provider, fn);
8617 }
8618 else if (provider && isEnvironmentProviders(provider)) {
8619 forEachSingleProvider(provider.ɵproviders, fn);
8620 }
8621 else {
8622 fn(provider);
8623 }
8624 }
8625}
8626
8627/**
8628 * Represents a component created by a `ComponentFactory`.
8629 * Provides access to the component instance and related objects,
8630 * and provides the means of destroying the instance.
8631 *
8632 * @publicApi
8633 */
8634class ComponentRef$1 {
8635}
8636/**
8637 * Base class for a factory that can create a component dynamically.
8638 * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
8639 * Use the resulting `ComponentFactory.create()` method to create a component of that type.
8640 *
8641 * @see [Dynamic Components](guide/dynamic-component-loader)
8642 *
8643 * @publicApi
8644 *
8645 * @deprecated Angular no longer requires Component factories. Please use other APIs where
8646 * Component class can be used directly.
8647 */
8648class ComponentFactory$1 {
8649}
8650
8651function noComponentFactoryError(component) {
8652 const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
8653 error[ERROR_COMPONENT] = component;
8654 return error;
8655}
8656const ERROR_COMPONENT = 'ngComponent';
8657function getComponent$1(error) {
8658 return error[ERROR_COMPONENT];
8659}
8660class _NullComponentFactoryResolver {
8661 resolveComponentFactory(component) {
8662 throw noComponentFactoryError(component);
8663 }
8664}
8665/**
8666 * A simple registry that maps `Components` to generated `ComponentFactory` classes
8667 * that can be used to create instances of components.
8668 * Use to obtain the factory for a given component type,
8669 * then use the factory's `create()` method to create a component of that type.
8670 *
8671 * Note: since v13, dynamic component creation via
8672 * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
8673 * does **not** require resolving component factory: component class can be used directly.
8674 *
8675 * @publicApi
8676 *
8677 * @deprecated Angular no longer requires Component factories. Please use other APIs where
8678 * Component class can be used directly.
8679 */
8680class ComponentFactoryResolver$1 {
8681}
8682ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
8683
8684/**
8685 * Creates an ElementRef from the most recent node.
8686 *
8687 * @returns The ElementRef instance to use
8688 */
8689function injectElementRef() {
8690 return createElementRef(getCurrentTNode(), getLView());
8691}
8692/**
8693 * Creates an ElementRef given a node.
8694 *
8695 * @param tNode The node for which you'd like an ElementRef
8696 * @param lView The view to which the node belongs
8697 * @returns The ElementRef instance to use
8698 */
8699function createElementRef(tNode, lView) {
8700 return new ElementRef(getNativeByTNode(tNode, lView));
8701}
8702/**
8703 * A wrapper around a native element inside of a View.
8704 *
8705 * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
8706 * element.
8707 *
8708 * @security Permitting direct access to the DOM can make your application more vulnerable to
8709 * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
8710 * [Security Guide](https://g.co/ng/security).
8711 *
8712 * @publicApi
8713 */
8714// Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
8715// i.e. users have to ask for what they need. With that, we can build better analysis tools
8716// and could do better codegen in the future.
8717class ElementRef {
8718 constructor(nativeElement) {
8719 this.nativeElement = nativeElement;
8720 }
8721}
8722/**
8723 * @internal
8724 * @nocollapse
8725 */
8726ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
8727/**
8728 * Unwraps `ElementRef` and return the `nativeElement`.
8729 *
8730 * @param value value to unwrap
8731 * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
8732 */
8733function unwrapElementRef(value) {
8734 return value instanceof ElementRef ? value.nativeElement : value;
8735}
8736
8737/**
8738 * Creates and initializes a custom renderer that implements the `Renderer2` base class.
8739 *
8740 * @publicApi
8741 */
8742class RendererFactory2 {
8743}
8744/**
8745 * Extend this base class to implement custom rendering. By default, Angular
8746 * renders a template into DOM. You can use custom rendering to intercept
8747 * rendering calls, or to render to something other than DOM.
8748 *
8749 * Create your custom renderer using `RendererFactory2`.
8750 *
8751 * Use a custom renderer to bypass Angular's templating and
8752 * make custom UI changes that can't be expressed declaratively.
8753 * For example if you need to set a property or an attribute whose name is
8754 * not statically known, use the `setProperty()` or
8755 * `setAttribute()` method.
8756 *
8757 * @publicApi
8758 */
8759class Renderer2 {
8760}
8761/**
8762 * @internal
8763 * @nocollapse
8764 */
8765Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
8766/** Injects a Renderer2 for the current component. */
8767function injectRenderer2() {
8768 // We need the Renderer to be based on the component that it's being injected into, however since
8769 // DI happens before we've entered its view, `getLView` will return the parent view instead.
8770 const lView = getLView();
8771 const tNode = getCurrentTNode();
8772 const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
8773 return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
8774}
8775
8776/**
8777 * Sanitizer is used by the views to sanitize potentially dangerous values.
8778 *
8779 * @publicApi
8780 */
8781class Sanitizer {
8782}
8783/** @nocollapse */
8784Sanitizer.ɵprov = ɵɵdefineInjectable({
8785 token: Sanitizer,
8786 providedIn: 'root',
8787 factory: () => null,
8788});
8789
8790/**
8791 * @description Represents the version of Angular
8792 *
8793 * @publicApi
8794 */
8795class Version {
8796 constructor(full) {
8797 this.full = full;
8798 this.major = full.split('.')[0];
8799 this.minor = full.split('.')[1];
8800 this.patch = full.split('.').slice(2).join('.');
8801 }
8802}
8803/**
8804 * @publicApi
8805 */
8806const VERSION = new Version('15.1.5');
8807
8808// This default value is when checking the hierarchy for a token.
8809//
8810// It means both:
8811// - the token is not provided by the current injector,
8812// - only the element injectors should be checked (ie do not check module injectors
8813//
8814// mod1
8815// /
8816// el1 mod2
8817// \ /
8818// el2
8819//
8820// When requesting el2.injector.get(token), we should check in the following order and return the
8821// first found value:
8822// - el2.injector.get(token, default)
8823// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
8824// - mod2.injector.get(token, default)
8825const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
8826
8827const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
8828function wrappedError(message, originalError) {
8829 const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
8830 const error = Error(msg);
8831 error[ERROR_ORIGINAL_ERROR] = originalError;
8832 return error;
8833}
8834function getOriginalError(error) {
8835 return error[ERROR_ORIGINAL_ERROR];
8836}
8837
8838/**
8839 * Provides a hook for centralized exception handling.
8840 *
8841 * The default implementation of `ErrorHandler` prints error messages to the `console`. To
8842 * intercept error handling, write a custom exception handler that replaces this default as
8843 * appropriate for your app.
8844 *
8845 * @usageNotes
8846 * ### Example
8847 *
8848 * ```
8849 * class MyErrorHandler implements ErrorHandler {
8850 * handleError(error) {
8851 * // do something with the exception
8852 * }
8853 * }
8854 *
8855 * @NgModule({
8856 * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
8857 * })
8858 * class MyModule {}
8859 * ```
8860 *
8861 * @publicApi
8862 */
8863class ErrorHandler {
8864 constructor() {
8865 /**
8866 * @internal
8867 */
8868 this._console = console;
8869 }
8870 handleError(error) {
8871 const originalError = this._findOriginalError(error);
8872 this._console.error('ERROR', error);
8873 if (originalError) {
8874 this._console.error('ORIGINAL ERROR', originalError);
8875 }
8876 }
8877 /** @internal */
8878 _findOriginalError(error) {
8879 let e = error && getOriginalError(error);
8880 while (e && getOriginalError(e)) {
8881 e = getOriginalError(e);
8882 }
8883 return e || null;
8884 }
8885}
8886
8887function normalizeDebugBindingName(name) {
8888 // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
8889 name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
8890 return `ng-reflect-${name}`;
8891}
8892const CAMEL_CASE_REGEXP = /([A-Z])/g;
8893function camelCaseToDashCase(input) {
8894 return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
8895}
8896function normalizeDebugBindingValue(value) {
8897 try {
8898 // Limit the size of the value as otherwise the DOM just gets polluted.
8899 return value != null ? value.toString().slice(0, 30) : value;
8900 }
8901 catch (e) {
8902 return '[ERROR] Exception while trying to serialize the value';
8903 }
8904}
8905
8906/** Verifies that a given type is a Standalone Component. */
8907function assertStandaloneComponentType(type) {
8908 assertComponentDef(type);
8909 const componentDef = getComponentDef$1(type);
8910 if (!componentDef.standalone) {
8911 throw new RuntimeError(907 /* RuntimeErrorCode.TYPE_IS_NOT_STANDALONE */, `The ${stringifyForError(type)} component is not marked as standalone, ` +
8912 `but Angular expects to have a standalone component here. ` +
8913 `Please make sure the ${stringifyForError(type)} component has ` +
8914 `the \`standalone: true\` flag in the decorator.`);
8915 }
8916}
8917/** Verifies whether a given type is a component */
8918function assertComponentDef(type) {
8919 if (!getComponentDef$1(type)) {
8920 throw new RuntimeError(906 /* RuntimeErrorCode.MISSING_GENERATED_DEF */, `The ${stringifyForError(type)} is not an Angular component, ` +
8921 `make sure it has the \`@Component\` decorator.`);
8922 }
8923}
8924/** Called when there are multiple component selectors that match a given node */
8925function throwMultipleComponentError(tNode, first, second) {
8926 throw new RuntimeError(-300 /* RuntimeErrorCode.MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
8927 `${stringifyForError(first)} and ` +
8928 `${stringifyForError(second)}`);
8929}
8930/** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
8931function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
8932 const field = propName ? ` for '${propName}'` : '';
8933 let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
8934 if (creationMode) {
8935 msg +=
8936 ` It seems like the view has been created after its parent and its children have been dirty checked.` +
8937 ` Has it been created in a change detection hook?`;
8938 }
8939 throw new RuntimeError(-100 /* RuntimeErrorCode.EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
8940}
8941function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
8942 const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
8943 let oldValue = prefix, newValue = prefix;
8944 for (let i = 0; i < chunks.length; i++) {
8945 const slotIdx = rootIndex + i;
8946 oldValue += `${lView[slotIdx]}${chunks[i]}`;
8947 newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
8948 }
8949 return { propName, oldValue, newValue };
8950}
8951/**
8952 * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
8953 * - property name (for property bindings or interpolations)
8954 * - old and new values, enriched using information from metadata
8955 *
8956 * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
8957 * function description.
8958 */
8959function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
8960 const tData = lView[TVIEW].data;
8961 const metadata = tData[bindingIndex];
8962 if (typeof metadata === 'string') {
8963 // metadata for property interpolation
8964 if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
8965 return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
8966 }
8967 // metadata for property binding
8968 return { propName: metadata, oldValue, newValue };
8969 }
8970 // metadata is not available for this expression, check if this expression is a part of the
8971 // property interpolation by going from the current binding index left and look for a string that
8972 // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
8973 // [..., 'id�Prefix � and � suffix', null, null, null, ...]
8974 if (metadata === null) {
8975 let idx = bindingIndex - 1;
8976 while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
8977 idx--;
8978 }
8979 const meta = tData[idx];
8980 if (typeof meta === 'string') {
8981 const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
8982 // first interpolation delimiter separates property name from interpolation parts (in case of
8983 // property interpolations), so we subtract one from total number of found delimiters
8984 if (matches && (matches.length - 1) > bindingIndex - idx) {
8985 return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
8986 }
8987 }
8988 }
8989 return { propName: undefined, oldValue, newValue };
8990}
8991
8992/**
8993 * Returns an index of `classToSearch` in `className` taking token boundaries into account.
8994 *
8995 * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
8996 *
8997 * @param className A string containing classes (whitespace separated)
8998 * @param classToSearch A class name to locate
8999 * @param startingIndex Starting location of search
9000 * @returns an index of the located class (or -1 if not found)
9001 */
9002function classIndexOf(className, classToSearch, startingIndex) {
9003 ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
9004 let end = className.length;
9005 while (true) {
9006 const foundIndex = className.indexOf(classToSearch, startingIndex);
9007 if (foundIndex === -1)
9008 return foundIndex;
9009 if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* CharCode.SPACE */) {
9010 // Ensure that it has leading whitespace
9011 const length = classToSearch.length;
9012 if (foundIndex + length === end ||
9013 className.charCodeAt(foundIndex + length) <= 32 /* CharCode.SPACE */) {
9014 // Ensure that it has trailing whitespace
9015 return foundIndex;
9016 }
9017 }
9018 // False positive, keep searching from where we left off.
9019 startingIndex = foundIndex + 1;
9020 }
9021}
9022
9023const NG_TEMPLATE_SELECTOR = 'ng-template';
9024/**
9025 * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
9026 *
9027 * @param attrs `TAttributes` to search through.
9028 * @param cssClassToMatch class to match (lowercase)
9029 * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
9030 * addition to the `AttributeMarker.Classes`.
9031 */
9032function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
9033 // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
9034 // It is strange to me that sometimes the class information comes in form of `class` attribute
9035 // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
9036 // if that is the right behavior.
9037 ngDevMode &&
9038 assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
9039 let i = 0;
9040 while (i < attrs.length) {
9041 let item = attrs[i++];
9042 if (isProjectionMode && item === 'class') {
9043 item = attrs[i];
9044 if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
9045 return true;
9046 }
9047 }
9048 else if (item === 1 /* AttributeMarker.Classes */) {
9049 // We found the classes section. Start searching for the class.
9050 while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
9051 // while we have strings
9052 if (item.toLowerCase() === cssClassToMatch)
9053 return true;
9054 }
9055 return false;
9056 }
9057 }
9058 return false;
9059}
9060/**
9061 * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
9062 *
9063 * @param tNode current TNode
9064 */
9065function isInlineTemplate(tNode) {
9066 return tNode.type === 4 /* TNodeType.Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
9067}
9068/**
9069 * Function that checks whether a given tNode matches tag-based selector and has a valid type.
9070 *
9071 * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
9072 * directive matching mode:
9073 * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
9074 * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
9075 * tag name was extracted from * syntax so we would match the same directive twice);
9076 * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
9077 * (applicable to TNodeType.Container only).
9078 */
9079function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
9080 const tagNameToCompare = tNode.type === 4 /* TNodeType.Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
9081 return currentSelector === tagNameToCompare;
9082}
9083/**
9084 * A utility function to match an Ivy node static data against a simple CSS selector
9085 *
9086 * @param node static data of the node to match
9087 * @param selector The selector to try matching against the node.
9088 * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
9089 * directive matching.
9090 * @returns true if node matches the selector.
9091 */
9092function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
9093 ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
9094 let mode = 4 /* SelectorFlags.ELEMENT */;
9095 const nodeAttrs = tNode.attrs || [];
9096 // Find the index of first attribute that has no value, only a name.
9097 const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
9098 // When processing ":not" selectors, we skip to the next ":not" if the
9099 // current one doesn't match
9100 let skipToNextSelector = false;
9101 for (let i = 0; i < selector.length; i++) {
9102 const current = selector[i];
9103 if (typeof current === 'number') {
9104 // If we finish processing a :not selector and it hasn't failed, return false
9105 if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
9106 return false;
9107 }
9108 // If we are skipping to the next :not() and this mode flag is positive,
9109 // it's a part of the current :not() selector, and we should keep skipping
9110 if (skipToNextSelector && isPositive(current))
9111 continue;
9112 skipToNextSelector = false;
9113 mode = current | (mode & 1 /* SelectorFlags.NOT */);
9114 continue;
9115 }
9116 if (skipToNextSelector)
9117 continue;
9118 if (mode & 4 /* SelectorFlags.ELEMENT */) {
9119 mode = 2 /* SelectorFlags.ATTRIBUTE */ | mode & 1 /* SelectorFlags.NOT */;
9120 if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
9121 current === '' && selector.length === 1) {
9122 if (isPositive(mode))
9123 return false;
9124 skipToNextSelector = true;
9125 }
9126 }
9127 else {
9128 const selectorAttrValue = mode & 8 /* SelectorFlags.CLASS */ ? current : selector[++i];
9129 // special case for matching against classes when a tNode has been instantiated with
9130 // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
9131 if ((mode & 8 /* SelectorFlags.CLASS */) && tNode.attrs !== null) {
9132 if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
9133 if (isPositive(mode))
9134 return false;
9135 skipToNextSelector = true;
9136 }
9137 continue;
9138 }
9139 const attrName = (mode & 8 /* SelectorFlags.CLASS */) ? 'class' : current;
9140 const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
9141 if (attrIndexInNode === -1) {
9142 if (isPositive(mode))
9143 return false;
9144 skipToNextSelector = true;
9145 continue;
9146 }
9147 if (selectorAttrValue !== '') {
9148 let nodeAttrValue;
9149 if (attrIndexInNode > nameOnlyMarkerIdx) {
9150 nodeAttrValue = '';
9151 }
9152 else {
9153 ngDevMode &&
9154 assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* AttributeMarker.NamespaceURI */, 'We do not match directives on namespaced attributes');
9155 // we lowercase the attribute value to be able to match
9156 // selectors without case-sensitivity
9157 // (selectors are already in lowercase when generated)
9158 nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
9159 }
9160 const compareAgainstClassName = mode & 8 /* SelectorFlags.CLASS */ ? nodeAttrValue : null;
9161 if (compareAgainstClassName &&
9162 classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
9163 mode & 2 /* SelectorFlags.ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
9164 if (isPositive(mode))
9165 return false;
9166 skipToNextSelector = true;
9167 }
9168 }
9169 }
9170 }
9171 return isPositive(mode) || skipToNextSelector;
9172}
9173function isPositive(mode) {
9174 return (mode & 1 /* SelectorFlags.NOT */) === 0;
9175}
9176/**
9177 * Examines the attribute's definition array for a node to find the index of the
9178 * attribute that matches the given `name`.
9179 *
9180 * NOTE: This will not match namespaced attributes.
9181 *
9182 * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
9183 * The following table summarizes which types of attributes we attempt to match:
9184 *
9185 * ===========================================================================================================
9186 * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
9187 * Attributes
9188 * ===========================================================================================================
9189 * Inline + Projection | YES | YES | NO | YES
9190 * -----------------------------------------------------------------------------------------------------------
9191 * Inline + Directive | NO | NO | YES | NO
9192 * -----------------------------------------------------------------------------------------------------------
9193 * Non-inline + Projection | YES | YES | NO | YES
9194 * -----------------------------------------------------------------------------------------------------------
9195 * Non-inline + Directive | YES | YES | NO | YES
9196 * ===========================================================================================================
9197 *
9198 * @param name the name of the attribute to find
9199 * @param attrs the attribute array to examine
9200 * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
9201 * rather than a manually expanded template node (e.g `<ng-template>`).
9202 * @param isProjectionMode true if we are matching against content projection otherwise we are
9203 * matching against directives.
9204 */
9205function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
9206 if (attrs === null)
9207 return -1;
9208 let i = 0;
9209 if (isProjectionMode || !isInlineTemplate) {
9210 let bindingsMode = false;
9211 while (i < attrs.length) {
9212 const maybeAttrName = attrs[i];
9213 if (maybeAttrName === name) {
9214 return i;
9215 }
9216 else if (maybeAttrName === 3 /* AttributeMarker.Bindings */ || maybeAttrName === 6 /* AttributeMarker.I18n */) {
9217 bindingsMode = true;
9218 }
9219 else if (maybeAttrName === 1 /* AttributeMarker.Classes */ || maybeAttrName === 2 /* AttributeMarker.Styles */) {
9220 let value = attrs[++i];
9221 // We should skip classes here because we have a separate mechanism for
9222 // matching classes in projection mode.
9223 while (typeof value === 'string') {
9224 value = attrs[++i];
9225 }
9226 continue;
9227 }
9228 else if (maybeAttrName === 4 /* AttributeMarker.Template */) {
9229 // We do not care about Template attributes in this scenario.
9230 break;
9231 }
9232 else if (maybeAttrName === 0 /* AttributeMarker.NamespaceURI */) {
9233 // Skip the whole namespaced attribute and value. This is by design.
9234 i += 4;
9235 continue;
9236 }
9237 // In binding mode there are only names, rather than name-value pairs.
9238 i += bindingsMode ? 1 : 2;
9239 }
9240 // We did not match the attribute
9241 return -1;
9242 }
9243 else {
9244 return matchTemplateAttribute(attrs, name);
9245 }
9246}
9247function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
9248 for (let i = 0; i < selector.length; i++) {
9249 if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
9250 return true;
9251 }
9252 }
9253 return false;
9254}
9255function getProjectAsAttrValue(tNode) {
9256 const nodeAttrs = tNode.attrs;
9257 if (nodeAttrs != null) {
9258 const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* AttributeMarker.ProjectAs */);
9259 // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
9260 // (attribute names are stored at even indexes)
9261 if ((ngProjectAsAttrIdx & 1) === 0) {
9262 return nodeAttrs[ngProjectAsAttrIdx + 1];
9263 }
9264 }
9265 return null;
9266}
9267function getNameOnlyMarkerIndex(nodeAttrs) {
9268 for (let i = 0; i < nodeAttrs.length; i++) {
9269 const nodeAttr = nodeAttrs[i];
9270 if (isNameOnlyAttributeMarker(nodeAttr)) {
9271 return i;
9272 }
9273 }
9274 return nodeAttrs.length;
9275}
9276function matchTemplateAttribute(attrs, name) {
9277 let i = attrs.indexOf(4 /* AttributeMarker.Template */);
9278 if (i > -1) {
9279 i++;
9280 while (i < attrs.length) {
9281 const attr = attrs[i];
9282 // Return in case we checked all template attrs and are switching to the next section in the
9283 // attrs array (that starts with a number that represents an attribute marker).
9284 if (typeof attr === 'number')
9285 return -1;
9286 if (attr === name)
9287 return i;
9288 i++;
9289 }
9290 }
9291 return -1;
9292}
9293/**
9294 * Checks whether a selector is inside a CssSelectorList
9295 * @param selector Selector to be checked.
9296 * @param list List in which to look for the selector.
9297 */
9298function isSelectorInSelectorList(selector, list) {
9299 selectorListLoop: for (let i = 0; i < list.length; i++) {
9300 const currentSelectorInList = list[i];
9301 if (selector.length !== currentSelectorInList.length) {
9302 continue;
9303 }
9304 for (let j = 0; j < selector.length; j++) {
9305 if (selector[j] !== currentSelectorInList[j]) {
9306 continue selectorListLoop;
9307 }
9308 }
9309 return true;
9310 }
9311 return false;
9312}
9313function maybeWrapInNotSelector(isNegativeMode, chunk) {
9314 return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
9315}
9316function stringifyCSSSelector(selector) {
9317 let result = selector[0];
9318 let i = 1;
9319 let mode = 2 /* SelectorFlags.ATTRIBUTE */;
9320 let currentChunk = '';
9321 let isNegativeMode = false;
9322 while (i < selector.length) {
9323 let valueOrMarker = selector[i];
9324 if (typeof valueOrMarker === 'string') {
9325 if (mode & 2 /* SelectorFlags.ATTRIBUTE */) {
9326 const attrValue = selector[++i];
9327 currentChunk +=
9328 '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
9329 }
9330 else if (mode & 8 /* SelectorFlags.CLASS */) {
9331 currentChunk += '.' + valueOrMarker;
9332 }
9333 else if (mode & 4 /* SelectorFlags.ELEMENT */) {
9334 currentChunk += ' ' + valueOrMarker;
9335 }
9336 }
9337 else {
9338 //
9339 // Append current chunk to the final result in case we come across SelectorFlag, which
9340 // indicates that the previous section of a selector is over. We need to accumulate content
9341 // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
9342 // ```
9343 // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
9344 // ```
9345 // should be transformed to `.classA :not(.classB .classC)`.
9346 //
9347 // Note: for negative selector part, we accumulate content between flags until we find the
9348 // next negative flag. This is needed to support a case where `:not()` rule contains more than
9349 // one chunk, e.g. the following selector:
9350 // ```
9351 // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
9352 // ```
9353 // should be stringified to `:not(p.foo) :not(.bar)`
9354 //
9355 if (currentChunk !== '' && !isPositive(valueOrMarker)) {
9356 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9357 currentChunk = '';
9358 }
9359 mode = valueOrMarker;
9360 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9361 // mode is maintained for remaining chunks of a selector.
9362 isNegativeMode = isNegativeMode || !isPositive(mode);
9363 }
9364 i++;
9365 }
9366 if (currentChunk !== '') {
9367 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9368 }
9369 return result;
9370}
9371/**
9372 * Generates string representation of CSS selector in parsed form.
9373 *
9374 * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
9375 * additional parsing at runtime (for example, for directive matching). However in some cases (for
9376 * example, while bootstrapping a component), a string version of the selector is required to query
9377 * for the host element on the page. This function takes the parsed form of a selector and returns
9378 * its string representation.
9379 *
9380 * @param selectorList selector in parsed form
9381 * @returns string representation of a given selector
9382 */
9383function stringifyCSSSelectorList(selectorList) {
9384 return selectorList.map(stringifyCSSSelector).join(',');
9385}
9386/**
9387 * Extracts attributes and classes information from a given CSS selector.
9388 *
9389 * This function is used while creating a component dynamically. In this case, the host element
9390 * (that is created dynamically) should contain attributes and classes specified in component's CSS
9391 * selector.
9392 *
9393 * @param selector CSS selector in parsed form (in a form of array)
9394 * @returns object with `attrs` and `classes` fields that contain extracted information
9395 */
9396function extractAttrsAndClassesFromSelector(selector) {
9397 const attrs = [];
9398 const classes = [];
9399 let i = 1;
9400 let mode = 2 /* SelectorFlags.ATTRIBUTE */;
9401 while (i < selector.length) {
9402 let valueOrMarker = selector[i];
9403 if (typeof valueOrMarker === 'string') {
9404 if (mode === 2 /* SelectorFlags.ATTRIBUTE */) {
9405 if (valueOrMarker !== '') {
9406 attrs.push(valueOrMarker, selector[++i]);
9407 }
9408 }
9409 else if (mode === 8 /* SelectorFlags.CLASS */) {
9410 classes.push(valueOrMarker);
9411 }
9412 }
9413 else {
9414 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9415 // mode is maintained for remaining chunks of a selector. Since attributes and classes are
9416 // extracted only for "positive" part of the selector, we can stop here.
9417 if (!isPositive(mode))
9418 break;
9419 mode = valueOrMarker;
9420 }
9421 i++;
9422 }
9423 return { attrs, classes };
9424}
9425
9426/** A special value which designates that a value has not changed. */
9427const NO_CHANGE = (typeof ngDevMode === 'undefined' || ngDevMode) ? { __brand__: 'NO_CHANGE' } : {};
9428
9429/**
9430 * Advances to an element for later binding instructions.
9431 *
9432 * Used in conjunction with instructions like {@link property} to act on elements with specified
9433 * indices, for example those created with {@link element} or {@link elementStart}.
9434 *
9435 * ```ts
9436 * (rf: RenderFlags, ctx: any) => {
9437 * if (rf & 1) {
9438 * text(0, 'Hello');
9439 * text(1, 'Goodbye')
9440 * element(2, 'div');
9441 * }
9442 * if (rf & 2) {
9443 * advance(2); // Advance twice to the <div>.
9444 * property('title', 'test');
9445 * }
9446 * }
9447 * ```
9448 * @param delta Number of elements to advance forwards by.
9449 *
9450 * @codeGenApi
9451 */
9452function ɵɵadvance(delta) {
9453 ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
9454 selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, !!ngDevMode && isInCheckNoChangesMode());
9455}
9456function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
9457 ngDevMode && assertIndexInDeclRange(lView, index);
9458 // Flush the initial hooks for elements in the view that have been added up to this point.
9459 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
9460 if (!checkNoChangesMode) {
9461 const hooksInitPhaseCompleted = (lView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
9462 if (hooksInitPhaseCompleted) {
9463 const preOrderCheckHooks = tView.preOrderCheckHooks;
9464 if (preOrderCheckHooks !== null) {
9465 executeCheckHooks(lView, preOrderCheckHooks, index);
9466 }
9467 }
9468 else {
9469 const preOrderHooks = tView.preOrderHooks;
9470 if (preOrderHooks !== null) {
9471 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, index);
9472 }
9473 }
9474 }
9475 // We must set the selected index *after* running the hooks, because hooks may have side-effects
9476 // that cause other template functions to run, thus updating the selected index, which is global
9477 // state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index
9478 // will be altered by the time we leave the `ɵɵadvance` instruction.
9479 setSelectedIndex(index);
9480}
9481
9482/**
9483 * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
9484 *
9485 * This should be kept up to date with the public exports of @angular/core.
9486 */
9487const angularCoreDiEnv = {
9488 'ɵɵdefineInjectable': ɵɵdefineInjectable,
9489 'ɵɵdefineInjector': ɵɵdefineInjector,
9490 'ɵɵinject': ɵɵinject,
9491 'ɵɵinvalidFactoryDep': ɵɵinvalidFactoryDep,
9492 'resolveForwardRef': resolveForwardRef,
9493};
9494
9495/**
9496 * Compile an Angular injectable according to its `Injectable` metadata, and patch the resulting
9497 * injectable def (`ɵprov`) onto the injectable type.
9498 */
9499function compileInjectable(type, meta) {
9500 let ngInjectableDef = null;
9501 let ngFactoryDef = null;
9502 // if NG_PROV_DEF is already defined on this class then don't overwrite it
9503 if (!type.hasOwnProperty(NG_PROV_DEF)) {
9504 Object.defineProperty(type, NG_PROV_DEF, {
9505 get: () => {
9506 if (ngInjectableDef === null) {
9507 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'injectable', type });
9508 ngInjectableDef = compiler.compileInjectable(angularCoreDiEnv, `ng:///${type.name}/ɵprov.js`, getInjectableMetadata(type, meta));
9509 }
9510 return ngInjectableDef;
9511 },
9512 });
9513 }
9514 // if NG_FACTORY_DEF is already defined on this class then don't overwrite it
9515 if (!type.hasOwnProperty(NG_FACTORY_DEF)) {
9516 Object.defineProperty(type, NG_FACTORY_DEF, {
9517 get: () => {
9518 if (ngFactoryDef === null) {
9519 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'injectable', type });
9520 ngFactoryDef = compiler.compileFactory(angularCoreDiEnv, `ng:///${type.name}/ɵfac.js`, {
9521 name: type.name,
9522 type,
9523 typeArgumentCount: 0,
9524 deps: reflectDependencies(type),
9525 target: compiler.FactoryTarget.Injectable
9526 });
9527 }
9528 return ngFactoryDef;
9529 },
9530 // Leave this configurable so that the factories from directives or pipes can take precedence.
9531 configurable: true
9532 });
9533 }
9534}
9535const USE_VALUE = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
9536function isUseClassProvider(meta) {
9537 return meta.useClass !== undefined;
9538}
9539function isUseValueProvider(meta) {
9540 return USE_VALUE in meta;
9541}
9542function isUseFactoryProvider(meta) {
9543 return meta.useFactory !== undefined;
9544}
9545function isUseExistingProvider(meta) {
9546 return meta.useExisting !== undefined;
9547}
9548function getInjectableMetadata(type, srcMeta) {
9549 // Allow the compilation of a class with a `@Injectable()` decorator without parameters
9550 const meta = srcMeta || { providedIn: null };
9551 const compilerMeta = {
9552 name: type.name,
9553 type: type,
9554 typeArgumentCount: 0,
9555 providedIn: meta.providedIn,
9556 };
9557 if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) {
9558 compilerMeta.deps = convertDependencies(meta.deps);
9559 }
9560 // Check to see if the user explicitly provided a `useXxxx` property.
9561 if (isUseClassProvider(meta)) {
9562 compilerMeta.useClass = meta.useClass;
9563 }
9564 else if (isUseValueProvider(meta)) {
9565 compilerMeta.useValue = meta.useValue;
9566 }
9567 else if (isUseFactoryProvider(meta)) {
9568 compilerMeta.useFactory = meta.useFactory;
9569 }
9570 else if (isUseExistingProvider(meta)) {
9571 compilerMeta.useExisting = meta.useExisting;
9572 }
9573 return compilerMeta;
9574}
9575
9576/**
9577 * Injectable decorator and metadata.
9578 *
9579 * @Annotation
9580 * @publicApi
9581 */
9582const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, (type, meta) => compileInjectable(type, meta));
9583
9584/**
9585 * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s.
9586 *
9587 * @publicApi
9588 */
9589function createInjector(defType, parent = null, additionalProviders = null, name) {
9590 const injector = createInjectorWithoutInjectorInstances(defType, parent, additionalProviders, name);
9591 injector.resolveInjectorInitializers();
9592 return injector;
9593}
9594/**
9595 * Creates a new injector without eagerly resolving its injector types. Can be used in places
9596 * where resolving the injector types immediately can lead to an infinite loop. The injector types
9597 * should be resolved at a later point by calling `_resolveInjectorDefTypes`.
9598 */
9599function createInjectorWithoutInjectorInstances(defType, parent = null, additionalProviders = null, name, scopes = new Set()) {
9600 const providers = [
9601 additionalProviders || EMPTY_ARRAY,
9602 importProvidersFrom(defType),
9603 ];
9604 name = name || (typeof defType === 'object' ? undefined : stringify(defType));
9605 return new R3Injector(providers, parent || getNullInjector(), name || null, scopes);
9606}
9607
9608/**
9609 * Concrete injectors implement this interface. Injectors are configured
9610 * with [providers](guide/glossary#provider) that associate
9611 * dependencies of various types with [injection tokens](guide/glossary#di-token).
9612 *
9613 * @see ["DI Providers"](guide/dependency-injection-providers).
9614 * @see `StaticProvider`
9615 *
9616 * @usageNotes
9617 *
9618 * The following example creates a service injector instance.
9619 *
9620 * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
9621 *
9622 * ### Usage example
9623 *
9624 * {@example core/di/ts/injector_spec.ts region='Injector'}
9625 *
9626 * `Injector` returns itself when given `Injector` as a token:
9627 *
9628 * {@example core/di/ts/injector_spec.ts region='injectInjector'}
9629 *
9630 * @publicApi
9631 */
9632class Injector {
9633 static create(options, parent) {
9634 var _a;
9635 if (Array.isArray(options)) {
9636 return createInjector({ name: '' }, parent, options, '');
9637 }
9638 else {
9639 const name = (_a = options.name) !== null && _a !== void 0 ? _a : '';
9640 return createInjector({ name }, options.parent, options.providers, name);
9641 }
9642 }
9643}
9644Injector.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
9645Injector.NULL = ( /* @__PURE__ */new NullInjector());
9646/** @nocollapse */
9647Injector.ɵprov = ɵɵdefineInjectable({
9648 token: Injector,
9649 providedIn: 'any',
9650 factory: () => ɵɵinject(INJECTOR),
9651});
9652/**
9653 * @internal
9654 * @nocollapse
9655 */
9656Injector.__NG_ELEMENT_ID__ = -1 /* InjectorMarkers.Injector */;
9657
9658function findFirstClosedCycle(keys) {
9659 const res = [];
9660 for (let i = 0; i < keys.length; ++i) {
9661 if (res.indexOf(keys[i]) > -1) {
9662 res.push(keys[i]);
9663 return res;
9664 }
9665 res.push(keys[i]);
9666 }
9667 return res;
9668}
9669function constructResolvingPath(keys) {
9670 if (keys.length > 1) {
9671 const reversed = findFirstClosedCycle(keys.slice().reverse());
9672 const tokenStrs = reversed.map(k => stringify(k.token));
9673 return ' (' + tokenStrs.join(' -> ') + ')';
9674 }
9675 return '';
9676}
9677function injectionError(injector, key, constructResolvingMessage, originalError) {
9678 const keys = [key];
9679 const errMsg = constructResolvingMessage(keys);
9680 const error = (originalError ? wrappedError(errMsg, originalError) : Error(errMsg));
9681 error.addKey = addKey;
9682 error.keys = keys;
9683 error.injectors = [injector];
9684 error.constructResolvingMessage = constructResolvingMessage;
9685 error[ERROR_ORIGINAL_ERROR] = originalError;
9686 return error;
9687}
9688function addKey(injector, key) {
9689 this.injectors.push(injector);
9690 this.keys.push(key);
9691 // Note: This updated message won't be reflected in the `.stack` property
9692 this.message = this.constructResolvingMessage(this.keys);
9693}
9694/**
9695 * Thrown when trying to retrieve a dependency by key from {@link Injector}, but the
9696 * {@link Injector} does not have a {@link Provider} for the given key.
9697 *
9698 * @usageNotes
9699 * ### Example
9700 *
9701 * ```typescript
9702 * class A {
9703 * constructor(b:B) {}
9704 * }
9705 *
9706 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
9707 * ```
9708 */
9709function noProviderError(injector, key) {
9710 return injectionError(injector, key, function (keys) {
9711 const first = stringify(keys[0].token);
9712 return `No provider for ${first}!${constructResolvingPath(keys)}`;
9713 });
9714}
9715/**
9716 * Thrown when dependencies form a cycle.
9717 *
9718 * @usageNotes
9719 * ### Example
9720 *
9721 * ```typescript
9722 * var injector = Injector.resolveAndCreate([
9723 * {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]},
9724 * {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]}
9725 * ]);
9726 *
9727 * expect(() => injector.get("one")).toThrowError();
9728 * ```
9729 *
9730 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
9731 */
9732function cyclicDependencyError(injector, key) {
9733 return injectionError(injector, key, function (keys) {
9734 return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
9735 });
9736}
9737/**
9738 * Thrown when a constructing type returns with an Error.
9739 *
9740 * The `InstantiationError` class contains the original error plus the dependency graph which caused
9741 * this object to be instantiated.
9742 *
9743 * @usageNotes
9744 * ### Example
9745 *
9746 * ```typescript
9747 * class A {
9748 * constructor() {
9749 * throw new Error('message');
9750 * }
9751 * }
9752 *
9753 * var injector = Injector.resolveAndCreate([A]);
9754
9755 * try {
9756 * injector.get(A);
9757 * } catch (e) {
9758 * expect(e instanceof InstantiationError).toBe(true);
9759 * expect(e.originalException.message).toEqual("message");
9760 * expect(e.originalStack).toBeDefined();
9761 * }
9762 * ```
9763 */
9764function instantiationError(injector, originalException, originalStack, key) {
9765 return injectionError(injector, key, function (keys) {
9766 const first = stringify(keys[0].token);
9767 return `${originalException.message}: Error during instantiation of ${first}!${constructResolvingPath(keys)}.`;
9768 }, originalException);
9769}
9770/**
9771 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
9772 * creation.
9773 *
9774 * @usageNotes
9775 * ### Example
9776 *
9777 * ```typescript
9778 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
9779 * ```
9780 */
9781function invalidProviderError(provider) {
9782 return Error(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
9783}
9784/**
9785 * Thrown when the class has no annotation information.
9786 *
9787 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
9788 * need to be injected into the constructor.
9789 *
9790 * @usageNotes
9791 * ### Example
9792 *
9793 * ```typescript
9794 * class A {
9795 * constructor(b) {}
9796 * }
9797 *
9798 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
9799 * ```
9800 *
9801 * This error is also thrown when the class not marked with {@link Injectable} has parameter types.
9802 *
9803 * ```typescript
9804 * class B {}
9805 *
9806 * class A {
9807 * constructor(b:B) {} // no information about the parameter types of A is available at runtime.
9808 * }
9809 *
9810 * expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
9811 * ```
9812 *
9813 */
9814function noAnnotationError(typeOrFunc, params) {
9815 const signature = [];
9816 for (let i = 0, ii = params.length; i < ii; i++) {
9817 const parameter = params[i];
9818 if (!parameter || parameter.length == 0) {
9819 signature.push('?');
9820 }
9821 else {
9822 signature.push(parameter.map(stringify).join(' '));
9823 }
9824 }
9825 return Error('Cannot resolve all parameters for \'' + stringify(typeOrFunc) + '\'(' +
9826 signature.join(', ') + '). ' +
9827 'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
9828 stringify(typeOrFunc) + '\' is decorated with Injectable.');
9829}
9830/**
9831 * Thrown when getting an object by index.
9832 *
9833 * @usageNotes
9834 * ### Example
9835 *
9836 * ```typescript
9837 * class A {}
9838 *
9839 * var injector = Injector.resolveAndCreate([A]);
9840 *
9841 * expect(() => injector.getAt(100)).toThrowError();
9842 * ```
9843 *
9844 */
9845function outOfBoundsError(index) {
9846 return Error(`Index ${index} is out-of-bounds.`);
9847}
9848// TODO: add a working example after alpha38 is released
9849/**
9850 * Thrown when a multi provider and a regular provider are bound to the same token.
9851 *
9852 * @usageNotes
9853 * ### Example
9854 *
9855 * ```typescript
9856 * expect(() => Injector.resolveAndCreate([
9857 * { provide: "Strings", useValue: "string1", multi: true},
9858 * { provide: "Strings", useValue: "string2", multi: false}
9859 * ])).toThrowError();
9860 * ```
9861 */
9862function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) {
9863 return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
9864}
9865
9866/**
9867 * A unique object used for retrieving items from the {@link ReflectiveInjector}.
9868 *
9869 * Keys have:
9870 * - a system-wide unique `id`.
9871 * - a `token`.
9872 *
9873 * `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
9874 * the
9875 * injector to store created objects in a more efficient way.
9876 *
9877 * `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
9878 * resolving
9879 * providers.
9880 *
9881 * @deprecated No replacement
9882 * @publicApi
9883 */
9884class ReflectiveKey {
9885 /**
9886 * Private
9887 */
9888 constructor(token, id) {
9889 this.token = token;
9890 this.id = id;
9891 if (!token) {
9892 throw new RuntimeError(208 /* RuntimeErrorCode.MISSING_INJECTION_TOKEN */, ngDevMode && 'Token must be defined!');
9893 }
9894 this.displayName = stringify(this.token);
9895 }
9896 /**
9897 * Retrieves a `Key` for a token.
9898 */
9899 static get(token) {
9900 return _globalKeyRegistry.get(resolveForwardRef(token));
9901 }
9902 /**
9903 * @returns the number of keys registered in the system.
9904 */
9905 static get numberOfKeys() {
9906 return _globalKeyRegistry.numberOfKeys;
9907 }
9908}
9909class KeyRegistry {
9910 constructor() {
9911 this._allKeys = new Map();
9912 }
9913 get(token) {
9914 if (token instanceof ReflectiveKey)
9915 return token;
9916 if (this._allKeys.has(token)) {
9917 return this._allKeys.get(token);
9918 }
9919 const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
9920 this._allKeys.set(token, newKey);
9921 return newKey;
9922 }
9923 get numberOfKeys() {
9924 return this._allKeys.size;
9925 }
9926}
9927const _globalKeyRegistry = new KeyRegistry();
9928
9929/**
9930 * `Dependency` is used by the framework to extend DI.
9931 * This is internal to Angular and should not be used directly.
9932 */
9933class ReflectiveDependency {
9934 constructor(key, optional, visibility) {
9935 this.key = key;
9936 this.optional = optional;
9937 this.visibility = visibility;
9938 }
9939 static fromKey(key) {
9940 return new ReflectiveDependency(key, false, null);
9941 }
9942}
9943const _EMPTY_LIST = [];
9944class ResolvedReflectiveProvider_ {
9945 constructor(key, resolvedFactories, multiProvider) {
9946 this.key = key;
9947 this.resolvedFactories = resolvedFactories;
9948 this.multiProvider = multiProvider;
9949 this.resolvedFactory = this.resolvedFactories[0];
9950 }
9951}
9952/**
9953 * An internal resolved representation of a factory function created by resolving `Provider`.
9954 * @publicApi
9955 */
9956class ResolvedReflectiveFactory {
9957 constructor(
9958 /**
9959 * Factory function which can return an instance of an object represented by a key.
9960 */
9961 factory,
9962 /**
9963 * Arguments (dependencies) to the `factory` function.
9964 */
9965 dependencies) {
9966 this.factory = factory;
9967 this.dependencies = dependencies;
9968 }
9969}
9970/**
9971 * Resolve a single provider.
9972 */
9973function resolveReflectiveFactory(provider) {
9974 let factoryFn;
9975 let resolvedDeps;
9976 if (provider.useClass) {
9977 const useClass = resolveForwardRef(provider.useClass);
9978 factoryFn = getReflect().factory(useClass);
9979 resolvedDeps = _dependenciesFor(useClass);
9980 }
9981 else if (provider.useExisting) {
9982 factoryFn = (aliasInstance) => aliasInstance;
9983 resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
9984 }
9985 else if (provider.useFactory) {
9986 factoryFn = provider.useFactory;
9987 resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
9988 }
9989 else {
9990 factoryFn = () => provider.useValue;
9991 resolvedDeps = _EMPTY_LIST;
9992 }
9993 return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
9994}
9995/**
9996 * Converts the `Provider` into `ResolvedProvider`.
9997 *
9998 * `Injector` internally only uses `ResolvedProvider`, `Provider` contains convenience provider
9999 * syntax.
10000 */
10001function resolveReflectiveProvider(provider) {
10002 return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false);
10003}
10004/**
10005 * Resolve a list of Providers.
10006 */
10007function resolveReflectiveProviders(providers) {
10008 const normalized = _normalizeProviders(providers, []);
10009 const resolved = normalized.map(resolveReflectiveProvider);
10010 const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
10011 return Array.from(resolvedProviderMap.values());
10012}
10013/**
10014 * Merges a list of ResolvedProviders into a list where each key is contained exactly once and
10015 * multi providers have been merged.
10016 */
10017function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) {
10018 for (let i = 0; i < providers.length; i++) {
10019 const provider = providers[i];
10020 const existing = normalizedProvidersMap.get(provider.key.id);
10021 if (existing) {
10022 if (provider.multiProvider !== existing.multiProvider) {
10023 throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
10024 }
10025 if (provider.multiProvider) {
10026 for (let j = 0; j < provider.resolvedFactories.length; j++) {
10027 existing.resolvedFactories.push(provider.resolvedFactories[j]);
10028 }
10029 }
10030 else {
10031 normalizedProvidersMap.set(provider.key.id, provider);
10032 }
10033 }
10034 else {
10035 let resolvedProvider;
10036 if (provider.multiProvider) {
10037 resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider);
10038 }
10039 else {
10040 resolvedProvider = provider;
10041 }
10042 normalizedProvidersMap.set(provider.key.id, resolvedProvider);
10043 }
10044 }
10045 return normalizedProvidersMap;
10046}
10047function _normalizeProviders(providers, res) {
10048 providers.forEach(b => {
10049 if (b instanceof Type) {
10050 res.push({ provide: b, useClass: b });
10051 }
10052 else if (b && typeof b == 'object' && b.provide !== undefined) {
10053 res.push(b);
10054 }
10055 else if (Array.isArray(b)) {
10056 _normalizeProviders(b, res);
10057 }
10058 else {
10059 throw invalidProviderError(b);
10060 }
10061 });
10062 return res;
10063}
10064function constructDependencies(typeOrFunc, dependencies) {
10065 if (!dependencies) {
10066 return _dependenciesFor(typeOrFunc);
10067 }
10068 else {
10069 const params = dependencies.map(t => [t]);
10070 return dependencies.map(t => _extractToken(typeOrFunc, t, params));
10071 }
10072}
10073function _dependenciesFor(typeOrFunc) {
10074 const params = getReflect().parameters(typeOrFunc);
10075 if (!params)
10076 return [];
10077 if (params.some(p => p == null)) {
10078 throw noAnnotationError(typeOrFunc, params);
10079 }
10080 return params.map(p => _extractToken(typeOrFunc, p, params));
10081}
10082function _extractToken(typeOrFunc, metadata, params) {
10083 let token = null;
10084 let optional = false;
10085 if (!Array.isArray(metadata)) {
10086 if (metadata instanceof Inject) {
10087 return _createDependency(metadata.token, optional, null);
10088 }
10089 else {
10090 return _createDependency(metadata, optional, null);
10091 }
10092 }
10093 let visibility = null;
10094 for (let i = 0; i < metadata.length; ++i) {
10095 const paramMetadata = metadata[i];
10096 if (paramMetadata instanceof Type) {
10097 token = paramMetadata;
10098 }
10099 else if (paramMetadata instanceof Inject) {
10100 token = paramMetadata.token;
10101 }
10102 else if (paramMetadata instanceof Optional) {
10103 optional = true;
10104 }
10105 else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
10106 visibility = paramMetadata;
10107 }
10108 else if (paramMetadata instanceof InjectionToken) {
10109 token = paramMetadata;
10110 }
10111 }
10112 token = resolveForwardRef(token);
10113 if (token != null) {
10114 return _createDependency(token, optional, visibility);
10115 }
10116 else {
10117 throw noAnnotationError(typeOrFunc, params);
10118 }
10119}
10120function _createDependency(token, optional, visibility) {
10121 return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
10122}
10123
10124// Threshold for the dynamic version
10125const UNDEFINED = {};
10126/**
10127 * A ReflectiveDependency injection container used for instantiating objects and resolving
10128 * dependencies.
10129 *
10130 * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
10131 * constructor dependencies.
10132 *
10133 * In typical use, application code asks for the dependencies in the constructor and they are
10134 * resolved by the `Injector`.
10135 *
10136 * @usageNotes
10137 * ### Example
10138 *
10139 * The following example creates an `Injector` configured to create `Engine` and `Car`.
10140 *
10141 * ```typescript
10142 * @Injectable()
10143 * class Engine {
10144 * }
10145 *
10146 * @Injectable()
10147 * class Car {
10148 * constructor(public engine:Engine) {}
10149 * }
10150 *
10151 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
10152 * var car = injector.get(Car);
10153 * expect(car instanceof Car).toBe(true);
10154 * expect(car.engine instanceof Engine).toBe(true);
10155 * ```
10156 *
10157 * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
10158 * resolve all of the object's dependencies automatically.
10159 *
10160 * TODO: delete in v14.
10161 *
10162 * @deprecated from v5 - slow and brings in a lot of code, Use `Injector.create` instead.
10163 * @publicApi
10164 */
10165class ReflectiveInjector {
10166 /**
10167 * Turns an array of provider definitions into an array of resolved providers.
10168 *
10169 * A resolution is a process of flattening multiple nested arrays and converting individual
10170 * providers into an array of `ResolvedReflectiveProvider`s.
10171 *
10172 * @usageNotes
10173 * ### Example
10174 *
10175 * ```typescript
10176 * @Injectable()
10177 * class Engine {
10178 * }
10179 *
10180 * @Injectable()
10181 * class Car {
10182 * constructor(public engine:Engine) {}
10183 * }
10184 *
10185 * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
10186 *
10187 * expect(providers.length).toEqual(2);
10188 *
10189 * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
10190 * expect(providers[0].key.displayName).toBe("Car");
10191 * expect(providers[0].dependencies.length).toEqual(1);
10192 * expect(providers[0].factory).toBeDefined();
10193 *
10194 * expect(providers[1].key.displayName).toBe("Engine");
10195 * });
10196 * ```
10197 *
10198 */
10199 static resolve(providers) {
10200 return resolveReflectiveProviders(providers);
10201 }
10202 /**
10203 * Resolves an array of providers and creates an injector from those providers.
10204 *
10205 * The passed-in providers can be an array of `Type`, `Provider`,
10206 * or a recursive array of more providers.
10207 *
10208 * @usageNotes
10209 * ### Example
10210 *
10211 * ```typescript
10212 * @Injectable()
10213 * class Engine {
10214 * }
10215 *
10216 * @Injectable()
10217 * class Car {
10218 * constructor(public engine:Engine) {}
10219 * }
10220 *
10221 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
10222 * expect(injector.get(Car) instanceof Car).toBe(true);
10223 * ```
10224 */
10225 static resolveAndCreate(providers, parent) {
10226 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
10227 return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
10228 }
10229 /**
10230 * Creates an injector from previously resolved providers.
10231 *
10232 * This API is the recommended way to construct injectors in performance-sensitive parts.
10233 *
10234 * @usageNotes
10235 * ### Example
10236 *
10237 * ```typescript
10238 * @Injectable()
10239 * class Engine {
10240 * }
10241 *
10242 * @Injectable()
10243 * class Car {
10244 * constructor(public engine:Engine) {}
10245 * }
10246 *
10247 * var providers = ReflectiveInjector.resolve([Car, Engine]);
10248 * var injector = ReflectiveInjector.fromResolvedProviders(providers);
10249 * expect(injector.get(Car) instanceof Car).toBe(true);
10250 * ```
10251 */
10252 static fromResolvedProviders(providers, parent) {
10253 return new ReflectiveInjector_(providers, parent);
10254 }
10255}
10256class ReflectiveInjector_ {
10257 /**
10258 * Private
10259 */
10260 constructor(_providers, _parent) {
10261 /** @internal */
10262 this._constructionCounter = 0;
10263 this._providers = _providers;
10264 this.parent = _parent || null;
10265 const len = _providers.length;
10266 this.keyIds = [];
10267 this.objs = [];
10268 for (let i = 0; i < len; i++) {
10269 this.keyIds[i] = _providers[i].key.id;
10270 this.objs[i] = UNDEFINED;
10271 }
10272 }
10273 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
10274 return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
10275 }
10276 resolveAndCreateChild(providers) {
10277 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
10278 return this.createChildFromResolved(ResolvedReflectiveProviders);
10279 }
10280 createChildFromResolved(providers) {
10281 const inj = new ReflectiveInjector_(providers);
10282 inj.parent = this;
10283 return inj;
10284 }
10285 resolveAndInstantiate(provider) {
10286 return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
10287 }
10288 instantiateResolved(provider) {
10289 return this._instantiateProvider(provider);
10290 }
10291 getProviderAtIndex(index) {
10292 if (index < 0 || index >= this._providers.length) {
10293 throw outOfBoundsError(index);
10294 }
10295 return this._providers[index];
10296 }
10297 /** @internal */
10298 _new(provider) {
10299 if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
10300 throw cyclicDependencyError(this, provider.key);
10301 }
10302 return this._instantiateProvider(provider);
10303 }
10304 _getMaxNumberOfObjects() {
10305 return this.objs.length;
10306 }
10307 _instantiateProvider(provider) {
10308 if (provider.multiProvider) {
10309 const res = [];
10310 for (let i = 0; i < provider.resolvedFactories.length; ++i) {
10311 res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
10312 }
10313 return res;
10314 }
10315 else {
10316 return this._instantiate(provider, provider.resolvedFactories[0]);
10317 }
10318 }
10319 _instantiate(provider, ResolvedReflectiveFactory) {
10320 const factory = ResolvedReflectiveFactory.factory;
10321 let deps;
10322 try {
10323 deps =
10324 ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
10325 }
10326 catch (e) {
10327 if (e.addKey) {
10328 e.addKey(this, provider.key);
10329 }
10330 throw e;
10331 }
10332 let obj;
10333 try {
10334 obj = factory(...deps);
10335 }
10336 catch (e) {
10337 throw instantiationError(this, e, e.stack, provider.key);
10338 }
10339 return obj;
10340 }
10341 _getByReflectiveDependency(dep) {
10342 return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
10343 }
10344 _getByKey(key, visibility, notFoundValue) {
10345 if (key === ReflectiveInjector_.INJECTOR_KEY) {
10346 return this;
10347 }
10348 if (visibility instanceof Self) {
10349 return this._getByKeySelf(key, notFoundValue);
10350 }
10351 else {
10352 return this._getByKeyDefault(key, notFoundValue, visibility);
10353 }
10354 }
10355 _getObjByKeyId(keyId) {
10356 for (let i = 0; i < this.keyIds.length; i++) {
10357 if (this.keyIds[i] === keyId) {
10358 if (this.objs[i] === UNDEFINED) {
10359 this.objs[i] = this._new(this._providers[i]);
10360 }
10361 return this.objs[i];
10362 }
10363 }
10364 return UNDEFINED;
10365 }
10366 /** @internal */
10367 _throwOrNull(key, notFoundValue) {
10368 if (notFoundValue !== THROW_IF_NOT_FOUND) {
10369 return notFoundValue;
10370 }
10371 else {
10372 throw noProviderError(this, key);
10373 }
10374 }
10375 /** @internal */
10376 _getByKeySelf(key, notFoundValue) {
10377 const obj = this._getObjByKeyId(key.id);
10378 return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
10379 }
10380 /** @internal */
10381 _getByKeyDefault(key, notFoundValue, visibility) {
10382 let inj;
10383 if (visibility instanceof SkipSelf) {
10384 inj = this.parent;
10385 }
10386 else {
10387 inj = this;
10388 }
10389 while (inj instanceof ReflectiveInjector_) {
10390 const inj_ = inj;
10391 const obj = inj_._getObjByKeyId(key.id);
10392 if (obj !== UNDEFINED)
10393 return obj;
10394 inj = inj_.parent;
10395 }
10396 if (inj !== null) {
10397 return inj.get(key.token, notFoundValue);
10398 }
10399 else {
10400 return this._throwOrNull(key, notFoundValue);
10401 }
10402 }
10403 get displayName() {
10404 const providers = _mapProviders(this, (b) => ' "' + b.key.displayName + '" ')
10405 .join(', ');
10406 return `ReflectiveInjector(providers: [${providers}])`;
10407 }
10408 toString() {
10409 return this.displayName;
10410 }
10411}
10412ReflectiveInjector_.INJECTOR_KEY = ( /* @__PURE__ */ReflectiveKey.get(Injector));
10413function _mapProviders(injector, fn) {
10414 const res = [];
10415 for (let i = 0; i < injector._providers.length; ++i) {
10416 res[i] = fn(injector.getProviderAtIndex(i));
10417 }
10418 return res;
10419}
10420
10421/**
10422 * @module
10423 * @description
10424 * The `di` module provides dependency injection container services.
10425 */
10426
10427/**
10428 * This file should not be necessary because node resolution should just default to `./di/index`!
10429 *
10430 * However it does not seem to work and it breaks:
10431 * - //packages/animations/browser/test:test_web_chromium-local
10432 * - //packages/compiler-cli/test:extract_i18n
10433 * - //packages/compiler-cli/test:ngc
10434 * - //packages/compiler-cli/test:perform_watch
10435 * - //packages/compiler-cli/test/diagnostics:check_types
10436 * - //packages/compiler-cli/test/transformers:test
10437 * - //packages/compiler/test:test
10438 * - //tools/public_api_guard:core_api
10439 *
10440 * Remove this file once the above is solved or wait until `ngc` is deleted and then it should be
10441 * safe to delete this file.
10442 */
10443
10444function ɵɵdirectiveInject(token, flags = InjectFlags.Default) {
10445 const lView = getLView();
10446 // Fall back to inject() if view hasn't been created. This situation can happen in tests
10447 // if inject utilities are used before bootstrapping.
10448 if (lView === null) {
10449 // Verify that we will not get into infinite loop.
10450 ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject);
10451 return ɵɵinject(token, flags);
10452 }
10453 const tNode = getCurrentTNode();
10454 return getOrCreateInjectable(tNode, lView, resolveForwardRef(token), flags);
10455}
10456/**
10457 * Throws an error indicating that a factory function could not be generated by the compiler for a
10458 * particular class.
10459 *
10460 * This instruction allows the actual error message to be optimized away when ngDevMode is turned
10461 * off, saving bytes of generated code while still providing a good experience in dev mode.
10462 *
10463 * The name of the class is not mentioned here, but will be in the generated factory function name
10464 * and thus in the stack trace.
10465 *
10466 * @codeGenApi
10467 */
10468function ɵɵinvalidFactory() {
10469 const msg = ngDevMode ? `This constructor was not compatible with Dependency Injection.` : 'invalid';
10470 throw new Error(msg);
10471}
10472
10473/**
10474 * Invoke `HostBindingsFunction`s for view.
10475 *
10476 * This methods executes `TView.hostBindingOpCodes`. It is used to execute the
10477 * `HostBindingsFunction`s associated with the current `LView`.
10478 *
10479 * @param tView Current `TView`.
10480 * @param lView Current `LView`.
10481 */
10482function processHostBindingOpCodes(tView, lView) {
10483 const hostBindingOpCodes = tView.hostBindingOpCodes;
10484 if (hostBindingOpCodes === null)
10485 return;
10486 try {
10487 for (let i = 0; i < hostBindingOpCodes.length; i++) {
10488 const opCode = hostBindingOpCodes[i];
10489 if (opCode < 0) {
10490 // Negative numbers are element indexes.
10491 setSelectedIndex(~opCode);
10492 }
10493 else {
10494 // Positive numbers are NumberTuple which store bindingRootIndex and directiveIndex.
10495 const directiveIdx = opCode;
10496 const bindingRootIndx = hostBindingOpCodes[++i];
10497 const hostBindingFn = hostBindingOpCodes[++i];
10498 setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
10499 const context = lView[directiveIdx];
10500 hostBindingFn(2 /* RenderFlags.Update */, context);
10501 }
10502 }
10503 }
10504 finally {
10505 setSelectedIndex(-1);
10506 }
10507}
10508/** Refreshes all content queries declared by directives in a given view */
10509function refreshContentQueries(tView, lView) {
10510 const contentQueries = tView.contentQueries;
10511 if (contentQueries !== null) {
10512 for (let i = 0; i < contentQueries.length; i += 2) {
10513 const queryStartIdx = contentQueries[i];
10514 const directiveDefIdx = contentQueries[i + 1];
10515 if (directiveDefIdx !== -1) {
10516 const directiveDef = tView.data[directiveDefIdx];
10517 ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
10518 ngDevMode &&
10519 assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
10520 setCurrentQueryIndex(queryStartIdx);
10521 directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
10522 }
10523 }
10524 }
10525}
10526/** Refreshes child components in the current view (update mode). */
10527function refreshChildComponents(hostLView, components) {
10528 for (let i = 0; i < components.length; i++) {
10529 refreshComponent(hostLView, components[i]);
10530 }
10531}
10532/** Renders child components in the current view (creation mode). */
10533function renderChildComponents(hostLView, components) {
10534 for (let i = 0; i < components.length; i++) {
10535 renderComponent(hostLView, components[i]);
10536 }
10537}
10538function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector, embeddedViewInjector) {
10539 const lView = tView.blueprint.slice();
10540 lView[HOST] = host;
10541 lView[FLAGS] = flags | 4 /* LViewFlags.CreationMode */ | 64 /* LViewFlags.Attached */ | 8 /* LViewFlags.FirstLViewPass */;
10542 if (embeddedViewInjector !== null ||
10543 (parentLView && (parentLView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */))) {
10544 lView[FLAGS] |= 1024 /* LViewFlags.HasEmbeddedViewInjector */;
10545 }
10546 resetPreOrderHookFlags(lView);
10547 ngDevMode && tView.declTNode && parentLView && assertTNodeForLView(tView.declTNode, parentLView);
10548 lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
10549 lView[CONTEXT] = context;
10550 lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]);
10551 ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required');
10552 lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]);
10553 ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required');
10554 lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null;
10555 lView[INJECTOR$1] = injector || parentLView && parentLView[INJECTOR$1] || null;
10556 lView[T_HOST] = tHostNode;
10557 lView[ID] = getUniqueLViewId();
10558 lView[EMBEDDED_VIEW_INJECTOR] = embeddedViewInjector;
10559 ngDevMode &&
10560 assertEqual(tView.type == 2 /* TViewType.Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
10561 lView[DECLARATION_COMPONENT_VIEW] =
10562 tView.type == 2 /* TViewType.Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
10563 return lView;
10564}
10565function getOrCreateTNode(tView, index, type, name, attrs) {
10566 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
10567 // `view_engine_compatibility` for additional context.
10568 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
10569 // Keep this function short, so that the VM will inline it.
10570 ngDevMode && assertPureTNodeType(type);
10571 let tNode = tView.data[index];
10572 if (tNode === null) {
10573 tNode = createTNodeAtIndex(tView, index, type, name, attrs);
10574 if (isInI18nBlock()) {
10575 // If we are in i18n block then all elements should be pre declared through `Placeholder`
10576 // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
10577 // If the `TNode` was not pre-declared than it means it was not mentioned which means it was
10578 // removed, so we mark it as detached.
10579 tNode.flags |= 32 /* TNodeFlags.isDetached */;
10580 }
10581 }
10582 else if (tNode.type & 64 /* TNodeType.Placeholder */) {
10583 tNode.type = type;
10584 tNode.value = name;
10585 tNode.attrs = attrs;
10586 const parent = getCurrentParentTNode();
10587 tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex;
10588 ngDevMode && assertTNodeForTView(tNode, tView);
10589 ngDevMode && assertEqual(index, tNode.index, 'Expecting same index');
10590 }
10591 setCurrentTNode(tNode, true);
10592 return tNode;
10593}
10594function createTNodeAtIndex(tView, index, type, name, attrs) {
10595 const currentTNode = getCurrentTNodePlaceholderOk();
10596 const isParent = isCurrentTNodeParent();
10597 const parent = isParent ? currentTNode : currentTNode && currentTNode.parent;
10598 // Parents cannot cross component boundaries because components will be used in multiple places.
10599 const tNode = tView.data[index] =
10600 createTNode(tView, parent, type, index, name, attrs);
10601 // Assign a pointer to the first child node of a given view. The first node is not always the one
10602 // at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
10603 // the index 1 or more, so we can't just check node index.
10604 if (tView.firstChild === null) {
10605 tView.firstChild = tNode;
10606 }
10607 if (currentTNode !== null) {
10608 if (isParent) {
10609 // FIXME(misko): This logic looks unnecessarily complicated. Could we simplify?
10610 if (currentTNode.child == null && tNode.parent !== null) {
10611 // We are in the same view, which means we are adding content node to the parent view.
10612 currentTNode.child = tNode;
10613 }
10614 }
10615 else {
10616 if (currentTNode.next === null) {
10617 // In the case of i18n the `currentTNode` may already be linked, in which case we don't want
10618 // to break the links which i18n created.
10619 currentTNode.next = tNode;
10620 }
10621 }
10622 }
10623 return tNode;
10624}
10625/**
10626 * When elements are created dynamically after a view blueprint is created (e.g. through
10627 * i18nApply()), we need to adjust the blueprint for future
10628 * template passes.
10629 *
10630 * @param tView `TView` associated with `LView`
10631 * @param lView The `LView` containing the blueprint to adjust
10632 * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
10633 * @param initialValue Initial value to store in blueprint
10634 */
10635function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
10636 if (numSlotsToAlloc === 0)
10637 return -1;
10638 if (ngDevMode) {
10639 assertFirstCreatePass(tView);
10640 assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
10641 assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
10642 assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
10643 assertFirstUpdatePass(tView);
10644 }
10645 const allocIdx = lView.length;
10646 for (let i = 0; i < numSlotsToAlloc; i++) {
10647 lView.push(initialValue);
10648 tView.blueprint.push(initialValue);
10649 tView.data.push(null);
10650 }
10651 return allocIdx;
10652}
10653//////////////////////////
10654//// Render
10655//////////////////////////
10656/**
10657 * Processes a view in the creation mode. This includes a number of steps in a specific order:
10658 * - creating view query functions (if any);
10659 * - executing a template function in the creation mode;
10660 * - updating static queries (if any);
10661 * - creating child components defined in a given view.
10662 */
10663function renderView(tView, lView, context) {
10664 ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
10665 enterView(lView);
10666 try {
10667 const viewQuery = tView.viewQuery;
10668 if (viewQuery !== null) {
10669 executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
10670 }
10671 // Execute a template associated with this view, if it exists. A template function might not be
10672 // defined for the root component views.
10673 const templateFn = tView.template;
10674 if (templateFn !== null) {
10675 executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
10676 }
10677 // This needs to be set before children are processed to support recursive components.
10678 // This must be set to false immediately after the first creation run because in an
10679 // ngFor loop, all the views will be created together before update mode runs and turns
10680 // off firstCreatePass. If we don't set it here, instances will perform directive
10681 // matching, etc again and again.
10682 if (tView.firstCreatePass) {
10683 tView.firstCreatePass = false;
10684 }
10685 // We resolve content queries specifically marked as `static` in creation mode. Dynamic
10686 // content queries are resolved during change detection (i.e. update mode), after embedded
10687 // views are refreshed (see block above).
10688 if (tView.staticContentQueries) {
10689 refreshContentQueries(tView, lView);
10690 }
10691 // We must materialize query results before child components are processed
10692 // in case a child component has projected a container. The LContainer needs
10693 // to exist so the embedded views are properly attached by the container.
10694 if (tView.staticViewQueries) {
10695 executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
10696 }
10697 // Render child component views.
10698 const components = tView.components;
10699 if (components !== null) {
10700 renderChildComponents(lView, components);
10701 }
10702 }
10703 catch (error) {
10704 // If we didn't manage to get past the first template pass due to
10705 // an error, mark the view as corrupted so we can try to recover.
10706 if (tView.firstCreatePass) {
10707 tView.incompleteFirstPass = true;
10708 tView.firstCreatePass = false;
10709 }
10710 throw error;
10711 }
10712 finally {
10713 lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
10714 leaveView();
10715 }
10716}
10717/**
10718 * Processes a view in update mode. This includes a number of steps in a specific order:
10719 * - executing a template function in update mode;
10720 * - executing hooks;
10721 * - refreshing queries;
10722 * - setting host bindings;
10723 * - refreshing child (embedded and component) views.
10724 */
10725function refreshView(tView, lView, templateFn, context) {
10726 ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
10727 const flags = lView[FLAGS];
10728 if ((flags & 128 /* LViewFlags.Destroyed */) === 128 /* LViewFlags.Destroyed */)
10729 return;
10730 enterView(lView);
10731 // Check no changes mode is a dev only mode used to verify that bindings have not changed
10732 // since they were assigned. We do not want to execute lifecycle hooks in that mode.
10733 const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
10734 try {
10735 resetPreOrderHookFlags(lView);
10736 setBindingIndex(tView.bindingStartIndex);
10737 if (templateFn !== null) {
10738 executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
10739 }
10740 const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
10741 // execute pre-order hooks (OnInit, OnChanges, DoCheck)
10742 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10743 if (!isInCheckNoChangesPass) {
10744 if (hooksInitPhaseCompleted) {
10745 const preOrderCheckHooks = tView.preOrderCheckHooks;
10746 if (preOrderCheckHooks !== null) {
10747 executeCheckHooks(lView, preOrderCheckHooks, null);
10748 }
10749 }
10750 else {
10751 const preOrderHooks = tView.preOrderHooks;
10752 if (preOrderHooks !== null) {
10753 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
10754 }
10755 incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
10756 }
10757 }
10758 // First mark transplanted views that are declared in this lView as needing a refresh at their
10759 // insertion points. This is needed to avoid the situation where the template is defined in this
10760 // `LView` but its declaration appears after the insertion component.
10761 markTransplantedViewsForRefresh(lView);
10762 refreshEmbeddedViews(lView);
10763 // Content query results must be refreshed before content hooks are called.
10764 if (tView.contentQueries !== null) {
10765 refreshContentQueries(tView, lView);
10766 }
10767 // execute content hooks (AfterContentInit, AfterContentChecked)
10768 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10769 if (!isInCheckNoChangesPass) {
10770 if (hooksInitPhaseCompleted) {
10771 const contentCheckHooks = tView.contentCheckHooks;
10772 if (contentCheckHooks !== null) {
10773 executeCheckHooks(lView, contentCheckHooks);
10774 }
10775 }
10776 else {
10777 const contentHooks = tView.contentHooks;
10778 if (contentHooks !== null) {
10779 executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
10780 }
10781 incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
10782 }
10783 }
10784 processHostBindingOpCodes(tView, lView);
10785 // Refresh child component views.
10786 const components = tView.components;
10787 if (components !== null) {
10788 refreshChildComponents(lView, components);
10789 }
10790 // View queries must execute after refreshing child components because a template in this view
10791 // could be inserted in a child component. If the view query executes before child component
10792 // refresh, the template might not yet be inserted.
10793 const viewQuery = tView.viewQuery;
10794 if (viewQuery !== null) {
10795 executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
10796 }
10797 // execute view hooks (AfterViewInit, AfterViewChecked)
10798 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10799 if (!isInCheckNoChangesPass) {
10800 if (hooksInitPhaseCompleted) {
10801 const viewCheckHooks = tView.viewCheckHooks;
10802 if (viewCheckHooks !== null) {
10803 executeCheckHooks(lView, viewCheckHooks);
10804 }
10805 }
10806 else {
10807 const viewHooks = tView.viewHooks;
10808 if (viewHooks !== null) {
10809 executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
10810 }
10811 incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
10812 }
10813 }
10814 if (tView.firstUpdatePass === true) {
10815 // We need to make sure that we only flip the flag on successful `refreshView` only
10816 // Don't do this in `finally` block.
10817 // If we did this in `finally` block then an exception could block the execution of styling
10818 // instructions which in turn would be unable to insert themselves into the styling linked
10819 // list. The result of this would be that if the exception would not be throw on subsequent CD
10820 // the styling would be unable to process it data and reflect to the DOM.
10821 tView.firstUpdatePass = false;
10822 }
10823 // Do not reset the dirty state when running in check no changes mode. We don't want components
10824 // to behave differently depending on whether check no changes is enabled or not. For example:
10825 // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
10826 // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
10827 // no changes cycle, the component would be not be dirty for the next update pass. This would
10828 // be different in production mode where the component dirty state is not reset.
10829 if (!isInCheckNoChangesPass) {
10830 lView[FLAGS] &= ~(32 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
10831 }
10832 if (lView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
10833 lView[FLAGS] &= ~512 /* LViewFlags.RefreshTransplantedView */;
10834 updateTransplantedViewCount(lView[PARENT], -1);
10835 }
10836 }
10837 finally {
10838 leaveView();
10839 }
10840}
10841function executeTemplate(tView, lView, templateFn, rf, context) {
10842 const prevSelectedIndex = getSelectedIndex();
10843 const isUpdatePhase = rf & 2 /* RenderFlags.Update */;
10844 try {
10845 setSelectedIndex(-1);
10846 if (isUpdatePhase && lView.length > HEADER_OFFSET) {
10847 // When we're updating, inherently select 0 so we don't
10848 // have to generate that instruction for most update blocks.
10849 selectIndexInternal(tView, lView, HEADER_OFFSET, !!ngDevMode && isInCheckNoChangesMode());
10850 }
10851 const preHookType = isUpdatePhase ? 2 /* ProfilerEvent.TemplateUpdateStart */ : 0 /* ProfilerEvent.TemplateCreateStart */;
10852 profiler(preHookType, context);
10853 templateFn(rf, context);
10854 }
10855 finally {
10856 setSelectedIndex(prevSelectedIndex);
10857 const postHookType = isUpdatePhase ? 3 /* ProfilerEvent.TemplateUpdateEnd */ : 1 /* ProfilerEvent.TemplateCreateEnd */;
10858 profiler(postHookType, context);
10859 }
10860}
10861//////////////////////////
10862//// Element
10863//////////////////////////
10864function executeContentQueries(tView, tNode, lView) {
10865 if (isContentQueryHost(tNode)) {
10866 const start = tNode.directiveStart;
10867 const end = tNode.directiveEnd;
10868 for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
10869 const def = tView.data[directiveIndex];
10870 if (def.contentQueries) {
10871 def.contentQueries(1 /* RenderFlags.Create */, lView[directiveIndex], directiveIndex);
10872 }
10873 }
10874 }
10875}
10876/**
10877 * Creates directive instances.
10878 */
10879function createDirectivesInstances(tView, lView, tNode) {
10880 if (!getBindingsEnabled())
10881 return;
10882 instantiateAllDirectives(tView, lView, tNode, getNativeByTNode(tNode, lView));
10883 if ((tNode.flags & 64 /* TNodeFlags.hasHostBindings */) === 64 /* TNodeFlags.hasHostBindings */) {
10884 invokeDirectivesHostBindings(tView, lView, tNode);
10885 }
10886}
10887/**
10888 * Takes a list of local names and indices and pushes the resolved local variable values
10889 * to LView in the same order as they are loaded in the template with load().
10890 */
10891function saveResolvedLocalsInData(viewData, tNode, localRefExtractor = getNativeByTNode) {
10892 const localNames = tNode.localNames;
10893 if (localNames !== null) {
10894 let localIndex = tNode.index + 1;
10895 for (let i = 0; i < localNames.length; i += 2) {
10896 const index = localNames[i + 1];
10897 const value = index === -1 ?
10898 localRefExtractor(tNode, viewData) :
10899 viewData[index];
10900 viewData[localIndex++] = value;
10901 }
10902 }
10903}
10904/**
10905 * Gets TView from a template function or creates a new TView
10906 * if it doesn't already exist.
10907 *
10908 * @param def ComponentDef
10909 * @returns TView
10910 */
10911function getOrCreateComponentTView(def) {
10912 const tView = def.tView;
10913 // Create a TView if there isn't one, or recreate it if the first create pass didn't
10914 // complete successfully since we can't know for sure whether it's in a usable shape.
10915 if (tView === null || tView.incompleteFirstPass) {
10916 // Declaration node here is null since this function is called when we dynamically create a
10917 // component and hence there is no declaration.
10918 const declTNode = null;
10919 return def.tView = createTView(1 /* TViewType.Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
10920 }
10921 return tView;
10922}
10923/**
10924 * Creates a TView instance
10925 *
10926 * @param type Type of `TView`.
10927 * @param declTNode Declaration location of this `TView`.
10928 * @param templateFn Template function
10929 * @param decls The number of nodes, local refs, and pipes in this template
10930 * @param directives Registry of directives for this view
10931 * @param pipes Registry of pipes for this view
10932 * @param viewQuery View queries for this view
10933 * @param schemas Schemas for this view
10934 * @param consts Constants for this view
10935 */
10936function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
10937 ngDevMode && ngDevMode.tView++;
10938 const bindingStartIndex = HEADER_OFFSET + decls;
10939 // This length does not yet contain host bindings from child directives because at this point,
10940 // we don't know which directives are active on this template. As soon as a directive is matched
10941 // that has a host binding, we will update the blueprint with that def's hostVars count.
10942 const initialViewLength = bindingStartIndex + vars;
10943 const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
10944 const consts = typeof constsOrFactory === 'function' ? constsOrFactory() : constsOrFactory;
10945 const tView = blueprint[TVIEW] = {
10946 type: type,
10947 blueprint: blueprint,
10948 template: templateFn,
10949 queries: null,
10950 viewQuery: viewQuery,
10951 declTNode: declTNode,
10952 data: blueprint.slice().fill(null, bindingStartIndex),
10953 bindingStartIndex: bindingStartIndex,
10954 expandoStartIndex: initialViewLength,
10955 hostBindingOpCodes: null,
10956 firstCreatePass: true,
10957 firstUpdatePass: true,
10958 staticViewQueries: false,
10959 staticContentQueries: false,
10960 preOrderHooks: null,
10961 preOrderCheckHooks: null,
10962 contentHooks: null,
10963 contentCheckHooks: null,
10964 viewHooks: null,
10965 viewCheckHooks: null,
10966 destroyHooks: null,
10967 cleanup: null,
10968 contentQueries: null,
10969 components: null,
10970 directiveRegistry: typeof directives === 'function' ? directives() : directives,
10971 pipeRegistry: typeof pipes === 'function' ? pipes() : pipes,
10972 firstChild: null,
10973 schemas: schemas,
10974 consts: consts,
10975 incompleteFirstPass: false
10976 };
10977 if (ngDevMode) {
10978 // For performance reasons it is important that the tView retains the same shape during runtime.
10979 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
10980 // prevent class transitions.
10981 Object.seal(tView);
10982 }
10983 return tView;
10984}
10985function createViewBlueprint(bindingStartIndex, initialViewLength) {
10986 const blueprint = [];
10987 for (let i = 0; i < initialViewLength; i++) {
10988 blueprint.push(i < bindingStartIndex ? null : NO_CHANGE);
10989 }
10990 return blueprint;
10991}
10992/**
10993 * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
10994 *
10995 * @param rendererFactory Factory function to create renderer instance.
10996 * @param elementOrSelector Render element or CSS selector to locate the element.
10997 * @param encapsulation View Encapsulation defined for component that requests host element.
10998 */
10999function locateHostElement(renderer, elementOrSelector, encapsulation) {
11000 // When using native Shadow DOM, do not clear host element to allow native slot projection
11001 const preserveContent = encapsulation === ViewEncapsulation.ShadowDom;
11002 return renderer.selectRootElement(elementOrSelector, preserveContent);
11003}
11004/**
11005 * Saves context for this cleanup function in LView.cleanupInstances.
11006 *
11007 * On the first template pass, saves in TView:
11008 * - Cleanup function
11009 * - Index of context we just saved in LView.cleanupInstances
11010 *
11011 * This function can also be used to store instance specific cleanup fns. In that case the `context`
11012 * is `null` and the function is store in `LView` (rather than it `TView`).
11013 */
11014function storeCleanupWithContext(tView, lView, context, cleanupFn) {
11015 const lCleanup = getOrCreateLViewCleanup(lView);
11016 if (context === null) {
11017 // If context is null that this is instance specific callback. These callbacks can only be
11018 // inserted after template shared instances. For this reason in ngDevMode we freeze the TView.
11019 if (ngDevMode) {
11020 Object.freeze(getOrCreateTViewCleanup(tView));
11021 }
11022 lCleanup.push(cleanupFn);
11023 }
11024 else {
11025 lCleanup.push(context);
11026 if (tView.firstCreatePass) {
11027 getOrCreateTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1);
11028 }
11029 }
11030}
11031function createTNode(tView, tParent, type, index, value, attrs) {
11032 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
11033 // `view_engine_compatibility` for additional context.
11034 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
11035 ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\'');
11036 ngDevMode && ngDevMode.tNode++;
11037 ngDevMode && tParent && assertTNodeForTView(tParent, tView);
11038 let injectorIndex = tParent ? tParent.injectorIndex : -1;
11039 const tNode = {
11040 type,
11041 index,
11042 insertBeforeIndex: null,
11043 injectorIndex,
11044 directiveStart: -1,
11045 directiveEnd: -1,
11046 directiveStylingLast: -1,
11047 componentOffset: -1,
11048 propertyBindings: null,
11049 flags: 0,
11050 providerIndexes: 0,
11051 value: value,
11052 attrs: attrs,
11053 mergedAttrs: null,
11054 localNames: null,
11055 initialInputs: undefined,
11056 inputs: null,
11057 outputs: null,
11058 tViews: null,
11059 next: null,
11060 projectionNext: null,
11061 child: null,
11062 parent: tParent,
11063 projection: null,
11064 styles: null,
11065 stylesWithoutHost: null,
11066 residualStyles: undefined,
11067 classes: null,
11068 classesWithoutHost: null,
11069 residualClasses: undefined,
11070 classBindings: 0,
11071 styleBindings: 0,
11072 };
11073 if (ngDevMode) {
11074 // For performance reasons it is important that the tNode retains the same shape during runtime.
11075 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
11076 // prevent class transitions.
11077 Object.seal(tNode);
11078 }
11079 return tNode;
11080}
11081/**
11082 * Generates the `PropertyAliases` data structure from the provided input/output mapping.
11083 * @param aliasMap Input/output mapping from the directive definition.
11084 * @param directiveIndex Index of the directive.
11085 * @param propertyAliases Object in which to store the results.
11086 * @param hostDirectiveAliasMap Object used to alias or filter out properties for host directives.
11087 * If the mapping is provided, it'll act as an allowlist, as well as a mapping of what public
11088 * name inputs/outputs should be exposed under.
11089 */
11090function generatePropertyAliases(aliasMap, directiveIndex, propertyAliases, hostDirectiveAliasMap) {
11091 for (let publicName in aliasMap) {
11092 if (aliasMap.hasOwnProperty(publicName)) {
11093 propertyAliases = propertyAliases === null ? {} : propertyAliases;
11094 const internalName = aliasMap[publicName];
11095 // If there are no host directive mappings, we want to remap using the alias map from the
11096 // definition itself. If there is an alias map, it has two functions:
11097 // 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
11098 // ones inside the host directive map will be exposed on the host.
11099 // 2. The public name of the property is aliased using the host directive alias map, rather
11100 // than the alias map from the definition.
11101 if (hostDirectiveAliasMap === null) {
11102 addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName);
11103 }
11104 else if (hostDirectiveAliasMap.hasOwnProperty(publicName)) {
11105 addPropertyAlias(propertyAliases, directiveIndex, hostDirectiveAliasMap[publicName], internalName);
11106 }
11107 }
11108 }
11109 return propertyAliases;
11110}
11111function addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName) {
11112 if (propertyAliases.hasOwnProperty(publicName)) {
11113 propertyAliases[publicName].push(directiveIndex, internalName);
11114 }
11115 else {
11116 propertyAliases[publicName] = [directiveIndex, internalName];
11117 }
11118}
11119/**
11120 * Initializes data structures required to work with directive inputs and outputs.
11121 * Initialization is done for all directives matched on a given TNode.
11122 */
11123function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
11124 ngDevMode && assertFirstCreatePass(tView);
11125 const start = tNode.directiveStart;
11126 const end = tNode.directiveEnd;
11127 const tViewData = tView.data;
11128 const tNodeAttrs = tNode.attrs;
11129 const inputsFromAttrs = [];
11130 let inputsStore = null;
11131 let outputsStore = null;
11132 for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
11133 const directiveDef = tViewData[directiveIndex];
11134 const aliasData = hostDirectiveDefinitionMap ? hostDirectiveDefinitionMap.get(directiveDef) : null;
11135 const aliasedInputs = aliasData ? aliasData.inputs : null;
11136 const aliasedOutputs = aliasData ? aliasData.outputs : null;
11137 inputsStore =
11138 generatePropertyAliases(directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
11139 outputsStore =
11140 generatePropertyAliases(directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
11141 // Do not use unbound attributes as inputs to structural directives, since structural
11142 // directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
11143 // TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
11144 // should be set for inline templates.
11145 const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
11146 generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs) :
11147 null;
11148 inputsFromAttrs.push(initialInputs);
11149 }
11150 if (inputsStore !== null) {
11151 if (inputsStore.hasOwnProperty('class')) {
11152 tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
11153 }
11154 if (inputsStore.hasOwnProperty('style')) {
11155 tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
11156 }
11157 }
11158 tNode.initialInputs = inputsFromAttrs;
11159 tNode.inputs = inputsStore;
11160 tNode.outputs = outputsStore;
11161}
11162/**
11163 * Mapping between attributes names that don't correspond to their element property names.
11164 *
11165 * Performance note: this function is written as a series of if checks (instead of, say, a property
11166 * object lookup) for performance reasons - the series of `if` checks seems to be the fastest way of
11167 * mapping property names. Do NOT change without benchmarking.
11168 *
11169 * Note: this mapping has to be kept in sync with the equally named mapping in the template
11170 * type-checking machinery of ngtsc.
11171 */
11172function mapPropName(name) {
11173 if (name === 'class')
11174 return 'className';
11175 if (name === 'for')
11176 return 'htmlFor';
11177 if (name === 'formaction')
11178 return 'formAction';
11179 if (name === 'innerHtml')
11180 return 'innerHTML';
11181 if (name === 'readonly')
11182 return 'readOnly';
11183 if (name === 'tabindex')
11184 return 'tabIndex';
11185 return name;
11186}
11187function elementPropertyInternal(tView, tNode, lView, propName, value, renderer, sanitizer, nativeOnly) {
11188 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
11189 const element = getNativeByTNode(tNode, lView);
11190 let inputData = tNode.inputs;
11191 let dataValue;
11192 if (!nativeOnly && inputData != null && (dataValue = inputData[propName])) {
11193 setInputsForProperty(tView, lView, dataValue, propName, value);
11194 if (isComponentHost(tNode))
11195 markDirtyIfOnPush(lView, tNode.index);
11196 if (ngDevMode) {
11197 setNgReflectProperties(lView, element, tNode.type, dataValue, value);
11198 }
11199 }
11200 else if (tNode.type & 3 /* TNodeType.AnyRNode */) {
11201 propName = mapPropName(propName);
11202 if (ngDevMode) {
11203 validateAgainstEventProperties(propName);
11204 if (!isPropertyValid(element, propName, tNode.value, tView.schemas)) {
11205 handleUnknownPropertyError(propName, tNode.value, tNode.type, lView);
11206 }
11207 ngDevMode.rendererSetProperty++;
11208 }
11209 // It is assumed that the sanitizer is only added when the compiler determines that the
11210 // property is risky, so sanitization can be done without further checks.
11211 value = sanitizer != null ? sanitizer(value, tNode.value || '', propName) : value;
11212 renderer.setProperty(element, propName, value);
11213 }
11214 else if (tNode.type & 12 /* TNodeType.AnyContainer */) {
11215 // If the node is a container and the property didn't
11216 // match any of the inputs or schemas we should throw.
11217 if (ngDevMode && !matchingSchemas(tView.schemas, tNode.value)) {
11218 handleUnknownPropertyError(propName, tNode.value, tNode.type, lView);
11219 }
11220 }
11221}
11222/** If node is an OnPush component, marks its LView dirty. */
11223function markDirtyIfOnPush(lView, viewIndex) {
11224 ngDevMode && assertLView(lView);
11225 const childComponentLView = getComponentLViewByIndex(viewIndex, lView);
11226 if (!(childComponentLView[FLAGS] & 16 /* LViewFlags.CheckAlways */)) {
11227 childComponentLView[FLAGS] |= 32 /* LViewFlags.Dirty */;
11228 }
11229}
11230function setNgReflectProperty(lView, element, type, attrName, value) {
11231 const renderer = lView[RENDERER];
11232 attrName = normalizeDebugBindingName(attrName);
11233 const debugValue = normalizeDebugBindingValue(value);
11234 if (type & 3 /* TNodeType.AnyRNode */) {
11235 if (value == null) {
11236 renderer.removeAttribute(element, attrName);
11237 }
11238 else {
11239 renderer.setAttribute(element, attrName, debugValue);
11240 }
11241 }
11242 else {
11243 const textContent = escapeCommentText(`bindings=${JSON.stringify({ [attrName]: debugValue }, null, 2)}`);
11244 renderer.setValue(element, textContent);
11245 }
11246}
11247function setNgReflectProperties(lView, element, type, dataValue, value) {
11248 if (type & (3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */)) {
11249 /**
11250 * dataValue is an array containing runtime input or output names for the directives:
11251 * i+0: directive instance index
11252 * i+1: privateName
11253 *
11254 * e.g. [0, 'change', 'change-minified']
11255 * we want to set the reflected property with the privateName: dataValue[i+1]
11256 */
11257 for (let i = 0; i < dataValue.length; i += 2) {
11258 setNgReflectProperty(lView, element, type, dataValue[i + 1], value);
11259 }
11260 }
11261}
11262/**
11263 * Resolve the matched directives on a node.
11264 */
11265function resolveDirectives(tView, lView, tNode, localRefs) {
11266 // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
11267 // tsickle.
11268 ngDevMode && assertFirstCreatePass(tView);
11269 let hasDirectives = false;
11270 if (getBindingsEnabled()) {
11271 const exportsMap = localRefs === null ? null : { '': -1 };
11272 const matchResult = findDirectiveDefMatches(tView, tNode);
11273 let directiveDefs;
11274 let hostDirectiveDefs;
11275 if (matchResult === null) {
11276 directiveDefs = hostDirectiveDefs = null;
11277 }
11278 else {
11279 [directiveDefs, hostDirectiveDefs] = matchResult;
11280 }
11281 if (directiveDefs !== null) {
11282 hasDirectives = true;
11283 initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
11284 }
11285 if (exportsMap)
11286 cacheMatchingLocalNames(tNode, localRefs, exportsMap);
11287 }
11288 // Merge the template attrs last so that they have the highest priority.
11289 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
11290 return hasDirectives;
11291}
11292/** Initializes the data structures necessary for a list of directives to be instantiated. */
11293function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
11294 ngDevMode && assertFirstCreatePass(tView);
11295 // Publishes the directive types to DI so they can be injected. Needs to
11296 // happen in a separate pass before the TNode flags have been initialized.
11297 for (let i = 0; i < directives.length; i++) {
11298 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
11299 }
11300 initTNodeFlags(tNode, tView.data.length, directives.length);
11301 // When the same token is provided by several directives on the same node, some rules apply in
11302 // the viewEngine:
11303 // - viewProviders have priority over providers
11304 // - the last directive in NgModule.declarations has priority over the previous one
11305 // So to match these rules, the order in which providers are added in the arrays is very
11306 // important.
11307 for (let i = 0; i < directives.length; i++) {
11308 const def = directives[i];
11309 if (def.providersResolver)
11310 def.providersResolver(def);
11311 }
11312 let preOrderHooksFound = false;
11313 let preOrderCheckHooksFound = false;
11314 let directiveIdx = allocExpando(tView, lView, directives.length, null);
11315 ngDevMode &&
11316 assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
11317 for (let i = 0; i < directives.length; i++) {
11318 const def = directives[i];
11319 // Merge the attrs in the order of matches. This assumes that the first directive is the
11320 // component itself, so that the component has the least priority.
11321 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
11322 configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
11323 saveNameToExportMap(directiveIdx, def, exportsMap);
11324 if (def.contentQueries !== null)
11325 tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
11326 if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
11327 tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
11328 const lifeCycleHooks = def.type.prototype;
11329 // Only push a node index into the preOrderHooks array if this is the first
11330 // pre-order hook found on this node.
11331 if (!preOrderHooksFound &&
11332 (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
11333 // We will push the actual hook function into this array later during dir instantiation.
11334 // We cannot do it now because we must ensure hooks are registered in the same
11335 // order that directives are created (i.e. injection order).
11336 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
11337 preOrderHooksFound = true;
11338 }
11339 if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
11340 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
11341 preOrderCheckHooksFound = true;
11342 }
11343 directiveIdx++;
11344 }
11345 initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
11346}
11347/**
11348 * Add `hostBindings` to the `TView.hostBindingOpCodes`.
11349 *
11350 * @param tView `TView` to which the `hostBindings` should be added.
11351 * @param tNode `TNode` the element which contains the directive
11352 * @param directiveIdx Directive index in view.
11353 * @param directiveVarsIdx Where will the directive's vars be stored
11354 * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
11355 */
11356function registerHostBindingOpCodes(tView, tNode, directiveIdx, directiveVarsIdx, def) {
11357 ngDevMode && assertFirstCreatePass(tView);
11358 const hostBindings = def.hostBindings;
11359 if (hostBindings) {
11360 let hostBindingOpCodes = tView.hostBindingOpCodes;
11361 if (hostBindingOpCodes === null) {
11362 hostBindingOpCodes = tView.hostBindingOpCodes = [];
11363 }
11364 const elementIndx = ~tNode.index;
11365 if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
11366 // Conditionally add select element so that we are more efficient in execution.
11367 // NOTE: this is strictly not necessary and it trades code size for runtime perf.
11368 // (We could just always add it.)
11369 hostBindingOpCodes.push(elementIndx);
11370 }
11371 hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
11372 }
11373}
11374/**
11375 * Returns the last selected element index in the `HostBindingOpCodes`
11376 *
11377 * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
11378 * if it changes. This method returns the last index (or '0' if not found.)
11379 *
11380 * Selected element index are only the ones which are negative.
11381 */
11382function lastSelectedElementIdx(hostBindingOpCodes) {
11383 let i = hostBindingOpCodes.length;
11384 while (i > 0) {
11385 const value = hostBindingOpCodes[--i];
11386 if (typeof value === 'number' && value < 0) {
11387 return value;
11388 }
11389 }
11390 return 0;
11391}
11392/**
11393 * Instantiate all the directives that were previously resolved on the current node.
11394 */
11395function instantiateAllDirectives(tView, lView, tNode, native) {
11396 const start = tNode.directiveStart;
11397 const end = tNode.directiveEnd;
11398 // The component view needs to be created before creating the node injector
11399 // since it is used to inject some special symbols like `ChangeDetectorRef`.
11400 if (isComponentHost(tNode)) {
11401 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */);
11402 addComponentLogic(lView, tNode, tView.data[start + tNode.componentOffset]);
11403 }
11404 if (!tView.firstCreatePass) {
11405 getOrCreateNodeInjectorForNode(tNode, lView);
11406 }
11407 attachPatchData(native, lView);
11408 const initialInputs = tNode.initialInputs;
11409 for (let i = start; i < end; i++) {
11410 const def = tView.data[i];
11411 const directive = getNodeInjectable(lView, tView, i, tNode);
11412 attachPatchData(directive, lView);
11413 if (initialInputs !== null) {
11414 setInputsFromAttrs(lView, i - start, directive, def, tNode, initialInputs);
11415 }
11416 if (isComponentDef(def)) {
11417 const componentView = getComponentLViewByIndex(tNode.index, lView);
11418 componentView[CONTEXT] = getNodeInjectable(lView, tView, i, tNode);
11419 }
11420 }
11421}
11422function invokeDirectivesHostBindings(tView, lView, tNode) {
11423 const start = tNode.directiveStart;
11424 const end = tNode.directiveEnd;
11425 const elementIndex = tNode.index;
11426 const currentDirectiveIndex = getCurrentDirectiveIndex();
11427 try {
11428 setSelectedIndex(elementIndex);
11429 for (let dirIndex = start; dirIndex < end; dirIndex++) {
11430 const def = tView.data[dirIndex];
11431 const directive = lView[dirIndex];
11432 setCurrentDirectiveIndex(dirIndex);
11433 if (def.hostBindings !== null || def.hostVars !== 0 || def.hostAttrs !== null) {
11434 invokeHostBindingsInCreationMode(def, directive);
11435 }
11436 }
11437 }
11438 finally {
11439 setSelectedIndex(-1);
11440 setCurrentDirectiveIndex(currentDirectiveIndex);
11441 }
11442}
11443/**
11444 * Invoke the host bindings in creation mode.
11445 *
11446 * @param def `DirectiveDef` which may contain the `hostBindings` function.
11447 * @param directive Instance of directive.
11448 */
11449function invokeHostBindingsInCreationMode(def, directive) {
11450 if (def.hostBindings !== null) {
11451 def.hostBindings(1 /* RenderFlags.Create */, directive);
11452 }
11453}
11454/**
11455 * Matches the current node against all available selectors.
11456 * If a component is matched (at most one), it is returned in first position in the array.
11457 */
11458function findDirectiveDefMatches(tView, tNode) {
11459 var _a;
11460 ngDevMode && assertFirstCreatePass(tView);
11461 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
11462 const registry = tView.directiveRegistry;
11463 let matches = null;
11464 let hostDirectiveDefs = null;
11465 if (registry) {
11466 for (let i = 0; i < registry.length; i++) {
11467 const def = registry[i];
11468 if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) {
11469 matches || (matches = []);
11470 if (isComponentDef(def)) {
11471 if (ngDevMode) {
11472 assertTNodeType(tNode, 2 /* TNodeType.Element */, `"${tNode.value}" tags cannot be used as component hosts. ` +
11473 `Please use a different tag to activate the ${stringify(def.type)} component.`);
11474 if (isComponentHost(tNode)) {
11475 throwMultipleComponentError(tNode, matches.find(isComponentDef).type, def.type);
11476 }
11477 }
11478 // Components are inserted at the front of the matches array so that their lifecycle
11479 // hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
11480 // compatibility. This logic doesn't make sense with host directives, because it
11481 // would allow the host directives to undo any overrides the host may have made.
11482 // To handle this case, the host directives of components are inserted at the beginning
11483 // of the array, followed by the component. As such, the insertion order is as follows:
11484 // 1. Host directives belonging to the selector-matched component.
11485 // 2. Selector-matched component.
11486 // 3. Host directives belonging to selector-matched directives.
11487 // 4. Selector-matched directives.
11488 if (def.findHostDirectiveDefs !== null) {
11489 const hostDirectiveMatches = [];
11490 hostDirectiveDefs = hostDirectiveDefs || new Map();
11491 def.findHostDirectiveDefs(def, hostDirectiveMatches, hostDirectiveDefs);
11492 // Add all host directives declared on this component, followed by the component itself.
11493 // Host directives should execute first so the host has a chance to override changes
11494 // to the DOM made by them.
11495 matches.unshift(...hostDirectiveMatches, def);
11496 // Component is offset starting from the beginning of the host directives array.
11497 const componentOffset = hostDirectiveMatches.length;
11498 markAsComponentHost(tView, tNode, componentOffset);
11499 }
11500 else {
11501 // No host directives on this component, just add the
11502 // component def to the beginning of the matches.
11503 matches.unshift(def);
11504 markAsComponentHost(tView, tNode, 0);
11505 }
11506 }
11507 else {
11508 // Append any host directives to the matches first.
11509 hostDirectiveDefs = hostDirectiveDefs || new Map();
11510 (_a = def.findHostDirectiveDefs) === null || _a === void 0 ? void 0 : _a.call(def, def, matches, hostDirectiveDefs);
11511 matches.push(def);
11512 }
11513 }
11514 }
11515 }
11516 return matches === null ? null : [matches, hostDirectiveDefs];
11517}
11518/**
11519 * Marks a given TNode as a component's host. This consists of:
11520 * - setting the component offset on the TNode.
11521 * - storing index of component's host element so it will be queued for view refresh during CD.
11522 */
11523function markAsComponentHost(tView, hostTNode, componentOffset) {
11524 ngDevMode && assertFirstCreatePass(tView);
11525 ngDevMode && assertGreaterThan(componentOffset, -1, 'componentOffset must be great than -1');
11526 hostTNode.componentOffset = componentOffset;
11527 (tView.components || (tView.components = [])).push(hostTNode.index);
11528}
11529/** Caches local names and their matching directive indices for query and template lookups. */
11530function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
11531 if (localRefs) {
11532 const localNames = tNode.localNames = [];
11533 // Local names must be stored in tNode in the same order that localRefs are defined
11534 // in the template to ensure the data is loaded in the same slots as their refs
11535 // in the template (for template queries).
11536 for (let i = 0; i < localRefs.length; i += 2) {
11537 const index = exportsMap[localRefs[i + 1]];
11538 if (index == null)
11539 throw new RuntimeError(-301 /* RuntimeErrorCode.EXPORT_NOT_FOUND */, ngDevMode && `Export of name '${localRefs[i + 1]}' not found!`);
11540 localNames.push(localRefs[i], index);
11541 }
11542 }
11543}
11544/**
11545 * Builds up an export map as directives are created, so local refs can be quickly mapped
11546 * to their directive instances.
11547 */
11548function saveNameToExportMap(directiveIdx, def, exportsMap) {
11549 if (exportsMap) {
11550 if (def.exportAs) {
11551 for (let i = 0; i < def.exportAs.length; i++) {
11552 exportsMap[def.exportAs[i]] = directiveIdx;
11553 }
11554 }
11555 if (isComponentDef(def))
11556 exportsMap[''] = directiveIdx;
11557 }
11558}
11559/**
11560 * Initializes the flags on the current node, setting all indices to the initial index,
11561 * the directive count to 0, and adding the isComponent flag.
11562 * @param index the initial index
11563 */
11564function initTNodeFlags(tNode, index, numberOfDirectives) {
11565 ngDevMode &&
11566 assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
11567 tNode.flags |= 1 /* TNodeFlags.isDirectiveHost */;
11568 // When the first directive is created on a node, save the index
11569 tNode.directiveStart = index;
11570 tNode.directiveEnd = index + numberOfDirectives;
11571 tNode.providerIndexes = index;
11572}
11573/**
11574 * Setup directive for instantiation.
11575 *
11576 * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
11577 * as `LView`. `TView` gets the `DirectiveDef`.
11578 *
11579 * @param tView `TView`
11580 * @param tNode `TNode`
11581 * @param lView `LView`
11582 * @param directiveIndex Index where the directive will be stored in the Expando.
11583 * @param def `DirectiveDef`
11584 */
11585function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
11586 ngDevMode &&
11587 assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
11588 tView.data[directiveIndex] = def;
11589 const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
11590 // Even though `directiveFactory` will already be using `ɵɵdirectiveInject` in its generated code,
11591 // we also want to support `inject()` directly from the directive constructor context so we set
11592 // `ɵɵdirectiveInject` as the inject implementation here too.
11593 const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
11594 tView.blueprint[directiveIndex] = nodeInjectorFactory;
11595 lView[directiveIndex] = nodeInjectorFactory;
11596 registerHostBindingOpCodes(tView, tNode, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
11597}
11598function addComponentLogic(lView, hostTNode, def) {
11599 const native = getNativeByTNode(hostTNode, lView);
11600 const tView = getOrCreateComponentTView(def);
11601 // Only component views should be added to the view tree directly. Embedded views are
11602 // accessed through their containers because they may be removed / re-added later.
11603 const rendererFactory = lView[RENDERER_FACTORY];
11604 const componentView = addToViewTree(lView, createLView(lView, tView, null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, native, hostTNode, rendererFactory, rendererFactory.createRenderer(native, def), null, null, null));
11605 // Component view will always be created before any injected LContainers,
11606 // so this is a regular element, wrap it with the component view
11607 lView[hostTNode.index] = componentView;
11608}
11609function elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace) {
11610 if (ngDevMode) {
11611 assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
11612 validateAgainstEventAttributes(name);
11613 assertTNodeType(tNode, 2 /* TNodeType.Element */, `Attempted to set attribute \`${name}\` on a container node. ` +
11614 `Host bindings are not valid on ng-container or ng-template.`);
11615 }
11616 const element = getNativeByTNode(tNode, lView);
11617 setElementAttribute(lView[RENDERER], element, namespace, tNode.value, name, value, sanitizer);
11618}
11619function setElementAttribute(renderer, element, namespace, tagName, name, value, sanitizer) {
11620 if (value == null) {
11621 ngDevMode && ngDevMode.rendererRemoveAttribute++;
11622 renderer.removeAttribute(element, name, namespace);
11623 }
11624 else {
11625 ngDevMode && ngDevMode.rendererSetAttribute++;
11626 const strValue = sanitizer == null ? renderStringify(value) : sanitizer(value, tagName || '', name);
11627 renderer.setAttribute(element, name, strValue, namespace);
11628 }
11629}
11630/**
11631 * Sets initial input properties on directive instances from attribute data
11632 *
11633 * @param lView Current LView that is being processed.
11634 * @param directiveIndex Index of the directive in directives array
11635 * @param instance Instance of the directive on which to set the initial inputs
11636 * @param def The directive def that contains the list of inputs
11637 * @param tNode The static data for this node
11638 */
11639function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initialInputData) {
11640 const initialInputs = initialInputData[directiveIndex];
11641 if (initialInputs !== null) {
11642 const setInput = def.setInput;
11643 for (let i = 0; i < initialInputs.length;) {
11644 const publicName = initialInputs[i++];
11645 const privateName = initialInputs[i++];
11646 const value = initialInputs[i++];
11647 if (setInput !== null) {
11648 def.setInput(instance, value, publicName, privateName);
11649 }
11650 else {
11651 instance[privateName] = value;
11652 }
11653 if (ngDevMode) {
11654 const nativeElement = getNativeByTNode(tNode, lView);
11655 setNgReflectProperty(lView, nativeElement, tNode.type, privateName, value);
11656 }
11657 }
11658 }
11659}
11660/**
11661 * Generates initialInputData for a node and stores it in the template's static storage
11662 * so subsequent template invocations don't have to recalculate it.
11663 *
11664 * initialInputData is an array containing values that need to be set as input properties
11665 * for directives on this node, but only once on creation. We need this array to support
11666 * the case where you set an @Input property of a directive using attribute-like syntax.
11667 * e.g. if you have a `name` @Input, you can set it once like this:
11668 *
11669 * <my-component name="Bess"></my-component>
11670 *
11671 * @param inputs Input alias map that was generated from the directive def inputs.
11672 * @param directiveIndex Index of the directive that is currently being processed.
11673 * @param attrs Static attrs on this node.
11674 */
11675function generateInitialInputs(inputs, directiveIndex, attrs) {
11676 let inputsToStore = null;
11677 let i = 0;
11678 while (i < attrs.length) {
11679 const attrName = attrs[i];
11680 if (attrName === 0 /* AttributeMarker.NamespaceURI */) {
11681 // We do not allow inputs on namespaced attributes.
11682 i += 4;
11683 continue;
11684 }
11685 else if (attrName === 5 /* AttributeMarker.ProjectAs */) {
11686 // Skip over the `ngProjectAs` value.
11687 i += 2;
11688 continue;
11689 }
11690 // If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
11691 if (typeof attrName === 'number')
11692 break;
11693 if (inputs.hasOwnProperty(attrName)) {
11694 if (inputsToStore === null)
11695 inputsToStore = [];
11696 // Find the input's public name from the input store. Note that we can be found easier
11697 // through the directive def, but we want to do it using the inputs store so that it can
11698 // account for host directive aliases.
11699 const inputConfig = inputs[attrName];
11700 for (let j = 0; j < inputConfig.length; j += 2) {
11701 if (inputConfig[j] === directiveIndex) {
11702 inputsToStore.push(attrName, inputConfig[j + 1], attrs[i + 1]);
11703 // A directive can't have multiple inputs with the same name so we can break here.
11704 break;
11705 }
11706 }
11707 }
11708 i += 2;
11709 }
11710 return inputsToStore;
11711}
11712//////////////////////////
11713//// ViewContainer & View
11714//////////////////////////
11715/**
11716 * Creates a LContainer, either from a container instruction, or for a ViewContainerRef.
11717 *
11718 * @param hostNative The host element for the LContainer
11719 * @param hostTNode The host TNode for the LContainer
11720 * @param currentView The parent view of the LContainer
11721 * @param native The native comment element
11722 * @param isForViewContainerRef Optional a flag indicating the ViewContainerRef case
11723 * @returns LContainer
11724 */
11725function createLContainer(hostNative, currentView, native, tNode) {
11726 ngDevMode && assertLView(currentView);
11727 const lContainer = [
11728 hostNative,
11729 true,
11730 false,
11731 currentView,
11732 null,
11733 0,
11734 tNode,
11735 native,
11736 null,
11737 null, // moved views
11738 ];
11739 ngDevMode &&
11740 assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
11741 return lContainer;
11742}
11743/**
11744 * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
11745 * them by executing an associated template function.
11746 */
11747function refreshEmbeddedViews(lView) {
11748 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
11749 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
11750 const embeddedLView = lContainer[i];
11751 const embeddedTView = embeddedLView[TVIEW];
11752 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
11753 if (viewAttachedToChangeDetector(embeddedLView)) {
11754 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
11755 }
11756 }
11757 }
11758}
11759/**
11760 * Mark transplanted views as needing to be refreshed at their insertion points.
11761 *
11762 * @param lView The `LView` that may have transplanted views.
11763 */
11764function markTransplantedViewsForRefresh(lView) {
11765 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
11766 if (!lContainer[HAS_TRANSPLANTED_VIEWS])
11767 continue;
11768 const movedViews = lContainer[MOVED_VIEWS];
11769 ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
11770 for (let i = 0; i < movedViews.length; i++) {
11771 const movedLView = movedViews[i];
11772 const insertionLContainer = movedLView[PARENT];
11773 ngDevMode && assertLContainer(insertionLContainer);
11774 // We don't want to increment the counter if the moved LView was already marked for
11775 // refresh.
11776 if ((movedLView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) === 0) {
11777 updateTransplantedViewCount(insertionLContainer, 1);
11778 }
11779 // Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
11780 // those that aren't (declaration component === insertion component). In the latter case,
11781 // it's fine to add the flag, as we will clear it immediately in
11782 // `refreshEmbeddedViews` for the view currently being refreshed.
11783 movedLView[FLAGS] |= 512 /* LViewFlags.RefreshTransplantedView */;
11784 }
11785 }
11786}
11787/////////////
11788/**
11789 * Refreshes components by entering the component view and processing its bindings, queries, etc.
11790 *
11791 * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
11792 */
11793function refreshComponent(hostLView, componentHostIdx) {
11794 ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
11795 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
11796 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
11797 if (viewAttachedToChangeDetector(componentView)) {
11798 const tView = componentView[TVIEW];
11799 if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 32 /* LViewFlags.Dirty */)) {
11800 refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
11801 }
11802 else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
11803 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
11804 refreshContainsDirtyView(componentView);
11805 }
11806 }
11807}
11808/**
11809 * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
11810 * children or descendants of the given lView.
11811 *
11812 * @param lView The lView which contains descendant transplanted views that need to be refreshed.
11813 */
11814function refreshContainsDirtyView(lView) {
11815 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
11816 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
11817 const embeddedLView = lContainer[i];
11818 if (viewAttachedToChangeDetector(embeddedLView)) {
11819 if (embeddedLView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
11820 const embeddedTView = embeddedLView[TVIEW];
11821 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
11822 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
11823 }
11824 else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
11825 refreshContainsDirtyView(embeddedLView);
11826 }
11827 }
11828 }
11829 }
11830 const tView = lView[TVIEW];
11831 // Refresh child component views.
11832 const components = tView.components;
11833 if (components !== null) {
11834 for (let i = 0; i < components.length; i++) {
11835 const componentView = getComponentLViewByIndex(components[i], lView);
11836 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
11837 if (viewAttachedToChangeDetector(componentView) &&
11838 componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
11839 refreshContainsDirtyView(componentView);
11840 }
11841 }
11842 }
11843}
11844function renderComponent(hostLView, componentHostIdx) {
11845 ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
11846 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
11847 const componentTView = componentView[TVIEW];
11848 syncViewWithBlueprint(componentTView, componentView);
11849 renderView(componentTView, componentView, componentView[CONTEXT]);
11850}
11851/**
11852 * Syncs an LView instance with its blueprint if they have gotten out of sync.
11853 *
11854 * Typically, blueprints and their view instances should always be in sync, so the loop here
11855 * will be skipped. However, consider this case of two components side-by-side:
11856 *
11857 * App template:
11858 * ```
11859 * <comp></comp>
11860 * <comp></comp>
11861 * ```
11862 *
11863 * The following will happen:
11864 * 1. App template begins processing.
11865 * 2. First <comp> is matched as a component and its LView is created.
11866 * 3. Second <comp> is matched as a component and its LView is created.
11867 * 4. App template completes processing, so it's time to check child templates.
11868 * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
11869 * 6. Second <comp> template is checked. Its blueprint has been updated by the first
11870 * <comp> template, but its LView was created before this update, so it is out of sync.
11871 *
11872 * Note that embedded views inside ngFor loops will never be out of sync because these views
11873 * are processed as soon as they are created.
11874 *
11875 * @param tView The `TView` that contains the blueprint for syncing
11876 * @param lView The view to sync
11877 */
11878function syncViewWithBlueprint(tView, lView) {
11879 for (let i = lView.length; i < tView.blueprint.length; i++) {
11880 lView.push(tView.blueprint[i]);
11881 }
11882}
11883/**
11884 * Adds LView or LContainer to the end of the current view tree.
11885 *
11886 * This structure will be used to traverse through nested views to remove listeners
11887 * and call onDestroy callbacks.
11888 *
11889 * @param lView The view where LView or LContainer should be added
11890 * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header
11891 * @param lViewOrLContainer The LView or LContainer to add to the view tree
11892 * @returns The state passed in
11893 */
11894function addToViewTree(lView, lViewOrLContainer) {
11895 // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
11896 // to the end of the queue, which means if the developer retrieves the LContainers from RNodes out
11897 // of order, the change detection will run out of order, as the act of retrieving the the
11898 // LContainer from the RNode is what adds it to the queue.
11899 if (lView[CHILD_HEAD]) {
11900 lView[CHILD_TAIL][NEXT] = lViewOrLContainer;
11901 }
11902 else {
11903 lView[CHILD_HEAD] = lViewOrLContainer;
11904 }
11905 lView[CHILD_TAIL] = lViewOrLContainer;
11906 return lViewOrLContainer;
11907}
11908///////////////////////////////
11909//// Change detection
11910///////////////////////////////
11911/**
11912 * Marks current view and all ancestors dirty.
11913 *
11914 * Returns the root view because it is found as a byproduct of marking the view tree
11915 * dirty, and can be used by methods that consume markViewDirty() to easily schedule
11916 * change detection. Otherwise, such methods would need to traverse up the view tree
11917 * an additional time to get the root view and schedule a tick on it.
11918 *
11919 * @param lView The starting LView to mark dirty
11920 * @returns the root LView
11921 */
11922function markViewDirty(lView) {
11923 while (lView) {
11924 lView[FLAGS] |= 32 /* LViewFlags.Dirty */;
11925 const parent = getLViewParent(lView);
11926 // Stop traversing up as soon as you find a root view that wasn't attached to any container
11927 if (isRootView(lView) && !parent) {
11928 return lView;
11929 }
11930 // continue otherwise
11931 lView = parent;
11932 }
11933 return null;
11934}
11935function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
11936 const rendererFactory = lView[RENDERER_FACTORY];
11937 // Check no changes mode is a dev only mode used to verify that bindings have not changed
11938 // since they were assigned. We do not want to invoke renderer factory functions in that mode
11939 // to avoid any possible side-effects.
11940 const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
11941 if (!checkNoChangesMode && rendererFactory.begin)
11942 rendererFactory.begin();
11943 try {
11944 refreshView(tView, lView, tView.template, context);
11945 }
11946 catch (error) {
11947 if (notifyErrorHandler) {
11948 handleError(lView, error);
11949 }
11950 throw error;
11951 }
11952 finally {
11953 if (!checkNoChangesMode && rendererFactory.end)
11954 rendererFactory.end();
11955 }
11956}
11957function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
11958 setIsInCheckNoChangesMode(true);
11959 try {
11960 detectChangesInternal(tView, lView, context, notifyErrorHandler);
11961 }
11962 finally {
11963 setIsInCheckNoChangesMode(false);
11964 }
11965}
11966function executeViewQueryFn(flags, viewQueryFn, component) {
11967 ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
11968 setCurrentQueryIndex(0);
11969 viewQueryFn(flags, component);
11970}
11971///////////////////////////////
11972//// Bindings & interpolations
11973///////////////////////////////
11974/**
11975 * Stores meta-data for a property binding to be used by TestBed's `DebugElement.properties`.
11976 *
11977 * In order to support TestBed's `DebugElement.properties` we need to save, for each binding:
11978 * - a bound property name;
11979 * - a static parts of interpolated strings;
11980 *
11981 * A given property metadata is saved at the binding's index in the `TView.data` (in other words, a
11982 * property binding metadata will be stored in `TView.data` at the same index as a bound value in
11983 * `LView`). Metadata are represented as `INTERPOLATION_DELIMITER`-delimited string with the
11984 * following format:
11985 * - `propertyName` for bound properties;
11986 * - `propertyName�prefix�interpolation_static_part1�..interpolation_static_partN�suffix` for
11987 * interpolated properties.
11988 *
11989 * @param tData `TData` where meta-data will be saved;
11990 * @param tNode `TNode` that is a target of the binding;
11991 * @param propertyName bound property name;
11992 * @param bindingIndex binding index in `LView`
11993 * @param interpolationParts static interpolation parts (for property interpolations)
11994 */
11995function storePropertyBindingMetadata(tData, tNode, propertyName, bindingIndex, ...interpolationParts) {
11996 // Binding meta-data are stored only the first time a given property instruction is processed.
11997 // Since we don't have a concept of the "first update pass" we need to check for presence of the
11998 // binding meta-data to decide if one should be stored (or if was stored already).
11999 if (tData[bindingIndex] === null) {
12000 if (tNode.inputs == null || !tNode.inputs[propertyName]) {
12001 const propBindingIdxs = tNode.propertyBindings || (tNode.propertyBindings = []);
12002 propBindingIdxs.push(bindingIndex);
12003 let bindingMetadata = propertyName;
12004 if (interpolationParts.length > 0) {
12005 bindingMetadata +=
12006 INTERPOLATION_DELIMITER + interpolationParts.join(INTERPOLATION_DELIMITER);
12007 }
12008 tData[bindingIndex] = bindingMetadata;
12009 }
12010 }
12011}
12012function getOrCreateLViewCleanup(view) {
12013 // top level variables should not be exported for performance reasons (PERF_NOTES.md)
12014 return view[CLEANUP] || (view[CLEANUP] = []);
12015}
12016function getOrCreateTViewCleanup(tView) {
12017 return tView.cleanup || (tView.cleanup = []);
12018}
12019/**
12020 * There are cases where the sub component's renderer needs to be included
12021 * instead of the current renderer (see the componentSyntheticHost* instructions).
12022 */
12023function loadComponentRenderer(currentDef, tNode, lView) {
12024 // TODO(FW-2043): the `currentDef` is null when host bindings are invoked while creating root
12025 // component (see packages/core/src/render3/component.ts). This is not consistent with the process
12026 // of creating inner components, when current directive index is available in the state. In order
12027 // to avoid relying on current def being `null` (thus special-casing root component creation), the
12028 // process of creating root component should be unified with the process of creating inner
12029 // components.
12030 if (currentDef === null || isComponentDef(currentDef)) {
12031 lView = unwrapLView(lView[tNode.index]);
12032 }
12033 return lView[RENDERER];
12034}
12035/** Handles an error thrown in an LView. */
12036function handleError(lView, error) {
12037 const injector = lView[INJECTOR$1];
12038 const errorHandler = injector ? injector.get(ErrorHandler, null) : null;
12039 errorHandler && errorHandler.handleError(error);
12040}
12041/**
12042 * Set the inputs of directives at the current node to corresponding value.
12043 *
12044 * @param tView The current TView
12045 * @param lView the `LView` which contains the directives.
12046 * @param inputs mapping between the public "input" name and privately-known,
12047 * possibly minified, property names to write to.
12048 * @param value Value to set.
12049 */
12050function setInputsForProperty(tView, lView, inputs, publicName, value) {
12051 for (let i = 0; i < inputs.length;) {
12052 const index = inputs[i++];
12053 const privateName = inputs[i++];
12054 const instance = lView[index];
12055 ngDevMode && assertIndexInRange(lView, index);
12056 const def = tView.data[index];
12057 if (def.setInput !== null) {
12058 def.setInput(instance, value, publicName, privateName);
12059 }
12060 else {
12061 instance[privateName] = value;
12062 }
12063 }
12064}
12065/**
12066 * Updates a text binding at a given index in a given LView.
12067 */
12068function textBindingInternal(lView, index, value) {
12069 ngDevMode && assertString(value, 'Value should be a string');
12070 ngDevMode && assertNotSame(value, NO_CHANGE, 'value should not be NO_CHANGE');
12071 ngDevMode && assertIndexInRange(lView, index);
12072 const element = getNativeByIndex(index, lView);
12073 ngDevMode && assertDefined(element, 'native element should exist');
12074 updateTextNode(lView[RENDERER], element, value);
12075}
12076
12077/**
12078 * Compute the static styling (class/style) from `TAttributes`.
12079 *
12080 * This function should be called during `firstCreatePass` only.
12081 *
12082 * @param tNode The `TNode` into which the styling information should be loaded.
12083 * @param attrs `TAttributes` containing the styling information.
12084 * @param writeToHost Where should the resulting static styles be written?
12085 * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
12086 * - `true` Write to `TNode.styles` / `TNode.classes`
12087 */
12088function computeStaticStyling(tNode, attrs, writeToHost) {
12089 ngDevMode &&
12090 assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
12091 let styles = writeToHost ? tNode.styles : null;
12092 let classes = writeToHost ? tNode.classes : null;
12093 let mode = 0;
12094 if (attrs !== null) {
12095 for (let i = 0; i < attrs.length; i++) {
12096 const value = attrs[i];
12097 if (typeof value === 'number') {
12098 mode = value;
12099 }
12100 else if (mode == 1 /* AttributeMarker.Classes */) {
12101 classes = concatStringsWithSpace(classes, value);
12102 }
12103 else if (mode == 2 /* AttributeMarker.Styles */) {
12104 const style = value;
12105 const styleValue = attrs[++i];
12106 styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
12107 }
12108 }
12109 }
12110 writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
12111 writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
12112}
12113
12114function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
12115 while (tNode !== null) {
12116 ngDevMode &&
12117 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
12118 const lNode = lView[tNode.index];
12119 if (lNode !== null) {
12120 result.push(unwrapRNode(lNode));
12121 }
12122 // A given lNode can represent either a native node or a LContainer (when it is a host of a
12123 // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
12124 // from the views in this container.
12125 if (isLContainer(lNode)) {
12126 for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
12127 const lViewInAContainer = lNode[i];
12128 const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
12129 if (lViewFirstChildTNode !== null) {
12130 collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
12131 }
12132 }
12133 }
12134 const tNodeType = tNode.type;
12135 if (tNodeType & 8 /* TNodeType.ElementContainer */) {
12136 collectNativeNodes(tView, lView, tNode.child, result);
12137 }
12138 else if (tNodeType & 32 /* TNodeType.Icu */) {
12139 const nextRNode = icuContainerIterate(tNode, lView);
12140 let rNode;
12141 while (rNode = nextRNode()) {
12142 result.push(rNode);
12143 }
12144 }
12145 else if (tNodeType & 16 /* TNodeType.Projection */) {
12146 const nodesInSlot = getProjectionNodes(lView, tNode);
12147 if (Array.isArray(nodesInSlot)) {
12148 result.push(...nodesInSlot);
12149 }
12150 else {
12151 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
12152 ngDevMode && assertParentView(parentView);
12153 collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
12154 }
12155 }
12156 tNode = isProjection ? tNode.projectionNext : tNode.next;
12157 }
12158 return result;
12159}
12160
12161class ViewRef {
12162 get rootNodes() {
12163 const lView = this._lView;
12164 const tView = lView[TVIEW];
12165 return collectNativeNodes(tView, lView, tView.firstChild, []);
12166 }
12167 constructor(
12168 /**
12169 * This represents `LView` associated with the component when ViewRef is a ChangeDetectorRef.
12170 *
12171 * When ViewRef is created for a dynamic component, this also represents the `LView` for the
12172 * component.
12173 *
12174 * For a "regular" ViewRef created for an embedded view, this is the `LView` for the embedded
12175 * view.
12176 *
12177 * @internal
12178 */
12179 _lView,
12180 /**
12181 * This represents the `LView` associated with the point where `ChangeDetectorRef` was
12182 * requested.
12183 *
12184 * This may be different from `_lView` if the `_cdRefInjectingView` is an embedded view.
12185 */
12186 _cdRefInjectingView) {
12187 this._lView = _lView;
12188 this._cdRefInjectingView = _cdRefInjectingView;
12189 this._appRef = null;
12190 this._attachedToViewContainer = false;
12191 }
12192 get context() {
12193 return this._lView[CONTEXT];
12194 }
12195 set context(value) {
12196 this._lView[CONTEXT] = value;
12197 }
12198 get destroyed() {
12199 return (this._lView[FLAGS] & 128 /* LViewFlags.Destroyed */) === 128 /* LViewFlags.Destroyed */;
12200 }
12201 destroy() {
12202 if (this._appRef) {
12203 this._appRef.detachView(this);
12204 }
12205 else if (this._attachedToViewContainer) {
12206 const parent = this._lView[PARENT];
12207 if (isLContainer(parent)) {
12208 const viewRefs = parent[VIEW_REFS];
12209 const index = viewRefs ? viewRefs.indexOf(this) : -1;
12210 if (index > -1) {
12211 ngDevMode &&
12212 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.');
12213 detachView(parent, index);
12214 removeFromArray(viewRefs, index);
12215 }
12216 }
12217 this._attachedToViewContainer = false;
12218 }
12219 destroyLView(this._lView[TVIEW], this._lView);
12220 }
12221 onDestroy(callback) {
12222 storeCleanupWithContext(this._lView[TVIEW], this._lView, null, callback);
12223 }
12224 /**
12225 * Marks a view and all of its ancestors dirty.
12226 *
12227 * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is
12228 * checked when it needs to be re-rendered but the two normal triggers haven't marked it
12229 * dirty (i.e. inputs haven't changed and events haven't fired in the view).
12230 *
12231 * <!-- TODO: Add a link to a chapter on OnPush components -->
12232 *
12233 * @usageNotes
12234 * ### Example
12235 *
12236 * ```typescript
12237 * @Component({
12238 * selector: 'app-root',
12239 * template: `Number of ticks: {{numberOfTicks}}`
12240 * changeDetection: ChangeDetectionStrategy.OnPush,
12241 * })
12242 * class AppComponent {
12243 * numberOfTicks = 0;
12244 *
12245 * constructor(private ref: ChangeDetectorRef) {
12246 * setInterval(() => {
12247 * this.numberOfTicks++;
12248 * // the following is required, otherwise the view will not be updated
12249 * this.ref.markForCheck();
12250 * }, 1000);
12251 * }
12252 * }
12253 * ```
12254 */
12255 markForCheck() {
12256 markViewDirty(this._cdRefInjectingView || this._lView);
12257 }
12258 /**
12259 * Detaches the view from the change detection tree.
12260 *
12261 * Detached views will not be checked during change detection runs until they are
12262 * re-attached, even if they are dirty. `detach` can be used in combination with
12263 * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change
12264 * detection checks.
12265 *
12266 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
12267 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
12268 *
12269 * @usageNotes
12270 * ### Example
12271 *
12272 * The following example defines a component with a large list of readonly data.
12273 * Imagine the data changes constantly, many times per second. For performance reasons,
12274 * we want to check and update the list every five seconds. We can do that by detaching
12275 * the component's change detector and doing a local check every five seconds.
12276 *
12277 * ```typescript
12278 * class DataProvider {
12279 * // in a real application the returned data will be different every time
12280 * get data() {
12281 * return [1,2,3,4,5];
12282 * }
12283 * }
12284 *
12285 * @Component({
12286 * selector: 'giant-list',
12287 * template: `
12288 * <li *ngFor="let d of dataProvider.data">Data {{d}}</li>
12289 * `,
12290 * })
12291 * class GiantList {
12292 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {
12293 * ref.detach();
12294 * setInterval(() => {
12295 * this.ref.detectChanges();
12296 * }, 5000);
12297 * }
12298 * }
12299 *
12300 * @Component({
12301 * selector: 'app',
12302 * providers: [DataProvider],
12303 * template: `
12304 * <giant-list><giant-list>
12305 * `,
12306 * })
12307 * class App {
12308 * }
12309 * ```
12310 */
12311 detach() {
12312 this._lView[FLAGS] &= ~64 /* LViewFlags.Attached */;
12313 }
12314 /**
12315 * Re-attaches a view to the change detection tree.
12316 *
12317 * This can be used to re-attach views that were previously detached from the tree
12318 * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default.
12319 *
12320 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
12321 *
12322 * @usageNotes
12323 * ### Example
12324 *
12325 * The following example creates a component displaying `live` data. The component will detach
12326 * its change detector from the main change detector tree when the component's live property
12327 * is set to false.
12328 *
12329 * ```typescript
12330 * class DataProvider {
12331 * data = 1;
12332 *
12333 * constructor() {
12334 * setInterval(() => {
12335 * this.data = this.data * 2;
12336 * }, 500);
12337 * }
12338 * }
12339 *
12340 * @Component({
12341 * selector: 'live-data',
12342 * inputs: ['live'],
12343 * template: 'Data: {{dataProvider.data}}'
12344 * })
12345 * class LiveData {
12346 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {}
12347 *
12348 * set live(value) {
12349 * if (value) {
12350 * this.ref.reattach();
12351 * } else {
12352 * this.ref.detach();
12353 * }
12354 * }
12355 * }
12356 *
12357 * @Component({
12358 * selector: 'app-root',
12359 * providers: [DataProvider],
12360 * template: `
12361 * Live Update: <input type="checkbox" [(ngModel)]="live">
12362 * <live-data [live]="live"><live-data>
12363 * `,
12364 * })
12365 * class AppComponent {
12366 * live = true;
12367 * }
12368 * ```
12369 */
12370 reattach() {
12371 this._lView[FLAGS] |= 64 /* LViewFlags.Attached */;
12372 }
12373 /**
12374 * Checks the view and its children.
12375 *
12376 * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement
12377 * local change detection checks.
12378 *
12379 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
12380 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
12381 *
12382 * @usageNotes
12383 * ### Example
12384 *
12385 * The following example defines a component with a large list of readonly data.
12386 * Imagine, the data changes constantly, many times per second. For performance reasons,
12387 * we want to check and update the list every five seconds.
12388 *
12389 * We can do that by detaching the component's change detector and doing a local change detection
12390 * check every five seconds.
12391 *
12392 * See {@link ChangeDetectorRef#detach detach} for more information.
12393 */
12394 detectChanges() {
12395 detectChangesInternal(this._lView[TVIEW], this._lView, this.context);
12396 }
12397 /**
12398 * Checks the change detector and its children, and throws if any changes are detected.
12399 *
12400 * This is used in development mode to verify that running change detection doesn't
12401 * introduce other changes.
12402 */
12403 checkNoChanges() {
12404 if (ngDevMode) {
12405 checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
12406 }
12407 }
12408 attachToViewContainerRef() {
12409 if (this._appRef) {
12410 throw new RuntimeError(902 /* RuntimeErrorCode.VIEW_ALREADY_ATTACHED */, ngDevMode && 'This view is already attached directly to the ApplicationRef!');
12411 }
12412 this._attachedToViewContainer = true;
12413 }
12414 detachFromAppRef() {
12415 this._appRef = null;
12416 renderDetachView(this._lView[TVIEW], this._lView);
12417 }
12418 attachToAppRef(appRef) {
12419 if (this._attachedToViewContainer) {
12420 throw new RuntimeError(902 /* RuntimeErrorCode.VIEW_ALREADY_ATTACHED */, ngDevMode && 'This view is already attached to a ViewContainer!');
12421 }
12422 this._appRef = appRef;
12423 }
12424}
12425/** @internal */
12426class RootViewRef extends ViewRef {
12427 constructor(_view) {
12428 super(_view);
12429 this._view = _view;
12430 }
12431 detectChanges() {
12432 const lView = this._view;
12433 const tView = lView[TVIEW];
12434 const context = lView[CONTEXT];
12435 detectChangesInternal(tView, lView, context, false);
12436 }
12437 checkNoChanges() {
12438 if (ngDevMode) {
12439 const lView = this._view;
12440 const tView = lView[TVIEW];
12441 const context = lView[CONTEXT];
12442 checkNoChangesInternal(tView, lView, context, false);
12443 }
12444 }
12445 get context() {
12446 return null;
12447 }
12448}
12449
12450class ComponentFactoryResolver extends ComponentFactoryResolver$1 {
12451 /**
12452 * @param ngModule The NgModuleRef to which all resolved factories are bound.
12453 */
12454 constructor(ngModule) {
12455 super();
12456 this.ngModule = ngModule;
12457 }
12458 resolveComponentFactory(component) {
12459 ngDevMode && assertComponentType(component);
12460 const componentDef = getComponentDef$1(component);
12461 return new ComponentFactory(componentDef, this.ngModule);
12462 }
12463}
12464function toRefArray(map) {
12465 const array = [];
12466 for (let nonMinified in map) {
12467 if (map.hasOwnProperty(nonMinified)) {
12468 const minified = map[nonMinified];
12469 array.push({ propName: minified, templateName: nonMinified });
12470 }
12471 }
12472 return array;
12473}
12474function getNamespace(elementName) {
12475 const name = elementName.toLowerCase();
12476 return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null);
12477}
12478/**
12479 * Injector that looks up a value using a specific injector, before falling back to the module
12480 * injector. Used primarily when creating components or embedded views dynamically.
12481 */
12482class ChainedInjector {
12483 constructor(injector, parentInjector) {
12484 this.injector = injector;
12485 this.parentInjector = parentInjector;
12486 }
12487 get(token, notFoundValue, flags) {
12488 flags = convertToBitFlags(flags);
12489 const value = this.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
12490 if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
12491 notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
12492 // Return the value from the root element injector when
12493 // - it provides it
12494 // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
12495 // - the module injector should not be checked
12496 // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
12497 return value;
12498 }
12499 return this.parentInjector.get(token, notFoundValue, flags);
12500 }
12501}
12502/**
12503 * ComponentFactory interface implementation.
12504 */
12505class ComponentFactory extends ComponentFactory$1 {
12506 get inputs() {
12507 return toRefArray(this.componentDef.inputs);
12508 }
12509 get outputs() {
12510 return toRefArray(this.componentDef.outputs);
12511 }
12512 /**
12513 * @param componentDef The component definition.
12514 * @param ngModule The NgModuleRef to which the factory is bound.
12515 */
12516 constructor(componentDef, ngModule) {
12517 super();
12518 this.componentDef = componentDef;
12519 this.ngModule = ngModule;
12520 this.componentType = componentDef.type;
12521 this.selector = stringifyCSSSelectorList(componentDef.selectors);
12522 this.ngContentSelectors =
12523 componentDef.ngContentSelectors ? componentDef.ngContentSelectors : [];
12524 this.isBoundToModule = !!ngModule;
12525 }
12526 create(injector, projectableNodes, rootSelectorOrNode, environmentInjector) {
12527 environmentInjector = environmentInjector || this.ngModule;
12528 let realEnvironmentInjector = environmentInjector instanceof EnvironmentInjector ?
12529 environmentInjector :
12530 environmentInjector === null || environmentInjector === void 0 ? void 0 : environmentInjector.injector;
12531 if (realEnvironmentInjector && this.componentDef.getStandaloneInjector !== null) {
12532 realEnvironmentInjector = this.componentDef.getStandaloneInjector(realEnvironmentInjector) ||
12533 realEnvironmentInjector;
12534 }
12535 const rootViewInjector = realEnvironmentInjector ? new ChainedInjector(injector, realEnvironmentInjector) : injector;
12536 const rendererFactory = rootViewInjector.get(RendererFactory2, null);
12537 if (rendererFactory === null) {
12538 throw new RuntimeError(407 /* RuntimeErrorCode.RENDERER_NOT_FOUND */, ngDevMode &&
12539 'Angular was not able to inject a renderer (RendererFactory2). ' +
12540 'Likely this is due to a broken DI hierarchy. ' +
12541 'Make sure that any injector used to create this component has a correct parent.');
12542 }
12543 const sanitizer = rootViewInjector.get(Sanitizer, null);
12544 const hostRenderer = rendererFactory.createRenderer(null, this.componentDef);
12545 // Determine a tag name used for creating host elements when this component is created
12546 // dynamically. Default to 'div' if this component did not specify any tag name in its selector.
12547 const elementName = this.componentDef.selectors[0][0] || 'div';
12548 const hostRNode = rootSelectorOrNode ?
12549 locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) :
12550 createElementNode(hostRenderer, elementName, getNamespace(elementName));
12551 const rootFlags = this.componentDef.onPush ? 32 /* LViewFlags.Dirty */ | 256 /* LViewFlags.IsRoot */ :
12552 16 /* LViewFlags.CheckAlways */ | 256 /* LViewFlags.IsRoot */;
12553 // Create the root view. Uses empty TView and ContentTemplate.
12554 const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null);
12555 const rootLView = createLView(null, rootTView, null, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector, null);
12556 // rootView is the parent when bootstrapping
12557 // TODO(misko): it looks like we are entering view here but we don't really need to as
12558 // `renderView` does that. However as the code is written it is needed because
12559 // `createRootComponentView` and `createRootComponent` both read global state. Fixing those
12560 // issues would allow us to drop this.
12561 enterView(rootLView);
12562 let component;
12563 let tElementNode;
12564 try {
12565 const rootComponentDef = this.componentDef;
12566 let rootDirectives;
12567 let hostDirectiveDefs = null;
12568 if (rootComponentDef.findHostDirectiveDefs) {
12569 rootDirectives = [];
12570 hostDirectiveDefs = new Map();
12571 rootComponentDef.findHostDirectiveDefs(rootComponentDef, rootDirectives, hostDirectiveDefs);
12572 rootDirectives.push(rootComponentDef);
12573 }
12574 else {
12575 rootDirectives = [rootComponentDef];
12576 }
12577 const hostTNode = createRootComponentTNode(rootLView, hostRNode);
12578 const componentView = createRootComponentView(hostTNode, hostRNode, rootComponentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
12579 tElementNode = getTNode(rootTView, HEADER_OFFSET);
12580 // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests
12581 // where the renderer is mocked out and `undefined` is returned. We should update the tests so
12582 // that this check can be removed.
12583 if (hostRNode) {
12584 setRootNodeAttributes(hostRenderer, rootComponentDef, hostRNode, rootSelectorOrNode);
12585 }
12586 if (projectableNodes !== undefined) {
12587 projectNodes(tElementNode, this.ngContentSelectors, projectableNodes);
12588 }
12589 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
12590 // executed here?
12591 // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
12592 component = createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, [LifecycleHooksFeature]);
12593 renderView(rootTView, rootLView, null);
12594 }
12595 finally {
12596 leaveView();
12597 }
12598 return new ComponentRef(this.componentType, component, createElementRef(tElementNode, rootLView), rootLView, tElementNode);
12599 }
12600}
12601/**
12602 * Represents an instance of a Component created via a {@link ComponentFactory}.
12603 *
12604 * `ComponentRef` provides access to the Component Instance as well other objects related to this
12605 * Component Instance and allows you to destroy the Component Instance via the {@link #destroy}
12606 * method.
12607 *
12608 */
12609class ComponentRef extends ComponentRef$1 {
12610 constructor(componentType, instance, location, _rootLView, _tNode) {
12611 super();
12612 this.location = location;
12613 this._rootLView = _rootLView;
12614 this._tNode = _tNode;
12615 this.instance = instance;
12616 this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView);
12617 this.componentType = componentType;
12618 }
12619 setInput(name, value) {
12620 const inputData = this._tNode.inputs;
12621 let dataValue;
12622 if (inputData !== null && (dataValue = inputData[name])) {
12623 const lView = this._rootLView;
12624 setInputsForProperty(lView[TVIEW], lView, dataValue, name, value);
12625 markDirtyIfOnPush(lView, this._tNode.index);
12626 }
12627 else {
12628 if (ngDevMode) {
12629 const cmpNameForError = stringifyForError(this.componentType);
12630 let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `;
12631 message += `Make sure that the '${name}' property is annotated with @Input() or a mapped @Input('${name}') exists.`;
12632 reportUnknownPropertyError(message);
12633 }
12634 }
12635 }
12636 get injector() {
12637 return new NodeInjector(this._tNode, this._rootLView);
12638 }
12639 destroy() {
12640 this.hostView.destroy();
12641 }
12642 onDestroy(callback) {
12643 this.hostView.onDestroy(callback);
12644 }
12645}
12646// TODO: A hack to not pull in the NullInjector from @angular/core.
12647const NULL_INJECTOR = {
12648 get: (token, notFoundValue) => {
12649 throwProviderNotFoundError(token, 'NullInjector');
12650 }
12651};
12652/** Creates a TNode that can be used to instantiate a root component. */
12653function createRootComponentTNode(lView, rNode) {
12654 const tView = lView[TVIEW];
12655 const index = HEADER_OFFSET;
12656 ngDevMode && assertIndexInRange(lView, index);
12657 lView[index] = rNode;
12658 // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
12659 // the same time we want to communicate the debug `TNode` that this is a special `TNode`
12660 // representing a host element.
12661 return getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null);
12662}
12663/**
12664 * Creates the root component view and the root component node.
12665 *
12666 * @param rNode Render host element.
12667 * @param rootComponentDef ComponentDef
12668 * @param rootView The parent view where the host node is stored
12669 * @param rendererFactory Factory to be used for creating child renderers.
12670 * @param hostRenderer The current renderer
12671 * @param sanitizer The sanitizer, if provided
12672 *
12673 * @returns Component view created
12674 */
12675function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives, rootView, rendererFactory, hostRenderer, sanitizer) {
12676 const tView = rootView[TVIEW];
12677 applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer);
12678 const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
12679 const componentView = createLView(rootView, getOrCreateComponentTView(rootComponentDef), null, rootComponentDef.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[tNode.index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
12680 if (tView.firstCreatePass) {
12681 markAsComponentHost(tView, tNode, rootDirectives.length - 1);
12682 }
12683 addToViewTree(rootView, componentView);
12684 // Store component view at node index, with node as the HOST
12685 return rootView[tNode.index] = componentView;
12686}
12687/** Sets up the styling information on a root component. */
12688function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) {
12689 for (const def of rootDirectives) {
12690 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
12691 }
12692 if (tNode.mergedAttrs !== null) {
12693 computeStaticStyling(tNode, tNode.mergedAttrs, true);
12694 if (rNode !== null) {
12695 setupStaticAttributes(hostRenderer, rNode, tNode);
12696 }
12697 }
12698}
12699/**
12700 * Creates a root component and sets it up with features and host bindings.Shared by
12701 * renderComponent() and ViewContainerRef.createComponent().
12702 */
12703function createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, hostFeatures) {
12704 const rootTNode = getCurrentTNode();
12705 ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
12706 const tView = rootLView[TVIEW];
12707 const native = getNativeByTNode(rootTNode, rootLView);
12708 initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null, hostDirectiveDefs);
12709 for (let i = 0; i < rootDirectives.length; i++) {
12710 const directiveIndex = rootTNode.directiveStart + i;
12711 const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode);
12712 attachPatchData(directiveInstance, rootLView);
12713 }
12714 invokeDirectivesHostBindings(tView, rootLView, rootTNode);
12715 if (native) {
12716 attachPatchData(native, rootLView);
12717 }
12718 // We're guaranteed for the `componentOffset` to be positive here
12719 // since a root component always matches a component def.
12720 ngDevMode &&
12721 assertGreaterThan(rootTNode.componentOffset, -1, 'componentOffset must be great than -1');
12722 const component = getNodeInjectable(rootLView, tView, rootTNode.directiveStart + rootTNode.componentOffset, rootTNode);
12723 componentView[CONTEXT] = rootLView[CONTEXT] = component;
12724 if (hostFeatures !== null) {
12725 for (const feature of hostFeatures) {
12726 feature(component, rootComponentDef);
12727 }
12728 }
12729 // We want to generate an empty QueryList for root content queries for backwards
12730 // compatibility with ViewEngine.
12731 executeContentQueries(tView, rootTNode, componentView);
12732 return component;
12733}
12734/** Sets the static attributes on a root component. */
12735function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) {
12736 if (rootSelectorOrNode) {
12737 setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]);
12738 }
12739 else {
12740 // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
12741 // is not defined), also apply attributes and classes extracted from component selector.
12742 // Extract attributes and classes from the first selector only to match VE behavior.
12743 const { attrs, classes } = extractAttrsAndClassesFromSelector(componentDef.selectors[0]);
12744 if (attrs) {
12745 setUpAttributes(hostRenderer, hostRNode, attrs);
12746 }
12747 if (classes && classes.length > 0) {
12748 writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
12749 }
12750 }
12751}
12752/** Projects the `projectableNodes` that were specified when creating a root component. */
12753function projectNodes(tNode, ngContentSelectors, projectableNodes) {
12754 const projection = tNode.projection = [];
12755 for (let i = 0; i < ngContentSelectors.length; i++) {
12756 const nodesforSlot = projectableNodes[i];
12757 // Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
12758 // case). Here we do normalize passed data structure to be an array of arrays to avoid
12759 // complex checks down the line.
12760 // We also normalize the length of the passed in projectable nodes (to match the number of
12761 // <ng-container> slots defined by a component).
12762 projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
12763 }
12764}
12765/**
12766 * Used to enable lifecycle hooks on the root component.
12767 *
12768 * Include this feature when calling `renderComponent` if the root component
12769 * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't
12770 * be called properly.
12771 *
12772 * Example:
12773 *
12774 * ```
12775 * renderComponent(AppComponent, {hostFeatures: [LifecycleHooksFeature]});
12776 * ```
12777 */
12778function LifecycleHooksFeature() {
12779 const tNode = getCurrentTNode();
12780 ngDevMode && assertDefined(tNode, 'TNode is required');
12781 registerPostOrderHooks(getLView()[TVIEW], tNode);
12782}
12783
12784function getSuperType(type) {
12785 return Object.getPrototypeOf(type.prototype).constructor;
12786}
12787/**
12788 * Merges the definition from a super class to a sub class.
12789 * @param definition The definition that is a SubClass of another directive of component
12790 *
12791 * @codeGenApi
12792 */
12793function ɵɵInheritDefinitionFeature(definition) {
12794 let superType = getSuperType(definition.type);
12795 let shouldInheritFields = true;
12796 const inheritanceChain = [definition];
12797 while (superType) {
12798 let superDef = undefined;
12799 if (isComponentDef(definition)) {
12800 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12801 superDef = superType.ɵcmp || superType.ɵdir;
12802 }
12803 else {
12804 if (superType.ɵcmp) {
12805 throw new RuntimeError(903 /* RuntimeErrorCode.INVALID_INHERITANCE */, ngDevMode &&
12806 `Directives cannot inherit Components. Directive ${stringifyForError(definition.type)} is attempting to extend component ${stringifyForError(superType)}`);
12807 }
12808 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12809 superDef = superType.ɵdir;
12810 }
12811 if (superDef) {
12812 if (shouldInheritFields) {
12813 inheritanceChain.push(superDef);
12814 // Some fields in the definition may be empty, if there were no values to put in them that
12815 // would've justified object creation. Unwrap them if necessary.
12816 const writeableDef = definition;
12817 writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
12818 writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
12819 writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
12820 // Merge hostBindings
12821 const superHostBindings = superDef.hostBindings;
12822 superHostBindings && inheritHostBindings(definition, superHostBindings);
12823 // Merge queries
12824 const superViewQuery = superDef.viewQuery;
12825 const superContentQueries = superDef.contentQueries;
12826 superViewQuery && inheritViewQuery(definition, superViewQuery);
12827 superContentQueries && inheritContentQueries(definition, superContentQueries);
12828 // Merge inputs and outputs
12829 fillProperties(definition.inputs, superDef.inputs);
12830 fillProperties(definition.declaredInputs, superDef.declaredInputs);
12831 fillProperties(definition.outputs, superDef.outputs);
12832 // Merge animations metadata.
12833 // If `superDef` is a Component, the `data` field is present (defaults to an empty object).
12834 if (isComponentDef(superDef) && superDef.data.animation) {
12835 // If super def is a Component, the `definition` is also a Component, since Directives can
12836 // not inherit Components (we throw an error above and cannot reach this code).
12837 const defData = definition.data;
12838 defData.animation = (defData.animation || []).concat(superDef.data.animation);
12839 }
12840 }
12841 // Run parent features
12842 const features = superDef.features;
12843 if (features) {
12844 for (let i = 0; i < features.length; i++) {
12845 const feature = features[i];
12846 if (feature && feature.ngInherit) {
12847 feature(definition);
12848 }
12849 // If `InheritDefinitionFeature` is a part of the current `superDef`, it means that this
12850 // def already has all the necessary information inherited from its super class(es), so we
12851 // can stop merging fields from super classes. However we need to iterate through the
12852 // prototype chain to look for classes that might contain other "features" (like
12853 // NgOnChanges), which we should invoke for the original `definition`. We set the
12854 // `shouldInheritFields` flag to indicate that, essentially skipping fields inheritance
12855 // logic and only invoking functions from the "features" list.
12856 if (feature === ɵɵInheritDefinitionFeature) {
12857 shouldInheritFields = false;
12858 }
12859 }
12860 }
12861 }
12862 superType = Object.getPrototypeOf(superType);
12863 }
12864 mergeHostAttrsAcrossInheritance(inheritanceChain);
12865}
12866/**
12867 * Merge the `hostAttrs` and `hostVars` from the inherited parent to the base class.
12868 *
12869 * @param inheritanceChain A list of `WritableDefs` starting at the top most type and listing
12870 * sub-types in order. For each type take the `hostAttrs` and `hostVars` and merge it with the child
12871 * type.
12872 */
12873function mergeHostAttrsAcrossInheritance(inheritanceChain) {
12874 let hostVars = 0;
12875 let hostAttrs = null;
12876 // We process the inheritance order from the base to the leaves here.
12877 for (let i = inheritanceChain.length - 1; i >= 0; i--) {
12878 const def = inheritanceChain[i];
12879 // For each `hostVars`, we need to add the superclass amount.
12880 def.hostVars = (hostVars += def.hostVars);
12881 // for each `hostAttrs` we need to merge it with superclass.
12882 def.hostAttrs =
12883 mergeHostAttrs(def.hostAttrs, hostAttrs = mergeHostAttrs(hostAttrs, def.hostAttrs));
12884 }
12885}
12886function maybeUnwrapEmpty(value) {
12887 if (value === EMPTY_OBJ) {
12888 return {};
12889 }
12890 else if (value === EMPTY_ARRAY) {
12891 return [];
12892 }
12893 else {
12894 return value;
12895 }
12896}
12897function inheritViewQuery(definition, superViewQuery) {
12898 const prevViewQuery = definition.viewQuery;
12899 if (prevViewQuery) {
12900 definition.viewQuery = (rf, ctx) => {
12901 superViewQuery(rf, ctx);
12902 prevViewQuery(rf, ctx);
12903 };
12904 }
12905 else {
12906 definition.viewQuery = superViewQuery;
12907 }
12908}
12909function inheritContentQueries(definition, superContentQueries) {
12910 const prevContentQueries = definition.contentQueries;
12911 if (prevContentQueries) {
12912 definition.contentQueries = (rf, ctx, directiveIndex) => {
12913 superContentQueries(rf, ctx, directiveIndex);
12914 prevContentQueries(rf, ctx, directiveIndex);
12915 };
12916 }
12917 else {
12918 definition.contentQueries = superContentQueries;
12919 }
12920}
12921function inheritHostBindings(definition, superHostBindings) {
12922 const prevHostBindings = definition.hostBindings;
12923 if (prevHostBindings) {
12924 definition.hostBindings = (rf, ctx) => {
12925 superHostBindings(rf, ctx);
12926 prevHostBindings(rf, ctx);
12927 };
12928 }
12929 else {
12930 definition.hostBindings = superHostBindings;
12931 }
12932}
12933
12934/**
12935 * Fields which exist on either directive or component definitions, and need to be copied from
12936 * parent to child classes by the `ɵɵCopyDefinitionFeature`.
12937 */
12938const COPY_DIRECTIVE_FIELDS = [
12939 // The child class should use the providers of its parent.
12940 'providersResolver',
12941 // Not listed here are any fields which are handled by the `ɵɵInheritDefinitionFeature`, such
12942 // as inputs, outputs, and host binding functions.
12943];
12944/**
12945 * Fields which exist only on component definitions, and need to be copied from parent to child
12946 * classes by the `ɵɵCopyDefinitionFeature`.
12947 *
12948 * The type here allows any field of `ComponentDef` which is not also a property of `DirectiveDef`,
12949 * since those should go in `COPY_DIRECTIVE_FIELDS` above.
12950 */
12951const COPY_COMPONENT_FIELDS = [
12952 // The child class should use the template function of its parent, including all template
12953 // semantics.
12954 'template',
12955 'decls',
12956 'consts',
12957 'vars',
12958 'onPush',
12959 'ngContentSelectors',
12960 // The child class should use the CSS styles of its parent, including all styling semantics.
12961 'styles',
12962 'encapsulation',
12963 // The child class should be checked by the runtime in the same way as its parent.
12964 'schemas',
12965];
12966/**
12967 * Copies the fields not handled by the `ɵɵInheritDefinitionFeature` from the supertype of a
12968 * definition.
12969 *
12970 * This exists primarily to support ngcc migration of an existing View Engine pattern, where an
12971 * entire decorator is inherited from a parent to a child class. When ngcc detects this case, it
12972 * generates a skeleton definition on the child class, and applies this feature.
12973 *
12974 * The `ɵɵCopyDefinitionFeature` then copies any needed fields from the parent class' definition,
12975 * including things like the component template function.
12976 *
12977 * @param definition The definition of a child class which inherits from a parent class with its
12978 * own definition.
12979 *
12980 * @codeGenApi
12981 */
12982function ɵɵCopyDefinitionFeature(definition) {
12983 let superType = getSuperType(definition.type);
12984 let superDef = undefined;
12985 if (isComponentDef(definition)) {
12986 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12987 superDef = superType.ɵcmp;
12988 }
12989 else {
12990 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12991 superDef = superType.ɵdir;
12992 }
12993 // Needed because `definition` fields are readonly.
12994 const defAny = definition;
12995 // Copy over any fields that apply to either directives or components.
12996 for (const field of COPY_DIRECTIVE_FIELDS) {
12997 defAny[field] = superDef[field];
12998 }
12999 if (isComponentDef(superDef)) {
13000 // Copy over any component-specific fields.
13001 for (const field of COPY_COMPONENT_FIELDS) {
13002 defAny[field] = superDef[field];
13003 }
13004 }
13005}
13006
13007/**
13008 * This feature adds the host directives behavior to a directive definition by patching a
13009 * function onto it. The expectation is that the runtime will invoke the function during
13010 * directive matching.
13011 *
13012 * For example:
13013 * ```ts
13014 * class ComponentWithHostDirective {
13015 * static ɵcmp = defineComponent({
13016 * type: ComponentWithHostDirective,
13017 * features: [ɵɵHostDirectivesFeature([
13018 * SimpleHostDirective,
13019 * {directive: AdvancedHostDirective, inputs: ['foo: alias'], outputs: ['bar']},
13020 * ])]
13021 * });
13022 * }
13023 * ```
13024 *
13025 * @codeGenApi
13026 */
13027function ɵɵHostDirectivesFeature(rawHostDirectives) {
13028 return (definition) => {
13029 definition.findHostDirectiveDefs = findHostDirectiveDefs;
13030 definition.hostDirectives =
13031 (Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
13032 return typeof dir === 'function' ?
13033 { directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
13034 {
13035 directive: resolveForwardRef(dir.directive),
13036 inputs: bindingArrayToMap(dir.inputs),
13037 outputs: bindingArrayToMap(dir.outputs)
13038 };
13039 });
13040 };
13041}
13042function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
13043 if (currentDef.hostDirectives !== null) {
13044 for (const hostDirectiveConfig of currentDef.hostDirectives) {
13045 const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
13046 if (typeof ngDevMode === 'undefined' || ngDevMode) {
13047 validateHostDirective(hostDirectiveConfig, hostDirectiveDef, matchedDefs);
13048 }
13049 // We need to patch the `declaredInputs` so that
13050 // `ngOnChanges` can map the properties correctly.
13051 patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
13052 // Host directives execute before the host so that its host bindings can be overwritten.
13053 findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
13054 hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
13055 matchedDefs.push(hostDirectiveDef);
13056 }
13057 }
13058}
13059/**
13060 * Converts an array in the form of `['publicName', 'alias', 'otherPublicName', 'otherAlias']` into
13061 * a map in the form of `{publicName: 'alias', otherPublicName: 'otherAlias'}`.
13062 */
13063function bindingArrayToMap(bindings) {
13064 if (bindings === undefined || bindings.length === 0) {
13065 return EMPTY_OBJ;
13066 }
13067 const result = {};
13068 for (let i = 0; i < bindings.length; i += 2) {
13069 result[bindings[i]] = bindings[i + 1];
13070 }
13071 return result;
13072}
13073/**
13074 * `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
13075 * `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
13076 * minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
13077 * will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
13078 * minification.
13079 *
13080 * This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
13081 * definition is declared. When a property is written to the directive instance, the
13082 * `NgOnChangesFeature` will try to remap the property name being written to using the
13083 * `declaredInputs`.
13084 *
13085 * Since the host directive input remapping happens during directive matching, `declaredInputs`
13086 * won't contain the new alias that the input is available under. This function addresses the
13087 * issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
13088 * this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
13089 * is used *only* by the `NgOnChangesFeature` when determining what name is used in the
13090 * `SimpleChanges` object which won't be reached if an input doesn't exist.
13091 */
13092function patchDeclaredInputs(declaredInputs, exposedInputs) {
13093 for (const publicName in exposedInputs) {
13094 if (exposedInputs.hasOwnProperty(publicName)) {
13095 const remappedPublicName = exposedInputs[publicName];
13096 const privateName = declaredInputs[publicName];
13097 // We *technically* shouldn't be able to hit this case because we can't have multiple
13098 // inputs on the same property and we have validations against conflicting aliases in
13099 // `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
13100 // with the wrong name so we have a non-user-friendly assertion here just in case.
13101 if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
13102 declaredInputs.hasOwnProperty(remappedPublicName)) {
13103 assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
13104 }
13105 declaredInputs[remappedPublicName] = privateName;
13106 }
13107 }
13108}
13109/**
13110 * Verifies that the host directive has been configured correctly.
13111 * @param hostDirectiveConfig Host directive configuration object.
13112 * @param directiveDef Directive definition of the host directive.
13113 * @param matchedDefs Directives that have been matched so far.
13114 */
13115function validateHostDirective(hostDirectiveConfig, directiveDef, matchedDefs) {
13116 const type = hostDirectiveConfig.directive;
13117 if (directiveDef === null) {
13118 if (getComponentDef$1(type) !== null) {
13119 throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
13120 }
13121 throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
13122 `Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
13123 }
13124 if (!directiveDef.standalone) {
13125 throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
13126 }
13127 if (matchedDefs.indexOf(directiveDef) > -1) {
13128 throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTITVE */, `Directive ${directiveDef.type.name} matches multiple times on the same element. ` +
13129 `Directives can only match an element once.`);
13130 }
13131 validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
13132 validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
13133}
13134/**
13135 * Checks that the host directive inputs/outputs configuration is valid.
13136 * @param bindingType Kind of binding that is being validated. Used in the error message.
13137 * @param def Definition of the host directive that is being validated against.
13138 * @param hostDirectiveBindings Host directive mapping object that shold be validated.
13139 */
13140function validateMappings(bindingType, def, hostDirectiveBindings) {
13141 const className = def.type.name;
13142 const bindings = bindingType === 'input' ? def.inputs : def.outputs;
13143 for (const publicName in hostDirectiveBindings) {
13144 if (hostDirectiveBindings.hasOwnProperty(publicName)) {
13145 if (!bindings.hasOwnProperty(publicName)) {
13146 throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
13147 }
13148 const remappedPublicName = hostDirectiveBindings[publicName];
13149 if (bindings.hasOwnProperty(remappedPublicName) &&
13150 bindings[remappedPublicName] !== publicName) {
13151 throw new RuntimeError(312 /* RuntimeErrorCode.HOST_DIRECTIVE_CONFLICTING_ALIAS */, `Cannot alias ${bindingType} ${publicName} of host directive ${className} to ${remappedPublicName}, because it already has a different ${bindingType} with the same public name.`);
13152 }
13153 }
13154 }
13155}
13156
13157let _symbolIterator = null;
13158function getSymbolIterator() {
13159 if (!_symbolIterator) {
13160 const Symbol = _global$1['Symbol'];
13161 if (Symbol && Symbol.iterator) {
13162 _symbolIterator = Symbol.iterator;
13163 }
13164 else {
13165 // es6-shim specific logic
13166 const keys = Object.getOwnPropertyNames(Map.prototype);
13167 for (let i = 0; i < keys.length; ++i) {
13168 const key = keys[i];
13169 if (key !== 'entries' && key !== 'size' &&
13170 Map.prototype[key] === Map.prototype['entries']) {
13171 _symbolIterator = key;
13172 }
13173 }
13174 }
13175 }
13176 return _symbolIterator;
13177}
13178
13179function isIterable(obj) {
13180 return obj !== null && typeof obj === 'object' && obj[getSymbolIterator()] !== undefined;
13181}
13182function isListLikeIterable(obj) {
13183 if (!isJsObject(obj))
13184 return false;
13185 return Array.isArray(obj) ||
13186 (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
13187 getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop
13188}
13189function areIterablesEqual(a, b, comparator) {
13190 const iterator1 = a[getSymbolIterator()]();
13191 const iterator2 = b[getSymbolIterator()]();
13192 while (true) {
13193 const item1 = iterator1.next();
13194 const item2 = iterator2.next();
13195 if (item1.done && item2.done)
13196 return true;
13197 if (item1.done || item2.done)
13198 return false;
13199 if (!comparator(item1.value, item2.value))
13200 return false;
13201 }
13202}
13203function iterateListLike(obj, fn) {
13204 if (Array.isArray(obj)) {
13205 for (let i = 0; i < obj.length; i++) {
13206 fn(obj[i]);
13207 }
13208 }
13209 else {
13210 const iterator = obj[getSymbolIterator()]();
13211 let item;
13212 while (!((item = iterator.next()).done)) {
13213 fn(item.value);
13214 }
13215 }
13216}
13217function isJsObject(o) {
13218 return o !== null && (typeof o === 'function' || typeof o === 'object');
13219}
13220
13221function devModeEqual(a, b) {
13222 const isListLikeIterableA = isListLikeIterable(a);
13223 const isListLikeIterableB = isListLikeIterable(b);
13224 if (isListLikeIterableA && isListLikeIterableB) {
13225 return areIterablesEqual(a, b, devModeEqual);
13226 }
13227 else {
13228 const isAObject = a && (typeof a === 'object' || typeof a === 'function');
13229 const isBObject = b && (typeof b === 'object' || typeof b === 'function');
13230 if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
13231 return true;
13232 }
13233 else {
13234 return Object.is(a, b);
13235 }
13236 }
13237}
13238
13239// TODO(misko): consider inlining
13240/** Updates binding and returns the value. */
13241function updateBinding(lView, bindingIndex, value) {
13242 return lView[bindingIndex] = value;
13243}
13244/** Gets the current binding value. */
13245function getBinding(lView, bindingIndex) {
13246 ngDevMode && assertIndexInRange(lView, bindingIndex);
13247 ngDevMode &&
13248 assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
13249 return lView[bindingIndex];
13250}
13251/**
13252 * Updates binding if changed, then returns whether it was updated.
13253 *
13254 * This function also checks the `CheckNoChangesMode` and throws if changes are made.
13255 * Some changes (Objects/iterables) during `CheckNoChangesMode` are exempt to comply with VE
13256 * behavior.
13257 *
13258 * @param lView current `LView`
13259 * @param bindingIndex The binding in the `LView` to check
13260 * @param value New value to check against `lView[bindingIndex]`
13261 * @returns `true` if the bindings has changed. (Throws if binding has changed during
13262 * `CheckNoChangesMode`)
13263 */
13264function bindingUpdated(lView, bindingIndex, value) {
13265 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
13266 ngDevMode &&
13267 assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`);
13268 const oldValue = lView[bindingIndex];
13269 if (Object.is(oldValue, value)) {
13270 return false;
13271 }
13272 else {
13273 if (ngDevMode && isInCheckNoChangesMode()) {
13274 // View engine didn't report undefined values as changed on the first checkNoChanges pass
13275 // (before the change detection was run).
13276 const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
13277 if (!devModeEqual(oldValueToCompare, value)) {
13278 const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
13279 throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName);
13280 }
13281 // There was a change, but the `devModeEqual` decided that the change is exempt from an error.
13282 // For this reason we exit as if no change. The early exit is needed to prevent the changed
13283 // value to be written into `LView` (If we would write the new value that we would not see it
13284 // as change on next CD.)
13285 return false;
13286 }
13287 lView[bindingIndex] = value;
13288 return true;
13289 }
13290}
13291/** Updates 2 bindings if changed, then returns whether either was updated. */
13292function bindingUpdated2(lView, bindingIndex, exp1, exp2) {
13293 const different = bindingUpdated(lView, bindingIndex, exp1);
13294 return bindingUpdated(lView, bindingIndex + 1, exp2) || different;
13295}
13296/** Updates 3 bindings if changed, then returns whether any was updated. */
13297function bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) {
13298 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
13299 return bindingUpdated(lView, bindingIndex + 2, exp3) || different;
13300}
13301/** Updates 4 bindings if changed, then returns whether any was updated. */
13302function bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) {
13303 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
13304 return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different;
13305}
13306
13307/**
13308 * Updates the value of or removes a bound attribute on an Element.
13309 *
13310 * Used in the case of `[attr.title]="value"`
13311 *
13312 * @param name name The name of the attribute.
13313 * @param value value The attribute is removed when value is `null` or `undefined`.
13314 * Otherwise the attribute value is set to the stringified value.
13315 * @param sanitizer An optional function used to sanitize the value.
13316 * @param namespace Optional namespace to use when setting the attribute.
13317 *
13318 * @codeGenApi
13319 */
13320function ɵɵattribute(name, value, sanitizer, namespace) {
13321 const lView = getLView();
13322 const bindingIndex = nextBindingIndex();
13323 if (bindingUpdated(lView, bindingIndex, value)) {
13324 const tView = getTView();
13325 const tNode = getSelectedTNode();
13326 elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace);
13327 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, 'attr.' + name, bindingIndex);
13328 }
13329 return ɵɵattribute;
13330}
13331
13332/**
13333 * Create interpolation bindings with a variable number of expressions.
13334 *
13335 * If there are 1 to 8 expressions `interpolation1()` to `interpolation8()` should be used instead.
13336 * Those are faster because there is no need to create an array of expressions and iterate over it.
13337 *
13338 * `values`:
13339 * - has static text at even indexes,
13340 * - has evaluated expressions at odd indexes.
13341 *
13342 * Returns the concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
13343 */
13344function interpolationV(lView, values) {
13345 ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
13346 ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
13347 let isBindingUpdated = false;
13348 let bindingIndex = getBindingIndex();
13349 for (let i = 1; i < values.length; i += 2) {
13350 // Check if bindings (odd indexes) have changed
13351 isBindingUpdated = bindingUpdated(lView, bindingIndex++, values[i]) || isBindingUpdated;
13352 }
13353 setBindingIndex(bindingIndex);
13354 if (!isBindingUpdated) {
13355 return NO_CHANGE;
13356 }
13357 // Build the updated content
13358 let content = values[0];
13359 for (let i = 1; i < values.length; i += 2) {
13360 content += renderStringify(values[i]) + values[i + 1];
13361 }
13362 return content;
13363}
13364/**
13365 * Creates an interpolation binding with 1 expression.
13366 *
13367 * @param prefix static value used for concatenation only.
13368 * @param v0 value checked for change.
13369 * @param suffix static value used for concatenation only.
13370 */
13371function interpolation1(lView, prefix, v0, suffix) {
13372 const different = bindingUpdated(lView, nextBindingIndex(), v0);
13373 return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE;
13374}
13375/**
13376 * Creates an interpolation binding with 2 expressions.
13377 */
13378function interpolation2(lView, prefix, v0, i0, v1, suffix) {
13379 const bindingIndex = getBindingIndex();
13380 const different = bindingUpdated2(lView, bindingIndex, v0, v1);
13381 incrementBindingIndex(2);
13382 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE;
13383}
13384/**
13385 * Creates an interpolation binding with 3 expressions.
13386 */
13387function interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix) {
13388 const bindingIndex = getBindingIndex();
13389 const different = bindingUpdated3(lView, bindingIndex, v0, v1, v2);
13390 incrementBindingIndex(3);
13391 return different ?
13392 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix :
13393 NO_CHANGE;
13394}
13395/**
13396 * Create an interpolation binding with 4 expressions.
13397 */
13398function interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
13399 const bindingIndex = getBindingIndex();
13400 const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13401 incrementBindingIndex(4);
13402 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13403 renderStringify(v2) + i2 + renderStringify(v3) + suffix :
13404 NO_CHANGE;
13405}
13406/**
13407 * Creates an interpolation binding with 5 expressions.
13408 */
13409function interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
13410 const bindingIndex = getBindingIndex();
13411 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13412 different = bindingUpdated(lView, bindingIndex + 4, v4) || different;
13413 incrementBindingIndex(5);
13414 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13415 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + suffix :
13416 NO_CHANGE;
13417}
13418/**
13419 * Creates an interpolation binding with 6 expressions.
13420 */
13421function interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
13422 const bindingIndex = getBindingIndex();
13423 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13424 different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different;
13425 incrementBindingIndex(6);
13426 return different ?
13427 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
13428 renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix :
13429 NO_CHANGE;
13430}
13431/**
13432 * Creates an interpolation binding with 7 expressions.
13433 */
13434function interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
13435 const bindingIndex = getBindingIndex();
13436 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13437 different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different;
13438 incrementBindingIndex(7);
13439 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13440 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
13441 renderStringify(v5) + i5 + renderStringify(v6) + suffix :
13442 NO_CHANGE;
13443}
13444/**
13445 * Creates an interpolation binding with 8 expressions.
13446 */
13447function interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
13448 const bindingIndex = getBindingIndex();
13449 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13450 different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different;
13451 incrementBindingIndex(8);
13452 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13453 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
13454 renderStringify(v5) + i5 + renderStringify(v6) + i6 + renderStringify(v7) + suffix :
13455 NO_CHANGE;
13456}
13457
13458/**
13459 *
13460 * Update an interpolated attribute on an element with single bound value surrounded by text.
13461 *
13462 * Used when the value passed to a property has 1 interpolated value in it:
13463 *
13464 * ```html
13465 * <div attr.title="prefix{{v0}}suffix"></div>
13466 * ```
13467 *
13468 * Its compiled representation is::
13469 *
13470 * ```ts
13471 * ɵɵattributeInterpolate1('title', 'prefix', v0, 'suffix');
13472 * ```
13473 *
13474 * @param attrName The name of the attribute to update
13475 * @param prefix Static value used for concatenation only.
13476 * @param v0 Value checked for change.
13477 * @param suffix Static value used for concatenation only.
13478 * @param sanitizer An optional sanitizer function
13479 * @returns itself, so that it may be chained.
13480 * @codeGenApi
13481 */
13482function ɵɵattributeInterpolate1(attrName, prefix, v0, suffix, sanitizer, namespace) {
13483 const lView = getLView();
13484 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
13485 if (interpolatedValue !== NO_CHANGE) {
13486 const tNode = getSelectedTNode();
13487 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13488 ngDevMode &&
13489 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 1, prefix, suffix);
13490 }
13491 return ɵɵattributeInterpolate1;
13492}
13493/**
13494 *
13495 * Update an interpolated attribute on an element with 2 bound values surrounded by text.
13496 *
13497 * Used when the value passed to a property has 2 interpolated values in it:
13498 *
13499 * ```html
13500 * <div attr.title="prefix{{v0}}-{{v1}}suffix"></div>
13501 * ```
13502 *
13503 * Its compiled representation is::
13504 *
13505 * ```ts
13506 * ɵɵattributeInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
13507 * ```
13508 *
13509 * @param attrName The name of the attribute to update
13510 * @param prefix Static value used for concatenation only.
13511 * @param v0 Value checked for change.
13512 * @param i0 Static value used for concatenation only.
13513 * @param v1 Value checked for change.
13514 * @param suffix Static value used for concatenation only.
13515 * @param sanitizer An optional sanitizer function
13516 * @returns itself, so that it may be chained.
13517 * @codeGenApi
13518 */
13519function ɵɵattributeInterpolate2(attrName, prefix, v0, i0, v1, suffix, sanitizer, namespace) {
13520 const lView = getLView();
13521 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
13522 if (interpolatedValue !== NO_CHANGE) {
13523 const tNode = getSelectedTNode();
13524 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13525 ngDevMode &&
13526 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 2, prefix, i0, suffix);
13527 }
13528 return ɵɵattributeInterpolate2;
13529}
13530/**
13531 *
13532 * Update an interpolated attribute on an element with 3 bound values surrounded by text.
13533 *
13534 * Used when the value passed to a property has 3 interpolated values in it:
13535 *
13536 * ```html
13537 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
13538 * ```
13539 *
13540 * Its compiled representation is::
13541 *
13542 * ```ts
13543 * ɵɵattributeInterpolate3(
13544 * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
13545 * ```
13546 *
13547 * @param attrName The name of the attribute to update
13548 * @param prefix Static value used for concatenation only.
13549 * @param v0 Value checked for change.
13550 * @param i0 Static value used for concatenation only.
13551 * @param v1 Value checked for change.
13552 * @param i1 Static value used for concatenation only.
13553 * @param v2 Value checked for change.
13554 * @param suffix Static value used for concatenation only.
13555 * @param sanitizer An optional sanitizer function
13556 * @returns itself, so that it may be chained.
13557 * @codeGenApi
13558 */
13559function ɵɵattributeInterpolate3(attrName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer, namespace) {
13560 const lView = getLView();
13561 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
13562 if (interpolatedValue !== NO_CHANGE) {
13563 const tNode = getSelectedTNode();
13564 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13565 ngDevMode &&
13566 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 3, prefix, i0, i1, suffix);
13567 }
13568 return ɵɵattributeInterpolate3;
13569}
13570/**
13571 *
13572 * Update an interpolated attribute on an element with 4 bound values surrounded by text.
13573 *
13574 * Used when the value passed to a property has 4 interpolated values in it:
13575 *
13576 * ```html
13577 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
13578 * ```
13579 *
13580 * Its compiled representation is::
13581 *
13582 * ```ts
13583 * ɵɵattributeInterpolate4(
13584 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
13585 * ```
13586 *
13587 * @param attrName The name of the attribute to update
13588 * @param prefix Static value used for concatenation only.
13589 * @param v0 Value checked for change.
13590 * @param i0 Static value used for concatenation only.
13591 * @param v1 Value checked for change.
13592 * @param i1 Static value used for concatenation only.
13593 * @param v2 Value checked for change.
13594 * @param i2 Static value used for concatenation only.
13595 * @param v3 Value checked for change.
13596 * @param suffix Static value used for concatenation only.
13597 * @param sanitizer An optional sanitizer function
13598 * @returns itself, so that it may be chained.
13599 * @codeGenApi
13600 */
13601function ɵɵattributeInterpolate4(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer, namespace) {
13602 const lView = getLView();
13603 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
13604 if (interpolatedValue !== NO_CHANGE) {
13605 const tNode = getSelectedTNode();
13606 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13607 ngDevMode &&
13608 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix);
13609 }
13610 return ɵɵattributeInterpolate4;
13611}
13612/**
13613 *
13614 * Update an interpolated attribute on an element with 5 bound values surrounded by text.
13615 *
13616 * Used when the value passed to a property has 5 interpolated values in it:
13617 *
13618 * ```html
13619 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
13620 * ```
13621 *
13622 * Its compiled representation is::
13623 *
13624 * ```ts
13625 * ɵɵattributeInterpolate5(
13626 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
13627 * ```
13628 *
13629 * @param attrName The name of the attribute to update
13630 * @param prefix Static value used for concatenation only.
13631 * @param v0 Value checked for change.
13632 * @param i0 Static value used for concatenation only.
13633 * @param v1 Value checked for change.
13634 * @param i1 Static value used for concatenation only.
13635 * @param v2 Value checked for change.
13636 * @param i2 Static value used for concatenation only.
13637 * @param v3 Value checked for change.
13638 * @param i3 Static value used for concatenation only.
13639 * @param v4 Value checked for change.
13640 * @param suffix Static value used for concatenation only.
13641 * @param sanitizer An optional sanitizer function
13642 * @returns itself, so that it may be chained.
13643 * @codeGenApi
13644 */
13645function ɵɵattributeInterpolate5(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer, namespace) {
13646 const lView = getLView();
13647 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
13648 if (interpolatedValue !== NO_CHANGE) {
13649 const tNode = getSelectedTNode();
13650 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13651 ngDevMode &&
13652 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix);
13653 }
13654 return ɵɵattributeInterpolate5;
13655}
13656/**
13657 *
13658 * Update an interpolated attribute on an element with 6 bound values surrounded by text.
13659 *
13660 * Used when the value passed to a property has 6 interpolated values in it:
13661 *
13662 * ```html
13663 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
13664 * ```
13665 *
13666 * Its compiled representation is::
13667 *
13668 * ```ts
13669 * ɵɵattributeInterpolate6(
13670 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
13671 * ```
13672 *
13673 * @param attrName The name of the attribute to update
13674 * @param prefix Static value used for concatenation only.
13675 * @param v0 Value checked for change.
13676 * @param i0 Static value used for concatenation only.
13677 * @param v1 Value checked for change.
13678 * @param i1 Static value used for concatenation only.
13679 * @param v2 Value checked for change.
13680 * @param i2 Static value used for concatenation only.
13681 * @param v3 Value checked for change.
13682 * @param i3 Static value used for concatenation only.
13683 * @param v4 Value checked for change.
13684 * @param i4 Static value used for concatenation only.
13685 * @param v5 Value checked for change.
13686 * @param suffix Static value used for concatenation only.
13687 * @param sanitizer An optional sanitizer function
13688 * @returns itself, so that it may be chained.
13689 * @codeGenApi
13690 */
13691function ɵɵattributeInterpolate6(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer, namespace) {
13692 const lView = getLView();
13693 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
13694 if (interpolatedValue !== NO_CHANGE) {
13695 const tNode = getSelectedTNode();
13696 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13697 ngDevMode &&
13698 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, i4, suffix);
13699 }
13700 return ɵɵattributeInterpolate6;
13701}
13702/**
13703 *
13704 * Update an interpolated attribute on an element with 7 bound values surrounded by text.
13705 *
13706 * Used when the value passed to a property has 7 interpolated values in it:
13707 *
13708 * ```html
13709 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
13710 * ```
13711 *
13712 * Its compiled representation is::
13713 *
13714 * ```ts
13715 * ɵɵattributeInterpolate7(
13716 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
13717 * ```
13718 *
13719 * @param attrName The name of the attribute to update
13720 * @param prefix Static value used for concatenation only.
13721 * @param v0 Value checked for change.
13722 * @param i0 Static value used for concatenation only.
13723 * @param v1 Value checked for change.
13724 * @param i1 Static value used for concatenation only.
13725 * @param v2 Value checked for change.
13726 * @param i2 Static value used for concatenation only.
13727 * @param v3 Value checked for change.
13728 * @param i3 Static value used for concatenation only.
13729 * @param v4 Value checked for change.
13730 * @param i4 Static value used for concatenation only.
13731 * @param v5 Value checked for change.
13732 * @param i5 Static value used for concatenation only.
13733 * @param v6 Value checked for change.
13734 * @param suffix Static value used for concatenation only.
13735 * @param sanitizer An optional sanitizer function
13736 * @returns itself, so that it may be chained.
13737 * @codeGenApi
13738 */
13739function ɵɵattributeInterpolate7(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer, namespace) {
13740 const lView = getLView();
13741 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
13742 if (interpolatedValue !== NO_CHANGE) {
13743 const tNode = getSelectedTNode();
13744 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13745 ngDevMode &&
13746 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, suffix);
13747 }
13748 return ɵɵattributeInterpolate7;
13749}
13750/**
13751 *
13752 * Update an interpolated attribute on an element with 8 bound values surrounded by text.
13753 *
13754 * Used when the value passed to a property has 8 interpolated values in it:
13755 *
13756 * ```html
13757 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
13758 * ```
13759 *
13760 * Its compiled representation is::
13761 *
13762 * ```ts
13763 * ɵɵattributeInterpolate8(
13764 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
13765 * ```
13766 *
13767 * @param attrName The name of the attribute to update
13768 * @param prefix Static value used for concatenation only.
13769 * @param v0 Value checked for change.
13770 * @param i0 Static value used for concatenation only.
13771 * @param v1 Value checked for change.
13772 * @param i1 Static value used for concatenation only.
13773 * @param v2 Value checked for change.
13774 * @param i2 Static value used for concatenation only.
13775 * @param v3 Value checked for change.
13776 * @param i3 Static value used for concatenation only.
13777 * @param v4 Value checked for change.
13778 * @param i4 Static value used for concatenation only.
13779 * @param v5 Value checked for change.
13780 * @param i5 Static value used for concatenation only.
13781 * @param v6 Value checked for change.
13782 * @param i6 Static value used for concatenation only.
13783 * @param v7 Value checked for change.
13784 * @param suffix Static value used for concatenation only.
13785 * @param sanitizer An optional sanitizer function
13786 * @returns itself, so that it may be chained.
13787 * @codeGenApi
13788 */
13789function ɵɵattributeInterpolate8(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer, namespace) {
13790 const lView = getLView();
13791 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
13792 if (interpolatedValue !== NO_CHANGE) {
13793 const tNode = getSelectedTNode();
13794 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13795 ngDevMode &&
13796 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, suffix);
13797 }
13798 return ɵɵattributeInterpolate8;
13799}
13800/**
13801 * Update an interpolated attribute on an element with 9 or more bound values surrounded by text.
13802 *
13803 * Used when the number of interpolated values exceeds 8.
13804 *
13805 * ```html
13806 * <div
13807 * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
13808 * ```
13809 *
13810 * Its compiled representation is::
13811 *
13812 * ```ts
13813 * ɵɵattributeInterpolateV(
13814 * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
13815 * 'suffix']);
13816 * ```
13817 *
13818 * @param attrName The name of the attribute to update.
13819 * @param values The collection of values and the strings in-between those values, beginning with
13820 * a string prefix and ending with a string suffix.
13821 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
13822 * @param sanitizer An optional sanitizer function
13823 * @returns itself, so that it may be chained.
13824 * @codeGenApi
13825 */
13826function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
13827 const lView = getLView();
13828 const interpolated = interpolationV(lView, values);
13829 if (interpolated !== NO_CHANGE) {
13830 const tNode = getSelectedTNode();
13831 elementAttributeInternal(tNode, lView, attrName, interpolated, sanitizer, namespace);
13832 if (ngDevMode) {
13833 const interpolationInBetween = [values[0]]; // prefix
13834 for (let i = 2; i < values.length; i += 2) {
13835 interpolationInBetween.push(values[i]);
13836 }
13837 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
13838 }
13839 }
13840 return ɵɵattributeInterpolateV;
13841}
13842
13843/**
13844 * Synchronously perform change detection on a component (and possibly its sub-components).
13845 *
13846 * This function triggers change detection in a synchronous way on a component.
13847 *
13848 * @param component The component which the change detection should be performed on.
13849 */
13850function detectChanges(component) {
13851 const view = getComponentViewByInstance(component);
13852 detectChangesInternal(view[TVIEW], view, component);
13853}
13854
13855function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
13856 ngDevMode && assertFirstCreatePass(tView);
13857 ngDevMode && ngDevMode.firstCreatePass++;
13858 const tViewConsts = tView.consts;
13859 // TODO(pk): refactor getOrCreateTNode to have the "create" only version
13860 const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
13861 resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
13862 registerPostOrderHooks(tView, tNode);
13863 const embeddedTView = tNode.tViews = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
13864 if (tView.queries !== null) {
13865 tView.queries.template(tView, tNode);
13866 embeddedTView.queries = tView.queries.embeddedTView(tNode);
13867 }
13868 return tNode;
13869}
13870/**
13871 * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
13872 *
13873 * <ng-template #foo>
13874 * <div></div>
13875 * </ng-template>
13876 *
13877 * @param index The index of the container in the data array
13878 * @param templateFn Inline template
13879 * @param decls The number of nodes, local refs, and pipes for this template
13880 * @param vars The number of bindings for this template
13881 * @param tagName The name of the container element, if applicable
13882 * @param attrsIndex Index of template attributes in the `consts` array.
13883 * @param localRefs Index of the local references in the `consts` array.
13884 * @param localRefExtractor A function which extracts local-refs values from the template.
13885 * Defaults to the current element associated with the local-ref.
13886 *
13887 * @codeGenApi
13888 */
13889function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
13890 const lView = getLView();
13891 const tView = getTView();
13892 const adjustedIndex = index + HEADER_OFFSET;
13893 const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
13894 tView.data[adjustedIndex];
13895 setCurrentTNode(tNode, false);
13896 const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : '');
13897 appendChild(tView, lView, comment, tNode);
13898 attachPatchData(comment, lView);
13899 addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
13900 if (isDirectiveHost(tNode)) {
13901 createDirectivesInstances(tView, lView, tNode);
13902 }
13903 if (localRefsIndex != null) {
13904 saveResolvedLocalsInData(lView, tNode, localRefExtractor);
13905 }
13906}
13907
13908/** Store a value in the `data` at a given `index`. */
13909function store(tView, lView, index, value) {
13910 // We don't store any static data for local variables, so the first time
13911 // we see the template, we should store as null to avoid a sparse array
13912 if (index >= tView.data.length) {
13913 tView.data[index] = null;
13914 tView.blueprint[index] = null;
13915 }
13916 lView[index] = value;
13917}
13918/**
13919 * Retrieves a local reference from the current contextViewData.
13920 *
13921 * If the reference to retrieve is in a parent view, this instruction is used in conjunction
13922 * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
13923 *
13924 * @param index The index of the local ref in contextViewData.
13925 *
13926 * @codeGenApi
13927 */
13928function ɵɵreference(index) {
13929 const contextLView = getContextLView();
13930 return load(contextLView, HEADER_OFFSET + index);
13931}
13932
13933/**
13934 * Update a property on a selected element.
13935 *
13936 * Operates on the element selected by index via the {@link select} instruction.
13937 *
13938 * If the property name also exists as an input property on one of the element's directives,
13939 * the component property will be set instead of the element property. This check must
13940 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled
13941 *
13942 * @param propName Name of property. Because it is going to DOM, this is not subject to
13943 * renaming as part of minification.
13944 * @param value New value to write.
13945 * @param sanitizer An optional function used to sanitize the value.
13946 * @returns This function returns itself so that it may be chained
13947 * (e.g. `property('name', ctx.name)('title', ctx.title)`)
13948 *
13949 * @codeGenApi
13950 */
13951function ɵɵproperty(propName, value, sanitizer) {
13952 const lView = getLView();
13953 const bindingIndex = nextBindingIndex();
13954 if (bindingUpdated(lView, bindingIndex, value)) {
13955 const tView = getTView();
13956 const tNode = getSelectedTNode();
13957 elementPropertyInternal(tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, false);
13958 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
13959 }
13960 return ɵɵproperty;
13961}
13962/**
13963 * Given `<div style="..." my-dir>` and `MyDir` with `@Input('style')` we need to write to
13964 * directive input.
13965 */
13966function setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased) {
13967 const inputs = tNode.inputs;
13968 const property = isClassBased ? 'class' : 'style';
13969 // We support both 'class' and `className` hence the fallback.
13970 setInputsForProperty(tView, lView, inputs[property], property, value);
13971}
13972
13973function elementStartFirstCreatePass(index, tView, lView, native, name, attrsIndex, localRefsIndex) {
13974 ngDevMode && assertFirstCreatePass(tView);
13975 ngDevMode && ngDevMode.firstCreatePass++;
13976 const tViewConsts = tView.consts;
13977 const attrs = getConstant(tViewConsts, attrsIndex);
13978 const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, name, attrs);
13979 const hasDirectives = resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
13980 if (ngDevMode) {
13981 validateElementIsKnown(native, lView, tNode.value, tView.schemas, hasDirectives);
13982 }
13983 if (tNode.attrs !== null) {
13984 computeStaticStyling(tNode, tNode.attrs, false);
13985 }
13986 if (tNode.mergedAttrs !== null) {
13987 computeStaticStyling(tNode, tNode.mergedAttrs, true);
13988 }
13989 if (tView.queries !== null) {
13990 tView.queries.elementStart(tView, tNode);
13991 }
13992 return tNode;
13993}
13994/**
13995 * Create DOM element. The instruction must later be followed by `elementEnd()` call.
13996 *
13997 * @param index Index of the element in the LView array
13998 * @param name Name of the DOM Node
13999 * @param attrsIndex Index of the element's attributes in the `consts` array.
14000 * @param localRefsIndex Index of the element's local references in the `consts` array.
14001 * @returns This function returns itself so that it may be chained.
14002 *
14003 * Attributes and localRefs are passed as an array of strings where elements with an even index
14004 * hold an attribute name and elements with an odd index hold an attribute value, ex.:
14005 * ['id', 'warning5', 'class', 'alert']
14006 *
14007 * @codeGenApi
14008 */
14009function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
14010 const lView = getLView();
14011 const tView = getTView();
14012 const adjustedIndex = HEADER_OFFSET + index;
14013 ngDevMode &&
14014 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'elements should be created before any bindings');
14015 ngDevMode && assertIndexInRange(lView, adjustedIndex);
14016 const renderer = lView[RENDERER];
14017 const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1());
14018 const tNode = tView.firstCreatePass ?
14019 elementStartFirstCreatePass(adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
14020 tView.data[adjustedIndex];
14021 setCurrentTNode(tNode, true);
14022 setupStaticAttributes(renderer, native, tNode);
14023 if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
14024 // In the i18n case, the translation may have removed this element, so only add it if it is not
14025 // detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
14026 appendChild(tView, lView, native, tNode);
14027 }
14028 // any immediate children of a component or template container must be pre-emptively
14029 // monkey-patched with the component view data so that the element can be inspected
14030 // later on using any element discovery utility methods (see `element_discovery.ts`)
14031 if (getElementDepthCount() === 0) {
14032 attachPatchData(native, lView);
14033 }
14034 increaseElementDepthCount();
14035 if (isDirectiveHost(tNode)) {
14036 createDirectivesInstances(tView, lView, tNode);
14037 executeContentQueries(tView, tNode, lView);
14038 }
14039 if (localRefsIndex !== null) {
14040 saveResolvedLocalsInData(lView, tNode);
14041 }
14042 return ɵɵelementStart;
14043}
14044/**
14045 * Mark the end of the element.
14046 * @returns This function returns itself so that it may be chained.
14047 *
14048 * @codeGenApi
14049 */
14050function ɵɵelementEnd() {
14051 let currentTNode = getCurrentTNode();
14052 ngDevMode && assertDefined(currentTNode, 'No parent node to close.');
14053 if (isCurrentTNodeParent()) {
14054 setCurrentTNodeAsNotParent();
14055 }
14056 else {
14057 ngDevMode && assertHasParent(getCurrentTNode());
14058 currentTNode = currentTNode.parent;
14059 setCurrentTNode(currentTNode, false);
14060 }
14061 const tNode = currentTNode;
14062 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */);
14063 decreaseElementDepthCount();
14064 const tView = getTView();
14065 if (tView.firstCreatePass) {
14066 registerPostOrderHooks(tView, currentTNode);
14067 if (isContentQueryHost(currentTNode)) {
14068 tView.queries.elementEnd(currentTNode);
14069 }
14070 }
14071 if (tNode.classesWithoutHost != null && hasClassInput(tNode)) {
14072 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.classesWithoutHost, true);
14073 }
14074 if (tNode.stylesWithoutHost != null && hasStyleInput(tNode)) {
14075 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.stylesWithoutHost, false);
14076 }
14077 return ɵɵelementEnd;
14078}
14079/**
14080 * Creates an empty element using {@link elementStart} and {@link elementEnd}
14081 *
14082 * @param index Index of the element in the data array
14083 * @param name Name of the DOM Node
14084 * @param attrsIndex Index of the element's attributes in the `consts` array.
14085 * @param localRefsIndex Index of the element's local references in the `consts` array.
14086 * @returns This function returns itself so that it may be chained.
14087 *
14088 * @codeGenApi
14089 */
14090function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
14091 ɵɵelementStart(index, name, attrsIndex, localRefsIndex);
14092 ɵɵelementEnd();
14093 return ɵɵelement;
14094}
14095
14096function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) {
14097 ngDevMode && ngDevMode.firstCreatePass++;
14098 const tViewConsts = tView.consts;
14099 const attrs = getConstant(tViewConsts, attrsIndex);
14100 const tNode = getOrCreateTNode(tView, index, 8 /* TNodeType.ElementContainer */, 'ng-container', attrs);
14101 // While ng-container doesn't necessarily support styling, we use the style context to identify
14102 // and execute directives on the ng-container.
14103 if (attrs !== null) {
14104 computeStaticStyling(tNode, attrs, true);
14105 }
14106 const localRefs = getConstant(tViewConsts, localRefsIndex);
14107 resolveDirectives(tView, lView, tNode, localRefs);
14108 if (tView.queries !== null) {
14109 tView.queries.elementStart(tView, tNode);
14110 }
14111 return tNode;
14112}
14113/**
14114 * Creates a logical container for other nodes (<ng-container>) backed by a comment node in the DOM.
14115 * The instruction must later be followed by `elementContainerEnd()` call.
14116 *
14117 * @param index Index of the element in the LView array
14118 * @param attrsIndex Index of the container attributes in the `consts` array.
14119 * @param localRefsIndex Index of the container's local references in the `consts` array.
14120 * @returns This function returns itself so that it may be chained.
14121 *
14122 * Even if this instruction accepts a set of attributes no actual attribute values are propagated to
14123 * the DOM (as a comment node can't have attributes). Attributes are here only for directive
14124 * matching purposes and setting initial inputs of directives.
14125 *
14126 * @codeGenApi
14127 */
14128function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
14129 const lView = getLView();
14130 const tView = getTView();
14131 const adjustedIndex = index + HEADER_OFFSET;
14132 ngDevMode && assertIndexInRange(lView, adjustedIndex);
14133 ngDevMode &&
14134 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings');
14135 const tNode = tView.firstCreatePass ?
14136 elementContainerStartFirstCreatePass(adjustedIndex, tView, lView, attrsIndex, localRefsIndex) :
14137 tView.data[adjustedIndex];
14138 setCurrentTNode(tNode, true);
14139 ngDevMode && ngDevMode.rendererCreateComment++;
14140 const native = lView[adjustedIndex] =
14141 lView[RENDERER].createComment(ngDevMode ? 'ng-container' : '');
14142 appendChild(tView, lView, native, tNode);
14143 attachPatchData(native, lView);
14144 if (isDirectiveHost(tNode)) {
14145 createDirectivesInstances(tView, lView, tNode);
14146 executeContentQueries(tView, tNode, lView);
14147 }
14148 if (localRefsIndex != null) {
14149 saveResolvedLocalsInData(lView, tNode);
14150 }
14151 return ɵɵelementContainerStart;
14152}
14153/**
14154 * Mark the end of the <ng-container>.
14155 * @returns This function returns itself so that it may be chained.
14156 *
14157 * @codeGenApi
14158 */
14159function ɵɵelementContainerEnd() {
14160 let currentTNode = getCurrentTNode();
14161 const tView = getTView();
14162 if (isCurrentTNodeParent()) {
14163 setCurrentTNodeAsNotParent();
14164 }
14165 else {
14166 ngDevMode && assertHasParent(currentTNode);
14167 currentTNode = currentTNode.parent;
14168 setCurrentTNode(currentTNode, false);
14169 }
14170 ngDevMode && assertTNodeType(currentTNode, 8 /* TNodeType.ElementContainer */);
14171 if (tView.firstCreatePass) {
14172 registerPostOrderHooks(tView, currentTNode);
14173 if (isContentQueryHost(currentTNode)) {
14174 tView.queries.elementEnd(currentTNode);
14175 }
14176 }
14177 return ɵɵelementContainerEnd;
14178}
14179/**
14180 * Creates an empty logical container using {@link elementContainerStart}
14181 * and {@link elementContainerEnd}
14182 *
14183 * @param index Index of the element in the LView array
14184 * @param attrsIndex Index of the container attributes in the `consts` array.
14185 * @param localRefsIndex Index of the container's local references in the `consts` array.
14186 * @returns This function returns itself so that it may be chained.
14187 *
14188 * @codeGenApi
14189 */
14190function ɵɵelementContainer(index, attrsIndex, localRefsIndex) {
14191 ɵɵelementContainerStart(index, attrsIndex, localRefsIndex);
14192 ɵɵelementContainerEnd();
14193 return ɵɵelementContainer;
14194}
14195
14196/**
14197 * Returns the current OpaqueViewState instance.
14198 *
14199 * Used in conjunction with the restoreView() instruction to save a snapshot
14200 * of the current view and restore it when listeners are invoked. This allows
14201 * walking the declaration view tree in listeners to get vars from parent views.
14202 *
14203 * @codeGenApi
14204 */
14205function ɵɵgetCurrentView() {
14206 return getLView();
14207}
14208
14209/**
14210 * Determine if the argument is shaped like a Promise
14211 */
14212function isPromise(obj) {
14213 // allow any Promise/A+ compliant thenable.
14214 // It's up to the caller to ensure that obj.then conforms to the spec
14215 return !!obj && typeof obj.then === 'function';
14216}
14217/**
14218 * Determine if the argument is a Subscribable
14219 */
14220function isSubscribable(obj) {
14221 return !!obj && typeof obj.subscribe === 'function';
14222}
14223/**
14224 * Determine if the argument is an Observable
14225 *
14226 * Strictly this tests that the `obj` is `Subscribable`, since `Observable`
14227 * types need additional methods, such as `lift()`. But it is adequate for our
14228 * needs since within the Angular framework code we only ever need to use the
14229 * `subscribe()` method, and RxJS has mechanisms to wrap `Subscribable` objects
14230 * into `Observable` as needed.
14231 */
14232const isObservable = isSubscribable;
14233
14234/**
14235 * Adds an event listener to the current node.
14236 *
14237 * If an output exists on one of the node's directives, it also subscribes to the output
14238 * and saves the subscription for later cleanup.
14239 *
14240 * @param eventName Name of the event
14241 * @param listenerFn The function to be called when event emits
14242 * @param useCapture Whether or not to use capture in event listener - this argument is a reminder
14243 * from the Renderer3 infrastructure and should be removed from the instruction arguments
14244 * @param eventTargetResolver Function that returns global target information in case this listener
14245 * should be attached to a global object like window, document or body
14246 *
14247 * @codeGenApi
14248 */
14249function ɵɵlistener(eventName, listenerFn, useCapture, eventTargetResolver) {
14250 const lView = getLView();
14251 const tView = getTView();
14252 const tNode = getCurrentTNode();
14253 listenerInternal(tView, lView, lView[RENDERER], tNode, eventName, listenerFn, eventTargetResolver);
14254 return ɵɵlistener;
14255}
14256/**
14257 * Registers a synthetic host listener (e.g. `(@foo.start)`) on a component or directive.
14258 *
14259 * This instruction is for compatibility purposes and is designed to ensure that a
14260 * synthetic host listener (e.g. `@HostListener('@foo.start')`) properly gets rendered
14261 * in the component's renderer. Normally all host listeners are evaluated with the
14262 * parent component's renderer, but, in the case of animation @triggers, they need
14263 * to be evaluated with the sub component's renderer (because that's where the
14264 * animation triggers are defined).
14265 *
14266 * Do not use this instruction as a replacement for `listener`. This instruction
14267 * only exists to ensure compatibility with the ViewEngine's host binding behavior.
14268 *
14269 * @param eventName Name of the event
14270 * @param listenerFn The function to be called when event emits
14271 * @param useCapture Whether or not to use capture in event listener
14272 * @param eventTargetResolver Function that returns global target information in case this listener
14273 * should be attached to a global object like window, document or body
14274 *
14275 * @codeGenApi
14276 */
14277function ɵɵsyntheticHostListener(eventName, listenerFn) {
14278 const tNode = getCurrentTNode();
14279 const lView = getLView();
14280 const tView = getTView();
14281 const currentDef = getCurrentDirectiveDef(tView.data);
14282 const renderer = loadComponentRenderer(currentDef, tNode, lView);
14283 listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn);
14284 return ɵɵsyntheticHostListener;
14285}
14286/**
14287 * A utility function that checks if a given element has already an event handler registered for an
14288 * event with a specified name. The TView.cleanup data structure is used to find out which events
14289 * are registered for a given element.
14290 */
14291function findExistingListener(tView, lView, eventName, tNodeIdx) {
14292 const tCleanup = tView.cleanup;
14293 if (tCleanup != null) {
14294 for (let i = 0; i < tCleanup.length - 1; i += 2) {
14295 const cleanupEventName = tCleanup[i];
14296 if (cleanupEventName === eventName && tCleanup[i + 1] === tNodeIdx) {
14297 // We have found a matching event name on the same node but it might not have been
14298 // registered yet, so we must explicitly verify entries in the LView cleanup data
14299 // structures.
14300 const lCleanup = lView[CLEANUP];
14301 const listenerIdxInLCleanup = tCleanup[i + 2];
14302 return lCleanup.length > listenerIdxInLCleanup ? lCleanup[listenerIdxInLCleanup] : null;
14303 }
14304 // TView.cleanup can have a mix of 4-elements entries (for event handler cleanups) or
14305 // 2-element entries (for directive and queries destroy hooks). As such we can encounter
14306 // blocks of 4 or 2 items in the tView.cleanup and this is why we iterate over 2 elements
14307 // first and jump another 2 elements if we detect listeners cleanup (4 elements). Also check
14308 // documentation of TView.cleanup for more details of this data structure layout.
14309 if (typeof cleanupEventName === 'string') {
14310 i += 2;
14311 }
14312 }
14313 }
14314 return null;
14315}
14316function listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn, eventTargetResolver) {
14317 const isTNodeDirectiveHost = isDirectiveHost(tNode);
14318 const firstCreatePass = tView.firstCreatePass;
14319 const tCleanup = firstCreatePass && getOrCreateTViewCleanup(tView);
14320 const context = lView[CONTEXT];
14321 // When the ɵɵlistener instruction was generated and is executed we know that there is either a
14322 // native listener or a directive output on this element. As such we we know that we will have to
14323 // register a listener and store its cleanup function on LView.
14324 const lCleanup = getOrCreateLViewCleanup(lView);
14325 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
14326 let processOutputs = true;
14327 // Adding a native event listener is applicable when:
14328 // - The corresponding TNode represents a DOM element.
14329 // - The event target has a resolver (usually resulting in a global object,
14330 // such as `window` or `document`).
14331 if ((tNode.type & 3 /* TNodeType.AnyRNode */) || eventTargetResolver) {
14332 const native = getNativeByTNode(tNode, lView);
14333 const target = eventTargetResolver ? eventTargetResolver(native) : native;
14334 const lCleanupIndex = lCleanup.length;
14335 const idxOrTargetGetter = eventTargetResolver ?
14336 (_lView) => eventTargetResolver(unwrapRNode(_lView[tNode.index])) :
14337 tNode.index;
14338 // In order to match current behavior, native DOM event listeners must be added for all
14339 // events (including outputs).
14340 // There might be cases where multiple directives on the same element try to register an event
14341 // handler function for the same event. In this situation we want to avoid registration of
14342 // several native listeners as each registration would be intercepted by NgZone and
14343 // trigger change detection. This would mean that a single user action would result in several
14344 // change detections being invoked. To avoid this situation we want to have only one call to
14345 // native handler registration (for the same element and same type of event).
14346 //
14347 // In order to have just one native event handler in presence of multiple handler functions,
14348 // we just register a first handler function as a native event listener and then chain
14349 // (coalesce) other handler functions on top of the first native handler function.
14350 let existingListener = null;
14351 // Please note that the coalescing described here doesn't happen for events specifying an
14352 // alternative target (ex. (document:click)) - this is to keep backward compatibility with the
14353 // view engine.
14354 // Also, we don't have to search for existing listeners is there are no directives
14355 // matching on a given node as we can't register multiple event handlers for the same event in
14356 // a template (this would mean having duplicate attributes).
14357 if (!eventTargetResolver && isTNodeDirectiveHost) {
14358 existingListener = findExistingListener(tView, lView, eventName, tNode.index);
14359 }
14360 if (existingListener !== null) {
14361 // Attach a new listener to coalesced listeners list, maintaining the order in which
14362 // listeners are registered. For performance reasons, we keep a reference to the last
14363 // listener in that list (in `__ngLastListenerFn__` field), so we can avoid going through
14364 // the entire set each time we need to add a new listener.
14365 const lastListenerFn = existingListener.__ngLastListenerFn__ || existingListener;
14366 lastListenerFn.__ngNextListenerFn__ = listenerFn;
14367 existingListener.__ngLastListenerFn__ = listenerFn;
14368 processOutputs = false;
14369 }
14370 else {
14371 listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
14372 const cleanupFn = renderer.listen(target, eventName, listenerFn);
14373 ngDevMode && ngDevMode.rendererAddEventListener++;
14374 lCleanup.push(listenerFn, cleanupFn);
14375 tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1);
14376 }
14377 }
14378 else {
14379 // Even if there is no native listener to add, we still need to wrap the listener so that OnPush
14380 // ancestors are marked dirty when an event occurs.
14381 listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
14382 }
14383 // subscribe to directive outputs
14384 const outputs = tNode.outputs;
14385 let props;
14386 if (processOutputs && outputs !== null && (props = outputs[eventName])) {
14387 const propsLength = props.length;
14388 if (propsLength) {
14389 for (let i = 0; i < propsLength; i += 2) {
14390 const index = props[i];
14391 ngDevMode && assertIndexInRange(lView, index);
14392 const minifiedName = props[i + 1];
14393 const directiveInstance = lView[index];
14394 const output = directiveInstance[minifiedName];
14395 if (ngDevMode && !isObservable(output)) {
14396 throw new Error(`@Output ${minifiedName} not initialized in '${directiveInstance.constructor.name}'.`);
14397 }
14398 const subscription = output.subscribe(listenerFn);
14399 const idx = lCleanup.length;
14400 lCleanup.push(listenerFn, subscription);
14401 tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
14402 }
14403 }
14404 }
14405}
14406function executeListenerWithErrorHandling(lView, context, listenerFn, e) {
14407 try {
14408 profiler(6 /* ProfilerEvent.OutputStart */, context, listenerFn);
14409 // Only explicitly returning false from a listener should preventDefault
14410 return listenerFn(e) !== false;
14411 }
14412 catch (error) {
14413 handleError(lView, error);
14414 return false;
14415 }
14416 finally {
14417 profiler(7 /* ProfilerEvent.OutputEnd */, context, listenerFn);
14418 }
14419}
14420/**
14421 * Wraps an event listener with a function that marks ancestors dirty and prevents default behavior,
14422 * if applicable.
14423 *
14424 * @param tNode The TNode associated with this listener
14425 * @param lView The LView that contains this listener
14426 * @param listenerFn The listener function to call
14427 * @param wrapWithPreventDefault Whether or not to prevent default behavior
14428 * (the procedural renderer does this already, so in those cases, we should skip)
14429 */
14430function wrapListener(tNode, lView, context, listenerFn, wrapWithPreventDefault) {
14431 // Note: we are performing most of the work in the listener function itself
14432 // to optimize listener registration.
14433 return function wrapListenerIn_markDirtyAndPreventDefault(e) {
14434 // Ivy uses `Function` as a special token that allows us to unwrap the function
14435 // so that it can be invoked programmatically by `DebugNode.triggerEventHandler`.
14436 if (e === Function) {
14437 return listenerFn;
14438 }
14439 // In order to be backwards compatible with View Engine, events on component host nodes
14440 // must also mark the component view itself dirty (i.e. the view that it owns).
14441 const startView = tNode.componentOffset > -1 ? getComponentLViewByIndex(tNode.index, lView) : lView;
14442 markViewDirty(startView);
14443 let result = executeListenerWithErrorHandling(lView, context, listenerFn, e);
14444 // A just-invoked listener function might have coalesced listeners so we need to check for
14445 // their presence and invoke as needed.
14446 let nextListenerFn = wrapListenerIn_markDirtyAndPreventDefault.__ngNextListenerFn__;
14447 while (nextListenerFn) {
14448 // We should prevent default if any of the listeners explicitly return false
14449 result = executeListenerWithErrorHandling(lView, context, nextListenerFn, e) && result;
14450 nextListenerFn = nextListenerFn.__ngNextListenerFn__;
14451 }
14452 if (wrapWithPreventDefault && result === false) {
14453 e.preventDefault();
14454 // Necessary for legacy browsers that don't support preventDefault (e.g. IE)
14455 e.returnValue = false;
14456 }
14457 return result;
14458 };
14459}
14460
14461/**
14462 * Retrieves a context at the level specified and saves it as the global, contextViewData.
14463 * Will get the next level up if level is not specified.
14464 *
14465 * This is used to save contexts of parent views so they can be bound in embedded views, or
14466 * in conjunction with reference() to bind a ref from a parent view.
14467 *
14468 * @param level The relative level of the view from which to grab context compared to contextVewData
14469 * @returns context
14470 *
14471 * @codeGenApi
14472 */
14473function ɵɵnextContext(level = 1) {
14474 return nextContextImpl(level);
14475}
14476
14477/**
14478 * Checks a given node against matching projection slots and returns the
14479 * determined slot index. Returns "null" if no slot matched the given node.
14480 *
14481 * This function takes into account the parsed ngProjectAs selector from the
14482 * node's attributes. If present, it will check whether the ngProjectAs selector
14483 * matches any of the projection slot selectors.
14484 */
14485function matchingProjectionSlotIndex(tNode, projectionSlots) {
14486 let wildcardNgContentIndex = null;
14487 const ngProjectAsAttrVal = getProjectAsAttrValue(tNode);
14488 for (let i = 0; i < projectionSlots.length; i++) {
14489 const slotValue = projectionSlots[i];
14490 // The last wildcard projection slot should match all nodes which aren't matching
14491 // any selector. This is necessary to be backwards compatible with view engine.
14492 if (slotValue === '*') {
14493 wildcardNgContentIndex = i;
14494 continue;
14495 }
14496 // If we ran into an `ngProjectAs` attribute, we should match its parsed selector
14497 // to the list of selectors, otherwise we fall back to matching against the node.
14498 if (ngProjectAsAttrVal === null ?
14499 isNodeMatchingSelectorList(tNode, slotValue, /* isProjectionMode */ true) :
14500 isSelectorInSelectorList(ngProjectAsAttrVal, slotValue)) {
14501 return i; // first matching selector "captures" a given node
14502 }
14503 }
14504 return wildcardNgContentIndex;
14505}
14506/**
14507 * Instruction to distribute projectable nodes among <ng-content> occurrences in a given template.
14508 * It takes all the selectors from the entire component's template and decides where
14509 * each projected node belongs (it re-distributes nodes among "buckets" where each "bucket" is
14510 * backed by a selector).
14511 *
14512 * This function requires CSS selectors to be provided in 2 forms: parsed (by a compiler) and text,
14513 * un-parsed form.
14514 *
14515 * The parsed form is needed for efficient matching of a node against a given CSS selector.
14516 * The un-parsed, textual form is needed for support of the ngProjectAs attribute.
14517 *
14518 * Having a CSS selector in 2 different formats is not ideal, but alternatives have even more
14519 * drawbacks:
14520 * - having only a textual form would require runtime parsing of CSS selectors;
14521 * - we can't have only a parsed as we can't re-construct textual form from it (as entered by a
14522 * template author).
14523 *
14524 * @param projectionSlots? A collection of projection slots. A projection slot can be based
14525 * on a parsed CSS selectors or set to the wildcard selector ("*") in order to match
14526 * all nodes which do not match any selector. If not specified, a single wildcard
14527 * selector projection slot will be defined.
14528 *
14529 * @codeGenApi
14530 */
14531function ɵɵprojectionDef(projectionSlots) {
14532 const componentNode = getLView()[DECLARATION_COMPONENT_VIEW][T_HOST];
14533 if (!componentNode.projection) {
14534 // If no explicit projection slots are defined, fall back to a single
14535 // projection slot with the wildcard selector.
14536 const numProjectionSlots = projectionSlots ? projectionSlots.length : 1;
14537 const projectionHeads = componentNode.projection =
14538 newArray(numProjectionSlots, null);
14539 const tails = projectionHeads.slice();
14540 let componentChild = componentNode.child;
14541 while (componentChild !== null) {
14542 const slotIndex = projectionSlots ? matchingProjectionSlotIndex(componentChild, projectionSlots) : 0;
14543 if (slotIndex !== null) {
14544 if (tails[slotIndex]) {
14545 tails[slotIndex].projectionNext = componentChild;
14546 }
14547 else {
14548 projectionHeads[slotIndex] = componentChild;
14549 }
14550 tails[slotIndex] = componentChild;
14551 }
14552 componentChild = componentChild.next;
14553 }
14554 }
14555}
14556/**
14557 * Inserts previously re-distributed projected nodes. This instruction must be preceded by a call
14558 * to the projectionDef instruction.
14559 *
14560 * @param nodeIndex
14561 * @param selectorIndex:
14562 * - 0 when the selector is `*` (or unspecified as this is the default value),
14563 * - 1 based index of the selector from the {@link projectionDef}
14564 *
14565 * @codeGenApi
14566 */
14567function ɵɵprojection(nodeIndex, selectorIndex = 0, attrs) {
14568 const lView = getLView();
14569 const tView = getTView();
14570 const tProjectionNode = getOrCreateTNode(tView, HEADER_OFFSET + nodeIndex, 16 /* TNodeType.Projection */, null, attrs || null);
14571 // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views.
14572 if (tProjectionNode.projection === null)
14573 tProjectionNode.projection = selectorIndex;
14574 // `<ng-content>` has no content
14575 setCurrentTNodeAsNotParent();
14576 if ((tProjectionNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
14577 // re-distribution of projectable nodes is stored on a component's view level
14578 applyProjection(tView, lView, tProjectionNode);
14579 }
14580}
14581
14582/**
14583 *
14584 * Update an interpolated property on an element with a lone bound value
14585 *
14586 * Used when the value passed to a property has 1 interpolated value in it, an no additional text
14587 * surrounds that interpolated value:
14588 *
14589 * ```html
14590 * <div title="{{v0}}"></div>
14591 * ```
14592 *
14593 * Its compiled representation is::
14594 *
14595 * ```ts
14596 * ɵɵpropertyInterpolate('title', v0);
14597 * ```
14598 *
14599 * If the property name also exists as an input property on one of the element's directives,
14600 * the component property will be set instead of the element property. This check must
14601 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14602 *
14603 * @param propName The name of the property to update
14604 * @param prefix Static value used for concatenation only.
14605 * @param v0 Value checked for change.
14606 * @param suffix Static value used for concatenation only.
14607 * @param sanitizer An optional sanitizer function
14608 * @returns itself, so that it may be chained.
14609 * @codeGenApi
14610 */
14611function ɵɵpropertyInterpolate(propName, v0, sanitizer) {
14612 ɵɵpropertyInterpolate1(propName, '', v0, '', sanitizer);
14613 return ɵɵpropertyInterpolate;
14614}
14615/**
14616 *
14617 * Update an interpolated property on an element with single bound value surrounded by text.
14618 *
14619 * Used when the value passed to a property has 1 interpolated value in it:
14620 *
14621 * ```html
14622 * <div title="prefix{{v0}}suffix"></div>
14623 * ```
14624 *
14625 * Its compiled representation is::
14626 *
14627 * ```ts
14628 * ɵɵpropertyInterpolate1('title', 'prefix', v0, 'suffix');
14629 * ```
14630 *
14631 * If the property name also exists as an input property on one of the element's directives,
14632 * the component property will be set instead of the element property. This check must
14633 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14634 *
14635 * @param propName The name of the property to update
14636 * @param prefix Static value used for concatenation only.
14637 * @param v0 Value checked for change.
14638 * @param suffix Static value used for concatenation only.
14639 * @param sanitizer An optional sanitizer function
14640 * @returns itself, so that it may be chained.
14641 * @codeGenApi
14642 */
14643function ɵɵpropertyInterpolate1(propName, prefix, v0, suffix, sanitizer) {
14644 const lView = getLView();
14645 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
14646 if (interpolatedValue !== NO_CHANGE) {
14647 const tView = getTView();
14648 const tNode = getSelectedTNode();
14649 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14650 ngDevMode &&
14651 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 1, prefix, suffix);
14652 }
14653 return ɵɵpropertyInterpolate1;
14654}
14655/**
14656 *
14657 * Update an interpolated property on an element with 2 bound values surrounded by text.
14658 *
14659 * Used when the value passed to a property has 2 interpolated values in it:
14660 *
14661 * ```html
14662 * <div title="prefix{{v0}}-{{v1}}suffix"></div>
14663 * ```
14664 *
14665 * Its compiled representation is::
14666 *
14667 * ```ts
14668 * ɵɵpropertyInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
14669 * ```
14670 *
14671 * If the property name also exists as an input property on one of the element's directives,
14672 * the component property will be set instead of the element property. This check must
14673 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14674 *
14675 * @param propName The name of the property to update
14676 * @param prefix Static value used for concatenation only.
14677 * @param v0 Value checked for change.
14678 * @param i0 Static value used for concatenation only.
14679 * @param v1 Value checked for change.
14680 * @param suffix Static value used for concatenation only.
14681 * @param sanitizer An optional sanitizer function
14682 * @returns itself, so that it may be chained.
14683 * @codeGenApi
14684 */
14685function ɵɵpropertyInterpolate2(propName, prefix, v0, i0, v1, suffix, sanitizer) {
14686 const lView = getLView();
14687 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
14688 if (interpolatedValue !== NO_CHANGE) {
14689 const tView = getTView();
14690 const tNode = getSelectedTNode();
14691 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14692 ngDevMode &&
14693 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 2, prefix, i0, suffix);
14694 }
14695 return ɵɵpropertyInterpolate2;
14696}
14697/**
14698 *
14699 * Update an interpolated property on an element with 3 bound values surrounded by text.
14700 *
14701 * Used when the value passed to a property has 3 interpolated values in it:
14702 *
14703 * ```html
14704 * <div title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
14705 * ```
14706 *
14707 * Its compiled representation is::
14708 *
14709 * ```ts
14710 * ɵɵpropertyInterpolate3(
14711 * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
14712 * ```
14713 *
14714 * If the property name also exists as an input property on one of the element's directives,
14715 * the component property will be set instead of the element property. This check must
14716 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14717 *
14718 * @param propName The name of the property to update
14719 * @param prefix Static value used for concatenation only.
14720 * @param v0 Value checked for change.
14721 * @param i0 Static value used for concatenation only.
14722 * @param v1 Value checked for change.
14723 * @param i1 Static value used for concatenation only.
14724 * @param v2 Value checked for change.
14725 * @param suffix Static value used for concatenation only.
14726 * @param sanitizer An optional sanitizer function
14727 * @returns itself, so that it may be chained.
14728 * @codeGenApi
14729 */
14730function ɵɵpropertyInterpolate3(propName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer) {
14731 const lView = getLView();
14732 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
14733 if (interpolatedValue !== NO_CHANGE) {
14734 const tView = getTView();
14735 const tNode = getSelectedTNode();
14736 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14737 ngDevMode &&
14738 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 3, prefix, i0, i1, suffix);
14739 }
14740 return ɵɵpropertyInterpolate3;
14741}
14742/**
14743 *
14744 * Update an interpolated property on an element with 4 bound values surrounded by text.
14745 *
14746 * Used when the value passed to a property has 4 interpolated values in it:
14747 *
14748 * ```html
14749 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
14750 * ```
14751 *
14752 * Its compiled representation is::
14753 *
14754 * ```ts
14755 * ɵɵpropertyInterpolate4(
14756 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
14757 * ```
14758 *
14759 * If the property name also exists as an input property on one of the element's directives,
14760 * the component property will be set instead of the element property. This check must
14761 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14762 *
14763 * @param propName The name of the property to update
14764 * @param prefix Static value used for concatenation only.
14765 * @param v0 Value checked for change.
14766 * @param i0 Static value used for concatenation only.
14767 * @param v1 Value checked for change.
14768 * @param i1 Static value used for concatenation only.
14769 * @param v2 Value checked for change.
14770 * @param i2 Static value used for concatenation only.
14771 * @param v3 Value checked for change.
14772 * @param suffix Static value used for concatenation only.
14773 * @param sanitizer An optional sanitizer function
14774 * @returns itself, so that it may be chained.
14775 * @codeGenApi
14776 */
14777function ɵɵpropertyInterpolate4(propName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer) {
14778 const lView = getLView();
14779 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
14780 if (interpolatedValue !== NO_CHANGE) {
14781 const tView = getTView();
14782 const tNode = getSelectedTNode();
14783 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14784 ngDevMode &&
14785 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix);
14786 }
14787 return ɵɵpropertyInterpolate4;
14788}
14789/**
14790 *
14791 * Update an interpolated property on an element with 5 bound values surrounded by text.
14792 *
14793 * Used when the value passed to a property has 5 interpolated values in it:
14794 *
14795 * ```html
14796 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
14797 * ```
14798 *
14799 * Its compiled representation is::
14800 *
14801 * ```ts
14802 * ɵɵpropertyInterpolate5(
14803 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
14804 * ```
14805 *
14806 * If the property name also exists as an input property on one of the element's directives,
14807 * the component property will be set instead of the element property. This check must
14808 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14809 *
14810 * @param propName The name of the property to update
14811 * @param prefix Static value used for concatenation only.
14812 * @param v0 Value checked for change.
14813 * @param i0 Static value used for concatenation only.
14814 * @param v1 Value checked for change.
14815 * @param i1 Static value used for concatenation only.
14816 * @param v2 Value checked for change.
14817 * @param i2 Static value used for concatenation only.
14818 * @param v3 Value checked for change.
14819 * @param i3 Static value used for concatenation only.
14820 * @param v4 Value checked for change.
14821 * @param suffix Static value used for concatenation only.
14822 * @param sanitizer An optional sanitizer function
14823 * @returns itself, so that it may be chained.
14824 * @codeGenApi
14825 */
14826function ɵɵpropertyInterpolate5(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer) {
14827 const lView = getLView();
14828 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
14829 if (interpolatedValue !== NO_CHANGE) {
14830 const tView = getTView();
14831 const tNode = getSelectedTNode();
14832 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14833 ngDevMode &&
14834 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix);
14835 }
14836 return ɵɵpropertyInterpolate5;
14837}
14838/**
14839 *
14840 * Update an interpolated property on an element with 6 bound values surrounded by text.
14841 *
14842 * Used when the value passed to a property has 6 interpolated values in it:
14843 *
14844 * ```html
14845 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
14846 * ```
14847 *
14848 * Its compiled representation is::
14849 *
14850 * ```ts
14851 * ɵɵpropertyInterpolate6(
14852 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
14853 * ```
14854 *
14855 * If the property name also exists as an input property on one of the element's directives,
14856 * the component property will be set instead of the element property. This check must
14857 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14858 *
14859 * @param propName The name of the property to update
14860 * @param prefix Static value used for concatenation only.
14861 * @param v0 Value checked for change.
14862 * @param i0 Static value used for concatenation only.
14863 * @param v1 Value checked for change.
14864 * @param i1 Static value used for concatenation only.
14865 * @param v2 Value checked for change.
14866 * @param i2 Static value used for concatenation only.
14867 * @param v3 Value checked for change.
14868 * @param i3 Static value used for concatenation only.
14869 * @param v4 Value checked for change.
14870 * @param i4 Static value used for concatenation only.
14871 * @param v5 Value checked for change.
14872 * @param suffix Static value used for concatenation only.
14873 * @param sanitizer An optional sanitizer function
14874 * @returns itself, so that it may be chained.
14875 * @codeGenApi
14876 */
14877function ɵɵpropertyInterpolate6(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer) {
14878 const lView = getLView();
14879 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
14880 if (interpolatedValue !== NO_CHANGE) {
14881 const tView = getTView();
14882 const tNode = getSelectedTNode();
14883 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14884 ngDevMode &&
14885 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, i4, suffix);
14886 }
14887 return ɵɵpropertyInterpolate6;
14888}
14889/**
14890 *
14891 * Update an interpolated property on an element with 7 bound values surrounded by text.
14892 *
14893 * Used when the value passed to a property has 7 interpolated values in it:
14894 *
14895 * ```html
14896 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
14897 * ```
14898 *
14899 * Its compiled representation is::
14900 *
14901 * ```ts
14902 * ɵɵpropertyInterpolate7(
14903 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
14904 * ```
14905 *
14906 * If the property name also exists as an input property on one of the element's directives,
14907 * the component property will be set instead of the element property. This check must
14908 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14909 *
14910 * @param propName The name of the property to update
14911 * @param prefix Static value used for concatenation only.
14912 * @param v0 Value checked for change.
14913 * @param i0 Static value used for concatenation only.
14914 * @param v1 Value checked for change.
14915 * @param i1 Static value used for concatenation only.
14916 * @param v2 Value checked for change.
14917 * @param i2 Static value used for concatenation only.
14918 * @param v3 Value checked for change.
14919 * @param i3 Static value used for concatenation only.
14920 * @param v4 Value checked for change.
14921 * @param i4 Static value used for concatenation only.
14922 * @param v5 Value checked for change.
14923 * @param i5 Static value used for concatenation only.
14924 * @param v6 Value checked for change.
14925 * @param suffix Static value used for concatenation only.
14926 * @param sanitizer An optional sanitizer function
14927 * @returns itself, so that it may be chained.
14928 * @codeGenApi
14929 */
14930function ɵɵpropertyInterpolate7(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer) {
14931 const lView = getLView();
14932 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
14933 if (interpolatedValue !== NO_CHANGE) {
14934 const tView = getTView();
14935 const tNode = getSelectedTNode();
14936 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14937 ngDevMode &&
14938 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, suffix);
14939 }
14940 return ɵɵpropertyInterpolate7;
14941}
14942/**
14943 *
14944 * Update an interpolated property on an element with 8 bound values surrounded by text.
14945 *
14946 * Used when the value passed to a property has 8 interpolated values in it:
14947 *
14948 * ```html
14949 * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
14950 * ```
14951 *
14952 * Its compiled representation is::
14953 *
14954 * ```ts
14955 * ɵɵpropertyInterpolate8(
14956 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
14957 * ```
14958 *
14959 * If the property name also exists as an input property on one of the element's directives,
14960 * the component property will be set instead of the element property. This check must
14961 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
14962 *
14963 * @param propName The name of the property to update
14964 * @param prefix Static value used for concatenation only.
14965 * @param v0 Value checked for change.
14966 * @param i0 Static value used for concatenation only.
14967 * @param v1 Value checked for change.
14968 * @param i1 Static value used for concatenation only.
14969 * @param v2 Value checked for change.
14970 * @param i2 Static value used for concatenation only.
14971 * @param v3 Value checked for change.
14972 * @param i3 Static value used for concatenation only.
14973 * @param v4 Value checked for change.
14974 * @param i4 Static value used for concatenation only.
14975 * @param v5 Value checked for change.
14976 * @param i5 Static value used for concatenation only.
14977 * @param v6 Value checked for change.
14978 * @param i6 Static value used for concatenation only.
14979 * @param v7 Value checked for change.
14980 * @param suffix Static value used for concatenation only.
14981 * @param sanitizer An optional sanitizer function
14982 * @returns itself, so that it may be chained.
14983 * @codeGenApi
14984 */
14985function ɵɵpropertyInterpolate8(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer) {
14986 const lView = getLView();
14987 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
14988 if (interpolatedValue !== NO_CHANGE) {
14989 const tView = getTView();
14990 const tNode = getSelectedTNode();
14991 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
14992 ngDevMode &&
14993 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, suffix);
14994 }
14995 return ɵɵpropertyInterpolate8;
14996}
14997/**
14998 * Update an interpolated property on an element with 9 or more bound values surrounded by text.
14999 *
15000 * Used when the number of interpolated values exceeds 8.
15001 *
15002 * ```html
15003 * <div
15004 * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
15005 * ```
15006 *
15007 * Its compiled representation is::
15008 *
15009 * ```ts
15010 * ɵɵpropertyInterpolateV(
15011 * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
15012 * 'suffix']);
15013 * ```
15014 *
15015 * If the property name also exists as an input property on one of the element's directives,
15016 * the component property will be set instead of the element property. This check must
15017 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
15018 *
15019 * @param propName The name of the property to update.
15020 * @param values The collection of values and the strings in between those values, beginning with a
15021 * string prefix and ending with a string suffix.
15022 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
15023 * @param sanitizer An optional sanitizer function
15024 * @returns itself, so that it may be chained.
15025 * @codeGenApi
15026 */
15027function ɵɵpropertyInterpolateV(propName, values, sanitizer) {
15028 const lView = getLView();
15029 const interpolatedValue = interpolationV(lView, values);
15030 if (interpolatedValue !== NO_CHANGE) {
15031 const tView = getTView();
15032 const tNode = getSelectedTNode();
15033 elementPropertyInternal(tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false);
15034 if (ngDevMode) {
15035 const interpolationInBetween = [values[0]]; // prefix
15036 for (let i = 2; i < values.length; i += 2) {
15037 interpolationInBetween.push(values[i]);
15038 }
15039 storePropertyBindingMetadata(tView.data, tNode, propName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
15040 }
15041 }
15042 return ɵɵpropertyInterpolateV;
15043}
15044
15045function toTStylingRange(prev, next) {
15046 ngDevMode && assertNumberInRange(prev, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
15047 ngDevMode && assertNumberInRange(next, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
15048 return (prev << 17 /* StylingRange.PREV_SHIFT */ | next << 2 /* StylingRange.NEXT_SHIFT */);
15049}
15050function getTStylingRangePrev(tStylingRange) {
15051 ngDevMode && assertNumber(tStylingRange, 'expected number');
15052 return (tStylingRange >> 17 /* StylingRange.PREV_SHIFT */) & 32767 /* StylingRange.UNSIGNED_MASK */;
15053}
15054function getTStylingRangePrevDuplicate(tStylingRange) {
15055 ngDevMode && assertNumber(tStylingRange, 'expected number');
15056 return (tStylingRange & 2 /* StylingRange.PREV_DUPLICATE */) ==
15057 2 /* StylingRange.PREV_DUPLICATE */;
15058}
15059function setTStylingRangePrev(tStylingRange, previous) {
15060 ngDevMode && assertNumber(tStylingRange, 'expected number');
15061 ngDevMode && assertNumberInRange(previous, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
15062 return ((tStylingRange & ~4294836224 /* StylingRange.PREV_MASK */) |
15063 (previous << 17 /* StylingRange.PREV_SHIFT */));
15064}
15065function setTStylingRangePrevDuplicate(tStylingRange) {
15066 ngDevMode && assertNumber(tStylingRange, 'expected number');
15067 return (tStylingRange | 2 /* StylingRange.PREV_DUPLICATE */);
15068}
15069function getTStylingRangeNext(tStylingRange) {
15070 ngDevMode && assertNumber(tStylingRange, 'expected number');
15071 return (tStylingRange & 131068 /* StylingRange.NEXT_MASK */) >> 2 /* StylingRange.NEXT_SHIFT */;
15072}
15073function setTStylingRangeNext(tStylingRange, next) {
15074 ngDevMode && assertNumber(tStylingRange, 'expected number');
15075 ngDevMode && assertNumberInRange(next, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
15076 return ((tStylingRange & ~131068 /* StylingRange.NEXT_MASK */) | //
15077 next << 2 /* StylingRange.NEXT_SHIFT */);
15078}
15079function getTStylingRangeNextDuplicate(tStylingRange) {
15080 ngDevMode && assertNumber(tStylingRange, 'expected number');
15081 return (tStylingRange & 1 /* StylingRange.NEXT_DUPLICATE */) ===
15082 1 /* StylingRange.NEXT_DUPLICATE */;
15083}
15084function setTStylingRangeNextDuplicate(tStylingRange) {
15085 ngDevMode && assertNumber(tStylingRange, 'expected number');
15086 return (tStylingRange | 1 /* StylingRange.NEXT_DUPLICATE */);
15087}
15088function getTStylingRangeTail(tStylingRange) {
15089 ngDevMode && assertNumber(tStylingRange, 'expected number');
15090 const next = getTStylingRangeNext(tStylingRange);
15091 return next === 0 ? getTStylingRangePrev(tStylingRange) : next;
15092}
15093
15094/**
15095 * NOTE: The word `styling` is used interchangeably as style or class styling.
15096 *
15097 * This file contains code to link styling instructions together so that they can be replayed in
15098 * priority order. The file exists because Ivy styling instruction execution order does not match
15099 * that of the priority order. The purpose of this code is to create a linked list so that the
15100 * instructions can be traversed in priority order when computing the styles.
15101 *
15102 * Assume we are dealing with the following code:
15103 * ```
15104 * @Component({
15105 * template: `
15106 * <my-cmp [style]=" {color: '#001'} "
15107 * [style.color]=" #002 "
15108 * dir-style-color-1
15109 * dir-style-color-2> `
15110 * })
15111 * class ExampleComponent {
15112 * static ngComp = ... {
15113 * ...
15114 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
15115 * ɵɵstyleMap({color: '#001'});
15116 * ɵɵstyleProp('color', '#002');
15117 * ...
15118 * }
15119 * }
15120 *
15121 * @Directive({
15122 * selector: `[dir-style-color-1]',
15123 * })
15124 * class Style1Directive {
15125 * @HostBinding('style') style = {color: '#005'};
15126 * @HostBinding('style.color') color = '#006';
15127 *
15128 * static ngDir = ... {
15129 * ...
15130 * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap`
15131 * ɵɵstyleMap({color: '#005'});
15132 * ɵɵstyleProp('color', '#006');
15133 * ...
15134 * }
15135 * }
15136 *
15137 * @Directive({
15138 * selector: `[dir-style-color-2]',
15139 * })
15140 * class Style2Directive {
15141 * @HostBinding('style') style = {color: '#007'};
15142 * @HostBinding('style.color') color = '#008';
15143 *
15144 * static ngDir = ... {
15145 * ...
15146 * // Comp