UNPKG

1.15 MBJavaScriptView Raw
1/**
2 * @license Angular v15.1.5
3 * (c) 2010-2022 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { Subject, Subscription, Observable, merge as merge$1 } from 'rxjs';
8import { share } from 'rxjs/operators';
9
10function getClosureSafeProperty(objWithPropertyToExtract) {
11 for (let key in objWithPropertyToExtract) {
12 if (objWithPropertyToExtract[key] === getClosureSafeProperty) {
13 return key;
14 }
15 }
16 throw Error('Could not find renamed property on target object.');
17}
18/**
19 * Sets properties on a target object from a source object, but only if
20 * the property doesn't already exist on the target object.
21 * @param target The target to set properties on
22 * @param source The source of the property keys and values to set
23 */
24function fillProperties(target, source) {
25 for (const key in source) {
26 if (source.hasOwnProperty(key) && !target.hasOwnProperty(key)) {
27 target[key] = source[key];
28 }
29 }
30}
31
32function stringify(token) {
33 if (typeof token === 'string') {
34 return token;
35 }
36 if (Array.isArray(token)) {
37 return '[' + token.map(stringify).join(', ') + ']';
38 }
39 if (token == null) {
40 return '' + token;
41 }
42 if (token.overriddenName) {
43 return `${token.overriddenName}`;
44 }
45 if (token.name) {
46 return `${token.name}`;
47 }
48 const res = token.toString();
49 if (res == null) {
50 return '' + res;
51 }
52 const newLineIndex = res.indexOf('\n');
53 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
54}
55/**
56 * Concatenates two strings with separator, allocating new strings only when necessary.
57 *
58 * @param before before string.
59 * @param separator separator string.
60 * @param after after string.
61 * @returns concatenated string.
62 */
63function concatStringsWithSpace(before, after) {
64 return (before == null || before === '') ?
65 (after === null ? '' : after) :
66 ((after == null || after === '') ? before : before + ' ' + after);
67}
68
69const __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty });
70/**
71 * Allows to refer to references which are not yet defined.
72 *
73 * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
74 * DI is declared, but not yet defined. It is also used when the `token` which we use when creating
75 * a query is not yet defined.
76 *
77 * @usageNotes
78 * ### Example
79 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'}
80 * @publicApi
81 */
82function forwardRef(forwardRefFn) {
83 forwardRefFn.__forward_ref__ = forwardRef;
84 forwardRefFn.toString = function () {
85 return stringify(this());
86 };
87 return forwardRefFn;
88}
89/**
90 * Lazily retrieves the reference value from a forwardRef.
91 *
92 * Acts as the identity function when given a non-forward-ref value.
93 *
94 * @usageNotes
95 * ### Example
96 *
97 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'}
98 *
99 * @see `forwardRef`
100 * @publicApi
101 */
102function resolveForwardRef(type) {
103 return isForwardRef(type) ? type() : type;
104}
105/** Checks whether a function is wrapped by a `forwardRef`. */
106function isForwardRef(fn) {
107 return typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
108 fn.__forward_ref__ === forwardRef;
109}
110
111function isEnvironmentProviders(value) {
112 return value && !!value.ɵproviders;
113}
114
115/**
116 * Base URL for the error details page.
117 *
118 * Keep this constant in sync across:
119 * - packages/compiler-cli/src/ngtsc/diagnostics/src/error_details_base_url.ts
120 * - packages/core/src/error_details_base_url.ts
121 */
122const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors';
123/**
124 * URL for the XSS security documentation.
125 */
126const XSS_SECURITY_URL = 'https://g.co/ng/security#xss';
127
128/**
129 * Class that represents a runtime error.
130 * Formats and outputs the error message in a consistent way.
131 *
132 * Example:
133 * ```
134 * throw new RuntimeError(
135 * RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED,
136 * ngDevMode && 'Injector has already been destroyed.');
137 * ```
138 *
139 * Note: the `message` argument contains a descriptive error message as a string in development
140 * mode (when the `ngDevMode` is defined). In production mode (after tree-shaking pass), the
141 * `message` argument becomes `false`, thus we account for it in the typings and the runtime logic.
142 */
143class RuntimeError extends Error {
144 constructor(code, message) {
145 super(formatRuntimeError(code, message));
146 this.code = code;
147 }
148}
149/**
150 * Called to format a runtime error.
151 * See additional info on the `message` argument type in the `RuntimeError` class description.
152 */
153function formatRuntimeError(code, message) {
154 // Error code might be a negative number, which is a special marker that instructs the logic to
155 // generate a link to the error details page on angular.io.
156 // We also prepend `0` to non-compile-time errors.
157 const fullCode = `NG0${Math.abs(code)}`;
158 let errorMessage = `${fullCode}${message ? ': ' + message.trim() : ''}`;
159 if (ngDevMode && code < 0) {
160 const addPeriodSeparator = !errorMessage.match(/[.,;!?]$/);
161 const separator = addPeriodSeparator ? '.' : '';
162 errorMessage =
163 `${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
164 }
165 return errorMessage;
166}
167
168/**
169 * Used for stringify render output in Ivy.
170 * Important! This function is very performance-sensitive and we should
171 * be extra careful not to introduce megamorphic reads in it.
172 * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations.
173 */
174function renderStringify(value) {
175 if (typeof value === 'string')
176 return value;
177 if (value == null)
178 return '';
179 // Use `String` so that it invokes the `toString` method of the value. Note that this
180 // appears to be faster than calling `value.toString` (see `render_stringify` benchmark).
181 return String(value);
182}
183/**
184 * Used to stringify a value so that it can be displayed in an error message.
185 * Important! This function contains a megamorphic read and should only be
186 * used for error messages.
187 */
188function stringifyForError(value) {
189 if (typeof value === 'function')
190 return value.name || value.toString();
191 if (typeof value === 'object' && value != null && typeof value.type === 'function') {
192 return value.type.name || value.type.toString();
193 }
194 return renderStringify(value);
195}
196
197/** Called when directives inject each other (creating a circular dependency) */
198function throwCyclicDependencyError(token, path) {
199 const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
200 throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, `Circular dependency in DI detected for ${token}${depPath}`);
201}
202function throwMixedMultiProviderError() {
203 throw new Error(`Cannot mix multi providers and regular providers`);
204}
205function throwInvalidProviderError(ngModuleType, providers, provider) {
206 if (ngModuleType && providers) {
207 const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...');
208 throw new Error(`Invalid provider for the NgModule '${stringify(ngModuleType)}' - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`);
209 }
210 else if (isEnvironmentProviders(provider)) {
211 if (provider.ɵfromNgModule) {
212 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.`);
213 }
214 else {
215 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.`);
216 }
217 }
218 else {
219 throw new Error('Invalid provider');
220 }
221}
222/** Throws an error when a token is not found in DI. */
223function throwProviderNotFoundError(token, injectorName) {
224 const injectorDetails = injectorName ? ` in ${injectorName}` : '';
225 throw new RuntimeError(-201 /* RuntimeErrorCode.PROVIDER_NOT_FOUND */, ngDevMode && `No provider for ${stringifyForError(token)} found${injectorDetails}`);
226}
227
228// The functions in this file verify that the assumptions we are making
229function assertNumber(actual, msg) {
230 if (!(typeof actual === 'number')) {
231 throwError(msg, typeof actual, 'number', '===');
232 }
233}
234function assertNumberInRange(actual, minInclusive, maxInclusive) {
235 assertNumber(actual, 'Expected a number');
236 assertLessThanOrEqual(actual, maxInclusive, 'Expected number to be less than or equal to');
237 assertGreaterThanOrEqual(actual, minInclusive, 'Expected number to be greater than or equal to');
238}
239function assertString(actual, msg) {
240 if (!(typeof actual === 'string')) {
241 throwError(msg, actual === null ? 'null' : typeof actual, 'string', '===');
242 }
243}
244function assertFunction(actual, msg) {
245 if (!(typeof actual === 'function')) {
246 throwError(msg, actual === null ? 'null' : typeof actual, 'function', '===');
247 }
248}
249function assertEqual(actual, expected, msg) {
250 if (!(actual == expected)) {
251 throwError(msg, actual, expected, '==');
252 }
253}
254function assertNotEqual(actual, expected, msg) {
255 if (!(actual != expected)) {
256 throwError(msg, actual, expected, '!=');
257 }
258}
259function assertSame(actual, expected, msg) {
260 if (!(actual === expected)) {
261 throwError(msg, actual, expected, '===');
262 }
263}
264function assertNotSame(actual, expected, msg) {
265 if (!(actual !== expected)) {
266 throwError(msg, actual, expected, '!==');
267 }
268}
269function assertLessThan(actual, expected, msg) {
270 if (!(actual < expected)) {
271 throwError(msg, actual, expected, '<');
272 }
273}
274function assertLessThanOrEqual(actual, expected, msg) {
275 if (!(actual <= expected)) {
276 throwError(msg, actual, expected, '<=');
277 }
278}
279function assertGreaterThan(actual, expected, msg) {
280 if (!(actual > expected)) {
281 throwError(msg, actual, expected, '>');
282 }
283}
284function assertGreaterThanOrEqual(actual, expected, msg) {
285 if (!(actual >= expected)) {
286 throwError(msg, actual, expected, '>=');
287 }
288}
289function assertNotDefined(actual, msg) {
290 if (actual != null) {
291 throwError(msg, actual, null, '==');
292 }
293}
294function assertDefined(actual, msg) {
295 if (actual == null) {
296 throwError(msg, actual, null, '!=');
297 }
298}
299function throwError(msg, actual, expected, comparison) {
300 throw new Error(`ASSERTION ERROR: ${msg}` +
301 (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
302}
303function assertDomNode(node) {
304 // If we're in a worker, `Node` will not be defined.
305 if (!(typeof Node !== 'undefined' && node instanceof Node) &&
306 !(typeof node === 'object' && node != null &&
307 node.constructor.name === 'WebWorkerRenderNode')) {
308 throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
309 }
310}
311function assertIndexInRange(arr, index) {
312 assertDefined(arr, 'Array must be defined.');
313 const maxLen = arr.length;
314 if (index < 0 || index >= maxLen) {
315 throwError(`Index expected to be less than ${maxLen} but got ${index}`);
316 }
317}
318function assertOneOf(value, ...validValues) {
319 if (validValues.indexOf(value) !== -1)
320 return true;
321 throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${JSON.stringify(value)}.`);
322}
323
324/**
325 * Construct an injectable definition which defines how a token will be constructed by the DI
326 * system, and in which injectors (if any) it will be available.
327 *
328 * This should be assigned to a static `ɵprov` field on a type, which will then be an
329 * `InjectableType`.
330 *
331 * Options:
332 * * `providedIn` determines which injectors will include the injectable, by either associating it
333 * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
334 * provided in the `'root'` injector, which will be the application-level injector in most apps.
335 * * `factory` gives the zero argument function which will create an instance of the injectable.
336 * The factory can call `inject` to access the `Injector` and request injection of dependencies.
337 *
338 * @codeGenApi
339 * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
340 */
341function ɵɵdefineInjectable(opts) {
342 return {
343 token: opts.token,
344 providedIn: opts.providedIn || null,
345 factory: opts.factory,
346 value: undefined,
347 };
348}
349/**
350 * @deprecated in v8, delete after v10. This API should be used only by generated code, and that
351 * code should now use ɵɵdefineInjectable instead.
352 * @publicApi
353 */
354const defineInjectable = ɵɵdefineInjectable;
355/**
356 * Construct an `InjectorDef` which configures an injector.
357 *
358 * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
359 * `InjectorType`.
360 *
361 * Options:
362 *
363 * * `providers`: an optional array of providers to add to the injector. Each provider must
364 * either have a factory or point to a type which has a `ɵprov` static property (the
365 * type must be an `InjectableType`).
366 * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
367 * whose providers will also be added to the injector. Locally provided types will override
368 * providers from imports.
369 *
370 * @codeGenApi
371 */
372function ɵɵdefineInjector(options) {
373 return { providers: options.providers || [], imports: options.imports || [] };
374}
375/**
376 * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
377 * inherited value.
378 *
379 * @param type A type which may have its own (non-inherited) `ɵprov`.
380 */
381function getInjectableDef(type) {
382 return getOwnDefinition(type, NG_PROV_DEF) || getOwnDefinition(type, NG_INJECTABLE_DEF);
383}
384function isInjectable(type) {
385 return getInjectableDef(type) !== null;
386}
387/**
388 * Return definition only if it is defined directly on `type` and is not inherited from a base
389 * class of `type`.
390 */
391function getOwnDefinition(type, field) {
392 return type.hasOwnProperty(field) ? type[field] : null;
393}
394/**
395 * Read the injectable def (`ɵprov`) for `type` or read the `ɵprov` from one of its ancestors.
396 *
397 * @param type A type which may have `ɵprov`, via inheritance.
398 *
399 * @deprecated Will be removed in a future version of Angular, where an error will occur in the
400 * scenario if we find the `ɵprov` on an ancestor only.
401 */
402function getInheritedInjectableDef(type) {
403 const def = type && (type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF]);
404 if (def) {
405 const typeName = getTypeName(type);
406 // TODO(FW-1307): Re-add ngDevMode when closure can handle it
407 // ngDevMode &&
408 console.warn(`DEPRECATED: DI is instantiating a token "${typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` +
409 `This will become an error in a future version of Angular. Please add @Injectable() to the "${typeName}" class.`);
410 return def;
411 }
412 else {
413 return null;
414 }
415}
416/** Gets the name of a type, accounting for some cross-browser differences. */
417function getTypeName(type) {
418 // `Function.prototype.name` behaves differently between IE and other browsers. In most browsers
419 // it'll always return the name of the function itself, no matter how many other functions it
420 // inherits from. On IE the function doesn't have its own `name` property, but it takes it from
421 // the lowest level in the prototype chain. E.g. if we have `class Foo extends Parent` most
422 // browsers will evaluate `Foo.name` to `Foo` while IE will return `Parent`. We work around
423 // the issue by converting the function to a string and parsing its name out that way via a regex.
424 if (type.hasOwnProperty('name')) {
425 return type.name;
426 }
427 const match = ('' + type).match(/^function\s*([^\s(]+)/);
428 return match === null ? '' : match[1];
429}
430/**
431 * Read the injector def type in a way which is immune to accidentally reading inherited value.
432 *
433 * @param type type which may have an injector def (`ɵinj`)
434 */
435function getInjectorDef(type) {
436 return type && (type.hasOwnProperty(NG_INJ_DEF) || type.hasOwnProperty(NG_INJECTOR_DEF)) ?
437 type[NG_INJ_DEF] :
438 null;
439}
440const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty });
441const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty });
442// We need to keep these around so we can read off old defs if new defs are unavailable
443const NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty });
444const NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty });
445
446/**
447 * Injection flags for DI.
448 *
449 * @publicApi
450 * @deprecated use an options object for `inject` instead.
451 */
452var InjectFlags;
453(function (InjectFlags) {
454 // TODO(alxhub): make this 'const' (and remove `InternalInjectFlags` enum) when ngc no longer
455 // writes exports of it into ngfactory files.
456 /** Check self and check parent injector if needed */
457 InjectFlags[InjectFlags["Default"] = 0] = "Default";
458 /**
459 * Specifies that an injector should retrieve a dependency from any injector until reaching the
460 * host element of the current component. (Only used with Element Injector)
461 */
462 InjectFlags[InjectFlags["Host"] = 1] = "Host";
463 /** Don't ascend to ancestors of the node requesting injection. */
464 InjectFlags[InjectFlags["Self"] = 2] = "Self";
465 /** Skip the node that is requesting injection. */
466 InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf";
467 /** Inject `defaultValue` instead if token not found. */
468 InjectFlags[InjectFlags["Optional"] = 8] = "Optional";
469})(InjectFlags || (InjectFlags = {}));
470
471/**
472 * Current implementation of inject.
473 *
474 * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
475 * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
476 * way for two reasons:
477 * 1. `Injector` should not depend on ivy logic.
478 * 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
479 */
480let _injectImplementation;
481function getInjectImplementation() {
482 return _injectImplementation;
483}
484/**
485 * Sets the current inject implementation.
486 */
487function setInjectImplementation(impl) {
488 const previous = _injectImplementation;
489 _injectImplementation = impl;
490 return previous;
491}
492/**
493 * Injects `root` tokens in limp mode.
494 *
495 * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
496 * `"root"`. This is known as the limp mode injection. In such case the value is stored in the
497 * injectable definition.
498 */
499function injectRootLimpMode(token, notFoundValue, flags) {
500 const injectableDef = getInjectableDef(token);
501 if (injectableDef && injectableDef.providedIn == 'root') {
502 return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
503 injectableDef.value;
504 }
505 if (flags & InjectFlags.Optional)
506 return null;
507 if (notFoundValue !== undefined)
508 return notFoundValue;
509 throwProviderNotFoundError(stringify(token), 'Injector');
510}
511/**
512 * Assert that `_injectImplementation` is not `fn`.
513 *
514 * This is useful, to prevent infinite recursion.
515 *
516 * @param fn Function which it should not equal to
517 */
518function assertInjectImplementationNotEqual(fn) {
519 ngDevMode &&
520 assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion');
521}
522
523// Always use __globalThis if available, which is the spec-defined global variable across all
524// environments, then fallback to __global first, because in Node tests both __global and
525// __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof
526// checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
527// https://github.com/terser/terser/issues/250.
528const _global = ( /* @__PURE__ */(() => (typeof globalThis !== 'undefined' && globalThis) ||
529 (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
530 (typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
531 self instanceof WorkerGlobalScope && self))());
532
533function ngDevModeResetPerfCounters() {
534 const locationString = typeof location !== 'undefined' ? location.toString() : '';
535 const newCounters = {
536 namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1,
537 firstCreatePass: 0,
538 tNode: 0,
539 tView: 0,
540 rendererCreateTextNode: 0,
541 rendererSetText: 0,
542 rendererCreateElement: 0,
543 rendererAddEventListener: 0,
544 rendererSetAttribute: 0,
545 rendererRemoveAttribute: 0,
546 rendererSetProperty: 0,
547 rendererSetClassName: 0,
548 rendererAddClass: 0,
549 rendererRemoveClass: 0,
550 rendererSetStyle: 0,
551 rendererRemoveStyle: 0,
552 rendererDestroy: 0,
553 rendererDestroyNode: 0,
554 rendererMoveNode: 0,
555 rendererRemoveNode: 0,
556 rendererAppendChild: 0,
557 rendererInsertBefore: 0,
558 rendererCreateComment: 0,
559 };
560 // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
561 const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
562 _global['ngDevMode'] = allowNgDevModeTrue && newCounters;
563 return newCounters;
564}
565/**
566 * This function checks to see if the `ngDevMode` has been set. If yes,
567 * then we honor it, otherwise we default to dev mode with additional checks.
568 *
569 * The idea is that unless we are doing production build where we explicitly
570 * set `ngDevMode == false` we should be helping the developer by providing
571 * as much early warning and errors as possible.
572 *
573 * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions
574 * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode
575 * is defined for the entire instruction set.
576 *
577 * When checking `ngDevMode` on toplevel, always init it before referencing it
578 * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can
579 * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595.
580 *
581 * Details on possible values for `ngDevMode` can be found on its docstring.
582 *
583 * NOTE:
584 * - changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`.
585 */
586function initNgDevMode() {
587 // The below checks are to ensure that calling `initNgDevMode` multiple times does not
588 // reset the counters.
589 // If the `ngDevMode` is not an object, then it means we have not created the perf counters
590 // yet.
591 if (typeof ngDevMode === 'undefined' || ngDevMode) {
592 if (typeof ngDevMode !== 'object') {
593 ngDevModeResetPerfCounters();
594 }
595 return typeof ngDevMode !== 'undefined' && !!ngDevMode;
596 }
597 return false;
598}
599
600const _THROW_IF_NOT_FOUND = {};
601const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
602/*
603 * Name of a property (that we patch onto DI decorator), which is used as an annotation of which
604 * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators
605 * in the code, thus making them tree-shakable.
606 */
607const DI_DECORATOR_FLAG = '__NG_DI_FLAG__';
608const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath';
609const NG_TOKEN_PATH = 'ngTokenPath';
610const NEW_LINE = /\n/gm;
611const NO_NEW_LINE = 'ɵ';
612const SOURCE = '__source';
613/**
614 * Current injector value used by `inject`.
615 * - `undefined`: it is an error to call `inject`
616 * - `null`: `inject` can be called but there is no injector (limp-mode).
617 * - Injector instance: Use the injector for resolution.
618 */
619let _currentInjector = undefined;
620function setCurrentInjector(injector) {
621 const former = _currentInjector;
622 _currentInjector = injector;
623 return former;
624}
625function injectInjectorOnly(token, flags = InjectFlags.Default) {
626 if (_currentInjector === undefined) {
627 throw new RuntimeError(-203 /* RuntimeErrorCode.MISSING_INJECTION_CONTEXT */, ngDevMode &&
628 `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\`.`);
629 }
630 else if (_currentInjector === null) {
631 return injectRootLimpMode(token, undefined, flags);
632 }
633 else {
634 return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
635 }
636}
637function ɵɵinject(token, flags = InjectFlags.Default) {
638 return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef(token), flags);
639}
640/**
641 * Throws an error indicating that a factory function could not be generated by the compiler for a
642 * particular class.
643 *
644 * The name of the class is not mentioned here, but will be in the generated factory function name
645 * and thus in the stack trace.
646 *
647 * @codeGenApi
648 */
649function ɵɵinvalidFactoryDep(index) {
650 throw new RuntimeError(202 /* RuntimeErrorCode.INVALID_FACTORY_DEPENDENCY */, ngDevMode &&
651 `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${index} of the parameter list is invalid.
652This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.
653
654Please 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.`);
655}
656/**
657 * Injects a token from the currently active injector.
658 * `inject` is only supported during instantiation of a dependency by the DI system. It can be used
659 * during:
660 * - Construction (via the `constructor`) of a class being instantiated by the DI system, such
661 * as an `@Injectable` or `@Component`.
662 * - In the initializer for fields of such classes.
663 * - In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`.
664 * - In the `factory` function specified for an `InjectionToken`.
665 *
666 * @param token A token that represents a dependency that should be injected.
667 * @param flags Optional flags that control how injection is executed.
668 * The flags correspond to injection strategies that can be specified with
669 * parameter decorators `@Host`, `@Self`, `@SkipSelf`, and `@Optional`.
670 * @returns the injected value if operation is successful, `null` otherwise.
671 * @throws if called outside of a supported context.
672 *
673 * @usageNotes
674 * In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a
675 * field initializer:
676 *
677 * ```typescript
678 * @Injectable({providedIn: 'root'})
679 * export class Car {
680 * radio: Radio|undefined;
681 * // OK: field initializer
682 * spareTyre = inject(Tyre);
683 *
684 * constructor() {
685 * // OK: constructor body
686 * this.radio = inject(Radio);
687 * }
688 * }
689 * ```
690 *
691 * It is also legal to call `inject` from a provider's factory:
692 *
693 * ```typescript
694 * providers: [
695 * {provide: Car, useFactory: () => {
696 * // OK: a class factory
697 * const engine = inject(Engine);
698 * return new Car(engine);
699 * }}
700 * ]
701 * ```
702 *
703 * Calls to the `inject()` function outside of the class creation context will result in error. Most
704 * notably, calls to `inject()` are disallowed after a class instance was created, in methods
705 * (including lifecycle hooks):
706 *
707 * ```typescript
708 * @Component({ ... })
709 * export class CarComponent {
710 * ngOnInit() {
711 * // ERROR: too late, the component instance was already created
712 * const engine = inject(Engine);
713 * engine.start();
714 * }
715 * }
716 * ```
717 *
718 * @publicApi
719 */
720function inject(token, flags = InjectFlags.Default) {
721 return ɵɵinject(token, convertToBitFlags(flags));
722}
723// Converts object-based DI flags (`InjectOptions`) to bit flags (`InjectFlags`).
724function convertToBitFlags(flags) {
725 if (typeof flags === 'undefined' || typeof flags === 'number') {
726 return flags;
727 }
728 // While TypeScript doesn't accept it without a cast, bitwise OR with false-y values in
729 // JavaScript is a no-op. We can use that for a very codesize-efficient conversion from
730 // `InjectOptions` to `InjectFlags`.
731 return (0 /* InternalInjectFlags.Default */ | // comment to force a line break in the formatter
732 (flags.optional && 8 /* InternalInjectFlags.Optional */) |
733 (flags.host && 1 /* InternalInjectFlags.Host */) |
734 (flags.self && 2 /* InternalInjectFlags.Self */) |
735 (flags.skipSelf && 4 /* InternalInjectFlags.SkipSelf */));
736}
737function injectArgs(types) {
738 const args = [];
739 for (let i = 0; i < types.length; i++) {
740 const arg = resolveForwardRef(types[i]);
741 if (Array.isArray(arg)) {
742 if (arg.length === 0) {
743 throw new RuntimeError(900 /* RuntimeErrorCode.INVALID_DIFFER_INPUT */, ngDevMode && 'Arguments array must have arguments.');
744 }
745 let type = undefined;
746 let flags = InjectFlags.Default;
747 for (let j = 0; j < arg.length; j++) {
748 const meta = arg[j];
749 const flag = getInjectFlag(meta);
750 if (typeof flag === 'number') {
751 // Special case when we handle @Inject decorator.
752 if (flag === -1 /* DecoratorFlags.Inject */) {
753 type = meta.token;
754 }
755 else {
756 flags |= flag;
757 }
758 }
759 else {
760 type = meta;
761 }
762 }
763 args.push(ɵɵinject(type, flags));
764 }
765 else {
766 args.push(ɵɵinject(arg));
767 }
768 }
769 return args;
770}
771/**
772 * Attaches a given InjectFlag to a given decorator using monkey-patching.
773 * Since DI decorators can be used in providers `deps` array (when provider is configured using
774 * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we
775 * attach the flag to make it available both as a static property and as a field on decorator
776 * instance.
777 *
778 * @param decorator Provided DI decorator.
779 * @param flag InjectFlag that should be applied.
780 */
781function attachInjectFlag(decorator, flag) {
782 decorator[DI_DECORATOR_FLAG] = flag;
783 decorator.prototype[DI_DECORATOR_FLAG] = flag;
784 return decorator;
785}
786/**
787 * Reads monkey-patched property that contains InjectFlag attached to a decorator.
788 *
789 * @param token Token that may contain monkey-patched DI flags property.
790 */
791function getInjectFlag(token) {
792 return token[DI_DECORATOR_FLAG];
793}
794function catchInjectorError(e, token, injectorErrorName, source) {
795 const tokenPath = e[NG_TEMP_TOKEN_PATH];
796 if (token[SOURCE]) {
797 tokenPath.unshift(token[SOURCE]);
798 }
799 e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source);
800 e[NG_TOKEN_PATH] = tokenPath;
801 e[NG_TEMP_TOKEN_PATH] = null;
802 throw e;
803}
804function formatError(text, obj, injectorErrorName, source = null) {
805 text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.slice(2) : text;
806 let context = stringify(obj);
807 if (Array.isArray(obj)) {
808 context = obj.map(stringify).join(' -> ');
809 }
810 else if (typeof obj === 'object') {
811 let parts = [];
812 for (let key in obj) {
813 if (obj.hasOwnProperty(key)) {
814 let value = obj[key];
815 parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value)));
816 }
817 }
818 context = `{${parts.join(', ')}}`;
819 }
820 return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
821}
822
823/**
824 * Convince closure compiler that the wrapped function has no side-effects.
825 *
826 * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to
827 * allow us to execute a function but have closure compiler mark the call as no-side-effects.
828 * It is important that the return value for the `noSideEffects` function be assigned
829 * to something which is retained otherwise the call to `noSideEffects` will be removed by closure
830 * compiler.
831 */
832function noSideEffects(fn) {
833 return { toString: fn }.toString();
834}
835
836/**
837 * The strategy that the default change detector uses to detect changes.
838 * When set, takes effect the next time change detection is triggered.
839 *
840 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
841 *
842 * @publicApi
843 */
844var ChangeDetectionStrategy;
845(function (ChangeDetectionStrategy) {
846 /**
847 * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated
848 * until reactivated by setting the strategy to `Default` (`CheckAlways`).
849 * Change detection can still be explicitly invoked.
850 * This strategy applies to all child directives and cannot be overridden.
851 */
852 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
853 /**
854 * Use the default `CheckAlways` strategy, in which change detection is automatic until
855 * explicitly deactivated.
856 */
857 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
858})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
859/**
860 * Defines the possible states of the default change detector.
861 * @see `ChangeDetectorRef`
862 */
863var ChangeDetectorStatus;
864(function (ChangeDetectorStatus) {
865 /**
866 * A state in which, after calling `detectChanges()`, the change detector
867 * state becomes `Checked`, and must be explicitly invoked or reactivated.
868 */
869 ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce";
870 /**
871 * A state in which change detection is skipped until the change detector mode
872 * becomes `CheckOnce`.
873 */
874 ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked";
875 /**
876 * A state in which change detection continues automatically until explicitly
877 * deactivated.
878 */
879 ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways";
880 /**
881 * A state in which a change detector sub tree is not a part of the main tree and
882 * should be skipped.
883 */
884 ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached";
885 /**
886 * Indicates that the change detector encountered an error checking a binding
887 * or calling a directive lifecycle method and is now in an inconsistent state. Change
888 * detectors in this state do not detect changes.
889 */
890 ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored";
891 /**
892 * Indicates that the change detector has been destroyed.
893 */
894 ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed";
895})(ChangeDetectorStatus || (ChangeDetectorStatus = {}));
896/**
897 * Reports whether a given strategy is currently the default for change detection.
898 * @param changeDetectionStrategy The strategy to check.
899 * @returns True if the given strategy is the current default, false otherwise.
900 * @see `ChangeDetectorStatus`
901 * @see `ChangeDetectorRef`
902 */
903function isDefaultChangeDetectionStrategy(changeDetectionStrategy) {
904 return changeDetectionStrategy == null ||
905 changeDetectionStrategy === ChangeDetectionStrategy.Default;
906}
907
908/**
909 * Defines the CSS styles encapsulation policies for the {@link Component} decorator's
910 * `encapsulation` option.
911 *
912 * See {@link Component#encapsulation encapsulation}.
913 *
914 * @usageNotes
915 * ### Example
916 *
917 * {@example core/ts/metadata/encapsulation.ts region='longform'}
918 *
919 * @publicApi
920 */
921var ViewEncapsulation$1;
922(function (ViewEncapsulation) {
923 // TODO: consider making `ViewEncapsulation` a `const enum` instead. See
924 // https://github.com/angular/angular/issues/44119 for additional information.
925 /**
926 * Emulates a native Shadow DOM encapsulation behavior by adding a specific attribute to the
927 * component's host element and applying the same attribute to all the CSS selectors provided
928 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls}.
929 *
930 * This is the default option.
931 */
932 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
933 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
934 /**
935 * Doesn't provide any sort of CSS style encapsulation, meaning that all the styles provided
936 * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls} are applicable
937 * to any HTML element of the application regardless of their host Component.
938 */
939 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
940 /**
941 * Uses the browser's native Shadow DOM API to encapsulate CSS styles, meaning that it creates
942 * a ShadowRoot for the component's host element which is then used to encapsulate
943 * all the Component's styling.
944 */
945 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
946})(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
947
948/**
949 * This file contains reuseable "empty" symbols that can be used as default return values
950 * in different parts of the rendering code. Because the same symbols are returned, this
951 * allows for identity checks against these values to be consistently used by the framework
952 * code.
953 */
954const EMPTY_OBJ = {};
955const EMPTY_ARRAY = [];
956// freezing the values prevents any code from accidentally inserting new values in
957if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
958 // These property accesses can be ignored because ngDevMode will be set to false
959 // when optimizing code and the whole if statement will be dropped.
960 // tslint:disable-next-line:no-toplevel-property-access
961 Object.freeze(EMPTY_OBJ);
962 // tslint:disable-next-line:no-toplevel-property-access
963 Object.freeze(EMPTY_ARRAY);
964}
965
966const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty });
967const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty });
968const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty });
969const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty });
970const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty });
971/**
972 * If a directive is diPublic, bloomAdd sets a property on the type with this constant as
973 * the key and the directive's unique ID as the value. This allows us to map directives to their
974 * bloom filter bit for DI.
975 */
976// TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified.
977const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty });
978
979/** Counter used to generate unique IDs for component definitions. */
980let componentDefCount = 0;
981/**
982 * Create a component definition object.
983 *
984 *
985 * # Example
986 * ```
987 * class MyDirective {
988 * // Generated by Angular Template Compiler
989 * // [Symbol] syntax will not be supported by TypeScript until v2.7
990 * static ɵcmp = defineComponent({
991 * ...
992 * });
993 * }
994 * ```
995 * @codeGenApi
996 */
997function ɵɵdefineComponent(componentDefinition) {
998 return noSideEffects(() => {
999 // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
1000 // See the `initNgDevMode` docstring for more information.
1001 (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
1002 const type = componentDefinition.type;
1003 const standalone = componentDefinition.standalone === true;
1004 const declaredInputs = {};
1005 const def = {
1006 type: type,
1007 providersResolver: null,
1008 decls: componentDefinition.decls,
1009 vars: componentDefinition.vars,
1010 factory: null,
1011 template: componentDefinition.template || null,
1012 consts: componentDefinition.consts || null,
1013 ngContentSelectors: componentDefinition.ngContentSelectors,
1014 hostBindings: componentDefinition.hostBindings || null,
1015 hostVars: componentDefinition.hostVars || 0,
1016 hostAttrs: componentDefinition.hostAttrs || null,
1017 contentQueries: componentDefinition.contentQueries || null,
1018 declaredInputs: declaredInputs,
1019 inputs: null,
1020 outputs: null,
1021 exportAs: componentDefinition.exportAs || null,
1022 onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
1023 directiveDefs: null,
1024 pipeDefs: null,
1025 standalone,
1026 dependencies: standalone && componentDefinition.dependencies || null,
1027 getStandaloneInjector: null,
1028 selectors: componentDefinition.selectors || EMPTY_ARRAY,
1029 viewQuery: componentDefinition.viewQuery || null,
1030 features: componentDefinition.features || null,
1031 data: componentDefinition.data || {},
1032 encapsulation: componentDefinition.encapsulation || ViewEncapsulation$1.Emulated,
1033 id: `c${componentDefCount++}`,
1034 styles: componentDefinition.styles || EMPTY_ARRAY,
1035 _: null,
1036 setInput: null,
1037 schemas: componentDefinition.schemas || null,
1038 tView: null,
1039 findHostDirectiveDefs: null,
1040 hostDirectives: null,
1041 };
1042 const dependencies = componentDefinition.dependencies;
1043 const feature = componentDefinition.features;
1044 def.inputs = invertObject(componentDefinition.inputs, declaredInputs),
1045 def.outputs = invertObject(componentDefinition.outputs),
1046 feature && feature.forEach((fn) => fn(def));
1047 def.directiveDefs = dependencies ?
1048 (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
1049 .map(extractDirectiveDef)
1050 .filter(nonNull)) :
1051 null;
1052 def.pipeDefs = dependencies ?
1053 (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
1054 .map(getPipeDef$1)
1055 .filter(nonNull)) :
1056 null;
1057 return def;
1058 });
1059}
1060/**
1061 * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
1062 * definition, when generating a direct reference in the component file would otherwise create an
1063 * import cycle.
1064 *
1065 * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
1066 *
1067 * @codeGenApi
1068 */
1069function ɵɵsetComponentScope(type, directives, pipes) {
1070 const def = type.ɵcmp;
1071 def.directiveDefs = () => (typeof directives === 'function' ? directives() : directives).map(extractDirectiveDef);
1072 def.pipeDefs = () => (typeof pipes === 'function' ? pipes() : pipes).map(getPipeDef$1);
1073}
1074function extractDirectiveDef(type) {
1075 return getComponentDef(type) || getDirectiveDef(type);
1076}
1077function nonNull(value) {
1078 return value !== null;
1079}
1080/**
1081 * @codeGenApi
1082 */
1083function ɵɵdefineNgModule(def) {
1084 return noSideEffects(() => {
1085 const res = {
1086 type: def.type,
1087 bootstrap: def.bootstrap || EMPTY_ARRAY,
1088 declarations: def.declarations || EMPTY_ARRAY,
1089 imports: def.imports || EMPTY_ARRAY,
1090 exports: def.exports || EMPTY_ARRAY,
1091 transitiveCompileScopes: null,
1092 schemas: def.schemas || null,
1093 id: def.id || null,
1094 };
1095 return res;
1096 });
1097}
1098/**
1099 * Adds the module metadata that is necessary to compute the module's transitive scope to an
1100 * existing module definition.
1101 *
1102 * Scope metadata of modules is not used in production builds, so calls to this function can be
1103 * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
1104 * to become eligible for tree-shaking as well.
1105 *
1106 * @codeGenApi
1107 */
1108function ɵɵsetNgModuleScope(type, scope) {
1109 return noSideEffects(() => {
1110 const ngModuleDef = getNgModuleDef(type, true);
1111 ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
1112 ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
1113 ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
1114 });
1115}
1116/**
1117 * Inverts an inputs or outputs lookup such that the keys, which were the
1118 * minified keys, are part of the values, and the values are parsed so that
1119 * the publicName of the property is the new key
1120 *
1121 * e.g. for
1122 *
1123 * ```
1124 * class Comp {
1125 * @Input()
1126 * propName1: string;
1127 *
1128 * @Input('publicName2')
1129 * declaredPropName2: number;
1130 * }
1131 * ```
1132 *
1133 * will be serialized as
1134 *
1135 * ```
1136 * {
1137 * propName1: 'propName1',
1138 * declaredPropName2: ['publicName2', 'declaredPropName2'],
1139 * }
1140 * ```
1141 *
1142 * which is than translated by the minifier as:
1143 *
1144 * ```
1145 * {
1146 * minifiedPropName1: 'propName1',
1147 * minifiedPropName2: ['publicName2', 'declaredPropName2'],
1148 * }
1149 * ```
1150 *
1151 * becomes: (public name => minifiedName)
1152 *
1153 * ```
1154 * {
1155 * 'propName1': 'minifiedPropName1',
1156 * 'publicName2': 'minifiedPropName2',
1157 * }
1158 * ```
1159 *
1160 * Optionally the function can take `secondary` which will result in: (public name => declared name)
1161 *
1162 * ```
1163 * {
1164 * 'propName1': 'propName1',
1165 * 'publicName2': 'declaredPropName2',
1166 * }
1167 * ```
1168 *
1169
1170 */
1171function invertObject(obj, secondary) {
1172 if (obj == null)
1173 return EMPTY_OBJ;
1174 const newLookup = {};
1175 for (const minifiedKey in obj) {
1176 if (obj.hasOwnProperty(minifiedKey)) {
1177 let publicName = obj[minifiedKey];
1178 let declaredName = publicName;
1179 if (Array.isArray(publicName)) {
1180 declaredName = publicName[1];
1181 publicName = publicName[0];
1182 }
1183 newLookup[publicName] = minifiedKey;
1184 if (secondary) {
1185 (secondary[publicName] = declaredName);
1186 }
1187 }
1188 }
1189 return newLookup;
1190}
1191/**
1192 * Create a directive definition object.
1193 *
1194 * # Example
1195 * ```ts
1196 * class MyDirective {
1197 * // Generated by Angular Template Compiler
1198 * // [Symbol] syntax will not be supported by TypeScript until v2.7
1199 * static ɵdir = ɵɵdefineDirective({
1200 * ...
1201 * });
1202 * }
1203 * ```
1204 *
1205 * @codeGenApi
1206 */
1207const ɵɵdefineDirective = ɵɵdefineComponent;
1208/**
1209 * Create a pipe definition object.
1210 *
1211 * # Example
1212 * ```
1213 * class MyPipe implements PipeTransform {
1214 * // Generated by Angular Template Compiler
1215 * static ɵpipe = definePipe({
1216 * ...
1217 * });
1218 * }
1219 * ```
1220 * @param pipeDef Pipe definition generated by the compiler
1221 *
1222 * @codeGenApi
1223 */
1224function ɵɵdefinePipe(pipeDef) {
1225 return {
1226 type: pipeDef.type,
1227 name: pipeDef.name,
1228 factory: null,
1229 pure: pipeDef.pure !== false,
1230 standalone: pipeDef.standalone === true,
1231 onDestroy: pipeDef.type.prototype.ngOnDestroy || null
1232 };
1233}
1234/**
1235 * The following getter methods retrieve the definition from the type. Currently the retrieval
1236 * honors inheritance, but in the future we may change the rule to require that definitions are
1237 * explicit. This would require some sort of migration strategy.
1238 */
1239function getComponentDef(type) {
1240 return type[NG_COMP_DEF] || null;
1241}
1242function getDirectiveDef(type) {
1243 return type[NG_DIR_DEF] || null;
1244}
1245function getPipeDef$1(type) {
1246 return type[NG_PIPE_DEF] || null;
1247}
1248/**
1249 * Checks whether a given Component, Directive or Pipe is marked as standalone.
1250 * This will return false if passed anything other than a Component, Directive, or Pipe class
1251 * See this guide for additional information: https://angular.io/guide/standalone-components
1252 *
1253 * @param type A reference to a Component, Directive or Pipe.
1254 * @publicApi
1255 */
1256function isStandalone(type) {
1257 const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef$1(type);
1258 return def !== null ? def.standalone : false;
1259}
1260function getNgModuleDef(type, throwNotFound) {
1261 const ngModuleDef = type[NG_MOD_DEF] || null;
1262 if (!ngModuleDef && throwNotFound === true) {
1263 throw new Error(`Type ${stringify(type)} does not have 'ɵmod' property.`);
1264 }
1265 return ngModuleDef;
1266}
1267
1268/**
1269 * Special location which allows easy identification of type. If we have an array which was
1270 * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
1271 * `LContainer`.
1272 */
1273const TYPE = 1;
1274/**
1275 * Below are constants for LContainer indices to help us look up LContainer members
1276 * without having to remember the specific indices.
1277 * Uglify will inline these when minifying so there shouldn't be a cost.
1278 */
1279/**
1280 * Flag to signify that this `LContainer` may have transplanted views which need to be change
1281 * detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
1282 *
1283 * This flag, once set, is never unset for the `LContainer`. This means that when unset we can skip
1284 * a lot of work in `refreshEmbeddedViews`. But when set we still need to verify
1285 * that the `MOVED_VIEWS` are transplanted and on-push.
1286 */
1287const HAS_TRANSPLANTED_VIEWS = 2;
1288// PARENT, NEXT, TRANSPLANTED_VIEWS_TO_REFRESH are indices 3, 4, and 5
1289// As we already have these constants in LView, we don't need to re-create them.
1290// T_HOST is index 6
1291// We already have this constants in LView, we don't need to re-create it.
1292const NATIVE = 7;
1293const VIEW_REFS = 8;
1294const MOVED_VIEWS = 9;
1295/**
1296 * Size of LContainer's header. Represents the index after which all views in the
1297 * container will be inserted. We need to keep a record of current views so we know
1298 * which views are already in the DOM (and don't need to be re-added) and so we can
1299 * remove views from the DOM when they are no longer required.
1300 */
1301const CONTAINER_HEADER_OFFSET = 10;
1302// Note: This hack is necessary so we don't erroneously get a circular dependency
1303// failure based on types.
1304const unusedValueExportToPlacateAjd$4 = 1;
1305
1306// Below are constants for LView indices to help us look up LView members
1307// without having to remember the specific indices.
1308// Uglify will inline these when minifying so there shouldn't be a cost.
1309const HOST = 0;
1310const TVIEW = 1;
1311const FLAGS = 2;
1312const PARENT = 3;
1313const NEXT = 4;
1314const TRANSPLANTED_VIEWS_TO_REFRESH = 5;
1315const T_HOST = 6;
1316const CLEANUP = 7;
1317const CONTEXT = 8;
1318const INJECTOR$1 = 9;
1319const RENDERER_FACTORY = 10;
1320const RENDERER = 11;
1321const SANITIZER = 12;
1322const CHILD_HEAD = 13;
1323const CHILD_TAIL = 14;
1324// FIXME(misko): Investigate if the three declarations aren't all same thing.
1325const DECLARATION_VIEW = 15;
1326const DECLARATION_COMPONENT_VIEW = 16;
1327const DECLARATION_LCONTAINER = 17;
1328const PREORDER_HOOK_FLAGS = 18;
1329const QUERIES = 19;
1330const ID = 20;
1331const EMBEDDED_VIEW_INJECTOR = 21;
1332/**
1333 * Size of LView's header. Necessary to adjust for it when setting slots.
1334 *
1335 * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
1336 * instruction index into `LView` index. All other indexes should be in the `LView` index space and
1337 * there should be no need to refer to `HEADER_OFFSET` anywhere else.
1338 */
1339const HEADER_OFFSET = 22;
1340// Note: This hack is necessary so we don't erroneously get a circular dependency
1341// failure based on types.
1342const unusedValueExportToPlacateAjd$3 = 1;
1343
1344/**
1345 * True if `value` is `LView`.
1346 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1347 */
1348function isLView(value) {
1349 return Array.isArray(value) && typeof value[TYPE] === 'object';
1350}
1351/**
1352 * True if `value` is `LContainer`.
1353 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1354 */
1355function isLContainer(value) {
1356 return Array.isArray(value) && value[TYPE] === true;
1357}
1358function isContentQueryHost(tNode) {
1359 return (tNode.flags & 4 /* TNodeFlags.hasContentQuery */) !== 0;
1360}
1361function isComponentHost(tNode) {
1362 return tNode.componentOffset > -1;
1363}
1364function isDirectiveHost(tNode) {
1365 return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
1366}
1367function isComponentDef(def) {
1368 return def.template !== null;
1369}
1370function isRootView(target) {
1371 return (target[FLAGS] & 256 /* LViewFlags.IsRoot */) !== 0;
1372}
1373
1374// [Assert functions do not constraint type when they are guarded by a truthy
1375// expression.](https://github.com/microsoft/TypeScript/issues/37295)
1376function assertTNodeForLView(tNode, lView) {
1377 assertTNodeForTView(tNode, lView[TVIEW]);
1378}
1379function assertTNodeForTView(tNode, tView) {
1380 assertTNode(tNode);
1381 tNode.hasOwnProperty('tView_') &&
1382 assertEqual(tNode.tView_, tView, 'This TNode does not belong to this TView.');
1383}
1384function assertTNode(tNode) {
1385 assertDefined(tNode, 'TNode must be defined');
1386 if (!(tNode && typeof tNode === 'object' && tNode.hasOwnProperty('directiveStylingLast'))) {
1387 throwError('Not of type TNode, got: ' + tNode);
1388 }
1389}
1390function assertTIcu(tIcu) {
1391 assertDefined(tIcu, 'Expected TIcu to be defined');
1392 if (!(typeof tIcu.currentCaseLViewIndex === 'number')) {
1393 throwError('Object is not of TIcu type.');
1394 }
1395}
1396function assertComponentType(actual, msg = 'Type passed in is not ComponentType, it does not have \'ɵcmp\' property.') {
1397 if (!getComponentDef(actual)) {
1398 throwError(msg);
1399 }
1400}
1401function assertNgModuleType(actual, msg = 'Type passed in is not NgModuleType, it does not have \'ɵmod\' property.') {
1402 if (!getNgModuleDef(actual)) {
1403 throwError(msg);
1404 }
1405}
1406function assertCurrentTNodeIsParent(isParent) {
1407 assertEqual(isParent, true, 'currentTNode should be a parent');
1408}
1409function assertHasParent(tNode) {
1410 assertDefined(tNode, 'currentTNode should exist!');
1411 assertDefined(tNode.parent, 'currentTNode should have a parent');
1412}
1413function assertLContainer(value) {
1414 assertDefined(value, 'LContainer must be defined');
1415 assertEqual(isLContainer(value), true, 'Expecting LContainer');
1416}
1417function assertLViewOrUndefined(value) {
1418 value && assertEqual(isLView(value), true, 'Expecting LView or undefined or null');
1419}
1420function assertLView(value) {
1421 assertDefined(value, 'LView must be defined');
1422 assertEqual(isLView(value), true, 'Expecting LView');
1423}
1424function assertFirstCreatePass(tView, errMessage) {
1425 assertEqual(tView.firstCreatePass, true, errMessage || 'Should only be called in first create pass.');
1426}
1427function assertFirstUpdatePass(tView, errMessage) {
1428 assertEqual(tView.firstUpdatePass, true, errMessage || 'Should only be called in first update pass.');
1429}
1430/**
1431 * This is a basic sanity check that an object is probably a directive def. DirectiveDef is
1432 * an interface, so we can't do a direct instanceof check.
1433 */
1434function assertDirectiveDef(obj) {
1435 if (obj.type === undefined || obj.selectors == undefined || obj.inputs === undefined) {
1436 throwError(`Expected a DirectiveDef/ComponentDef and this object does not seem to have the expected shape.`);
1437 }
1438}
1439function assertIndexInDeclRange(lView, index) {
1440 const tView = lView[1];
1441 assertBetween(HEADER_OFFSET, tView.bindingStartIndex, index);
1442}
1443function assertIndexInExpandoRange(lView, index) {
1444 const tView = lView[1];
1445 assertBetween(tView.expandoStartIndex, lView.length, index);
1446}
1447function assertBetween(lower, upper, index) {
1448 if (!(lower <= index && index < upper)) {
1449 throwError(`Index out of range (expecting ${lower} <= ${index} < ${upper})`);
1450 }
1451}
1452function assertProjectionSlots(lView, errMessage) {
1453 assertDefined(lView[DECLARATION_COMPONENT_VIEW], 'Component views should exist.');
1454 assertDefined(lView[DECLARATION_COMPONENT_VIEW][T_HOST].projection, errMessage ||
1455 'Components with projection nodes (<ng-content>) must have projection slots defined.');
1456}
1457function assertParentView(lView, errMessage) {
1458 assertDefined(lView, errMessage || 'Component views should always have a parent view (component\'s host view)');
1459}
1460/**
1461 * This is a basic sanity check that the `injectorIndex` seems to point to what looks like a
1462 * NodeInjector data structure.
1463 *
1464 * @param lView `LView` which should be checked.
1465 * @param injectorIndex index into the `LView` where the `NodeInjector` is expected.
1466 */
1467function assertNodeInjector(lView, injectorIndex) {
1468 assertIndexInExpandoRange(lView, injectorIndex);
1469 assertIndexInExpandoRange(lView, injectorIndex + 8 /* NodeInjectorOffset.PARENT */);
1470 assertNumber(lView[injectorIndex + 0], 'injectorIndex should point to a bloom filter');
1471 assertNumber(lView[injectorIndex + 1], 'injectorIndex should point to a bloom filter');
1472 assertNumber(lView[injectorIndex + 2], 'injectorIndex should point to a bloom filter');
1473 assertNumber(lView[injectorIndex + 3], 'injectorIndex should point to a bloom filter');
1474 assertNumber(lView[injectorIndex + 4], 'injectorIndex should point to a bloom filter');
1475 assertNumber(lView[injectorIndex + 5], 'injectorIndex should point to a bloom filter');
1476 assertNumber(lView[injectorIndex + 6], 'injectorIndex should point to a bloom filter');
1477 assertNumber(lView[injectorIndex + 7], 'injectorIndex should point to a bloom filter');
1478 assertNumber(lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */], 'injectorIndex should point to parent injector');
1479}
1480
1481function getFactoryDef(type, throwNotFound) {
1482 const hasFactoryDef = type.hasOwnProperty(NG_FACTORY_DEF);
1483 if (!hasFactoryDef && throwNotFound === true && ngDevMode) {
1484 throw new Error(`Type ${stringify(type)} does not have 'ɵfac' property.`);
1485 }
1486 return hasFactoryDef ? type[NG_FACTORY_DEF] : null;
1487}
1488
1489/**
1490 * Represents a basic change from a previous to a new value for a single
1491 * property on a directive instance. Passed as a value in a
1492 * {@link SimpleChanges} object to the `ngOnChanges` hook.
1493 *
1494 * @see `OnChanges`
1495 *
1496 * @publicApi
1497 */
1498class SimpleChange {
1499 constructor(previousValue, currentValue, firstChange) {
1500 this.previousValue = previousValue;
1501 this.currentValue = currentValue;
1502 this.firstChange = firstChange;
1503 }
1504 /**
1505 * Check whether the new value is the first value assigned.
1506 */
1507 isFirstChange() {
1508 return this.firstChange;
1509 }
1510}
1511
1512/**
1513 * The NgOnChangesFeature decorates a component with support for the ngOnChanges
1514 * lifecycle hook, so it should be included in any component that implements
1515 * that hook.
1516 *
1517 * If the component or directive uses inheritance, the NgOnChangesFeature MUST
1518 * be included as a feature AFTER {@link InheritDefinitionFeature}, otherwise
1519 * inherited properties will not be propagated to the ngOnChanges lifecycle
1520 * hook.
1521 *
1522 * Example usage:
1523 *
1524 * ```
1525 * static ɵcmp = defineComponent({
1526 * ...
1527 * inputs: {name: 'publicName'},
1528 * features: [NgOnChangesFeature]
1529 * });
1530 * ```
1531 *
1532 * @codeGenApi
1533 */
1534function ɵɵNgOnChangesFeature() {
1535 return NgOnChangesFeatureImpl;
1536}
1537function NgOnChangesFeatureImpl(definition) {
1538 if (definition.type.prototype.ngOnChanges) {
1539 definition.setInput = ngOnChangesSetInput;
1540 }
1541 return rememberChangeHistoryAndInvokeOnChangesHook;
1542}
1543// This option ensures that the ngOnChanges lifecycle hook will be inherited
1544// from superclasses (in InheritDefinitionFeature).
1545/** @nocollapse */
1546// tslint:disable-next-line:no-toplevel-property-access
1547ɵɵNgOnChangesFeature.ngInherit = true;
1548/**
1549 * This is a synthetic lifecycle hook which gets inserted into `TView.preOrderHooks` to simulate
1550 * `ngOnChanges`.
1551 *
1552 * The hook reads the `NgSimpleChangesStore` data from the component instance and if changes are
1553 * found it invokes `ngOnChanges` on the component instance.
1554 *
1555 * @param this Component instance. Because this function gets inserted into `TView.preOrderHooks`,
1556 * it is guaranteed to be called with component instance.
1557 */
1558function rememberChangeHistoryAndInvokeOnChangesHook() {
1559 const simpleChangesStore = getSimpleChangesStore(this);
1560 const current = simpleChangesStore === null || simpleChangesStore === void 0 ? void 0 : simpleChangesStore.current;
1561 if (current) {
1562 const previous = simpleChangesStore.previous;
1563 if (previous === EMPTY_OBJ) {
1564 simpleChangesStore.previous = current;
1565 }
1566 else {
1567 // New changes are copied to the previous store, so that we don't lose history for inputs
1568 // which were not changed this time
1569 for (let key in current) {
1570 previous[key] = current[key];
1571 }
1572 }
1573 simpleChangesStore.current = null;
1574 this.ngOnChanges(current);
1575 }
1576}
1577function ngOnChangesSetInput(instance, value, publicName, privateName) {
1578 const declaredName = this.declaredInputs[publicName];
1579 ngDevMode && assertString(declaredName, 'Name of input in ngOnChanges has to be a string');
1580 const simpleChangesStore = getSimpleChangesStore(instance) ||
1581 setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
1582 const current = simpleChangesStore.current || (simpleChangesStore.current = {});
1583 const previous = simpleChangesStore.previous;
1584 const previousChange = previous[declaredName];
1585 current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
1586 instance[privateName] = value;
1587}
1588const SIMPLE_CHANGES_STORE = '__ngSimpleChanges__';
1589function getSimpleChangesStore(instance) {
1590 return instance[SIMPLE_CHANGES_STORE] || null;
1591}
1592function setSimpleChangesStore(instance, store) {
1593 return instance[SIMPLE_CHANGES_STORE] = store;
1594}
1595
1596let profilerCallback = null;
1597/**
1598 * Sets the callback function which will be invoked before and after performing certain actions at
1599 * runtime (for example, before and after running change detection).
1600 *
1601 * Warning: this function is *INTERNAL* and should not be relied upon in application's code.
1602 * The contract of the function might be changed in any release and/or the function can be removed
1603 * completely.
1604 *
1605 * @param profiler function provided by the caller or null value to disable profiling.
1606 */
1607const setProfiler = (profiler) => {
1608 profilerCallback = profiler;
1609};
1610/**
1611 * Profiler function which wraps user code executed by the runtime.
1612 *
1613 * @param event ProfilerEvent corresponding to the execution context
1614 * @param instance component instance
1615 * @param hookOrListener lifecycle hook function or output listener. The value depends on the
1616 * execution context
1617 * @returns
1618 */
1619const profiler = function (event, instance, hookOrListener) {
1620 if (profilerCallback != null /* both `null` and `undefined` */) {
1621 profilerCallback(event, instance, hookOrListener);
1622 }
1623};
1624
1625const SVG_NAMESPACE = 'svg';
1626const MATH_ML_NAMESPACE = 'math';
1627
1628/**
1629 * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
1630 * in same location in `LView`. This is because we don't want to pre-allocate space for it
1631 * because the storage is sparse. This file contains utilities for dealing with such data types.
1632 *
1633 * How do we know what is stored at a given location in `LView`.
1634 * - `Array.isArray(value) === false` => `RNode` (The normal storage value)
1635 * - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value.
1636 * - `typeof value[TYPE] === 'object'` => `LView`
1637 * - This happens when we have a component at a given location
1638 * - `typeof value[TYPE] === true` => `LContainer`
1639 * - This happens when we have `LContainer` binding at a given location.
1640 *
1641 *
1642 * NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.
1643 */
1644/**
1645 * Returns `RNode`.
1646 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1647 */
1648function unwrapRNode(value) {
1649 while (Array.isArray(value)) {
1650 value = value[HOST];
1651 }
1652 return value;
1653}
1654/**
1655 * Returns `LView` or `null` if not found.
1656 * @param value wrapped value of `RNode`, `LView`, `LContainer`
1657 */
1658function unwrapLView(value) {
1659 while (Array.isArray(value)) {
1660 // This check is same as `isLView()` but we don't call at as we don't want to call
1661 // `Array.isArray()` twice and give JITer more work for inlining.
1662 if (typeof value[TYPE] === 'object')
1663 return value;
1664 value = value[HOST];
1665 }
1666 return null;
1667}
1668/**
1669 * Retrieves an element value from the provided `viewData`, by unwrapping
1670 * from any containers, component views, or style contexts.
1671 */
1672function getNativeByIndex(index, lView) {
1673 ngDevMode && assertIndexInRange(lView, index);
1674 ngDevMode && assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Expected to be past HEADER_OFFSET');
1675 return unwrapRNode(lView[index]);
1676}
1677/**
1678 * Retrieve an `RNode` for a given `TNode` and `LView`.
1679 *
1680 * This function guarantees in dev mode to retrieve a non-null `RNode`.
1681 *
1682 * @param tNode
1683 * @param lView
1684 */
1685function getNativeByTNode(tNode, lView) {
1686 ngDevMode && assertTNodeForLView(tNode, lView);
1687 ngDevMode && assertIndexInRange(lView, tNode.index);
1688 const node = unwrapRNode(lView[tNode.index]);
1689 return node;
1690}
1691/**
1692 * Retrieve an `RNode` or `null` for a given `TNode` and `LView`.
1693 *
1694 * Some `TNode`s don't have associated `RNode`s. For example `Projection`
1695 *
1696 * @param tNode
1697 * @param lView
1698 */
1699function getNativeByTNodeOrNull(tNode, lView) {
1700 const index = tNode === null ? -1 : tNode.index;
1701 if (index !== -1) {
1702 ngDevMode && assertTNodeForLView(tNode, lView);
1703 const node = unwrapRNode(lView[index]);
1704 return node;
1705 }
1706 return null;
1707}
1708// fixme(misko): The return Type should be `TNode|null`
1709function getTNode(tView, index) {
1710 ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
1711 ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode');
1712 const tNode = tView.data[index];
1713 ngDevMode && tNode !== null && assertTNode(tNode);
1714 return tNode;
1715}
1716/** Retrieves a value from any `LView` or `TData`. */
1717function load(view, index) {
1718 ngDevMode && assertIndexInRange(view, index);
1719 return view[index];
1720}
1721function getComponentLViewByIndex(nodeIndex, hostView) {
1722 // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
1723 ngDevMode && assertIndexInRange(hostView, nodeIndex);
1724 const slotValue = hostView[nodeIndex];
1725 const lView = isLView(slotValue) ? slotValue : slotValue[HOST];
1726 return lView;
1727}
1728/** Checks whether a given view is in creation mode */
1729function isCreationMode(view) {
1730 return (view[FLAGS] & 4 /* LViewFlags.CreationMode */) === 4 /* LViewFlags.CreationMode */;
1731}
1732/**
1733 * Returns a boolean for whether the view is attached to the change detection tree.
1734 *
1735 * Note: This determines whether a view should be checked, not whether it's inserted
1736 * into a container. For that, you'll want `viewAttachedToContainer` below.
1737 */
1738function viewAttachedToChangeDetector(view) {
1739 return (view[FLAGS] & 64 /* LViewFlags.Attached */) === 64 /* LViewFlags.Attached */;
1740}
1741/** Returns a boolean for whether the view is attached to a container. */
1742function viewAttachedToContainer(view) {
1743 return isLContainer(view[PARENT]);
1744}
1745function getConstant(consts, index) {
1746 if (index === null || index === undefined)
1747 return null;
1748 ngDevMode && assertIndexInRange(consts, index);
1749 return consts[index];
1750}
1751/**
1752 * Resets the pre-order hook flags of the view.
1753 * @param lView the LView on which the flags are reset
1754 */
1755function resetPreOrderHookFlags(lView) {
1756 lView[PREORDER_HOOK_FLAGS] = 0;
1757}
1758/**
1759 * Updates the `TRANSPLANTED_VIEWS_TO_REFRESH` counter on the `LContainer` as well as the parents
1760 * whose
1761 * 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
1762 * or
1763 * 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
1764 */
1765function updateTransplantedViewCount(lContainer, amount) {
1766 lContainer[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
1767 let viewOrContainer = lContainer;
1768 let parent = lContainer[PARENT];
1769 while (parent !== null &&
1770 ((amount === 1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 1) ||
1771 (amount === -1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 0))) {
1772 parent[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
1773 viewOrContainer = parent;
1774 parent = parent[PARENT];
1775 }
1776}
1777
1778const instructionState = {
1779 lFrame: createLFrame(null),
1780 bindingsEnabled: true,
1781};
1782/**
1783 * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
1784 *
1785 * Necessary to support ChangeDetectorRef.checkNoChanges().
1786 *
1787 * The `checkNoChanges` function is invoked only in ngDevMode=true and verifies that no unintended
1788 * changes exist in the change detector or its children.
1789 */
1790let _isInCheckNoChangesMode = false;
1791/**
1792 * Returns true if the instruction state stack is empty.
1793 *
1794 * Intended to be called from tests only (tree shaken otherwise).
1795 */
1796function specOnlyIsInstructionStateEmpty() {
1797 return instructionState.lFrame.parent === null;
1798}
1799function getElementDepthCount() {
1800 return instructionState.lFrame.elementDepthCount;
1801}
1802function increaseElementDepthCount() {
1803 instructionState.lFrame.elementDepthCount++;
1804}
1805function decreaseElementDepthCount() {
1806 instructionState.lFrame.elementDepthCount--;
1807}
1808function getBindingsEnabled() {
1809 return instructionState.bindingsEnabled;
1810}
1811/**
1812 * Enables directive matching on elements.
1813 *
1814 * * Example:
1815 * ```
1816 * <my-comp my-directive>
1817 * Should match component / directive.
1818 * </my-comp>
1819 * <div ngNonBindable>
1820 * <!-- ɵɵdisableBindings() -->
1821 * <my-comp my-directive>
1822 * Should not match component / directive because we are in ngNonBindable.
1823 * </my-comp>
1824 * <!-- ɵɵenableBindings() -->
1825 * </div>
1826 * ```
1827 *
1828 * @codeGenApi
1829 */
1830function ɵɵenableBindings() {
1831 instructionState.bindingsEnabled = true;
1832}
1833/**
1834 * Disables directive matching on element.
1835 *
1836 * * Example:
1837 * ```
1838 * <my-comp my-directive>
1839 * Should match component / directive.
1840 * </my-comp>
1841 * <div ngNonBindable>
1842 * <!-- ɵɵdisableBindings() -->
1843 * <my-comp my-directive>
1844 * Should not match component / directive because we are in ngNonBindable.
1845 * </my-comp>
1846 * <!-- ɵɵenableBindings() -->
1847 * </div>
1848 * ```
1849 *
1850 * @codeGenApi
1851 */
1852function ɵɵdisableBindings() {
1853 instructionState.bindingsEnabled = false;
1854}
1855/**
1856 * Return the current `LView`.
1857 */
1858function getLView() {
1859 return instructionState.lFrame.lView;
1860}
1861/**
1862 * Return the current `TView`.
1863 */
1864function getTView() {
1865 return instructionState.lFrame.tView;
1866}
1867/**
1868 * Restores `contextViewData` to the given OpaqueViewState instance.
1869 *
1870 * Used in conjunction with the getCurrentView() instruction to save a snapshot
1871 * of the current view and restore it when listeners are invoked. This allows
1872 * walking the declaration view tree in listeners to get vars from parent views.
1873 *
1874 * @param viewToRestore The OpaqueViewState instance to restore.
1875 * @returns Context of the restored OpaqueViewState instance.
1876 *
1877 * @codeGenApi
1878 */
1879function ɵɵrestoreView(viewToRestore) {
1880 instructionState.lFrame.contextLView = viewToRestore;
1881 return viewToRestore[CONTEXT];
1882}
1883/**
1884 * Clears the view set in `ɵɵrestoreView` from memory. Returns the passed in
1885 * value so that it can be used as a return value of an instruction.
1886 *
1887 * @codeGenApi
1888 */
1889function ɵɵresetView(value) {
1890 instructionState.lFrame.contextLView = null;
1891 return value;
1892}
1893function getCurrentTNode() {
1894 let currentTNode = getCurrentTNodePlaceholderOk();
1895 while (currentTNode !== null && currentTNode.type === 64 /* TNodeType.Placeholder */) {
1896 currentTNode = currentTNode.parent;
1897 }
1898 return currentTNode;
1899}
1900function getCurrentTNodePlaceholderOk() {
1901 return instructionState.lFrame.currentTNode;
1902}
1903function getCurrentParentTNode() {
1904 const lFrame = instructionState.lFrame;
1905 const currentTNode = lFrame.currentTNode;
1906 return lFrame.isParent ? currentTNode : currentTNode.parent;
1907}
1908function setCurrentTNode(tNode, isParent) {
1909 ngDevMode && tNode && assertTNodeForTView(tNode, instructionState.lFrame.tView);
1910 const lFrame = instructionState.lFrame;
1911 lFrame.currentTNode = tNode;
1912 lFrame.isParent = isParent;
1913}
1914function isCurrentTNodeParent() {
1915 return instructionState.lFrame.isParent;
1916}
1917function setCurrentTNodeAsNotParent() {
1918 instructionState.lFrame.isParent = false;
1919}
1920function getContextLView() {
1921 const contextLView = instructionState.lFrame.contextLView;
1922 ngDevMode && assertDefined(contextLView, 'contextLView must be defined.');
1923 return contextLView;
1924}
1925function isInCheckNoChangesMode() {
1926 !ngDevMode && throwError('Must never be called in production mode');
1927 return _isInCheckNoChangesMode;
1928}
1929function setIsInCheckNoChangesMode(mode) {
1930 !ngDevMode && throwError('Must never be called in production mode');
1931 _isInCheckNoChangesMode = mode;
1932}
1933// top level variables should not be exported for performance reasons (PERF_NOTES.md)
1934function getBindingRoot() {
1935 const lFrame = instructionState.lFrame;
1936 let index = lFrame.bindingRootIndex;
1937 if (index === -1) {
1938 index = lFrame.bindingRootIndex = lFrame.tView.bindingStartIndex;
1939 }
1940 return index;
1941}
1942function getBindingIndex() {
1943 return instructionState.lFrame.bindingIndex;
1944}
1945function setBindingIndex(value) {
1946 return instructionState.lFrame.bindingIndex = value;
1947}
1948function nextBindingIndex() {
1949 return instructionState.lFrame.bindingIndex++;
1950}
1951function incrementBindingIndex(count) {
1952 const lFrame = instructionState.lFrame;
1953 const index = lFrame.bindingIndex;
1954 lFrame.bindingIndex = lFrame.bindingIndex + count;
1955 return index;
1956}
1957function isInI18nBlock() {
1958 return instructionState.lFrame.inI18n;
1959}
1960function setInI18nBlock(isInI18nBlock) {
1961 instructionState.lFrame.inI18n = isInI18nBlock;
1962}
1963/**
1964 * Set a new binding root index so that host template functions can execute.
1965 *
1966 * Bindings inside the host template are 0 index. But because we don't know ahead of time
1967 * how many host bindings we have we can't pre-compute them. For this reason they are all
1968 * 0 index and we just shift the root so that they match next available location in the LView.
1969 *
1970 * @param bindingRootIndex Root index for `hostBindings`
1971 * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive
1972 * whose `hostBindings` are being processed.
1973 */
1974function setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex) {
1975 const lFrame = instructionState.lFrame;
1976 lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex;
1977 setCurrentDirectiveIndex(currentDirectiveIndex);
1978}
1979/**
1980 * When host binding is executing this points to the directive index.
1981 * `TView.data[getCurrentDirectiveIndex()]` is `DirectiveDef`
1982 * `LView[getCurrentDirectiveIndex()]` is directive instance.
1983 */
1984function getCurrentDirectiveIndex() {
1985 return instructionState.lFrame.currentDirectiveIndex;
1986}
1987/**
1988 * Sets an index of a directive whose `hostBindings` are being processed.
1989 *
1990 * @param currentDirectiveIndex `TData` index where current directive instance can be found.
1991 */
1992function setCurrentDirectiveIndex(currentDirectiveIndex) {
1993 instructionState.lFrame.currentDirectiveIndex = currentDirectiveIndex;
1994}
1995/**
1996 * Retrieve the current `DirectiveDef` which is active when `hostBindings` instruction is being
1997 * executed.
1998 *
1999 * @param tData Current `TData` where the `DirectiveDef` will be looked up at.
2000 */
2001function getCurrentDirectiveDef(tData) {
2002 const currentDirectiveIndex = instructionState.lFrame.currentDirectiveIndex;
2003 return currentDirectiveIndex === -1 ? null : tData[currentDirectiveIndex];
2004}
2005function getCurrentQueryIndex() {
2006 return instructionState.lFrame.currentQueryIndex;
2007}
2008function setCurrentQueryIndex(value) {
2009 instructionState.lFrame.currentQueryIndex = value;
2010}
2011/**
2012 * Returns a `TNode` of the location where the current `LView` is declared at.
2013 *
2014 * @param lView an `LView` that we want to find parent `TNode` for.
2015 */
2016function getDeclarationTNode(lView) {
2017 const tView = lView[TVIEW];
2018 // Return the declaration parent for embedded views
2019 if (tView.type === 2 /* TViewType.Embedded */) {
2020 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
2021 return tView.declTNode;
2022 }
2023 // Components don't have `TView.declTNode` because each instance of component could be
2024 // inserted in different location, hence `TView.declTNode` is meaningless.
2025 // Falling back to `T_HOST` in case we cross component boundary.
2026 if (tView.type === 1 /* TViewType.Component */) {
2027 return lView[T_HOST];
2028 }
2029 // Remaining TNode type is `TViewType.Root` which doesn't have a parent TNode.
2030 return null;
2031}
2032/**
2033 * This is a light weight version of the `enterView` which is needed by the DI system.
2034 *
2035 * @param lView `LView` location of the DI context.
2036 * @param tNode `TNode` for DI context
2037 * @param flags DI context flags. if `SkipSelf` flag is set than we walk up the declaration
2038 * tree from `tNode` until we find parent declared `TElementNode`.
2039 * @returns `true` if we have successfully entered DI associated with `tNode` (or with declared
2040 * `TNode` if `flags` has `SkipSelf`). Failing to enter DI implies that no associated
2041 * `NodeInjector` can be found and we should instead use `ModuleInjector`.
2042 * - If `true` than this call must be fallowed by `leaveDI`
2043 * - If `false` than this call failed and we should NOT call `leaveDI`
2044 */
2045function enterDI(lView, tNode, flags) {
2046 ngDevMode && assertLViewOrUndefined(lView);
2047 if (flags & InjectFlags.SkipSelf) {
2048 ngDevMode && assertTNodeForTView(tNode, lView[TVIEW]);
2049 let parentTNode = tNode;
2050 let parentLView = lView;
2051 while (true) {
2052 ngDevMode && assertDefined(parentTNode, 'Parent TNode should be defined');
2053 parentTNode = parentTNode.parent;
2054 if (parentTNode === null && !(flags & InjectFlags.Host)) {
2055 parentTNode = getDeclarationTNode(parentLView);
2056 if (parentTNode === null)
2057 break;
2058 // In this case, a parent exists and is definitely an element. So it will definitely
2059 // have an existing lView as the declaration view, which is why we can assume it's defined.
2060 ngDevMode && assertDefined(parentLView, 'Parent LView should be defined');
2061 parentLView = parentLView[DECLARATION_VIEW];
2062 // In Ivy there are Comment nodes that correspond to ngIf and NgFor embedded directives
2063 // We want to skip those and look only at Elements and ElementContainers to ensure
2064 // we're looking at true parent nodes, and not content or other types.
2065 if (parentTNode.type & (2 /* TNodeType.Element */ | 8 /* TNodeType.ElementContainer */)) {
2066 break;
2067 }
2068 }
2069 else {
2070 break;
2071 }
2072 }
2073 if (parentTNode === null) {
2074 // If we failed to find a parent TNode this means that we should use module injector.
2075 return false;
2076 }
2077 else {
2078 tNode = parentTNode;
2079 lView = parentLView;
2080 }
2081 }
2082 ngDevMode && assertTNodeForLView(tNode, lView);
2083 const lFrame = instructionState.lFrame = allocLFrame();
2084 lFrame.currentTNode = tNode;
2085 lFrame.lView = lView;
2086 return true;
2087}
2088/**
2089 * Swap the current lView with a new lView.
2090 *
2091 * For performance reasons we store the lView in the top level of the module.
2092 * This way we minimize the number of properties to read. Whenever a new view
2093 * is entered we have to store the lView for later, and when the view is
2094 * exited the state has to be restored
2095 *
2096 * @param newView New lView to become active
2097 * @returns the previously active lView;
2098 */
2099function enterView(newView) {
2100 ngDevMode && assertNotEqual(newView[0], newView[1], '????');
2101 ngDevMode && assertLViewOrUndefined(newView);
2102 const newLFrame = allocLFrame();
2103 if (ngDevMode) {
2104 assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
2105 assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
2106 assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
2107 assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
2108 assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
2109 assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
2110 assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
2111 assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
2112 assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
2113 }
2114 const tView = newView[TVIEW];
2115 instructionState.lFrame = newLFrame;
2116 ngDevMode && tView.firstChild && assertTNodeForTView(tView.firstChild, tView);
2117 newLFrame.currentTNode = tView.firstChild;
2118 newLFrame.lView = newView;
2119 newLFrame.tView = tView;
2120 newLFrame.contextLView = newView;
2121 newLFrame.bindingIndex = tView.bindingStartIndex;
2122 newLFrame.inI18n = false;
2123}
2124/**
2125 * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure.
2126 */
2127function allocLFrame() {
2128 const currentLFrame = instructionState.lFrame;
2129 const childLFrame = currentLFrame === null ? null : currentLFrame.child;
2130 const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame;
2131 return newLFrame;
2132}
2133function createLFrame(parent) {
2134 const lFrame = {
2135 currentTNode: null,
2136 isParent: true,
2137 lView: null,
2138 tView: null,
2139 selectedIndex: -1,
2140 contextLView: null,
2141 elementDepthCount: 0,
2142 currentNamespace: null,
2143 currentDirectiveIndex: -1,
2144 bindingRootIndex: -1,
2145 bindingIndex: -1,
2146 currentQueryIndex: 0,
2147 parent: parent,
2148 child: null,
2149 inI18n: false,
2150 };
2151 parent !== null && (parent.child = lFrame); // link the new LFrame for reuse.
2152 return lFrame;
2153}
2154/**
2155 * A lightweight version of leave which is used with DI.
2156 *
2157 * This function only resets `currentTNode` and `LView` as those are the only properties
2158 * used with DI (`enterDI()`).
2159 *
2160 * NOTE: This function is reexported as `leaveDI`. However `leaveDI` has return type of `void` where
2161 * as `leaveViewLight` has `LFrame`. This is so that `leaveViewLight` can be used in `leaveView`.
2162 */
2163function leaveViewLight() {
2164 const oldLFrame = instructionState.lFrame;
2165 instructionState.lFrame = oldLFrame.parent;
2166 oldLFrame.currentTNode = null;
2167 oldLFrame.lView = null;
2168 return oldLFrame;
2169}
2170/**
2171 * This is a lightweight version of the `leaveView` which is needed by the DI system.
2172 *
2173 * NOTE: this function is an alias so that we can change the type of the function to have `void`
2174 * return type.
2175 */
2176const leaveDI = leaveViewLight;
2177/**
2178 * Leave the current `LView`
2179 *
2180 * This pops the `LFrame` with the associated `LView` from the stack.
2181 *
2182 * IMPORTANT: We must zero out the `LFrame` values here otherwise they will be retained. This is
2183 * because for performance reasons we don't release `LFrame` but rather keep it for next use.
2184 */
2185function leaveView() {
2186 const oldLFrame = leaveViewLight();
2187 oldLFrame.isParent = true;
2188 oldLFrame.tView = null;
2189 oldLFrame.selectedIndex = -1;
2190 oldLFrame.contextLView = null;
2191 oldLFrame.elementDepthCount = 0;
2192 oldLFrame.currentDirectiveIndex = -1;
2193 oldLFrame.currentNamespace = null;
2194 oldLFrame.bindingRootIndex = -1;
2195 oldLFrame.bindingIndex = -1;
2196 oldLFrame.currentQueryIndex = 0;
2197}
2198function nextContextImpl(level) {
2199 const contextLView = instructionState.lFrame.contextLView =
2200 walkUpViews(level, instructionState.lFrame.contextLView);
2201 return contextLView[CONTEXT];
2202}
2203function walkUpViews(nestingLevel, currentView) {
2204 while (nestingLevel > 0) {
2205 ngDevMode &&
2206 assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.');
2207 currentView = currentView[DECLARATION_VIEW];
2208 nestingLevel--;
2209 }
2210 return currentView;
2211}
2212/**
2213 * Gets the currently selected element index.
2214 *
2215 * Used with {@link property} instruction (and more in the future) to identify the index in the
2216 * current `LView` to act on.
2217 */
2218function getSelectedIndex() {
2219 return instructionState.lFrame.selectedIndex;
2220}
2221/**
2222 * Sets the most recent index passed to {@link select}
2223 *
2224 * Used with {@link property} instruction (and more in the future) to identify the index in the
2225 * current `LView` to act on.
2226 *
2227 * (Note that if an "exit function" was set earlier (via `setElementExitFn()`) then that will be
2228 * run if and when the provided `index` value is different from the current selected index value.)
2229 */
2230function setSelectedIndex(index) {
2231 ngDevMode && index !== -1 &&
2232 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
2233 ngDevMode &&
2234 assertLessThan(index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView');
2235 instructionState.lFrame.selectedIndex = index;
2236}
2237/**
2238 * Gets the `tNode` that represents currently selected element.
2239 */
2240function getSelectedTNode() {
2241 const lFrame = instructionState.lFrame;
2242 return getTNode(lFrame.tView, lFrame.selectedIndex);
2243}
2244/**
2245 * Sets the namespace used to create elements to `'http://www.w3.org/2000/svg'` in global state.
2246 *
2247 * @codeGenApi
2248 */
2249function ɵɵnamespaceSVG() {
2250 instructionState.lFrame.currentNamespace = SVG_NAMESPACE;
2251}
2252/**
2253 * Sets the namespace used to create elements to `'http://www.w3.org/1998/MathML/'` in global state.
2254 *
2255 * @codeGenApi
2256 */
2257function ɵɵnamespaceMathML() {
2258 instructionState.lFrame.currentNamespace = MATH_ML_NAMESPACE;
2259}
2260/**
2261 * Sets the namespace used to create elements to `null`, which forces element creation to use
2262 * `createElement` rather than `createElementNS`.
2263 *
2264 * @codeGenApi
2265 */
2266function ɵɵnamespaceHTML() {
2267 namespaceHTMLInternal();
2268}
2269/**
2270 * Sets the namespace used to create elements to `null`, which forces element creation to use
2271 * `createElement` rather than `createElementNS`.
2272 */
2273function namespaceHTMLInternal() {
2274 instructionState.lFrame.currentNamespace = null;
2275}
2276function getNamespace$1() {
2277 return instructionState.lFrame.currentNamespace;
2278}
2279
2280/**
2281 * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`.
2282 *
2283 * Must be run *only* on the first template pass.
2284 *
2285 * Sets up the pre-order hooks on the provided `tView`,
2286 * see {@link HookData} for details about the data structure.
2287 *
2288 * @param directiveIndex The index of the directive in LView
2289 * @param directiveDef The definition containing the hooks to setup in tView
2290 * @param tView The current TView
2291 */
2292function registerPreOrderHooks(directiveIndex, directiveDef, tView) {
2293 ngDevMode && assertFirstCreatePass(tView);
2294 const { ngOnChanges, ngOnInit, ngDoCheck } = directiveDef.type.prototype;
2295 if (ngOnChanges) {
2296 const wrappedOnChanges = NgOnChangesFeatureImpl(directiveDef);
2297 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, wrappedOnChanges);
2298 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = []))
2299 .push(directiveIndex, wrappedOnChanges);
2300 }
2301 if (ngOnInit) {
2302 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(0 - directiveIndex, ngOnInit);
2303 }
2304 if (ngDoCheck) {
2305 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, ngDoCheck);
2306 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, ngDoCheck);
2307 }
2308}
2309/**
2310 *
2311 * Loops through the directives on the provided `tNode` and queues hooks to be
2312 * run that are not initialization hooks.
2313 *
2314 * Should be executed during `elementEnd()` and similar to
2315 * preserve hook execution order. Content, view, and destroy hooks for projected
2316 * components and directives must be called *before* their hosts.
2317 *
2318 * Sets up the content, view, and destroy hooks on the provided `tView`,
2319 * see {@link HookData} for details about the data structure.
2320 *
2321 * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up
2322 * separately at `elementStart`.
2323 *
2324 * @param tView The current TView
2325 * @param tNode The TNode whose directives are to be searched for hooks to queue
2326 */
2327function registerPostOrderHooks(tView, tNode) {
2328 ngDevMode && assertFirstCreatePass(tView);
2329 // It's necessary to loop through the directives at elementEnd() (rather than processing in
2330 // directiveCreate) so we can preserve the current hook order. Content, view, and destroy
2331 // hooks for projected components and directives must be called *before* their hosts.
2332 for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) {
2333 const directiveDef = tView.data[i];
2334 ngDevMode && assertDefined(directiveDef, 'Expecting DirectiveDef');
2335 const lifecycleHooks = directiveDef.type.prototype;
2336 const { ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked, ngOnDestroy } = lifecycleHooks;
2337 if (ngAfterContentInit) {
2338 (tView.contentHooks || (tView.contentHooks = [])).push(-i, ngAfterContentInit);
2339 }
2340 if (ngAfterContentChecked) {
2341 (tView.contentHooks || (tView.contentHooks = [])).push(i, ngAfterContentChecked);
2342 (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, ngAfterContentChecked);
2343 }
2344 if (ngAfterViewInit) {
2345 (tView.viewHooks || (tView.viewHooks = [])).push(-i, ngAfterViewInit);
2346 }
2347 if (ngAfterViewChecked) {
2348 (tView.viewHooks || (tView.viewHooks = [])).push(i, ngAfterViewChecked);
2349 (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, ngAfterViewChecked);
2350 }
2351 if (ngOnDestroy != null) {
2352 (tView.destroyHooks || (tView.destroyHooks = [])).push(i, ngOnDestroy);
2353 }
2354 }
2355}
2356/**
2357 * Executing hooks requires complex logic as we need to deal with 2 constraints.
2358 *
2359 * 1. Init hooks (ngOnInit, ngAfterContentInit, ngAfterViewInit) must all be executed once and only
2360 * once, across many change detection cycles. This must be true even if some hooks throw, or if
2361 * some recursively trigger a change detection cycle.
2362 * To solve that, it is required to track the state of the execution of these init hooks.
2363 * This is done by storing and maintaining flags in the view: the {@link InitPhaseState},
2364 * and the index within that phase. They can be seen as a cursor in the following structure:
2365 * [[onInit1, onInit2], [afterContentInit1], [afterViewInit1, afterViewInit2, afterViewInit3]]
2366 * They are are stored as flags in LView[FLAGS].
2367 *
2368 * 2. Pre-order hooks can be executed in batches, because of the select instruction.
2369 * To be able to pause and resume their execution, we also need some state about the hook's array
2370 * that is being processed:
2371 * - the index of the next hook to be executed
2372 * - the number of init hooks already found in the processed part of the array
2373 * They are are stored as flags in LView[PREORDER_HOOK_FLAGS].
2374 */
2375/**
2376 * Executes pre-order check hooks ( OnChanges, DoChanges) given a view where all the init hooks were
2377 * executed once. This is a light version of executeInitAndCheckPreOrderHooks where we can skip read
2378 * / write of the init-hooks related flags.
2379 * @param lView The LView where hooks are defined
2380 * @param hooks Hooks to be run
2381 * @param nodeIndex 3 cases depending on the value:
2382 * - undefined: all hooks from the array should be executed (post-order case)
2383 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2384 * flushing the remaining hooks)
2385 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2386 * case, when executing select(number))
2387 */
2388function executeCheckHooks(lView, hooks, nodeIndex) {
2389 callHooks(lView, hooks, 3 /* InitPhaseState.InitPhaseCompleted */, nodeIndex);
2390}
2391/**
2392 * Executes post-order init and check hooks (one of AfterContentInit, AfterContentChecked,
2393 * AfterViewInit, AfterViewChecked) given a view where there are pending init hooks to be executed.
2394 * @param lView The LView where hooks are defined
2395 * @param hooks Hooks to be run
2396 * @param initPhase A phase for which hooks should be run
2397 * @param nodeIndex 3 cases depending on the value:
2398 * - undefined: all hooks from the array should be executed (post-order case)
2399 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2400 * flushing the remaining hooks)
2401 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2402 * case, when executing select(number))
2403 */
2404function executeInitAndCheckHooks(lView, hooks, initPhase, nodeIndex) {
2405 ngDevMode &&
2406 assertNotEqual(initPhase, 3 /* InitPhaseState.InitPhaseCompleted */, 'Init pre-order hooks should not be called more than once');
2407 if ((lView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
2408 callHooks(lView, hooks, initPhase, nodeIndex);
2409 }
2410}
2411function incrementInitPhaseFlags(lView, initPhase) {
2412 ngDevMode &&
2413 assertNotEqual(initPhase, 3 /* InitPhaseState.InitPhaseCompleted */, 'Init hooks phase should not be incremented after all init hooks have been run.');
2414 let flags = lView[FLAGS];
2415 if ((flags & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
2416 flags &= 2047 /* LViewFlags.IndexWithinInitPhaseReset */;
2417 flags += 1 /* LViewFlags.InitPhaseStateIncrementer */;
2418 lView[FLAGS] = flags;
2419 }
2420}
2421/**
2422 * Calls lifecycle hooks with their contexts, skipping init hooks if it's not
2423 * the first LView pass
2424 *
2425 * @param currentView The current view
2426 * @param arr The array in which the hooks are found
2427 * @param initPhaseState the current state of the init phase
2428 * @param currentNodeIndex 3 cases depending on the value:
2429 * - undefined: all hooks from the array should be executed (post-order case)
2430 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
2431 * flushing the remaining hooks)
2432 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
2433 * case, when executing select(number))
2434 */
2435function callHooks(currentView, arr, initPhase, currentNodeIndex) {
2436 ngDevMode &&
2437 assertEqual(isInCheckNoChangesMode(), false, 'Hooks should never be run when in check no changes mode.');
2438 const startIndex = currentNodeIndex !== undefined ?
2439 (currentView[PREORDER_HOOK_FLAGS] & 65535 /* PreOrderHookFlags.IndexOfTheNextPreOrderHookMaskMask */) :
2440 0;
2441 const nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1;
2442 const max = arr.length - 1; // Stop the loop at length - 1, because we look for the hook at i + 1
2443 let lastNodeIndexFound = 0;
2444 for (let i = startIndex; i < max; i++) {
2445 const hook = arr[i + 1];
2446 if (typeof hook === 'number') {
2447 lastNodeIndexFound = arr[i];
2448 if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) {
2449 break;
2450 }
2451 }
2452 else {
2453 const isInitHook = arr[i] < 0;
2454 if (isInitHook)
2455 currentView[PREORDER_HOOK_FLAGS] += 65536 /* PreOrderHookFlags.NumberOfInitHooksCalledIncrementer */;
2456 if (lastNodeIndexFound < nodeIndexLimit || nodeIndexLimit == -1) {
2457 callHook(currentView, initPhase, arr, i);
2458 currentView[PREORDER_HOOK_FLAGS] =
2459 (currentView[PREORDER_HOOK_FLAGS] & 4294901760 /* PreOrderHookFlags.NumberOfInitHooksCalledMask */) + i +
2460 2;
2461 }
2462 i++;
2463 }
2464 }
2465}
2466/**
2467 * Execute one hook against the current `LView`.
2468 *
2469 * @param currentView The current view
2470 * @param initPhaseState the current state of the init phase
2471 * @param arr The array in which the hooks are found
2472 * @param i The current index within the hook data array
2473 */
2474function callHook(currentView, initPhase, arr, i) {
2475 const isInitHook = arr[i] < 0;
2476 const hook = arr[i + 1];
2477 const directiveIndex = isInitHook ? -arr[i] : arr[i];
2478 const directive = currentView[directiveIndex];
2479 if (isInitHook) {
2480 const indexWithintInitPhase = currentView[FLAGS] >> 11 /* LViewFlags.IndexWithinInitPhaseShift */;
2481 // The init phase state must be always checked here as it may have been recursively updated.
2482 if (indexWithintInitPhase <
2483 (currentView[PREORDER_HOOK_FLAGS] >> 16 /* PreOrderHookFlags.NumberOfInitHooksCalledShift */) &&
2484 (currentView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
2485 currentView[FLAGS] += 2048 /* LViewFlags.IndexWithinInitPhaseIncrementer */;
2486 profiler(4 /* ProfilerEvent.LifecycleHookStart */, directive, hook);
2487 try {
2488 hook.call(directive);
2489 }
2490 finally {
2491 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, directive, hook);
2492 }
2493 }
2494 }
2495 else {
2496 profiler(4 /* ProfilerEvent.LifecycleHookStart */, directive, hook);
2497 try {
2498 hook.call(directive);
2499 }
2500 finally {
2501 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, directive, hook);
2502 }
2503 }
2504}
2505
2506const NO_PARENT_INJECTOR = -1;
2507/**
2508 * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in
2509 * `TView.data`. This allows us to store information about the current node's tokens (which
2510 * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
2511 * shared, so they live in `LView`).
2512 *
2513 * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter
2514 * determines whether a directive is available on the associated node or not. This prevents us
2515 * from searching the directives array at this level unless it's probable the directive is in it.
2516 *
2517 * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
2518 *
2519 * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed
2520 * using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
2521 * will differ based on where it is flattened into the main array, so it's not possible to know
2522 * the indices ahead of time and save their types here. The interfaces are still included here
2523 * for documentation purposes.
2524 *
2525 * export interface LInjector extends Array<any> {
2526 *
2527 * // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
2528 * [0]: number;
2529 *
2530 * // Cumulative bloom for directive IDs 32-63
2531 * [1]: number;
2532 *
2533 * // Cumulative bloom for directive IDs 64-95
2534 * [2]: number;
2535 *
2536 * // Cumulative bloom for directive IDs 96-127
2537 * [3]: number;
2538 *
2539 * // Cumulative bloom for directive IDs 128-159
2540 * [4]: number;
2541 *
2542 * // Cumulative bloom for directive IDs 160 - 191
2543 * [5]: number;
2544 *
2545 * // Cumulative bloom for directive IDs 192 - 223
2546 * [6]: number;
2547 *
2548 * // Cumulative bloom for directive IDs 224 - 255
2549 * [7]: number;
2550 *
2551 * // We need to store a reference to the injector's parent so DI can keep looking up
2552 * // the injector tree until it finds the dependency it's looking for.
2553 * [PARENT_INJECTOR]: number;
2554 * }
2555 *
2556 * export interface TInjector extends Array<any> {
2557 *
2558 * // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
2559 * [0]: number;
2560 *
2561 * // Shared node bloom for directive IDs 32-63
2562 * [1]: number;
2563 *
2564 * // Shared node bloom for directive IDs 64-95
2565 * [2]: number;
2566 *
2567 * // Shared node bloom for directive IDs 96-127
2568 * [3]: number;
2569 *
2570 * // Shared node bloom for directive IDs 128-159
2571 * [4]: number;
2572 *
2573 * // Shared node bloom for directive IDs 160 - 191
2574 * [5]: number;
2575 *
2576 * // Shared node bloom for directive IDs 192 - 223
2577 * [6]: number;
2578 *
2579 * // Shared node bloom for directive IDs 224 - 255
2580 * [7]: number;
2581 *
2582 * // Necessary to find directive indices for a particular node.
2583 * [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
2584 * }
2585 */
2586/**
2587 * Factory for creating instances of injectors in the NodeInjector.
2588 *
2589 * This factory is complicated by the fact that it can resolve `multi` factories as well.
2590 *
2591 * NOTE: Some of the fields are optional which means that this class has two hidden classes.
2592 * - One without `multi` support (most common)
2593 * - One with `multi` values, (rare).
2594 *
2595 * Since VMs can cache up to 4 inline hidden classes this is OK.
2596 *
2597 * - Single factory: Only `resolving` and `factory` is defined.
2598 * - `providers` factory: `componentProviders` is a number and `index = -1`.
2599 * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`.
2600 */
2601class NodeInjectorFactory {
2602 constructor(
2603 /**
2604 * Factory to invoke in order to create a new instance.
2605 */
2606 factory,
2607 /**
2608 * Set to `true` if the token is declared in `viewProviders` (or if it is component).
2609 */
2610 isViewProvider, injectImplementation) {
2611 this.factory = factory;
2612 /**
2613 * Marker set to true during factory invocation to see if we get into recursive loop.
2614 * Recursive loop causes an error to be displayed.
2615 */
2616 this.resolving = false;
2617 ngDevMode && assertDefined(factory, 'Factory not specified');
2618 ngDevMode && assertEqual(typeof factory, 'function', 'Expected factory function.');
2619 this.canSeeViewProviders = isViewProvider;
2620 this.injectImpl = injectImplementation;
2621 }
2622}
2623function isFactory(obj) {
2624 return obj instanceof NodeInjectorFactory;
2625}
2626// Note: This hack is necessary so we don't erroneously get a circular dependency
2627// failure based on types.
2628const unusedValueExportToPlacateAjd$2 = 1;
2629
2630/**
2631 * Converts `TNodeType` into human readable text.
2632 * Make sure this matches with `TNodeType`
2633 */
2634function toTNodeTypeAsString(tNodeType) {
2635 let text = '';
2636 (tNodeType & 1 /* TNodeType.Text */) && (text += '|Text');
2637 (tNodeType & 2 /* TNodeType.Element */) && (text += '|Element');
2638 (tNodeType & 4 /* TNodeType.Container */) && (text += '|Container');
2639 (tNodeType & 8 /* TNodeType.ElementContainer */) && (text += '|ElementContainer');
2640 (tNodeType & 16 /* TNodeType.Projection */) && (text += '|Projection');
2641 (tNodeType & 32 /* TNodeType.Icu */) && (text += '|IcuContainer');
2642 (tNodeType & 64 /* TNodeType.Placeholder */) && (text += '|Placeholder');
2643 return text.length > 0 ? text.substring(1) : text;
2644}
2645// Note: This hack is necessary so we don't erroneously get a circular dependency
2646// failure based on types.
2647const unusedValueExportToPlacateAjd$1 = 1;
2648/**
2649 * Returns `true` if the `TNode` has a directive which has `@Input()` for `class` binding.
2650 *
2651 * ```
2652 * <div my-dir [class]="exp"></div>
2653 * ```
2654 * and
2655 * ```
2656 * @Directive({
2657 * })
2658 * class MyDirective {
2659 * @Input()
2660 * class: string;
2661 * }
2662 * ```
2663 *
2664 * In the above case it is necessary to write the reconciled styling information into the
2665 * directive's input.
2666 *
2667 * @param tNode
2668 */
2669function hasClassInput(tNode) {
2670 return (tNode.flags & 8 /* TNodeFlags.hasClassInput */) !== 0;
2671}
2672/**
2673 * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
2674 *
2675 * ```
2676 * <div my-dir [style]="exp"></div>
2677 * ```
2678 * and
2679 * ```
2680 * @Directive({
2681 * })
2682 * class MyDirective {
2683 * @Input()
2684 * class: string;
2685 * }
2686 * ```
2687 *
2688 * In the above case it is necessary to write the reconciled styling information into the
2689 * directive's input.
2690 *
2691 * @param tNode
2692 */
2693function hasStyleInput(tNode) {
2694 return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
2695}
2696
2697function assertTNodeType(tNode, expectedTypes, message) {
2698 assertDefined(tNode, 'should be called with a TNode');
2699 if ((tNode.type & expectedTypes) === 0) {
2700 throwError(message ||
2701 `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
2702 }
2703}
2704function assertPureTNodeType(type) {
2705 if (!(type === 2 /* TNodeType.Element */ || //
2706 type === 1 /* TNodeType.Text */ || //
2707 type === 4 /* TNodeType.Container */ || //
2708 type === 8 /* TNodeType.ElementContainer */ || //
2709 type === 32 /* TNodeType.Icu */ || //
2710 type === 16 /* TNodeType.Projection */ || //
2711 type === 64 /* TNodeType.Placeholder */)) {
2712 throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
2713 }
2714}
2715
2716/**
2717 * Assigns all attribute values to the provided element via the inferred renderer.
2718 *
2719 * This function accepts two forms of attribute entries:
2720 *
2721 * default: (key, value):
2722 * attrs = [key1, value1, key2, value2]
2723 *
2724 * namespaced: (NAMESPACE_MARKER, uri, name, value)
2725 * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
2726 *
2727 * The `attrs` array can contain a mix of both the default and namespaced entries.
2728 * The "default" values are set without a marker, but if the function comes across
2729 * a marker value then it will attempt to set a namespaced value. If the marker is
2730 * not of a namespaced value then the function will quit and return the index value
2731 * where it stopped during the iteration of the attrs array.
2732 *
2733 * See [AttributeMarker] to understand what the namespace marker value is.
2734 *
2735 * Note that this instruction does not support assigning style and class values to
2736 * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
2737 * are applied to an element.
2738 * @param renderer The renderer to be used
2739 * @param native The element that the attributes will be assigned to
2740 * @param attrs The attribute array of values that will be assigned to the element
2741 * @returns the index value that was last accessed in the attributes array
2742 */
2743function setUpAttributes(renderer, native, attrs) {
2744 let i = 0;
2745 while (i < attrs.length) {
2746 const value = attrs[i];
2747 if (typeof value === 'number') {
2748 // only namespaces are supported. Other value types (such as style/class
2749 // entries) are not supported in this function.
2750 if (value !== 0 /* AttributeMarker.NamespaceURI */) {
2751 break;
2752 }
2753 // we just landed on the marker value ... therefore
2754 // we should skip to the next entry
2755 i++;
2756 const namespaceURI = attrs[i++];
2757 const attrName = attrs[i++];
2758 const attrVal = attrs[i++];
2759 ngDevMode && ngDevMode.rendererSetAttribute++;
2760 renderer.setAttribute(native, attrName, attrVal, namespaceURI);
2761 }
2762 else {
2763 // attrName is string;
2764 const attrName = value;
2765 const attrVal = attrs[++i];
2766 // Standard attributes
2767 ngDevMode && ngDevMode.rendererSetAttribute++;
2768 if (isAnimationProp(attrName)) {
2769 renderer.setProperty(native, attrName, attrVal);
2770 }
2771 else {
2772 renderer.setAttribute(native, attrName, attrVal);
2773 }
2774 i++;
2775 }
2776 }
2777 // another piece of code may iterate over the same attributes array. Therefore
2778 // it may be helpful to return the exact spot where the attributes array exited
2779 // whether by running into an unsupported marker or if all the static values were
2780 // iterated over.
2781 return i;
2782}
2783/**
2784 * Test whether the given value is a marker that indicates that the following
2785 * attribute values in a `TAttributes` array are only the names of attributes,
2786 * and not name-value pairs.
2787 * @param marker The attribute marker to test.
2788 * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
2789 */
2790function isNameOnlyAttributeMarker(marker) {
2791 return marker === 3 /* AttributeMarker.Bindings */ || marker === 4 /* AttributeMarker.Template */ ||
2792 marker === 6 /* AttributeMarker.I18n */;
2793}
2794function isAnimationProp(name) {
2795 // Perf note: accessing charCodeAt to check for the first character of a string is faster as
2796 // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
2797 // charCodeAt doesn't allocate memory to return a substring.
2798 return name.charCodeAt(0) === 64 /* CharCode.AT_SIGN */;
2799}
2800/**
2801 * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
2802 *
2803 * This merge function keeps the order of attrs same.
2804 *
2805 * @param dst Location of where the merged `TAttributes` should end up.
2806 * @param src `TAttributes` which should be appended to `dst`
2807 */
2808function mergeHostAttrs(dst, src) {
2809 if (src === null || src.length === 0) {
2810 // do nothing
2811 }
2812 else if (dst === null || dst.length === 0) {
2813 // We have source, but dst is empty, just make a copy.
2814 dst = src.slice();
2815 }
2816 else {
2817 let srcMarker = -1 /* AttributeMarker.ImplicitAttributes */;
2818 for (let i = 0; i < src.length; i++) {
2819 const item = src[i];
2820 if (typeof item === 'number') {
2821 srcMarker = item;
2822 }
2823 else {
2824 if (srcMarker === 0 /* AttributeMarker.NamespaceURI */) {
2825 // Case where we need to consume `key1`, `key2`, `value` items.
2826 }
2827 else if (srcMarker === -1 /* AttributeMarker.ImplicitAttributes */ ||
2828 srcMarker === 2 /* AttributeMarker.Styles */) {
2829 // Case where we have to consume `key1` and `value` only.
2830 mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
2831 }
2832 else {
2833 // Case where we have to consume `key1` only.
2834 mergeHostAttribute(dst, srcMarker, item, null, null);
2835 }
2836 }
2837 }
2838 }
2839 return dst;
2840}
2841/**
2842 * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
2843 *
2844 * @param dst `TAttributes` to append to.
2845 * @param marker Region where the `key`/`value` should be added.
2846 * @param key1 Key to add to `TAttributes`
2847 * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
2848 * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
2849 */
2850function mergeHostAttribute(dst, marker, key1, key2, value) {
2851 let i = 0;
2852 // Assume that new markers will be inserted at the end.
2853 let markerInsertPosition = dst.length;
2854 // scan until correct type.
2855 if (marker === -1 /* AttributeMarker.ImplicitAttributes */) {
2856 markerInsertPosition = -1;
2857 }
2858 else {
2859 while (i < dst.length) {
2860 const dstValue = dst[i++];
2861 if (typeof dstValue === 'number') {
2862 if (dstValue === marker) {
2863 markerInsertPosition = -1;
2864 break;
2865 }
2866 else if (dstValue > marker) {
2867 // We need to save this as we want the markers to be inserted in specific order.
2868 markerInsertPosition = i - 1;
2869 break;
2870 }
2871 }
2872 }
2873 }
2874 // search until you find place of insertion
2875 while (i < dst.length) {
2876 const item = dst[i];
2877 if (typeof item === 'number') {
2878 // since `i` started as the index after the marker, we did not find it if we are at the next
2879 // marker
2880 break;
2881 }
2882 else if (item === key1) {
2883 // We already have same token
2884 if (key2 === null) {
2885 if (value !== null) {
2886 dst[i + 1] = value;
2887 }
2888 return;
2889 }
2890 else if (key2 === dst[i + 1]) {
2891 dst[i + 2] = value;
2892 return;
2893 }
2894 }
2895 // Increment counter.
2896 i++;
2897 if (key2 !== null)
2898 i++;
2899 if (value !== null)
2900 i++;
2901 }
2902 // insert at location.
2903 if (markerInsertPosition !== -1) {
2904 dst.splice(markerInsertPosition, 0, marker);
2905 i = markerInsertPosition + 1;
2906 }
2907 dst.splice(i++, 0, key1);
2908 if (key2 !== null) {
2909 dst.splice(i++, 0, key2);
2910 }
2911 if (value !== null) {
2912 dst.splice(i++, 0, value);
2913 }
2914}
2915
2916/// Parent Injector Utils ///////////////////////////////////////////////////////////////
2917function hasParentInjector(parentLocation) {
2918 return parentLocation !== NO_PARENT_INJECTOR;
2919}
2920function getParentInjectorIndex(parentLocation) {
2921 ngDevMode && assertNumber(parentLocation, 'Number expected');
2922 ngDevMode && assertNotEqual(parentLocation, -1, 'Not a valid state.');
2923 const parentInjectorIndex = parentLocation & 32767 /* RelativeInjectorLocationFlags.InjectorIndexMask */;
2924 ngDevMode &&
2925 assertGreaterThan(parentInjectorIndex, HEADER_OFFSET, 'Parent injector must be pointing past HEADER_OFFSET.');
2926 return parentLocation & 32767 /* RelativeInjectorLocationFlags.InjectorIndexMask */;
2927}
2928function getParentInjectorViewOffset(parentLocation) {
2929 return parentLocation >> 16 /* RelativeInjectorLocationFlags.ViewOffsetShift */;
2930}
2931/**
2932 * Unwraps a parent injector location number to find the view offset from the current injector,
2933 * then walks up the declaration view tree until the view is found that contains the parent
2934 * injector.
2935 *
2936 * @param location The location of the parent injector, which contains the view offset
2937 * @param startView The LView instance from which to start walking up the view tree
2938 * @returns The LView instance that contains the parent injector
2939 */
2940function getParentInjectorView(location, startView) {
2941 let viewOffset = getParentInjectorViewOffset(location);
2942 let parentView = startView;
2943 // For most cases, the parent injector can be found on the host node (e.g. for component
2944 // or container), but we must keep the loop here to support the rarer case of deeply nested
2945 // <ng-template> tags or inline views, where the parent injector might live many views
2946 // above the child injector.
2947 while (viewOffset > 0) {
2948 parentView = parentView[DECLARATION_VIEW];
2949 viewOffset--;
2950 }
2951 return parentView;
2952}
2953
2954/**
2955 * Defines if the call to `inject` should include `viewProviders` in its resolution.
2956 *
2957 * This is set to true when we try to instantiate a component. This value is reset in
2958 * `getNodeInjectable` to a value which matches the declaration location of the token about to be
2959 * instantiated. This is done so that if we are injecting a token which was declared outside of
2960 * `viewProviders` we don't accidentally pull `viewProviders` in.
2961 *
2962 * Example:
2963 *
2964 * ```
2965 * @Injectable()
2966 * class MyService {
2967 * constructor(public value: String) {}
2968 * }
2969 *
2970 * @Component({
2971 * providers: [
2972 * MyService,
2973 * {provide: String, value: 'providers' }
2974 * ]
2975 * viewProviders: [
2976 * {provide: String, value: 'viewProviders'}
2977 * ]
2978 * })
2979 * class MyComponent {
2980 * constructor(myService: MyService, value: String) {
2981 * // We expect that Component can see into `viewProviders`.
2982 * expect(value).toEqual('viewProviders');
2983 * // `MyService` was not declared in `viewProviders` hence it can't see it.
2984 * expect(myService.value).toEqual('providers');
2985 * }
2986 * }
2987 *
2988 * ```
2989 */
2990let includeViewProviders = true;
2991function setIncludeViewProviders(v) {
2992 const oldValue = includeViewProviders;
2993 includeViewProviders = v;
2994 return oldValue;
2995}
2996/**
2997 * The number of slots in each bloom filter (used by DI). The larger this number, the fewer
2998 * directives that will share slots, and thus, the fewer false positives when checking for
2999 * the existence of a directive.
3000 */
3001const BLOOM_SIZE = 256;
3002const BLOOM_MASK = BLOOM_SIZE - 1;
3003/**
3004 * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits,
3005 * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash
3006 * number.
3007 */
3008const BLOOM_BUCKET_BITS = 5;
3009/** Counter used to generate unique IDs for directives. */
3010let nextNgElementId = 0;
3011/** Value used when something wasn't found by an injector. */
3012const NOT_FOUND = {};
3013/**
3014 * Registers this directive as present in its node's injector by flipping the directive's
3015 * corresponding bit in the injector's bloom filter.
3016 *
3017 * @param injectorIndex The index of the node injector where this token should be registered
3018 * @param tView The TView for the injector's bloom filters
3019 * @param type The directive token to register
3020 */
3021function bloomAdd(injectorIndex, tView, type) {
3022 ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
3023 let id;
3024 if (typeof type === 'string') {
3025 id = type.charCodeAt(0) || 0;
3026 }
3027 else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
3028 id = type[NG_ELEMENT_ID];
3029 }
3030 // Set a unique ID on the directive type, so if something tries to inject the directive,
3031 // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
3032 if (id == null) {
3033 id = type[NG_ELEMENT_ID] = nextNgElementId++;
3034 }
3035 // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
3036 // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
3037 const bloomHash = id & BLOOM_MASK;
3038 // Create a mask that targets the specific bit associated with the directive.
3039 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
3040 // to bit positions 0 - 31 in a 32 bit integer.
3041 const mask = 1 << bloomHash;
3042 // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`.
3043 // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask
3044 // should be written to.
3045 tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask;
3046}
3047/**
3048 * Creates (or gets an existing) injector for a given element or container.
3049 *
3050 * @param tNode for which an injector should be retrieved / created.
3051 * @param lView View where the node is stored
3052 * @returns Node injector
3053 */
3054function getOrCreateNodeInjectorForNode(tNode, lView) {
3055 const existingInjectorIndex = getInjectorIndex(tNode, lView);
3056 if (existingInjectorIndex !== -1) {
3057 return existingInjectorIndex;
3058 }
3059 const tView = lView[TVIEW];
3060 if (tView.firstCreatePass) {
3061 tNode.injectorIndex = lView.length;
3062 insertBloom(tView.data, tNode); // foundation for node bloom
3063 insertBloom(lView, null); // foundation for cumulative bloom
3064 insertBloom(tView.blueprint, null);
3065 }
3066 const parentLoc = getParentInjectorLocation(tNode, lView);
3067 const injectorIndex = tNode.injectorIndex;
3068 // If a parent injector can't be found, its location is set to -1.
3069 // In that case, we don't need to set up a cumulative bloom
3070 if (hasParentInjector(parentLoc)) {
3071 const parentIndex = getParentInjectorIndex(parentLoc);
3072 const parentLView = getParentInjectorView(parentLoc, lView);
3073 const parentData = parentLView[TVIEW].data;
3074 // Creates a cumulative bloom filter that merges the parent's bloom filter
3075 // and its own cumulative bloom (which contains tokens for all ancestors)
3076 for (let i = 0; i < 8 /* NodeInjectorOffset.BLOOM_SIZE */; i++) {
3077 lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
3078 }
3079 }
3080 lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */] = parentLoc;
3081 return injectorIndex;
3082}
3083function insertBloom(arr, footer) {
3084 arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
3085}
3086function getInjectorIndex(tNode, lView) {
3087 if (tNode.injectorIndex === -1 ||
3088 // If the injector index is the same as its parent's injector index, then the index has been
3089 // copied down from the parent node. No injector has been created yet on this node.
3090 (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
3091 // After the first template pass, the injector index might exist but the parent values
3092 // might not have been calculated yet for this instance
3093 lView[tNode.injectorIndex + 8 /* NodeInjectorOffset.PARENT */] === null) {
3094 return -1;
3095 }
3096 else {
3097 ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
3098 return tNode.injectorIndex;
3099 }
3100}
3101/**
3102 * Finds the index of the parent injector, with a view offset if applicable. Used to set the
3103 * parent injector initially.
3104 *
3105 * @returns Returns a number that is the combination of the number of LViews that we have to go up
3106 * to find the LView containing the parent inject AND the index of the injector within that LView.
3107 */
3108function getParentInjectorLocation(tNode, lView) {
3109 if (tNode.parent && tNode.parent.injectorIndex !== -1) {
3110 // If we have a parent `TNode` and there is an injector associated with it we are done, because
3111 // the parent injector is within the current `LView`.
3112 return tNode.parent.injectorIndex; // ViewOffset is 0
3113 }
3114 // When parent injector location is computed it may be outside of the current view. (ie it could
3115 // be pointing to a declared parent location). This variable stores number of declaration parents
3116 // we need to walk up in order to find the parent injector location.
3117 let declarationViewOffset = 0;
3118 let parentTNode = null;
3119 let lViewCursor = lView;
3120 // The parent injector is not in the current `LView`. We will have to walk the declared parent
3121 // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
3122 // `NodeInjector`.
3123 while (lViewCursor !== null) {
3124 parentTNode = getTNodeFromLView(lViewCursor);
3125 if (parentTNode === null) {
3126 // If we have no parent, than we are done.
3127 return NO_PARENT_INJECTOR;
3128 }
3129 ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]);
3130 // Every iteration of the loop requires that we go to the declared parent.
3131 declarationViewOffset++;
3132 lViewCursor = lViewCursor[DECLARATION_VIEW];
3133 if (parentTNode.injectorIndex !== -1) {
3134 // We found a NodeInjector which points to something.
3135 return (parentTNode.injectorIndex |
3136 (declarationViewOffset << 16 /* RelativeInjectorLocationFlags.ViewOffsetShift */));
3137 }
3138 }
3139 return NO_PARENT_INJECTOR;
3140}
3141/**
3142 * Makes a type or an injection token public to the DI system by adding it to an
3143 * injector's bloom filter.
3144 *
3145 * @param di The node injector in which a directive will be added
3146 * @param token The type or the injection token to be made public
3147 */
3148function diPublicInInjector(injectorIndex, tView, token) {
3149 bloomAdd(injectorIndex, tView, token);
3150}
3151/**
3152 * Inject static attribute value into directive constructor.
3153 *
3154 * This method is used with `factory` functions which are generated as part of
3155 * `defineDirective` or `defineComponent`. The method retrieves the static value
3156 * of an attribute. (Dynamic attributes are not supported since they are not resolved
3157 * at the time of injection and can change over time.)
3158 *
3159 * # Example
3160 * Given:
3161 * ```
3162 * @Component(...)
3163 * class MyComponent {
3164 * constructor(@Attribute('title') title: string) { ... }
3165 * }
3166 * ```
3167 * When instantiated with
3168 * ```
3169 * <my-component title="Hello"></my-component>
3170 * ```
3171 *
3172 * Then factory method generated is:
3173 * ```
3174 * MyComponent.ɵcmp = defineComponent({
3175 * factory: () => new MyComponent(injectAttribute('title'))
3176 * ...
3177 * })
3178 * ```
3179 *
3180 * @publicApi
3181 */
3182function injectAttributeImpl(tNode, attrNameToInject) {
3183 ngDevMode && assertTNodeType(tNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */);
3184 ngDevMode && assertDefined(tNode, 'expecting tNode');
3185 if (attrNameToInject === 'class') {
3186 return tNode.classes;
3187 }
3188 if (attrNameToInject === 'style') {
3189 return tNode.styles;
3190 }
3191 const attrs = tNode.attrs;
3192 if (attrs) {
3193 const attrsLength = attrs.length;
3194 let i = 0;
3195 while (i < attrsLength) {
3196 const value = attrs[i];
3197 // If we hit a `Bindings` or `Template` marker then we are done.
3198 if (isNameOnlyAttributeMarker(value))
3199 break;
3200 // Skip namespaced attributes
3201 if (value === 0 /* AttributeMarker.NamespaceURI */) {
3202 // we skip the next two values
3203 // as namespaced attributes looks like
3204 // [..., AttributeMarker.NamespaceURI, 'http://someuri.com/test', 'test:exist',
3205 // 'existValue', ...]
3206 i = i + 2;
3207 }
3208 else if (typeof value === 'number') {
3209 // Skip to the first value of the marked attribute.
3210 i++;
3211 while (i < attrsLength && typeof attrs[i] === 'string') {
3212 i++;
3213 }
3214 }
3215 else if (value === attrNameToInject) {
3216 return attrs[i + 1];
3217 }
3218 else {
3219 i = i + 2;
3220 }
3221 }
3222 }
3223 return null;
3224}
3225function notFoundValueOrThrow(notFoundValue, token, flags) {
3226 if ((flags & InjectFlags.Optional) || notFoundValue !== undefined) {
3227 return notFoundValue;
3228 }
3229 else {
3230 throwProviderNotFoundError(token, 'NodeInjector');
3231 }
3232}
3233/**
3234 * Returns the value associated to the given token from the ModuleInjector or throws exception
3235 *
3236 * @param lView The `LView` that contains the `tNode`
3237 * @param token The token to look for
3238 * @param flags Injection flags
3239 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3240 * @returns the value from the injector or throws an exception
3241 */
3242function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) {
3243 if ((flags & InjectFlags.Optional) && notFoundValue === undefined) {
3244 // This must be set or the NullInjector will throw for optional deps
3245 notFoundValue = null;
3246 }
3247 if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
3248 const moduleInjector = lView[INJECTOR$1];
3249 // switch to `injectInjectorOnly` implementation for module injector, since module injector
3250 // should not have access to Component/Directive DI scope (that may happen through
3251 // `directiveInject` implementation)
3252 const previousInjectImplementation = setInjectImplementation(undefined);
3253 try {
3254 if (moduleInjector) {
3255 return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
3256 }
3257 else {
3258 return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
3259 }
3260 }
3261 finally {
3262 setInjectImplementation(previousInjectImplementation);
3263 }
3264 }
3265 return notFoundValueOrThrow(notFoundValue, token, flags);
3266}
3267/**
3268 * Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
3269 *
3270 * Look for the injector providing the token by walking up the node injector tree and then
3271 * the module injector tree.
3272 *
3273 * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom
3274 * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`)
3275 *
3276 * @param tNode The Node where the search for the injector should start
3277 * @param lView The `LView` that contains the `tNode`
3278 * @param token The token to look for
3279 * @param flags Injection flags
3280 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3281 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
3282 */
3283function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) {
3284 if (tNode !== null) {
3285 // If the view or any of its ancestors have an embedded
3286 // view injector, we have to look it up there first.
3287 if (lView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) {
3288 const embeddedInjectorValue = lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, NOT_FOUND);
3289 if (embeddedInjectorValue !== NOT_FOUND) {
3290 return embeddedInjectorValue;
3291 }
3292 }
3293 // Otherwise try the node injector.
3294 const value = lookupTokenUsingNodeInjector(tNode, lView, token, flags, NOT_FOUND);
3295 if (value !== NOT_FOUND) {
3296 return value;
3297 }
3298 }
3299 // Finally, fall back to the module injector.
3300 return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
3301}
3302/**
3303 * Returns the value associated to the given token from the node injector.
3304 *
3305 * @param tNode The Node where the search for the injector should start
3306 * @param lView The `LView` that contains the `tNode`
3307 * @param token The token to look for
3308 * @param flags Injection flags
3309 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3310 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
3311 */
3312function lookupTokenUsingNodeInjector(tNode, lView, token, flags, notFoundValue) {
3313 const bloomHash = bloomHashBitOrFactory(token);
3314 // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
3315 // so just call the factory function to create it.
3316 if (typeof bloomHash === 'function') {
3317 if (!enterDI(lView, tNode, flags)) {
3318 // Failed to enter DI, try module injector instead. If a token is injected with the @Host
3319 // flag, the module injector is not searched for that token in Ivy.
3320 return (flags & InjectFlags.Host) ?
3321 notFoundValueOrThrow(notFoundValue, token, flags) :
3322 lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
3323 }
3324 try {
3325 const value = bloomHash(flags);
3326 if (value == null && !(flags & InjectFlags.Optional)) {
3327 throwProviderNotFoundError(token);
3328 }
3329 else {
3330 return value;
3331 }
3332 }
3333 finally {
3334 leaveDI();
3335 }
3336 }
3337 else if (typeof bloomHash === 'number') {
3338 // A reference to the previous injector TView that was found while climbing the element
3339 // injector tree. This is used to know if viewProviders can be accessed on the current
3340 // injector.
3341 let previousTView = null;
3342 let injectorIndex = getInjectorIndex(tNode, lView);
3343 let parentLocation = NO_PARENT_INJECTOR;
3344 let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
3345 // If we should skip this injector, or if there is no injector on this node, start by
3346 // searching the parent injector.
3347 if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
3348 parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
3349 lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */];
3350 if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
3351 injectorIndex = -1;
3352 }
3353 else {
3354 previousTView = lView[TVIEW];
3355 injectorIndex = getParentInjectorIndex(parentLocation);
3356 lView = getParentInjectorView(parentLocation, lView);
3357 }
3358 }
3359 // Traverse up the injector tree until we find a potential match or until we know there
3360 // *isn't* a match.
3361 while (injectorIndex !== -1) {
3362 ngDevMode && assertNodeInjector(lView, injectorIndex);
3363 // Check the current injector. If it matches, see if it contains token.
3364 const tView = lView[TVIEW];
3365 ngDevMode &&
3366 assertTNodeForLView(tView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */], lView);
3367 if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
3368 // At this point, we have an injector which *may* contain the token, so we step through
3369 // the providers and directives associated with the injector's corresponding node to get
3370 // the instance.
3371 const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode);
3372 if (instance !== NOT_FOUND) {
3373 return instance;
3374 }
3375 }
3376 parentLocation = lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */];
3377 if (parentLocation !== NO_PARENT_INJECTOR &&
3378 shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */] === hostTElementNode) &&
3379 bloomHasToken(bloomHash, injectorIndex, lView)) {
3380 // The def wasn't found anywhere on this node, so it was a false positive.
3381 // Traverse up the tree and continue searching.
3382 previousTView = tView;
3383 injectorIndex = getParentInjectorIndex(parentLocation);
3384 lView = getParentInjectorView(parentLocation, lView);
3385 }
3386 else {
3387 // If we should not search parent OR If the ancestor bloom filter value does not have the
3388 // bit corresponding to the directive we can give up on traversing up to find the specific
3389 // injector.
3390 injectorIndex = -1;
3391 }
3392 }
3393 }
3394 return notFoundValue;
3395}
3396function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) {
3397 const currentTView = lView[TVIEW];
3398 const tNode = currentTView.data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
3399 // First, we need to determine if view providers can be accessed by the starting element.
3400 // There are two possibilities
3401 const canAccessViewProviders = previousTView == null ?
3402 // 1) This is the first invocation `previousTView == null` which means that we are at the
3403 // `TNode` of where injector is starting to look. In such a case the only time we are allowed
3404 // to look into the ViewProviders is if:
3405 // - we are on a component
3406 // - AND the injector set `includeViewProviders` to true (implying that the token can see
3407 // ViewProviders because it is the Component or a Service which itself was declared in
3408 // ViewProviders)
3409 (isComponentHost(tNode) && includeViewProviders) :
3410 // 2) `previousTView != null` which means that we are now walking across the parent nodes.
3411 // In such a case we are only allowed to look into the ViewProviders if:
3412 // - We just crossed from child View to Parent View `previousTView != currentTView`
3413 // - AND the parent TNode is an Element.
3414 // This means that we just came from the Component's View and therefore are allowed to see
3415 // into the ViewProviders.
3416 (previousTView != currentTView && ((tNode.type & 3 /* TNodeType.AnyRNode */) !== 0));
3417 // This special case happens when there is a @host on the inject and when we are searching
3418 // on the host element node.
3419 const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode;
3420 const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase);
3421 if (injectableIdx !== null) {
3422 return getNodeInjectable(lView, currentTView, injectableIdx, tNode);
3423 }
3424 else {
3425 return NOT_FOUND;
3426 }
3427}
3428/**
3429 * Searches for the given token among the node's directives and providers.
3430 *
3431 * @param tNode TNode on which directives are present.
3432 * @param tView The tView we are currently processing
3433 * @param token Provider token or type of a directive to look for.
3434 * @param canAccessViewProviders Whether view providers should be considered.
3435 * @param isHostSpecialCase Whether the host special case applies.
3436 * @returns Index of a found directive or provider, or null when none found.
3437 */
3438function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) {
3439 const nodeProviderIndexes = tNode.providerIndexes;
3440 const tInjectables = tView.data;
3441 const injectablesStart = nodeProviderIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */;
3442 const directivesStart = tNode.directiveStart;
3443 const directiveEnd = tNode.directiveEnd;
3444 const cptViewProvidersCount = nodeProviderIndexes >> 20 /* TNodeProviderIndexes.CptViewProvidersCountShift */;
3445 const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount;
3446 // When the host special case applies, only the viewProviders and the component are visible
3447 const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd;
3448 for (let i = startingIndex; i < endIndex; i++) {
3449 const providerTokenOrDef = tInjectables[i];
3450 if (i < directivesStart && token === providerTokenOrDef ||
3451 i >= directivesStart && providerTokenOrDef.type === token) {
3452 return i;
3453 }
3454 }
3455 if (isHostSpecialCase) {
3456 const dirDef = tInjectables[directivesStart];
3457 if (dirDef && isComponentDef(dirDef) && dirDef.type === token) {
3458 return directivesStart;
3459 }
3460 }
3461 return null;
3462}
3463/**
3464 * Retrieve or instantiate the injectable from the `LView` at particular `index`.
3465 *
3466 * This function checks to see if the value has already been instantiated and if so returns the
3467 * cached `injectable`. Otherwise if it detects that the value is still a factory it
3468 * instantiates the `injectable` and caches the value.
3469 */
3470function getNodeInjectable(lView, tView, index, tNode) {
3471 let value = lView[index];
3472 const tData = tView.data;
3473 if (isFactory(value)) {
3474 const factory = value;
3475 if (factory.resolving) {
3476 throwCyclicDependencyError(stringifyForError(tData[index]));
3477 }
3478 const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
3479 factory.resolving = true;
3480 const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
3481 const success = enterDI(lView, tNode, InjectFlags.Default);
3482 ngDevMode &&
3483 assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.');
3484 try {
3485 value = lView[index] = factory.factory(undefined, tData, lView, tNode);
3486 // This code path is hit for both directives and providers.
3487 // For perf reasons, we want to avoid searching for hooks on providers.
3488 // It does no harm to try (the hooks just won't exist), but the extra
3489 // checks are unnecessary and this is a hot path. So we check to see
3490 // if the index of the dependency is in the directive range for this
3491 // tNode. If it's not, we know it's a provider and skip hook registration.
3492 if (tView.firstCreatePass && index >= tNode.directiveStart) {
3493 ngDevMode && assertDirectiveDef(tData[index]);
3494 registerPreOrderHooks(index, tData[index], tView);
3495 }
3496 }
3497 finally {
3498 previousInjectImplementation !== null &&
3499 setInjectImplementation(previousInjectImplementation);
3500 setIncludeViewProviders(previousIncludeViewProviders);
3501 factory.resolving = false;
3502 leaveDI();
3503 }
3504 }
3505 return value;
3506}
3507/**
3508 * Returns the bit in an injector's bloom filter that should be used to determine whether or not
3509 * the directive might be provided by the injector.
3510 *
3511 * When a directive is public, it is added to the bloom filter and given a unique ID that can be
3512 * retrieved on the Type. When the directive isn't public or the token is not a directive `null`
3513 * is returned as the node injector can not possibly provide that token.
3514 *
3515 * @param token the injection token
3516 * @returns the matching bit to check in the bloom filter or `null` if the token is not known.
3517 * When the returned value is negative then it represents special values such as `Injector`.
3518 */
3519function bloomHashBitOrFactory(token) {
3520 ngDevMode && assertDefined(token, 'token must be defined');
3521 if (typeof token === 'string') {
3522 return token.charCodeAt(0) || 0;
3523 }
3524 const tokenId =
3525 // First check with `hasOwnProperty` so we don't get an inherited ID.
3526 token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined;
3527 // Negative token IDs are used for special objects such as `Injector`
3528 if (typeof tokenId === 'number') {
3529 if (tokenId >= 0) {
3530 return tokenId & BLOOM_MASK;
3531 }
3532 else {
3533 ngDevMode &&
3534 assertEqual(tokenId, -1 /* InjectorMarkers.Injector */, 'Expecting to get Special Injector Id');
3535 return createNodeInjector;
3536 }
3537 }
3538 else {
3539 return tokenId;
3540 }
3541}
3542function bloomHasToken(bloomHash, injectorIndex, injectorView) {
3543 // Create a mask that targets the specific bit associated with the directive we're looking for.
3544 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
3545 // to bit positions 0 - 31 in a 32 bit integer.
3546 const mask = 1 << bloomHash;
3547 // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of
3548 // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset
3549 // that should be used.
3550 const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)];
3551 // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
3552 // this injector is a potential match.
3553 return !!(value & mask);
3554}
3555/** Returns true if flags prevent parent injector from being searched for tokens */
3556function shouldSearchParent(flags, isFirstHostTNode) {
3557 return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode);
3558}
3559class NodeInjector {
3560 constructor(_tNode, _lView) {
3561 this._tNode = _tNode;
3562 this._lView = _lView;
3563 }
3564 get(token, notFoundValue, flags) {
3565 return getOrCreateInjectable(this._tNode, this._lView, token, convertToBitFlags(flags), notFoundValue);
3566 }
3567}
3568/** Creates a `NodeInjector` for the current node. */
3569function createNodeInjector() {
3570 return new NodeInjector(getCurrentTNode(), getLView());
3571}
3572/**
3573 * @codeGenApi
3574 */
3575function ɵɵgetInheritedFactory(type) {
3576 return noSideEffects(() => {
3577 const ownConstructor = type.prototype.constructor;
3578 const ownFactory = ownConstructor[NG_FACTORY_DEF] || getFactoryOf(ownConstructor);
3579 const objectPrototype = Object.prototype;
3580 let parent = Object.getPrototypeOf(type.prototype).constructor;
3581 // Go up the prototype until we hit `Object`.
3582 while (parent && parent !== objectPrototype) {
3583 const factory = parent[NG_FACTORY_DEF] || getFactoryOf(parent);
3584 // If we hit something that has a factory and the factory isn't the same as the type,
3585 // we've found the inherited factory. Note the check that the factory isn't the type's
3586 // own factory is redundant in most cases, but if the user has custom decorators on the
3587 // class, this lookup will start one level down in the prototype chain, causing us to
3588 // find the own factory first and potentially triggering an infinite loop downstream.
3589 if (factory && factory !== ownFactory) {
3590 return factory;
3591 }
3592 parent = Object.getPrototypeOf(parent);
3593 }
3594 // There is no factory defined. Either this was improper usage of inheritance
3595 // (no Angular decorator on the superclass) or there is no constructor at all
3596 // in the inheritance chain. Since the two cases cannot be distinguished, the
3597 // latter has to be assumed.
3598 return t => new t();
3599 });
3600}
3601function getFactoryOf(type) {
3602 if (isForwardRef(type)) {
3603 return () => {
3604 const factory = getFactoryOf(resolveForwardRef(type));
3605 return factory && factory();
3606 };
3607 }
3608 return getFactoryDef(type);
3609}
3610/**
3611 * Returns a value from the closest embedded or node injector.
3612 *
3613 * @param tNode The Node where the search for the injector should start
3614 * @param lView The `LView` that contains the `tNode`
3615 * @param token The token to look for
3616 * @param flags Injection flags
3617 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
3618 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
3619 */
3620function lookupTokenUsingEmbeddedInjector(tNode, lView, token, flags, notFoundValue) {
3621 let currentTNode = tNode;
3622 let currentLView = lView;
3623 // When an LView with an embedded view injector is inserted, it'll likely be interlaced with
3624 // nodes who may have injectors (e.g. node injector -> embedded view injector -> node injector).
3625 // Since the bloom filters for the node injectors have already been constructed and we don't
3626 // have a way of extracting the records from an injector, the only way to maintain the correct
3627 // hierarchy when resolving the value is to walk it node-by-node while attempting to resolve
3628 // the token at each level.
3629 while (currentTNode !== null && currentLView !== null &&
3630 (currentLView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */) &&
3631 !(currentLView[FLAGS] & 256 /* LViewFlags.IsRoot */)) {
3632 ngDevMode && assertTNodeForLView(currentTNode, currentLView);
3633 // Note that this lookup on the node injector is using the `Self` flag, because
3634 // we don't want the node injector to look at any parent injectors since we
3635 // may hit the embedded view injector first.
3636 const nodeInjectorValue = lookupTokenUsingNodeInjector(currentTNode, currentLView, token, flags | InjectFlags.Self, NOT_FOUND);
3637 if (nodeInjectorValue !== NOT_FOUND) {
3638 return nodeInjectorValue;
3639 }
3640 // Has an explicit type due to a TS bug: https://github.com/microsoft/TypeScript/issues/33191
3641 let parentTNode = currentTNode.parent;
3642 // `TNode.parent` includes the parent within the current view only. If it doesn't exist,
3643 // it means that we've hit the view boundary and we need to go up to the next view.
3644 if (!parentTNode) {
3645 // Before we go to the next LView, check if the token exists on the current embedded injector.
3646 const embeddedViewInjector = currentLView[EMBEDDED_VIEW_INJECTOR];
3647 if (embeddedViewInjector) {
3648 const embeddedViewInjectorValue = embeddedViewInjector.get(token, NOT_FOUND, flags);
3649 if (embeddedViewInjectorValue !== NOT_FOUND) {
3650 return embeddedViewInjectorValue;
3651 }
3652 }
3653 // Otherwise keep going up the tree.
3654 parentTNode = getTNodeFromLView(currentLView);
3655 currentLView = currentLView[DECLARATION_VIEW];
3656 }
3657 currentTNode = parentTNode;
3658 }
3659 return notFoundValue;
3660}
3661/** Gets the TNode associated with an LView inside of the declaration view. */
3662function getTNodeFromLView(lView) {
3663 const tView = lView[TVIEW];
3664 const tViewType = tView.type;
3665 // The parent pointer differs based on `TView.type`.
3666 if (tViewType === 2 /* TViewType.Embedded */) {
3667 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
3668 return tView.declTNode;
3669 }
3670 else if (tViewType === 1 /* TViewType.Component */) {
3671 // Components don't have `TView.declTNode` because each instance of component could be
3672 // inserted in different location, hence `TView.declTNode` is meaningless.
3673 return lView[T_HOST];
3674 }
3675 return null;
3676}
3677
3678/**
3679 * Facade for the attribute injection from DI.
3680 *
3681 * @codeGenApi
3682 */
3683function ɵɵinjectAttribute(attrNameToInject) {
3684 return injectAttributeImpl(getCurrentTNode(), attrNameToInject);
3685}
3686
3687const ANNOTATIONS = '__annotations__';
3688const PARAMETERS = '__parameters__';
3689const PROP_METADATA = '__prop__metadata__';
3690/**
3691 * @suppress {globalThis}
3692 */
3693function makeDecorator(name, props, parentClass, additionalProcessing, typeFn) {
3694 return noSideEffects(() => {
3695 const metaCtor = makeMetadataCtor(props);
3696 function DecoratorFactory(...args) {
3697 if (this instanceof DecoratorFactory) {
3698 metaCtor.call(this, ...args);
3699 return this;
3700 }
3701 const annotationInstance = new DecoratorFactory(...args);
3702 return function TypeDecorator(cls) {
3703 if (typeFn)
3704 typeFn(cls, ...args);
3705 // Use of Object.defineProperty is important since it creates non-enumerable property which
3706 // prevents the property is copied during subclassing.
3707 const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
3708 cls[ANNOTATIONS] :
3709 Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
3710 annotations.push(annotationInstance);
3711 if (additionalProcessing)
3712 additionalProcessing(cls);
3713 return cls;
3714 };
3715 }
3716 if (parentClass) {
3717 DecoratorFactory.prototype = Object.create(parentClass.prototype);
3718 }
3719 DecoratorFactory.prototype.ngMetadataName = name;
3720 DecoratorFactory.annotationCls = DecoratorFactory;
3721 return DecoratorFactory;
3722 });
3723}
3724function makeMetadataCtor(props) {
3725 return function ctor(...args) {
3726 if (props) {
3727 const values = props(...args);
3728 for (const propName in values) {
3729 this[propName] = values[propName];
3730 }
3731 }
3732 };
3733}
3734function makeParamDecorator(name, props, parentClass) {
3735 return noSideEffects(() => {
3736 const metaCtor = makeMetadataCtor(props);
3737 function ParamDecoratorFactory(...args) {
3738 if (this instanceof ParamDecoratorFactory) {
3739 metaCtor.apply(this, args);
3740 return this;
3741 }
3742 const annotationInstance = new ParamDecoratorFactory(...args);
3743 ParamDecorator.annotation = annotationInstance;
3744 return ParamDecorator;
3745 function ParamDecorator(cls, unusedKey, index) {
3746 // Use of Object.defineProperty is important since it creates non-enumerable property which
3747 // prevents the property is copied during subclassing.
3748 const parameters = cls.hasOwnProperty(PARAMETERS) ?
3749 cls[PARAMETERS] :
3750 Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS];
3751 // there might be gaps if some in between parameters do not have annotations.
3752 // we pad with nulls.
3753 while (parameters.length <= index) {
3754 parameters.push(null);
3755 }
3756 (parameters[index] = parameters[index] || []).push(annotationInstance);
3757 return cls;
3758 }
3759 }
3760 if (parentClass) {
3761 ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
3762 }
3763 ParamDecoratorFactory.prototype.ngMetadataName = name;
3764 ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
3765 return ParamDecoratorFactory;
3766 });
3767}
3768function makePropDecorator(name, props, parentClass, additionalProcessing) {
3769 return noSideEffects(() => {
3770 const metaCtor = makeMetadataCtor(props);
3771 function PropDecoratorFactory(...args) {
3772 if (this instanceof PropDecoratorFactory) {
3773 metaCtor.apply(this, args);
3774 return this;
3775 }
3776 const decoratorInstance = new PropDecoratorFactory(...args);
3777 function PropDecorator(target, name) {
3778 const constructor = target.constructor;
3779 // Use of Object.defineProperty is important because it creates a non-enumerable property
3780 // which prevents the property from being copied during subclassing.
3781 const meta = constructor.hasOwnProperty(PROP_METADATA) ?
3782 constructor[PROP_METADATA] :
3783 Object.defineProperty(constructor, PROP_METADATA, { value: {} })[PROP_METADATA];
3784 meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
3785 meta[name].unshift(decoratorInstance);
3786 if (additionalProcessing)
3787 additionalProcessing(target, name, ...args);
3788 }
3789 return PropDecorator;
3790 }
3791 if (parentClass) {
3792 PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
3793 }
3794 PropDecoratorFactory.prototype.ngMetadataName = name;
3795 PropDecoratorFactory.annotationCls = PropDecoratorFactory;
3796 return PropDecoratorFactory;
3797 });
3798}
3799
3800/**
3801 * Attribute decorator and metadata.
3802 *
3803 * @Annotation
3804 * @publicApi
3805 */
3806const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName) }));
3807
3808/**
3809 * Creates a token that can be used in a DI Provider.
3810 *
3811 * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
3812 * runtime representation) such as when injecting an interface, callable type, array or
3813 * parameterized type.
3814 *
3815 * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
3816 * the `Injector`. This provides an additional level of type safety.
3817 *
3818 * ```
3819 * interface MyInterface {...}
3820 * const myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
3821 * // myInterface is inferred to be MyInterface.
3822 * ```
3823 *
3824 * When creating an `InjectionToken`, you can optionally specify a factory function which returns
3825 * (possibly by creating) a default value of the parameterized type `T`. This sets up the
3826 * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
3827 * application's root injector. If the factory function, which takes zero arguments, needs to inject
3828 * dependencies, it can do so using the `inject` function.
3829 * As you can see in the Tree-shakable InjectionToken example below.
3830 *
3831 * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
3832 * overrides the above behavior and marks the token as belonging to a particular `@NgModule` (note:
3833 * this option is now deprecated). As mentioned above, `'root'` is the default value for
3834 * `providedIn`.
3835 *
3836 * The `providedIn: NgModule` and `providedIn: 'any'` options are deprecated.
3837 *
3838 * @usageNotes
3839 * ### Basic Examples
3840 *
3841 * ### Plain InjectionToken
3842 *
3843 * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
3844 *
3845 * ### Tree-shakable InjectionToken
3846 *
3847 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
3848 *
3849 *
3850 * @publicApi
3851 */
3852class InjectionToken {
3853 /**
3854 * @param _desc Description for the token,
3855 * used only for debugging purposes,
3856 * it should but does not need to be unique
3857 * @param options Options for the token's usage, as described above
3858 */
3859 constructor(_desc, options) {
3860 this._desc = _desc;
3861 /** @internal */
3862 this.ngMetadataName = 'InjectionToken';
3863 this.ɵprov = undefined;
3864 if (typeof options == 'number') {
3865 (typeof ngDevMode === 'undefined' || ngDevMode) &&
3866 assertLessThan(options, 0, 'Only negative numbers are supported here');
3867 // This is a special hack to assign __NG_ELEMENT_ID__ to this instance.
3868 // See `InjectorMarkers`
3869 this.__NG_ELEMENT_ID__ = options;
3870 }
3871 else if (options !== undefined) {
3872 this.ɵprov = ɵɵdefineInjectable({
3873 token: this,
3874 providedIn: options.providedIn || 'root',
3875 factory: options.factory,
3876 });
3877 }
3878 }
3879 /**
3880 * @internal
3881 */
3882 get multi() {
3883 return this;
3884 }
3885 toString() {
3886 return `InjectionToken ${this._desc}`;
3887 }
3888}
3889
3890/**
3891 * A DI token that you can use to create a virtual [provider](guide/glossary#provider)
3892 * that will populate the `entryComponents` field of components and NgModules
3893 * based on its `useValue` property value.
3894 * All components that are referenced in the `useValue` value (either directly
3895 * or in a nested array or map) are added to the `entryComponents` property.
3896 *
3897 * @usageNotes
3898 *
3899 * The following example shows how the router can populate the `entryComponents`
3900 * field of an NgModule based on a router configuration that refers
3901 * to components.
3902 *
3903 * ```typescript
3904 * // helper function inside the router
3905 * function provideRoutes(routes) {
3906 * return [
3907 * {provide: ROUTES, useValue: routes},
3908 * {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: routes, multi: true}
3909 * ];
3910 * }
3911 *
3912 * // user code
3913 * let routes = [
3914 * {path: '/root', component: RootComp},
3915 * {path: '/teams', component: TeamsComp}
3916 * ];
3917 *
3918 * @NgModule({
3919 * providers: [provideRoutes(routes)]
3920 * })
3921 * class ModuleWithRoutes {}
3922 * ```
3923 *
3924 * @publicApi
3925 * @deprecated Since 9.0.0. With Ivy, this property is no longer necessary.
3926 */
3927const ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForEntryComponents');
3928// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
3929// explicitly set.
3930const emitDistinctChangesOnlyDefaultValue = true;
3931/**
3932 * Base class for query metadata.
3933 *
3934 * @see `ContentChildren`.
3935 * @see `ContentChild`.
3936 * @see `ViewChildren`.
3937 * @see `ViewChild`.
3938 *
3939 * @publicApi
3940 */
3941class Query {
3942}
3943/**
3944 * ContentChildren decorator and metadata.
3945 *
3946 *
3947 * @Annotation
3948 * @publicApi
3949 */
3950const ContentChildren = makePropDecorator('ContentChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)), Query);
3951/**
3952 * ContentChild decorator and metadata.
3953 *
3954 *
3955 * @Annotation
3956 *
3957 * @publicApi
3958 */
3959const ContentChild = makePropDecorator('ContentChild', (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data)), Query);
3960/**
3961 * ViewChildren decorator and metadata.
3962 *
3963 * @Annotation
3964 * @publicApi
3965 */
3966const ViewChildren = makePropDecorator('ViewChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)), Query);
3967/**
3968 * ViewChild decorator and metadata.
3969 *
3970 * @Annotation
3971 * @publicApi
3972 */
3973const ViewChild = makePropDecorator('ViewChild', (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data)), Query);
3974
3975var FactoryTarget;
3976(function (FactoryTarget) {
3977 FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
3978 FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
3979 FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
3980 FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
3981 FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
3982})(FactoryTarget || (FactoryTarget = {}));
3983var R3TemplateDependencyKind;
3984(function (R3TemplateDependencyKind) {
3985 R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive";
3986 R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe";
3987 R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule";
3988})(R3TemplateDependencyKind || (R3TemplateDependencyKind = {}));
3989var ViewEncapsulation;
3990(function (ViewEncapsulation) {
3991 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
3992 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
3993 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
3994 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
3995})(ViewEncapsulation || (ViewEncapsulation = {}));
3996
3997function getCompilerFacade(request) {
3998 const globalNg = _global['ng'];
3999 if (globalNg && globalNg.ɵcompilerFacade) {
4000 return globalNg.ɵcompilerFacade;
4001 }
4002 if (typeof ngDevMode === 'undefined' || ngDevMode) {
4003 // Log the type as an error so that a developer can easily navigate to the type from the
4004 // console.
4005 console.error(`JIT compilation failed for ${request.kind}`, request.type);
4006 let message = `The ${request.kind} '${request
4007 .type.name}' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.\n\n`;
4008 if (request.usage === 1 /* JitCompilerUsage.PartialDeclaration */) {
4009 message += `The ${request.kind} is part of a library that has been partially compiled.\n`;
4010 message +=
4011 `However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.\n`;
4012 message += '\n';
4013 message +=
4014 `Ideally, the library is processed using the Angular Linker to become fully AOT compiled.\n`;
4015 }
4016 else {
4017 message +=
4018 `JIT compilation is discouraged for production use-cases! Consider using AOT mode instead.\n`;
4019 }
4020 message +=
4021 `Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',\n`;
4022 message +=
4023 `or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`;
4024 throw new Error(message);
4025 }
4026 else {
4027 throw new Error('JIT compiler unavailable');
4028 }
4029}
4030
4031/**
4032 * @description
4033 *
4034 * Represents a type that a Component or other object is instances of.
4035 *
4036 * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is represented by
4037 * the `MyCustomComponent` constructor function.
4038 *
4039 * @publicApi
4040 */
4041const Type = Function;
4042function isType(v) {
4043 return typeof v === 'function';
4044}
4045
4046/**
4047 * Determines if the contents of two arrays is identical
4048 *
4049 * @param a first array
4050 * @param b second array
4051 * @param identityAccessor Optional function for extracting stable object identity from a value in
4052 * the array.
4053 */
4054function arrayEquals(a, b, identityAccessor) {
4055 if (a.length !== b.length)
4056 return false;
4057 for (let i = 0; i < a.length; i++) {
4058 let valueA = a[i];
4059 let valueB = b[i];
4060 if (identityAccessor) {
4061 valueA = identityAccessor(valueA);
4062 valueB = identityAccessor(valueB);
4063 }
4064 if (valueB !== valueA) {
4065 return false;
4066 }
4067 }
4068 return true;
4069}
4070/**
4071 * Flattens an array.
4072 */
4073function flatten(list) {
4074 return list.flat(Number.POSITIVE_INFINITY);
4075}
4076function deepForEach(input, fn) {
4077 input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value));
4078}
4079function addToArray(arr, index, value) {
4080 // perf: array.push is faster than array.splice!
4081 if (index >= arr.length) {
4082 arr.push(value);
4083 }
4084 else {
4085 arr.splice(index, 0, value);
4086 }
4087}
4088function removeFromArray(arr, index) {
4089 // perf: array.pop is faster than array.splice!
4090 if (index >= arr.length - 1) {
4091 return arr.pop();
4092 }
4093 else {
4094 return arr.splice(index, 1)[0];
4095 }
4096}
4097function newArray(size, value) {
4098 const list = [];
4099 for (let i = 0; i < size; i++) {
4100 list.push(value);
4101 }
4102 return list;
4103}
4104/**
4105 * Remove item from array (Same as `Array.splice()` but faster.)
4106 *
4107 * `Array.splice()` is not as fast because it has to allocate an array for the elements which were
4108 * removed. This causes memory pressure and slows down code when most of the time we don't
4109 * care about the deleted items array.
4110 *
4111 * https://jsperf.com/fast-array-splice (About 20x faster)
4112 *
4113 * @param array Array to splice
4114 * @param index Index of element in array to remove.
4115 * @param count Number of items to remove.
4116 */
4117function arraySplice(array, index, count) {
4118 const length = array.length - count;
4119 while (index < length) {
4120 array[index] = array[index + count];
4121 index++;
4122 }
4123 while (count--) {
4124 array.pop(); // shrink the array
4125 }
4126}
4127/**
4128 * Same as `Array.splice(index, 0, value)` but faster.
4129 *
4130 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
4131 * removed. This causes memory pressure and slows down code when most of the time we don't
4132 * care about the deleted items array.
4133 *
4134 * @param array Array to splice.
4135 * @param index Index in array where the `value` should be added.
4136 * @param value Value to add to array.
4137 */
4138function arrayInsert(array, index, value) {
4139 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
4140 let end = array.length;
4141 while (end > index) {
4142 const previousEnd = end - 1;
4143 array[end] = array[previousEnd];
4144 end = previousEnd;
4145 }
4146 array[index] = value;
4147}
4148/**
4149 * Same as `Array.splice2(index, 0, value1, value2)` but faster.
4150 *
4151 * `Array.splice()` is not fast because it has to allocate an array for the elements which were
4152 * removed. This causes memory pressure and slows down code when most of the time we don't
4153 * care about the deleted items array.
4154 *
4155 * @param array Array to splice.
4156 * @param index Index in array where the `value` should be added.
4157 * @param value1 Value to add to array.
4158 * @param value2 Value to add to array.
4159 */
4160function arrayInsert2(array, index, value1, value2) {
4161 ngDevMode && assertLessThanOrEqual(index, array.length, 'Can\'t insert past array end.');
4162 let end = array.length;
4163 if (end == index) {
4164 // inserting at the end.
4165 array.push(value1, value2);
4166 }
4167 else if (end === 1) {
4168 // corner case when we have less items in array than we have items to insert.
4169 array.push(value2, array[0]);
4170 array[0] = value1;
4171 }
4172 else {
4173 end--;
4174 array.push(array[end - 1], array[end]);
4175 while (end > index) {
4176 const previousEnd = end - 2;
4177 array[end] = array[previousEnd];
4178 end--;
4179 }
4180 array[index] = value1;
4181 array[index + 1] = value2;
4182 }
4183}
4184/**
4185 * Get an index of an `value` in a sorted `array`.
4186 *
4187 * NOTE:
4188 * - This uses binary search algorithm for fast removals.
4189 *
4190 * @param array A sorted array to binary search.
4191 * @param value The value to look for.
4192 * @returns index of the value.
4193 * - positive index if value found.
4194 * - negative index if value not found. (`~index` to get the value where it should have been
4195 * located)
4196 */
4197function arrayIndexOfSorted(array, value) {
4198 return _arrayIndexOfSorted(array, value, 0);
4199}
4200/**
4201 * Set a `value` for a `key`.
4202 *
4203 * @param keyValueArray to modify.
4204 * @param key The key to locate or create.
4205 * @param value The value to set for a `key`.
4206 * @returns index (always even) of where the value vas set.
4207 */
4208function keyValueArraySet(keyValueArray, key, value) {
4209 let index = keyValueArrayIndexOf(keyValueArray, key);
4210 if (index >= 0) {
4211 // if we found it set it.
4212 keyValueArray[index | 1] = value;
4213 }
4214 else {
4215 index = ~index;
4216 arrayInsert2(keyValueArray, index, key, value);
4217 }
4218 return index;
4219}
4220/**
4221 * Retrieve a `value` for a `key` (on `undefined` if not found.)
4222 *
4223 * @param keyValueArray to search.
4224 * @param key The key to locate.
4225 * @return The `value` stored at the `key` location or `undefined if not found.
4226 */
4227function keyValueArrayGet(keyValueArray, key) {
4228 const index = keyValueArrayIndexOf(keyValueArray, key);
4229 if (index >= 0) {
4230 // if we found it retrieve it.
4231 return keyValueArray[index | 1];
4232 }
4233 return undefined;
4234}
4235/**
4236 * Retrieve a `key` index value in the array or `-1` if not found.
4237 *
4238 * @param keyValueArray to search.
4239 * @param key The key to locate.
4240 * @returns index of where the key is (or should have been.)
4241 * - positive (even) index if key found.
4242 * - negative index if key not found. (`~index` (even) to get the index where it should have
4243 * been inserted.)
4244 */
4245function keyValueArrayIndexOf(keyValueArray, key) {
4246 return _arrayIndexOfSorted(keyValueArray, key, 1);
4247}
4248/**
4249 * Delete a `key` (and `value`) from the `KeyValueArray`.
4250 *
4251 * @param keyValueArray to modify.
4252 * @param key The key to locate or delete (if exist).
4253 * @returns index of where the key was (or should have been.)
4254 * - positive (even) index if key found and deleted.
4255 * - negative index if key not found. (`~index` (even) to get the index where it should have
4256 * been.)
4257 */
4258function keyValueArrayDelete(keyValueArray, key) {
4259 const index = keyValueArrayIndexOf(keyValueArray, key);
4260 if (index >= 0) {
4261 // if we found it remove it.
4262 arraySplice(keyValueArray, index, 2);
4263 }
4264 return index;
4265}
4266/**
4267 * INTERNAL: Get an index of an `value` in a sorted `array` by grouping search by `shift`.
4268 *
4269 * NOTE:
4270 * - This uses binary search algorithm for fast removals.
4271 *
4272 * @param array A sorted array to binary search.
4273 * @param value The value to look for.
4274 * @param shift grouping shift.
4275 * - `0` means look at every location
4276 * - `1` means only look at every other (even) location (the odd locations are to be ignored as
4277 * they are values.)
4278 * @returns index of the value.
4279 * - positive index if value found.
4280 * - negative index if value not found. (`~index` to get the value where it should have been
4281 * inserted)
4282 */
4283function _arrayIndexOfSorted(array, value, shift) {
4284 ngDevMode && assertEqual(Array.isArray(array), true, 'Expecting an array');
4285 let start = 0;
4286 let end = array.length >> shift;
4287 while (end !== start) {
4288 const middle = start + ((end - start) >> 1); // find the middle.
4289 const current = array[middle << shift];
4290 if (value === current) {
4291 return (middle << shift);
4292 }
4293 else if (current > value) {
4294 end = middle;
4295 }
4296 else {
4297 start = middle + 1; // We already searched middle so make it non-inclusive by adding 1
4298 }
4299 }
4300 return ~(end << shift);
4301}
4302
4303/*
4304 * #########################
4305 * Attention: These Regular expressions have to hold even if the code is minified!
4306 * ##########################
4307 */
4308/**
4309 * Regular expression that detects pass-through constructors for ES5 output. This Regex
4310 * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
4311 * it intends to capture the pattern where existing constructors have been downleveled from
4312 * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
4313 *
4314 * ```
4315 * function MyClass() {
4316 * var _this = _super.apply(this, arguments) || this;
4317 * ```
4318 *
4319 * downleveled to ES5 with `downlevelIteration` for TypeScript < 4.2:
4320 * ```
4321 * function MyClass() {
4322 * var _this = _super.apply(this, __spread(arguments)) || this;
4323 * ```
4324 *
4325 * or downleveled to ES5 with `downlevelIteration` for TypeScript >= 4.2:
4326 * ```
4327 * function MyClass() {
4328 * var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
4329 * ```
4330 *
4331 * More details can be found in: https://github.com/angular/angular/issues/38453.
4332 */
4333const ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|(?:[^()]+\(\[\],)?[^()]+\(arguments\).*)\)/;
4334/** Regular expression that detects ES2015 classes which extend from other classes. */
4335const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
4336/**
4337 * Regular expression that detects ES2015 classes which extend from other classes and
4338 * have an explicit constructor defined.
4339 */
4340const ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
4341/**
4342 * Regular expression that detects ES2015 classes which extend from other classes
4343 * and inherit a constructor.
4344 */
4345const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{[^}]*super\(\.\.\.arguments\)/;
4346/**
4347 * Determine whether a stringified type is a class which delegates its constructor
4348 * to its parent.
4349 *
4350 * This is not trivial since compiled code can actually contain a constructor function
4351 * even if the original source code did not. For instance, when the child class contains
4352 * an initialized instance property.
4353 */
4354function isDelegateCtor(typeStr) {
4355 return ES5_DELEGATE_CTOR.test(typeStr) ||
4356 ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
4357 (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
4358}
4359class ReflectionCapabilities {
4360 constructor(reflect) {
4361 this._reflect = reflect || _global['Reflect'];
4362 }
4363 factory(t) {
4364 return (...args) => new t(...args);
4365 }
4366 /** @internal */
4367 _zipTypesAndAnnotations(paramTypes, paramAnnotations) {
4368 let result;
4369 if (typeof paramTypes === 'undefined') {
4370 result = newArray(paramAnnotations.length);
4371 }
4372 else {
4373 result = newArray(paramTypes.length);
4374 }
4375 for (let i = 0; i < result.length; i++) {
4376 // TS outputs Object for parameters without types, while Traceur omits
4377 // the annotations. For now we preserve the Traceur behavior to aid
4378 // migration, but this can be revisited.
4379 if (typeof paramTypes === 'undefined') {
4380 result[i] = [];
4381 }
4382 else if (paramTypes[i] && paramTypes[i] != Object) {
4383 result[i] = [paramTypes[i]];
4384 }
4385 else {
4386 result[i] = [];
4387 }
4388 if (paramAnnotations && paramAnnotations[i] != null) {
4389 result[i] = result[i].concat(paramAnnotations[i]);
4390 }
4391 }
4392 return result;
4393 }
4394 _ownParameters(type, parentCtor) {
4395 const typeStr = type.toString();
4396 // If we have no decorators, we only have function.length as metadata.
4397 // In that case, to detect whether a child class declared an own constructor or not,
4398 // we need to look inside of that constructor to check whether it is
4399 // just calling the parent.
4400 // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
4401 // that sets 'design:paramtypes' to []
4402 // if a class inherits from another class but has no ctor declared itself.
4403 if (isDelegateCtor(typeStr)) {
4404 return null;
4405 }
4406 // Prefer the direct API.
4407 if (type.parameters && type.parameters !== parentCtor.parameters) {
4408 return type.parameters;
4409 }
4410 // API of tsickle for lowering decorators to properties on the class.
4411 const tsickleCtorParams = type.ctorParameters;
4412 if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
4413 // Newer tsickle uses a function closure
4414 // Retain the non-function case for compatibility with older tsickle
4415 const ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
4416 const paramTypes = ctorParameters.map((ctorParam) => ctorParam && ctorParam.type);
4417 const paramAnnotations = ctorParameters.map((ctorParam) => ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
4418 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
4419 }
4420 // API for metadata created by invoking the decorators.
4421 const paramAnnotations = type.hasOwnProperty(PARAMETERS) && type[PARAMETERS];
4422 const paramTypes = this._reflect && this._reflect.getOwnMetadata &&
4423 this._reflect.getOwnMetadata('design:paramtypes', type);
4424 if (paramTypes || paramAnnotations) {
4425 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
4426 }
4427 // If a class has no decorators, at least create metadata
4428 // based on function.length.
4429 // Note: We know that this is a real constructor as we checked
4430 // the content of the constructor above.
4431 return newArray(type.length);
4432 }
4433 parameters(type) {
4434 // Note: only report metadata if we have at least one class decorator
4435 // to stay in sync with the static reflector.
4436 if (!isType(type)) {
4437 return [];
4438 }
4439 const parentCtor = getParentCtor(type);
4440 let parameters = this._ownParameters(type, parentCtor);
4441 if (!parameters && parentCtor !== Object) {
4442 parameters = this.parameters(parentCtor);
4443 }
4444 return parameters || [];
4445 }
4446 _ownAnnotations(typeOrFunc, parentCtor) {
4447 // Prefer the direct API.
4448 if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
4449 let annotations = typeOrFunc.annotations;
4450 if (typeof annotations === 'function' && annotations.annotations) {
4451 annotations = annotations.annotations;
4452 }
4453 return annotations;
4454 }
4455 // API of tsickle for lowering decorators to properties on the class.
4456 if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) {
4457 return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators);
4458 }
4459 // API for metadata created by invoking the decorators.
4460 if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
4461 return typeOrFunc[ANNOTATIONS];
4462 }
4463 return null;
4464 }
4465 annotations(typeOrFunc) {
4466 if (!isType(typeOrFunc)) {
4467 return [];
4468 }
4469 const parentCtor = getParentCtor(typeOrFunc);
4470 const ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
4471 const parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
4472 return parentAnnotations.concat(ownAnnotations);
4473 }
4474 _ownPropMetadata(typeOrFunc, parentCtor) {
4475 // Prefer the direct API.
4476 if (typeOrFunc.propMetadata &&
4477 typeOrFunc.propMetadata !== parentCtor.propMetadata) {
4478 let propMetadata = typeOrFunc.propMetadata;
4479 if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
4480 propMetadata = propMetadata.propMetadata;
4481 }
4482 return propMetadata;
4483 }
4484 // API of tsickle for lowering decorators to properties on the class.
4485 if (typeOrFunc.propDecorators &&
4486 typeOrFunc.propDecorators !== parentCtor.propDecorators) {
4487 const propDecorators = typeOrFunc.propDecorators;
4488 const propMetadata = {};
4489 Object.keys(propDecorators).forEach(prop => {
4490 propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
4491 });
4492 return propMetadata;
4493 }
4494 // API for metadata created by invoking the decorators.
4495 if (typeOrFunc.hasOwnProperty(PROP_METADATA)) {
4496 return typeOrFunc[PROP_METADATA];
4497 }
4498 return null;
4499 }
4500 propMetadata(typeOrFunc) {
4501 if (!isType(typeOrFunc)) {
4502 return {};
4503 }
4504 const parentCtor = getParentCtor(typeOrFunc);
4505 const propMetadata = {};
4506 if (parentCtor !== Object) {
4507 const parentPropMetadata = this.propMetadata(parentCtor);
4508 Object.keys(parentPropMetadata).forEach((propName) => {
4509 propMetadata[propName] = parentPropMetadata[propName];
4510 });
4511 }
4512 const ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
4513 if (ownPropMetadata) {
4514 Object.keys(ownPropMetadata).forEach((propName) => {
4515 const decorators = [];
4516 if (propMetadata.hasOwnProperty(propName)) {
4517 decorators.push(...propMetadata[propName]);
4518 }
4519 decorators.push(...ownPropMetadata[propName]);
4520 propMetadata[propName] = decorators;
4521 });
4522 }
4523 return propMetadata;
4524 }
4525 ownPropMetadata(typeOrFunc) {
4526 if (!isType(typeOrFunc)) {
4527 return {};
4528 }
4529 return this._ownPropMetadata(typeOrFunc, getParentCtor(typeOrFunc)) || {};
4530 }
4531 hasLifecycleHook(type, lcProperty) {
4532 return type instanceof Type && lcProperty in type.prototype;
4533 }
4534}
4535function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
4536 if (!decoratorInvocations) {
4537 return [];
4538 }
4539 return decoratorInvocations.map(decoratorInvocation => {
4540 const decoratorType = decoratorInvocation.type;
4541 const annotationCls = decoratorType.annotationCls;
4542 const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
4543 return new annotationCls(...annotationArgs);
4544 });
4545}
4546function getParentCtor(ctor) {
4547 const parentProto = ctor.prototype ? Object.getPrototypeOf(ctor.prototype) : null;
4548 const parentCtor = parentProto ? parentProto.constructor : null;
4549 // Note: We always use `Object` as the null value
4550 // to simplify checking later on.
4551 return parentCtor || Object;
4552}
4553
4554/**
4555 * Inject decorator and metadata.
4556 *
4557 * @Annotation
4558 * @publicApi
4559 */
4560const Inject = attachInjectFlag(
4561// Disable tslint because `DecoratorFlags` is a const enum which gets inlined.
4562// tslint:disable-next-line: no-toplevel-property-access
4563makeParamDecorator('Inject', (token) => ({ token })), -1 /* DecoratorFlags.Inject */);
4564/**
4565 * Optional decorator and metadata.
4566 *
4567 * @Annotation
4568 * @publicApi
4569 */
4570const Optional =
4571// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4572// tslint:disable-next-line: no-toplevel-property-access
4573attachInjectFlag(makeParamDecorator('Optional'), 8 /* InternalInjectFlags.Optional */);
4574/**
4575 * Self decorator and metadata.
4576 *
4577 * @Annotation
4578 * @publicApi
4579 */
4580const Self =
4581// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4582// tslint:disable-next-line: no-toplevel-property-access
4583attachInjectFlag(makeParamDecorator('Self'), 2 /* InternalInjectFlags.Self */);
4584/**
4585 * `SkipSelf` decorator and metadata.
4586 *
4587 * @Annotation
4588 * @publicApi
4589 */
4590const SkipSelf =
4591// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4592// tslint:disable-next-line: no-toplevel-property-access
4593attachInjectFlag(makeParamDecorator('SkipSelf'), 4 /* InternalInjectFlags.SkipSelf */);
4594/**
4595 * Host decorator and metadata.
4596 *
4597 * @Annotation
4598 * @publicApi
4599 */
4600const Host =
4601// Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
4602// tslint:disable-next-line: no-toplevel-property-access
4603attachInjectFlag(makeParamDecorator('Host'), 1 /* InternalInjectFlags.Host */);
4604
4605let _reflect = null;
4606function getReflect() {
4607 return (_reflect = _reflect || new ReflectionCapabilities());
4608}
4609function reflectDependencies(type) {
4610 return convertDependencies(getReflect().parameters(type));
4611}
4612function convertDependencies(deps) {
4613 return deps.map(dep => reflectDependency(dep));
4614}
4615function reflectDependency(dep) {
4616 const meta = {
4617 token: null,
4618 attribute: null,
4619 host: false,
4620 optional: false,
4621 self: false,
4622 skipSelf: false,
4623 };
4624 if (Array.isArray(dep) && dep.length > 0) {
4625 for (let j = 0; j < dep.length; j++) {
4626 const param = dep[j];
4627 if (param === undefined) {
4628 // param may be undefined if type of dep is not set by ngtsc
4629 continue;
4630 }
4631 const proto = Object.getPrototypeOf(param);
4632 if (param instanceof Optional || proto.ngMetadataName === 'Optional') {
4633 meta.optional = true;
4634 }
4635 else if (param instanceof SkipSelf || proto.ngMetadataName === 'SkipSelf') {
4636 meta.skipSelf = true;
4637 }
4638 else if (param instanceof Self || proto.ngMetadataName === 'Self') {
4639 meta.self = true;
4640 }
4641 else if (param instanceof Host || proto.ngMetadataName === 'Host') {
4642 meta.host = true;
4643 }
4644 else if (param instanceof Inject) {
4645 meta.token = param.token;
4646 }
4647 else if (param instanceof Attribute) {
4648 if (param.attributeName === undefined) {
4649 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Attribute name must be defined.`);
4650 }
4651 meta.attribute = param.attributeName;
4652 }
4653 else {
4654 meta.token = param;
4655 }
4656 }
4657 }
4658 else if (dep === undefined || (Array.isArray(dep) && dep.length === 0)) {
4659 meta.token = null;
4660 }
4661 else {
4662 meta.token = dep;
4663 }
4664 return meta;
4665}
4666
4667/**
4668 * Used to resolve resource URLs on `@Component` when used with JIT compilation.
4669 *
4670 * Example:
4671 * ```
4672 * @Component({
4673 * selector: 'my-comp',
4674 * templateUrl: 'my-comp.html', // This requires asynchronous resolution
4675 * })
4676 * class MyComponent{
4677 * }
4678 *
4679 * // Calling `renderComponent` will fail because `renderComponent` is a synchronous process
4680 * // and `MyComponent`'s `@Component.templateUrl` needs to be resolved asynchronously.
4681 *
4682 * // Calling `resolveComponentResources()` will resolve `@Component.templateUrl` into
4683 * // `@Component.template`, which allows `renderComponent` to proceed in a synchronous manner.
4684 *
4685 * // Use browser's `fetch()` function as the default resource resolution strategy.
4686 * resolveComponentResources(fetch).then(() => {
4687 * // After resolution all URLs have been converted into `template` strings.
4688 * renderComponent(MyComponent);
4689 * });
4690 *
4691 * ```
4692 *
4693 * NOTE: In AOT the resolution happens during compilation, and so there should be no need
4694 * to call this method outside JIT mode.
4695 *
4696 * @param resourceResolver a function which is responsible for returning a `Promise` to the
4697 * contents of the resolved URL. Browser's `fetch()` method is a good default implementation.
4698 */
4699function resolveComponentResources(resourceResolver) {
4700 // Store all promises which are fetching the resources.
4701 const componentResolved = [];
4702 // Cache so that we don't fetch the same resource more than once.
4703 const urlMap = new Map();
4704 function cachedResourceResolve(url) {
4705 let promise = urlMap.get(url);
4706 if (!promise) {
4707 const resp = resourceResolver(url);
4708 urlMap.set(url, promise = resp.then(unwrapResponse));
4709 }
4710 return promise;
4711 }
4712 componentResourceResolutionQueue.forEach((component, type) => {
4713 const promises = [];
4714 if (component.templateUrl) {
4715 promises.push(cachedResourceResolve(component.templateUrl).then((template) => {
4716 component.template = template;
4717 }));
4718 }
4719 const styleUrls = component.styleUrls;
4720 const styles = component.styles || (component.styles = []);
4721 const styleOffset = component.styles.length;
4722 styleUrls && styleUrls.forEach((styleUrl, index) => {
4723 styles.push(''); // pre-allocate array.
4724 promises.push(cachedResourceResolve(styleUrl).then((style) => {
4725 styles[styleOffset + index] = style;
4726 styleUrls.splice(styleUrls.indexOf(styleUrl), 1);
4727 if (styleUrls.length == 0) {
4728 component.styleUrls = undefined;
4729 }
4730 }));
4731 });
4732 const fullyResolved = Promise.all(promises).then(() => componentDefResolved(type));
4733 componentResolved.push(fullyResolved);
4734 });
4735 clearResolutionOfComponentResourcesQueue();
4736 return Promise.all(componentResolved).then(() => undefined);
4737}
4738let componentResourceResolutionQueue = new Map();
4739// Track when existing ɵcmp for a Type is waiting on resources.
4740const componentDefPendingResolution = new Set();
4741function maybeQueueResolutionOfComponentResources(type, metadata) {
4742 if (componentNeedsResolution(metadata)) {
4743 componentResourceResolutionQueue.set(type, metadata);
4744 componentDefPendingResolution.add(type);
4745 }
4746}
4747function isComponentDefPendingResolution(type) {
4748 return componentDefPendingResolution.has(type);
4749}
4750function componentNeedsResolution(component) {
4751 return !!((component.templateUrl && !component.hasOwnProperty('template')) ||
4752 component.styleUrls && component.styleUrls.length);
4753}
4754function clearResolutionOfComponentResourcesQueue() {
4755 const old = componentResourceResolutionQueue;
4756 componentResourceResolutionQueue = new Map();
4757 return old;
4758}
4759function restoreComponentResolutionQueue(queue) {
4760 componentDefPendingResolution.clear();
4761 queue.forEach((_, type) => componentDefPendingResolution.add(type));
4762 componentResourceResolutionQueue = queue;
4763}
4764function isComponentResourceResolutionQueueEmpty() {
4765 return componentResourceResolutionQueue.size === 0;
4766}
4767function unwrapResponse(response) {
4768 return typeof response == 'string' ? response : response.text();
4769}
4770function componentDefResolved(type) {
4771 componentDefPendingResolution.delete(type);
4772}
4773
4774/**
4775 * Map of module-id to the corresponding NgModule.
4776 */
4777const modules = new Map();
4778/**
4779 * Whether to check for duplicate NgModule registrations.
4780 *
4781 * This can be disabled for testing.
4782 */
4783let checkForDuplicateNgModules = true;
4784function assertSameOrNotExisting(id, type, incoming) {
4785 if (type && type !== incoming && checkForDuplicateNgModules) {
4786 throw new Error(`Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`);
4787 }
4788}
4789/**
4790 * Adds the given NgModule type to Angular's NgModule registry.
4791 *
4792 * This is generated as a side-effect of NgModule compilation. Note that the `id` is passed in
4793 * explicitly and not read from the NgModule definition. This is for two reasons: it avoids a
4794 * megamorphic read, and in JIT there's a chicken-and-egg problem where the NgModule may not be
4795 * fully resolved when it's registered.
4796 *
4797 * @codeGenApi
4798 */
4799function registerNgModuleType(ngModuleType, id) {
4800 const existing = modules.get(id) || null;
4801 assertSameOrNotExisting(id, existing, ngModuleType);
4802 modules.set(id, ngModuleType);
4803}
4804function clearModulesForTest() {
4805 modules.clear();
4806}
4807function getRegisteredNgModuleType(id) {
4808 return modules.get(id);
4809}
4810/**
4811 * Control whether the NgModule registration system enforces that each NgModule type registered has
4812 * a unique id.
4813 *
4814 * This is useful for testing as the NgModule registry cannot be properly reset between tests with
4815 * Angular's current API.
4816 */
4817function setAllowDuplicateNgModuleIdsForTest(allowDuplicates) {
4818 checkForDuplicateNgModules = !allowDuplicates;
4819}
4820
4821/**
4822 * Defines a schema that allows an NgModule to contain the following:
4823 * - Non-Angular elements named with dash case (`-`).
4824 * - Element properties named with dash case (`-`).
4825 * Dash case is the naming convention for custom elements.
4826 *
4827 * @publicApi
4828 */
4829const CUSTOM_ELEMENTS_SCHEMA = {
4830 name: 'custom-elements'
4831};
4832/**
4833 * Defines a schema that allows any property on any element.
4834 *
4835 * This schema allows you to ignore the errors related to any unknown elements or properties in a
4836 * template. The usage of this schema is generally discouraged because it prevents useful validation
4837 * and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
4838 *
4839 * @publicApi
4840 */
4841const NO_ERRORS_SCHEMA = {
4842 name: 'no-errors-schema'
4843};
4844
4845let shouldThrowErrorOnUnknownElement = false;
4846/**
4847 * Sets a strict mode for JIT-compiled components to throw an error on unknown elements,
4848 * instead of just logging the error.
4849 * (for AOT-compiled ones this check happens at build time).
4850 */
4851function ɵsetUnknownElementStrictMode(shouldThrow) {
4852 shouldThrowErrorOnUnknownElement = shouldThrow;
4853}
4854/**
4855 * Gets the current value of the strict mode.
4856 */
4857function ɵgetUnknownElementStrictMode() {
4858 return shouldThrowErrorOnUnknownElement;
4859}
4860let shouldThrowErrorOnUnknownProperty = false;
4861/**
4862 * Sets a strict mode for JIT-compiled components to throw an error on unknown properties,
4863 * instead of just logging the error.
4864 * (for AOT-compiled ones this check happens at build time).
4865 */
4866function ɵsetUnknownPropertyStrictMode(shouldThrow) {
4867 shouldThrowErrorOnUnknownProperty = shouldThrow;
4868}
4869/**
4870 * Gets the current value of the strict mode.
4871 */
4872function ɵgetUnknownPropertyStrictMode() {
4873 return shouldThrowErrorOnUnknownProperty;
4874}
4875/**
4876 * Validates that the element is known at runtime and produces
4877 * an error if it's not the case.
4878 * This check is relevant for JIT-compiled components (for AOT-compiled
4879 * ones this check happens at build time).
4880 *
4881 * The element is considered known if either:
4882 * - it's a known HTML element
4883 * - it's a known custom element
4884 * - the element matches any directive
4885 * - the element is allowed by one of the schemas
4886 *
4887 * @param element Element to validate
4888 * @param lView An `LView` that represents a current component that is being rendered
4889 * @param tagName Name of the tag to check
4890 * @param schemas Array of schemas
4891 * @param hasDirectives Boolean indicating that the element matches any directive
4892 */
4893function validateElementIsKnown(element, lView, tagName, schemas, hasDirectives) {
4894 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
4895 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
4896 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
4897 // execute the check below.
4898 if (schemas === null)
4899 return;
4900 // If the element matches any directive, it's considered as valid.
4901 if (!hasDirectives && tagName !== null) {
4902 // The element is unknown if it's an instance of HTMLUnknownElement, or it isn't registered
4903 // as a custom element. Note that unknown elements with a dash in their name won't be instances
4904 // of HTMLUnknownElement in browsers that support web components.
4905 const isUnknown =
4906 // Note that we can't check for `typeof HTMLUnknownElement === 'function'`,
4907 // because while most browsers return 'function', IE returns 'object'.
4908 (typeof HTMLUnknownElement !== 'undefined' && HTMLUnknownElement &&
4909 element instanceof HTMLUnknownElement) ||
4910 (typeof customElements !== 'undefined' && tagName.indexOf('-') > -1 &&
4911 !customElements.get(tagName));
4912 if (isUnknown && !matchingSchemas(schemas, tagName)) {
4913 const isHostStandalone = isHostComponentStandalone(lView);
4914 const templateLocation = getTemplateLocationDetails(lView);
4915 const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
4916 let message = `'${tagName}' is not a known element${templateLocation}:\n`;
4917 message += `1. If '${tagName}' is an Angular component, then verify that it is ${isHostStandalone ? 'included in the \'@Component.imports\' of this component' :
4918 'a part of an @NgModule where this component is declared'}.\n`;
4919 if (tagName && tagName.indexOf('-') > -1) {
4920 message +=
4921 `2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${schemas} of this component to suppress this message.`;
4922 }
4923 else {
4924 message +=
4925 `2. To allow any element add 'NO_ERRORS_SCHEMA' to the ${schemas} of this component.`;
4926 }
4927 if (shouldThrowErrorOnUnknownElement) {
4928 throw new RuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message);
4929 }
4930 else {
4931 console.error(formatRuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message));
4932 }
4933 }
4934 }
4935}
4936/**
4937 * Validates that the property of the element is known at runtime and returns
4938 * false if it's not the case.
4939 * This check is relevant for JIT-compiled components (for AOT-compiled
4940 * ones this check happens at build time).
4941 *
4942 * The property is considered known if either:
4943 * - it's a known property of the element
4944 * - the element is allowed by one of the schemas
4945 * - the property is used for animations
4946 *
4947 * @param element Element to validate
4948 * @param propName Name of the property to check
4949 * @param tagName Name of the tag hosting the property
4950 * @param schemas Array of schemas
4951 */
4952function isPropertyValid(element, propName, tagName, schemas) {
4953 // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
4954 // mode where this check happens at compile time. In JIT mode, `schemas` is always present and
4955 // defined as an array (as an empty array in case `schemas` field is not defined) and we should
4956 // execute the check below.
4957 if (schemas === null)
4958 return true;
4959 // The property is considered valid if the element matches the schema, it exists on the element,
4960 // or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
4961 if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
4962 return true;
4963 }
4964 // Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
4965 // need to account for both here, while being careful with `typeof null` also returning 'object'.
4966 return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
4967}
4968/**
4969 * Logs or throws an error that a property is not supported on an element.
4970 *
4971 * @param propName Name of the invalid property
4972 * @param tagName Name of the tag hosting the property
4973 * @param nodeType Type of the node hosting the property
4974 * @param lView An `LView` that represents a current component
4975 */
4976function handleUnknownPropertyError(propName, tagName, nodeType, lView) {
4977 // Special-case a situation when a structural directive is applied to
4978 // an `<ng-template>` element, for example: `<ng-template *ngIf="true">`.
4979 // In this case the compiler generates the `ɵɵtemplate` instruction with
4980 // the `null` as the tagName. The directive matching logic at runtime relies
4981 // on this effect (see `isInlineTemplate`), thus using the 'ng-template' as
4982 // a default value of the `tNode.value` is not feasible at this moment.
4983 if (!tagName && nodeType === 4 /* TNodeType.Container */) {
4984 tagName = 'ng-template';
4985 }
4986 const isHostStandalone = isHostComponentStandalone(lView);
4987 const templateLocation = getTemplateLocationDetails(lView);
4988 let message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'${templateLocation}.`;
4989 const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
4990 const importLocation = isHostStandalone ?
4991 'included in the \'@Component.imports\' of this component' :
4992 'a part of an @NgModule where this component is declared';
4993 if (KNOWN_CONTROL_FLOW_DIRECTIVES.has(propName)) {
4994 // Most likely this is a control flow directive (such as `*ngIf`) used in
4995 // a template, but the directive or the `CommonModule` is not imported.
4996 const correspondingImport = KNOWN_CONTROL_FLOW_DIRECTIVES.get(propName);
4997 message += `\nIf the '${propName}' is an Angular control flow directive, ` +
4998 `please make sure that either the '${correspondingImport}' directive or the 'CommonModule' is ${importLocation}.`;
4999 }
5000 else {
5001 // May be an Angular component, which is not imported/declared?
5002 message += `\n1. If '${tagName}' is an Angular component and it has the ` +
5003 `'${propName}' input, then verify that it is ${importLocation}.`;
5004 // May be a Web Component?
5005 if (tagName && tagName.indexOf('-') > -1) {
5006 message += `\n2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' ` +
5007 `to the ${schemas} of this component to suppress this message.`;
5008 message += `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
5009 `the ${schemas} of this component.`;
5010 }
5011 else {
5012 // If it's expected, the error can be suppressed by the `NO_ERRORS_SCHEMA` schema.
5013 message += `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
5014 `the ${schemas} of this component.`;
5015 }
5016 }
5017 reportUnknownPropertyError(message);
5018}
5019function reportUnknownPropertyError(message) {
5020 if (shouldThrowErrorOnUnknownProperty) {
5021 throw new RuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message);
5022 }
5023 else {
5024 console.error(formatRuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message));
5025 }
5026}
5027/**
5028 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
5029 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
5030 * be too slow for production mode and also it relies on the constructor function being available.
5031 *
5032 * Gets a reference to the host component def (where a current component is declared).
5033 *
5034 * @param lView An `LView` that represents a current component that is being rendered.
5035 */
5036function getDeclarationComponentDef(lView) {
5037 !ngDevMode && throwError('Must never be called in production mode');
5038 const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
5039 const context = declarationLView[CONTEXT];
5040 // Unable to obtain a context.
5041 if (!context)
5042 return null;
5043 return context.constructor ? getComponentDef(context.constructor) : null;
5044}
5045/**
5046 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
5047 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
5048 * be too slow for production mode.
5049 *
5050 * Checks if the current component is declared inside of a standalone component template.
5051 *
5052 * @param lView An `LView` that represents a current component that is being rendered.
5053 */
5054function isHostComponentStandalone(lView) {
5055 !ngDevMode && throwError('Must never be called in production mode');
5056 const componentDef = getDeclarationComponentDef(lView);
5057 // Treat host component as non-standalone if we can't obtain the def.
5058 return !!(componentDef === null || componentDef === void 0 ? void 0 : componentDef.standalone);
5059}
5060/**
5061 * WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
5062 * and must **not** be used in production bundles. The function makes megamorphic reads, which might
5063 * be too slow for production mode.
5064 *
5065 * Constructs a string describing the location of the host component template. The function is used
5066 * in dev mode to produce error messages.
5067 *
5068 * @param lView An `LView` that represents a current component that is being rendered.
5069 */
5070function getTemplateLocationDetails(lView) {
5071 var _a;
5072 !ngDevMode && throwError('Must never be called in production mode');
5073 const hostComponentDef = getDeclarationComponentDef(lView);
5074 const componentClassName = (_a = hostComponentDef === null || hostComponentDef === void 0 ? void 0 : hostComponentDef.type) === null || _a === void 0 ? void 0 : _a.name;
5075 return componentClassName ? ` (used in the '${componentClassName}' component template)` : '';
5076}
5077/**
5078 * The set of known control flow directives and their corresponding imports.
5079 * We use this set to produce a more precises error message with a note
5080 * that the `CommonModule` should also be included.
5081 */
5082const KNOWN_CONTROL_FLOW_DIRECTIVES = new Map([
5083 ['ngIf', 'NgIf'], ['ngFor', 'NgFor'], ['ngSwitchCase', 'NgSwitchCase'],
5084 ['ngSwitchDefault', 'NgSwitchDefault']
5085]);
5086/**
5087 * Returns true if the tag name is allowed by specified schemas.
5088 * @param schemas Array of schemas
5089 * @param tagName Name of the tag
5090 */
5091function matchingSchemas(schemas, tagName) {
5092 if (schemas !== null) {
5093 for (let i = 0; i < schemas.length; i++) {
5094 const schema = schemas[i];
5095 if (schema === NO_ERRORS_SCHEMA ||
5096 schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
5097 return true;
5098 }
5099 }
5100 }
5101 return false;
5102}
5103
5104/**
5105 * Flags for renderer-specific style modifiers.
5106 * @publicApi
5107 */
5108var RendererStyleFlags2;
5109(function (RendererStyleFlags2) {
5110 // TODO(misko): This needs to be refactored into a separate file so that it can be imported from
5111 // `node_manipulation.ts` Currently doing the import cause resolution order to change and fails
5112 // the tests. The work around is to have hard coded value in `node_manipulation.ts` for now.
5113 /**
5114 * Marks a style as important.
5115 */
5116 RendererStyleFlags2[RendererStyleFlags2["Important"] = 1] = "Important";
5117 /**
5118 * Marks a style as using dash case naming (this-is-dash-case).
5119 */
5120 RendererStyleFlags2[RendererStyleFlags2["DashCase"] = 2] = "DashCase";
5121})(RendererStyleFlags2 || (RendererStyleFlags2 = {}));
5122
5123/**
5124 * Disallowed strings in the comment.
5125 *
5126 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
5127 */
5128const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
5129/**
5130 * Delimiter in the disallowed strings which needs to be wrapped with zero with character.
5131 */
5132const COMMENT_DELIMITER = /(<|>)/;
5133const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
5134/**
5135 * Escape the content of comment strings so that it can be safely inserted into a comment node.
5136 *
5137 * The issue is that HTML does not specify any way to escape comment end text inside the comment.
5138 * Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
5139 * "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
5140 * can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
5141 *
5142 * see: https://html.spec.whatwg.org/multipage/syntax.html#comments
5143 *
5144 * ```
5145 * div.innerHTML = div.innerHTML
5146 * ```
5147 *
5148 * One would expect that the above code would be safe to do, but it turns out that because comment
5149 * text is not escaped, the comment may contain text which will prematurely close the comment
5150 * opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
5151 * may contain such text and expect them to be safe.)
5152 *
5153 * This function escapes the comment text by looking for comment delimiters (`<` and `>`) and
5154 * surrounding them with `_>_` where the `_` is a zero width space `\u200B`. The result is that if a
5155 * comment contains any of the comment start/end delimiters (such as `<!--`, `-->` or `--!>`) the
5156 * text it will render normally but it will not cause the HTML parser to close/open the comment.
5157 *
5158 * @param value text to make safe for comment node by escaping the comment open/close character
5159 * sequence.
5160 */
5161function escapeCommentText(value) {
5162 return value.replace(COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED));
5163}
5164
5165// Keeps track of the currently-active LViews.
5166const TRACKED_LVIEWS = new Map();
5167// Used for generating unique IDs for LViews.
5168let uniqueIdCounter = 0;
5169/** Gets a unique ID that can be assigned to an LView. */
5170function getUniqueLViewId() {
5171 return uniqueIdCounter++;
5172}
5173/** Starts tracking an LView. */
5174function registerLView(lView) {
5175 ngDevMode && assertNumber(lView[ID], 'LView must have an ID in order to be registered');
5176 TRACKED_LVIEWS.set(lView[ID], lView);
5177}
5178/** Gets an LView by its unique ID. */
5179function getLViewById(id) {
5180 ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number');
5181 return TRACKED_LVIEWS.get(id) || null;
5182}
5183/** Stops tracking an LView. */
5184function unregisterLView(lView) {
5185 ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID');
5186 TRACKED_LVIEWS.delete(lView[ID]);
5187}
5188
5189/**
5190 * The internal view context which is specific to a given DOM element, directive or
5191 * component instance. Each value in here (besides the LView and element node details)
5192 * can be present, null or undefined. If undefined then it implies the value has not been
5193 * looked up yet, otherwise, if null, then a lookup was executed and nothing was found.
5194 *
5195 * Each value will get filled when the respective value is examined within the getContext
5196 * function. The component, element and each directive instance will share the same instance
5197 * of the context.
5198 */
5199class LContext {
5200 /** Component's parent view data. */
5201 get lView() {
5202 return getLViewById(this.lViewId);
5203 }
5204 constructor(
5205 /**
5206 * ID of the component's parent view data.
5207 */
5208 lViewId,
5209 /**
5210 * The index instance of the node.
5211 */
5212 nodeIndex,
5213 /**
5214 * The instance of the DOM node that is attached to the lNode.
5215 */
5216 native) {
5217 this.lViewId = lViewId;
5218 this.nodeIndex = nodeIndex;
5219 this.native = native;
5220 }
5221}
5222
5223/**
5224 * Returns the matching `LContext` data for a given DOM node, directive or component instance.
5225 *
5226 * This function will examine the provided DOM element, component, or directive instance\'s
5227 * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched
5228 * value will be that of the newly created `LContext`.
5229 *
5230 * If the monkey-patched value is the `LView` instance then the context value for that
5231 * target will be created and the monkey-patch reference will be updated. Therefore when this
5232 * function is called it may mutate the provided element\'s, component\'s or any of the associated
5233 * directive\'s monkey-patch values.
5234 *
5235 * If the monkey-patch value is not detected then the code will walk up the DOM until an element
5236 * is found which contains a monkey-patch reference. When that occurs then the provided element
5237 * will be updated with a new context (which is then returned). If the monkey-patch value is not
5238 * detected for a component/directive instance then it will throw an error (all components and
5239 * directives should be automatically monkey-patched by ivy).
5240 *
5241 * @param target Component, Directive or DOM Node.
5242 */
5243function getLContext(target) {
5244 let mpValue = readPatchedData(target);
5245 if (mpValue) {
5246 // only when it's an array is it considered an LView instance
5247 // ... otherwise it's an already constructed LContext instance
5248 if (isLView(mpValue)) {
5249 const lView = mpValue;
5250 let nodeIndex;
5251 let component = undefined;
5252 let directives = undefined;
5253 if (isComponentInstance(target)) {
5254 nodeIndex = findViaComponent(lView, target);
5255 if (nodeIndex == -1) {
5256 throw new Error('The provided component was not found in the application');
5257 }
5258 component = target;
5259 }
5260 else if (isDirectiveInstance(target)) {
5261 nodeIndex = findViaDirective(lView, target);
5262 if (nodeIndex == -1) {
5263 throw new Error('The provided directive was not found in the application');
5264 }
5265 directives = getDirectivesAtNodeIndex(nodeIndex, lView);
5266 }
5267 else {
5268 nodeIndex = findViaNativeElement(lView, target);
5269 if (nodeIndex == -1) {
5270 return null;
5271 }
5272 }
5273 // the goal is not to fill the entire context full of data because the lookups
5274 // are expensive. Instead, only the target data (the element, component, container, ICU
5275 // expression or directive details) are filled into the context. If called multiple times
5276 // with different target values then the missing target data will be filled in.
5277 const native = unwrapRNode(lView[nodeIndex]);
5278 const existingCtx = readPatchedData(native);
5279 const context = (existingCtx && !Array.isArray(existingCtx)) ?
5280 existingCtx :
5281 createLContext(lView, nodeIndex, native);
5282 // only when the component has been discovered then update the monkey-patch
5283 if (component && context.component === undefined) {
5284 context.component = component;
5285 attachPatchData(context.component, context);
5286 }
5287 // only when the directives have been discovered then update the monkey-patch
5288 if (directives && context.directives === undefined) {
5289 context.directives = directives;
5290 for (let i = 0; i < directives.length; i++) {
5291 attachPatchData(directives[i], context);
5292 }
5293 }
5294 attachPatchData(context.native, context);
5295 mpValue = context;
5296 }
5297 }
5298 else {
5299 const rElement = target;
5300 ngDevMode && assertDomNode(rElement);
5301 // if the context is not found then we need to traverse upwards up the DOM
5302 // to find the nearest element that has already been monkey patched with data
5303 let parent = rElement;
5304 while (parent = parent.parentNode) {
5305 const parentContext = readPatchedData(parent);
5306 if (parentContext) {
5307 const lView = Array.isArray(parentContext) ? parentContext : parentContext.lView;
5308 // the edge of the app was also reached here through another means
5309 // (maybe because the DOM was changed manually).
5310 if (!lView) {
5311 return null;
5312 }
5313 const index = findViaNativeElement(lView, rElement);
5314 if (index >= 0) {
5315 const native = unwrapRNode(lView[index]);
5316 const context = createLContext(lView, index, native);
5317 attachPatchData(native, context);
5318 mpValue = context;
5319 break;
5320 }
5321 }
5322 }
5323 }
5324 return mpValue || null;
5325}
5326/**
5327 * Creates an empty instance of a `LContext` context
5328 */
5329function createLContext(lView, nodeIndex, native) {
5330 return new LContext(lView[ID], nodeIndex, native);
5331}
5332/**
5333 * Takes a component instance and returns the view for that component.
5334 *
5335 * @param componentInstance
5336 * @returns The component's view
5337 */
5338function getComponentViewByInstance(componentInstance) {
5339 let patchedData = readPatchedData(componentInstance);
5340 let lView;
5341 if (isLView(patchedData)) {
5342 const contextLView = patchedData;
5343 const nodeIndex = findViaComponent(contextLView, componentInstance);
5344 lView = getComponentLViewByIndex(nodeIndex, contextLView);
5345 const context = createLContext(contextLView, nodeIndex, lView[HOST]);
5346 context.component = componentInstance;
5347 attachPatchData(componentInstance, context);
5348 attachPatchData(context.native, context);
5349 }
5350 else {
5351 const context = patchedData;
5352 const contextLView = context.lView;
5353 ngDevMode && assertLView(contextLView);
5354 lView = getComponentLViewByIndex(context.nodeIndex, contextLView);
5355 }
5356 return lView;
5357}
5358/**
5359 * This property will be monkey-patched on elements, components and directives.
5360 */
5361const MONKEY_PATCH_KEY_NAME = '__ngContext__';
5362/**
5363 * Assigns the given data to the given target (which could be a component,
5364 * directive or DOM node instance) using monkey-patching.
5365 */
5366function attachPatchData(target, data) {
5367 ngDevMode && assertDefined(target, 'Target expected');
5368 // Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this
5369 // for `LView`, because we have control over when an `LView` is created and destroyed, whereas
5370 // we can't know when to remove an `LContext`.
5371 if (isLView(data)) {
5372 target[MONKEY_PATCH_KEY_NAME] = data[ID];
5373 registerLView(data);
5374 }
5375 else {
5376 target[MONKEY_PATCH_KEY_NAME] = data;
5377 }
5378}
5379/**
5380 * Returns the monkey-patch value data present on the target (which could be
5381 * a component, directive or a DOM node).
5382 */
5383function readPatchedData(target) {
5384 ngDevMode && assertDefined(target, 'Target expected');
5385 const data = target[MONKEY_PATCH_KEY_NAME];
5386 return (typeof data === 'number') ? getLViewById(data) : data || null;
5387}
5388function readPatchedLView(target) {
5389 const value = readPatchedData(target);
5390 if (value) {
5391 return (isLView(value) ? value : value.lView);
5392 }
5393 return null;
5394}
5395function isComponentInstance(instance) {
5396 return instance && instance.constructor && instance.constructor.ɵcmp;
5397}
5398function isDirectiveInstance(instance) {
5399 return instance && instance.constructor && instance.constructor.ɵdir;
5400}
5401/**
5402 * Locates the element within the given LView and returns the matching index
5403 */
5404function findViaNativeElement(lView, target) {
5405 const tView = lView[TVIEW];
5406 for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
5407 if (unwrapRNode(lView[i]) === target) {
5408 return i;
5409 }
5410 }
5411 return -1;
5412}
5413/**
5414 * Locates the next tNode (child, sibling or parent).
5415 */
5416function traverseNextElement(tNode) {
5417 if (tNode.child) {
5418 return tNode.child;
5419 }
5420 else if (tNode.next) {
5421 return tNode.next;
5422 }
5423 else {
5424 // Let's take the following template: <div><span>text</span></div><component/>
5425 // After checking the text node, we need to find the next parent that has a "next" TNode,
5426 // in this case the parent `div`, so that we can find the component.
5427 while (tNode.parent && !tNode.parent.next) {
5428 tNode = tNode.parent;
5429 }
5430 return tNode.parent && tNode.parent.next;
5431 }
5432}
5433/**
5434 * Locates the component within the given LView and returns the matching index
5435 */
5436function findViaComponent(lView, componentInstance) {
5437 const componentIndices = lView[TVIEW].components;
5438 if (componentIndices) {
5439 for (let i = 0; i < componentIndices.length; i++) {
5440 const elementComponentIndex = componentIndices[i];
5441 const componentView = getComponentLViewByIndex(elementComponentIndex, lView);
5442 if (componentView[CONTEXT] === componentInstance) {
5443 return elementComponentIndex;
5444 }
5445 }
5446 }
5447 else {
5448 const rootComponentView = getComponentLViewByIndex(HEADER_OFFSET, lView);
5449 const rootComponent = rootComponentView[CONTEXT];
5450 if (rootComponent === componentInstance) {
5451 // we are dealing with the root element here therefore we know that the
5452 // element is the very first element after the HEADER data in the lView
5453 return HEADER_OFFSET;
5454 }
5455 }
5456 return -1;
5457}
5458/**
5459 * Locates the directive within the given LView and returns the matching index
5460 */
5461function findViaDirective(lView, directiveInstance) {
5462 // if a directive is monkey patched then it will (by default)
5463 // have a reference to the LView of the current view. The
5464 // element bound to the directive being search lives somewhere
5465 // in the view data. We loop through the nodes and check their
5466 // list of directives for the instance.
5467 let tNode = lView[TVIEW].firstChild;
5468 while (tNode) {
5469 const directiveIndexStart = tNode.directiveStart;
5470 const directiveIndexEnd = tNode.directiveEnd;
5471 for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
5472 if (lView[i] === directiveInstance) {
5473 return tNode.index;
5474 }
5475 }
5476 tNode = traverseNextElement(tNode);
5477 }
5478 return -1;
5479}
5480/**
5481 * Returns a list of directives applied to a node at a specific index. The list includes
5482 * directives matched by selector and any host directives, but it excludes components.
5483 * Use `getComponentAtNodeIndex` to find the component applied to a node.
5484 *
5485 * @param nodeIndex The node index
5486 * @param lView The target view data
5487 */
5488function getDirectivesAtNodeIndex(nodeIndex, lView) {
5489 const tNode = lView[TVIEW].data[nodeIndex];
5490 if (tNode.directiveStart === 0)
5491 return EMPTY_ARRAY;
5492 const results = [];
5493 for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
5494 const directiveInstance = lView[i];
5495 if (!isComponentInstance(directiveInstance)) {
5496 results.push(directiveInstance);
5497 }
5498 }
5499 return results;
5500}
5501function getComponentAtNodeIndex(nodeIndex, lView) {
5502 const tNode = lView[TVIEW].data[nodeIndex];
5503 const { directiveStart, componentOffset } = tNode;
5504 return componentOffset > -1 ? lView[directiveStart + componentOffset] : null;
5505}
5506/**
5507 * Returns a map of local references (local reference name => element or directive instance) that
5508 * exist on a given element.
5509 */
5510function discoverLocalRefs(lView, nodeIndex) {
5511 const tNode = lView[TVIEW].data[nodeIndex];
5512 if (tNode && tNode.localNames) {
5513 const result = {};
5514 let localIndex = tNode.index + 1;
5515 for (let i = 0; i < tNode.localNames.length; i += 2) {
5516 result[tNode.localNames[i]] = lView[localIndex];
5517 localIndex++;
5518 }
5519 return result;
5520 }
5521 return null;
5522}
5523
5524let _icuContainerIterate;
5525/**
5526 * Iterator which provides ability to visit all of the `TIcuContainerNode` root `RNode`s.
5527 */
5528function icuContainerIterate(tIcuContainerNode, lView) {
5529 return _icuContainerIterate(tIcuContainerNode, lView);
5530}
5531/**
5532 * Ensures that `IcuContainerVisitor`'s implementation is present.
5533 *
5534 * This function is invoked when i18n instruction comes across an ICU. The purpose is to allow the
5535 * bundler to tree shake ICU logic and only load it if ICU instruction is executed.
5536 */
5537function ensureIcuContainerVisitorLoaded(loader) {
5538 if (_icuContainerIterate === undefined) {
5539 // Do not inline this function. We want to keep `ensureIcuContainerVisitorLoaded` light, so it
5540 // can be inlined into call-site.
5541 _icuContainerIterate = loader();
5542 }
5543}
5544
5545/**
5546 * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of
5547 * that LContainer, which is an LView
5548 * @param lView the lView whose parent to get
5549 */
5550function getLViewParent(lView) {
5551 ngDevMode && assertLView(lView);
5552 const parent = lView[PARENT];
5553 return isLContainer(parent) ? parent[PARENT] : parent;
5554}
5555/**
5556 * Retrieve the root view from any component or `LView` by walking the parent `LView` until
5557 * reaching the root `LView`.
5558 *
5559 * @param componentOrLView any component or `LView`
5560 */
5561function getRootView(componentOrLView) {
5562 ngDevMode && assertDefined(componentOrLView, 'component');
5563 let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView);
5564 while (lView && !(lView[FLAGS] & 256 /* LViewFlags.IsRoot */)) {
5565 lView = getLViewParent(lView);
5566 }
5567 ngDevMode && assertLView(lView);
5568 return lView;
5569}
5570/**
5571 * Returns the context information associated with the application where the target is situated. It
5572 * does this by walking the parent views until it gets to the root view, then getting the context
5573 * off of that.
5574 *
5575 * @param viewOrComponent the `LView` or component to get the root context for.
5576 */
5577function getRootContext(viewOrComponent) {
5578 const rootView = getRootView(viewOrComponent);
5579 ngDevMode &&
5580 assertDefined(rootView[CONTEXT], 'Root view has no context. Perhaps it is disconnected?');
5581 return rootView[CONTEXT];
5582}
5583/**
5584 * Gets the first `LContainer` in the LView or `null` if none exists.
5585 */
5586function getFirstLContainer(lView) {
5587 return getNearestLContainer(lView[CHILD_HEAD]);
5588}
5589/**
5590 * Gets the next `LContainer` that is a sibling of the given container.
5591 */
5592function getNextLContainer(container) {
5593 return getNearestLContainer(container[NEXT]);
5594}
5595function getNearestLContainer(viewOrContainer) {
5596 while (viewOrContainer !== null && !isLContainer(viewOrContainer)) {
5597 viewOrContainer = viewOrContainer[NEXT];
5598 }
5599 return viewOrContainer;
5600}
5601
5602/**
5603 * NOTE: for performance reasons, the possible actions are inlined within the function instead of
5604 * being passed as an argument.
5605 */
5606function applyToElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
5607 // If this slot was allocated for a text node dynamically created by i18n, the text node itself
5608 // won't be created until i18nApply() in the update block, so this node should be skipped.
5609 // For more info, see "ICU expressions should work inside an ngTemplateOutlet inside an ngFor"
5610 // in `i18n_spec.ts`.
5611 if (lNodeToHandle != null) {
5612 let lContainer;
5613 let isComponent = false;
5614 // We are expecting an RNode, but in the case of a component or LContainer the `RNode` is
5615 // wrapped in an array which needs to be unwrapped. We need to know if it is a component and if
5616 // it has LContainer so that we can process all of those cases appropriately.
5617 if (isLContainer(lNodeToHandle)) {
5618 lContainer = lNodeToHandle;
5619 }
5620 else if (isLView(lNodeToHandle)) {
5621 isComponent = true;
5622 ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView');
5623 lNodeToHandle = lNodeToHandle[HOST];
5624 }
5625 const rNode = unwrapRNode(lNodeToHandle);
5626 if (action === 0 /* WalkTNodeTreeAction.Create */ && parent !== null) {
5627 if (beforeNode == null) {
5628 nativeAppendChild(renderer, parent, rNode);
5629 }
5630 else {
5631 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
5632 }
5633 }
5634 else if (action === 1 /* WalkTNodeTreeAction.Insert */ && parent !== null) {
5635 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
5636 }
5637 else if (action === 2 /* WalkTNodeTreeAction.Detach */) {
5638 nativeRemoveNode(renderer, rNode, isComponent);
5639 }
5640 else if (action === 3 /* WalkTNodeTreeAction.Destroy */) {
5641 ngDevMode && ngDevMode.rendererDestroyNode++;
5642 renderer.destroyNode(rNode);
5643 }
5644 if (lContainer != null) {
5645 applyContainer(renderer, action, lContainer, parent, beforeNode);
5646 }
5647 }
5648}
5649function createTextNode(renderer, value) {
5650 ngDevMode && ngDevMode.rendererCreateTextNode++;
5651 ngDevMode && ngDevMode.rendererSetText++;
5652 return renderer.createText(value);
5653}
5654function updateTextNode(renderer, rNode, value) {
5655 ngDevMode && ngDevMode.rendererSetText++;
5656 renderer.setValue(rNode, value);
5657}
5658function createCommentNode(renderer, value) {
5659 ngDevMode && ngDevMode.rendererCreateComment++;
5660 return renderer.createComment(escapeCommentText(value));
5661}
5662/**
5663 * Creates a native element from a tag name, using a renderer.
5664 * @param renderer A renderer to use
5665 * @param name the tag name
5666 * @param namespace Optional namespace for element.
5667 * @returns the element created
5668 */
5669function createElementNode(renderer, name, namespace) {
5670 ngDevMode && ngDevMode.rendererCreateElement++;
5671 return renderer.createElement(name, namespace);
5672}
5673/**
5674 * Removes all DOM elements associated with a view.
5675 *
5676 * Because some root nodes of the view may be containers, we sometimes need
5677 * to propagate deeply into the nested containers to remove all elements in the
5678 * views beneath it.
5679 *
5680 * @param tView The `TView' of the `LView` from which elements should be added or removed
5681 * @param lView The view from which elements should be added or removed
5682 */
5683function removeViewFromContainer(tView, lView) {
5684 const renderer = lView[RENDERER];
5685 applyView(tView, lView, renderer, 2 /* WalkTNodeTreeAction.Detach */, null, null);
5686 lView[HOST] = null;
5687 lView[T_HOST] = null;
5688}
5689/**
5690 * Adds all DOM elements associated with a view.
5691 *
5692 * Because some root nodes of the view may be containers, we sometimes need
5693 * to propagate deeply into the nested containers to add all elements in the
5694 * views beneath it.
5695 *
5696 * @param tView The `TView' of the `LView` from which elements should be added or removed
5697 * @param parentTNode The `TNode` where the `LView` should be attached to.
5698 * @param renderer Current renderer to use for DOM manipulations.
5699 * @param lView The view from which elements should be added or removed
5700 * @param parentNativeNode The parent `RElement` where it should be inserted into.
5701 * @param beforeNode The node before which elements should be added, if insert mode
5702 */
5703function addViewToContainer(tView, parentTNode, renderer, lView, parentNativeNode, beforeNode) {
5704 lView[HOST] = parentNativeNode;
5705 lView[T_HOST] = parentTNode;
5706 applyView(tView, lView, renderer, 1 /* WalkTNodeTreeAction.Insert */, parentNativeNode, beforeNode);
5707}
5708/**
5709 * Detach a `LView` from the DOM by detaching its nodes.
5710 *
5711 * @param tView The `TView' of the `LView` to be detached
5712 * @param lView the `LView` to be detached.
5713 */
5714function renderDetachView(tView, lView) {
5715 applyView(tView, lView, lView[RENDERER], 2 /* WalkTNodeTreeAction.Detach */, null, null);
5716}
5717/**
5718 * Traverses down and up the tree of views and containers to remove listeners and
5719 * call onDestroy callbacks.
5720 *
5721 * Notes:
5722 * - Because it's used for onDestroy calls, it needs to be bottom-up.
5723 * - Must process containers instead of their views to avoid splicing
5724 * when views are destroyed and re-added.
5725 * - Using a while loop because it's faster than recursion
5726 * - Destroy only called on movement to sibling or movement to parent (laterally or up)
5727 *
5728 * @param rootView The view to destroy
5729 */
5730function destroyViewTree(rootView) {
5731 // If the view has no children, we can clean it up and return early.
5732 let lViewOrLContainer = rootView[CHILD_HEAD];
5733 if (!lViewOrLContainer) {
5734 return cleanUpView(rootView[TVIEW], rootView);
5735 }
5736 while (lViewOrLContainer) {
5737 let next = null;
5738 if (isLView(lViewOrLContainer)) {
5739 // If LView, traverse down to child.
5740 next = lViewOrLContainer[CHILD_HEAD];
5741 }
5742 else {
5743 ngDevMode && assertLContainer(lViewOrLContainer);
5744 // If container, traverse down to its first LView.
5745 const firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET];
5746 if (firstView)
5747 next = firstView;
5748 }
5749 if (!next) {
5750 // Only clean up view when moving to the side or up, as destroy hooks
5751 // should be called in order from the bottom up.
5752 while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) {
5753 if (isLView(lViewOrLContainer)) {
5754 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
5755 }
5756 lViewOrLContainer = lViewOrLContainer[PARENT];
5757 }
5758 if (lViewOrLContainer === null)
5759 lViewOrLContainer = rootView;
5760 if (isLView(lViewOrLContainer)) {
5761 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
5762 }
5763 next = lViewOrLContainer && lViewOrLContainer[NEXT];
5764 }
5765 lViewOrLContainer = next;
5766 }
5767}
5768/**
5769 * Inserts a view into a container.
5770 *
5771 * This adds the view to the container's array of active views in the correct
5772 * position. It also adds the view's elements to the DOM if the container isn't a
5773 * root node of another view (in that case, the view's elements will be added when
5774 * the container's parent view is added later).
5775 *
5776 * @param tView The `TView' of the `LView` to insert
5777 * @param lView The view to insert
5778 * @param lContainer The container into which the view should be inserted
5779 * @param index Which index in the container to insert the child view into
5780 */
5781function insertView(tView, lView, lContainer, index) {
5782 ngDevMode && assertLView(lView);
5783 ngDevMode && assertLContainer(lContainer);
5784 const indexInContainer = CONTAINER_HEADER_OFFSET + index;
5785 const containerLength = lContainer.length;
5786 if (index > 0) {
5787 // This is a new view, we need to add it to the children.
5788 lContainer[indexInContainer - 1][NEXT] = lView;
5789 }
5790 if (index < containerLength - CONTAINER_HEADER_OFFSET) {
5791 lView[NEXT] = lContainer[indexInContainer];
5792 addToArray(lContainer, CONTAINER_HEADER_OFFSET + index, lView);
5793 }
5794 else {
5795 lContainer.push(lView);
5796 lView[NEXT] = null;
5797 }
5798 lView[PARENT] = lContainer;
5799 // track views where declaration and insertion points are different
5800 const declarationLContainer = lView[DECLARATION_LCONTAINER];
5801 if (declarationLContainer !== null && lContainer !== declarationLContainer) {
5802 trackMovedView(declarationLContainer, lView);
5803 }
5804 // notify query that a new view has been added
5805 const lQueries = lView[QUERIES];
5806 if (lQueries !== null) {
5807 lQueries.insertView(tView);
5808 }
5809 // Sets the attached flag
5810 lView[FLAGS] |= 64 /* LViewFlags.Attached */;
5811}
5812/**
5813 * Track views created from the declaration container (TemplateRef) and inserted into a
5814 * different LContainer.
5815 */
5816function trackMovedView(declarationContainer, lView) {
5817 ngDevMode && assertDefined(lView, 'LView required');
5818 ngDevMode && assertLContainer(declarationContainer);
5819 const movedViews = declarationContainer[MOVED_VIEWS];
5820 const insertedLContainer = lView[PARENT];
5821 ngDevMode && assertLContainer(insertedLContainer);
5822 const insertedComponentLView = insertedLContainer[PARENT][DECLARATION_COMPONENT_VIEW];
5823 ngDevMode && assertDefined(insertedComponentLView, 'Missing insertedComponentLView');
5824 const declaredComponentLView = lView[DECLARATION_COMPONENT_VIEW];
5825 ngDevMode && assertDefined(declaredComponentLView, 'Missing declaredComponentLView');
5826 if (declaredComponentLView !== insertedComponentLView) {
5827 // At this point the declaration-component is not same as insertion-component; this means that
5828 // this is a transplanted view. Mark the declared lView as having transplanted views so that
5829 // those views can participate in CD.
5830 declarationContainer[HAS_TRANSPLANTED_VIEWS] = true;
5831 }
5832 if (movedViews === null) {
5833 declarationContainer[MOVED_VIEWS] = [lView];
5834 }
5835 else {
5836 movedViews.push(lView);
5837 }
5838}
5839function detachMovedView(declarationContainer, lView) {
5840 ngDevMode && assertLContainer(declarationContainer);
5841 ngDevMode &&
5842 assertDefined(declarationContainer[MOVED_VIEWS], 'A projected view should belong to a non-empty projected views collection');
5843 const movedViews = declarationContainer[MOVED_VIEWS];
5844 const declarationViewIndex = movedViews.indexOf(lView);
5845 const insertionLContainer = lView[PARENT];
5846 ngDevMode && assertLContainer(insertionLContainer);
5847 // If the view was marked for refresh but then detached before it was checked (where the flag
5848 // would be cleared and the counter decremented), we need to decrement the view counter here
5849 // instead.
5850 if (lView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
5851 lView[FLAGS] &= ~512 /* LViewFlags.RefreshTransplantedView */;
5852 updateTransplantedViewCount(insertionLContainer, -1);
5853 }
5854 movedViews.splice(declarationViewIndex, 1);
5855}
5856/**
5857 * Detaches a view from a container.
5858 *
5859 * This method removes the view from the container's array of active views. It also
5860 * removes the view's elements from the DOM.
5861 *
5862 * @param lContainer The container from which to detach a view
5863 * @param removeIndex The index of the view to detach
5864 * @returns Detached LView instance.
5865 */
5866function detachView(lContainer, removeIndex) {
5867 if (lContainer.length <= CONTAINER_HEADER_OFFSET)
5868 return;
5869 const indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
5870 const viewToDetach = lContainer[indexInContainer];
5871 if (viewToDetach) {
5872 const declarationLContainer = viewToDetach[DECLARATION_LCONTAINER];
5873 if (declarationLContainer !== null && declarationLContainer !== lContainer) {
5874 detachMovedView(declarationLContainer, viewToDetach);
5875 }
5876 if (removeIndex > 0) {
5877 lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT];
5878 }
5879 const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
5880 removeViewFromContainer(viewToDetach[TVIEW], viewToDetach);
5881 // notify query that a view has been removed
5882 const lQueries = removedLView[QUERIES];
5883 if (lQueries !== null) {
5884 lQueries.detachView(removedLView[TVIEW]);
5885 }
5886 viewToDetach[PARENT] = null;
5887 viewToDetach[NEXT] = null;
5888 // Unsets the attached flag
5889 viewToDetach[FLAGS] &= ~64 /* LViewFlags.Attached */;
5890 }
5891 return viewToDetach;
5892}
5893/**
5894 * A standalone function which destroys an LView,
5895 * conducting clean up (e.g. removing listeners, calling onDestroys).
5896 *
5897 * @param tView The `TView' of the `LView` to be destroyed
5898 * @param lView The view to be destroyed.
5899 */
5900function destroyLView(tView, lView) {
5901 if (!(lView[FLAGS] & 128 /* LViewFlags.Destroyed */)) {
5902 const renderer = lView[RENDERER];
5903 if (renderer.destroyNode) {
5904 applyView(tView, lView, renderer, 3 /* WalkTNodeTreeAction.Destroy */, null, null);
5905 }
5906 destroyViewTree(lView);
5907 }
5908}
5909/**
5910 * Calls onDestroys hooks for all directives and pipes in a given view and then removes all
5911 * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks
5912 * can be propagated to @Output listeners.
5913 *
5914 * @param tView `TView` for the `LView` to clean up.
5915 * @param lView The LView to clean up
5916 */
5917function cleanUpView(tView, lView) {
5918 if (!(lView[FLAGS] & 128 /* LViewFlags.Destroyed */)) {
5919 // Usually the Attached flag is removed when the view is detached from its parent, however
5920 // if it's a root view, the flag won't be unset hence why we're also removing on destroy.
5921 lView[FLAGS] &= ~64 /* LViewFlags.Attached */;
5922 // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
5923 // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
5924 // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
5925 // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
5926 // really more of an "afterDestroy" hook if you think about it.
5927 lView[FLAGS] |= 128 /* LViewFlags.Destroyed */;
5928 executeOnDestroys(tView, lView);
5929 processCleanups(tView, lView);
5930 // For component views only, the local renderer is destroyed at clean up time.
5931 if (lView[TVIEW].type === 1 /* TViewType.Component */) {
5932 ngDevMode && ngDevMode.rendererDestroy++;
5933 lView[RENDERER].destroy();
5934 }
5935 const declarationContainer = lView[DECLARATION_LCONTAINER];
5936 // we are dealing with an embedded view that is still inserted into a container
5937 if (declarationContainer !== null && isLContainer(lView[PARENT])) {
5938 // and this is a projected view
5939 if (declarationContainer !== lView[PARENT]) {
5940 detachMovedView(declarationContainer, lView);
5941 }
5942 // For embedded views still attached to a container: remove query result from this view.
5943 const lQueries = lView[QUERIES];
5944 if (lQueries !== null) {
5945 lQueries.detachView(tView);
5946 }
5947 }
5948 // Unregister the view once everything else has been cleaned up.
5949 unregisterLView(lView);
5950 }
5951}
5952/** Removes listeners and unsubscribes from output subscriptions */
5953function processCleanups(tView, lView) {
5954 const tCleanup = tView.cleanup;
5955 const lCleanup = lView[CLEANUP];
5956 // `LCleanup` contains both share information with `TCleanup` as well as instance specific
5957 // information appended at the end. We need to know where the end of the `TCleanup` information
5958 // is, and we track this with `lastLCleanupIndex`.
5959 let lastLCleanupIndex = -1;
5960 if (tCleanup !== null) {
5961 for (let i = 0; i < tCleanup.length - 1; i += 2) {
5962 if (typeof tCleanup[i] === 'string') {
5963 // This is a native DOM listener. It will occupy 4 entries in the TCleanup array (hence i +=
5964 // 2 at the end of this block).
5965 const targetIdx = tCleanup[i + 3];
5966 ngDevMode && assertNumber(targetIdx, 'cleanup target must be a number');
5967 if (targetIdx >= 0) {
5968 // unregister
5969 lCleanup[lastLCleanupIndex = targetIdx]();
5970 }
5971 else {
5972 // Subscription
5973 lCleanup[lastLCleanupIndex = -targetIdx].unsubscribe();
5974 }
5975 i += 2;
5976 }
5977 else {
5978 // This is a cleanup function that is grouped with the index of its context
5979 const context = lCleanup[lastLCleanupIndex = tCleanup[i + 1]];
5980 tCleanup[i].call(context);
5981 }
5982 }
5983 }
5984 if (lCleanup !== null) {
5985 for (let i = lastLCleanupIndex + 1; i < lCleanup.length; i++) {
5986 const instanceCleanupFn = lCleanup[i];
5987 ngDevMode && assertFunction(instanceCleanupFn, 'Expecting instance cleanup function.');
5988 instanceCleanupFn();
5989 }
5990 lView[CLEANUP] = null;
5991 }
5992}
5993/** Calls onDestroy hooks for this view */
5994function executeOnDestroys(tView, lView) {
5995 let destroyHooks;
5996 if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
5997 for (let i = 0; i < destroyHooks.length; i += 2) {
5998 const context = lView[destroyHooks[i]];
5999 // Only call the destroy hook if the context has been requested.
6000 if (!(context instanceof NodeInjectorFactory)) {
6001 const toCall = destroyHooks[i + 1];
6002 if (Array.isArray(toCall)) {
6003 for (let j = 0; j < toCall.length; j += 2) {
6004 const callContext = context[toCall[j]];
6005 const hook = toCall[j + 1];
6006 profiler(4 /* ProfilerEvent.LifecycleHookStart */, callContext, hook);
6007 try {
6008 hook.call(callContext);
6009 }
6010 finally {
6011 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, callContext, hook);
6012 }
6013 }
6014 }
6015 else {
6016 profiler(4 /* ProfilerEvent.LifecycleHookStart */, context, toCall);
6017 try {
6018 toCall.call(context);
6019 }
6020 finally {
6021 profiler(5 /* ProfilerEvent.LifecycleHookEnd */, context, toCall);
6022 }
6023 }
6024 }
6025 }
6026 }
6027}
6028/**
6029 * Returns a native element if a node can be inserted into the given parent.
6030 *
6031 * There are two reasons why we may not be able to insert a element immediately.
6032 * - Projection: When creating a child content element of a component, we have to skip the
6033 * insertion because the content of a component will be projected.
6034 * `<component><content>delayed due to projection</content></component>`
6035 * - Parent container is disconnected: This can happen when we are inserting a view into
6036 * parent container, which itself is disconnected. For example the parent container is part
6037 * of a View which has not be inserted or is made for projection but has not been inserted
6038 * into destination.
6039 *
6040 * @param tView: Current `TView`.
6041 * @param tNode: `TNode` for which we wish to retrieve render parent.
6042 * @param lView: Current `LView`.
6043 */
6044function getParentRElement(tView, tNode, lView) {
6045 return getClosestRElement(tView, tNode.parent, lView);
6046}
6047/**
6048 * Get closest `RElement` or `null` if it can't be found.
6049 *
6050 * If `TNode` is `TNodeType.Element` => return `RElement` at `LView[tNode.index]` location.
6051 * If `TNode` is `TNodeType.ElementContainer|IcuContain` => return the parent (recursively).
6052 * If `TNode` is `null` then return host `RElement`:
6053 * - return `null` if projection
6054 * - return `null` if parent container is disconnected (we have no parent.)
6055 *
6056 * @param tView: Current `TView`.
6057 * @param tNode: `TNode` for which we wish to retrieve `RElement` (or `null` if host element is
6058 * needed).
6059 * @param lView: Current `LView`.
6060 * @returns `null` if the `RElement` can't be determined at this time (no parent / projection)
6061 */
6062function getClosestRElement(tView, tNode, lView) {
6063 let parentTNode = tNode;
6064 // Skip over element and ICU containers as those are represented by a comment node and
6065 // can't be used as a render parent.
6066 while (parentTNode !== null &&
6067 (parentTNode.type & (8 /* TNodeType.ElementContainer */ | 32 /* TNodeType.Icu */))) {
6068 tNode = parentTNode;
6069 parentTNode = tNode.parent;
6070 }
6071 // If the parent tNode is null, then we are inserting across views: either into an embedded view
6072 // or a component view.
6073 if (parentTNode === null) {
6074 // We are inserting a root element of the component view into the component host element and
6075 // it should always be eager.
6076 return lView[HOST];
6077 }
6078 else {
6079 ngDevMode && assertTNodeType(parentTNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
6080 const { componentOffset } = parentTNode;
6081 if (componentOffset > -1) {
6082 ngDevMode && assertTNodeForLView(parentTNode, lView);
6083 const { encapsulation } = tView.data[parentTNode.directiveStart + componentOffset];
6084 // We've got a parent which is an element in the current view. We just need to verify if the
6085 // parent element is not a component. Component's content nodes are not inserted immediately
6086 // because they will be projected, and so doing insert at this point would be wasteful.
6087 // Since the projection would then move it to its final destination. Note that we can't
6088 // make this assumption when using the Shadow DOM, because the native projection placeholders
6089 // (<content> or <slot>) have to be in place as elements are being inserted.
6090 if (encapsulation === ViewEncapsulation$1.None ||
6091 encapsulation === ViewEncapsulation$1.Emulated) {
6092 return null;
6093 }
6094 }
6095 return getNativeByTNode(parentTNode, lView);
6096 }
6097}
6098/**
6099 * Inserts a native node before another native node for a given parent.
6100 * This is a utility function that can be used when native nodes were determined.
6101 */
6102function nativeInsertBefore(renderer, parent, child, beforeNode, isMove) {
6103 ngDevMode && ngDevMode.rendererInsertBefore++;
6104 renderer.insertBefore(parent, child, beforeNode, isMove);
6105}
6106function nativeAppendChild(renderer, parent, child) {
6107 ngDevMode && ngDevMode.rendererAppendChild++;
6108 ngDevMode && assertDefined(parent, 'parent node must be defined');
6109 renderer.appendChild(parent, child);
6110}
6111function nativeAppendOrInsertBefore(renderer, parent, child, beforeNode, isMove) {
6112 if (beforeNode !== null) {
6113 nativeInsertBefore(renderer, parent, child, beforeNode, isMove);
6114 }
6115 else {
6116 nativeAppendChild(renderer, parent, child);
6117 }
6118}
6119/** Removes a node from the DOM given its native parent. */
6120function nativeRemoveChild(renderer, parent, child, isHostElement) {
6121 renderer.removeChild(parent, child, isHostElement);
6122}
6123/** Checks if an element is a `<template>` node. */
6124function isTemplateNode(node) {
6125 return node.tagName === 'TEMPLATE' && node.content !== undefined;
6126}
6127/**
6128 * Returns a native parent of a given native node.
6129 */
6130function nativeParentNode(renderer, node) {
6131 return renderer.parentNode(node);
6132}
6133/**
6134 * Returns a native sibling of a given native node.
6135 */
6136function nativeNextSibling(renderer, node) {
6137 return renderer.nextSibling(node);
6138}
6139/**
6140 * Find a node in front of which `currentTNode` should be inserted.
6141 *
6142 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
6143 * takes `TNode.insertBeforeIndex` into account if i18n code has been invoked.
6144 *
6145 * @param parentTNode parent `TNode`
6146 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
6147 * @param lView current `LView`
6148 */
6149function getInsertInFrontOfRNode(parentTNode, currentTNode, lView) {
6150 return _getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView);
6151}
6152/**
6153 * Find a node in front of which `currentTNode` should be inserted. (Does not take i18n into
6154 * account)
6155 *
6156 * This method determines the `RNode` in front of which we should insert the `currentRNode`. This
6157 * does not take `TNode.insertBeforeIndex` into account.
6158 *
6159 * @param parentTNode parent `TNode`
6160 * @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
6161 * @param lView current `LView`
6162 */
6163function getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView) {
6164 if (parentTNode.type & (8 /* TNodeType.ElementContainer */ | 32 /* TNodeType.Icu */)) {
6165 return getNativeByTNode(parentTNode, lView);
6166 }
6167 return null;
6168}
6169/**
6170 * Tree shakable boundary for `getInsertInFrontOfRNodeWithI18n` function.
6171 *
6172 * This function will only be set if i18n code runs.
6173 */
6174let _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithNoI18n;
6175/**
6176 * Tree shakable boundary for `processI18nInsertBefore` function.
6177 *
6178 * This function will only be set if i18n code runs.
6179 */
6180let _processI18nInsertBefore;
6181function setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore) {
6182 _getInsertInFrontOfRNodeWithI18n = getInsertInFrontOfRNodeWithI18n;
6183 _processI18nInsertBefore = processI18nInsertBefore;
6184}
6185/**
6186 * Appends the `child` native node (or a collection of nodes) to the `parent`.
6187 *
6188 * @param tView The `TView' to be appended
6189 * @param lView The current LView
6190 * @param childRNode The native child (or children) that should be appended
6191 * @param childTNode The TNode of the child element
6192 */
6193function appendChild(tView, lView, childRNode, childTNode) {
6194 const parentRNode = getParentRElement(tView, childTNode, lView);
6195 const renderer = lView[RENDERER];
6196 const parentTNode = childTNode.parent || lView[T_HOST];
6197 const anchorNode = getInsertInFrontOfRNode(parentTNode, childTNode, lView);
6198 if (parentRNode != null) {
6199 if (Array.isArray(childRNode)) {
6200 for (let i = 0; i < childRNode.length; i++) {
6201 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode[i], anchorNode, false);
6202 }
6203 }
6204 else {
6205 nativeAppendOrInsertBefore(renderer, parentRNode, childRNode, anchorNode, false);
6206 }
6207 }
6208 _processI18nInsertBefore !== undefined &&
6209 _processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRNode);
6210}
6211/**
6212 * Returns the first native node for a given LView, starting from the provided TNode.
6213 *
6214 * Native nodes are returned in the order in which those appear in the native tree (DOM).
6215 */
6216function getFirstNativeNode(lView, tNode) {
6217 if (tNode !== null) {
6218 ngDevMode &&
6219 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 32 /* TNodeType.Icu */ | 16 /* TNodeType.Projection */);
6220 const tNodeType = tNode.type;
6221 if (tNodeType & 3 /* TNodeType.AnyRNode */) {
6222 return getNativeByTNode(tNode, lView);
6223 }
6224 else if (tNodeType & 4 /* TNodeType.Container */) {
6225 return getBeforeNodeForView(-1, lView[tNode.index]);
6226 }
6227 else if (tNodeType & 8 /* TNodeType.ElementContainer */) {
6228 const elIcuContainerChild = tNode.child;
6229 if (elIcuContainerChild !== null) {
6230 return getFirstNativeNode(lView, elIcuContainerChild);
6231 }
6232 else {
6233 const rNodeOrLContainer = lView[tNode.index];
6234 if (isLContainer(rNodeOrLContainer)) {
6235 return getBeforeNodeForView(-1, rNodeOrLContainer);
6236 }
6237 else {
6238 return unwrapRNode(rNodeOrLContainer);
6239 }
6240 }
6241 }
6242 else if (tNodeType & 32 /* TNodeType.Icu */) {
6243 let nextRNode = icuContainerIterate(tNode, lView);
6244 let rNode = nextRNode();
6245 // If the ICU container has no nodes, than we use the ICU anchor as the node.
6246 return rNode || unwrapRNode(lView[tNode.index]);
6247 }
6248 else {
6249 const projectionNodes = getProjectionNodes(lView, tNode);
6250 if (projectionNodes !== null) {
6251 if (Array.isArray(projectionNodes)) {
6252 return projectionNodes[0];
6253 }
6254 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
6255 ngDevMode && assertParentView(parentView);
6256 return getFirstNativeNode(parentView, projectionNodes);
6257 }
6258 else {
6259 return getFirstNativeNode(lView, tNode.next);
6260 }
6261 }
6262 }
6263 return null;
6264}
6265function getProjectionNodes(lView, tNode) {
6266 if (tNode !== null) {
6267 const componentView = lView[DECLARATION_COMPONENT_VIEW];
6268 const componentHost = componentView[T_HOST];
6269 const slotIdx = tNode.projection;
6270 ngDevMode && assertProjectionSlots(lView);
6271 return componentHost.projection[slotIdx];
6272 }
6273 return null;
6274}
6275function getBeforeNodeForView(viewIndexInContainer, lContainer) {
6276 const nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1;
6277 if (nextViewIndex < lContainer.length) {
6278 const lView = lContainer[nextViewIndex];
6279 const firstTNodeOfView = lView[TVIEW].firstChild;
6280 if (firstTNodeOfView !== null) {
6281 return getFirstNativeNode(lView, firstTNodeOfView);
6282 }
6283 }
6284 return lContainer[NATIVE];
6285}
6286/**
6287 * Removes a native node itself using a given renderer. To remove the node we are looking up its
6288 * parent from the native tree as not all platforms / browsers support the equivalent of
6289 * node.remove().
6290 *
6291 * @param renderer A renderer to be used
6292 * @param rNode The native node that should be removed
6293 * @param isHostElement A flag indicating if a node to be removed is a host of a component.
6294 */
6295function nativeRemoveNode(renderer, rNode, isHostElement) {
6296 ngDevMode && ngDevMode.rendererRemoveNode++;
6297 const nativeParent = nativeParentNode(renderer, rNode);
6298 if (nativeParent) {
6299 nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
6300 }
6301}
6302/**
6303 * Performs the operation of `action` on the node. Typically this involves inserting or removing
6304 * nodes on the LView or projection boundary.
6305 */
6306function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode, isProjection) {
6307 while (tNode != null) {
6308 ngDevMode && assertTNodeForLView(tNode, lView);
6309 ngDevMode &&
6310 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
6311 const rawSlotValue = lView[tNode.index];
6312 const tNodeType = tNode.type;
6313 if (isProjection) {
6314 if (action === 0 /* WalkTNodeTreeAction.Create */) {
6315 rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
6316 tNode.flags |= 2 /* TNodeFlags.isProjected */;
6317 }
6318 }
6319 if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
6320 if (tNodeType & 8 /* TNodeType.ElementContainer */) {
6321 applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
6322 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
6323 }
6324 else if (tNodeType & 32 /* TNodeType.Icu */) {
6325 const nextRNode = icuContainerIterate(tNode, lView);
6326 let rNode;
6327 while (rNode = nextRNode()) {
6328 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
6329 }
6330 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
6331 }
6332 else if (tNodeType & 16 /* TNodeType.Projection */) {
6333 applyProjectionRecursive(renderer, action, lView, tNode, parentRElement, beforeNode);
6334 }
6335 else {
6336 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
6337 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
6338 }
6339 }
6340 tNode = isProjection ? tNode.projectionNext : tNode.next;
6341 }
6342}
6343function applyView(tView, lView, renderer, action, parentRElement, beforeNode) {
6344 applyNodes(renderer, action, tView.firstChild, lView, parentRElement, beforeNode, false);
6345}
6346/**
6347 * `applyProjection` performs operation on the projection.
6348 *
6349 * Inserting a projection requires us to locate the projected nodes from the parent component. The
6350 * complication is that those nodes themselves could be re-projected from their parent component.
6351 *
6352 * @param tView The `TView` of `LView` which needs to be inserted, detached, destroyed
6353 * @param lView The `LView` which needs to be inserted, detached, destroyed.
6354 * @param tProjectionNode node to project
6355 */
6356function applyProjection(tView, lView, tProjectionNode) {
6357 const renderer = lView[RENDERER];
6358 const parentRNode = getParentRElement(tView, tProjectionNode, lView);
6359 const parentTNode = tProjectionNode.parent || lView[T_HOST];
6360 let beforeNode = getInsertInFrontOfRNode(parentTNode, tProjectionNode, lView);
6361 applyProjectionRecursive(renderer, 0 /* WalkTNodeTreeAction.Create */, lView, tProjectionNode, parentRNode, beforeNode);
6362}
6363/**
6364 * `applyProjectionRecursive` performs operation on the projection specified by `action` (insert,
6365 * detach, destroy)
6366 *
6367 * Inserting a projection requires us to locate the projected nodes from the parent component. The
6368 * complication is that those nodes themselves could be re-projected from their parent component.
6369 *
6370 * @param renderer Render to use
6371 * @param action action to perform (insert, detach, destroy)
6372 * @param lView The LView which needs to be inserted, detached, destroyed.
6373 * @param tProjectionNode node to project
6374 * @param parentRElement parent DOM element for insertion/removal.
6375 * @param beforeNode Before which node the insertions should happen.
6376 */
6377function applyProjectionRecursive(renderer, action, lView, tProjectionNode, parentRElement, beforeNode) {
6378 const componentLView = lView[DECLARATION_COMPONENT_VIEW];
6379 const componentNode = componentLView[T_HOST];
6380 ngDevMode &&
6381 assertEqual(typeof tProjectionNode.projection, 'number', 'expecting projection index');
6382 const nodeToProjectOrRNodes = componentNode.projection[tProjectionNode.projection];
6383 if (Array.isArray(nodeToProjectOrRNodes)) {
6384 // This should not exist, it is a bit of a hack. When we bootstrap a top level node and we
6385 // need to support passing projectable nodes, so we cheat and put them in the TNode
6386 // of the Host TView. (Yes we put instance info at the T Level). We can get away with it
6387 // because we know that that TView is not shared and therefore it will not be a problem.
6388 // This should be refactored and cleaned up.
6389 for (let i = 0; i < nodeToProjectOrRNodes.length; i++) {
6390 const rNode = nodeToProjectOrRNodes[i];
6391 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
6392 }
6393 }
6394 else {
6395 let nodeToProject = nodeToProjectOrRNodes;
6396 const projectedComponentLView = componentLView[PARENT];
6397 applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
6398 }
6399}
6400/**
6401 * `applyContainer` performs an operation on the container and its views as specified by
6402 * `action` (insert, detach, destroy)
6403 *
6404 * Inserting a Container is complicated by the fact that the container may have Views which
6405 * themselves have containers or projections.
6406 *
6407 * @param renderer Renderer to use
6408 * @param action action to perform (insert, detach, destroy)
6409 * @param lContainer The LContainer which needs to be inserted, detached, destroyed.
6410 * @param parentRElement parent DOM element for insertion/removal.
6411 * @param beforeNode Before which node the insertions should happen.
6412 */
6413function applyContainer(renderer, action, lContainer, parentRElement, beforeNode) {
6414 ngDevMode && assertLContainer(lContainer);
6415 const anchor = lContainer[NATIVE]; // LContainer has its own before node.
6416 const native = unwrapRNode(lContainer);
6417 // An LContainer can be created dynamically on any node by injecting ViewContainerRef.
6418 // Asking for a ViewContainerRef on an element will result in a creation of a separate anchor
6419 // node (comment in the DOM) that will be different from the LContainer's host node. In this
6420 // particular case we need to execute action on 2 nodes:
6421 // - container's host node (this is done in the executeActionOnElementOrContainer)
6422 // - container's host node (this is done here)
6423 if (anchor !== native) {
6424 // This is very strange to me (Misko). I would expect that the native is same as anchor. I
6425 // don't see a reason why they should be different, but they are.
6426 //
6427 // If they are we need to process the second anchor as well.
6428 applyToElementOrContainer(action, renderer, parentRElement, anchor, beforeNode);
6429 }
6430 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
6431 const lView = lContainer[i];
6432 applyView(lView[TVIEW], lView, renderer, action, parentRElement, anchor);
6433 }
6434}
6435/**
6436 * Writes class/style to element.
6437 *
6438 * @param renderer Renderer to use.
6439 * @param isClassBased `true` if it should be written to `class` (`false` to write to `style`)
6440 * @param rNode The Node to write to.
6441 * @param prop Property to write to. This would be the class/style name.
6442 * @param value Value to write. If `null`/`undefined`/`false` this is considered a remove (set/add
6443 * otherwise).
6444 */
6445function applyStyling(renderer, isClassBased, rNode, prop, value) {
6446 if (isClassBased) {
6447 // We actually want JS true/false here because any truthy value should add the class
6448 if (!value) {
6449 ngDevMode && ngDevMode.rendererRemoveClass++;
6450 renderer.removeClass(rNode, prop);
6451 }
6452 else {
6453 ngDevMode && ngDevMode.rendererAddClass++;
6454 renderer.addClass(rNode, prop);
6455 }
6456 }
6457 else {
6458 let flags = prop.indexOf('-') === -1 ? undefined : RendererStyleFlags2.DashCase;
6459 if (value == null /** || value === undefined */) {
6460 ngDevMode && ngDevMode.rendererRemoveStyle++;
6461 renderer.removeStyle(rNode, prop, flags);
6462 }
6463 else {
6464 // A value is important if it ends with `!important`. The style
6465 // parser strips any semicolons at the end of the value.
6466 const isImportant = typeof value === 'string' ? value.endsWith('!important') : false;
6467 if (isImportant) {
6468 // !important has to be stripped from the value for it to be valid.
6469 value = value.slice(0, -10);
6470 flags |= RendererStyleFlags2.Important;
6471 }
6472 ngDevMode && ngDevMode.rendererSetStyle++;
6473 renderer.setStyle(rNode, prop, value, flags);
6474 }
6475 }
6476}
6477/**
6478 * Write `cssText` to `RElement`.
6479 *
6480 * This function does direct write without any reconciliation. Used for writing initial values, so
6481 * that static styling values do not pull in the style parser.
6482 *
6483 * @param renderer Renderer to use
6484 * @param element The element which needs to be updated.
6485 * @param newValue The new class list to write.
6486 */
6487function writeDirectStyle(renderer, element, newValue) {
6488 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
6489 renderer.setAttribute(element, 'style', newValue);
6490 ngDevMode && ngDevMode.rendererSetStyle++;
6491}
6492/**
6493 * Write `className` to `RElement`.
6494 *
6495 * This function does direct write without any reconciliation. Used for writing initial values, so
6496 * that static styling values do not pull in the style parser.
6497 *
6498 * @param renderer Renderer to use
6499 * @param element The element which needs to be updated.
6500 * @param newValue The new class list to write.
6501 */
6502function writeDirectClass(renderer, element, newValue) {
6503 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
6504 if (newValue === '') {
6505 // There are tests in `google3` which expect `element.getAttribute('class')` to be `null`.
6506 renderer.removeAttribute(element, 'class');
6507 }
6508 else {
6509 renderer.setAttribute(element, 'class', newValue);
6510 }
6511 ngDevMode && ngDevMode.rendererSetClassName++;
6512}
6513/** Sets up the static DOM attributes on an `RNode`. */
6514function setupStaticAttributes(renderer, element, tNode) {
6515 const { mergedAttrs, classes, styles } = tNode;
6516 if (mergedAttrs !== null) {
6517 setUpAttributes(renderer, element, mergedAttrs);
6518 }
6519 if (classes !== null) {
6520 writeDirectClass(renderer, element, classes);
6521 }
6522 if (styles !== null) {
6523 writeDirectStyle(renderer, element, styles);
6524 }
6525}
6526
6527/**
6528 * @fileoverview
6529 * A module to facilitate use of a Trusted Types policy internally within
6530 * Angular. It lazily constructs the Trusted Types policy, providing helper
6531 * utilities for promoting strings to Trusted Types. When Trusted Types are not
6532 * available, strings are used as a fallback.
6533 * @security All use of this module is security-sensitive and should go through
6534 * security review.
6535 */
6536/**
6537 * The Trusted Types policy, or null if Trusted Types are not
6538 * enabled/supported, or undefined if the policy has not been created yet.
6539 */
6540let policy$1;
6541/**
6542 * Returns the Trusted Types policy, or null if Trusted Types are not
6543 * enabled/supported. The first call to this function will create the policy.
6544 */
6545function getPolicy$1() {
6546 if (policy$1 === undefined) {
6547 policy$1 = null;
6548 if (_global.trustedTypes) {
6549 try {
6550 policy$1 = _global.trustedTypes.createPolicy('angular', {
6551 createHTML: (s) => s,
6552 createScript: (s) => s,
6553 createScriptURL: (s) => s,
6554 });
6555 }
6556 catch (_a) {
6557 // trustedTypes.createPolicy throws if called with a name that is
6558 // already registered, even in report-only mode. Until the API changes,
6559 // catch the error not to break the applications functionally. In such
6560 // cases, the code will fall back to using strings.
6561 }
6562 }
6563 }
6564 return policy$1;
6565}
6566/**
6567 * Unsafely promote a string to a TrustedHTML, falling back to strings when
6568 * Trusted Types are not available.
6569 * @security This is a security-sensitive function; any use of this function
6570 * must go through security review. In particular, it must be assured that the
6571 * provided string will never cause an XSS vulnerability if used in a context
6572 * that will be interpreted as HTML by a browser, e.g. when assigning to
6573 * element.innerHTML.
6574 */
6575function trustedHTMLFromString(html) {
6576 var _a;
6577 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createHTML(html)) || html;
6578}
6579/**
6580 * Unsafely promote a string to a TrustedScript, falling back to strings when
6581 * Trusted Types are not available.
6582 * @security In particular, it must be assured that the provided string will
6583 * never cause an XSS vulnerability if used in a context that will be
6584 * interpreted and executed as a script by a browser, e.g. when calling eval.
6585 */
6586function trustedScriptFromString(script) {
6587 var _a;
6588 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
6589}
6590/**
6591 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
6592 * when Trusted Types are not available.
6593 * @security This is a security-sensitive function; any use of this function
6594 * must go through security review. In particular, it must be assured that the
6595 * provided string will never cause an XSS vulnerability if used in a context
6596 * that will cause a browser to load and execute a resource, e.g. when
6597 * assigning to script.src.
6598 */
6599function trustedScriptURLFromString(url) {
6600 var _a;
6601 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScriptURL(url)) || url;
6602}
6603/**
6604 * Unsafely call the Function constructor with the given string arguments. It
6605 * is only available in development mode, and should be stripped out of
6606 * production code.
6607 * @security This is a security-sensitive function; any use of this function
6608 * must go through security review. In particular, it must be assured that it
6609 * is only called from development code, as use in production code can lead to
6610 * XSS vulnerabilities.
6611 */
6612function newTrustedFunctionForDev(...args) {
6613 if (typeof ngDevMode === 'undefined') {
6614 throw new Error('newTrustedFunctionForDev should never be called in production');
6615 }
6616 if (!_global.trustedTypes) {
6617 // In environments that don't support Trusted Types, fall back to the most
6618 // straightforward implementation:
6619 return new Function(...args);
6620 }
6621 // Chrome currently does not support passing TrustedScript to the Function
6622 // constructor. The following implements the workaround proposed on the page
6623 // below, where the Chromium bug is also referenced:
6624 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
6625 const fnArgs = args.slice(0, -1).join(',');
6626 const fnBody = args[args.length - 1];
6627 const body = `(function anonymous(${fnArgs}
6628) { ${fnBody}
6629})`;
6630 // Using eval directly confuses the compiler and prevents this module from
6631 // being stripped out of JS binaries even if not used. The global['eval']
6632 // indirection fixes that.
6633 const fn = _global['eval'](trustedScriptFromString(body));
6634 if (fn.bind === undefined) {
6635 // Workaround for a browser bug that only exists in Chrome 83, where passing
6636 // a TrustedScript to eval just returns the TrustedScript back without
6637 // evaluating it. In that case, fall back to the most straightforward
6638 // implementation:
6639 return new Function(...args);
6640 }
6641 // To completely mimic the behavior of calling "new Function", two more
6642 // things need to happen:
6643 // 1. Stringifying the resulting function should return its source code
6644 fn.toString = () => body;
6645 // 2. When calling the resulting function, `this` should refer to `global`
6646 return fn.bind(_global);
6647 // When Trusted Types support in Function constructors is widely available,
6648 // the implementation of this function can be simplified to:
6649 // return new Function(...args.map(a => trustedScriptFromString(a)));
6650}
6651
6652/**
6653 * Validation function invoked at runtime for each binding that might potentially
6654 * represent a security-sensitive attribute of an <iframe>.
6655 * See `IFRAME_SECURITY_SENSITIVE_ATTRS` in the
6656 * `packages/compiler/src/schema/dom_security_schema.ts` script for the full list
6657 * of such attributes.
6658 *
6659 * @codeGenApi
6660 */
6661function ɵɵvalidateIframeAttribute(attrValue, tagName, attrName) {
6662 const lView = getLView();
6663 const tNode = getSelectedTNode();
6664 const element = getNativeByTNode(tNode, lView);
6665 // Restrict any dynamic bindings of security-sensitive attributes/properties
6666 // on an <iframe> for security reasons.
6667 if (tNode.type === 2 /* TNodeType.Element */ && tagName.toLowerCase() === 'iframe') {
6668 const iframe = element;
6669 // Unset previously applied `src` and `srcdoc` if we come across a situation when
6670 // a security-sensitive attribute is set later via an attribute/property binding.
6671 iframe.src = '';
6672 iframe.srcdoc = trustedHTMLFromString('');
6673 // Also remove the <iframe> from the document.
6674 nativeRemoveNode(lView[RENDERER], iframe);
6675 const errorMessage = ngDevMode &&
6676 `Angular has detected that the \`${attrName}\` was applied ` +
6677 `as a binding to an <iframe>${getTemplateLocationDetails(lView)}. ` +
6678 `For security reasons, the \`${attrName}\` can be set on an <iframe> ` +
6679 `as a static attribute only. \n` +
6680 `To fix this, switch the \`${attrName}\` binding to a static attribute ` +
6681 `in a template or in host bindings section.`;
6682 throw new RuntimeError(-910 /* RuntimeErrorCode.UNSAFE_IFRAME_ATTRS */, errorMessage);
6683 }
6684 return attrValue;
6685}
6686
6687/**
6688 * Most of the use of `document` in Angular is from within the DI system so it is possible to simply
6689 * inject the `DOCUMENT` token and are done.
6690 *
6691 * Ivy is special because it does not rely upon the DI and must get hold of the document some other
6692 * way.
6693 *
6694 * The solution is to define `getDocument()` and `setDocument()` top-level functions for ivy.
6695 * Wherever ivy needs the global document, it calls `getDocument()` instead.
6696 *
6697 * When running ivy outside of a browser environment, it is necessary to call `setDocument()` to
6698 * tell ivy what the global `document` is.
6699 *
6700 * Angular does this for us in each of the standard platforms (`Browser`, `Server`, and `WebWorker`)
6701 * by calling `setDocument()` when providing the `DOCUMENT` token.
6702 */
6703let DOCUMENT = undefined;
6704/**
6705 * Tell ivy what the `document` is for this platform.
6706 *
6707 * It is only necessary to call this if the current platform is not a browser.
6708 *
6709 * @param document The object representing the global `document` in this environment.
6710 */
6711function setDocument(document) {
6712 DOCUMENT = document;
6713}
6714/**
6715 * Access the object that represents the `document` for this platform.
6716 *
6717 * Ivy calls this whenever it needs to access the `document` object.
6718 * For example to create the renderer or to do sanitization.
6719 */
6720function getDocument() {
6721 if (DOCUMENT !== undefined) {
6722 return DOCUMENT;
6723 }
6724 else if (typeof document !== 'undefined') {
6725 return document;
6726 }
6727 // No "document" can be found. This should only happen if we are running ivy outside Angular and
6728 // the current platform is not a browser. Since this is not a supported scenario at the moment
6729 // this should not happen in Angular apps.
6730 // Once we support running ivy outside of Angular we will need to publish `setDocument()` as a
6731 // public API. Meanwhile we just return `undefined` and let the application fail.
6732 return undefined;
6733}
6734
6735/**
6736 * @fileoverview
6737 * A module to facilitate use of a Trusted Types policy internally within
6738 * Angular specifically for bypassSecurityTrust* and custom sanitizers. It
6739 * lazily constructs the Trusted Types policy, providing helper utilities for
6740 * promoting strings to Trusted Types. When Trusted Types are not available,
6741 * strings are used as a fallback.
6742 * @security All use of this module is security-sensitive and should go through
6743 * security review.
6744 */
6745/**
6746 * The Trusted Types policy, or null if Trusted Types are not
6747 * enabled/supported, or undefined if the policy has not been created yet.
6748 */
6749let policy;
6750/**
6751 * Returns the Trusted Types policy, or null if Trusted Types are not
6752 * enabled/supported. The first call to this function will create the policy.
6753 */
6754function getPolicy() {
6755 if (policy === undefined) {
6756 policy = null;
6757 if (_global.trustedTypes) {
6758 try {
6759 policy = _global.trustedTypes
6760 .createPolicy('angular#unsafe-bypass', {
6761 createHTML: (s) => s,
6762 createScript: (s) => s,
6763 createScriptURL: (s) => s,
6764 });
6765 }
6766 catch (_a) {
6767 // trustedTypes.createPolicy throws if called with a name that is
6768 // already registered, even in report-only mode. Until the API changes,
6769 // catch the error not to break the applications functionally. In such
6770 // cases, the code will fall back to using strings.
6771 }
6772 }
6773 }
6774 return policy;
6775}
6776/**
6777 * Unsafely promote a string to a TrustedHTML, falling back to strings when
6778 * Trusted Types are not available.
6779 * @security This is a security-sensitive function; any use of this function
6780 * must go through security review. In particular, it must be assured that it
6781 * is only passed strings that come directly from custom sanitizers or the
6782 * bypassSecurityTrust* functions.
6783 */
6784function trustedHTMLFromStringBypass(html) {
6785 var _a;
6786 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createHTML(html)) || html;
6787}
6788/**
6789 * Unsafely promote a string to a TrustedScript, falling back to strings when
6790 * Trusted Types are not available.
6791 * @security This is a security-sensitive function; any use of this function
6792 * must go through security review. In particular, it must be assured that it
6793 * is only passed strings that come directly from custom sanitizers or the
6794 * bypassSecurityTrust* functions.
6795 */
6796function trustedScriptFromStringBypass(script) {
6797 var _a;
6798 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
6799}
6800/**
6801 * Unsafely promote a string to a TrustedScriptURL, falling back to strings
6802 * when Trusted Types are not available.
6803 * @security This is a security-sensitive function; any use of this function
6804 * must go through security review. In particular, it must be assured that it
6805 * is only passed strings that come directly from custom sanitizers or the
6806 * bypassSecurityTrust* functions.
6807 */
6808function trustedScriptURLFromStringBypass(url) {
6809 var _a;
6810 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScriptURL(url)) || url;
6811}
6812
6813class SafeValueImpl {
6814 constructor(changingThisBreaksApplicationSecurity) {
6815 this.changingThisBreaksApplicationSecurity = changingThisBreaksApplicationSecurity;
6816 }
6817 toString() {
6818 return `SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity}` +
6819 ` (see ${XSS_SECURITY_URL})`;
6820 }
6821}
6822class SafeHtmlImpl extends SafeValueImpl {
6823 getTypeName() {
6824 return "HTML" /* BypassType.Html */;
6825 }
6826}
6827class SafeStyleImpl extends SafeValueImpl {
6828 getTypeName() {
6829 return "Style" /* BypassType.Style */;
6830 }
6831}
6832class SafeScriptImpl extends SafeValueImpl {
6833 getTypeName() {
6834 return "Script" /* BypassType.Script */;
6835 }
6836}
6837class SafeUrlImpl extends SafeValueImpl {
6838 getTypeName() {
6839 return "URL" /* BypassType.Url */;
6840 }
6841}
6842class SafeResourceUrlImpl extends SafeValueImpl {
6843 getTypeName() {
6844 return "ResourceURL" /* BypassType.ResourceUrl */;
6845 }
6846}
6847function unwrapSafeValue(value) {
6848 return value instanceof SafeValueImpl ? value.changingThisBreaksApplicationSecurity :
6849 value;
6850}
6851function allowSanitizationBypassAndThrow(value, type) {
6852 const actualType = getSanitizationBypassType(value);
6853 if (actualType != null && actualType !== type) {
6854 // Allow ResourceURLs in URL contexts, they are strictly more trusted.
6855 if (actualType === "ResourceURL" /* BypassType.ResourceUrl */ && type === "URL" /* BypassType.Url */)
6856 return true;
6857 throw new Error(`Required a safe ${type}, got a ${actualType} (see ${XSS_SECURITY_URL})`);
6858 }
6859 return actualType === type;
6860}
6861function getSanitizationBypassType(value) {
6862 return value instanceof SafeValueImpl && value.getTypeName() || null;
6863}
6864/**
6865 * Mark `html` string as trusted.
6866 *
6867 * This function wraps the trusted string in `String` and brands it in a way which makes it
6868 * recognizable to {@link htmlSanitizer} to be trusted implicitly.
6869 *
6870 * @param trustedHtml `html` string which needs to be implicitly trusted.
6871 * @returns a `html` which has been branded to be implicitly trusted.
6872 */
6873function bypassSanitizationTrustHtml(trustedHtml) {
6874 return new SafeHtmlImpl(trustedHtml);
6875}
6876/**
6877 * Mark `style` string as trusted.
6878 *
6879 * This function wraps the trusted string in `String` and brands it in a way which makes it
6880 * recognizable to {@link styleSanitizer} to be trusted implicitly.
6881 *
6882 * @param trustedStyle `style` string which needs to be implicitly trusted.
6883 * @returns a `style` hich has been branded to be implicitly trusted.
6884 */
6885function bypassSanitizationTrustStyle(trustedStyle) {
6886 return new SafeStyleImpl(trustedStyle);
6887}
6888/**
6889 * Mark `script` string as trusted.
6890 *
6891 * This function wraps the trusted string in `String` and brands it in a way which makes it
6892 * recognizable to {@link scriptSanitizer} to be trusted implicitly.
6893 *
6894 * @param trustedScript `script` string which needs to be implicitly trusted.
6895 * @returns a `script` which has been branded to be implicitly trusted.
6896 */
6897function bypassSanitizationTrustScript(trustedScript) {
6898 return new SafeScriptImpl(trustedScript);
6899}
6900/**
6901 * Mark `url` string as trusted.
6902 *
6903 * This function wraps the trusted string in `String` and brands it in a way which makes it
6904 * recognizable to {@link urlSanitizer} to be trusted implicitly.
6905 *
6906 * @param trustedUrl `url` string which needs to be implicitly trusted.
6907 * @returns a `url` which has been branded to be implicitly trusted.
6908 */
6909function bypassSanitizationTrustUrl(trustedUrl) {
6910 return new SafeUrlImpl(trustedUrl);
6911}
6912/**
6913 * Mark `url` string as trusted.
6914 *
6915 * This function wraps the trusted string in `String` and brands it in a way which makes it
6916 * recognizable to {@link resourceUrlSanitizer} to be trusted implicitly.
6917 *
6918 * @param trustedResourceUrl `url` string which needs to be implicitly trusted.
6919 * @returns a `url` which has been branded to be implicitly trusted.
6920 */
6921function bypassSanitizationTrustResourceUrl(trustedResourceUrl) {
6922 return new SafeResourceUrlImpl(trustedResourceUrl);
6923}
6924
6925/**
6926 * This helper is used to get hold of an inert tree of DOM elements containing dirty HTML
6927 * that needs sanitizing.
6928 * Depending upon browser support we use one of two strategies for doing this.
6929 * Default: DOMParser strategy
6930 * Fallback: InertDocument strategy
6931 */
6932function getInertBodyHelper(defaultDoc) {
6933 const inertDocumentHelper = new InertDocumentHelper(defaultDoc);
6934 return isDOMParserAvailable() ? new DOMParserHelper(inertDocumentHelper) : inertDocumentHelper;
6935}
6936/**
6937 * Uses DOMParser to create and fill an inert body element.
6938 * This is the default strategy used in browsers that support it.
6939 */
6940class DOMParserHelper {
6941 constructor(inertDocumentHelper) {
6942 this.inertDocumentHelper = inertDocumentHelper;
6943 }
6944 getInertBodyElement(html) {
6945 // We add these extra elements to ensure that the rest of the content is parsed as expected
6946 // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the
6947 // `<head>` tag. Note that the `<body>` tag is closed implicitly to prevent unclosed tags
6948 // in `html` from consuming the otherwise explicit `</body>` tag.
6949 html = '<body><remove></remove>' + html;
6950 try {
6951 const body = new window.DOMParser()
6952 .parseFromString(trustedHTMLFromString(html), 'text/html')
6953 .body;
6954 if (body === null) {
6955 // In some browsers (e.g. Mozilla/5.0 iPad AppleWebKit Mobile) the `body` property only
6956 // becomes available in the following tick of the JS engine. In that case we fall back to
6957 // the `inertDocumentHelper` instead.
6958 return this.inertDocumentHelper.getInertBodyElement(html);
6959 }
6960 body.removeChild(body.firstChild);
6961 return body;
6962 }
6963 catch (_a) {
6964 return null;
6965 }
6966 }
6967}
6968/**
6969 * Use an HTML5 `template` element, if supported, or an inert body element created via
6970 * `createHtmlDocument` to create and fill an inert DOM element.
6971 * This is the fallback strategy if the browser does not support DOMParser.
6972 */
6973class InertDocumentHelper {
6974 constructor(defaultDoc) {
6975 this.defaultDoc = defaultDoc;
6976 this.inertDocument = this.defaultDoc.implementation.createHTMLDocument('sanitization-inert');
6977 if (this.inertDocument.body == null) {
6978 // usually there should be only one body element in the document, but IE doesn't have any, so
6979 // we need to create one.
6980 const inertHtml = this.inertDocument.createElement('html');
6981 this.inertDocument.appendChild(inertHtml);
6982 const inertBodyElement = this.inertDocument.createElement('body');
6983 inertHtml.appendChild(inertBodyElement);
6984 }
6985 }
6986 getInertBodyElement(html) {
6987 // Prefer using <template> element if supported.
6988 const templateEl = this.inertDocument.createElement('template');
6989 if ('content' in templateEl) {
6990 templateEl.innerHTML = trustedHTMLFromString(html);
6991 return templateEl;
6992 }
6993 // Note that previously we used to do something like `this.inertDocument.body.innerHTML = html`
6994 // and we returned the inert `body` node. This was changed, because IE seems to treat setting
6995 // `innerHTML` on an inserted element differently, compared to one that hasn't been inserted
6996 // yet. In particular, IE appears to split some of the text into multiple text nodes rather
6997 // than keeping them in a single one which ends up messing with Ivy's i18n parsing further
6998 // down the line. This has been worked around by creating a new inert `body` and using it as
6999 // the root node in which we insert the HTML.
7000 const inertBody = this.inertDocument.createElement('body');
7001 inertBody.innerHTML = trustedHTMLFromString(html);
7002 // Support: IE 11 only
7003 // strip custom-namespaced attributes on IE<=11
7004 if (this.defaultDoc.documentMode) {
7005 this.stripCustomNsAttrs(inertBody);
7006 }
7007 return inertBody;
7008 }
7009 /**
7010 * When IE11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1'
7011 * attribute to declare ns1 namespace and prefixes the attribute with 'ns1' (e.g.
7012 * 'ns1:xlink:foo').
7013 *
7014 * This is undesirable since we don't want to allow any of these custom attributes. This method
7015 * strips them all.
7016 */
7017 stripCustomNsAttrs(el) {
7018 const elAttrs = el.attributes;
7019 // loop backwards so that we can support removals.
7020 for (let i = elAttrs.length - 1; 0 < i; i--) {
7021 const attrib = elAttrs.item(i);
7022 const attrName = attrib.name;
7023 if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) {
7024 el.removeAttribute(attrName);
7025 }
7026 }
7027 let childNode = el.firstChild;
7028 while (childNode) {
7029 if (childNode.nodeType === Node.ELEMENT_NODE)
7030 this.stripCustomNsAttrs(childNode);
7031 childNode = childNode.nextSibling;
7032 }
7033 }
7034}
7035/**
7036 * We need to determine whether the DOMParser exists in the global context and
7037 * supports parsing HTML; HTML parsing support is not as wide as other formats, see
7038 * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility.
7039 *
7040 * @suppress {uselessCode}
7041 */
7042function isDOMParserAvailable() {
7043 try {
7044 return !!new window.DOMParser().parseFromString(trustedHTMLFromString(''), 'text/html');
7045 }
7046 catch (_a) {
7047 return false;
7048 }
7049}
7050
7051/**
7052 * A pattern that recognizes a commonly useful subset of URLs that are safe.
7053 *
7054 * This regular expression matches a subset of URLs that will not cause script
7055 * execution if used in URL context within a HTML document. Specifically, this
7056 * regular expression matches if (comment from here on and regex copied from
7057 * Soy's EscapingConventions):
7058 * (1) Either an allowed protocol (http, https, mailto or ftp).
7059 * (2) or no protocol. A protocol must be followed by a colon. The below
7060 * allows that by allowing colons only after one of the characters [/?#].
7061 * A colon after a hash (#) must be in the fragment.
7062 * Otherwise, a colon after a (?) must be in a query.
7063 * Otherwise, a colon after a single solidus (/) must be in a path.
7064 * Otherwise, a colon after a double solidus (//) must be in the authority
7065 * (before port).
7066 *
7067 * The pattern disallows &, used in HTML entity declarations before
7068 * one of the characters in [/?#]. This disallows HTML entities used in the
7069 * protocol name, which should never happen, e.g. "h&#116;tp" for "http".
7070 * It also disallows HTML entities in the first path part of a relative path,
7071 * e.g. "foo&lt;bar/baz". Our existing escaping functions should not produce
7072 * that. More importantly, it disallows masking of a colon,
7073 * e.g. "javascript&#58;...".
7074 *
7075 * This regular expression was taken from the Closure sanitization library.
7076 */
7077const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|data|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi;
7078function _sanitizeUrl(url) {
7079 url = String(url);
7080 if (url.match(SAFE_URL_PATTERN))
7081 return url;
7082 if (typeof ngDevMode === 'undefined' || ngDevMode) {
7083 console.warn(`WARNING: sanitizing unsafe URL value ${url} (see ${XSS_SECURITY_URL})`);
7084 }
7085 return 'unsafe:' + url;
7086}
7087
7088function tagSet(tags) {
7089 const res = {};
7090 for (const t of tags.split(','))
7091 res[t] = true;
7092 return res;
7093}
7094function merge(...sets) {
7095 const res = {};
7096 for (const s of sets) {
7097 for (const v in s) {
7098 if (s.hasOwnProperty(v))
7099 res[v] = true;
7100 }
7101 }
7102 return res;
7103}
7104// Good source of info about elements and attributes
7105// https://html.spec.whatwg.org/#semantics
7106// https://simon.html5.org/html-elements
7107// Safe Void Elements - HTML5
7108// https://html.spec.whatwg.org/#void-elements
7109const VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr');
7110// Elements that you can, intentionally, leave open (and which close themselves)
7111// https://html.spec.whatwg.org/#optional-tags
7112const OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr');
7113const OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt');
7114const OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS);
7115// Safe Block Elements - HTML5
7116const BLOCK_ELEMENTS = merge(OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet('address,article,' +
7117 'aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
7118 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul'));
7119// Inline Elements - HTML5
7120const INLINE_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet('a,abbr,acronym,audio,b,' +
7121 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' +
7122 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video'));
7123const VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS);
7124// Attributes that have href and hence need to be sanitized
7125const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
7126const HTML_ATTRS = tagSet('abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' +
7127 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' +
7128 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' +
7129 'scope,scrolling,shape,size,sizes,span,srclang,srcset,start,summary,tabindex,target,title,translate,type,usemap,' +
7130 'valign,value,vspace,width');
7131// Accessibility attributes as per WAI-ARIA 1.1 (W3C Working Draft 14 December 2018)
7132const ARIA_ATTRS = tagSet('aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,' +
7133 'aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,' +
7134 'aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,' +
7135 'aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,' +
7136 'aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,' +
7137 'aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,' +
7138 'aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext');
7139// NB: This currently consciously doesn't support SVG. SVG sanitization has had several security
7140// issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via
7141// innerHTML is required, SVG attributes should be added here.
7142// NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those
7143// can be sanitized, but they increase security surface area without a legitimate use case, so they
7144// are left out here.
7145const VALID_ATTRS = merge(URI_ATTRS, HTML_ATTRS, ARIA_ATTRS);
7146// Elements whose content should not be traversed/preserved, if the elements themselves are invalid.
7147//
7148// Typically, `<invalid>Some content</invalid>` would traverse (and in this case preserve)
7149// `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we
7150// don't want to preserve the content, if the elements themselves are going to be removed.
7151const SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template');
7152/**
7153 * SanitizingHtmlSerializer serializes a DOM fragment, stripping out any unsafe elements and unsafe
7154 * attributes.
7155 */
7156class SanitizingHtmlSerializer {
7157 constructor() {
7158 // Explicitly track if something was stripped, to avoid accidentally warning of sanitization just
7159 // because characters were re-encoded.
7160 this.sanitizedSomething = false;
7161 this.buf = [];
7162 }
7163 sanitizeChildren(el) {
7164 // This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters.
7165 // However this code never accesses properties off of `document` before deleting its contents
7166 // again, so it shouldn't be vulnerable to DOM clobbering.
7167 let current = el.firstChild;
7168 let traverseContent = true;
7169 while (current) {
7170 if (current.nodeType === Node.ELEMENT_NODE) {
7171 traverseContent = this.startElement(current);
7172 }
7173 else if (current.nodeType === Node.TEXT_NODE) {
7174 this.chars(current.nodeValue);
7175 }
7176 else {
7177 // Strip non-element, non-text nodes.
7178 this.sanitizedSomething = true;
7179 }
7180 if (traverseContent && current.firstChild) {
7181 current = current.firstChild;
7182 continue;
7183 }
7184 while (current) {
7185 // Leaving the element. Walk up and to the right, closing tags as we go.
7186 if (current.nodeType === Node.ELEMENT_NODE) {
7187 this.endElement(current);
7188 }
7189 let next = this.checkClobberedElement(current, current.nextSibling);
7190 if (next) {
7191 current = next;
7192 break;
7193 }
7194 current = this.checkClobberedElement(current, current.parentNode);
7195 }
7196 }
7197 return this.buf.join('');
7198 }
7199 /**
7200 * Sanitizes an opening element tag (if valid) and returns whether the element's contents should
7201 * be traversed. Element content must always be traversed (even if the element itself is not
7202 * valid/safe), unless the element is one of `SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS`.
7203 *
7204 * @param element The element to sanitize.
7205 * @return True if the element's contents should be traversed.
7206 */
7207 startElement(element) {
7208 const tagName = element.nodeName.toLowerCase();
7209 if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
7210 this.sanitizedSomething = true;
7211 return !SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS.hasOwnProperty(tagName);
7212 }
7213 this.buf.push('<');
7214 this.buf.push(tagName);
7215 const elAttrs = element.attributes;
7216 for (let i = 0; i < elAttrs.length; i++) {
7217 const elAttr = elAttrs.item(i);
7218 const attrName = elAttr.name;
7219 const lower = attrName.toLowerCase();
7220 if (!VALID_ATTRS.hasOwnProperty(lower)) {
7221 this.sanitizedSomething = true;
7222 continue;
7223 }
7224 let value = elAttr.value;
7225 // TODO(martinprobst): Special case image URIs for data:image/...
7226 if (URI_ATTRS[lower])
7227 value = _sanitizeUrl(value);
7228 this.buf.push(' ', attrName, '="', encodeEntities(value), '"');
7229 }
7230 this.buf.push('>');
7231 return true;
7232 }
7233 endElement(current) {
7234 const tagName = current.nodeName.toLowerCase();
7235 if (VALID_ELEMENTS.hasOwnProperty(tagName) && !VOID_ELEMENTS.hasOwnProperty(tagName)) {
7236 this.buf.push('</');
7237 this.buf.push(tagName);
7238 this.buf.push('>');
7239 }
7240 }
7241 chars(chars) {
7242 this.buf.push(encodeEntities(chars));
7243 }
7244 checkClobberedElement(node, nextNode) {
7245 if (nextNode &&
7246 (node.compareDocumentPosition(nextNode) &
7247 Node.DOCUMENT_POSITION_CONTAINED_BY) === Node.DOCUMENT_POSITION_CONTAINED_BY) {
7248 throw new Error(`Failed to sanitize html because the element is clobbered: ${node.outerHTML}`);
7249 }
7250 return nextNode;
7251 }
7252}
7253// Regular Expressions for parsing tags and attributes
7254const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
7255// ! to ~ is the ASCII range.
7256const NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
7257/**
7258 * Escapes all potentially dangerous characters, so that the
7259 * resulting string can be safely inserted into attribute or
7260 * element text.
7261 * @param value
7262 */
7263function encodeEntities(value) {
7264 return value.replace(/&/g, '&amp;')
7265 .replace(SURROGATE_PAIR_REGEXP, function (match) {
7266 const hi = match.charCodeAt(0);
7267 const low = match.charCodeAt(1);
7268 return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
7269 })
7270 .replace(NON_ALPHANUMERIC_REGEXP, function (match) {
7271 return '&#' + match.charCodeAt(0) + ';';
7272 })
7273 .replace(/</g, '&lt;')
7274 .replace(/>/g, '&gt;');
7275}
7276let inertBodyHelper;
7277/**
7278 * Sanitizes the given unsafe, untrusted HTML fragment, and returns HTML text that is safe to add to
7279 * the DOM in a browser environment.
7280 */
7281function _sanitizeHtml(defaultDoc, unsafeHtmlInput) {
7282 let inertBodyElement = null;
7283 try {
7284 inertBodyHelper = inertBodyHelper || getInertBodyHelper(defaultDoc);
7285 // Make sure unsafeHtml is actually a string (TypeScript types are not enforced at runtime).
7286 let unsafeHtml = unsafeHtmlInput ? String(unsafeHtmlInput) : '';
7287 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
7288 // mXSS protection. Repeatedly parse the document to make sure it stabilizes, so that a browser
7289 // trying to auto-correct incorrect HTML cannot cause formerly inert HTML to become dangerous.
7290 let mXSSAttempts = 5;
7291 let parsedHtml = unsafeHtml;
7292 do {
7293 if (mXSSAttempts === 0) {
7294 throw new Error('Failed to sanitize html because the input is unstable');
7295 }
7296 mXSSAttempts--;
7297 unsafeHtml = parsedHtml;
7298 parsedHtml = inertBodyElement.innerHTML;
7299 inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
7300 } while (unsafeHtml !== parsedHtml);
7301 const sanitizer = new SanitizingHtmlSerializer();
7302 const safeHtml = sanitizer.sanitizeChildren(getTemplateContent(inertBodyElement) || inertBodyElement);
7303 if ((typeof ngDevMode === 'undefined' || ngDevMode) && sanitizer.sanitizedSomething) {
7304 console.warn(`WARNING: sanitizing HTML stripped some content, see ${XSS_SECURITY_URL}`);
7305 }
7306 return trustedHTMLFromString(safeHtml);
7307 }
7308 finally {
7309 // In case anything goes wrong, clear out inertElement to reset the entire DOM structure.
7310 if (inertBodyElement) {
7311 const parent = getTemplateContent(inertBodyElement) || inertBodyElement;
7312 while (parent.firstChild) {
7313 parent.removeChild(parent.firstChild);
7314 }
7315 }
7316 }
7317}
7318function getTemplateContent(el) {
7319 return 'content' in el /** Microsoft/TypeScript#21517 */ && isTemplateElement(el) ?
7320 el.content :
7321 null;
7322}
7323function isTemplateElement(el) {
7324 return el.nodeType === Node.ELEMENT_NODE && el.nodeName === 'TEMPLATE';
7325}
7326
7327/**
7328 * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
7329 * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
7330 * handled.
7331 *
7332 * See DomSanitizer for more details on security in Angular applications.
7333 *
7334 * @publicApi
7335 */
7336var SecurityContext;
7337(function (SecurityContext) {
7338 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
7339 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
7340 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
7341 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
7342 SecurityContext[SecurityContext["URL"] = 4] = "URL";
7343 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
7344})(SecurityContext || (SecurityContext = {}));
7345
7346/**
7347 * An `html` sanitizer which converts untrusted `html` **string** into trusted string by removing
7348 * dangerous content.
7349 *
7350 * This method parses the `html` and locates potentially dangerous content (such as urls and
7351 * javascript) and removes it.
7352 *
7353 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustHtml}.
7354 *
7355 * @param unsafeHtml untrusted `html`, typically from the user.
7356 * @returns `html` string which is safe to display to user, because all of the dangerous javascript
7357 * and urls have been removed.
7358 *
7359 * @codeGenApi
7360 */
7361function ɵɵsanitizeHtml(unsafeHtml) {
7362 const sanitizer = getSanitizer();
7363 if (sanitizer) {
7364 return trustedHTMLFromStringBypass(sanitizer.sanitize(SecurityContext.HTML, unsafeHtml) || '');
7365 }
7366 if (allowSanitizationBypassAndThrow(unsafeHtml, "HTML" /* BypassType.Html */)) {
7367 return trustedHTMLFromStringBypass(unwrapSafeValue(unsafeHtml));
7368 }
7369 return _sanitizeHtml(getDocument(), renderStringify(unsafeHtml));
7370}
7371/**
7372 * A `style` sanitizer which converts untrusted `style` **string** into trusted string by removing
7373 * dangerous content.
7374 *
7375 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustStyle}.
7376 *
7377 * @param unsafeStyle untrusted `style`, typically from the user.
7378 * @returns `style` string which is safe to bind to the `style` properties.
7379 *
7380 * @codeGenApi
7381 */
7382function ɵɵsanitizeStyle(unsafeStyle) {
7383 const sanitizer = getSanitizer();
7384 if (sanitizer) {
7385 return sanitizer.sanitize(SecurityContext.STYLE, unsafeStyle) || '';
7386 }
7387 if (allowSanitizationBypassAndThrow(unsafeStyle, "Style" /* BypassType.Style */)) {
7388 return unwrapSafeValue(unsafeStyle);
7389 }
7390 return renderStringify(unsafeStyle);
7391}
7392/**
7393 * A `url` sanitizer which converts untrusted `url` **string** into trusted string by removing
7394 * dangerous
7395 * content.
7396 *
7397 * This method parses the `url` and locates potentially dangerous content (such as javascript) and
7398 * removes it.
7399 *
7400 * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustUrl}.
7401 *
7402 * @param unsafeUrl untrusted `url`, typically from the user.
7403 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
7404 * all of the dangerous javascript has been removed.
7405 *
7406 * @codeGenApi
7407 */
7408function ɵɵsanitizeUrl(unsafeUrl) {
7409 const sanitizer = getSanitizer();
7410 if (sanitizer) {
7411 return sanitizer.sanitize(SecurityContext.URL, unsafeUrl) || '';
7412 }
7413 if (allowSanitizationBypassAndThrow(unsafeUrl, "URL" /* BypassType.Url */)) {
7414 return unwrapSafeValue(unsafeUrl);
7415 }
7416 return _sanitizeUrl(renderStringify(unsafeUrl));
7417}
7418/**
7419 * A `url` sanitizer which only lets trusted `url`s through.
7420 *
7421 * This passes only `url`s marked trusted by calling {@link bypassSanitizationTrustResourceUrl}.
7422 *
7423 * @param unsafeResourceUrl untrusted `url`, typically from the user.
7424 * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because
7425 * only trusted `url`s have been allowed to pass.
7426 *
7427 * @codeGenApi
7428 */
7429function ɵɵsanitizeResourceUrl(unsafeResourceUrl) {
7430 const sanitizer = getSanitizer();
7431 if (sanitizer) {
7432 return trustedScriptURLFromStringBypass(sanitizer.sanitize(SecurityContext.RESOURCE_URL, unsafeResourceUrl) || '');
7433 }
7434 if (allowSanitizationBypassAndThrow(unsafeResourceUrl, "ResourceURL" /* BypassType.ResourceUrl */)) {
7435 return trustedScriptURLFromStringBypass(unwrapSafeValue(unsafeResourceUrl));
7436 }
7437 throw new RuntimeError(904 /* RuntimeErrorCode.UNSAFE_VALUE_IN_RESOURCE_URL */, ngDevMode && `unsafe value used in a resource URL context (see ${XSS_SECURITY_URL})`);
7438}
7439/**
7440 * A `script` sanitizer which only lets trusted javascript through.
7441 *
7442 * This passes only `script`s marked trusted by calling {@link
7443 * bypassSanitizationTrustScript}.
7444 *
7445 * @param unsafeScript untrusted `script`, typically from the user.
7446 * @returns `url` string which is safe to bind to the `<script>` element such as `<img src>`,
7447 * because only trusted `scripts` have been allowed to pass.
7448 *
7449 * @codeGenApi
7450 */
7451function ɵɵsanitizeScript(unsafeScript) {
7452 const sanitizer = getSanitizer();
7453 if (sanitizer) {
7454 return trustedScriptFromStringBypass(sanitizer.sanitize(SecurityContext.SCRIPT, unsafeScript) || '');
7455 }
7456 if (allowSanitizationBypassAndThrow(unsafeScript, "Script" /* BypassType.Script */)) {
7457 return trustedScriptFromStringBypass(unwrapSafeValue(unsafeScript));
7458 }
7459 throw new RuntimeError(905 /* RuntimeErrorCode.UNSAFE_VALUE_IN_SCRIPT */, ngDevMode && 'unsafe value used in a script context');
7460}
7461/**
7462 * A template tag function for promoting the associated constant literal to a
7463 * TrustedHTML. Interpolation is explicitly not allowed.
7464 *
7465 * @param html constant template literal containing trusted HTML.
7466 * @returns TrustedHTML wrapping `html`.
7467 *
7468 * @security This is a security-sensitive function and should only be used to
7469 * convert constant values of attributes and properties found in
7470 * application-provided Angular templates to TrustedHTML.
7471 *
7472 * @codeGenApi
7473 */
7474function ɵɵtrustConstantHtml(html) {
7475 // The following runtime check ensures that the function was called as a
7476 // template tag (e.g. ɵɵtrustConstantHtml`content`), without any interpolation
7477 // (e.g. not ɵɵtrustConstantHtml`content ${variable}`). A TemplateStringsArray
7478 // is an array with a `raw` property that is also an array. The associated
7479 // template literal has no interpolation if and only if the length of the
7480 // TemplateStringsArray is 1.
7481 if (ngDevMode && (!Array.isArray(html) || !Array.isArray(html.raw) || html.length !== 1)) {
7482 throw new Error(`Unexpected interpolation in trusted HTML constant: ${html.join('?')}`);
7483 }
7484 return trustedHTMLFromString(html[0]);
7485}
7486/**
7487 * A template tag function for promoting the associated constant literal to a
7488 * TrustedScriptURL. Interpolation is explicitly not allowed.
7489 *
7490 * @param url constant template literal containing a trusted script URL.
7491 * @returns TrustedScriptURL wrapping `url`.
7492 *
7493 * @security This is a security-sensitive function and should only be used to
7494 * convert constant values of attributes and properties found in
7495 * application-provided Angular templates to TrustedScriptURL.
7496 *
7497 * @codeGenApi
7498 */
7499function ɵɵtrustConstantResourceUrl(url) {
7500 // The following runtime check ensures that the function was called as a
7501 // template tag (e.g. ɵɵtrustConstantResourceUrl`content`), without any
7502 // interpolation (e.g. not ɵɵtrustConstantResourceUrl`content ${variable}`). A
7503 // TemplateStringsArray is an array with a `raw` property that is also an
7504 // array. The associated template literal has no interpolation if and only if
7505 // the length of the TemplateStringsArray is 1.
7506 if (ngDevMode && (!Array.isArray(url) || !Array.isArray(url.raw) || url.length !== 1)) {
7507 throw new Error(`Unexpected interpolation in trusted URL constant: ${url.join('?')}`);
7508 }
7509 return trustedScriptURLFromString(url[0]);
7510}
7511/**
7512 * Detects which sanitizer to use for URL property, based on tag name and prop name.
7513 *
7514 * The rules are based on the RESOURCE_URL context config from
7515 * `packages/compiler/src/schema/dom_security_schema.ts`.
7516 * If tag and prop names don't match Resource URL schema, use URL sanitizer.
7517 */
7518function getUrlSanitizer(tag, prop) {
7519 if ((prop === 'src' &&
7520 (tag === 'embed' || tag === 'frame' || tag === 'iframe' || tag === 'media' ||
7521 tag === 'script')) ||
7522 (prop === 'href' && (tag === 'base' || tag === 'link'))) {
7523 return ɵɵsanitizeResourceUrl;
7524 }
7525 return ɵɵsanitizeUrl;
7526}
7527/**
7528 * Sanitizes URL, selecting sanitizer function based on tag and property names.
7529 *
7530 * This function is used in case we can't define security context at compile time, when only prop
7531 * name is available. This happens when we generate host bindings for Directives/Components. The
7532 * host element is unknown at compile time, so we defer calculation of specific sanitizer to
7533 * runtime.
7534 *
7535 * @param unsafeUrl untrusted `url`, typically from the user.
7536 * @param tag target element tag name.
7537 * @param prop name of the property that contains the value.
7538 * @returns `url` string which is safe to bind.
7539 *
7540 * @codeGenApi
7541 */
7542function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl, tag, prop) {
7543 return getUrlSanitizer(tag, prop)(unsafeUrl);
7544}
7545function validateAgainstEventProperties(name) {
7546 if (name.toLowerCase().startsWith('on')) {
7547 const errorMessage = `Binding to event property '${name}' is disallowed for security reasons, ` +
7548 `please use (${name.slice(2)})=...` +
7549 `\nIf '${name}' is a directive input, make sure the directive is imported by the` +
7550 ` current module.`;
7551 throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
7552 }
7553}
7554function validateAgainstEventAttributes(name) {
7555 if (name.toLowerCase().startsWith('on')) {
7556 const errorMessage = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
7557 `please use (${name.slice(2)})=...`;
7558 throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
7559 }
7560}
7561function getSanitizer() {
7562 const lView = getLView();
7563 return lView && lView[SANITIZER];
7564}
7565
7566/**
7567 * A multi-provider token for initialization functions that will run upon construction of an
7568 * environment injector.
7569 *
7570 * @publicApi
7571 */
7572const ENVIRONMENT_INITIALIZER = new InjectionToken('ENVIRONMENT_INITIALIZER');
7573
7574/**
7575 * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors.
7576 *
7577 * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a
7578 * project.
7579 *
7580 * @publicApi
7581 */
7582const INJECTOR = new InjectionToken('INJECTOR',
7583// Disable tslint because this is const enum which gets inlined not top level prop access.
7584// tslint:disable-next-line: no-toplevel-property-access
7585-1 /* InjectorMarkers.Injector */);
7586
7587const INJECTOR_DEF_TYPES = new InjectionToken('INJECTOR_DEF_TYPES');
7588
7589class NullInjector {
7590 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
7591 if (notFoundValue === THROW_IF_NOT_FOUND) {
7592 const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`);
7593 error.name = 'NullInjectorError';
7594 throw error;
7595 }
7596 return notFoundValue;
7597 }
7598}
7599
7600/**
7601 * Wrap an array of `Provider`s into `EnvironmentProviders`, preventing them from being accidentally
7602 * referenced in `@Component in a component injector.
7603 */
7604function makeEnvironmentProviders(providers) {
7605 return {
7606 ɵproviders: providers,
7607 };
7608}
7609/**
7610 * Collects providers from all NgModules and standalone components, including transitively imported
7611 * ones.
7612 *
7613 * Providers extracted via `importProvidersFrom` are only usable in an application injector or
7614 * another environment injector (such as a route injector). They should not be used in component
7615 * providers.
7616 *
7617 * More information about standalone components can be found in [this
7618 * guide](guide/standalone-components).
7619 *
7620 * @usageNotes
7621 * The results of the `importProvidersFrom` call can be used in the `bootstrapApplication` call:
7622 *
7623 * ```typescript
7624 * await bootstrapApplication(RootComponent, {
7625 * providers: [
7626 * importProvidersFrom(NgModuleOne, NgModuleTwo)
7627 * ]
7628 * });
7629 * ```
7630 *
7631 * You can also use the `importProvidersFrom` results in the `providers` field of a route, when a
7632 * standalone component is used:
7633 *
7634 * ```typescript
7635 * export const ROUTES: Route[] = [
7636 * {
7637 * path: 'foo',
7638 * providers: [
7639 * importProvidersFrom(NgModuleOne, NgModuleTwo)
7640 * ],
7641 * component: YourStandaloneComponent
7642 * }
7643 * ];
7644 * ```
7645 *
7646 * @returns Collected providers from the specified list of types.
7647 * @publicApi
7648 */
7649function importProvidersFrom(...sources) {
7650 return {
7651 ɵproviders: internalImportProvidersFrom(true, sources),
7652 ɵfromNgModule: true,
7653 };
7654}
7655function internalImportProvidersFrom(checkForStandaloneCmp, ...sources) {
7656 const providersOut = [];
7657 const dedup = new Set(); // already seen types
7658 let injectorTypesWithProviders;
7659 deepForEach(sources, source => {
7660 if ((typeof ngDevMode === 'undefined' || ngDevMode) && checkForStandaloneCmp) {
7661 const cmpDef = getComponentDef(source);
7662 if (cmpDef === null || cmpDef === void 0 ? void 0 : cmpDef.standalone) {
7663 throw new RuntimeError(800 /* RuntimeErrorCode.IMPORT_PROVIDERS_FROM_STANDALONE */, `Importing providers supports NgModule or ModuleWithProviders but got a standalone component "${stringifyForError(source)}"`);
7664 }
7665 }
7666 // Narrow `source` to access the internal type analogue for `ModuleWithProviders`.
7667 const internalSource = source;
7668 if (walkProviderTree(internalSource, providersOut, [], dedup)) {
7669 injectorTypesWithProviders || (injectorTypesWithProviders = []);
7670 injectorTypesWithProviders.push(internalSource);
7671 }
7672 });
7673 // Collect all providers from `ModuleWithProviders` types.
7674 if (injectorTypesWithProviders !== undefined) {
7675 processInjectorTypesWithProviders(injectorTypesWithProviders, providersOut);
7676 }
7677 return providersOut;
7678}
7679/**
7680 * Collects all providers from the list of `ModuleWithProviders` and appends them to the provided
7681 * array.
7682 */
7683function processInjectorTypesWithProviders(typesWithProviders, providersOut) {
7684 for (let i = 0; i < typesWithProviders.length; i++) {
7685 const { ngModule, providers } = typesWithProviders[i];
7686 deepForEachProvider(providers, provider => {
7687 ngDevMode && validateProvider(provider, providers || EMPTY_ARRAY, ngModule);
7688 providersOut.push(provider);
7689 });
7690 }
7691}
7692/**
7693 * The logic visits an `InjectorType`, an `InjectorTypeWithProviders`, or a standalone
7694 * `ComponentType`, and all of its transitive providers and collects providers.
7695 *
7696 * If an `InjectorTypeWithProviders` that declares providers besides the type is specified,
7697 * the function will return "true" to indicate that the providers of the type definition need
7698 * to be processed. This allows us to process providers of injector types after all imports of
7699 * an injector definition are processed. (following View Engine semantics: see FW-1349)
7700 */
7701function walkProviderTree(container, providersOut, parents, dedup) {
7702 container = resolveForwardRef(container);
7703 if (!container)
7704 return false;
7705 // The actual type which had the definition. Usually `container`, but may be an unwrapped type
7706 // from `InjectorTypeWithProviders`.
7707 let defType = null;
7708 let injDef = getInjectorDef(container);
7709 const cmpDef = !injDef && getComponentDef(container);
7710 if (!injDef && !cmpDef) {
7711 // `container` is not an injector type or a component type. It might be:
7712 // * An `InjectorTypeWithProviders` that wraps an injector type.
7713 // * A standalone directive or pipe that got pulled in from a standalone component's
7714 // dependencies.
7715 // Try to unwrap it as an `InjectorTypeWithProviders` first.
7716 const ngModule = container.ngModule;
7717 injDef = getInjectorDef(ngModule);
7718 if (injDef) {
7719 defType = ngModule;
7720 }
7721 else {
7722 // Not a component or injector type, so ignore it.
7723 return false;
7724 }
7725 }
7726 else if (cmpDef && !cmpDef.standalone) {
7727 return false;
7728 }
7729 else {
7730 defType = container;
7731 }
7732 // Check for circular dependencies.
7733 if (ngDevMode && parents.indexOf(defType) !== -1) {
7734 const defName = stringify(defType);
7735 const path = parents.map(stringify);
7736 throwCyclicDependencyError(defName, path);
7737 }
7738 // Check for multiple imports of the same module
7739 const isDuplicate = dedup.has(defType);
7740 if (cmpDef) {
7741 if (isDuplicate) {
7742 // This component definition has already been processed.
7743 return false;
7744 }
7745 dedup.add(defType);
7746 if (cmpDef.dependencies) {
7747 const deps = typeof cmpDef.dependencies === 'function' ? cmpDef.dependencies() : cmpDef.dependencies;
7748 for (const dep of deps) {
7749 walkProviderTree(dep, providersOut, parents, dedup);
7750 }
7751 }
7752 }
7753 else if (injDef) {
7754 // First, include providers from any imports.
7755 if (injDef.imports != null && !isDuplicate) {
7756 // Before processing defType's imports, add it to the set of parents. This way, if it ends
7757 // up deeply importing itself, this can be detected.
7758 ngDevMode && parents.push(defType);
7759 // Add it to the set of dedups. This way we can detect multiple imports of the same module
7760 dedup.add(defType);
7761 let importTypesWithProviders;
7762 try {
7763 deepForEach(injDef.imports, imported => {
7764 if (walkProviderTree(imported, providersOut, parents, dedup)) {
7765 importTypesWithProviders || (importTypesWithProviders = []);
7766 // If the processed import is an injector type with providers, we store it in the
7767 // list of import types with providers, so that we can process those afterwards.
7768 importTypesWithProviders.push(imported);
7769 }
7770 });
7771 }
7772 finally {
7773 // Remove it from the parents set when finished.
7774 ngDevMode && parents.pop();
7775 }
7776 // Imports which are declared with providers (TypeWithProviders) need to be processed
7777 // after all imported modules are processed. This is similar to how View Engine
7778 // processes/merges module imports in the metadata resolver. See: FW-1349.
7779 if (importTypesWithProviders !== undefined) {
7780 processInjectorTypesWithProviders(importTypesWithProviders, providersOut);
7781 }
7782 }
7783 if (!isDuplicate) {
7784 // Track the InjectorType and add a provider for it.
7785 // It's important that this is done after the def's imports.
7786 const factory = getFactoryDef(defType) || (() => new defType());
7787 // Append extra providers to make more info available for consumers (to retrieve an injector
7788 // type), as well as internally (to calculate an injection scope correctly and eagerly
7789 // instantiate a `defType` when an injector is created).
7790 providersOut.push(
7791 // Provider to create `defType` using its factory.
7792 { provide: defType, useFactory: factory, deps: EMPTY_ARRAY },
7793 // Make this `defType` available to an internal logic that calculates injector scope.
7794 { provide: INJECTOR_DEF_TYPES, useValue: defType, multi: true },
7795 // Provider to eagerly instantiate `defType` via `ENVIRONMENT_INITIALIZER`.
7796 { provide: ENVIRONMENT_INITIALIZER, useValue: () => ɵɵinject(defType), multi: true } //
7797 );
7798 }
7799 // Next, include providers listed on the definition itself.
7800 const defProviders = injDef.providers;
7801 if (defProviders != null && !isDuplicate) {
7802 const injectorType = container;
7803 deepForEachProvider(defProviders, provider => {
7804 ngDevMode && validateProvider(provider, defProviders, injectorType);
7805 providersOut.push(provider);
7806 });
7807 }
7808 }
7809 else {
7810 // Should not happen, but just in case.
7811 return false;
7812 }
7813 return (defType !== container &&
7814 container.providers !== undefined);
7815}
7816function validateProvider(provider, providers, containerType) {
7817 if (isTypeProvider(provider) || isValueProvider(provider) || isFactoryProvider(provider) ||
7818 isExistingProvider(provider)) {
7819 return;
7820 }
7821 // Here we expect the provider to be a `useClass` provider (by elimination).
7822 const classRef = resolveForwardRef(provider && (provider.useClass || provider.provide));
7823 if (!classRef) {
7824 throwInvalidProviderError(containerType, providers, provider);
7825 }
7826}
7827function deepForEachProvider(providers, fn) {
7828 for (let provider of providers) {
7829 if (isEnvironmentProviders(provider)) {
7830 provider = provider.ɵproviders;
7831 }
7832 if (Array.isArray(provider)) {
7833 deepForEachProvider(provider, fn);
7834 }
7835 else {
7836 fn(provider);
7837 }
7838 }
7839}
7840const USE_VALUE$1 = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
7841function isValueProvider(value) {
7842 return value !== null && typeof value == 'object' && USE_VALUE$1 in value;
7843}
7844function isExistingProvider(value) {
7845 return !!(value && value.useExisting);
7846}
7847function isFactoryProvider(value) {
7848 return !!(value && value.useFactory);
7849}
7850function isTypeProvider(value) {
7851 return typeof value === 'function';
7852}
7853function isClassProvider(value) {
7854 return !!value.useClass;
7855}
7856
7857/**
7858 * An internal token whose presence in an injector indicates that the injector should treat itself
7859 * as a root scoped injector when processing requests for unknown tokens which may indicate
7860 * they are provided in the root scope.
7861 */
7862const INJECTOR_SCOPE = new InjectionToken('Set Injector scope.');
7863
7864/**
7865 * Marker which indicates that a value has not yet been created from the factory function.
7866 */
7867const NOT_YET = {};
7868/**
7869 * Marker which indicates that the factory function for a token is in the process of being called.
7870 *
7871 * If the injector is asked to inject a token with its value set to CIRCULAR, that indicates
7872 * injection of a dependency has recursively attempted to inject the original token, and there is
7873 * a circular dependency among the providers.
7874 */
7875const CIRCULAR = {};
7876/**
7877 * A lazily initialized NullInjector.
7878 */
7879let NULL_INJECTOR$1 = undefined;
7880function getNullInjector() {
7881 if (NULL_INJECTOR$1 === undefined) {
7882 NULL_INJECTOR$1 = new NullInjector();
7883 }
7884 return NULL_INJECTOR$1;
7885}
7886/**
7887 * An `Injector` that's part of the environment injector hierarchy, which exists outside of the
7888 * component tree.
7889 */
7890class EnvironmentInjector {
7891}
7892class R3Injector extends EnvironmentInjector {
7893 /**
7894 * Flag indicating that this injector was previously destroyed.
7895 */
7896 get destroyed() {
7897 return this._destroyed;
7898 }
7899 constructor(providers, parent, source, scopes) {
7900 super();
7901 this.parent = parent;
7902 this.source = source;
7903 this.scopes = scopes;
7904 /**
7905 * Map of tokens to records which contain the instances of those tokens.
7906 * - `null` value implies that we don't have the record. Used by tree-shakable injectors
7907 * to prevent further searches.
7908 */
7909 this.records = new Map();
7910 /**
7911 * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks.
7912 */
7913 this._ngOnDestroyHooks = new Set();
7914 this._onDestroyHooks = [];
7915 this._destroyed = false;
7916 // Start off by creating Records for every provider.
7917 forEachSingleProvider(providers, provider => this.processProvider(provider));
7918 // Make sure the INJECTOR token provides this injector.
7919 this.records.set(INJECTOR, makeRecord(undefined, this));
7920 // And `EnvironmentInjector` if the current injector is supposed to be env-scoped.
7921 if (scopes.has('environment')) {
7922 this.records.set(EnvironmentInjector, makeRecord(undefined, this));
7923 }
7924 // Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide
7925 // any injectable scoped to APP_ROOT_SCOPE.
7926 const record = this.records.get(INJECTOR_SCOPE);
7927 if (record != null && typeof record.value === 'string') {
7928 this.scopes.add(record.value);
7929 }
7930 this.injectorDefTypes =
7931 new Set(this.get(INJECTOR_DEF_TYPES.multi, EMPTY_ARRAY, InjectFlags.Self));
7932 }
7933 /**
7934 * Destroy the injector and release references to every instance or provider associated with it.
7935 *
7936 * Also calls the `OnDestroy` lifecycle hooks of every instance that was created for which a
7937 * hook was found.
7938 */
7939 destroy() {
7940 this.assertNotDestroyed();
7941 // Set destroyed = true first, in case lifecycle hooks re-enter destroy().
7942 this._destroyed = true;
7943 try {
7944 // Call all the lifecycle hooks.
7945 for (const service of this._ngOnDestroyHooks) {
7946 service.ngOnDestroy();
7947 }
7948 for (const hook of this._onDestroyHooks) {
7949 hook();
7950 }
7951 }
7952 finally {
7953 // Release all references.
7954 this.records.clear();
7955 this._ngOnDestroyHooks.clear();
7956 this.injectorDefTypes.clear();
7957 this._onDestroyHooks.length = 0;
7958 }
7959 }
7960 onDestroy(callback) {
7961 this._onDestroyHooks.push(callback);
7962 }
7963 runInContext(fn) {
7964 this.assertNotDestroyed();
7965 const previousInjector = setCurrentInjector(this);
7966 const previousInjectImplementation = setInjectImplementation(undefined);
7967 try {
7968 return fn();
7969 }
7970 finally {
7971 setCurrentInjector(previousInjector);
7972 setInjectImplementation(previousInjectImplementation);
7973 }
7974 }
7975 get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
7976 this.assertNotDestroyed();
7977 flags = convertToBitFlags(flags);
7978 // Set the injection context.
7979 const previousInjector = setCurrentInjector(this);
7980 const previousInjectImplementation = setInjectImplementation(undefined);
7981 try {
7982 // Check for the SkipSelf flag.
7983 if (!(flags & InjectFlags.SkipSelf)) {
7984 // SkipSelf isn't set, check if the record belongs to this injector.
7985 let record = this.records.get(token);
7986 if (record === undefined) {
7987 // No record, but maybe the token is scoped to this injector. Look for an injectable
7988 // def with a scope matching this injector.
7989 const def = couldBeInjectableType(token) && getInjectableDef(token);
7990 if (def && this.injectableDefInScope(def)) {
7991 // Found an injectable def and it's scoped to this injector. Pretend as if it was here
7992 // all along.
7993 record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET);
7994 }
7995 else {
7996 record = null;
7997 }
7998 this.records.set(token, record);
7999 }
8000 // If a record was found, get the instance for it and return it.
8001 if (record != null /* NOT null || undefined */) {
8002 return this.hydrate(token, record);
8003 }
8004 }
8005 // Select the next injector based on the Self flag - if self is set, the next injector is
8006 // the NullInjector, otherwise it's the parent.
8007 const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector();
8008 // Set the notFoundValue based on the Optional flag - if optional is set and notFoundValue
8009 // is undefined, the value is null, otherwise it's the notFoundValue.
8010 notFoundValue = (flags & InjectFlags.Optional) && notFoundValue === THROW_IF_NOT_FOUND ?
8011 null :
8012 notFoundValue;
8013 return nextInjector.get(token, notFoundValue);
8014 }
8015 catch (e) {
8016 if (e.name === 'NullInjectorError') {
8017 const path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || [];
8018 path.unshift(stringify(token));
8019 if (previousInjector) {
8020 // We still have a parent injector, keep throwing
8021 throw e;
8022 }
8023 else {
8024 // Format & throw the final error message when we don't have any previous injector
8025 return catchInjectorError(e, token, 'R3InjectorError', this.source);
8026 }
8027 }
8028 else {
8029 throw e;
8030 }
8031 }
8032 finally {
8033 // Lastly, restore the previous injection context.
8034 setInjectImplementation(previousInjectImplementation);
8035 setCurrentInjector(previousInjector);
8036 }
8037 }
8038 /** @internal */
8039 resolveInjectorInitializers() {
8040 const previousInjector = setCurrentInjector(this);
8041 const previousInjectImplementation = setInjectImplementation(undefined);
8042 try {
8043 const initializers = this.get(ENVIRONMENT_INITIALIZER.multi, EMPTY_ARRAY, InjectFlags.Self);
8044 if (ngDevMode && !Array.isArray(initializers)) {
8045 throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `ENVIRONMENT_INITIALIZER` token value ' +
8046 `(expected an array, but got ${typeof initializers}). ` +
8047 'Please check that the `ENVIRONMENT_INITIALIZER` token is configured as a ' +
8048 '`multi: true` provider.');
8049 }
8050 for (const initializer of initializers) {
8051 initializer();
8052 }
8053 }
8054 finally {
8055 setCurrentInjector(previousInjector);
8056 setInjectImplementation(previousInjectImplementation);
8057 }
8058 }
8059 toString() {
8060 const tokens = [];
8061 const records = this.records;
8062 for (const token of records.keys()) {
8063 tokens.push(stringify(token));
8064 }
8065 return `R3Injector[${tokens.join(', ')}]`;
8066 }
8067 assertNotDestroyed() {
8068 if (this._destroyed) {
8069 throw new RuntimeError(205 /* RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED */, ngDevMode && 'Injector has already been destroyed.');
8070 }
8071 }
8072 /**
8073 * Process a `SingleProvider` and add it.
8074 */
8075 processProvider(provider) {
8076 // Determine the token from the provider. Either it's its own token, or has a {provide: ...}
8077 // property.
8078 provider = resolveForwardRef(provider);
8079 let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider && provider.provide);
8080 // Construct a `Record` for the provider.
8081 const record = providerToRecord(provider);
8082 if (!isTypeProvider(provider) && provider.multi === true) {
8083 // If the provider indicates that it's a multi-provider, process it specially.
8084 // First check whether it's been defined already.
8085 let multiRecord = this.records.get(token);
8086 if (multiRecord) {
8087 // It has. Throw a nice error if
8088 if (ngDevMode && multiRecord.multi === undefined) {
8089 throwMixedMultiProviderError();
8090 }
8091 }
8092 else {
8093 multiRecord = makeRecord(undefined, NOT_YET, true);
8094 multiRecord.factory = () => injectArgs(multiRecord.multi);
8095 this.records.set(token, multiRecord);
8096 }
8097 token = provider;
8098 multiRecord.multi.push(provider);
8099 }
8100 else {
8101 const existing = this.records.get(token);
8102 if (ngDevMode && existing && existing.multi !== undefined) {
8103 throwMixedMultiProviderError();
8104 }
8105 }
8106 this.records.set(token, record);
8107 }
8108 hydrate(token, record) {
8109 if (ngDevMode && record.value === CIRCULAR) {
8110 throwCyclicDependencyError(stringify(token));
8111 }
8112 else if (record.value === NOT_YET) {
8113 record.value = CIRCULAR;
8114 record.value = record.factory();
8115 }
8116 if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) {
8117 this._ngOnDestroyHooks.add(record.value);
8118 }
8119 return record.value;
8120 }
8121 injectableDefInScope(def) {
8122 if (!def.providedIn) {
8123 return false;
8124 }
8125 const providedIn = resolveForwardRef(def.providedIn);
8126 if (typeof providedIn === 'string') {
8127 return providedIn === 'any' || (this.scopes.has(providedIn));
8128 }
8129 else {
8130 return this.injectorDefTypes.has(providedIn);
8131 }
8132 }
8133}
8134function injectableDefOrInjectorDefFactory(token) {
8135 // Most tokens will have an injectable def directly on them, which specifies a factory directly.
8136 const injectableDef = getInjectableDef(token);
8137 const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token);
8138 if (factory !== null) {
8139 return factory;
8140 }
8141 // InjectionTokens should have an injectable def (ɵprov) and thus should be handled above.
8142 // If it's missing that, it's an error.
8143 if (token instanceof InjectionToken) {
8144 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Token ${stringify(token)} is missing a ɵprov definition.`);
8145 }
8146 // Undecorated types can sometimes be created if they have no constructor arguments.
8147 if (token instanceof Function) {
8148 return getUndecoratedInjectableFactory(token);
8149 }
8150 // There was no way to resolve a factory for this token.
8151 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && 'unreachable');
8152}
8153function getUndecoratedInjectableFactory(token) {
8154 // If the token has parameters then it has dependencies that we cannot resolve implicitly.
8155 const paramLength = token.length;
8156 if (paramLength > 0) {
8157 const args = newArray(paramLength, '?');
8158 throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Can't resolve all parameters for ${stringify(token)}: (${args.join(', ')}).`);
8159 }
8160 // The constructor function appears to have no parameters.
8161 // This might be because it inherits from a super-class. In which case, use an injectable
8162 // def from an ancestor if there is one.
8163 // Otherwise this really is a simple class with no dependencies, so return a factory that
8164 // just instantiates the zero-arg constructor.
8165 const inheritedInjectableDef = getInheritedInjectableDef(token);
8166 if (inheritedInjectableDef !== null) {
8167 return () => inheritedInjectableDef.factory(token);
8168 }
8169 else {
8170 return () => new token();
8171 }
8172}
8173function providerToRecord(provider) {
8174 if (isValueProvider(provider)) {
8175 return makeRecord(undefined, provider.useValue);
8176 }
8177 else {
8178 const factory = providerToFactory(provider);
8179 return makeRecord(factory, NOT_YET);
8180 }
8181}
8182/**
8183 * Converts a `SingleProvider` into a factory function.
8184 *
8185 * @param provider provider to convert to factory
8186 */
8187function providerToFactory(provider, ngModuleType, providers) {
8188 let factory = undefined;
8189 if (ngDevMode && isEnvironmentProviders(provider)) {
8190 throwInvalidProviderError(undefined, providers, provider);
8191 }
8192 if (isTypeProvider(provider)) {
8193 const unwrappedProvider = resolveForwardRef(provider);
8194 return getFactoryDef(unwrappedProvider) || injectableDefOrInjectorDefFactory(unwrappedProvider);
8195 }
8196 else {
8197 if (isValueProvider(provider)) {
8198 factory = () => resolveForwardRef(provider.useValue);
8199 }
8200 else if (isFactoryProvider(provider)) {
8201 factory = () => provider.useFactory(...injectArgs(provider.deps || []));
8202 }
8203 else if (isExistingProvider(provider)) {
8204 factory = () => ɵɵinject(resolveForwardRef(provider.useExisting));
8205 }
8206 else {
8207 const classRef = resolveForwardRef(provider &&
8208 (provider.useClass || provider.provide));
8209 if (ngDevMode && !classRef) {
8210 throwInvalidProviderError(ngModuleType, providers, provider);
8211 }
8212 if (hasDeps(provider)) {
8213 factory = () => new (classRef)(...injectArgs(provider.deps));
8214 }
8215 else {
8216 return getFactoryDef(classRef) || injectableDefOrInjectorDefFactory(classRef);
8217 }
8218 }
8219 }
8220 return factory;
8221}
8222function makeRecord(factory, value, multi = false) {
8223 return {
8224 factory: factory,
8225 value: value,
8226 multi: multi ? [] : undefined,
8227 };
8228}
8229function hasDeps(value) {
8230 return !!value.deps;
8231}
8232function hasOnDestroy(value) {
8233 return value !== null && typeof value === 'object' &&
8234 typeof value.ngOnDestroy === 'function';
8235}
8236function couldBeInjectableType(value) {
8237 return (typeof value === 'function') ||
8238 (typeof value === 'object' && value instanceof InjectionToken);
8239}
8240function forEachSingleProvider(providers, fn) {
8241 for (const provider of providers) {
8242 if (Array.isArray(provider)) {
8243 forEachSingleProvider(provider, fn);
8244 }
8245 else if (provider && isEnvironmentProviders(provider)) {
8246 forEachSingleProvider(provider.ɵproviders, fn);
8247 }
8248 else {
8249 fn(provider);
8250 }
8251 }
8252}
8253
8254/**
8255 * Represents a component created by a `ComponentFactory`.
8256 * Provides access to the component instance and related objects,
8257 * and provides the means of destroying the instance.
8258 *
8259 * @publicApi
8260 */
8261class ComponentRef$1 {
8262}
8263/**
8264 * Base class for a factory that can create a component dynamically.
8265 * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
8266 * Use the resulting `ComponentFactory.create()` method to create a component of that type.
8267 *
8268 * @see [Dynamic Components](guide/dynamic-component-loader)
8269 *
8270 * @publicApi
8271 *
8272 * @deprecated Angular no longer requires Component factories. Please use other APIs where
8273 * Component class can be used directly.
8274 */
8275class ComponentFactory$1 {
8276}
8277
8278function noComponentFactoryError(component) {
8279 const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
8280 error[ERROR_COMPONENT] = component;
8281 return error;
8282}
8283const ERROR_COMPONENT = 'ngComponent';
8284function getComponent$1(error) {
8285 return error[ERROR_COMPONENT];
8286}
8287class _NullComponentFactoryResolver {
8288 resolveComponentFactory(component) {
8289 throw noComponentFactoryError(component);
8290 }
8291}
8292/**
8293 * A simple registry that maps `Components` to generated `ComponentFactory` classes
8294 * that can be used to create instances of components.
8295 * Use to obtain the factory for a given component type,
8296 * then use the factory's `create()` method to create a component of that type.
8297 *
8298 * Note: since v13, dynamic component creation via
8299 * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
8300 * does **not** require resolving component factory: component class can be used directly.
8301 *
8302 * @publicApi
8303 *
8304 * @deprecated Angular no longer requires Component factories. Please use other APIs where
8305 * Component class can be used directly.
8306 */
8307class ComponentFactoryResolver$1 {
8308}
8309ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
8310
8311/**
8312 * Creates an ElementRef from the most recent node.
8313 *
8314 * @returns The ElementRef instance to use
8315 */
8316function injectElementRef() {
8317 return createElementRef(getCurrentTNode(), getLView());
8318}
8319/**
8320 * Creates an ElementRef given a node.
8321 *
8322 * @param tNode The node for which you'd like an ElementRef
8323 * @param lView The view to which the node belongs
8324 * @returns The ElementRef instance to use
8325 */
8326function createElementRef(tNode, lView) {
8327 return new ElementRef(getNativeByTNode(tNode, lView));
8328}
8329/**
8330 * A wrapper around a native element inside of a View.
8331 *
8332 * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
8333 * element.
8334 *
8335 * @security Permitting direct access to the DOM can make your application more vulnerable to
8336 * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
8337 * [Security Guide](https://g.co/ng/security).
8338 *
8339 * @publicApi
8340 */
8341// Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
8342// i.e. users have to ask for what they need. With that, we can build better analysis tools
8343// and could do better codegen in the future.
8344class ElementRef {
8345 constructor(nativeElement) {
8346 this.nativeElement = nativeElement;
8347 }
8348}
8349/**
8350 * @internal
8351 * @nocollapse
8352 */
8353ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
8354/**
8355 * Unwraps `ElementRef` and return the `nativeElement`.
8356 *
8357 * @param value value to unwrap
8358 * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
8359 */
8360function unwrapElementRef(value) {
8361 return value instanceof ElementRef ? value.nativeElement : value;
8362}
8363
8364/**
8365 * Creates and initializes a custom renderer that implements the `Renderer2` base class.
8366 *
8367 * @publicApi
8368 */
8369class RendererFactory2 {
8370}
8371/**
8372 * Extend this base class to implement custom rendering. By default, Angular
8373 * renders a template into DOM. You can use custom rendering to intercept
8374 * rendering calls, or to render to something other than DOM.
8375 *
8376 * Create your custom renderer using `RendererFactory2`.
8377 *
8378 * Use a custom renderer to bypass Angular's templating and
8379 * make custom UI changes that can't be expressed declaratively.
8380 * For example if you need to set a property or an attribute whose name is
8381 * not statically known, use the `setProperty()` or
8382 * `setAttribute()` method.
8383 *
8384 * @publicApi
8385 */
8386class Renderer2 {
8387}
8388/**
8389 * @internal
8390 * @nocollapse
8391 */
8392Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
8393/** Injects a Renderer2 for the current component. */
8394function injectRenderer2() {
8395 // We need the Renderer to be based on the component that it's being injected into, however since
8396 // DI happens before we've entered its view, `getLView` will return the parent view instead.
8397 const lView = getLView();
8398 const tNode = getCurrentTNode();
8399 const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
8400 return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
8401}
8402
8403/**
8404 * Sanitizer is used by the views to sanitize potentially dangerous values.
8405 *
8406 * @publicApi
8407 */
8408class Sanitizer {
8409}
8410/** @nocollapse */
8411Sanitizer.ɵprov = ɵɵdefineInjectable({
8412 token: Sanitizer,
8413 providedIn: 'root',
8414 factory: () => null,
8415});
8416
8417/**
8418 * @description Represents the version of Angular
8419 *
8420 * @publicApi
8421 */
8422class Version {
8423 constructor(full) {
8424 this.full = full;
8425 this.major = full.split('.')[0];
8426 this.minor = full.split('.')[1];
8427 this.patch = full.split('.').slice(2).join('.');
8428 }
8429}
8430/**
8431 * @publicApi
8432 */
8433const VERSION = new Version('15.1.5');
8434
8435// This default value is when checking the hierarchy for a token.
8436//
8437// It means both:
8438// - the token is not provided by the current injector,
8439// - only the element injectors should be checked (ie do not check module injectors
8440//
8441// mod1
8442// /
8443// el1 mod2
8444// \ /
8445// el2
8446//
8447// When requesting el2.injector.get(token), we should check in the following order and return the
8448// first found value:
8449// - el2.injector.get(token, default)
8450// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
8451// - mod2.injector.get(token, default)
8452const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
8453
8454const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
8455function wrappedError(message, originalError) {
8456 const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
8457 const error = Error(msg);
8458 error[ERROR_ORIGINAL_ERROR] = originalError;
8459 return error;
8460}
8461function getOriginalError(error) {
8462 return error[ERROR_ORIGINAL_ERROR];
8463}
8464
8465/**
8466 * Provides a hook for centralized exception handling.
8467 *
8468 * The default implementation of `ErrorHandler` prints error messages to the `console`. To
8469 * intercept error handling, write a custom exception handler that replaces this default as
8470 * appropriate for your app.
8471 *
8472 * @usageNotes
8473 * ### Example
8474 *
8475 * ```
8476 * class MyErrorHandler implements ErrorHandler {
8477 * handleError(error) {
8478 * // do something with the exception
8479 * }
8480 * }
8481 *
8482 * @NgModule({
8483 * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
8484 * })
8485 * class MyModule {}
8486 * ```
8487 *
8488 * @publicApi
8489 */
8490class ErrorHandler {
8491 constructor() {
8492 /**
8493 * @internal
8494 */
8495 this._console = console;
8496 }
8497 handleError(error) {
8498 const originalError = this._findOriginalError(error);
8499 this._console.error('ERROR', error);
8500 if (originalError) {
8501 this._console.error('ORIGINAL ERROR', originalError);
8502 }
8503 }
8504 /** @internal */
8505 _findOriginalError(error) {
8506 let e = error && getOriginalError(error);
8507 while (e && getOriginalError(e)) {
8508 e = getOriginalError(e);
8509 }
8510 return e || null;
8511 }
8512}
8513
8514function normalizeDebugBindingName(name) {
8515 // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
8516 name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
8517 return `ng-reflect-${name}`;
8518}
8519const CAMEL_CASE_REGEXP = /([A-Z])/g;
8520function camelCaseToDashCase(input) {
8521 return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
8522}
8523function normalizeDebugBindingValue(value) {
8524 try {
8525 // Limit the size of the value as otherwise the DOM just gets polluted.
8526 return value != null ? value.toString().slice(0, 30) : value;
8527 }
8528 catch (e) {
8529 return '[ERROR] Exception while trying to serialize the value';
8530 }
8531}
8532
8533/**
8534 *
8535 * @codeGenApi
8536 */
8537function ɵɵresolveWindow(element) {
8538 return element.ownerDocument.defaultView;
8539}
8540/**
8541 *
8542 * @codeGenApi
8543 */
8544function ɵɵresolveDocument(element) {
8545 return element.ownerDocument;
8546}
8547/**
8548 *
8549 * @codeGenApi
8550 */
8551function ɵɵresolveBody(element) {
8552 return element.ownerDocument.body;
8553}
8554/**
8555 * The special delimiter we use to separate property names, prefixes, and suffixes
8556 * in property binding metadata. See storeBindingMetadata().
8557 *
8558 * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter
8559 * because it is a very uncommon character that is unlikely to be part of a user's
8560 * property names or interpolation strings. If it is in fact used in a property
8561 * binding, DebugElement.properties will not return the correct value for that
8562 * binding. However, there should be no runtime effect for real applications.
8563 *
8564 * This character is typically rendered as a question mark inside of a diamond.
8565 * See https://en.wikipedia.org/wiki/Specials_(Unicode_block)
8566 *
8567 */
8568const INTERPOLATION_DELIMITER = `�`;
8569/**
8570 * Unwrap a value which might be behind a closure (for forward declaration reasons).
8571 */
8572function maybeUnwrapFn(value) {
8573 if (value instanceof Function) {
8574 return value();
8575 }
8576 else {
8577 return value;
8578 }
8579}
8580
8581/** Verifies that a given type is a Standalone Component. */
8582function assertStandaloneComponentType(type) {
8583 assertComponentDef(type);
8584 const componentDef = getComponentDef(type);
8585 if (!componentDef.standalone) {
8586 throw new RuntimeError(907 /* RuntimeErrorCode.TYPE_IS_NOT_STANDALONE */, `The ${stringifyForError(type)} component is not marked as standalone, ` +
8587 `but Angular expects to have a standalone component here. ` +
8588 `Please make sure the ${stringifyForError(type)} component has ` +
8589 `the \`standalone: true\` flag in the decorator.`);
8590 }
8591}
8592/** Verifies whether a given type is a component */
8593function assertComponentDef(type) {
8594 if (!getComponentDef(type)) {
8595 throw new RuntimeError(906 /* RuntimeErrorCode.MISSING_GENERATED_DEF */, `The ${stringifyForError(type)} is not an Angular component, ` +
8596 `make sure it has the \`@Component\` decorator.`);
8597 }
8598}
8599/** Called when there are multiple component selectors that match a given node */
8600function throwMultipleComponentError(tNode, first, second) {
8601 throw new RuntimeError(-300 /* RuntimeErrorCode.MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
8602 `${stringifyForError(first)} and ` +
8603 `${stringifyForError(second)}`);
8604}
8605/** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
8606function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
8607 const field = propName ? ` for '${propName}'` : '';
8608 let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
8609 if (creationMode) {
8610 msg +=
8611 ` It seems like the view has been created after its parent and its children have been dirty checked.` +
8612 ` Has it been created in a change detection hook?`;
8613 }
8614 throw new RuntimeError(-100 /* RuntimeErrorCode.EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
8615}
8616function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
8617 const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
8618 let oldValue = prefix, newValue = prefix;
8619 for (let i = 0; i < chunks.length; i++) {
8620 const slotIdx = rootIndex + i;
8621 oldValue += `${lView[slotIdx]}${chunks[i]}`;
8622 newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
8623 }
8624 return { propName, oldValue, newValue };
8625}
8626/**
8627 * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
8628 * - property name (for property bindings or interpolations)
8629 * - old and new values, enriched using information from metadata
8630 *
8631 * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
8632 * function description.
8633 */
8634function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
8635 const tData = lView[TVIEW].data;
8636 const metadata = tData[bindingIndex];
8637 if (typeof metadata === 'string') {
8638 // metadata for property interpolation
8639 if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
8640 return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
8641 }
8642 // metadata for property binding
8643 return { propName: metadata, oldValue, newValue };
8644 }
8645 // metadata is not available for this expression, check if this expression is a part of the
8646 // property interpolation by going from the current binding index left and look for a string that
8647 // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
8648 // [..., 'id�Prefix � and � suffix', null, null, null, ...]
8649 if (metadata === null) {
8650 let idx = bindingIndex - 1;
8651 while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
8652 idx--;
8653 }
8654 const meta = tData[idx];
8655 if (typeof meta === 'string') {
8656 const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
8657 // first interpolation delimiter separates property name from interpolation parts (in case of
8658 // property interpolations), so we subtract one from total number of found delimiters
8659 if (matches && (matches.length - 1) > bindingIndex - idx) {
8660 return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
8661 }
8662 }
8663 }
8664 return { propName: undefined, oldValue, newValue };
8665}
8666
8667/**
8668 * Returns an index of `classToSearch` in `className` taking token boundaries into account.
8669 *
8670 * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
8671 *
8672 * @param className A string containing classes (whitespace separated)
8673 * @param classToSearch A class name to locate
8674 * @param startingIndex Starting location of search
8675 * @returns an index of the located class (or -1 if not found)
8676 */
8677function classIndexOf(className, classToSearch, startingIndex) {
8678 ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
8679 let end = className.length;
8680 while (true) {
8681 const foundIndex = className.indexOf(classToSearch, startingIndex);
8682 if (foundIndex === -1)
8683 return foundIndex;
8684 if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* CharCode.SPACE */) {
8685 // Ensure that it has leading whitespace
8686 const length = classToSearch.length;
8687 if (foundIndex + length === end ||
8688 className.charCodeAt(foundIndex + length) <= 32 /* CharCode.SPACE */) {
8689 // Ensure that it has trailing whitespace
8690 return foundIndex;
8691 }
8692 }
8693 // False positive, keep searching from where we left off.
8694 startingIndex = foundIndex + 1;
8695 }
8696}
8697
8698const NG_TEMPLATE_SELECTOR = 'ng-template';
8699/**
8700 * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
8701 *
8702 * @param attrs `TAttributes` to search through.
8703 * @param cssClassToMatch class to match (lowercase)
8704 * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
8705 * addition to the `AttributeMarker.Classes`.
8706 */
8707function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
8708 // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
8709 // It is strange to me that sometimes the class information comes in form of `class` attribute
8710 // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
8711 // if that is the right behavior.
8712 ngDevMode &&
8713 assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
8714 let i = 0;
8715 while (i < attrs.length) {
8716 let item = attrs[i++];
8717 if (isProjectionMode && item === 'class') {
8718 item = attrs[i];
8719 if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
8720 return true;
8721 }
8722 }
8723 else if (item === 1 /* AttributeMarker.Classes */) {
8724 // We found the classes section. Start searching for the class.
8725 while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
8726 // while we have strings
8727 if (item.toLowerCase() === cssClassToMatch)
8728 return true;
8729 }
8730 return false;
8731 }
8732 }
8733 return false;
8734}
8735/**
8736 * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
8737 *
8738 * @param tNode current TNode
8739 */
8740function isInlineTemplate(tNode) {
8741 return tNode.type === 4 /* TNodeType.Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
8742}
8743/**
8744 * Function that checks whether a given tNode matches tag-based selector and has a valid type.
8745 *
8746 * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
8747 * directive matching mode:
8748 * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
8749 * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
8750 * tag name was extracted from * syntax so we would match the same directive twice);
8751 * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
8752 * (applicable to TNodeType.Container only).
8753 */
8754function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
8755 const tagNameToCompare = tNode.type === 4 /* TNodeType.Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
8756 return currentSelector === tagNameToCompare;
8757}
8758/**
8759 * A utility function to match an Ivy node static data against a simple CSS selector
8760 *
8761 * @param node static data of the node to match
8762 * @param selector The selector to try matching against the node.
8763 * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
8764 * directive matching.
8765 * @returns true if node matches the selector.
8766 */
8767function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
8768 ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
8769 let mode = 4 /* SelectorFlags.ELEMENT */;
8770 const nodeAttrs = tNode.attrs || [];
8771 // Find the index of first attribute that has no value, only a name.
8772 const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
8773 // When processing ":not" selectors, we skip to the next ":not" if the
8774 // current one doesn't match
8775 let skipToNextSelector = false;
8776 for (let i = 0; i < selector.length; i++) {
8777 const current = selector[i];
8778 if (typeof current === 'number') {
8779 // If we finish processing a :not selector and it hasn't failed, return false
8780 if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
8781 return false;
8782 }
8783 // If we are skipping to the next :not() and this mode flag is positive,
8784 // it's a part of the current :not() selector, and we should keep skipping
8785 if (skipToNextSelector && isPositive(current))
8786 continue;
8787 skipToNextSelector = false;
8788 mode = current | (mode & 1 /* SelectorFlags.NOT */);
8789 continue;
8790 }
8791 if (skipToNextSelector)
8792 continue;
8793 if (mode & 4 /* SelectorFlags.ELEMENT */) {
8794 mode = 2 /* SelectorFlags.ATTRIBUTE */ | mode & 1 /* SelectorFlags.NOT */;
8795 if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
8796 current === '' && selector.length === 1) {
8797 if (isPositive(mode))
8798 return false;
8799 skipToNextSelector = true;
8800 }
8801 }
8802 else {
8803 const selectorAttrValue = mode & 8 /* SelectorFlags.CLASS */ ? current : selector[++i];
8804 // special case for matching against classes when a tNode has been instantiated with
8805 // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
8806 if ((mode & 8 /* SelectorFlags.CLASS */) && tNode.attrs !== null) {
8807 if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
8808 if (isPositive(mode))
8809 return false;
8810 skipToNextSelector = true;
8811 }
8812 continue;
8813 }
8814 const attrName = (mode & 8 /* SelectorFlags.CLASS */) ? 'class' : current;
8815 const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
8816 if (attrIndexInNode === -1) {
8817 if (isPositive(mode))
8818 return false;
8819 skipToNextSelector = true;
8820 continue;
8821 }
8822 if (selectorAttrValue !== '') {
8823 let nodeAttrValue;
8824 if (attrIndexInNode > nameOnlyMarkerIdx) {
8825 nodeAttrValue = '';
8826 }
8827 else {
8828 ngDevMode &&
8829 assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* AttributeMarker.NamespaceURI */, 'We do not match directives on namespaced attributes');
8830 // we lowercase the attribute value to be able to match
8831 // selectors without case-sensitivity
8832 // (selectors are already in lowercase when generated)
8833 nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
8834 }
8835 const compareAgainstClassName = mode & 8 /* SelectorFlags.CLASS */ ? nodeAttrValue : null;
8836 if (compareAgainstClassName &&
8837 classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
8838 mode & 2 /* SelectorFlags.ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
8839 if (isPositive(mode))
8840 return false;
8841 skipToNextSelector = true;
8842 }
8843 }
8844 }
8845 }
8846 return isPositive(mode) || skipToNextSelector;
8847}
8848function isPositive(mode) {
8849 return (mode & 1 /* SelectorFlags.NOT */) === 0;
8850}
8851/**
8852 * Examines the attribute's definition array for a node to find the index of the
8853 * attribute that matches the given `name`.
8854 *
8855 * NOTE: This will not match namespaced attributes.
8856 *
8857 * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
8858 * The following table summarizes which types of attributes we attempt to match:
8859 *
8860 * ===========================================================================================================
8861 * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
8862 * Attributes
8863 * ===========================================================================================================
8864 * Inline + Projection | YES | YES | NO | YES
8865 * -----------------------------------------------------------------------------------------------------------
8866 * Inline + Directive | NO | NO | YES | NO
8867 * -----------------------------------------------------------------------------------------------------------
8868 * Non-inline + Projection | YES | YES | NO | YES
8869 * -----------------------------------------------------------------------------------------------------------
8870 * Non-inline + Directive | YES | YES | NO | YES
8871 * ===========================================================================================================
8872 *
8873 * @param name the name of the attribute to find
8874 * @param attrs the attribute array to examine
8875 * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
8876 * rather than a manually expanded template node (e.g `<ng-template>`).
8877 * @param isProjectionMode true if we are matching against content projection otherwise we are
8878 * matching against directives.
8879 */
8880function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
8881 if (attrs === null)
8882 return -1;
8883 let i = 0;
8884 if (isProjectionMode || !isInlineTemplate) {
8885 let bindingsMode = false;
8886 while (i < attrs.length) {
8887 const maybeAttrName = attrs[i];
8888 if (maybeAttrName === name) {
8889 return i;
8890 }
8891 else if (maybeAttrName === 3 /* AttributeMarker.Bindings */ || maybeAttrName === 6 /* AttributeMarker.I18n */) {
8892 bindingsMode = true;
8893 }
8894 else if (maybeAttrName === 1 /* AttributeMarker.Classes */ || maybeAttrName === 2 /* AttributeMarker.Styles */) {
8895 let value = attrs[++i];
8896 // We should skip classes here because we have a separate mechanism for
8897 // matching classes in projection mode.
8898 while (typeof value === 'string') {
8899 value = attrs[++i];
8900 }
8901 continue;
8902 }
8903 else if (maybeAttrName === 4 /* AttributeMarker.Template */) {
8904 // We do not care about Template attributes in this scenario.
8905 break;
8906 }
8907 else if (maybeAttrName === 0 /* AttributeMarker.NamespaceURI */) {
8908 // Skip the whole namespaced attribute and value. This is by design.
8909 i += 4;
8910 continue;
8911 }
8912 // In binding mode there are only names, rather than name-value pairs.
8913 i += bindingsMode ? 1 : 2;
8914 }
8915 // We did not match the attribute
8916 return -1;
8917 }
8918 else {
8919 return matchTemplateAttribute(attrs, name);
8920 }
8921}
8922function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
8923 for (let i = 0; i < selector.length; i++) {
8924 if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
8925 return true;
8926 }
8927 }
8928 return false;
8929}
8930function getProjectAsAttrValue(tNode) {
8931 const nodeAttrs = tNode.attrs;
8932 if (nodeAttrs != null) {
8933 const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* AttributeMarker.ProjectAs */);
8934 // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
8935 // (attribute names are stored at even indexes)
8936 if ((ngProjectAsAttrIdx & 1) === 0) {
8937 return nodeAttrs[ngProjectAsAttrIdx + 1];
8938 }
8939 }
8940 return null;
8941}
8942function getNameOnlyMarkerIndex(nodeAttrs) {
8943 for (let i = 0; i < nodeAttrs.length; i++) {
8944 const nodeAttr = nodeAttrs[i];
8945 if (isNameOnlyAttributeMarker(nodeAttr)) {
8946 return i;
8947 }
8948 }
8949 return nodeAttrs.length;
8950}
8951function matchTemplateAttribute(attrs, name) {
8952 let i = attrs.indexOf(4 /* AttributeMarker.Template */);
8953 if (i > -1) {
8954 i++;
8955 while (i < attrs.length) {
8956 const attr = attrs[i];
8957 // Return in case we checked all template attrs and are switching to the next section in the
8958 // attrs array (that starts with a number that represents an attribute marker).
8959 if (typeof attr === 'number')
8960 return -1;
8961 if (attr === name)
8962 return i;
8963 i++;
8964 }
8965 }
8966 return -1;
8967}
8968/**
8969 * Checks whether a selector is inside a CssSelectorList
8970 * @param selector Selector to be checked.
8971 * @param list List in which to look for the selector.
8972 */
8973function isSelectorInSelectorList(selector, list) {
8974 selectorListLoop: for (let i = 0; i < list.length; i++) {
8975 const currentSelectorInList = list[i];
8976 if (selector.length !== currentSelectorInList.length) {
8977 continue;
8978 }
8979 for (let j = 0; j < selector.length; j++) {
8980 if (selector[j] !== currentSelectorInList[j]) {
8981 continue selectorListLoop;
8982 }
8983 }
8984 return true;
8985 }
8986 return false;
8987}
8988function maybeWrapInNotSelector(isNegativeMode, chunk) {
8989 return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
8990}
8991function stringifyCSSSelector(selector) {
8992 let result = selector[0];
8993 let i = 1;
8994 let mode = 2 /* SelectorFlags.ATTRIBUTE */;
8995 let currentChunk = '';
8996 let isNegativeMode = false;
8997 while (i < selector.length) {
8998 let valueOrMarker = selector[i];
8999 if (typeof valueOrMarker === 'string') {
9000 if (mode & 2 /* SelectorFlags.ATTRIBUTE */) {
9001 const attrValue = selector[++i];
9002 currentChunk +=
9003 '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
9004 }
9005 else if (mode & 8 /* SelectorFlags.CLASS */) {
9006 currentChunk += '.' + valueOrMarker;
9007 }
9008 else if (mode & 4 /* SelectorFlags.ELEMENT */) {
9009 currentChunk += ' ' + valueOrMarker;
9010 }
9011 }
9012 else {
9013 //
9014 // Append current chunk to the final result in case we come across SelectorFlag, which
9015 // indicates that the previous section of a selector is over. We need to accumulate content
9016 // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
9017 // ```
9018 // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
9019 // ```
9020 // should be transformed to `.classA :not(.classB .classC)`.
9021 //
9022 // Note: for negative selector part, we accumulate content between flags until we find the
9023 // next negative flag. This is needed to support a case where `:not()` rule contains more than
9024 // one chunk, e.g. the following selector:
9025 // ```
9026 // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
9027 // ```
9028 // should be stringified to `:not(p.foo) :not(.bar)`
9029 //
9030 if (currentChunk !== '' && !isPositive(valueOrMarker)) {
9031 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9032 currentChunk = '';
9033 }
9034 mode = valueOrMarker;
9035 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9036 // mode is maintained for remaining chunks of a selector.
9037 isNegativeMode = isNegativeMode || !isPositive(mode);
9038 }
9039 i++;
9040 }
9041 if (currentChunk !== '') {
9042 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9043 }
9044 return result;
9045}
9046/**
9047 * Generates string representation of CSS selector in parsed form.
9048 *
9049 * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
9050 * additional parsing at runtime (for example, for directive matching). However in some cases (for
9051 * example, while bootstrapping a component), a string version of the selector is required to query
9052 * for the host element on the page. This function takes the parsed form of a selector and returns
9053 * its string representation.
9054 *
9055 * @param selectorList selector in parsed form
9056 * @returns string representation of a given selector
9057 */
9058function stringifyCSSSelectorList(selectorList) {
9059 return selectorList.map(stringifyCSSSelector).join(',');
9060}
9061/**
9062 * Extracts attributes and classes information from a given CSS selector.
9063 *
9064 * This function is used while creating a component dynamically. In this case, the host element
9065 * (that is created dynamically) should contain attributes and classes specified in component's CSS
9066 * selector.
9067 *
9068 * @param selector CSS selector in parsed form (in a form of array)
9069 * @returns object with `attrs` and `classes` fields that contain extracted information
9070 */
9071function extractAttrsAndClassesFromSelector(selector) {
9072 const attrs = [];
9073 const classes = [];
9074 let i = 1;
9075 let mode = 2 /* SelectorFlags.ATTRIBUTE */;
9076 while (i < selector.length) {
9077 let valueOrMarker = selector[i];
9078 if (typeof valueOrMarker === 'string') {
9079 if (mode === 2 /* SelectorFlags.ATTRIBUTE */) {
9080 if (valueOrMarker !== '') {
9081 attrs.push(valueOrMarker, selector[++i]);
9082 }
9083 }
9084 else if (mode === 8 /* SelectorFlags.CLASS */) {
9085 classes.push(valueOrMarker);
9086 }
9087 }
9088 else {
9089 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9090 // mode is maintained for remaining chunks of a selector. Since attributes and classes are
9091 // extracted only for "positive" part of the selector, we can stop here.
9092 if (!isPositive(mode))
9093 break;
9094 mode = valueOrMarker;
9095 }
9096 i++;
9097 }
9098 return { attrs, classes };
9099}
9100
9101/** A special value which designates that a value has not changed. */
9102const NO_CHANGE = (typeof ngDevMode === 'undefined' || ngDevMode) ? { __brand__: 'NO_CHANGE' } : {};
9103
9104/**
9105 * Advances to an element for later binding instructions.
9106 *
9107 * Used in conjunction with instructions like {@link property} to act on elements with specified
9108 * indices, for example those created with {@link element} or {@link elementStart}.
9109 *
9110 * ```ts
9111 * (rf: RenderFlags, ctx: any) => {
9112 * if (rf & 1) {
9113 * text(0, 'Hello');
9114 * text(1, 'Goodbye')
9115 * element(2, 'div');
9116 * }
9117 * if (rf & 2) {
9118 * advance(2); // Advance twice to the <div>.
9119 * property('title', 'test');
9120 * }
9121 * }
9122 * ```
9123 * @param delta Number of elements to advance forwards by.
9124 *
9125 * @codeGenApi
9126 */
9127function ɵɵadvance(delta) {
9128 ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
9129 selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, !!ngDevMode && isInCheckNoChangesMode());
9130}
9131function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
9132 ngDevMode && assertIndexInDeclRange(lView, index);
9133 // Flush the initial hooks for elements in the view that have been added up to this point.
9134 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
9135 if (!checkNoChangesMode) {
9136 const hooksInitPhaseCompleted = (lView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
9137 if (hooksInitPhaseCompleted) {
9138 const preOrderCheckHooks = tView.preOrderCheckHooks;
9139 if (preOrderCheckHooks !== null) {
9140 executeCheckHooks(lView, preOrderCheckHooks, index);
9141 }
9142 }
9143 else {
9144 const preOrderHooks = tView.preOrderHooks;
9145 if (preOrderHooks !== null) {
9146 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, index);
9147 }
9148 }
9149 }
9150 // We must set the selected index *after* running the hooks, because hooks may have side-effects
9151 // that cause other template functions to run, thus updating the selected index, which is global
9152 // state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index
9153 // will be altered by the time we leave the `ɵɵadvance` instruction.
9154 setSelectedIndex(index);
9155}
9156
9157/**
9158 * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
9159 *
9160 * This should be kept up to date with the public exports of @angular/core.
9161 */
9162const angularCoreDiEnv = {
9163 'ɵɵdefineInjectable': ɵɵdefineInjectable,
9164 'ɵɵdefineInjector': ɵɵdefineInjector,
9165 'ɵɵinject': ɵɵinject,
9166 'ɵɵinvalidFactoryDep': ɵɵinvalidFactoryDep,
9167 'resolveForwardRef': resolveForwardRef,
9168};
9169
9170/**
9171 * Compile an Angular injectable according to its `Injectable` metadata, and patch the resulting
9172 * injectable def (`ɵprov`) onto the injectable type.
9173 */
9174function compileInjectable(type, meta) {
9175 let ngInjectableDef = null;
9176 let ngFactoryDef = null;
9177 // if NG_PROV_DEF is already defined on this class then don't overwrite it
9178 if (!type.hasOwnProperty(NG_PROV_DEF)) {
9179 Object.defineProperty(type, NG_PROV_DEF, {
9180 get: () => {
9181 if (ngInjectableDef === null) {
9182 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'injectable', type });
9183 ngInjectableDef = compiler.compileInjectable(angularCoreDiEnv, `ng:///${type.name}/ɵprov.js`, getInjectableMetadata(type, meta));
9184 }
9185 return ngInjectableDef;
9186 },
9187 });
9188 }
9189 // if NG_FACTORY_DEF is already defined on this class then don't overwrite it
9190 if (!type.hasOwnProperty(NG_FACTORY_DEF)) {
9191 Object.defineProperty(type, NG_FACTORY_DEF, {
9192 get: () => {
9193 if (ngFactoryDef === null) {
9194 const compiler = getCompilerFacade({ usage: 0 /* JitCompilerUsage.Decorator */, kind: 'injectable', type });
9195 ngFactoryDef = compiler.compileFactory(angularCoreDiEnv, `ng:///${type.name}/ɵfac.js`, {
9196 name: type.name,
9197 type,
9198 typeArgumentCount: 0,
9199 deps: reflectDependencies(type),
9200 target: compiler.FactoryTarget.Injectable
9201 });
9202 }
9203 return ngFactoryDef;
9204 },
9205 // Leave this configurable so that the factories from directives or pipes can take precedence.
9206 configurable: true
9207 });
9208 }
9209}
9210const USE_VALUE = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty });
9211function isUseClassProvider(meta) {
9212 return meta.useClass !== undefined;
9213}
9214function isUseValueProvider(meta) {
9215 return USE_VALUE in meta;
9216}
9217function isUseFactoryProvider(meta) {
9218 return meta.useFactory !== undefined;
9219}
9220function isUseExistingProvider(meta) {
9221 return meta.useExisting !== undefined;
9222}
9223function getInjectableMetadata(type, srcMeta) {
9224 // Allow the compilation of a class with a `@Injectable()` decorator without parameters
9225 const meta = srcMeta || { providedIn: null };
9226 const compilerMeta = {
9227 name: type.name,
9228 type: type,
9229 typeArgumentCount: 0,
9230 providedIn: meta.providedIn,
9231 };
9232 if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) {
9233 compilerMeta.deps = convertDependencies(meta.deps);
9234 }
9235 // Check to see if the user explicitly provided a `useXxxx` property.
9236 if (isUseClassProvider(meta)) {
9237 compilerMeta.useClass = meta.useClass;
9238 }
9239 else if (isUseValueProvider(meta)) {
9240 compilerMeta.useValue = meta.useValue;
9241 }
9242 else if (isUseFactoryProvider(meta)) {
9243 compilerMeta.useFactory = meta.useFactory;
9244 }
9245 else if (isUseExistingProvider(meta)) {
9246 compilerMeta.useExisting = meta.useExisting;
9247 }
9248 return compilerMeta;
9249}
9250
9251/**
9252 * Injectable decorator and metadata.
9253 *
9254 * @Annotation
9255 * @publicApi
9256 */
9257const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, (type, meta) => compileInjectable(type, meta));
9258
9259/**
9260 * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s.
9261 *
9262 * @publicApi
9263 */
9264function createInjector(defType, parent = null, additionalProviders = null, name) {
9265 const injector = createInjectorWithoutInjectorInstances(defType, parent, additionalProviders, name);
9266 injector.resolveInjectorInitializers();
9267 return injector;
9268}
9269/**
9270 * Creates a new injector without eagerly resolving its injector types. Can be used in places
9271 * where resolving the injector types immediately can lead to an infinite loop. The injector types
9272 * should be resolved at a later point by calling `_resolveInjectorDefTypes`.
9273 */
9274function createInjectorWithoutInjectorInstances(defType, parent = null, additionalProviders = null, name, scopes = new Set()) {
9275 const providers = [
9276 additionalProviders || EMPTY_ARRAY,
9277 importProvidersFrom(defType),
9278 ];
9279 name = name || (typeof defType === 'object' ? undefined : stringify(defType));
9280 return new R3Injector(providers, parent || getNullInjector(), name || null, scopes);
9281}
9282
9283/**
9284 * Concrete injectors implement this interface. Injectors are configured
9285 * with [providers](guide/glossary#provider) that associate
9286 * dependencies of various types with [injection tokens](guide/glossary#di-token).
9287 *
9288 * @see ["DI Providers"](guide/dependency-injection-providers).
9289 * @see `StaticProvider`
9290 *
9291 * @usageNotes
9292 *
9293 * The following example creates a service injector instance.
9294 *
9295 * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
9296 *
9297 * ### Usage example
9298 *
9299 * {@example core/di/ts/injector_spec.ts region='Injector'}
9300 *
9301 * `Injector` returns itself when given `Injector` as a token:
9302 *
9303 * {@example core/di/ts/injector_spec.ts region='injectInjector'}
9304 *
9305 * @publicApi
9306 */
9307class Injector {
9308 static create(options, parent) {
9309 var _a;
9310 if (Array.isArray(options)) {
9311 return createInjector({ name: '' }, parent, options, '');
9312 }
9313 else {
9314 const name = (_a = options.name) !== null && _a !== void 0 ? _a : '';
9315 return createInjector({ name }, options.parent, options.providers, name);
9316 }
9317 }
9318}
9319Injector.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
9320Injector.NULL = ( /* @__PURE__ */new NullInjector());
9321/** @nocollapse */
9322Injector.ɵprov = ɵɵdefineInjectable({
9323 token: Injector,
9324 providedIn: 'any',
9325 factory: () => ɵɵinject(INJECTOR),
9326});
9327/**
9328 * @internal
9329 * @nocollapse
9330 */
9331Injector.__NG_ELEMENT_ID__ = -1 /* InjectorMarkers.Injector */;
9332
9333function findFirstClosedCycle(keys) {
9334 const res = [];
9335 for (let i = 0; i < keys.length; ++i) {
9336 if (res.indexOf(keys[i]) > -1) {
9337 res.push(keys[i]);
9338 return res;
9339 }
9340 res.push(keys[i]);
9341 }
9342 return res;
9343}
9344function constructResolvingPath(keys) {
9345 if (keys.length > 1) {
9346 const reversed = findFirstClosedCycle(keys.slice().reverse());
9347 const tokenStrs = reversed.map(k => stringify(k.token));
9348 return ' (' + tokenStrs.join(' -> ') + ')';
9349 }
9350 return '';
9351}
9352function injectionError(injector, key, constructResolvingMessage, originalError) {
9353 const keys = [key];
9354 const errMsg = constructResolvingMessage(keys);
9355 const error = (originalError ? wrappedError(errMsg, originalError) : Error(errMsg));
9356 error.addKey = addKey;
9357 error.keys = keys;
9358 error.injectors = [injector];
9359 error.constructResolvingMessage = constructResolvingMessage;
9360 error[ERROR_ORIGINAL_ERROR] = originalError;
9361 return error;
9362}
9363function addKey(injector, key) {
9364 this.injectors.push(injector);
9365 this.keys.push(key);
9366 // Note: This updated message won't be reflected in the `.stack` property
9367 this.message = this.constructResolvingMessage(this.keys);
9368}
9369/**
9370 * Thrown when trying to retrieve a dependency by key from {@link Injector}, but the
9371 * {@link Injector} does not have a {@link Provider} for the given key.
9372 *
9373 * @usageNotes
9374 * ### Example
9375 *
9376 * ```typescript
9377 * class A {
9378 * constructor(b:B) {}
9379 * }
9380 *
9381 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
9382 * ```
9383 */
9384function noProviderError(injector, key) {
9385 return injectionError(injector, key, function (keys) {
9386 const first = stringify(keys[0].token);
9387 return `No provider for ${first}!${constructResolvingPath(keys)}`;
9388 });
9389}
9390/**
9391 * Thrown when dependencies form a cycle.
9392 *
9393 * @usageNotes
9394 * ### Example
9395 *
9396 * ```typescript
9397 * var injector = Injector.resolveAndCreate([
9398 * {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]},
9399 * {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]}
9400 * ]);
9401 *
9402 * expect(() => injector.get("one")).toThrowError();
9403 * ```
9404 *
9405 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
9406 */
9407function cyclicDependencyError(injector, key) {
9408 return injectionError(injector, key, function (keys) {
9409 return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
9410 });
9411}
9412/**
9413 * Thrown when a constructing type returns with an Error.
9414 *
9415 * The `InstantiationError` class contains the original error plus the dependency graph which caused
9416 * this object to be instantiated.
9417 *
9418 * @usageNotes
9419 * ### Example
9420 *
9421 * ```typescript
9422 * class A {
9423 * constructor() {
9424 * throw new Error('message');
9425 * }
9426 * }
9427 *
9428 * var injector = Injector.resolveAndCreate([A]);
9429
9430 * try {
9431 * injector.get(A);
9432 * } catch (e) {
9433 * expect(e instanceof InstantiationError).toBe(true);
9434 * expect(e.originalException.message).toEqual("message");
9435 * expect(e.originalStack).toBeDefined();
9436 * }
9437 * ```
9438 */
9439function instantiationError(injector, originalException, originalStack, key) {
9440 return injectionError(injector, key, function (keys) {
9441 const first = stringify(keys[0].token);
9442 return `${originalException.message}: Error during instantiation of ${first}!${constructResolvingPath(keys)}.`;
9443 }, originalException);
9444}
9445/**
9446 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
9447 * creation.
9448 *
9449 * @usageNotes
9450 * ### Example
9451 *
9452 * ```typescript
9453 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
9454 * ```
9455 */
9456function invalidProviderError(provider) {
9457 return Error(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
9458}
9459/**
9460 * Thrown when the class has no annotation information.
9461 *
9462 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
9463 * need to be injected into the constructor.
9464 *
9465 * @usageNotes
9466 * ### Example
9467 *
9468 * ```typescript
9469 * class A {
9470 * constructor(b) {}
9471 * }
9472 *
9473 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
9474 * ```
9475 *
9476 * This error is also thrown when the class not marked with {@link Injectable} has parameter types.
9477 *
9478 * ```typescript
9479 * class B {}
9480 *
9481 * class A {
9482 * constructor(b:B) {} // no information about the parameter types of A is available at runtime.
9483 * }
9484 *
9485 * expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
9486 * ```
9487 *
9488 */
9489function noAnnotationError(typeOrFunc, params) {
9490 const signature = [];
9491 for (let i = 0, ii = params.length; i < ii; i++) {
9492 const parameter = params[i];
9493 if (!parameter || parameter.length == 0) {
9494 signature.push('?');
9495 }
9496 else {
9497 signature.push(parameter.map(stringify).join(' '));
9498 }
9499 }
9500 return Error('Cannot resolve all parameters for \'' + stringify(typeOrFunc) + '\'(' +
9501 signature.join(', ') + '). ' +
9502 'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
9503 stringify(typeOrFunc) + '\' is decorated with Injectable.');
9504}
9505/**
9506 * Thrown when getting an object by index.
9507 *
9508 * @usageNotes
9509 * ### Example
9510 *
9511 * ```typescript
9512 * class A {}
9513 *
9514 * var injector = Injector.resolveAndCreate([A]);
9515 *
9516 * expect(() => injector.getAt(100)).toThrowError();
9517 * ```
9518 *
9519 */
9520function outOfBoundsError(index) {
9521 return Error(`Index ${index} is out-of-bounds.`);
9522}
9523// TODO: add a working example after alpha38 is released
9524/**
9525 * Thrown when a multi provider and a regular provider are bound to the same token.
9526 *
9527 * @usageNotes
9528 * ### Example
9529 *
9530 * ```typescript
9531 * expect(() => Injector.resolveAndCreate([
9532 * { provide: "Strings", useValue: "string1", multi: true},
9533 * { provide: "Strings", useValue: "string2", multi: false}
9534 * ])).toThrowError();
9535 * ```
9536 */
9537function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) {
9538 return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
9539}
9540
9541/**
9542 * A unique object used for retrieving items from the {@link ReflectiveInjector}.
9543 *
9544 * Keys have:
9545 * - a system-wide unique `id`.
9546 * - a `token`.
9547 *
9548 * `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
9549 * the
9550 * injector to store created objects in a more efficient way.
9551 *
9552 * `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
9553 * resolving
9554 * providers.
9555 *
9556 * @deprecated No replacement
9557 * @publicApi
9558 */
9559class ReflectiveKey {
9560 /**
9561 * Private
9562 */
9563 constructor(token, id) {
9564 this.token = token;
9565 this.id = id;
9566 if (!token) {
9567 throw new RuntimeError(208 /* RuntimeErrorCode.MISSING_INJECTION_TOKEN */, ngDevMode && 'Token must be defined!');
9568 }
9569 this.displayName = stringify(this.token);
9570 }
9571 /**
9572 * Retrieves a `Key` for a token.
9573 */
9574 static get(token) {
9575 return _globalKeyRegistry.get(resolveForwardRef(token));
9576 }
9577 /**
9578 * @returns the number of keys registered in the system.
9579 */
9580 static get numberOfKeys() {
9581 return _globalKeyRegistry.numberOfKeys;
9582 }
9583}
9584class KeyRegistry {
9585 constructor() {
9586 this._allKeys = new Map();
9587 }
9588 get(token) {
9589 if (token instanceof ReflectiveKey)
9590 return token;
9591 if (this._allKeys.has(token)) {
9592 return this._allKeys.get(token);
9593 }
9594 const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
9595 this._allKeys.set(token, newKey);
9596 return newKey;
9597 }
9598 get numberOfKeys() {
9599 return this._allKeys.size;
9600 }
9601}
9602const _globalKeyRegistry = new KeyRegistry();
9603
9604/**
9605 * `Dependency` is used by the framework to extend DI.
9606 * This is internal to Angular and should not be used directly.
9607 */
9608class ReflectiveDependency {
9609 constructor(key, optional, visibility) {
9610 this.key = key;
9611 this.optional = optional;
9612 this.visibility = visibility;
9613 }
9614 static fromKey(key) {
9615 return new ReflectiveDependency(key, false, null);
9616 }
9617}
9618const _EMPTY_LIST = [];
9619class ResolvedReflectiveProvider_ {
9620 constructor(key, resolvedFactories, multiProvider) {
9621 this.key = key;
9622 this.resolvedFactories = resolvedFactories;
9623 this.multiProvider = multiProvider;
9624 this.resolvedFactory = this.resolvedFactories[0];
9625 }
9626}
9627/**
9628 * An internal resolved representation of a factory function created by resolving `Provider`.
9629 * @publicApi
9630 */
9631class ResolvedReflectiveFactory {
9632 constructor(
9633 /**
9634 * Factory function which can return an instance of an object represented by a key.
9635 */
9636 factory,
9637 /**
9638 * Arguments (dependencies) to the `factory` function.
9639 */
9640 dependencies) {
9641 this.factory = factory;
9642 this.dependencies = dependencies;
9643 }
9644}
9645/**
9646 * Resolve a single provider.
9647 */
9648function resolveReflectiveFactory(provider) {
9649 let factoryFn;
9650 let resolvedDeps;
9651 if (provider.useClass) {
9652 const useClass = resolveForwardRef(provider.useClass);
9653 factoryFn = getReflect().factory(useClass);
9654 resolvedDeps = _dependenciesFor(useClass);
9655 }
9656 else if (provider.useExisting) {
9657 factoryFn = (aliasInstance) => aliasInstance;
9658 resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
9659 }
9660 else if (provider.useFactory) {
9661 factoryFn = provider.useFactory;
9662 resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
9663 }
9664 else {
9665 factoryFn = () => provider.useValue;
9666 resolvedDeps = _EMPTY_LIST;
9667 }
9668 return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
9669}
9670/**
9671 * Converts the `Provider` into `ResolvedProvider`.
9672 *
9673 * `Injector` internally only uses `ResolvedProvider`, `Provider` contains convenience provider
9674 * syntax.
9675 */
9676function resolveReflectiveProvider(provider) {
9677 return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false);
9678}
9679/**
9680 * Resolve a list of Providers.
9681 */
9682function resolveReflectiveProviders(providers) {
9683 const normalized = _normalizeProviders(providers, []);
9684 const resolved = normalized.map(resolveReflectiveProvider);
9685 const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
9686 return Array.from(resolvedProviderMap.values());
9687}
9688/**
9689 * Merges a list of ResolvedProviders into a list where each key is contained exactly once and
9690 * multi providers have been merged.
9691 */
9692function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) {
9693 for (let i = 0; i < providers.length; i++) {
9694 const provider = providers[i];
9695 const existing = normalizedProvidersMap.get(provider.key.id);
9696 if (existing) {
9697 if (provider.multiProvider !== existing.multiProvider) {
9698 throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
9699 }
9700 if (provider.multiProvider) {
9701 for (let j = 0; j < provider.resolvedFactories.length; j++) {
9702 existing.resolvedFactories.push(provider.resolvedFactories[j]);
9703 }
9704 }
9705 else {
9706 normalizedProvidersMap.set(provider.key.id, provider);
9707 }
9708 }
9709 else {
9710 let resolvedProvider;
9711 if (provider.multiProvider) {
9712 resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider);
9713 }
9714 else {
9715 resolvedProvider = provider;
9716 }
9717 normalizedProvidersMap.set(provider.key.id, resolvedProvider);
9718 }
9719 }
9720 return normalizedProvidersMap;
9721}
9722function _normalizeProviders(providers, res) {
9723 providers.forEach(b => {
9724 if (b instanceof Type) {
9725 res.push({ provide: b, useClass: b });
9726 }
9727 else if (b && typeof b == 'object' && b.provide !== undefined) {
9728 res.push(b);
9729 }
9730 else if (Array.isArray(b)) {
9731 _normalizeProviders(b, res);
9732 }
9733 else {
9734 throw invalidProviderError(b);
9735 }
9736 });
9737 return res;
9738}
9739function constructDependencies(typeOrFunc, dependencies) {
9740 if (!dependencies) {
9741 return _dependenciesFor(typeOrFunc);
9742 }
9743 else {
9744 const params = dependencies.map(t => [t]);
9745 return dependencies.map(t => _extractToken(typeOrFunc, t, params));
9746 }
9747}
9748function _dependenciesFor(typeOrFunc) {
9749 const params = getReflect().parameters(typeOrFunc);
9750 if (!params)
9751 return [];
9752 if (params.some(p => p == null)) {
9753 throw noAnnotationError(typeOrFunc, params);
9754 }
9755 return params.map(p => _extractToken(typeOrFunc, p, params));
9756}
9757function _extractToken(typeOrFunc, metadata, params) {
9758 let token = null;
9759 let optional = false;
9760 if (!Array.isArray(metadata)) {
9761 if (metadata instanceof Inject) {
9762 return _createDependency(metadata.token, optional, null);
9763 }
9764 else {
9765 return _createDependency(metadata, optional, null);
9766 }
9767 }
9768 let visibility = null;
9769 for (let i = 0; i < metadata.length; ++i) {
9770 const paramMetadata = metadata[i];
9771 if (paramMetadata instanceof Type) {
9772 token = paramMetadata;
9773 }
9774 else if (paramMetadata instanceof Inject) {
9775 token = paramMetadata.token;
9776 }
9777 else if (paramMetadata instanceof Optional) {
9778 optional = true;
9779 }
9780 else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
9781 visibility = paramMetadata;
9782 }
9783 else if (paramMetadata instanceof InjectionToken) {
9784 token = paramMetadata;
9785 }
9786 }
9787 token = resolveForwardRef(token);
9788 if (token != null) {
9789 return _createDependency(token, optional, visibility);
9790 }
9791 else {
9792 throw noAnnotationError(typeOrFunc, params);
9793 }
9794}
9795function _createDependency(token, optional, visibility) {
9796 return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
9797}
9798
9799// Threshold for the dynamic version
9800const UNDEFINED = {};
9801/**
9802 * A ReflectiveDependency injection container used for instantiating objects and resolving
9803 * dependencies.
9804 *
9805 * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
9806 * constructor dependencies.
9807 *
9808 * In typical use, application code asks for the dependencies in the constructor and they are
9809 * resolved by the `Injector`.
9810 *
9811 * @usageNotes
9812 * ### Example
9813 *
9814 * The following example creates an `Injector` configured to create `Engine` and `Car`.
9815 *
9816 * ```typescript
9817 * @Injectable()
9818 * class Engine {
9819 * }
9820 *
9821 * @Injectable()
9822 * class Car {
9823 * constructor(public engine:Engine) {}
9824 * }
9825 *
9826 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
9827 * var car = injector.get(Car);
9828 * expect(car instanceof Car).toBe(true);
9829 * expect(car.engine instanceof Engine).toBe(true);
9830 * ```
9831 *
9832 * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
9833 * resolve all of the object's dependencies automatically.
9834 *
9835 * TODO: delete in v14.
9836 *
9837 * @deprecated from v5 - slow and brings in a lot of code, Use `Injector.create` instead.
9838 * @publicApi
9839 */
9840class ReflectiveInjector {
9841 /**
9842 * Turns an array of provider definitions into an array of resolved providers.
9843 *
9844 * A resolution is a process of flattening multiple nested arrays and converting individual
9845 * providers into an array of `ResolvedReflectiveProvider`s.
9846 *
9847 * @usageNotes
9848 * ### Example
9849 *
9850 * ```typescript
9851 * @Injectable()
9852 * class Engine {
9853 * }
9854 *
9855 * @Injectable()
9856 * class Car {
9857 * constructor(public engine:Engine) {}
9858 * }
9859 *
9860 * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
9861 *
9862 * expect(providers.length).toEqual(2);
9863 *
9864 * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
9865 * expect(providers[0].key.displayName).toBe("Car");
9866 * expect(providers[0].dependencies.length).toEqual(1);
9867 * expect(providers[0].factory).toBeDefined();
9868 *
9869 * expect(providers[1].key.displayName).toBe("Engine");
9870 * });
9871 * ```
9872 *
9873 */
9874 static resolve(providers) {
9875 return resolveReflectiveProviders(providers);
9876 }
9877 /**
9878 * Resolves an array of providers and creates an injector from those providers.
9879 *
9880 * The passed-in providers can be an array of `Type`, `Provider`,
9881 * or a recursive array of more providers.
9882 *
9883 * @usageNotes
9884 * ### Example
9885 *
9886 * ```typescript
9887 * @Injectable()
9888 * class Engine {
9889 * }
9890 *
9891 * @Injectable()
9892 * class Car {
9893 * constructor(public engine:Engine) {}
9894 * }
9895 *
9896 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
9897 * expect(injector.get(Car) instanceof Car).toBe(true);
9898 * ```
9899 */
9900 static resolveAndCreate(providers, parent) {
9901 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
9902 return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
9903 }
9904 /**
9905 * Creates an injector from previously resolved providers.
9906 *
9907 * This API is the recommended way to construct injectors in performance-sensitive parts.
9908 *
9909 * @usageNotes
9910 * ### Example
9911 *
9912 * ```typescript
9913 * @Injectable()
9914 * class Engine {
9915 * }
9916 *
9917 * @Injectable()
9918 * class Car {
9919 * constructor(public engine:Engine) {}
9920 * }
9921 *
9922 * var providers = ReflectiveInjector.resolve([Car, Engine]);
9923 * var injector = ReflectiveInjector.fromResolvedProviders(providers);
9924 * expect(injector.get(Car) instanceof Car).toBe(true);
9925 * ```
9926 */
9927 static fromResolvedProviders(providers, parent) {
9928 return new ReflectiveInjector_(providers, parent);
9929 }
9930}
9931class ReflectiveInjector_ {
9932 /**
9933 * Private
9934 */
9935 constructor(_providers, _parent) {
9936 /** @internal */
9937 this._constructionCounter = 0;
9938 this._providers = _providers;
9939 this.parent = _parent || null;
9940 const len = _providers.length;
9941 this.keyIds = [];
9942 this.objs = [];
9943 for (let i = 0; i < len; i++) {
9944 this.keyIds[i] = _providers[i].key.id;
9945 this.objs[i] = UNDEFINED;
9946 }
9947 }
9948 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
9949 return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
9950 }
9951 resolveAndCreateChild(providers) {
9952 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
9953 return this.createChildFromResolved(ResolvedReflectiveProviders);
9954 }
9955 createChildFromResolved(providers) {
9956 const inj = new ReflectiveInjector_(providers);
9957 inj.parent = this;
9958 return inj;
9959 }
9960 resolveAndInstantiate(provider) {
9961 return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
9962 }
9963 instantiateResolved(provider) {
9964 return this._instantiateProvider(provider);
9965 }
9966 getProviderAtIndex(index) {
9967 if (index < 0 || index >= this._providers.length) {
9968 throw outOfBoundsError(index);
9969 }
9970 return this._providers[index];
9971 }
9972 /** @internal */
9973 _new(provider) {
9974 if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
9975 throw cyclicDependencyError(this, provider.key);
9976 }
9977 return this._instantiateProvider(provider);
9978 }
9979 _getMaxNumberOfObjects() {
9980 return this.objs.length;
9981 }
9982 _instantiateProvider(provider) {
9983 if (provider.multiProvider) {
9984 const res = [];
9985 for (let i = 0; i < provider.resolvedFactories.length; ++i) {
9986 res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
9987 }
9988 return res;
9989 }
9990 else {
9991 return this._instantiate(provider, provider.resolvedFactories[0]);
9992 }
9993 }
9994 _instantiate(provider, ResolvedReflectiveFactory) {
9995 const factory = ResolvedReflectiveFactory.factory;
9996 let deps;
9997 try {
9998 deps =
9999 ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
10000 }
10001 catch (e) {
10002 if (e.addKey) {
10003 e.addKey(this, provider.key);
10004 }
10005 throw e;
10006 }
10007 let obj;
10008 try {
10009 obj = factory(...deps);
10010 }
10011 catch (e) {
10012 throw instantiationError(this, e, e.stack, provider.key);
10013 }
10014 return obj;
10015 }
10016 _getByReflectiveDependency(dep) {
10017 return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
10018 }
10019 _getByKey(key, visibility, notFoundValue) {
10020 if (key === ReflectiveInjector_.INJECTOR_KEY) {
10021 return this;
10022 }
10023 if (visibility instanceof Self) {
10024 return this._getByKeySelf(key, notFoundValue);
10025 }
10026 else {
10027 return this._getByKeyDefault(key, notFoundValue, visibility);
10028 }
10029 }
10030 _getObjByKeyId(keyId) {
10031 for (let i = 0; i < this.keyIds.length; i++) {
10032 if (this.keyIds[i] === keyId) {
10033 if (this.objs[i] === UNDEFINED) {
10034 this.objs[i] = this._new(this._providers[i]);
10035 }
10036 return this.objs[i];
10037 }
10038 }
10039 return UNDEFINED;
10040 }
10041 /** @internal */
10042 _throwOrNull(key, notFoundValue) {
10043 if (notFoundValue !== THROW_IF_NOT_FOUND) {
10044 return notFoundValue;
10045 }
10046 else {
10047 throw noProviderError(this, key);
10048 }
10049 }
10050 /** @internal */
10051 _getByKeySelf(key, notFoundValue) {
10052 const obj = this._getObjByKeyId(key.id);
10053 return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
10054 }
10055 /** @internal */
10056 _getByKeyDefault(key, notFoundValue, visibility) {
10057 let inj;
10058 if (visibility instanceof SkipSelf) {
10059 inj = this.parent;
10060 }
10061 else {
10062 inj = this;
10063 }
10064 while (inj instanceof ReflectiveInjector_) {
10065 const inj_ = inj;
10066 const obj = inj_._getObjByKeyId(key.id);
10067 if (obj !== UNDEFINED)
10068 return obj;
10069 inj = inj_.parent;
10070 }
10071 if (inj !== null) {
10072 return inj.get(key.token, notFoundValue);
10073 }
10074 else {
10075 return this._throwOrNull(key, notFoundValue);
10076 }
10077 }
10078 get displayName() {
10079 const providers = _mapProviders(this, (b) => ' "' + b.key.displayName + '" ')
10080 .join(', ');
10081 return `ReflectiveInjector(providers: [${providers}])`;
10082 }
10083 toString() {
10084 return this.displayName;
10085 }
10086}
10087ReflectiveInjector_.INJECTOR_KEY = ( /* @__PURE__ */ReflectiveKey.get(Injector));
10088function _mapProviders(injector, fn) {
10089 const res = [];
10090 for (let i = 0; i < injector._providers.length; ++i) {
10091 res[i] = fn(injector.getProviderAtIndex(i));
10092 }
10093 return res;
10094}
10095
10096/**
10097 * @module
10098 * @description
10099 * The `di` module provides dependency injection container services.
10100 */
10101
10102/**
10103 * This file should not be necessary because node resolution should just default to `./di/index`!
10104 *
10105 * However it does not seem to work and it breaks:
10106 * - //packages/animations/browser/test:test_web_chromium-local
10107 * - //packages/compiler-cli/test:extract_i18n
10108 * - //packages/compiler-cli/test:ngc
10109 * - //packages/compiler-cli/test:perform_watch
10110 * - //packages/compiler-cli/test/diagnostics:check_types
10111 * - //packages/compiler-cli/test/transformers:test
10112 * - //packages/compiler/test:test
10113 * - //tools/public_api_guard:core_api
10114 *
10115 * Remove this file once the above is solved or wait until `ngc` is deleted and then it should be
10116 * safe to delete this file.
10117 */
10118
10119function ɵɵdirectiveInject(token, flags = InjectFlags.Default) {
10120 const lView = getLView();
10121 // Fall back to inject() if view hasn't been created. This situation can happen in tests
10122 // if inject utilities are used before bootstrapping.
10123 if (lView === null) {
10124 // Verify that we will not get into infinite loop.
10125 ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject);
10126 return ɵɵinject(token, flags);
10127 }
10128 const tNode = getCurrentTNode();
10129 return getOrCreateInjectable(tNode, lView, resolveForwardRef(token), flags);
10130}
10131/**
10132 * Throws an error indicating that a factory function could not be generated by the compiler for a
10133 * particular class.
10134 *
10135 * This instruction allows the actual error message to be optimized away when ngDevMode is turned
10136 * off, saving bytes of generated code while still providing a good experience in dev mode.
10137 *
10138 * The name of the class is not mentioned here, but will be in the generated factory function name
10139 * and thus in the stack trace.
10140 *
10141 * @codeGenApi
10142 */
10143function ɵɵinvalidFactory() {
10144 const msg = ngDevMode ? `This constructor was not compatible with Dependency Injection.` : 'invalid';
10145 throw new Error(msg);
10146}
10147
10148/**
10149 * Invoke `HostBindingsFunction`s for view.
10150 *
10151 * This methods executes `TView.hostBindingOpCodes`. It is used to execute the
10152 * `HostBindingsFunction`s associated with the current `LView`.
10153 *
10154 * @param tView Current `TView`.
10155 * @param lView Current `LView`.
10156 */
10157function processHostBindingOpCodes(tView, lView) {
10158 const hostBindingOpCodes = tView.hostBindingOpCodes;
10159 if (hostBindingOpCodes === null)
10160 return;
10161 try {
10162 for (let i = 0; i < hostBindingOpCodes.length; i++) {
10163 const opCode = hostBindingOpCodes[i];
10164 if (opCode < 0) {
10165 // Negative numbers are element indexes.
10166 setSelectedIndex(~opCode);
10167 }
10168 else {
10169 // Positive numbers are NumberTuple which store bindingRootIndex and directiveIndex.
10170 const directiveIdx = opCode;
10171 const bindingRootIndx = hostBindingOpCodes[++i];
10172 const hostBindingFn = hostBindingOpCodes[++i];
10173 setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
10174 const context = lView[directiveIdx];
10175 hostBindingFn(2 /* RenderFlags.Update */, context);
10176 }
10177 }
10178 }
10179 finally {
10180 setSelectedIndex(-1);
10181 }
10182}
10183/** Refreshes all content queries declared by directives in a given view */
10184function refreshContentQueries(tView, lView) {
10185 const contentQueries = tView.contentQueries;
10186 if (contentQueries !== null) {
10187 for (let i = 0; i < contentQueries.length; i += 2) {
10188 const queryStartIdx = contentQueries[i];
10189 const directiveDefIdx = contentQueries[i + 1];
10190 if (directiveDefIdx !== -1) {
10191 const directiveDef = tView.data[directiveDefIdx];
10192 ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
10193 ngDevMode &&
10194 assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
10195 setCurrentQueryIndex(queryStartIdx);
10196 directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
10197 }
10198 }
10199 }
10200}
10201/** Refreshes child components in the current view (update mode). */
10202function refreshChildComponents(hostLView, components) {
10203 for (let i = 0; i < components.length; i++) {
10204 refreshComponent(hostLView, components[i]);
10205 }
10206}
10207/** Renders child components in the current view (creation mode). */
10208function renderChildComponents(hostLView, components) {
10209 for (let i = 0; i < components.length; i++) {
10210 renderComponent(hostLView, components[i]);
10211 }
10212}
10213function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector, embeddedViewInjector) {
10214 const lView = tView.blueprint.slice();
10215 lView[HOST] = host;
10216 lView[FLAGS] = flags | 4 /* LViewFlags.CreationMode */ | 64 /* LViewFlags.Attached */ | 8 /* LViewFlags.FirstLViewPass */;
10217 if (embeddedViewInjector !== null ||
10218 (parentLView && (parentLView[FLAGS] & 1024 /* LViewFlags.HasEmbeddedViewInjector */))) {
10219 lView[FLAGS] |= 1024 /* LViewFlags.HasEmbeddedViewInjector */;
10220 }
10221 resetPreOrderHookFlags(lView);
10222 ngDevMode && tView.declTNode && parentLView && assertTNodeForLView(tView.declTNode, parentLView);
10223 lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
10224 lView[CONTEXT] = context;
10225 lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]);
10226 ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required');
10227 lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]);
10228 ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required');
10229 lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null;
10230 lView[INJECTOR$1] = injector || parentLView && parentLView[INJECTOR$1] || null;
10231 lView[T_HOST] = tHostNode;
10232 lView[ID] = getUniqueLViewId();
10233 lView[EMBEDDED_VIEW_INJECTOR] = embeddedViewInjector;
10234 ngDevMode &&
10235 assertEqual(tView.type == 2 /* TViewType.Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
10236 lView[DECLARATION_COMPONENT_VIEW] =
10237 tView.type == 2 /* TViewType.Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
10238 return lView;
10239}
10240function getOrCreateTNode(tView, index, type, name, attrs) {
10241 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
10242 // `view_engine_compatibility` for additional context.
10243 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
10244 // Keep this function short, so that the VM will inline it.
10245 ngDevMode && assertPureTNodeType(type);
10246 let tNode = tView.data[index];
10247 if (tNode === null) {
10248 tNode = createTNodeAtIndex(tView, index, type, name, attrs);
10249 if (isInI18nBlock()) {
10250 // If we are in i18n block then all elements should be pre declared through `Placeholder`
10251 // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
10252 // If the `TNode` was not pre-declared than it means it was not mentioned which means it was
10253 // removed, so we mark it as detached.
10254 tNode.flags |= 32 /* TNodeFlags.isDetached */;
10255 }
10256 }
10257 else if (tNode.type & 64 /* TNodeType.Placeholder */) {
10258 tNode.type = type;
10259 tNode.value = name;
10260 tNode.attrs = attrs;
10261 const parent = getCurrentParentTNode();
10262 tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex;
10263 ngDevMode && assertTNodeForTView(tNode, tView);
10264 ngDevMode && assertEqual(index, tNode.index, 'Expecting same index');
10265 }
10266 setCurrentTNode(tNode, true);
10267 return tNode;
10268}
10269function createTNodeAtIndex(tView, index, type, name, attrs) {
10270 const currentTNode = getCurrentTNodePlaceholderOk();
10271 const isParent = isCurrentTNodeParent();
10272 const parent = isParent ? currentTNode : currentTNode && currentTNode.parent;
10273 // Parents cannot cross component boundaries because components will be used in multiple places.
10274 const tNode = tView.data[index] =
10275 createTNode(tView, parent, type, index, name, attrs);
10276 // Assign a pointer to the first child node of a given view. The first node is not always the one
10277 // at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
10278 // the index 1 or more, so we can't just check node index.
10279 if (tView.firstChild === null) {
10280 tView.firstChild = tNode;
10281 }
10282 if (currentTNode !== null) {
10283 if (isParent) {
10284 // FIXME(misko): This logic looks unnecessarily complicated. Could we simplify?
10285 if (currentTNode.child == null && tNode.parent !== null) {
10286 // We are in the same view, which means we are adding content node to the parent view.
10287 currentTNode.child = tNode;
10288 }
10289 }
10290 else {
10291 if (currentTNode.next === null) {
10292 // In the case of i18n the `currentTNode` may already be linked, in which case we don't want
10293 // to break the links which i18n created.
10294 currentTNode.next = tNode;
10295 }
10296 }
10297 }
10298 return tNode;
10299}
10300/**
10301 * When elements are created dynamically after a view blueprint is created (e.g. through
10302 * i18nApply()), we need to adjust the blueprint for future
10303 * template passes.
10304 *
10305 * @param tView `TView` associated with `LView`
10306 * @param lView The `LView` containing the blueprint to adjust
10307 * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
10308 * @param initialValue Initial value to store in blueprint
10309 */
10310function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
10311 if (numSlotsToAlloc === 0)
10312 return -1;
10313 if (ngDevMode) {
10314 assertFirstCreatePass(tView);
10315 assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
10316 assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
10317 assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
10318 assertFirstUpdatePass(tView);
10319 }
10320 const allocIdx = lView.length;
10321 for (let i = 0; i < numSlotsToAlloc; i++) {
10322 lView.push(initialValue);
10323 tView.blueprint.push(initialValue);
10324 tView.data.push(null);
10325 }
10326 return allocIdx;
10327}
10328//////////////////////////
10329//// Render
10330//////////////////////////
10331/**
10332 * Processes a view in the creation mode. This includes a number of steps in a specific order:
10333 * - creating view query functions (if any);
10334 * - executing a template function in the creation mode;
10335 * - updating static queries (if any);
10336 * - creating child components defined in a given view.
10337 */
10338function renderView(tView, lView, context) {
10339 ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
10340 enterView(lView);
10341 try {
10342 const viewQuery = tView.viewQuery;
10343 if (viewQuery !== null) {
10344 executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
10345 }
10346 // Execute a template associated with this view, if it exists. A template function might not be
10347 // defined for the root component views.
10348 const templateFn = tView.template;
10349 if (templateFn !== null) {
10350 executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
10351 }
10352 // This needs to be set before children are processed to support recursive components.
10353 // This must be set to false immediately after the first creation run because in an
10354 // ngFor loop, all the views will be created together before update mode runs and turns
10355 // off firstCreatePass. If we don't set it here, instances will perform directive
10356 // matching, etc again and again.
10357 if (tView.firstCreatePass) {
10358 tView.firstCreatePass = false;
10359 }
10360 // We resolve content queries specifically marked as `static` in creation mode. Dynamic
10361 // content queries are resolved during change detection (i.e. update mode), after embedded
10362 // views are refreshed (see block above).
10363 if (tView.staticContentQueries) {
10364 refreshContentQueries(tView, lView);
10365 }
10366 // We must materialize query results before child components are processed
10367 // in case a child component has projected a container. The LContainer needs
10368 // to exist so the embedded views are properly attached by the container.
10369 if (tView.staticViewQueries) {
10370 executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
10371 }
10372 // Render child component views.
10373 const components = tView.components;
10374 if (components !== null) {
10375 renderChildComponents(lView, components);
10376 }
10377 }
10378 catch (error) {
10379 // If we didn't manage to get past the first template pass due to
10380 // an error, mark the view as corrupted so we can try to recover.
10381 if (tView.firstCreatePass) {
10382 tView.incompleteFirstPass = true;
10383 tView.firstCreatePass = false;
10384 }
10385 throw error;
10386 }
10387 finally {
10388 lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
10389 leaveView();
10390 }
10391}
10392/**
10393 * Processes a view in update mode. This includes a number of steps in a specific order:
10394 * - executing a template function in update mode;
10395 * - executing hooks;
10396 * - refreshing queries;
10397 * - setting host bindings;
10398 * - refreshing child (embedded and component) views.
10399 */
10400function refreshView(tView, lView, templateFn, context) {
10401 ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
10402 const flags = lView[FLAGS];
10403 if ((flags & 128 /* LViewFlags.Destroyed */) === 128 /* LViewFlags.Destroyed */)
10404 return;
10405 enterView(lView);
10406 // Check no changes mode is a dev only mode used to verify that bindings have not changed
10407 // since they were assigned. We do not want to execute lifecycle hooks in that mode.
10408 const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
10409 try {
10410 resetPreOrderHookFlags(lView);
10411 setBindingIndex(tView.bindingStartIndex);
10412 if (templateFn !== null) {
10413 executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
10414 }
10415 const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
10416 // execute pre-order hooks (OnInit, OnChanges, DoCheck)
10417 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10418 if (!isInCheckNoChangesPass) {
10419 if (hooksInitPhaseCompleted) {
10420 const preOrderCheckHooks = tView.preOrderCheckHooks;
10421 if (preOrderCheckHooks !== null) {
10422 executeCheckHooks(lView, preOrderCheckHooks, null);
10423 }
10424 }
10425 else {
10426 const preOrderHooks = tView.preOrderHooks;
10427 if (preOrderHooks !== null) {
10428 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
10429 }
10430 incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
10431 }
10432 }
10433 // First mark transplanted views that are declared in this lView as needing a refresh at their
10434 // insertion points. This is needed to avoid the situation where the template is defined in this
10435 // `LView` but its declaration appears after the insertion component.
10436 markTransplantedViewsForRefresh(lView);
10437 refreshEmbeddedViews(lView);
10438 // Content query results must be refreshed before content hooks are called.
10439 if (tView.contentQueries !== null) {
10440 refreshContentQueries(tView, lView);
10441 }
10442 // execute content hooks (AfterContentInit, AfterContentChecked)
10443 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10444 if (!isInCheckNoChangesPass) {
10445 if (hooksInitPhaseCompleted) {
10446 const contentCheckHooks = tView.contentCheckHooks;
10447 if (contentCheckHooks !== null) {
10448 executeCheckHooks(lView, contentCheckHooks);
10449 }
10450 }
10451 else {
10452 const contentHooks = tView.contentHooks;
10453 if (contentHooks !== null) {
10454 executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
10455 }
10456 incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
10457 }
10458 }
10459 processHostBindingOpCodes(tView, lView);
10460 // Refresh child component views.
10461 const components = tView.components;
10462 if (components !== null) {
10463 refreshChildComponents(lView, components);
10464 }
10465 // View queries must execute after refreshing child components because a template in this view
10466 // could be inserted in a child component. If the view query executes before child component
10467 // refresh, the template might not yet be inserted.
10468 const viewQuery = tView.viewQuery;
10469 if (viewQuery !== null) {
10470 executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
10471 }
10472 // execute view hooks (AfterViewInit, AfterViewChecked)
10473 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10474 if (!isInCheckNoChangesPass) {
10475 if (hooksInitPhaseCompleted) {
10476 const viewCheckHooks = tView.viewCheckHooks;
10477 if (viewCheckHooks !== null) {
10478 executeCheckHooks(lView, viewCheckHooks);
10479 }
10480 }
10481 else {
10482 const viewHooks = tView.viewHooks;
10483 if (viewHooks !== null) {
10484 executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
10485 }
10486 incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
10487 }
10488 }
10489 if (tView.firstUpdatePass === true) {
10490 // We need to make sure that we only flip the flag on successful `refreshView` only
10491 // Don't do this in `finally` block.
10492 // If we did this in `finally` block then an exception could block the execution of styling
10493 // instructions which in turn would be unable to insert themselves into the styling linked
10494 // list. The result of this would be that if the exception would not be throw on subsequent CD
10495 // the styling would be unable to process it data and reflect to the DOM.
10496 tView.firstUpdatePass = false;
10497 }
10498 // Do not reset the dirty state when running in check no changes mode. We don't want components
10499 // to behave differently depending on whether check no changes is enabled or not. For example:
10500 // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
10501 // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
10502 // no changes cycle, the component would be not be dirty for the next update pass. This would
10503 // be different in production mode where the component dirty state is not reset.
10504 if (!isInCheckNoChangesPass) {
10505 lView[FLAGS] &= ~(32 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
10506 }
10507 if (lView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
10508 lView[FLAGS] &= ~512 /* LViewFlags.RefreshTransplantedView */;
10509 updateTransplantedViewCount(lView[PARENT], -1);
10510 }
10511 }
10512 finally {
10513 leaveView();
10514 }
10515}
10516function executeTemplate(tView, lView, templateFn, rf, context) {
10517 const prevSelectedIndex = getSelectedIndex();
10518 const isUpdatePhase = rf & 2 /* RenderFlags.Update */;
10519 try {
10520 setSelectedIndex(-1);
10521 if (isUpdatePhase && lView.length > HEADER_OFFSET) {
10522 // When we're updating, inherently select 0 so we don't
10523 // have to generate that instruction for most update blocks.
10524 selectIndexInternal(tView, lView, HEADER_OFFSET, !!ngDevMode && isInCheckNoChangesMode());
10525 }
10526 const preHookType = isUpdatePhase ? 2 /* ProfilerEvent.TemplateUpdateStart */ : 0 /* ProfilerEvent.TemplateCreateStart */;
10527 profiler(preHookType, context);
10528 templateFn(rf, context);
10529 }
10530 finally {
10531 setSelectedIndex(prevSelectedIndex);
10532 const postHookType = isUpdatePhase ? 3 /* ProfilerEvent.TemplateUpdateEnd */ : 1 /* ProfilerEvent.TemplateCreateEnd */;
10533 profiler(postHookType, context);
10534 }
10535}
10536//////////////////////////
10537//// Element
10538//////////////////////////
10539function executeContentQueries(tView, tNode, lView) {
10540 if (isContentQueryHost(tNode)) {
10541 const start = tNode.directiveStart;
10542 const end = tNode.directiveEnd;
10543 for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
10544 const def = tView.data[directiveIndex];
10545 if (def.contentQueries) {
10546 def.contentQueries(1 /* RenderFlags.Create */, lView[directiveIndex], directiveIndex);
10547 }
10548 }
10549 }
10550}
10551/**
10552 * Creates directive instances.
10553 */
10554function createDirectivesInstances(tView, lView, tNode) {
10555 if (!getBindingsEnabled())
10556 return;
10557 instantiateAllDirectives(tView, lView, tNode, getNativeByTNode(tNode, lView));
10558 if ((tNode.flags & 64 /* TNodeFlags.hasHostBindings */) === 64 /* TNodeFlags.hasHostBindings */) {
10559 invokeDirectivesHostBindings(tView, lView, tNode);
10560 }
10561}
10562/**
10563 * Takes a list of local names and indices and pushes the resolved local variable values
10564 * to LView in the same order as they are loaded in the template with load().
10565 */
10566function saveResolvedLocalsInData(viewData, tNode, localRefExtractor = getNativeByTNode) {
10567 const localNames = tNode.localNames;
10568 if (localNames !== null) {
10569 let localIndex = tNode.index + 1;
10570 for (let i = 0; i < localNames.length; i += 2) {
10571 const index = localNames[i + 1];
10572 const value = index === -1 ?
10573 localRefExtractor(tNode, viewData) :
10574 viewData[index];
10575 viewData[localIndex++] = value;
10576 }
10577 }
10578}
10579/**
10580 * Gets TView from a template function or creates a new TView
10581 * if it doesn't already exist.
10582 *
10583 * @param def ComponentDef
10584 * @returns TView
10585 */
10586function getOrCreateComponentTView(def) {
10587 const tView = def.tView;
10588 // Create a TView if there isn't one, or recreate it if the first create pass didn't
10589 // complete successfully since we can't know for sure whether it's in a usable shape.
10590 if (tView === null || tView.incompleteFirstPass) {
10591 // Declaration node here is null since this function is called when we dynamically create a
10592 // component and hence there is no declaration.
10593 const declTNode = null;
10594 return def.tView = createTView(1 /* TViewType.Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
10595 }
10596 return tView;
10597}
10598/**
10599 * Creates a TView instance
10600 *
10601 * @param type Type of `TView`.
10602 * @param declTNode Declaration location of this `TView`.
10603 * @param templateFn Template function
10604 * @param decls The number of nodes, local refs, and pipes in this template
10605 * @param directives Registry of directives for this view
10606 * @param pipes Registry of pipes for this view
10607 * @param viewQuery View queries for this view
10608 * @param schemas Schemas for this view
10609 * @param consts Constants for this view
10610 */
10611function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
10612 ngDevMode && ngDevMode.tView++;
10613 const bindingStartIndex = HEADER_OFFSET + decls;
10614 // This length does not yet contain host bindings from child directives because at this point,
10615 // we don't know which directives are active on this template. As soon as a directive is matched
10616 // that has a host binding, we will update the blueprint with that def's hostVars count.
10617 const initialViewLength = bindingStartIndex + vars;
10618 const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
10619 const consts = typeof constsOrFactory === 'function' ? constsOrFactory() : constsOrFactory;
10620 const tView = blueprint[TVIEW] = {
10621 type: type,
10622 blueprint: blueprint,
10623 template: templateFn,
10624 queries: null,
10625 viewQuery: viewQuery,
10626 declTNode: declTNode,
10627 data: blueprint.slice().fill(null, bindingStartIndex),
10628 bindingStartIndex: bindingStartIndex,
10629 expandoStartIndex: initialViewLength,
10630 hostBindingOpCodes: null,
10631 firstCreatePass: true,
10632 firstUpdatePass: true,
10633 staticViewQueries: false,
10634 staticContentQueries: false,
10635 preOrderHooks: null,
10636 preOrderCheckHooks: null,
10637 contentHooks: null,
10638 contentCheckHooks: null,
10639 viewHooks: null,
10640 viewCheckHooks: null,
10641 destroyHooks: null,
10642 cleanup: null,
10643 contentQueries: null,
10644 components: null,
10645 directiveRegistry: typeof directives === 'function' ? directives() : directives,
10646 pipeRegistry: typeof pipes === 'function' ? pipes() : pipes,
10647 firstChild: null,
10648 schemas: schemas,
10649 consts: consts,
10650 incompleteFirstPass: false
10651 };
10652 if (ngDevMode) {
10653 // For performance reasons it is important that the tView retains the same shape during runtime.
10654 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
10655 // prevent class transitions.
10656 Object.seal(tView);
10657 }
10658 return tView;
10659}
10660function createViewBlueprint(bindingStartIndex, initialViewLength) {
10661 const blueprint = [];
10662 for (let i = 0; i < initialViewLength; i++) {
10663 blueprint.push(i < bindingStartIndex ? null : NO_CHANGE);
10664 }
10665 return blueprint;
10666}
10667/**
10668 * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
10669 *
10670 * @param rendererFactory Factory function to create renderer instance.
10671 * @param elementOrSelector Render element or CSS selector to locate the element.
10672 * @param encapsulation View Encapsulation defined for component that requests host element.
10673 */
10674function locateHostElement(renderer, elementOrSelector, encapsulation) {
10675 // When using native Shadow DOM, do not clear host element to allow native slot projection
10676 const preserveContent = encapsulation === ViewEncapsulation$1.ShadowDom;
10677 return renderer.selectRootElement(elementOrSelector, preserveContent);
10678}
10679/**
10680 * Saves context for this cleanup function in LView.cleanupInstances.
10681 *
10682 * On the first template pass, saves in TView:
10683 * - Cleanup function
10684 * - Index of context we just saved in LView.cleanupInstances
10685 *
10686 * This function can also be used to store instance specific cleanup fns. In that case the `context`
10687 * is `null` and the function is store in `LView` (rather than it `TView`).
10688 */
10689function storeCleanupWithContext(tView, lView, context, cleanupFn) {
10690 const lCleanup = getOrCreateLViewCleanup(lView);
10691 if (context === null) {
10692 // If context is null that this is instance specific callback. These callbacks can only be
10693 // inserted after template shared instances. For this reason in ngDevMode we freeze the TView.
10694 if (ngDevMode) {
10695 Object.freeze(getOrCreateTViewCleanup(tView));
10696 }
10697 lCleanup.push(cleanupFn);
10698 }
10699 else {
10700 lCleanup.push(context);
10701 if (tView.firstCreatePass) {
10702 getOrCreateTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1);
10703 }
10704 }
10705}
10706function createTNode(tView, tParent, type, index, value, attrs) {
10707 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
10708 // `view_engine_compatibility` for additional context.
10709 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
10710 ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\'');
10711 ngDevMode && ngDevMode.tNode++;
10712 ngDevMode && tParent && assertTNodeForTView(tParent, tView);
10713 let injectorIndex = tParent ? tParent.injectorIndex : -1;
10714 const tNode = {
10715 type,
10716 index,
10717 insertBeforeIndex: null,
10718 injectorIndex,
10719 directiveStart: -1,
10720 directiveEnd: -1,
10721 directiveStylingLast: -1,
10722 componentOffset: -1,
10723 propertyBindings: null,
10724 flags: 0,
10725 providerIndexes: 0,
10726 value: value,
10727 attrs: attrs,
10728 mergedAttrs: null,
10729 localNames: null,
10730 initialInputs: undefined,
10731 inputs: null,
10732 outputs: null,
10733 tViews: null,
10734 next: null,
10735 projectionNext: null,
10736 child: null,
10737 parent: tParent,
10738 projection: null,
10739 styles: null,
10740 stylesWithoutHost: null,
10741 residualStyles: undefined,
10742 classes: null,
10743 classesWithoutHost: null,
10744 residualClasses: undefined,
10745 classBindings: 0,
10746 styleBindings: 0,
10747 };
10748 if (ngDevMode) {
10749 // For performance reasons it is important that the tNode retains the same shape during runtime.
10750 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
10751 // prevent class transitions.
10752 Object.seal(tNode);
10753 }
10754 return tNode;
10755}
10756/**
10757 * Generates the `PropertyAliases` data structure from the provided input/output mapping.
10758 * @param aliasMap Input/output mapping from the directive definition.
10759 * @param directiveIndex Index of the directive.
10760 * @param propertyAliases Object in which to store the results.
10761 * @param hostDirectiveAliasMap Object used to alias or filter out properties for host directives.
10762 * If the mapping is provided, it'll act as an allowlist, as well as a mapping of what public
10763 * name inputs/outputs should be exposed under.
10764 */
10765function generatePropertyAliases(aliasMap, directiveIndex, propertyAliases, hostDirectiveAliasMap) {
10766 for (let publicName in aliasMap) {
10767 if (aliasMap.hasOwnProperty(publicName)) {
10768 propertyAliases = propertyAliases === null ? {} : propertyAliases;
10769 const internalName = aliasMap[publicName];
10770 // If there are no host directive mappings, we want to remap using the alias map from the
10771 // definition itself. If there is an alias map, it has two functions:
10772 // 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
10773 // ones inside the host directive map will be exposed on the host.
10774 // 2. The public name of the property is aliased using the host directive alias map, rather
10775 // than the alias map from the definition.
10776 if (hostDirectiveAliasMap === null) {
10777 addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName);
10778 }
10779 else if (hostDirectiveAliasMap.hasOwnProperty(publicName)) {
10780 addPropertyAlias(propertyAliases, directiveIndex, hostDirectiveAliasMap[publicName], internalName);
10781 }
10782 }
10783 }
10784 return propertyAliases;
10785}
10786function addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName) {
10787 if (propertyAliases.hasOwnProperty(publicName)) {
10788 propertyAliases[publicName].push(directiveIndex, internalName);
10789 }
10790 else {
10791 propertyAliases[publicName] = [directiveIndex, internalName];
10792 }
10793}
10794/**
10795 * Initializes data structures required to work with directive inputs and outputs.
10796 * Initialization is done for all directives matched on a given TNode.
10797 */
10798function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
10799 ngDevMode && assertFirstCreatePass(tView);
10800 const start = tNode.directiveStart;
10801 const end = tNode.directiveEnd;
10802 const tViewData = tView.data;
10803 const tNodeAttrs = tNode.attrs;
10804 const inputsFromAttrs = [];
10805 let inputsStore = null;
10806 let outputsStore = null;
10807 for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
10808 const directiveDef = tViewData[directiveIndex];
10809 const aliasData = hostDirectiveDefinitionMap ? hostDirectiveDefinitionMap.get(directiveDef) : null;
10810 const aliasedInputs = aliasData ? aliasData.inputs : null;
10811 const aliasedOutputs = aliasData ? aliasData.outputs : null;
10812 inputsStore =
10813 generatePropertyAliases(directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
10814 outputsStore =
10815 generatePropertyAliases(directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
10816 // Do not use unbound attributes as inputs to structural directives, since structural
10817 // directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
10818 // TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
10819 // should be set for inline templates.
10820 const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
10821 generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs) :
10822 null;
10823 inputsFromAttrs.push(initialInputs);
10824 }
10825 if (inputsStore !== null) {
10826 if (inputsStore.hasOwnProperty('class')) {
10827 tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
10828 }
10829 if (inputsStore.hasOwnProperty('style')) {
10830 tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
10831 }
10832 }
10833 tNode.initialInputs = inputsFromAttrs;
10834 tNode.inputs = inputsStore;
10835 tNode.outputs = outputsStore;
10836}
10837/**
10838 * Mapping between attributes names that don't correspond to their element property names.
10839 *
10840 * Performance note: this function is written as a series of if checks (instead of, say, a property
10841 * object lookup) for performance reasons - the series of `if` checks seems to be the fastest way of
10842 * mapping property names. Do NOT change without benchmarking.
10843 *
10844 * Note: this mapping has to be kept in sync with the equally named mapping in the template
10845 * type-checking machinery of ngtsc.
10846 */
10847function mapPropName(name) {
10848 if (name === 'class')
10849 return 'className';
10850 if (name === 'for')
10851 return 'htmlFor';
10852 if (name === 'formaction')
10853 return 'formAction';
10854 if (name === 'innerHtml')
10855 return 'innerHTML';
10856 if (name === 'readonly')
10857 return 'readOnly';
10858 if (name === 'tabindex')
10859 return 'tabIndex';
10860 return name;
10861}
10862function elementPropertyInternal(tView, tNode, lView, propName, value, renderer, sanitizer, nativeOnly) {
10863 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
10864 const element = getNativeByTNode(tNode, lView);
10865 let inputData = tNode.inputs;
10866 let dataValue;
10867 if (!nativeOnly && inputData != null && (dataValue = inputData[propName])) {
10868 setInputsForProperty(tView, lView, dataValue, propName, value);
10869 if (isComponentHost(tNode))
10870 markDirtyIfOnPush(lView, tNode.index);
10871 if (ngDevMode) {
10872 setNgReflectProperties(lView, element, tNode.type, dataValue, value);
10873 }
10874 }
10875 else if (tNode.type & 3 /* TNodeType.AnyRNode */) {
10876 propName = mapPropName(propName);
10877 if (ngDevMode) {
10878 validateAgainstEventProperties(propName);
10879 if (!isPropertyValid(element, propName, tNode.value, tView.schemas)) {
10880 handleUnknownPropertyError(propName, tNode.value, tNode.type, lView);
10881 }
10882 ngDevMode.rendererSetProperty++;
10883 }
10884 // It is assumed that the sanitizer is only added when the compiler determines that the
10885 // property is risky, so sanitization can be done without further checks.
10886 value = sanitizer != null ? sanitizer(value, tNode.value || '', propName) : value;
10887 renderer.setProperty(element, propName, value);
10888 }
10889 else if (tNode.type & 12 /* TNodeType.AnyContainer */) {
10890 // If the node is a container and the property didn't
10891 // match any of the inputs or schemas we should throw.
10892 if (ngDevMode && !matchingSchemas(tView.schemas, tNode.value)) {
10893 handleUnknownPropertyError(propName, tNode.value, tNode.type, lView);
10894 }
10895 }
10896}
10897/** If node is an OnPush component, marks its LView dirty. */
10898function markDirtyIfOnPush(lView, viewIndex) {
10899 ngDevMode && assertLView(lView);
10900 const childComponentLView = getComponentLViewByIndex(viewIndex, lView);
10901 if (!(childComponentLView[FLAGS] & 16 /* LViewFlags.CheckAlways */)) {
10902 childComponentLView[FLAGS] |= 32 /* LViewFlags.Dirty */;
10903 }
10904}
10905function setNgReflectProperty(lView, element, type, attrName, value) {
10906 const renderer = lView[RENDERER];
10907 attrName = normalizeDebugBindingName(attrName);
10908 const debugValue = normalizeDebugBindingValue(value);
10909 if (type & 3 /* TNodeType.AnyRNode */) {
10910 if (value == null) {
10911 renderer.removeAttribute(element, attrName);
10912 }
10913 else {
10914 renderer.setAttribute(element, attrName, debugValue);
10915 }
10916 }
10917 else {
10918 const textContent = escapeCommentText(`bindings=${JSON.stringify({ [attrName]: debugValue }, null, 2)}`);
10919 renderer.setValue(element, textContent);
10920 }
10921}
10922function setNgReflectProperties(lView, element, type, dataValue, value) {
10923 if (type & (3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */)) {
10924 /**
10925 * dataValue is an array containing runtime input or output names for the directives:
10926 * i+0: directive instance index
10927 * i+1: privateName
10928 *
10929 * e.g. [0, 'change', 'change-minified']
10930 * we want to set the reflected property with the privateName: dataValue[i+1]
10931 */
10932 for (let i = 0; i < dataValue.length; i += 2) {
10933 setNgReflectProperty(lView, element, type, dataValue[i + 1], value);
10934 }
10935 }
10936}
10937/**
10938 * Resolve the matched directives on a node.
10939 */
10940function resolveDirectives(tView, lView, tNode, localRefs) {
10941 // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
10942 // tsickle.
10943 ngDevMode && assertFirstCreatePass(tView);
10944 let hasDirectives = false;
10945 if (getBindingsEnabled()) {
10946 const exportsMap = localRefs === null ? null : { '': -1 };
10947 const matchResult = findDirectiveDefMatches(tView, tNode);
10948 let directiveDefs;
10949 let hostDirectiveDefs;
10950 if (matchResult === null) {
10951 directiveDefs = hostDirectiveDefs = null;
10952 }
10953 else {
10954 [directiveDefs, hostDirectiveDefs] = matchResult;
10955 }
10956 if (directiveDefs !== null) {
10957 hasDirectives = true;
10958 initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
10959 }
10960 if (exportsMap)
10961 cacheMatchingLocalNames(tNode, localRefs, exportsMap);
10962 }
10963 // Merge the template attrs last so that they have the highest priority.
10964 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
10965 return hasDirectives;
10966}
10967/** Initializes the data structures necessary for a list of directives to be instantiated. */
10968function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
10969 ngDevMode && assertFirstCreatePass(tView);
10970 // Publishes the directive types to DI so they can be injected. Needs to
10971 // happen in a separate pass before the TNode flags have been initialized.
10972 for (let i = 0; i < directives.length; i++) {
10973 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
10974 }
10975 initTNodeFlags(tNode, tView.data.length, directives.length);
10976 // When the same token is provided by several directives on the same node, some rules apply in
10977 // the viewEngine:
10978 // - viewProviders have priority over providers
10979 // - the last directive in NgModule.declarations has priority over the previous one
10980 // So to match these rules, the order in which providers are added in the arrays is very
10981 // important.
10982 for (let i = 0; i < directives.length; i++) {
10983 const def = directives[i];
10984 if (def.providersResolver)
10985 def.providersResolver(def);
10986 }
10987 let preOrderHooksFound = false;
10988 let preOrderCheckHooksFound = false;
10989 let directiveIdx = allocExpando(tView, lView, directives.length, null);
10990 ngDevMode &&
10991 assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
10992 for (let i = 0; i < directives.length; i++) {
10993 const def = directives[i];
10994 // Merge the attrs in the order of matches. This assumes that the first directive is the
10995 // component itself, so that the component has the least priority.
10996 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
10997 configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
10998 saveNameToExportMap(directiveIdx, def, exportsMap);
10999 if (def.contentQueries !== null)
11000 tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
11001 if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
11002 tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
11003 const lifeCycleHooks = def.type.prototype;
11004 // Only push a node index into the preOrderHooks array if this is the first
11005 // pre-order hook found on this node.
11006 if (!preOrderHooksFound &&
11007 (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
11008 // We will push the actual hook function into this array later during dir instantiation.
11009 // We cannot do it now because we must ensure hooks are registered in the same
11010 // order that directives are created (i.e. injection order).
11011 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
11012 preOrderHooksFound = true;
11013 }
11014 if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
11015 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
11016 preOrderCheckHooksFound = true;
11017 }
11018 directiveIdx++;
11019 }
11020 initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
11021}
11022/**
11023 * Add `hostBindings` to the `TView.hostBindingOpCodes`.
11024 *
11025 * @param tView `TView` to which the `hostBindings` should be added.
11026 * @param tNode `TNode` the element which contains the directive
11027 * @param directiveIdx Directive index in view.
11028 * @param directiveVarsIdx Where will the directive's vars be stored
11029 * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
11030 */
11031function registerHostBindingOpCodes(tView, tNode, directiveIdx, directiveVarsIdx, def) {
11032 ngDevMode && assertFirstCreatePass(tView);
11033 const hostBindings = def.hostBindings;
11034 if (hostBindings) {
11035 let hostBindingOpCodes = tView.hostBindingOpCodes;
11036 if (hostBindingOpCodes === null) {
11037 hostBindingOpCodes = tView.hostBindingOpCodes = [];
11038 }
11039 const elementIndx = ~tNode.index;
11040 if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
11041 // Conditionally add select element so that we are more efficient in execution.
11042 // NOTE: this is strictly not necessary and it trades code size for runtime perf.
11043 // (We could just always add it.)
11044 hostBindingOpCodes.push(elementIndx);
11045 }
11046 hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
11047 }
11048}
11049/**
11050 * Returns the last selected element index in the `HostBindingOpCodes`
11051 *
11052 * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
11053 * if it changes. This method returns the last index (or '0' if not found.)
11054 *
11055 * Selected element index are only the ones which are negative.
11056 */
11057function lastSelectedElementIdx(hostBindingOpCodes) {
11058 let i = hostBindingOpCodes.length;
11059 while (i > 0) {
11060 const value = hostBindingOpCodes[--i];
11061 if (typeof value === 'number' && value < 0) {
11062 return value;
11063 }
11064 }
11065 return 0;
11066}
11067/**
11068 * Instantiate all the directives that were previously resolved on the current node.
11069 */
11070function instantiateAllDirectives(tView, lView, tNode, native) {
11071 const start = tNode.directiveStart;
11072 const end = tNode.directiveEnd;
11073 // The component view needs to be created before creating the node injector
11074 // since it is used to inject some special symbols like `ChangeDetectorRef`.
11075 if (isComponentHost(tNode)) {
11076 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */);
11077 addComponentLogic(lView, tNode, tView.data[start + tNode.componentOffset]);
11078 }
11079 if (!tView.firstCreatePass) {
11080 getOrCreateNodeInjectorForNode(tNode, lView);
11081 }
11082 attachPatchData(native, lView);
11083 const initialInputs = tNode.initialInputs;
11084 for (let i = start; i < end; i++) {
11085 const def = tView.data[i];
11086 const directive = getNodeInjectable(lView, tView, i, tNode);
11087 attachPatchData(directive, lView);
11088 if (initialInputs !== null) {
11089 setInputsFromAttrs(lView, i - start, directive, def, tNode, initialInputs);
11090 }
11091 if (isComponentDef(def)) {
11092 const componentView = getComponentLViewByIndex(tNode.index, lView);
11093 componentView[CONTEXT] = getNodeInjectable(lView, tView, i, tNode);
11094 }
11095 }
11096}
11097function invokeDirectivesHostBindings(tView, lView, tNode) {
11098 const start = tNode.directiveStart;
11099 const end = tNode.directiveEnd;
11100 const elementIndex = tNode.index;
11101 const currentDirectiveIndex = getCurrentDirectiveIndex();
11102 try {
11103 setSelectedIndex(elementIndex);
11104 for (let dirIndex = start; dirIndex < end; dirIndex++) {
11105 const def = tView.data[dirIndex];
11106 const directive = lView[dirIndex];
11107 setCurrentDirectiveIndex(dirIndex);
11108 if (def.hostBindings !== null || def.hostVars !== 0 || def.hostAttrs !== null) {
11109 invokeHostBindingsInCreationMode(def, directive);
11110 }
11111 }
11112 }
11113 finally {
11114 setSelectedIndex(-1);
11115 setCurrentDirectiveIndex(currentDirectiveIndex);
11116 }
11117}
11118/**
11119 * Invoke the host bindings in creation mode.
11120 *
11121 * @param def `DirectiveDef` which may contain the `hostBindings` function.
11122 * @param directive Instance of directive.
11123 */
11124function invokeHostBindingsInCreationMode(def, directive) {
11125 if (def.hostBindings !== null) {
11126 def.hostBindings(1 /* RenderFlags.Create */, directive);
11127 }
11128}
11129/**
11130 * Matches the current node against all available selectors.
11131 * If a component is matched (at most one), it is returned in first position in the array.
11132 */
11133function findDirectiveDefMatches(tView, tNode) {
11134 var _a;
11135 ngDevMode && assertFirstCreatePass(tView);
11136 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
11137 const registry = tView.directiveRegistry;
11138 let matches = null;
11139 let hostDirectiveDefs = null;
11140 if (registry) {
11141 for (let i = 0; i < registry.length; i++) {
11142 const def = registry[i];
11143 if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) {
11144 matches || (matches = []);
11145 if (isComponentDef(def)) {
11146 if (ngDevMode) {
11147 assertTNodeType(tNode, 2 /* TNodeType.Element */, `"${tNode.value}" tags cannot be used as component hosts. ` +
11148 `Please use a different tag to activate the ${stringify(def.type)} component.`);
11149 if (isComponentHost(tNode)) {
11150 throwMultipleComponentError(tNode, matches.find(isComponentDef).type, def.type);
11151 }
11152 }
11153 // Components are inserted at the front of the matches array so that their lifecycle
11154 // hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
11155 // compatibility. This logic doesn't make sense with host directives, because it
11156 // would allow the host directives to undo any overrides the host may have made.
11157 // To handle this case, the host directives of components are inserted at the beginning
11158 // of the array, followed by the component. As such, the insertion order is as follows:
11159 // 1. Host directives belonging to the selector-matched component.
11160 // 2. Selector-matched component.
11161 // 3. Host directives belonging to selector-matched directives.
11162 // 4. Selector-matched directives.
11163 if (def.findHostDirectiveDefs !== null) {
11164 const hostDirectiveMatches = [];
11165 hostDirectiveDefs = hostDirectiveDefs || new Map();
11166 def.findHostDirectiveDefs(def, hostDirectiveMatches, hostDirectiveDefs);
11167 // Add all host directives declared on this component, followed by the component itself.
11168 // Host directives should execute first so the host has a chance to override changes
11169 // to the DOM made by them.
11170 matches.unshift(...hostDirectiveMatches, def);
11171 // Component is offset starting from the beginning of the host directives array.
11172 const componentOffset = hostDirectiveMatches.length;
11173 markAsComponentHost(tView, tNode, componentOffset);
11174 }
11175 else {
11176 // No host directives on this component, just add the
11177 // component def to the beginning of the matches.
11178 matches.unshift(def);
11179 markAsComponentHost(tView, tNode, 0);
11180 }
11181 }
11182 else {
11183 // Append any host directives to the matches first.
11184 hostDirectiveDefs = hostDirectiveDefs || new Map();
11185 (_a = def.findHostDirectiveDefs) === null || _a === void 0 ? void 0 : _a.call(def, def, matches, hostDirectiveDefs);
11186 matches.push(def);
11187 }
11188 }
11189 }
11190 }
11191 return matches === null ? null : [matches, hostDirectiveDefs];
11192}
11193/**
11194 * Marks a given TNode as a component's host. This consists of:
11195 * - setting the component offset on the TNode.
11196 * - storing index of component's host element so it will be queued for view refresh during CD.
11197 */
11198function markAsComponentHost(tView, hostTNode, componentOffset) {
11199 ngDevMode && assertFirstCreatePass(tView);
11200 ngDevMode && assertGreaterThan(componentOffset, -1, 'componentOffset must be great than -1');
11201 hostTNode.componentOffset = componentOffset;
11202 (tView.components || (tView.components = [])).push(hostTNode.index);
11203}
11204/** Caches local names and their matching directive indices for query and template lookups. */
11205function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
11206 if (localRefs) {
11207 const localNames = tNode.localNames = [];
11208 // Local names must be stored in tNode in the same order that localRefs are defined
11209 // in the template to ensure the data is loaded in the same slots as their refs
11210 // in the template (for template queries).
11211 for (let i = 0; i < localRefs.length; i += 2) {
11212 const index = exportsMap[localRefs[i + 1]];
11213 if (index == null)
11214 throw new RuntimeError(-301 /* RuntimeErrorCode.EXPORT_NOT_FOUND */, ngDevMode && `Export of name '${localRefs[i + 1]}' not found!`);
11215 localNames.push(localRefs[i], index);
11216 }
11217 }
11218}
11219/**
11220 * Builds up an export map as directives are created, so local refs can be quickly mapped
11221 * to their directive instances.
11222 */
11223function saveNameToExportMap(directiveIdx, def, exportsMap) {
11224 if (exportsMap) {
11225 if (def.exportAs) {
11226 for (let i = 0; i < def.exportAs.length; i++) {
11227 exportsMap[def.exportAs[i]] = directiveIdx;
11228 }
11229 }
11230 if (isComponentDef(def))
11231 exportsMap[''] = directiveIdx;
11232 }
11233}
11234/**
11235 * Initializes the flags on the current node, setting all indices to the initial index,
11236 * the directive count to 0, and adding the isComponent flag.
11237 * @param index the initial index
11238 */
11239function initTNodeFlags(tNode, index, numberOfDirectives) {
11240 ngDevMode &&
11241 assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
11242 tNode.flags |= 1 /* TNodeFlags.isDirectiveHost */;
11243 // When the first directive is created on a node, save the index
11244 tNode.directiveStart = index;
11245 tNode.directiveEnd = index + numberOfDirectives;
11246 tNode.providerIndexes = index;
11247}
11248/**
11249 * Setup directive for instantiation.
11250 *
11251 * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
11252 * as `LView`. `TView` gets the `DirectiveDef`.
11253 *
11254 * @param tView `TView`
11255 * @param tNode `TNode`
11256 * @param lView `LView`
11257 * @param directiveIndex Index where the directive will be stored in the Expando.
11258 * @param def `DirectiveDef`
11259 */
11260function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
11261 ngDevMode &&
11262 assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
11263 tView.data[directiveIndex] = def;
11264 const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
11265 // Even though `directiveFactory` will already be using `ɵɵdirectiveInject` in its generated code,
11266 // we also want to support `inject()` directly from the directive constructor context so we set
11267 // `ɵɵdirectiveInject` as the inject implementation here too.
11268 const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
11269 tView.blueprint[directiveIndex] = nodeInjectorFactory;
11270 lView[directiveIndex] = nodeInjectorFactory;
11271 registerHostBindingOpCodes(tView, tNode, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
11272}
11273function addComponentLogic(lView, hostTNode, def) {
11274 const native = getNativeByTNode(hostTNode, lView);
11275 const tView = getOrCreateComponentTView(def);
11276 // Only component views should be added to the view tree directly. Embedded views are
11277 // accessed through their containers because they may be removed / re-added later.
11278 const rendererFactory = lView[RENDERER_FACTORY];
11279 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));
11280 // Component view will always be created before any injected LContainers,
11281 // so this is a regular element, wrap it with the component view
11282 lView[hostTNode.index] = componentView;
11283}
11284function elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace) {
11285 if (ngDevMode) {
11286 assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
11287 validateAgainstEventAttributes(name);
11288 assertTNodeType(tNode, 2 /* TNodeType.Element */, `Attempted to set attribute \`${name}\` on a container node. ` +
11289 `Host bindings are not valid on ng-container or ng-template.`);
11290 }
11291 const element = getNativeByTNode(tNode, lView);
11292 setElementAttribute(lView[RENDERER], element, namespace, tNode.value, name, value, sanitizer);
11293}
11294function setElementAttribute(renderer, element, namespace, tagName, name, value, sanitizer) {
11295 if (value == null) {
11296 ngDevMode && ngDevMode.rendererRemoveAttribute++;
11297 renderer.removeAttribute(element, name, namespace);
11298 }
11299 else {
11300 ngDevMode && ngDevMode.rendererSetAttribute++;
11301 const strValue = sanitizer == null ? renderStringify(value) : sanitizer(value, tagName || '', name);
11302 renderer.setAttribute(element, name, strValue, namespace);
11303 }
11304}
11305/**
11306 * Sets initial input properties on directive instances from attribute data
11307 *
11308 * @param lView Current LView that is being processed.
11309 * @param directiveIndex Index of the directive in directives array
11310 * @param instance Instance of the directive on which to set the initial inputs
11311 * @param def The directive def that contains the list of inputs
11312 * @param tNode The static data for this node
11313 */
11314function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initialInputData) {
11315 const initialInputs = initialInputData[directiveIndex];
11316 if (initialInputs !== null) {
11317 const setInput = def.setInput;
11318 for (let i = 0; i < initialInputs.length;) {
11319 const publicName = initialInputs[i++];
11320 const privateName = initialInputs[i++];
11321 const value = initialInputs[i++];
11322 if (setInput !== null) {
11323 def.setInput(instance, value, publicName, privateName);
11324 }
11325 else {
11326 instance[privateName] = value;
11327 }
11328 if (ngDevMode) {
11329 const nativeElement = getNativeByTNode(tNode, lView);
11330 setNgReflectProperty(lView, nativeElement, tNode.type, privateName, value);
11331 }
11332 }
11333 }
11334}
11335/**
11336 * Generates initialInputData for a node and stores it in the template's static storage
11337 * so subsequent template invocations don't have to recalculate it.
11338 *
11339 * initialInputData is an array containing values that need to be set as input properties
11340 * for directives on this node, but only once on creation. We need this array to support
11341 * the case where you set an @Input property of a directive using attribute-like syntax.
11342 * e.g. if you have a `name` @Input, you can set it once like this:
11343 *
11344 * <my-component name="Bess"></my-component>
11345 *
11346 * @param inputs Input alias map that was generated from the directive def inputs.
11347 * @param directiveIndex Index of the directive that is currently being processed.
11348 * @param attrs Static attrs on this node.
11349 */
11350function generateInitialInputs(inputs, directiveIndex, attrs) {
11351 let inputsToStore = null;
11352 let i = 0;
11353 while (i < attrs.length) {
11354 const attrName = attrs[i];
11355 if (attrName === 0 /* AttributeMarker.NamespaceURI */) {
11356 // We do not allow inputs on namespaced attributes.
11357 i += 4;
11358 continue;
11359 }
11360 else if (attrName === 5 /* AttributeMarker.ProjectAs */) {
11361 // Skip over the `ngProjectAs` value.
11362 i += 2;
11363 continue;
11364 }
11365 // If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
11366 if (typeof attrName === 'number')
11367 break;
11368 if (inputs.hasOwnProperty(attrName)) {
11369 if (inputsToStore === null)
11370 inputsToStore = [];
11371 // Find the input's public name from the input store. Note that we can be found easier
11372 // through the directive def, but we want to do it using the inputs store so that it can
11373 // account for host directive aliases.
11374 const inputConfig = inputs[attrName];
11375 for (let j = 0; j < inputConfig.length; j += 2) {
11376 if (inputConfig[j] === directiveIndex) {
11377 inputsToStore.push(attrName, inputConfig[j + 1], attrs[i + 1]);
11378 // A directive can't have multiple inputs with the same name so we can break here.
11379 break;
11380 }
11381 }
11382 }
11383 i += 2;
11384 }
11385 return inputsToStore;
11386}
11387//////////////////////////
11388//// ViewContainer & View
11389//////////////////////////
11390/**
11391 * Creates a LContainer, either from a container instruction, or for a ViewContainerRef.
11392 *
11393 * @param hostNative The host element for the LContainer
11394 * @param hostTNode The host TNode for the LContainer
11395 * @param currentView The parent view of the LContainer
11396 * @param native The native comment element
11397 * @param isForViewContainerRef Optional a flag indicating the ViewContainerRef case
11398 * @returns LContainer
11399 */
11400function createLContainer(hostNative, currentView, native, tNode) {
11401 ngDevMode && assertLView(currentView);
11402 const lContainer = [
11403 hostNative,
11404 true,
11405 false,
11406 currentView,
11407 null,
11408 0,
11409 tNode,
11410 native,
11411 null,
11412 null, // moved views
11413 ];
11414 ngDevMode &&
11415 assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
11416 return lContainer;
11417}
11418/**
11419 * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
11420 * them by executing an associated template function.
11421 */
11422function refreshEmbeddedViews(lView) {
11423 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
11424 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
11425 const embeddedLView = lContainer[i];
11426 const embeddedTView = embeddedLView[TVIEW];
11427 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
11428 if (viewAttachedToChangeDetector(embeddedLView)) {
11429 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
11430 }
11431 }
11432 }
11433}
11434/**
11435 * Mark transplanted views as needing to be refreshed at their insertion points.
11436 *
11437 * @param lView The `LView` that may have transplanted views.
11438 */
11439function markTransplantedViewsForRefresh(lView) {
11440 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
11441 if (!lContainer[HAS_TRANSPLANTED_VIEWS])
11442 continue;
11443 const movedViews = lContainer[MOVED_VIEWS];
11444 ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
11445 for (let i = 0; i < movedViews.length; i++) {
11446 const movedLView = movedViews[i];
11447 const insertionLContainer = movedLView[PARENT];
11448 ngDevMode && assertLContainer(insertionLContainer);
11449 // We don't want to increment the counter if the moved LView was already marked for
11450 // refresh.
11451 if ((movedLView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) === 0) {
11452 updateTransplantedViewCount(insertionLContainer, 1);
11453 }
11454 // Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
11455 // those that aren't (declaration component === insertion component). In the latter case,
11456 // it's fine to add the flag, as we will clear it immediately in
11457 // `refreshEmbeddedViews` for the view currently being refreshed.
11458 movedLView[FLAGS] |= 512 /* LViewFlags.RefreshTransplantedView */;
11459 }
11460 }
11461}
11462/////////////
11463/**
11464 * Refreshes components by entering the component view and processing its bindings, queries, etc.
11465 *
11466 * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
11467 */
11468function refreshComponent(hostLView, componentHostIdx) {
11469 ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
11470 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
11471 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
11472 if (viewAttachedToChangeDetector(componentView)) {
11473 const tView = componentView[TVIEW];
11474 if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 32 /* LViewFlags.Dirty */)) {
11475 refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
11476 }
11477 else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
11478 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
11479 refreshContainsDirtyView(componentView);
11480 }
11481 }
11482}
11483/**
11484 * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
11485 * children or descendants of the given lView.
11486 *
11487 * @param lView The lView which contains descendant transplanted views that need to be refreshed.
11488 */
11489function refreshContainsDirtyView(lView) {
11490 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
11491 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
11492 const embeddedLView = lContainer[i];
11493 if (viewAttachedToChangeDetector(embeddedLView)) {
11494 if (embeddedLView[FLAGS] & 512 /* LViewFlags.RefreshTransplantedView */) {
11495 const embeddedTView = embeddedLView[TVIEW];
11496 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
11497 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
11498 }
11499 else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
11500 refreshContainsDirtyView(embeddedLView);
11501 }
11502 }
11503 }
11504 }
11505 const tView = lView[TVIEW];
11506 // Refresh child component views.
11507 const components = tView.components;
11508 if (components !== null) {
11509 for (let i = 0; i < components.length; i++) {
11510 const componentView = getComponentLViewByIndex(components[i], lView);
11511 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
11512 if (viewAttachedToChangeDetector(componentView) &&
11513 componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
11514 refreshContainsDirtyView(componentView);
11515 }
11516 }
11517 }
11518}
11519function renderComponent(hostLView, componentHostIdx) {
11520 ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
11521 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
11522 const componentTView = componentView[TVIEW];
11523 syncViewWithBlueprint(componentTView, componentView);
11524 renderView(componentTView, componentView, componentView[CONTEXT]);
11525}
11526/**
11527 * Syncs an LView instance with its blueprint if they have gotten out of sync.
11528 *
11529 * Typically, blueprints and their view instances should always be in sync, so the loop here
11530 * will be skipped. However, consider this case of two components side-by-side:
11531 *
11532 * App template:
11533 * ```
11534 * <comp></comp>
11535 * <comp></comp>
11536 * ```
11537 *
11538 * The following will happen:
11539 * 1. App template begins processing.
11540 * 2. First <comp> is matched as a component and its LView is created.
11541 * 3. Second <comp> is matched as a component and its LView is created.
11542 * 4. App template completes processing, so it's time to check child templates.
11543 * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
11544 * 6. Second <comp> template is checked. Its blueprint has been updated by the first
11545 * <comp> template, but its LView was created before this update, so it is out of sync.
11546 *
11547 * Note that embedded views inside ngFor loops will never be out of sync because these views
11548 * are processed as soon as they are created.
11549 *
11550 * @param tView The `TView` that contains the blueprint for syncing
11551 * @param lView The view to sync
11552 */
11553function syncViewWithBlueprint(tView, lView) {
11554 for (let i = lView.length; i < tView.blueprint.length; i++) {
11555 lView.push(tView.blueprint[i]);
11556 }
11557}
11558/**
11559 * Adds LView or LContainer to the end of the current view tree.
11560 *
11561 * This structure will be used to traverse through nested views to remove listeners
11562 * and call onDestroy callbacks.
11563 *
11564 * @param lView The view where LView or LContainer should be added
11565 * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header
11566 * @param lViewOrLContainer The LView or LContainer to add to the view tree
11567 * @returns The state passed in
11568 */
11569function addToViewTree(lView, lViewOrLContainer) {
11570 // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
11571 // to the end of the queue, which means if the developer retrieves the LContainers from RNodes out
11572 // of order, the change detection will run out of order, as the act of retrieving the the
11573 // LContainer from the RNode is what adds it to the queue.
11574 if (lView[CHILD_HEAD]) {
11575 lView[CHILD_TAIL][NEXT] = lViewOrLContainer;
11576 }
11577 else {
11578 lView[CHILD_HEAD] = lViewOrLContainer;
11579 }
11580 lView[CHILD_TAIL] = lViewOrLContainer;
11581 return lViewOrLContainer;
11582}
11583///////////////////////////////
11584//// Change detection
11585///////////////////////////////
11586/**
11587 * Marks current view and all ancestors dirty.
11588 *
11589 * Returns the root view because it is found as a byproduct of marking the view tree
11590 * dirty, and can be used by methods that consume markViewDirty() to easily schedule
11591 * change detection. Otherwise, such methods would need to traverse up the view tree
11592 * an additional time to get the root view and schedule a tick on it.
11593 *
11594 * @param lView The starting LView to mark dirty
11595 * @returns the root LView
11596 */
11597function markViewDirty(lView) {
11598 while (lView) {
11599 lView[FLAGS] |= 32 /* LViewFlags.Dirty */;
11600 const parent = getLViewParent(lView);
11601 // Stop traversing up as soon as you find a root view that wasn't attached to any container
11602 if (isRootView(lView) && !parent) {
11603 return lView;
11604 }
11605 // continue otherwise
11606 lView = parent;
11607 }
11608 return null;
11609}
11610function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
11611 const rendererFactory = lView[RENDERER_FACTORY];
11612 // Check no changes mode is a dev only mode used to verify that bindings have not changed
11613 // since they were assigned. We do not want to invoke renderer factory functions in that mode
11614 // to avoid any possible side-effects.
11615 const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
11616 if (!checkNoChangesMode && rendererFactory.begin)
11617 rendererFactory.begin();
11618 try {
11619 refreshView(tView, lView, tView.template, context);
11620 }
11621 catch (error) {
11622 if (notifyErrorHandler) {
11623 handleError(lView, error);
11624 }
11625 throw error;
11626 }
11627 finally {
11628 if (!checkNoChangesMode && rendererFactory.end)
11629 rendererFactory.end();
11630 }
11631}
11632function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
11633 setIsInCheckNoChangesMode(true);
11634 try {
11635 detectChangesInternal(tView, lView, context, notifyErrorHandler);
11636 }
11637 finally {
11638 setIsInCheckNoChangesMode(false);
11639 }
11640}
11641function executeViewQueryFn(flags, viewQueryFn, component) {
11642 ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
11643 setCurrentQueryIndex(0);
11644 viewQueryFn(flags, component);
11645}
11646///////////////////////////////
11647//// Bindings & interpolations
11648///////////////////////////////
11649/**
11650 * Stores meta-data for a property binding to be used by TestBed's `DebugElement.properties`.
11651 *
11652 * In order to support TestBed's `DebugElement.properties` we need to save, for each binding:
11653 * - a bound property name;
11654 * - a static parts of interpolated strings;
11655 *
11656 * A given property metadata is saved at the binding's index in the `TView.data` (in other words, a
11657 * property binding metadata will be stored in `TView.data` at the same index as a bound value in
11658 * `LView`). Metadata are represented as `INTERPOLATION_DELIMITER`-delimited string with the
11659 * following format:
11660 * - `propertyName` for bound properties;
11661 * - `propertyName�prefix�interpolation_static_part1�..interpolation_static_partN�suffix` for
11662 * interpolated properties.
11663 *
11664 * @param tData `TData` where meta-data will be saved;
11665 * @param tNode `TNode` that is a target of the binding;
11666 * @param propertyName bound property name;
11667 * @param bindingIndex binding index in `LView`
11668 * @param interpolationParts static interpolation parts (for property interpolations)
11669 */
11670function storePropertyBindingMetadata(tData, tNode, propertyName, bindingIndex, ...interpolationParts) {
11671 // Binding meta-data are stored only the first time a given property instruction is processed.
11672 // Since we don't have a concept of the "first update pass" we need to check for presence of the
11673 // binding meta-data to decide if one should be stored (or if was stored already).
11674 if (tData[bindingIndex] === null) {
11675 if (tNode.inputs == null || !tNode.inputs[propertyName]) {
11676 const propBindingIdxs = tNode.propertyBindings || (tNode.propertyBindings = []);
11677 propBindingIdxs.push(bindingIndex);
11678 let bindingMetadata = propertyName;
11679 if (interpolationParts.length > 0) {
11680 bindingMetadata +=
11681 INTERPOLATION_DELIMITER + interpolationParts.join(INTERPOLATION_DELIMITER);
11682 }
11683 tData[bindingIndex] = bindingMetadata;
11684 }
11685 }
11686}
11687function getOrCreateLViewCleanup(view) {
11688 // top level variables should not be exported for performance reasons (PERF_NOTES.md)
11689 return view[CLEANUP] || (view[CLEANUP] = []);
11690}
11691function getOrCreateTViewCleanup(tView) {
11692 return tView.cleanup || (tView.cleanup = []);
11693}
11694/**
11695 * There are cases where the sub component's renderer needs to be included
11696 * instead of the current renderer (see the componentSyntheticHost* instructions).
11697 */
11698function loadComponentRenderer(currentDef, tNode, lView) {
11699 // TODO(FW-2043): the `currentDef` is null when host bindings are invoked while creating root
11700 // component (see packages/core/src/render3/component.ts). This is not consistent with the process
11701 // of creating inner components, when current directive index is available in the state. In order
11702 // to avoid relying on current def being `null` (thus special-casing root component creation), the
11703 // process of creating root component should be unified with the process of creating inner
11704 // components.
11705 if (currentDef === null || isComponentDef(currentDef)) {
11706 lView = unwrapLView(lView[tNode.index]);
11707 }
11708 return lView[RENDERER];
11709}
11710/** Handles an error thrown in an LView. */
11711function handleError(lView, error) {
11712 const injector = lView[INJECTOR$1];
11713 const errorHandler = injector ? injector.get(ErrorHandler, null) : null;
11714 errorHandler && errorHandler.handleError(error);
11715}
11716/**
11717 * Set the inputs of directives at the current node to corresponding value.
11718 *
11719 * @param tView The current TView
11720 * @param lView the `LView` which contains the directives.
11721 * @param inputs mapping between the public "input" name and privately-known,
11722 * possibly minified, property names to write to.
11723 * @param value Value to set.
11724 */
11725function setInputsForProperty(tView, lView, inputs, publicName, value) {
11726 for (let i = 0; i < inputs.length;) {
11727 const index = inputs[i++];
11728 const privateName = inputs[i++];
11729 const instance = lView[index];
11730 ngDevMode && assertIndexInRange(lView, index);
11731 const def = tView.data[index];
11732 if (def.setInput !== null) {
11733 def.setInput(instance, value, publicName, privateName);
11734 }
11735 else {
11736 instance[privateName] = value;
11737 }
11738 }
11739}
11740/**
11741 * Updates a text binding at a given index in a given LView.
11742 */
11743function textBindingInternal(lView, index, value) {
11744 ngDevMode && assertString(value, 'Value should be a string');
11745 ngDevMode && assertNotSame(value, NO_CHANGE, 'value should not be NO_CHANGE');
11746 ngDevMode && assertIndexInRange(lView, index);
11747 const element = getNativeByIndex(index, lView);
11748 ngDevMode && assertDefined(element, 'native element should exist');
11749 updateTextNode(lView[RENDERER], element, value);
11750}
11751
11752/**
11753 * Compute the static styling (class/style) from `TAttributes`.
11754 *
11755 * This function should be called during `firstCreatePass` only.
11756 *
11757 * @param tNode The `TNode` into which the styling information should be loaded.
11758 * @param attrs `TAttributes` containing the styling information.
11759 * @param writeToHost Where should the resulting static styles be written?
11760 * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
11761 * - `true` Write to `TNode.styles` / `TNode.classes`
11762 */
11763function computeStaticStyling(tNode, attrs, writeToHost) {
11764 ngDevMode &&
11765 assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
11766 let styles = writeToHost ? tNode.styles : null;
11767 let classes = writeToHost ? tNode.classes : null;
11768 let mode = 0;
11769 if (attrs !== null) {
11770 for (let i = 0; i < attrs.length; i++) {
11771 const value = attrs[i];
11772 if (typeof value === 'number') {
11773 mode = value;
11774 }
11775 else if (mode == 1 /* AttributeMarker.Classes */) {
11776 classes = concatStringsWithSpace(classes, value);
11777 }
11778 else if (mode == 2 /* AttributeMarker.Styles */) {
11779 const style = value;
11780 const styleValue = attrs[++i];
11781 styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
11782 }
11783 }
11784 }
11785 writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
11786 writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
11787}
11788
11789function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
11790 while (tNode !== null) {
11791 ngDevMode &&
11792 assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
11793 const lNode = lView[tNode.index];
11794 if (lNode !== null) {
11795 result.push(unwrapRNode(lNode));
11796 }
11797 // A given lNode can represent either a native node or a LContainer (when it is a host of a
11798 // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
11799 // from the views in this container.
11800 if (isLContainer(lNode)) {
11801 for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
11802 const lViewInAContainer = lNode[i];
11803 const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
11804 if (lViewFirstChildTNode !== null) {
11805 collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
11806 }
11807 }
11808 }
11809 const tNodeType = tNode.type;
11810 if (tNodeType & 8 /* TNodeType.ElementContainer */) {
11811 collectNativeNodes(tView, lView, tNode.child, result);
11812 }
11813 else if (tNodeType & 32 /* TNodeType.Icu */) {
11814 const nextRNode = icuContainerIterate(tNode, lView);
11815 let rNode;
11816 while (rNode = nextRNode()) {
11817 result.push(rNode);
11818 }
11819 }
11820 else if (tNodeType & 16 /* TNodeType.Projection */) {
11821 const nodesInSlot = getProjectionNodes(lView, tNode);
11822 if (Array.isArray(nodesInSlot)) {
11823 result.push(...nodesInSlot);
11824 }
11825 else {
11826 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
11827 ngDevMode && assertParentView(parentView);
11828 collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
11829 }
11830 }
11831 tNode = isProjection ? tNode.projectionNext : tNode.next;
11832 }
11833 return result;
11834}
11835
11836class ViewRef$1 {
11837 get rootNodes() {
11838 const lView = this._lView;
11839 const tView = lView[TVIEW];
11840 return collectNativeNodes(tView, lView, tView.firstChild, []);
11841 }
11842 constructor(
11843 /**
11844 * This represents `LView` associated with the component when ViewRef is a ChangeDetectorRef.
11845 *
11846 * When ViewRef is created for a dynamic component, this also represents the `LView` for the
11847 * component.
11848 *
11849 * For a "regular" ViewRef created for an embedded view, this is the `LView` for the embedded
11850 * view.
11851 *
11852 * @internal
11853 */
11854 _lView,
11855 /**
11856 * This represents the `LView` associated with the point where `ChangeDetectorRef` was
11857 * requested.
11858 *
11859 * This may be different from `_lView` if the `_cdRefInjectingView` is an embedded view.
11860 */
11861 _cdRefInjectingView) {
11862 this._lView = _lView;
11863 this._cdRefInjectingView = _cdRefInjectingView;
11864 this._appRef = null;
11865 this._attachedToViewContainer = false;
11866 }
11867 get context() {
11868 return this._lView[CONTEXT];
11869 }
11870 set context(value) {
11871 this._lView[CONTEXT] = value;
11872 }
11873 get destroyed() {
11874 return (this._lView[FLAGS] & 128 /* LViewFlags.Destroyed */) === 128 /* LViewFlags.Destroyed */;
11875 }
11876 destroy() {
11877 if (this._appRef) {
11878 this._appRef.detachView(this);
11879 }
11880 else if (this._attachedToViewContainer) {
11881 const parent = this._lView[PARENT];
11882 if (isLContainer(parent)) {
11883 const viewRefs = parent[VIEW_REFS];
11884 const index = viewRefs ? viewRefs.indexOf(this) : -1;
11885 if (index > -1) {
11886 ngDevMode &&
11887 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.');
11888 detachView(parent, index);
11889 removeFromArray(viewRefs, index);
11890 }
11891 }
11892 this._attachedToViewContainer = false;
11893 }
11894 destroyLView(this._lView[TVIEW], this._lView);
11895 }
11896 onDestroy(callback) {
11897 storeCleanupWithContext(this._lView[TVIEW], this._lView, null, callback);
11898 }
11899 /**
11900 * Marks a view and all of its ancestors dirty.
11901 *
11902 * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is
11903 * checked when it needs to be re-rendered but the two normal triggers haven't marked it
11904 * dirty (i.e. inputs haven't changed and events haven't fired in the view).
11905 *
11906 * <!-- TODO: Add a link to a chapter on OnPush components -->
11907 *
11908 * @usageNotes
11909 * ### Example
11910 *
11911 * ```typescript
11912 * @Component({
11913 * selector: 'app-root',
11914 * template: `Number of ticks: {{numberOfTicks}}`
11915 * changeDetection: ChangeDetectionStrategy.OnPush,
11916 * })
11917 * class AppComponent {
11918 * numberOfTicks = 0;
11919 *
11920 * constructor(private ref: ChangeDetectorRef) {
11921 * setInterval(() => {
11922 * this.numberOfTicks++;
11923 * // the following is required, otherwise the view will not be updated
11924 * this.ref.markForCheck();
11925 * }, 1000);
11926 * }
11927 * }
11928 * ```
11929 */
11930 markForCheck() {
11931 markViewDirty(this._cdRefInjectingView || this._lView);
11932 }
11933 /**
11934 * Detaches the view from the change detection tree.
11935 *
11936 * Detached views will not be checked during change detection runs until they are
11937 * re-attached, even if they are dirty. `detach` can be used in combination with
11938 * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change
11939 * detection checks.
11940 *
11941 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
11942 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
11943 *
11944 * @usageNotes
11945 * ### Example
11946 *
11947 * The following example defines a component with a large list of readonly data.
11948 * Imagine the data changes constantly, many times per second. For performance reasons,
11949 * we want to check and update the list every five seconds. We can do that by detaching
11950 * the component's change detector and doing a local check every five seconds.
11951 *
11952 * ```typescript
11953 * class DataProvider {
11954 * // in a real application the returned data will be different every time
11955 * get data() {
11956 * return [1,2,3,4,5];
11957 * }
11958 * }
11959 *
11960 * @Component({
11961 * selector: 'giant-list',
11962 * template: `
11963 * <li *ngFor="let d of dataProvider.data">Data {{d}}</li>
11964 * `,
11965 * })
11966 * class GiantList {
11967 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {
11968 * ref.detach();
11969 * setInterval(() => {
11970 * this.ref.detectChanges();
11971 * }, 5000);
11972 * }
11973 * }
11974 *
11975 * @Component({
11976 * selector: 'app',
11977 * providers: [DataProvider],
11978 * template: `
11979 * <giant-list><giant-list>
11980 * `,
11981 * })
11982 * class App {
11983 * }
11984 * ```
11985 */
11986 detach() {
11987 this._lView[FLAGS] &= ~64 /* LViewFlags.Attached */;
11988 }
11989 /**
11990 * Re-attaches a view to the change detection tree.
11991 *
11992 * This can be used to re-attach views that were previously detached from the tree
11993 * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default.
11994 *
11995 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
11996 *
11997 * @usageNotes
11998 * ### Example
11999 *
12000 * The following example creates a component displaying `live` data. The component will detach
12001 * its change detector from the main change detector tree when the component's live property
12002 * is set to false.
12003 *
12004 * ```typescript
12005 * class DataProvider {
12006 * data = 1;
12007 *
12008 * constructor() {
12009 * setInterval(() => {
12010 * this.data = this.data * 2;
12011 * }, 500);
12012 * }
12013 * }
12014 *
12015 * @Component({
12016 * selector: 'live-data',
12017 * inputs: ['live'],
12018 * template: 'Data: {{dataProvider.data}}'
12019 * })
12020 * class LiveData {
12021 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {}
12022 *
12023 * set live(value) {
12024 * if (value) {
12025 * this.ref.reattach();
12026 * } else {
12027 * this.ref.detach();
12028 * }
12029 * }
12030 * }
12031 *
12032 * @Component({
12033 * selector: 'app-root',
12034 * providers: [DataProvider],
12035 * template: `
12036 * Live Update: <input type="checkbox" [(ngModel)]="live">
12037 * <live-data [live]="live"><live-data>
12038 * `,
12039 * })
12040 * class AppComponent {
12041 * live = true;
12042 * }
12043 * ```
12044 */
12045 reattach() {
12046 this._lView[FLAGS] |= 64 /* LViewFlags.Attached */;
12047 }
12048 /**
12049 * Checks the view and its children.
12050 *
12051 * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement
12052 * local change detection checks.
12053 *
12054 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
12055 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
12056 *
12057 * @usageNotes
12058 * ### Example
12059 *
12060 * The following example defines a component with a large list of readonly data.
12061 * Imagine, the data changes constantly, many times per second. For performance reasons,
12062 * we want to check and update the list every five seconds.
12063 *
12064 * We can do that by detaching the component's change detector and doing a local change detection
12065 * check every five seconds.
12066 *
12067 * See {@link ChangeDetectorRef#detach detach} for more information.
12068 */
12069 detectChanges() {
12070 detectChangesInternal(this._lView[TVIEW], this._lView, this.context);
12071 }
12072 /**
12073 * Checks the change detector and its children, and throws if any changes are detected.
12074 *
12075 * This is used in development mode to verify that running change detection doesn't
12076 * introduce other changes.
12077 */
12078 checkNoChanges() {
12079 if (ngDevMode) {
12080 checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
12081 }
12082 }
12083 attachToViewContainerRef() {
12084 if (this._appRef) {
12085 throw new RuntimeError(902 /* RuntimeErrorCode.VIEW_ALREADY_ATTACHED */, ngDevMode && 'This view is already attached directly to the ApplicationRef!');
12086 }
12087 this._attachedToViewContainer = true;
12088 }
12089 detachFromAppRef() {
12090 this._appRef = null;
12091 renderDetachView(this._lView[TVIEW], this._lView);
12092 }
12093 attachToAppRef(appRef) {
12094 if (this._attachedToViewContainer) {
12095 throw new RuntimeError(902 /* RuntimeErrorCode.VIEW_ALREADY_ATTACHED */, ngDevMode && 'This view is already attached to a ViewContainer!');
12096 }
12097 this._appRef = appRef;
12098 }
12099}
12100/** @internal */
12101class RootViewRef extends ViewRef$1 {
12102 constructor(_view) {
12103 super(_view);
12104 this._view = _view;
12105 }
12106 detectChanges() {
12107 const lView = this._view;
12108 const tView = lView[TVIEW];
12109 const context = lView[CONTEXT];
12110 detectChangesInternal(tView, lView, context, false);
12111 }
12112 checkNoChanges() {
12113 if (ngDevMode) {
12114 const lView = this._view;
12115 const tView = lView[TVIEW];
12116 const context = lView[CONTEXT];
12117 checkNoChangesInternal(tView, lView, context, false);
12118 }
12119 }
12120 get context() {
12121 return null;
12122 }
12123}
12124
12125class ComponentFactoryResolver extends ComponentFactoryResolver$1 {
12126 /**
12127 * @param ngModule The NgModuleRef to which all resolved factories are bound.
12128 */
12129 constructor(ngModule) {
12130 super();
12131 this.ngModule = ngModule;
12132 }
12133 resolveComponentFactory(component) {
12134 ngDevMode && assertComponentType(component);
12135 const componentDef = getComponentDef(component);
12136 return new ComponentFactory(componentDef, this.ngModule);
12137 }
12138}
12139function toRefArray(map) {
12140 const array = [];
12141 for (let nonMinified in map) {
12142 if (map.hasOwnProperty(nonMinified)) {
12143 const minified = map[nonMinified];
12144 array.push({ propName: minified, templateName: nonMinified });
12145 }
12146 }
12147 return array;
12148}
12149function getNamespace(elementName) {
12150 const name = elementName.toLowerCase();
12151 return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null);
12152}
12153/**
12154 * Injector that looks up a value using a specific injector, before falling back to the module
12155 * injector. Used primarily when creating components or embedded views dynamically.
12156 */
12157class ChainedInjector {
12158 constructor(injector, parentInjector) {
12159 this.injector = injector;
12160 this.parentInjector = parentInjector;
12161 }
12162 get(token, notFoundValue, flags) {
12163 flags = convertToBitFlags(flags);
12164 const value = this.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
12165 if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
12166 notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
12167 // Return the value from the root element injector when
12168 // - it provides it
12169 // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
12170 // - the module injector should not be checked
12171 // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
12172 return value;
12173 }
12174 return this.parentInjector.get(token, notFoundValue, flags);
12175 }
12176}
12177/**
12178 * ComponentFactory interface implementation.
12179 */
12180class ComponentFactory extends ComponentFactory$1 {
12181 get inputs() {
12182 return toRefArray(this.componentDef.inputs);
12183 }
12184 get outputs() {
12185 return toRefArray(this.componentDef.outputs);
12186 }
12187 /**
12188 * @param componentDef The component definition.
12189 * @param ngModule The NgModuleRef to which the factory is bound.
12190 */
12191 constructor(componentDef, ngModule) {
12192 super();
12193 this.componentDef = componentDef;
12194 this.ngModule = ngModule;
12195 this.componentType = componentDef.type;
12196 this.selector = stringifyCSSSelectorList(componentDef.selectors);
12197 this.ngContentSelectors =
12198 componentDef.ngContentSelectors ? componentDef.ngContentSelectors : [];
12199 this.isBoundToModule = !!ngModule;
12200 }
12201 create(injector, projectableNodes, rootSelectorOrNode, environmentInjector) {
12202 environmentInjector = environmentInjector || this.ngModule;
12203 let realEnvironmentInjector = environmentInjector instanceof EnvironmentInjector ?
12204 environmentInjector :
12205 environmentInjector === null || environmentInjector === void 0 ? void 0 : environmentInjector.injector;
12206 if (realEnvironmentInjector && this.componentDef.getStandaloneInjector !== null) {
12207 realEnvironmentInjector = this.componentDef.getStandaloneInjector(realEnvironmentInjector) ||
12208 realEnvironmentInjector;
12209 }
12210 const rootViewInjector = realEnvironmentInjector ? new ChainedInjector(injector, realEnvironmentInjector) : injector;
12211 const rendererFactory = rootViewInjector.get(RendererFactory2, null);
12212 if (rendererFactory === null) {
12213 throw new RuntimeError(407 /* RuntimeErrorCode.RENDERER_NOT_FOUND */, ngDevMode &&
12214 'Angular was not able to inject a renderer (RendererFactory2). ' +
12215 'Likely this is due to a broken DI hierarchy. ' +
12216 'Make sure that any injector used to create this component has a correct parent.');
12217 }
12218 const sanitizer = rootViewInjector.get(Sanitizer, null);
12219 const hostRenderer = rendererFactory.createRenderer(null, this.componentDef);
12220 // Determine a tag name used for creating host elements when this component is created
12221 // dynamically. Default to 'div' if this component did not specify any tag name in its selector.
12222 const elementName = this.componentDef.selectors[0][0] || 'div';
12223 const hostRNode = rootSelectorOrNode ?
12224 locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) :
12225 createElementNode(hostRenderer, elementName, getNamespace(elementName));
12226 const rootFlags = this.componentDef.onPush ? 32 /* LViewFlags.Dirty */ | 256 /* LViewFlags.IsRoot */ :
12227 16 /* LViewFlags.CheckAlways */ | 256 /* LViewFlags.IsRoot */;
12228 // Create the root view. Uses empty TView and ContentTemplate.
12229 const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null);
12230 const rootLView = createLView(null, rootTView, null, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector, null);
12231 // rootView is the parent when bootstrapping
12232 // TODO(misko): it looks like we are entering view here but we don't really need to as
12233 // `renderView` does that. However as the code is written it is needed because
12234 // `createRootComponentView` and `createRootComponent` both read global state. Fixing those
12235 // issues would allow us to drop this.
12236 enterView(rootLView);
12237 let component;
12238 let tElementNode;
12239 try {
12240 const rootComponentDef = this.componentDef;
12241 let rootDirectives;
12242 let hostDirectiveDefs = null;
12243 if (rootComponentDef.findHostDirectiveDefs) {
12244 rootDirectives = [];
12245 hostDirectiveDefs = new Map();
12246 rootComponentDef.findHostDirectiveDefs(rootComponentDef, rootDirectives, hostDirectiveDefs);
12247 rootDirectives.push(rootComponentDef);
12248 }
12249 else {
12250 rootDirectives = [rootComponentDef];
12251 }
12252 const hostTNode = createRootComponentTNode(rootLView, hostRNode);
12253 const componentView = createRootComponentView(hostTNode, hostRNode, rootComponentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
12254 tElementNode = getTNode(rootTView, HEADER_OFFSET);
12255 // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests
12256 // where the renderer is mocked out and `undefined` is returned. We should update the tests so
12257 // that this check can be removed.
12258 if (hostRNode) {
12259 setRootNodeAttributes(hostRenderer, rootComponentDef, hostRNode, rootSelectorOrNode);
12260 }
12261 if (projectableNodes !== undefined) {
12262 projectNodes(tElementNode, this.ngContentSelectors, projectableNodes);
12263 }
12264 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
12265 // executed here?
12266 // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
12267 component = createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, [LifecycleHooksFeature]);
12268 renderView(rootTView, rootLView, null);
12269 }
12270 finally {
12271 leaveView();
12272 }
12273 return new ComponentRef(this.componentType, component, createElementRef(tElementNode, rootLView), rootLView, tElementNode);
12274 }
12275}
12276/**
12277 * Represents an instance of a Component created via a {@link ComponentFactory}.
12278 *
12279 * `ComponentRef` provides access to the Component Instance as well other objects related to this
12280 * Component Instance and allows you to destroy the Component Instance via the {@link #destroy}
12281 * method.
12282 *
12283 */
12284class ComponentRef extends ComponentRef$1 {
12285 constructor(componentType, instance, location, _rootLView, _tNode) {
12286 super();
12287 this.location = location;
12288 this._rootLView = _rootLView;
12289 this._tNode = _tNode;
12290 this.instance = instance;
12291 this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView);
12292 this.componentType = componentType;
12293 }
12294 setInput(name, value) {
12295 const inputData = this._tNode.inputs;
12296 let dataValue;
12297 if (inputData !== null && (dataValue = inputData[name])) {
12298 const lView = this._rootLView;
12299 setInputsForProperty(lView[TVIEW], lView, dataValue, name, value);
12300 markDirtyIfOnPush(lView, this._tNode.index);
12301 }
12302 else {
12303 if (ngDevMode) {
12304 const cmpNameForError = stringifyForError(this.componentType);
12305 let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `;
12306 message += `Make sure that the '${name}' property is annotated with @Input() or a mapped @Input('${name}') exists.`;
12307 reportUnknownPropertyError(message);
12308 }
12309 }
12310 }
12311 get injector() {
12312 return new NodeInjector(this._tNode, this._rootLView);
12313 }
12314 destroy() {
12315 this.hostView.destroy();
12316 }
12317 onDestroy(callback) {
12318 this.hostView.onDestroy(callback);
12319 }
12320}
12321// TODO: A hack to not pull in the NullInjector from @angular/core.
12322const NULL_INJECTOR = {
12323 get: (token, notFoundValue) => {
12324 throwProviderNotFoundError(token, 'NullInjector');
12325 }
12326};
12327/** Creates a TNode that can be used to instantiate a root component. */
12328function createRootComponentTNode(lView, rNode) {
12329 const tView = lView[TVIEW];
12330 const index = HEADER_OFFSET;
12331 ngDevMode && assertIndexInRange(lView, index);
12332 lView[index] = rNode;
12333 // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
12334 // the same time we want to communicate the debug `TNode` that this is a special `TNode`
12335 // representing a host element.
12336 return getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null);
12337}
12338/**
12339 * Creates the root component view and the root component node.
12340 *
12341 * @param rNode Render host element.
12342 * @param rootComponentDef ComponentDef
12343 * @param rootView The parent view where the host node is stored
12344 * @param rendererFactory Factory to be used for creating child renderers.
12345 * @param hostRenderer The current renderer
12346 * @param sanitizer The sanitizer, if provided
12347 *
12348 * @returns Component view created
12349 */
12350function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives, rootView, rendererFactory, hostRenderer, sanitizer) {
12351 const tView = rootView[TVIEW];
12352 applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer);
12353 const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
12354 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);
12355 if (tView.firstCreatePass) {
12356 markAsComponentHost(tView, tNode, rootDirectives.length - 1);
12357 }
12358 addToViewTree(rootView, componentView);
12359 // Store component view at node index, with node as the HOST
12360 return rootView[tNode.index] = componentView;
12361}
12362/** Sets up the styling information on a root component. */
12363function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) {
12364 for (const def of rootDirectives) {
12365 tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
12366 }
12367 if (tNode.mergedAttrs !== null) {
12368 computeStaticStyling(tNode, tNode.mergedAttrs, true);
12369 if (rNode !== null) {
12370 setupStaticAttributes(hostRenderer, rNode, tNode);
12371 }
12372 }
12373}
12374/**
12375 * Creates a root component and sets it up with features and host bindings.Shared by
12376 * renderComponent() and ViewContainerRef.createComponent().
12377 */
12378function createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, hostFeatures) {
12379 const rootTNode = getCurrentTNode();
12380 ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
12381 const tView = rootLView[TVIEW];
12382 const native = getNativeByTNode(rootTNode, rootLView);
12383 initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null, hostDirectiveDefs);
12384 for (let i = 0; i < rootDirectives.length; i++) {
12385 const directiveIndex = rootTNode.directiveStart + i;
12386 const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode);
12387 attachPatchData(directiveInstance, rootLView);
12388 }
12389 invokeDirectivesHostBindings(tView, rootLView, rootTNode);
12390 if (native) {
12391 attachPatchData(native, rootLView);
12392 }
12393 // We're guaranteed for the `componentOffset` to be positive here
12394 // since a root component always matches a component def.
12395 ngDevMode &&
12396 assertGreaterThan(rootTNode.componentOffset, -1, 'componentOffset must be great than -1');
12397 const component = getNodeInjectable(rootLView, tView, rootTNode.directiveStart + rootTNode.componentOffset, rootTNode);
12398 componentView[CONTEXT] = rootLView[CONTEXT] = component;
12399 if (hostFeatures !== null) {
12400 for (const feature of hostFeatures) {
12401 feature(component, rootComponentDef);
12402 }
12403 }
12404 // We want to generate an empty QueryList for root content queries for backwards
12405 // compatibility with ViewEngine.
12406 executeContentQueries(tView, rootTNode, componentView);
12407 return component;
12408}
12409/** Sets the static attributes on a root component. */
12410function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) {
12411 if (rootSelectorOrNode) {
12412 setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]);
12413 }
12414 else {
12415 // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
12416 // is not defined), also apply attributes and classes extracted from component selector.
12417 // Extract attributes and classes from the first selector only to match VE behavior.
12418 const { attrs, classes } = extractAttrsAndClassesFromSelector(componentDef.selectors[0]);
12419 if (attrs) {
12420 setUpAttributes(hostRenderer, hostRNode, attrs);
12421 }
12422 if (classes && classes.length > 0) {
12423 writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
12424 }
12425 }
12426}
12427/** Projects the `projectableNodes` that were specified when creating a root component. */
12428function projectNodes(tNode, ngContentSelectors, projectableNodes) {
12429 const projection = tNode.projection = [];
12430 for (let i = 0; i < ngContentSelectors.length; i++) {
12431 const nodesforSlot = projectableNodes[i];
12432 // Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
12433 // case). Here we do normalize passed data structure to be an array of arrays to avoid
12434 // complex checks down the line.
12435 // We also normalize the length of the passed in projectable nodes (to match the number of
12436 // <ng-container> slots defined by a component).
12437 projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
12438 }
12439}
12440/**
12441 * Used to enable lifecycle hooks on the root component.
12442 *
12443 * Include this feature when calling `renderComponent` if the root component
12444 * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't
12445 * be called properly.
12446 *
12447 * Example:
12448 *
12449 * ```
12450 * renderComponent(AppComponent, {hostFeatures: [LifecycleHooksFeature]});
12451 * ```
12452 */
12453function LifecycleHooksFeature() {
12454 const tNode = getCurrentTNode();
12455 ngDevMode && assertDefined(tNode, 'TNode is required');
12456 registerPostOrderHooks(getLView()[TVIEW], tNode);
12457}
12458
12459function getSuperType(type) {
12460 return Object.getPrototypeOf(type.prototype).constructor;
12461}
12462/**
12463 * Merges the definition from a super class to a sub class.
12464 * @param definition The definition that is a SubClass of another directive of component
12465 *
12466 * @codeGenApi
12467 */
12468function ɵɵInheritDefinitionFeature(definition) {
12469 let superType = getSuperType(definition.type);
12470 let shouldInheritFields = true;
12471 const inheritanceChain = [definition];
12472 while (superType) {
12473 let superDef = undefined;
12474 if (isComponentDef(definition)) {
12475 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12476 superDef = superType.ɵcmp || superType.ɵdir;
12477 }
12478 else {
12479 if (superType.ɵcmp) {
12480 throw new RuntimeError(903 /* RuntimeErrorCode.INVALID_INHERITANCE */, ngDevMode &&
12481 `Directives cannot inherit Components. Directive ${stringifyForError(definition.type)} is attempting to extend component ${stringifyForError(superType)}`);
12482 }
12483 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12484 superDef = superType.ɵdir;
12485 }
12486 if (superDef) {
12487 if (shouldInheritFields) {
12488 inheritanceChain.push(superDef);
12489 // Some fields in the definition may be empty, if there were no values to put in them that
12490 // would've justified object creation. Unwrap them if necessary.
12491 const writeableDef = definition;
12492 writeableDef.inputs = maybeUnwrapEmpty(definition.inputs);
12493 writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs);
12494 writeableDef.outputs = maybeUnwrapEmpty(definition.outputs);
12495 // Merge hostBindings
12496 const superHostBindings = superDef.hostBindings;
12497 superHostBindings && inheritHostBindings(definition, superHostBindings);
12498 // Merge queries
12499 const superViewQuery = superDef.viewQuery;
12500 const superContentQueries = superDef.contentQueries;
12501 superViewQuery && inheritViewQuery(definition, superViewQuery);
12502 superContentQueries && inheritContentQueries(definition, superContentQueries);
12503 // Merge inputs and outputs
12504 fillProperties(definition.inputs, superDef.inputs);
12505 fillProperties(definition.declaredInputs, superDef.declaredInputs);
12506 fillProperties(definition.outputs, superDef.outputs);
12507 // Merge animations metadata.
12508 // If `superDef` is a Component, the `data` field is present (defaults to an empty object).
12509 if (isComponentDef(superDef) && superDef.data.animation) {
12510 // If super def is a Component, the `definition` is also a Component, since Directives can
12511 // not inherit Components (we throw an error above and cannot reach this code).
12512 const defData = definition.data;
12513 defData.animation = (defData.animation || []).concat(superDef.data.animation);
12514 }
12515 }
12516 // Run parent features
12517 const features = superDef.features;
12518 if (features) {
12519 for (let i = 0; i < features.length; i++) {
12520 const feature = features[i];
12521 if (feature && feature.ngInherit) {
12522 feature(definition);
12523 }
12524 // If `InheritDefinitionFeature` is a part of the current `superDef`, it means that this
12525 // def already has all the necessary information inherited from its super class(es), so we
12526 // can stop merging fields from super classes. However we need to iterate through the
12527 // prototype chain to look for classes that might contain other "features" (like
12528 // NgOnChanges), which we should invoke for the original `definition`. We set the
12529 // `shouldInheritFields` flag to indicate that, essentially skipping fields inheritance
12530 // logic and only invoking functions from the "features" list.
12531 if (feature === ɵɵInheritDefinitionFeature) {
12532 shouldInheritFields = false;
12533 }
12534 }
12535 }
12536 }
12537 superType = Object.getPrototypeOf(superType);
12538 }
12539 mergeHostAttrsAcrossInheritance(inheritanceChain);
12540}
12541/**
12542 * Merge the `hostAttrs` and `hostVars` from the inherited parent to the base class.
12543 *
12544 * @param inheritanceChain A list of `WritableDefs` starting at the top most type and listing
12545 * sub-types in order. For each type take the `hostAttrs` and `hostVars` and merge it with the child
12546 * type.
12547 */
12548function mergeHostAttrsAcrossInheritance(inheritanceChain) {
12549 let hostVars = 0;
12550 let hostAttrs = null;
12551 // We process the inheritance order from the base to the leaves here.
12552 for (let i = inheritanceChain.length - 1; i >= 0; i--) {
12553 const def = inheritanceChain[i];
12554 // For each `hostVars`, we need to add the superclass amount.
12555 def.hostVars = (hostVars += def.hostVars);
12556 // for each `hostAttrs` we need to merge it with superclass.
12557 def.hostAttrs =
12558 mergeHostAttrs(def.hostAttrs, hostAttrs = mergeHostAttrs(hostAttrs, def.hostAttrs));
12559 }
12560}
12561function maybeUnwrapEmpty(value) {
12562 if (value === EMPTY_OBJ) {
12563 return {};
12564 }
12565 else if (value === EMPTY_ARRAY) {
12566 return [];
12567 }
12568 else {
12569 return value;
12570 }
12571}
12572function inheritViewQuery(definition, superViewQuery) {
12573 const prevViewQuery = definition.viewQuery;
12574 if (prevViewQuery) {
12575 definition.viewQuery = (rf, ctx) => {
12576 superViewQuery(rf, ctx);
12577 prevViewQuery(rf, ctx);
12578 };
12579 }
12580 else {
12581 definition.viewQuery = superViewQuery;
12582 }
12583}
12584function inheritContentQueries(definition, superContentQueries) {
12585 const prevContentQueries = definition.contentQueries;
12586 if (prevContentQueries) {
12587 definition.contentQueries = (rf, ctx, directiveIndex) => {
12588 superContentQueries(rf, ctx, directiveIndex);
12589 prevContentQueries(rf, ctx, directiveIndex);
12590 };
12591 }
12592 else {
12593 definition.contentQueries = superContentQueries;
12594 }
12595}
12596function inheritHostBindings(definition, superHostBindings) {
12597 const prevHostBindings = definition.hostBindings;
12598 if (prevHostBindings) {
12599 definition.hostBindings = (rf, ctx) => {
12600 superHostBindings(rf, ctx);
12601 prevHostBindings(rf, ctx);
12602 };
12603 }
12604 else {
12605 definition.hostBindings = superHostBindings;
12606 }
12607}
12608
12609/**
12610 * Fields which exist on either directive or component definitions, and need to be copied from
12611 * parent to child classes by the `ɵɵCopyDefinitionFeature`.
12612 */
12613const COPY_DIRECTIVE_FIELDS = [
12614 // The child class should use the providers of its parent.
12615 'providersResolver',
12616 // Not listed here are any fields which are handled by the `ɵɵInheritDefinitionFeature`, such
12617 // as inputs, outputs, and host binding functions.
12618];
12619/**
12620 * Fields which exist only on component definitions, and need to be copied from parent to child
12621 * classes by the `ɵɵCopyDefinitionFeature`.
12622 *
12623 * The type here allows any field of `ComponentDef` which is not also a property of `DirectiveDef`,
12624 * since those should go in `COPY_DIRECTIVE_FIELDS` above.
12625 */
12626const COPY_COMPONENT_FIELDS = [
12627 // The child class should use the template function of its parent, including all template
12628 // semantics.
12629 'template',
12630 'decls',
12631 'consts',
12632 'vars',
12633 'onPush',
12634 'ngContentSelectors',
12635 // The child class should use the CSS styles of its parent, including all styling semantics.
12636 'styles',
12637 'encapsulation',
12638 // The child class should be checked by the runtime in the same way as its parent.
12639 'schemas',
12640];
12641/**
12642 * Copies the fields not handled by the `ɵɵInheritDefinitionFeature` from the supertype of a
12643 * definition.
12644 *
12645 * This exists primarily to support ngcc migration of an existing View Engine pattern, where an
12646 * entire decorator is inherited from a parent to a child class. When ngcc detects this case, it
12647 * generates a skeleton definition on the child class, and applies this feature.
12648 *
12649 * The `ɵɵCopyDefinitionFeature` then copies any needed fields from the parent class' definition,
12650 * including things like the component template function.
12651 *
12652 * @param definition The definition of a child class which inherits from a parent class with its
12653 * own definition.
12654 *
12655 * @codeGenApi
12656 */
12657function ɵɵCopyDefinitionFeature(definition) {
12658 let superType = getSuperType(definition.type);
12659 let superDef = undefined;
12660 if (isComponentDef(definition)) {
12661 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12662 superDef = superType.ɵcmp;
12663 }
12664 else {
12665 // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
12666 superDef = superType.ɵdir;
12667 }
12668 // Needed because `definition` fields are readonly.
12669 const defAny = definition;
12670 // Copy over any fields that apply to either directives or components.
12671 for (const field of COPY_DIRECTIVE_FIELDS) {
12672 defAny[field] = superDef[field];
12673 }
12674 if (isComponentDef(superDef)) {
12675 // Copy over any component-specific fields.
12676 for (const field of COPY_COMPONENT_FIELDS) {
12677 defAny[field] = superDef[field];
12678 }
12679 }
12680}
12681
12682/**
12683 * This feature adds the host directives behavior to a directive definition by patching a
12684 * function onto it. The expectation is that the runtime will invoke the function during
12685 * directive matching.
12686 *
12687 * For example:
12688 * ```ts
12689 * class ComponentWithHostDirective {
12690 * static ɵcmp = defineComponent({
12691 * type: ComponentWithHostDirective,
12692 * features: [ɵɵHostDirectivesFeature([
12693 * SimpleHostDirective,
12694 * {directive: AdvancedHostDirective, inputs: ['foo: alias'], outputs: ['bar']},
12695 * ])]
12696 * });
12697 * }
12698 * ```
12699 *
12700 * @codeGenApi
12701 */
12702function ɵɵHostDirectivesFeature(rawHostDirectives) {
12703 return (definition) => {
12704 definition.findHostDirectiveDefs = findHostDirectiveDefs;
12705 definition.hostDirectives =
12706 (Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
12707 return typeof dir === 'function' ?
12708 { directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
12709 {
12710 directive: resolveForwardRef(dir.directive),
12711 inputs: bindingArrayToMap(dir.inputs),
12712 outputs: bindingArrayToMap(dir.outputs)
12713 };
12714 });
12715 };
12716}
12717function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
12718 if (currentDef.hostDirectives !== null) {
12719 for (const hostDirectiveConfig of currentDef.hostDirectives) {
12720 const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
12721 if (typeof ngDevMode === 'undefined' || ngDevMode) {
12722 validateHostDirective(hostDirectiveConfig, hostDirectiveDef, matchedDefs);
12723 }
12724 // We need to patch the `declaredInputs` so that
12725 // `ngOnChanges` can map the properties correctly.
12726 patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
12727 // Host directives execute before the host so that its host bindings can be overwritten.
12728 findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
12729 hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
12730 matchedDefs.push(hostDirectiveDef);
12731 }
12732 }
12733}
12734/**
12735 * Converts an array in the form of `['publicName', 'alias', 'otherPublicName', 'otherAlias']` into
12736 * a map in the form of `{publicName: 'alias', otherPublicName: 'otherAlias'}`.
12737 */
12738function bindingArrayToMap(bindings) {
12739 if (bindings === undefined || bindings.length === 0) {
12740 return EMPTY_OBJ;
12741 }
12742 const result = {};
12743 for (let i = 0; i < bindings.length; i += 2) {
12744 result[bindings[i]] = bindings[i + 1];
12745 }
12746 return result;
12747}
12748/**
12749 * `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
12750 * `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
12751 * minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
12752 * will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
12753 * minification.
12754 *
12755 * This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
12756 * definition is declared. When a property is written to the directive instance, the
12757 * `NgOnChangesFeature` will try to remap the property name being written to using the
12758 * `declaredInputs`.
12759 *
12760 * Since the host directive input remapping happens during directive matching, `declaredInputs`
12761 * won't contain the new alias that the input is available under. This function addresses the
12762 * issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
12763 * this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
12764 * is used *only* by the `NgOnChangesFeature` when determining what name is used in the
12765 * `SimpleChanges` object which won't be reached if an input doesn't exist.
12766 */
12767function patchDeclaredInputs(declaredInputs, exposedInputs) {
12768 for (const publicName in exposedInputs) {
12769 if (exposedInputs.hasOwnProperty(publicName)) {
12770 const remappedPublicName = exposedInputs[publicName];
12771 const privateName = declaredInputs[publicName];
12772 // We *technically* shouldn't be able to hit this case because we can't have multiple
12773 // inputs on the same property and we have validations against conflicting aliases in
12774 // `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
12775 // with the wrong name so we have a non-user-friendly assertion here just in case.
12776 if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
12777 declaredInputs.hasOwnProperty(remappedPublicName)) {
12778 assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
12779 }
12780 declaredInputs[remappedPublicName] = privateName;
12781 }
12782 }
12783}
12784/**
12785 * Verifies that the host directive has been configured correctly.
12786 * @param hostDirectiveConfig Host directive configuration object.
12787 * @param directiveDef Directive definition of the host directive.
12788 * @param matchedDefs Directives that have been matched so far.
12789 */
12790function validateHostDirective(hostDirectiveConfig, directiveDef, matchedDefs) {
12791 const type = hostDirectiveConfig.directive;
12792 if (directiveDef === null) {
12793 if (getComponentDef(type) !== null) {
12794 throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
12795 }
12796 throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
12797 `Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
12798 }
12799 if (!directiveDef.standalone) {
12800 throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
12801 }
12802 if (matchedDefs.indexOf(directiveDef) > -1) {
12803 throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTITVE */, `Directive ${directiveDef.type.name} matches multiple times on the same element. ` +
12804 `Directives can only match an element once.`);
12805 }
12806 validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
12807 validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
12808}
12809/**
12810 * Checks that the host directive inputs/outputs configuration is valid.
12811 * @param bindingType Kind of binding that is being validated. Used in the error message.
12812 * @param def Definition of the host directive that is being validated against.
12813 * @param hostDirectiveBindings Host directive mapping object that shold be validated.
12814 */
12815function validateMappings(bindingType, def, hostDirectiveBindings) {
12816 const className = def.type.name;
12817 const bindings = bindingType === 'input' ? def.inputs : def.outputs;
12818 for (const publicName in hostDirectiveBindings) {
12819 if (hostDirectiveBindings.hasOwnProperty(publicName)) {
12820 if (!bindings.hasOwnProperty(publicName)) {
12821 throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
12822 }
12823 const remappedPublicName = hostDirectiveBindings[publicName];
12824 if (bindings.hasOwnProperty(remappedPublicName) &&
12825 bindings[remappedPublicName] !== publicName) {
12826 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.`);
12827 }
12828 }
12829 }
12830}
12831
12832let _symbolIterator = null;
12833function getSymbolIterator() {
12834 if (!_symbolIterator) {
12835 const Symbol = _global['Symbol'];
12836 if (Symbol && Symbol.iterator) {
12837 _symbolIterator = Symbol.iterator;
12838 }
12839 else {
12840 // es6-shim specific logic
12841 const keys = Object.getOwnPropertyNames(Map.prototype);
12842 for (let i = 0; i < keys.length; ++i) {
12843 const key = keys[i];
12844 if (key !== 'entries' && key !== 'size' &&
12845 Map.prototype[key] === Map.prototype['entries']) {
12846 _symbolIterator = key;
12847 }
12848 }
12849 }
12850 }
12851 return _symbolIterator;
12852}
12853
12854function isIterable(obj) {
12855 return obj !== null && typeof obj === 'object' && obj[getSymbolIterator()] !== undefined;
12856}
12857function isListLikeIterable(obj) {
12858 if (!isJsObject(obj))
12859 return false;
12860 return Array.isArray(obj) ||
12861 (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
12862 getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop
12863}
12864function areIterablesEqual(a, b, comparator) {
12865 const iterator1 = a[getSymbolIterator()]();
12866 const iterator2 = b[getSymbolIterator()]();
12867 while (true) {
12868 const item1 = iterator1.next();
12869 const item2 = iterator2.next();
12870 if (item1.done && item2.done)
12871 return true;
12872 if (item1.done || item2.done)
12873 return false;
12874 if (!comparator(item1.value, item2.value))
12875 return false;
12876 }
12877}
12878function iterateListLike(obj, fn) {
12879 if (Array.isArray(obj)) {
12880 for (let i = 0; i < obj.length; i++) {
12881 fn(obj[i]);
12882 }
12883 }
12884 else {
12885 const iterator = obj[getSymbolIterator()]();
12886 let item;
12887 while (!((item = iterator.next()).done)) {
12888 fn(item.value);
12889 }
12890 }
12891}
12892function isJsObject(o) {
12893 return o !== null && (typeof o === 'function' || typeof o === 'object');
12894}
12895
12896function devModeEqual(a, b) {
12897 const isListLikeIterableA = isListLikeIterable(a);
12898 const isListLikeIterableB = isListLikeIterable(b);
12899 if (isListLikeIterableA && isListLikeIterableB) {
12900 return areIterablesEqual(a, b, devModeEqual);
12901 }
12902 else {
12903 const isAObject = a && (typeof a === 'object' || typeof a === 'function');
12904 const isBObject = b && (typeof b === 'object' || typeof b === 'function');
12905 if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
12906 return true;
12907 }
12908 else {
12909 return Object.is(a, b);
12910 }
12911 }
12912}
12913
12914// TODO(misko): consider inlining
12915/** Updates binding and returns the value. */
12916function updateBinding(lView, bindingIndex, value) {
12917 return lView[bindingIndex] = value;
12918}
12919/** Gets the current binding value. */
12920function getBinding(lView, bindingIndex) {
12921 ngDevMode && assertIndexInRange(lView, bindingIndex);
12922 ngDevMode &&
12923 assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
12924 return lView[bindingIndex];
12925}
12926/**
12927 * Updates binding if changed, then returns whether it was updated.
12928 *
12929 * This function also checks the `CheckNoChangesMode` and throws if changes are made.
12930 * Some changes (Objects/iterables) during `CheckNoChangesMode` are exempt to comply with VE
12931 * behavior.
12932 *
12933 * @param lView current `LView`
12934 * @param bindingIndex The binding in the `LView` to check
12935 * @param value New value to check against `lView[bindingIndex]`
12936 * @returns `true` if the bindings has changed. (Throws if binding has changed during
12937 * `CheckNoChangesMode`)
12938 */
12939function bindingUpdated(lView, bindingIndex, value) {
12940 ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
12941 ngDevMode &&
12942 assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`);
12943 const oldValue = lView[bindingIndex];
12944 if (Object.is(oldValue, value)) {
12945 return false;
12946 }
12947 else {
12948 if (ngDevMode && isInCheckNoChangesMode()) {
12949 // View engine didn't report undefined values as changed on the first checkNoChanges pass
12950 // (before the change detection was run).
12951 const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
12952 if (!devModeEqual(oldValueToCompare, value)) {
12953 const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
12954 throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName);
12955 }
12956 // There was a change, but the `devModeEqual` decided that the change is exempt from an error.
12957 // For this reason we exit as if no change. The early exit is needed to prevent the changed
12958 // value to be written into `LView` (If we would write the new value that we would not see it
12959 // as change on next CD.)
12960 return false;
12961 }
12962 lView[bindingIndex] = value;
12963 return true;
12964 }
12965}
12966/** Updates 2 bindings if changed, then returns whether either was updated. */
12967function bindingUpdated2(lView, bindingIndex, exp1, exp2) {
12968 const different = bindingUpdated(lView, bindingIndex, exp1);
12969 return bindingUpdated(lView, bindingIndex + 1, exp2) || different;
12970}
12971/** Updates 3 bindings if changed, then returns whether any was updated. */
12972function bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) {
12973 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
12974 return bindingUpdated(lView, bindingIndex + 2, exp3) || different;
12975}
12976/** Updates 4 bindings if changed, then returns whether any was updated. */
12977function bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) {
12978 const different = bindingUpdated2(lView, bindingIndex, exp1, exp2);
12979 return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different;
12980}
12981
12982/**
12983 * Updates the value of or removes a bound attribute on an Element.
12984 *
12985 * Used in the case of `[attr.title]="value"`
12986 *
12987 * @param name name The name of the attribute.
12988 * @param value value The attribute is removed when value is `null` or `undefined`.
12989 * Otherwise the attribute value is set to the stringified value.
12990 * @param sanitizer An optional function used to sanitize the value.
12991 * @param namespace Optional namespace to use when setting the attribute.
12992 *
12993 * @codeGenApi
12994 */
12995function ɵɵattribute(name, value, sanitizer, namespace) {
12996 const lView = getLView();
12997 const bindingIndex = nextBindingIndex();
12998 if (bindingUpdated(lView, bindingIndex, value)) {
12999 const tView = getTView();
13000 const tNode = getSelectedTNode();
13001 elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace);
13002 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, 'attr.' + name, bindingIndex);
13003 }
13004 return ɵɵattribute;
13005}
13006
13007/**
13008 * Create interpolation bindings with a variable number of expressions.
13009 *
13010 * If there are 1 to 8 expressions `interpolation1()` to `interpolation8()` should be used instead.
13011 * Those are faster because there is no need to create an array of expressions and iterate over it.
13012 *
13013 * `values`:
13014 * - has static text at even indexes,
13015 * - has evaluated expressions at odd indexes.
13016 *
13017 * Returns the concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
13018 */
13019function interpolationV(lView, values) {
13020 ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
13021 ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
13022 let isBindingUpdated = false;
13023 let bindingIndex = getBindingIndex();
13024 for (let i = 1; i < values.length; i += 2) {
13025 // Check if bindings (odd indexes) have changed
13026 isBindingUpdated = bindingUpdated(lView, bindingIndex++, values[i]) || isBindingUpdated;
13027 }
13028 setBindingIndex(bindingIndex);
13029 if (!isBindingUpdated) {
13030 return NO_CHANGE;
13031 }
13032 // Build the updated content
13033 let content = values[0];
13034 for (let i = 1; i < values.length; i += 2) {
13035 content += renderStringify(values[i]) + values[i + 1];
13036 }
13037 return content;
13038}
13039/**
13040 * Creates an interpolation binding with 1 expression.
13041 *
13042 * @param prefix static value used for concatenation only.
13043 * @param v0 value checked for change.
13044 * @param suffix static value used for concatenation only.
13045 */
13046function interpolation1(lView, prefix, v0, suffix) {
13047 const different = bindingUpdated(lView, nextBindingIndex(), v0);
13048 return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE;
13049}
13050/**
13051 * Creates an interpolation binding with 2 expressions.
13052 */
13053function interpolation2(lView, prefix, v0, i0, v1, suffix) {
13054 const bindingIndex = getBindingIndex();
13055 const different = bindingUpdated2(lView, bindingIndex, v0, v1);
13056 incrementBindingIndex(2);
13057 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE;
13058}
13059/**
13060 * Creates an interpolation binding with 3 expressions.
13061 */
13062function interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix) {
13063 const bindingIndex = getBindingIndex();
13064 const different = bindingUpdated3(lView, bindingIndex, v0, v1, v2);
13065 incrementBindingIndex(3);
13066 return different ?
13067 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix :
13068 NO_CHANGE;
13069}
13070/**
13071 * Create an interpolation binding with 4 expressions.
13072 */
13073function interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix) {
13074 const bindingIndex = getBindingIndex();
13075 const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13076 incrementBindingIndex(4);
13077 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13078 renderStringify(v2) + i2 + renderStringify(v3) + suffix :
13079 NO_CHANGE;
13080}
13081/**
13082 * Creates an interpolation binding with 5 expressions.
13083 */
13084function interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) {
13085 const bindingIndex = getBindingIndex();
13086 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13087 different = bindingUpdated(lView, bindingIndex + 4, v4) || different;
13088 incrementBindingIndex(5);
13089 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13090 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + suffix :
13091 NO_CHANGE;
13092}
13093/**
13094 * Creates an interpolation binding with 6 expressions.
13095 */
13096function interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) {
13097 const bindingIndex = getBindingIndex();
13098 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13099 different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different;
13100 incrementBindingIndex(6);
13101 return different ?
13102 prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
13103 renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix :
13104 NO_CHANGE;
13105}
13106/**
13107 * Creates an interpolation binding with 7 expressions.
13108 */
13109function interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) {
13110 const bindingIndex = getBindingIndex();
13111 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13112 different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different;
13113 incrementBindingIndex(7);
13114 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13115 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
13116 renderStringify(v5) + i5 + renderStringify(v6) + suffix :
13117 NO_CHANGE;
13118}
13119/**
13120 * Creates an interpolation binding with 8 expressions.
13121 */
13122function interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) {
13123 const bindingIndex = getBindingIndex();
13124 let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
13125 different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different;
13126 incrementBindingIndex(8);
13127 return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 +
13128 renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 +
13129 renderStringify(v5) + i5 + renderStringify(v6) + i6 + renderStringify(v7) + suffix :
13130 NO_CHANGE;
13131}
13132
13133/**
13134 *
13135 * Update an interpolated attribute on an element with single bound value surrounded by text.
13136 *
13137 * Used when the value passed to a property has 1 interpolated value in it:
13138 *
13139 * ```html
13140 * <div attr.title="prefix{{v0}}suffix"></div>
13141 * ```
13142 *
13143 * Its compiled representation is::
13144 *
13145 * ```ts
13146 * ɵɵattributeInterpolate1('title', 'prefix', v0, 'suffix');
13147 * ```
13148 *
13149 * @param attrName The name of the attribute to update
13150 * @param prefix Static value used for concatenation only.
13151 * @param v0 Value checked for change.
13152 * @param suffix Static value used for concatenation only.
13153 * @param sanitizer An optional sanitizer function
13154 * @returns itself, so that it may be chained.
13155 * @codeGenApi
13156 */
13157function ɵɵattributeInterpolate1(attrName, prefix, v0, suffix, sanitizer, namespace) {
13158 const lView = getLView();
13159 const interpolatedValue = interpolation1(lView, prefix, v0, suffix);
13160 if (interpolatedValue !== NO_CHANGE) {
13161 const tNode = getSelectedTNode();
13162 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13163 ngDevMode &&
13164 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 1, prefix, suffix);
13165 }
13166 return ɵɵattributeInterpolate1;
13167}
13168/**
13169 *
13170 * Update an interpolated attribute on an element with 2 bound values surrounded by text.
13171 *
13172 * Used when the value passed to a property has 2 interpolated values in it:
13173 *
13174 * ```html
13175 * <div attr.title="prefix{{v0}}-{{v1}}suffix"></div>
13176 * ```
13177 *
13178 * Its compiled representation is::
13179 *
13180 * ```ts
13181 * ɵɵattributeInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
13182 * ```
13183 *
13184 * @param attrName The name of the attribute to update
13185 * @param prefix Static value used for concatenation only.
13186 * @param v0 Value checked for change.
13187 * @param i0 Static value used for concatenation only.
13188 * @param v1 Value checked for change.
13189 * @param suffix Static value used for concatenation only.
13190 * @param sanitizer An optional sanitizer function
13191 * @returns itself, so that it may be chained.
13192 * @codeGenApi
13193 */
13194function ɵɵattributeInterpolate2(attrName, prefix, v0, i0, v1, suffix, sanitizer, namespace) {
13195 const lView = getLView();
13196 const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix);
13197 if (interpolatedValue !== NO_CHANGE) {
13198 const tNode = getSelectedTNode();
13199 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13200 ngDevMode &&
13201 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 2, prefix, i0, suffix);
13202 }
13203 return ɵɵattributeInterpolate2;
13204}
13205/**
13206 *
13207 * Update an interpolated attribute on an element with 3 bound values surrounded by text.
13208 *
13209 * Used when the value passed to a property has 3 interpolated values in it:
13210 *
13211 * ```html
13212 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
13213 * ```
13214 *
13215 * Its compiled representation is::
13216 *
13217 * ```ts
13218 * ɵɵattributeInterpolate3(
13219 * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
13220 * ```
13221 *
13222 * @param attrName The name of the attribute to update
13223 * @param prefix Static value used for concatenation only.
13224 * @param v0 Value checked for change.
13225 * @param i0 Static value used for concatenation only.
13226 * @param v1 Value checked for change.
13227 * @param i1 Static value used for concatenation only.
13228 * @param v2 Value checked for change.
13229 * @param suffix Static value used for concatenation only.
13230 * @param sanitizer An optional sanitizer function
13231 * @returns itself, so that it may be chained.
13232 * @codeGenApi
13233 */
13234function ɵɵattributeInterpolate3(attrName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer, namespace) {
13235 const lView = getLView();
13236 const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix);
13237 if (interpolatedValue !== NO_CHANGE) {
13238 const tNode = getSelectedTNode();
13239 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13240 ngDevMode &&
13241 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 3, prefix, i0, i1, suffix);
13242 }
13243 return ɵɵattributeInterpolate3;
13244}
13245/**
13246 *
13247 * Update an interpolated attribute on an element with 4 bound values surrounded by text.
13248 *
13249 * Used when the value passed to a property has 4 interpolated values in it:
13250 *
13251 * ```html
13252 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
13253 * ```
13254 *
13255 * Its compiled representation is::
13256 *
13257 * ```ts
13258 * ɵɵattributeInterpolate4(
13259 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
13260 * ```
13261 *
13262 * @param attrName The name of the attribute to update
13263 * @param prefix Static value used for concatenation only.
13264 * @param v0 Value checked for change.
13265 * @param i0 Static value used for concatenation only.
13266 * @param v1 Value checked for change.
13267 * @param i1 Static value used for concatenation only.
13268 * @param v2 Value checked for change.
13269 * @param i2 Static value used for concatenation only.
13270 * @param v3 Value checked for change.
13271 * @param suffix Static value used for concatenation only.
13272 * @param sanitizer An optional sanitizer function
13273 * @returns itself, so that it may be chained.
13274 * @codeGenApi
13275 */
13276function ɵɵattributeInterpolate4(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer, namespace) {
13277 const lView = getLView();
13278 const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
13279 if (interpolatedValue !== NO_CHANGE) {
13280 const tNode = getSelectedTNode();
13281 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13282 ngDevMode &&
13283 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix);
13284 }
13285 return ɵɵattributeInterpolate4;
13286}
13287/**
13288 *
13289 * Update an interpolated attribute on an element with 5 bound values surrounded by text.
13290 *
13291 * Used when the value passed to a property has 5 interpolated values in it:
13292 *
13293 * ```html
13294 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
13295 * ```
13296 *
13297 * Its compiled representation is::
13298 *
13299 * ```ts
13300 * ɵɵattributeInterpolate5(
13301 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
13302 * ```
13303 *
13304 * @param attrName The name of the attribute to update
13305 * @param prefix Static value used for concatenation only.
13306 * @param v0 Value checked for change.
13307 * @param i0 Static value used for concatenation only.
13308 * @param v1 Value checked for change.
13309 * @param i1 Static value used for concatenation only.
13310 * @param v2 Value checked for change.
13311 * @param i2 Static value used for concatenation only.
13312 * @param v3 Value checked for change.
13313 * @param i3 Static value used for concatenation only.
13314 * @param v4 Value checked for change.
13315 * @param suffix Static value used for concatenation only.
13316 * @param sanitizer An optional sanitizer function
13317 * @returns itself, so that it may be chained.
13318 * @codeGenApi
13319 */
13320function ɵɵattributeInterpolate5(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer, namespace) {
13321 const lView = getLView();
13322 const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
13323 if (interpolatedValue !== NO_CHANGE) {
13324 const tNode = getSelectedTNode();
13325 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13326 ngDevMode &&
13327 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix);
13328 }
13329 return ɵɵattributeInterpolate5;
13330}
13331/**
13332 *
13333 * Update an interpolated attribute on an element with 6 bound values surrounded by text.
13334 *
13335 * Used when the value passed to a property has 6 interpolated values in it:
13336 *
13337 * ```html
13338 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
13339 * ```
13340 *
13341 * Its compiled representation is::
13342 *
13343 * ```ts
13344 * ɵɵattributeInterpolate6(
13345 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
13346 * ```
13347 *
13348 * @param attrName The name of the attribute to update
13349 * @param prefix Static value used for concatenation only.
13350 * @param v0 Value checked for change.
13351 * @param i0 Static value used for concatenation only.
13352 * @param v1 Value checked for change.
13353 * @param i1 Static value used for concatenation only.
13354 * @param v2 Value checked for change.
13355 * @param i2 Static value used for concatenation only.
13356 * @param v3 Value checked for change.
13357 * @param i3 Static value used for concatenation only.
13358 * @param v4 Value checked for change.
13359 * @param i4 Static value used for concatenation only.
13360 * @param v5 Value checked for change.
13361 * @param suffix Static value used for concatenation only.
13362 * @param sanitizer An optional sanitizer function
13363 * @returns itself, so that it may be chained.
13364 * @codeGenApi
13365 */
13366function ɵɵattributeInterpolate6(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer, namespace) {
13367 const lView = getLView();
13368 const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
13369 if (interpolatedValue !== NO_CHANGE) {
13370 const tNode = getSelectedTNode();
13371 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13372 ngDevMode &&
13373 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, i4, suffix);
13374 }
13375 return ɵɵattributeInterpolate6;
13376}
13377/**
13378 *
13379 * Update an interpolated attribute on an element with 7 bound values surrounded by text.
13380 *
13381 * Used when the value passed to a property has 7 interpolated values in it:
13382 *
13383 * ```html
13384 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
13385 * ```
13386 *
13387 * Its compiled representation is::
13388 *
13389 * ```ts
13390 * ɵɵattributeInterpolate7(
13391 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
13392 * ```
13393 *
13394 * @param attrName The name of the attribute to update
13395 * @param prefix Static value used for concatenation only.
13396 * @param v0 Value checked for change.
13397 * @param i0 Static value used for concatenation only.
13398 * @param v1 Value checked for change.
13399 * @param i1 Static value used for concatenation only.
13400 * @param v2 Value checked for change.
13401 * @param i2 Static value used for concatenation only.
13402 * @param v3 Value checked for change.
13403 * @param i3 Static value used for concatenation only.
13404 * @param v4 Value checked for change.
13405 * @param i4 Static value used for concatenation only.
13406 * @param v5 Value checked for change.
13407 * @param i5 Static value used for concatenation only.
13408 * @param v6 Value checked for change.
13409 * @param suffix Static value used for concatenation only.
13410 * @param sanitizer An optional sanitizer function
13411 * @returns itself, so that it may be chained.
13412 * @codeGenApi
13413 */
13414function ɵɵattributeInterpolate7(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer, namespace) {
13415 const lView = getLView();
13416 const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
13417 if (interpolatedValue !== NO_CHANGE) {
13418 const tNode = getSelectedTNode();
13419 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13420 ngDevMode &&
13421 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, suffix);
13422 }
13423 return ɵɵattributeInterpolate7;
13424}
13425/**
13426 *
13427 * Update an interpolated attribute on an element with 8 bound values surrounded by text.
13428 *
13429 * Used when the value passed to a property has 8 interpolated values in it:
13430 *
13431 * ```html
13432 * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
13433 * ```
13434 *
13435 * Its compiled representation is::
13436 *
13437 * ```ts
13438 * ɵɵattributeInterpolate8(
13439 * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
13440 * ```
13441 *
13442 * @param attrName The name of the attribute to update
13443 * @param prefix Static value used for concatenation only.
13444 * @param v0 Value checked for change.
13445 * @param i0 Static value used for concatenation only.
13446 * @param v1 Value checked for change.
13447 * @param i1 Static value used for concatenation only.
13448 * @param v2 Value checked for change.
13449 * @param i2 Static value used for concatenation only.
13450 * @param v3 Value checked for change.
13451 * @param i3 Static value used for concatenation only.
13452 * @param v4 Value checked for change.
13453 * @param i4 Static value used for concatenation only.
13454 * @param v5 Value checked for change.
13455 * @param i5 Static value used for concatenation only.
13456 * @param v6 Value checked for change.
13457 * @param i6 Static value used for concatenation only.
13458 * @param v7 Value checked for change.
13459 * @param suffix Static value used for concatenation only.
13460 * @param sanitizer An optional sanitizer function
13461 * @returns itself, so that it may be chained.
13462 * @codeGenApi
13463 */
13464function ɵɵattributeInterpolate8(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer, namespace) {
13465 const lView = getLView();
13466 const interpolatedValue = interpolation8(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
13467 if (interpolatedValue !== NO_CHANGE) {
13468 const tNode = getSelectedTNode();
13469 elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace);
13470 ngDevMode &&
13471 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, suffix);
13472 }
13473 return ɵɵattributeInterpolate8;
13474}
13475/**
13476 * Update an interpolated attribute on an element with 9 or more bound values surrounded by text.
13477 *
13478 * Used when the number of interpolated values exceeds 8.
13479 *
13480 * ```html
13481 * <div
13482 * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
13483 * ```
13484 *
13485 * Its compiled representation is::
13486 *
13487 * ```ts
13488 * ɵɵattributeInterpolateV(
13489 * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
13490 * 'suffix']);
13491 * ```
13492 *
13493 * @param attrName The name of the attribute to update.
13494 * @param values The collection of values and the strings in-between those values, beginning with
13495 * a string prefix and ending with a string suffix.
13496 * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
13497 * @param sanitizer An optional sanitizer function
13498 * @returns itself, so that it may be chained.
13499 * @codeGenApi
13500 */
13501function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
13502 const lView = getLView();
13503 const interpolated = interpolationV(lView, values);
13504 if (interpolated !== NO_CHANGE) {
13505 const tNode = getSelectedTNode();
13506 elementAttributeInternal(tNode, lView, attrName, interpolated, sanitizer, namespace);
13507 if (ngDevMode) {
13508 const interpolationInBetween = [values[0]]; // prefix
13509 for (let i = 2; i < values.length; i += 2) {
13510 interpolationInBetween.push(values[i]);
13511 }
13512 storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
13513 }
13514 }
13515 return ɵɵattributeInterpolateV;
13516}
13517
13518/**
13519 * Synchronously perform change detection on a component (and possibly its sub-components).
13520 *
13521 * This function triggers change detection in a synchronous way on a component.
13522 *
13523 * @param component The component which the change detection should be performed on.
13524 */
13525function detectChanges(component) {
13526 const view = getComponentViewByInstance(component);
13527 detectChangesInternal(view[TVIEW], view, component);
13528}
13529
13530function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
13531 ngDevMode && assertFirstCreatePass(tView);
13532 ngDevMode && ngDevMode.firstCreatePass++;
13533 const tViewConsts = tView.consts;
13534 // TODO(pk): refactor getOrCreateTNode to have the "create" only version
13535 const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
13536 resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
13537 registerPostOrderHooks(tView, tNode);
13538 const embeddedTView = tNode.tViews = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
13539 if (tView.queries !== null) {
13540 tView.queries.template(tView, tNode);
13541 embeddedTView.queries = tView.queries.embeddedTView(tNode);
13542 }
13543 return tNode;
13544}
13545/**
13546 * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
13547 *
13548 * <ng-template #foo>
13549 * <div></div>
13550 * </ng-template>
13551 *
13552 * @param index The index of the container in the data array
13553 * @param templateFn Inline template
13554 * @param decls The number of nodes, local refs, and pipes for this template
13555 * @param vars The number of bindings for this template
13556 * @param tagName The name of the container element, if applicable
13557 * @param attrsIndex Index of template attributes in the `consts` array.
13558 * @param localRefs Index of the local references in the `consts` array.
13559 * @param localRefExtractor A function which extracts local-refs values from the template.
13560 * Defaults to the current element associated with the local-ref.
13561 *
13562 * @codeGenApi
13563 */
13564function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
13565 const lView = getLView();
13566 const tView = getTView();
13567 const adjustedIndex = index + HEADER_OFFSET;
13568 const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
13569 tView.data[adjustedIndex];
13570 setCurrentTNode(tNode, false);
13571 const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : '');
13572 appendChild(tView, lView, comment, tNode);
13573 attachPatchData(comment, lView);
13574 addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
13575 if (isDirectiveHost(tNode)) {
13576 createDirectivesInstances(tView, lView, tNode);
13577 }
13578 if (localRefsIndex != null) {
13579 saveResolvedLocalsInData(lView, tNode, localRefExtractor);
13580 }
13581}
13582
13583/** Store a value in the `data` at a given `index`. */
13584function store(tView, lView, index, value) {
13585 // We don't store any static data for local variables, so the first time
13586 // we see the template, we should store as null to avoid a sparse array
13587 if (index >= tView.data.length) {
13588 tView.data[index] = null;
13589 tView.blueprint[index] = null;
13590 }
13591 lView[index] = value;
13592}
13593/**
13594 * Retrieves a local reference from the current contextViewData.
13595 *
13596 * If the reference to retrieve is in a parent view, this instruction is used in conjunction
13597 * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
13598 *
13599 * @param index The index of the local ref in contextViewData.
13600 *
13601 * @codeGenApi
13602 */
13603function ɵɵreference(index) {
13604 const contextLView = getContextLView();
13605 return load(contextLView, HEADER_OFFSET + index);
13606}
13607
13608/**
13609 * Update a property on a selected element.
13610 *
13611 * Operates on the element selected by index via the {@link select} instruction.
13612 *
13613 * If the property name also exists as an input property on one of the element's directives,
13614 * the component property will be set instead of the element property. This check must
13615 * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled
13616 *
13617 * @param propName Name of property. Because it is going to DOM, this is not subject to
13618 * renaming as part of minification.
13619 * @param value New value to write.
13620 * @param sanitizer An optional function used to sanitize the value.
13621 * @returns This function returns itself so that it may be chained
13622 * (e.g. `property('name', ctx.name)('title', ctx.title)`)
13623 *
13624 * @codeGenApi
13625 */
13626function ɵɵproperty(propName, value, sanitizer) {
13627 const lView = getLView();
13628 const bindingIndex = nextBindingIndex();
13629 if (bindingUpdated(lView, bindingIndex, value)) {
13630 const tView = getTView();
13631 const tNode = getSelectedTNode();
13632 elementPropertyInternal(tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, false);
13633 ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
13634 }
13635 return ɵɵproperty;
13636}
13637/**
13638 * Given `<div style="..." my-dir>` and `MyDir` with `@Input('style')` we need to write to
13639 * directive input.
13640 */
13641function setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased) {
13642 const inputs = tNode.inputs;
13643 const property = isClassBased ? 'class' : 'style';
13644 // We support both 'class' and `className` hence the fallback.
13645 setInputsForProperty(tView, lView, inputs[property], property, value);
13646}
13647
13648function elementStartFirstCreatePass(index, tView, lView, native, name, attrsIndex, localRefsIndex) {
13649 ngDevMode && assertFirstCreatePass(tView);
13650 ngDevMode && ngDevMode.firstCreatePass++;
13651 const tViewConsts = tView.consts;
13652 const attrs = getConstant(tViewConsts, attrsIndex);
13653 const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, name, attrs);
13654 const hasDirectives = resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
13655 if (ngDevMode) {
13656 validateElementIsKnown(native, lView, tNode.value, tView.schemas, hasDirectives);
13657 }
13658 if (tNode.attrs !== null) {
13659 computeStaticStyling(tNode, tNode.attrs, false);
13660 }
13661 if (tNode.mergedAttrs !== null) {
13662 computeStaticStyling(tNode, tNode.mergedAttrs, true);
13663 }
13664 if (tView.queries !== null) {
13665 tView.queries.elementStart(tView, tNode);
13666 }
13667 return tNode;
13668}
13669/**
13670 * Create DOM element. The instruction must later be followed by `elementEnd()` call.
13671 *
13672 * @param index Index of the element in the LView array
13673 * @param name Name of the DOM Node
13674 * @param attrsIndex Index of the element's attributes in the `consts` array.
13675 * @param localRefsIndex Index of the element's local references in the `consts` array.
13676 * @returns This function returns itself so that it may be chained.
13677 *
13678 * Attributes and localRefs are passed as an array of strings where elements with an even index
13679 * hold an attribute name and elements with an odd index hold an attribute value, ex.:
13680 * ['id', 'warning5', 'class', 'alert']
13681 *
13682 * @codeGenApi
13683 */
13684function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
13685 const lView = getLView();
13686 const tView = getTView();
13687 const adjustedIndex = HEADER_OFFSET + index;
13688 ngDevMode &&
13689 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'elements should be created before any bindings');
13690 ngDevMode && assertIndexInRange(lView, adjustedIndex);
13691 const renderer = lView[RENDERER];
13692 const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1());
13693 const tNode = tView.firstCreatePass ?
13694 elementStartFirstCreatePass(adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
13695 tView.data[adjustedIndex];
13696 setCurrentTNode(tNode, true);
13697 setupStaticAttributes(renderer, native, tNode);
13698 if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
13699 // In the i18n case, the translation may have removed this element, so only add it if it is not
13700 // detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
13701 appendChild(tView, lView, native, tNode);
13702 }
13703 // any immediate children of a component or template container must be pre-emptively
13704 // monkey-patched with the component view data so that the element can be inspected
13705 // later on using any element discovery utility methods (see `element_discovery.ts`)
13706 if (getElementDepthCount() === 0) {
13707 attachPatchData(native, lView);
13708 }
13709 increaseElementDepthCount();
13710 if (isDirectiveHost(tNode)) {
13711 createDirectivesInstances(tView, lView, tNode);
13712 executeContentQueries(tView, tNode, lView);
13713 }
13714 if (localRefsIndex !== null) {
13715 saveResolvedLocalsInData(lView, tNode);
13716 }
13717 return ɵɵelementStart;
13718}
13719/**
13720 * Mark the end of the element.
13721 * @returns This function returns itself so that it may be chained.
13722 *
13723 * @codeGenApi
13724 */
13725function ɵɵelementEnd() {
13726 let currentTNode = getCurrentTNode();
13727 ngDevMode && assertDefined(currentTNode, 'No parent node to close.');
13728 if (isCurrentTNodeParent()) {
13729 setCurrentTNodeAsNotParent();
13730 }
13731 else {
13732 ngDevMode && assertHasParent(getCurrentTNode());
13733 currentTNode = currentTNode.parent;
13734 setCurrentTNode(currentTNode, false);
13735 }
13736 const tNode = currentTNode;
13737 ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */);
13738 decreaseElementDepthCount();
13739 const tView = getTView();
13740 if (tView.firstCreatePass) {
13741 registerPostOrderHooks(tView, currentTNode);
13742 if (isContentQueryHost(currentTNode)) {
13743 tView.queries.elementEnd(currentTNode);
13744 }
13745 }
13746 if (tNode.classesWithoutHost != null && hasClassInput(tNode)) {
13747 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.classesWithoutHost, true);
13748 }
13749 if (tNode.stylesWithoutHost != null && hasStyleInput(tNode)) {
13750 setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.stylesWithoutHost, false);
13751 }
13752 return ɵɵelementEnd;
13753}
13754/**
13755 * Creates an empty element using {@link elementStart} and {@link elementEnd}
13756 *
13757 * @param index Index of the element in the data array
13758 * @param name Name of the DOM Node
13759 * @param attrsIndex Index of the element's attributes in the `consts` array.
13760 * @param localRefsIndex Index of the element's local references in the `consts` array.
13761 * @returns This function returns itself so that it may be chained.
13762 *
13763 * @codeGenApi
13764 */
13765function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
13766 ɵɵelementStart(index, name, attrsIndex, localRefsIndex);
13767 ɵɵelementEnd();
13768 return ɵɵelement;
13769}
13770
13771function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) {
13772 ngDevMode && ngDevMode.firstCreatePass++;
13773 const tViewConsts = tView.consts;
13774 const attrs = getConstant(tViewConsts, attrsIndex);
13775 const tNode = getOrCreateTNode(tView, index, 8 /* TNodeType.ElementContainer */, 'ng-container', attrs);
13776 // While ng-container doesn't necessarily support styling, we use the style context to identify
13777 // and execute directives on the ng-container.
13778 if (attrs !== null) {
13779 computeStaticStyling(tNode, attrs, true);
13780 }
13781 const localRefs = getConstant(tViewConsts, localRefsIndex);
13782 resolveDirectives(tView, lView, tNode, localRefs);
13783 if (tView.queries !== null) {
13784 tView.queries.elementStart(tView, tNode);
13785 }
13786 return tNode;
13787}
13788/**
13789 * Creates a logical container for other nodes (<ng-container>) backed by a comment node in the DOM.
13790 * The instruction must later be followed by `elementContainerEnd()` call.
13791 *
13792 * @param index Index of the element in the LView array
13793 * @param attrsIndex Index of the container attributes in the `consts` array.
13794 * @param localRefsIndex Index of the container's local references in the `consts` array.
13795 * @returns This function returns itself so that it may be chained.
13796 *
13797 * Even if this instruction accepts a set of attributes no actual attribute values are propagated to
13798 * the DOM (as a comment node can't have attributes). Attributes are here only for directive
13799 * matching purposes and setting initial inputs of directives.
13800 *
13801 * @codeGenApi
13802 */
13803function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
13804 const lView = getLView();
13805 const tView = getTView();
13806 const adjustedIndex = index + HEADER_OFFSET;
13807 ngDevMode && assertIndexInRange(lView, adjustedIndex);
13808 ngDevMode &&
13809 assertEqual(getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings');
13810 const tNode = tView.firstCreatePass ?
13811 elementContainerStartFirstCreatePass(adjustedIndex, tView, lView, attrsIndex, localRefsIndex) :
13812 tView.data[adjustedIndex];
13813 setCurrentTNode(tNode, true);
13814 ngDevMode && ngDevMode.rendererCreateComment++;
13815 const native = lView[adjustedIndex] =
13816 lView[RENDERER].createComment(ngDevMode ? 'ng-container' : '');
13817 appendChild(tView, lView, native, tNode);
13818 attachPatchData(native, lView);
13819 if (isDirectiveHost(tNode)) {
13820 createDirectivesInstances(tView, lView, tNode);
13821 executeContentQueries(tView, tNode, lView);
13822 }
13823 if (localRefsIndex != null) {
13824 saveResolvedLocalsInData(lView, tNode);
13825 }
13826 return ɵɵelementContainerStart;
13827}
13828/**
13829 * Mark the end of the <ng-container>.
13830 * @returns This function returns itself so that it may be chained.
13831 *
13832 * @codeGenApi
13833 */
13834function ɵɵelementContainerEnd() {
13835 let currentTNode = getCurrentTNode();
13836 const tView = getTView();
13837 if (isCurrentTNodeParent()) {
13838 setCurrentTNodeAsNotParent();
13839 }
13840 else {
13841 ngDevMode && assertHasParent(currentTNode);
13842 currentTNode = currentTNode.parent;
13843 setCurrentTNode(currentTNode, false);
13844 }
13845 ngDevMode && assertTNodeType(currentTNode, 8 /* TNodeType.ElementContainer */);
13846 if (tView.firstCreatePass) {
13847 registerPostOrderHooks(tView, currentTNode);
13848 if (isContentQueryHost(currentTNode)) {
13849 tView.queries.elementEnd(currentTNode);
13850 }
13851 }
13852 return ɵɵelementContainerEnd;
13853}
13854/**
13855 * Creates an empty logical container using {@link elementContainerStart}
13856 * and {@link elementContainerEnd}
13857 *
13858 * @param index Index of the element in the LView array
13859 * @param attrsIndex Index of the container attributes in the `consts` array.
13860 * @param localRefsIndex Index of the container's local references in the `consts` array.
13861 * @returns This function returns itself so that it may be chained.
13862 *
13863 * @codeGenApi
13864 */
13865function ɵɵelementContainer(index, attrsIndex, localRefsIndex) {
13866 ɵɵelementContainerStart(index, attrsIndex, localRefsIndex);
13867 ɵɵelementContainerEnd();
13868 return ɵɵelementContainer;
13869}
13870
13871/**
13872 * Returns the current OpaqueViewState instance.
13873 *
13874 * Used in conjunction with the restoreView() instruction to save a snapshot
13875 * of the current view and restore it when listeners are invoked. This allows
13876 * walking the declaration view tree in listeners to get vars from parent views.
13877 *
13878 * @codeGenApi
13879 */
13880function ɵɵgetCurrentView() {
13881 return getLView();
13882}
13883
13884/**
13885 * Determine if the argument is shaped like a Promise
13886 */
13887function isPromise(obj) {
13888 // allow any Promise/A+ compliant thenable.
13889 // It's up to the caller to ensure that obj.then conforms to the spec
13890 return !!obj && typeof obj.then === 'function';
13891}
13892/**
13893