UNPKG

1.91 MBJavaScriptView Raw
1/**
2 * @license Angular v11.2.0
3 * Copyright Google LLC All Rights Reserved.
4 * License: MIT
5 */
6
7let $deferred;
8function define(modules, callback) {
9 $deferred = {modules, callback};
10}
11module.exports = function(provided) {
12 const ts = provided['typescript'];
13 if (!ts) {
14 throw new Error('Caller does not provide typescript module');
15 }
16 const results = {};
17 const resolvedModules = $deferred.modules.map(m => {
18 if (m === 'exports') {
19 return results;
20 }
21 if (m === 'typescript' || m === 'typescript/lib/tsserverlibrary') {
22 return ts;
23 }
24 return require(m);
25 });
26 $deferred.callback(...resolvedModules);
27 return results;
28};
29
30define(['exports', 'typescript/lib/tsserverlibrary', 'typescript', 'path'], function (exports, tss, ts, path) { 'use strict';
31
32 /**
33 * @license
34 * Copyright Google LLC All Rights Reserved.
35 *
36 * Use of this source code is governed by an MIT-style license that can be
37 * found in the LICENSE file at https://angular.io/license
38 */
39 var TagContentType;
40 (function (TagContentType) {
41 TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
42 TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
43 TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
44 })(TagContentType || (TagContentType = {}));
45 function splitNsName(elementName) {
46 if (elementName[0] != ':') {
47 return [null, elementName];
48 }
49 const colonIndex = elementName.indexOf(':', 1);
50 if (colonIndex == -1) {
51 throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
52 }
53 return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
54 }
55 // `<ng-container>` tags work the same regardless the namespace
56 function isNgContainer(tagName) {
57 return splitNsName(tagName)[1] === 'ng-container';
58 }
59 // `<ng-content>` tags work the same regardless the namespace
60 function isNgContent(tagName) {
61 return splitNsName(tagName)[1] === 'ng-content';
62 }
63 // `<ng-template>` tags work the same regardless the namespace
64 function isNgTemplate(tagName) {
65 return splitNsName(tagName)[1] === 'ng-template';
66 }
67 function getNsPrefix(fullName) {
68 return fullName === null ? null : splitNsName(fullName)[0];
69 }
70 function mergeNsAndName(prefix, localName) {
71 return prefix ? `:${prefix}:${localName}` : localName;
72 }
73 // see https://www.w3.org/TR/html51/syntax.html#named-character-references
74 // see https://html.spec.whatwg.org/multipage/entities.json
75 // This list is not exhaustive to keep the compiler footprint low.
76 // The `&#123;` / `&#x1ab;` syntax should be used when the named character reference does not
77 // exist.
78 const NAMED_ENTITIES = {
79 'Aacute': '\u00C1',
80 'aacute': '\u00E1',
81 'Acirc': '\u00C2',
82 'acirc': '\u00E2',
83 'acute': '\u00B4',
84 'AElig': '\u00C6',
85 'aelig': '\u00E6',
86 'Agrave': '\u00C0',
87 'agrave': '\u00E0',
88 'alefsym': '\u2135',
89 'Alpha': '\u0391',
90 'alpha': '\u03B1',
91 'amp': '&',
92 'and': '\u2227',
93 'ang': '\u2220',
94 'apos': '\u0027',
95 'Aring': '\u00C5',
96 'aring': '\u00E5',
97 'asymp': '\u2248',
98 'Atilde': '\u00C3',
99 'atilde': '\u00E3',
100 'Auml': '\u00C4',
101 'auml': '\u00E4',
102 'bdquo': '\u201E',
103 'Beta': '\u0392',
104 'beta': '\u03B2',
105 'brvbar': '\u00A6',
106 'bull': '\u2022',
107 'cap': '\u2229',
108 'Ccedil': '\u00C7',
109 'ccedil': '\u00E7',
110 'cedil': '\u00B8',
111 'cent': '\u00A2',
112 'Chi': '\u03A7',
113 'chi': '\u03C7',
114 'circ': '\u02C6',
115 'clubs': '\u2663',
116 'cong': '\u2245',
117 'copy': '\u00A9',
118 'crarr': '\u21B5',
119 'cup': '\u222A',
120 'curren': '\u00A4',
121 'dagger': '\u2020',
122 'Dagger': '\u2021',
123 'darr': '\u2193',
124 'dArr': '\u21D3',
125 'deg': '\u00B0',
126 'Delta': '\u0394',
127 'delta': '\u03B4',
128 'diams': '\u2666',
129 'divide': '\u00F7',
130 'Eacute': '\u00C9',
131 'eacute': '\u00E9',
132 'Ecirc': '\u00CA',
133 'ecirc': '\u00EA',
134 'Egrave': '\u00C8',
135 'egrave': '\u00E8',
136 'empty': '\u2205',
137 'emsp': '\u2003',
138 'ensp': '\u2002',
139 'Epsilon': '\u0395',
140 'epsilon': '\u03B5',
141 'equiv': '\u2261',
142 'Eta': '\u0397',
143 'eta': '\u03B7',
144 'ETH': '\u00D0',
145 'eth': '\u00F0',
146 'Euml': '\u00CB',
147 'euml': '\u00EB',
148 'euro': '\u20AC',
149 'exist': '\u2203',
150 'fnof': '\u0192',
151 'forall': '\u2200',
152 'frac12': '\u00BD',
153 'frac14': '\u00BC',
154 'frac34': '\u00BE',
155 'frasl': '\u2044',
156 'Gamma': '\u0393',
157 'gamma': '\u03B3',
158 'ge': '\u2265',
159 'gt': '>',
160 'harr': '\u2194',
161 'hArr': '\u21D4',
162 'hearts': '\u2665',
163 'hellip': '\u2026',
164 'Iacute': '\u00CD',
165 'iacute': '\u00ED',
166 'Icirc': '\u00CE',
167 'icirc': '\u00EE',
168 'iexcl': '\u00A1',
169 'Igrave': '\u00CC',
170 'igrave': '\u00EC',
171 'image': '\u2111',
172 'infin': '\u221E',
173 'int': '\u222B',
174 'Iota': '\u0399',
175 'iota': '\u03B9',
176 'iquest': '\u00BF',
177 'isin': '\u2208',
178 'Iuml': '\u00CF',
179 'iuml': '\u00EF',
180 'Kappa': '\u039A',
181 'kappa': '\u03BA',
182 'Lambda': '\u039B',
183 'lambda': '\u03BB',
184 'lang': '\u27E8',
185 'laquo': '\u00AB',
186 'larr': '\u2190',
187 'lArr': '\u21D0',
188 'lceil': '\u2308',
189 'ldquo': '\u201C',
190 'le': '\u2264',
191 'lfloor': '\u230A',
192 'lowast': '\u2217',
193 'loz': '\u25CA',
194 'lrm': '\u200E',
195 'lsaquo': '\u2039',
196 'lsquo': '\u2018',
197 'lt': '<',
198 'macr': '\u00AF',
199 'mdash': '\u2014',
200 'micro': '\u00B5',
201 'middot': '\u00B7',
202 'minus': '\u2212',
203 'Mu': '\u039C',
204 'mu': '\u03BC',
205 'nabla': '\u2207',
206 'nbsp': '\u00A0',
207 'ndash': '\u2013',
208 'ne': '\u2260',
209 'ni': '\u220B',
210 'not': '\u00AC',
211 'notin': '\u2209',
212 'nsub': '\u2284',
213 'Ntilde': '\u00D1',
214 'ntilde': '\u00F1',
215 'Nu': '\u039D',
216 'nu': '\u03BD',
217 'Oacute': '\u00D3',
218 'oacute': '\u00F3',
219 'Ocirc': '\u00D4',
220 'ocirc': '\u00F4',
221 'OElig': '\u0152',
222 'oelig': '\u0153',
223 'Ograve': '\u00D2',
224 'ograve': '\u00F2',
225 'oline': '\u203E',
226 'Omega': '\u03A9',
227 'omega': '\u03C9',
228 'Omicron': '\u039F',
229 'omicron': '\u03BF',
230 'oplus': '\u2295',
231 'or': '\u2228',
232 'ordf': '\u00AA',
233 'ordm': '\u00BA',
234 'Oslash': '\u00D8',
235 'oslash': '\u00F8',
236 'Otilde': '\u00D5',
237 'otilde': '\u00F5',
238 'otimes': '\u2297',
239 'Ouml': '\u00D6',
240 'ouml': '\u00F6',
241 'para': '\u00B6',
242 'permil': '\u2030',
243 'perp': '\u22A5',
244 'Phi': '\u03A6',
245 'phi': '\u03C6',
246 'Pi': '\u03A0',
247 'pi': '\u03C0',
248 'piv': '\u03D6',
249 'plusmn': '\u00B1',
250 'pound': '\u00A3',
251 'prime': '\u2032',
252 'Prime': '\u2033',
253 'prod': '\u220F',
254 'prop': '\u221D',
255 'Psi': '\u03A8',
256 'psi': '\u03C8',
257 'quot': '\u0022',
258 'radic': '\u221A',
259 'rang': '\u27E9',
260 'raquo': '\u00BB',
261 'rarr': '\u2192',
262 'rArr': '\u21D2',
263 'rceil': '\u2309',
264 'rdquo': '\u201D',
265 'real': '\u211C',
266 'reg': '\u00AE',
267 'rfloor': '\u230B',
268 'Rho': '\u03A1',
269 'rho': '\u03C1',
270 'rlm': '\u200F',
271 'rsaquo': '\u203A',
272 'rsquo': '\u2019',
273 'sbquo': '\u201A',
274 'Scaron': '\u0160',
275 'scaron': '\u0161',
276 'sdot': '\u22C5',
277 'sect': '\u00A7',
278 'shy': '\u00AD',
279 'Sigma': '\u03A3',
280 'sigma': '\u03C3',
281 'sigmaf': '\u03C2',
282 'sim': '\u223C',
283 'spades': '\u2660',
284 'sub': '\u2282',
285 'sube': '\u2286',
286 'sum': '\u2211',
287 'sup': '\u2283',
288 'sup1': '\u00B9',
289 'sup2': '\u00B2',
290 'sup3': '\u00B3',
291 'supe': '\u2287',
292 'szlig': '\u00DF',
293 'Tau': '\u03A4',
294 'tau': '\u03C4',
295 'there4': '\u2234',
296 'Theta': '\u0398',
297 'theta': '\u03B8',
298 'thetasym': '\u03D1',
299 'thinsp': '\u2009',
300 'THORN': '\u00DE',
301 'thorn': '\u00FE',
302 'tilde': '\u02DC',
303 'times': '\u00D7',
304 'trade': '\u2122',
305 'Uacute': '\u00DA',
306 'uacute': '\u00FA',
307 'uarr': '\u2191',
308 'uArr': '\u21D1',
309 'Ucirc': '\u00DB',
310 'ucirc': '\u00FB',
311 'Ugrave': '\u00D9',
312 'ugrave': '\u00F9',
313 'uml': '\u00A8',
314 'upsih': '\u03D2',
315 'Upsilon': '\u03A5',
316 'upsilon': '\u03C5',
317 'Uuml': '\u00DC',
318 'uuml': '\u00FC',
319 'weierp': '\u2118',
320 'Xi': '\u039E',
321 'xi': '\u03BE',
322 'Yacute': '\u00DD',
323 'yacute': '\u00FD',
324 'yen': '\u00A5',
325 'yuml': '\u00FF',
326 'Yuml': '\u0178',
327 'Zeta': '\u0396',
328 'zeta': '\u03B6',
329 'zwj': '\u200D',
330 'zwnj': '\u200C',
331 };
332 // The &ngsp; pseudo-entity is denoting a space. see:
333 // https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart
334 const NGSP_UNICODE = '\uE500';
335 NAMED_ENTITIES['ngsp'] = NGSP_UNICODE;
336
337 /**
338 * @license
339 * Copyright Google LLC All Rights Reserved.
340 *
341 * Use of this source code is governed by an MIT-style license that can be
342 * found in the LICENSE file at https://angular.io/license
343 */
344 class HtmlTagDefinition {
345 constructor({ closedByChildren, implicitNamespacePrefix, contentType = TagContentType.PARSABLE_DATA, closedByParent = false, isVoid = false, ignoreFirstLf = false, preventNamespaceInheritance = false } = {}) {
346 this.closedByChildren = {};
347 this.closedByParent = false;
348 this.canSelfClose = false;
349 if (closedByChildren && closedByChildren.length > 0) {
350 closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
351 }
352 this.isVoid = isVoid;
353 this.closedByParent = closedByParent || isVoid;
354 this.implicitNamespacePrefix = implicitNamespacePrefix || null;
355 this.contentType = contentType;
356 this.ignoreFirstLf = ignoreFirstLf;
357 this.preventNamespaceInheritance = preventNamespaceInheritance;
358 }
359 isClosedByChild(name) {
360 return this.isVoid || name.toLowerCase() in this.closedByChildren;
361 }
362 getContentType(prefix) {
363 if (typeof this.contentType === 'object') {
364 const overrideType = prefix == null ? undefined : this.contentType[prefix];
365 return overrideType !== null && overrideType !== void 0 ? overrideType : this.contentType.default;
366 }
367 return this.contentType;
368 }
369 }
370 let _DEFAULT_TAG_DEFINITION;
371 // see https://www.w3.org/TR/html51/syntax.html#optional-tags
372 // This implementation does not fully conform to the HTML5 spec.
373 let TAG_DEFINITIONS;
374 function getHtmlTagDefinition(tagName) {
375 var _a, _b;
376 if (!TAG_DEFINITIONS) {
377 _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
378 TAG_DEFINITIONS = {
379 'base': new HtmlTagDefinition({ isVoid: true }),
380 'meta': new HtmlTagDefinition({ isVoid: true }),
381 'area': new HtmlTagDefinition({ isVoid: true }),
382 'embed': new HtmlTagDefinition({ isVoid: true }),
383 'link': new HtmlTagDefinition({ isVoid: true }),
384 'img': new HtmlTagDefinition({ isVoid: true }),
385 'input': new HtmlTagDefinition({ isVoid: true }),
386 'param': new HtmlTagDefinition({ isVoid: true }),
387 'hr': new HtmlTagDefinition({ isVoid: true }),
388 'br': new HtmlTagDefinition({ isVoid: true }),
389 'source': new HtmlTagDefinition({ isVoid: true }),
390 'track': new HtmlTagDefinition({ isVoid: true }),
391 'wbr': new HtmlTagDefinition({ isVoid: true }),
392 'p': new HtmlTagDefinition({
393 closedByChildren: [
394 'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset',
395 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',
396 'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol',
397 'p', 'pre', 'section', 'table', 'ul'
398 ],
399 closedByParent: true
400 }),
401 'thead': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'] }),
402 'tbody': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'], closedByParent: true }),
403 'tfoot': new HtmlTagDefinition({ closedByChildren: ['tbody'], closedByParent: true }),
404 'tr': new HtmlTagDefinition({ closedByChildren: ['tr'], closedByParent: true }),
405 'td': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
406 'th': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
407 'col': new HtmlTagDefinition({ isVoid: true }),
408 'svg': new HtmlTagDefinition({ implicitNamespacePrefix: 'svg' }),
409 'foreignObject': new HtmlTagDefinition({
410 // Usually the implicit namespace here would be redundant since it will be inherited from
411 // the parent `svg`, but we have to do it for `foreignObject`, because the way the parser
412 // works is that the parent node of an end tag is its own start tag which means that
413 // the `preventNamespaceInheritance` on `foreignObject` would have it default to the
414 // implicit namespace which is `html`, unless specified otherwise.
415 implicitNamespacePrefix: 'svg',
416 // We want to prevent children of foreignObject from inheriting its namespace, because
417 // the point of the element is to allow nodes from other namespaces to be inserted.
418 preventNamespaceInheritance: true,
419 }),
420 'math': new HtmlTagDefinition({ implicitNamespacePrefix: 'math' }),
421 'li': new HtmlTagDefinition({ closedByChildren: ['li'], closedByParent: true }),
422 'dt': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'] }),
423 'dd': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'], closedByParent: true }),
424 'rb': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
425 'rt': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
426 'rtc': new HtmlTagDefinition({ closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true }),
427 'rp': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
428 'optgroup': new HtmlTagDefinition({ closedByChildren: ['optgroup'], closedByParent: true }),
429 'option': new HtmlTagDefinition({ closedByChildren: ['option', 'optgroup'], closedByParent: true }),
430 'pre': new HtmlTagDefinition({ ignoreFirstLf: true }),
431 'listing': new HtmlTagDefinition({ ignoreFirstLf: true }),
432 'style': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }),
433 'script': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }),
434 'title': new HtmlTagDefinition({
435 // The browser supports two separate `title` tags which have to use
436 // a different content type: `HTMLTitleElement` and `SVGTitleElement`
437 contentType: { default: TagContentType.ESCAPABLE_RAW_TEXT, svg: TagContentType.PARSABLE_DATA }
438 }),
439 'textarea': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }),
440 };
441 }
442 // We have to make both a case-sensitive and a case-insesitive lookup, because
443 // HTML tag names are case insensitive, whereas some SVG tags are case sensitive.
444 return (_b = (_a = TAG_DEFINITIONS[tagName]) !== null && _a !== void 0 ? _a : TAG_DEFINITIONS[tagName.toLowerCase()]) !== null && _b !== void 0 ? _b : _DEFAULT_TAG_DEFINITION;
445 }
446
447 /**
448 * @license
449 * Copyright Google LLC All Rights Reserved.
450 *
451 * Use of this source code is governed by an MIT-style license that can be
452 * found in the LICENSE file at https://angular.io/license
453 */
454 const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + // 1: ":not("
455 '(([\\.\\#]?)[-\\w]+)|' + // 2: "tag"; 3: "."/"#";
456 // "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range
457 // 4: attribute; 5: attribute_string; 6: attribute_value
458 '(?:\\[([-.\\w*]+)(?:=([\"\']?)([^\\]\"\']*)\\5)?\\])|' + // "[name]", "[name=value]",
459 // "[name="value"]",
460 // "[name='value']"
461 '(\\))|' + // 7: ")"
462 '(\\s*,\\s*)', // 8: ","
463 'g');
464 /**
465 * A css selector contains an element name,
466 * css classes and attribute/value pairs with the purpose
467 * of selecting subsets out of them.
468 */
469 class CssSelector {
470 constructor() {
471 this.element = null;
472 this.classNames = [];
473 /**
474 * The selectors are encoded in pairs where:
475 * - even locations are attribute names
476 * - odd locations are attribute values.
477 *
478 * Example:
479 * Selector: `[key1=value1][key2]` would parse to:
480 * ```
481 * ['key1', 'value1', 'key2', '']
482 * ```
483 */
484 this.attrs = [];
485 this.notSelectors = [];
486 }
487 static parse(selector) {
488 const results = [];
489 const _addResult = (res, cssSel) => {
490 if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
491 cssSel.attrs.length == 0) {
492 cssSel.element = '*';
493 }
494 res.push(cssSel);
495 };
496 let cssSelector = new CssSelector();
497 let match;
498 let current = cssSelector;
499 let inNot = false;
500 _SELECTOR_REGEXP.lastIndex = 0;
501 while (match = _SELECTOR_REGEXP.exec(selector)) {
502 if (match[1 /* NOT */]) {
503 if (inNot) {
504 throw new Error('Nesting :not in a selector is not allowed');
505 }
506 inNot = true;
507 current = new CssSelector();
508 cssSelector.notSelectors.push(current);
509 }
510 const tag = match[2 /* TAG */];
511 if (tag) {
512 const prefix = match[3 /* PREFIX */];
513 if (prefix === '#') {
514 // #hash
515 current.addAttribute('id', tag.substr(1));
516 }
517 else if (prefix === '.') {
518 // Class
519 current.addClassName(tag.substr(1));
520 }
521 else {
522 // Element
523 current.setElement(tag);
524 }
525 }
526 const attribute = match[4 /* ATTRIBUTE */];
527 if (attribute) {
528 current.addAttribute(attribute, match[6 /* ATTRIBUTE_VALUE */]);
529 }
530 if (match[7 /* NOT_END */]) {
531 inNot = false;
532 current = cssSelector;
533 }
534 if (match[8 /* SEPARATOR */]) {
535 if (inNot) {
536 throw new Error('Multiple selectors in :not are not supported');
537 }
538 _addResult(results, cssSelector);
539 cssSelector = current = new CssSelector();
540 }
541 }
542 _addResult(results, cssSelector);
543 return results;
544 }
545 isElementSelector() {
546 return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 &&
547 this.notSelectors.length === 0;
548 }
549 hasElementSelector() {
550 return !!this.element;
551 }
552 setElement(element = null) {
553 this.element = element;
554 }
555 /** Gets a template string for an element that matches the selector. */
556 getMatchingElementTemplate() {
557 const tagName = this.element || 'div';
558 const classAttr = this.classNames.length > 0 ? ` class="${this.classNames.join(' ')}"` : '';
559 let attrs = '';
560 for (let i = 0; i < this.attrs.length; i += 2) {
561 const attrName = this.attrs[i];
562 const attrValue = this.attrs[i + 1] !== '' ? `="${this.attrs[i + 1]}"` : '';
563 attrs += ` ${attrName}${attrValue}`;
564 }
565 return getHtmlTagDefinition(tagName).isVoid ? `<${tagName}${classAttr}${attrs}/>` :
566 `<${tagName}${classAttr}${attrs}></${tagName}>`;
567 }
568 getAttrs() {
569 const result = [];
570 if (this.classNames.length > 0) {
571 result.push('class', this.classNames.join(' '));
572 }
573 return result.concat(this.attrs);
574 }
575 addAttribute(name, value = '') {
576 this.attrs.push(name, value && value.toLowerCase() || '');
577 }
578 addClassName(name) {
579 this.classNames.push(name.toLowerCase());
580 }
581 toString() {
582 let res = this.element || '';
583 if (this.classNames) {
584 this.classNames.forEach(klass => res += `.${klass}`);
585 }
586 if (this.attrs) {
587 for (let i = 0; i < this.attrs.length; i += 2) {
588 const name = this.attrs[i];
589 const value = this.attrs[i + 1];
590 res += `[${name}${value ? '=' + value : ''}]`;
591 }
592 }
593 this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
594 return res;
595 }
596 }
597 /**
598 * Reads a list of CssSelectors and allows to calculate which ones
599 * are contained in a given CssSelector.
600 */
601 class SelectorMatcher {
602 constructor() {
603 this._elementMap = new Map();
604 this._elementPartialMap = new Map();
605 this._classMap = new Map();
606 this._classPartialMap = new Map();
607 this._attrValueMap = new Map();
608 this._attrValuePartialMap = new Map();
609 this._listContexts = [];
610 }
611 static createNotMatcher(notSelectors) {
612 const notMatcher = new SelectorMatcher();
613 notMatcher.addSelectables(notSelectors, null);
614 return notMatcher;
615 }
616 addSelectables(cssSelectors, callbackCtxt) {
617 let listContext = null;
618 if (cssSelectors.length > 1) {
619 listContext = new SelectorListContext(cssSelectors);
620 this._listContexts.push(listContext);
621 }
622 for (let i = 0; i < cssSelectors.length; i++) {
623 this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
624 }
625 }
626 /**
627 * Add an object that can be found later on by calling `match`.
628 * @param cssSelector A css selector
629 * @param callbackCtxt An opaque object that will be given to the callback of the `match` function
630 */
631 _addSelectable(cssSelector, callbackCtxt, listContext) {
632 let matcher = this;
633 const element = cssSelector.element;
634 const classNames = cssSelector.classNames;
635 const attrs = cssSelector.attrs;
636 const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
637 if (element) {
638 const isTerminal = attrs.length === 0 && classNames.length === 0;
639 if (isTerminal) {
640 this._addTerminal(matcher._elementMap, element, selectable);
641 }
642 else {
643 matcher = this._addPartial(matcher._elementPartialMap, element);
644 }
645 }
646 if (classNames) {
647 for (let i = 0; i < classNames.length; i++) {
648 const isTerminal = attrs.length === 0 && i === classNames.length - 1;
649 const className = classNames[i];
650 if (isTerminal) {
651 this._addTerminal(matcher._classMap, className, selectable);
652 }
653 else {
654 matcher = this._addPartial(matcher._classPartialMap, className);
655 }
656 }
657 }
658 if (attrs) {
659 for (let i = 0; i < attrs.length; i += 2) {
660 const isTerminal = i === attrs.length - 2;
661 const name = attrs[i];
662 const value = attrs[i + 1];
663 if (isTerminal) {
664 const terminalMap = matcher._attrValueMap;
665 let terminalValuesMap = terminalMap.get(name);
666 if (!terminalValuesMap) {
667 terminalValuesMap = new Map();
668 terminalMap.set(name, terminalValuesMap);
669 }
670 this._addTerminal(terminalValuesMap, value, selectable);
671 }
672 else {
673 const partialMap = matcher._attrValuePartialMap;
674 let partialValuesMap = partialMap.get(name);
675 if (!partialValuesMap) {
676 partialValuesMap = new Map();
677 partialMap.set(name, partialValuesMap);
678 }
679 matcher = this._addPartial(partialValuesMap, value);
680 }
681 }
682 }
683 }
684 _addTerminal(map, name, selectable) {
685 let terminalList = map.get(name);
686 if (!terminalList) {
687 terminalList = [];
688 map.set(name, terminalList);
689 }
690 terminalList.push(selectable);
691 }
692 _addPartial(map, name) {
693 let matcher = map.get(name);
694 if (!matcher) {
695 matcher = new SelectorMatcher();
696 map.set(name, matcher);
697 }
698 return matcher;
699 }
700 /**
701 * Find the objects that have been added via `addSelectable`
702 * whose css selector is contained in the given css selector.
703 * @param cssSelector A css selector
704 * @param matchedCallback This callback will be called with the object handed into `addSelectable`
705 * @return boolean true if a match was found
706 */
707 match(cssSelector, matchedCallback) {
708 let result = false;
709 const element = cssSelector.element;
710 const classNames = cssSelector.classNames;
711 const attrs = cssSelector.attrs;
712 for (let i = 0; i < this._listContexts.length; i++) {
713 this._listContexts[i].alreadyMatched = false;
714 }
715 result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result;
716 result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
717 result;
718 if (classNames) {
719 for (let i = 0; i < classNames.length; i++) {
720 const className = classNames[i];
721 result =
722 this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
723 result =
724 this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) ||
725 result;
726 }
727 }
728 if (attrs) {
729 for (let i = 0; i < attrs.length; i += 2) {
730 const name = attrs[i];
731 const value = attrs[i + 1];
732 const terminalValuesMap = this._attrValueMap.get(name);
733 if (value) {
734 result =
735 this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
736 }
737 result =
738 this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
739 const partialValuesMap = this._attrValuePartialMap.get(name);
740 if (value) {
741 result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
742 }
743 result =
744 this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
745 }
746 }
747 return result;
748 }
749 /** @internal */
750 _matchTerminal(map, name, cssSelector, matchedCallback) {
751 if (!map || typeof name !== 'string') {
752 return false;
753 }
754 let selectables = map.get(name) || [];
755 const starSelectables = map.get('*');
756 if (starSelectables) {
757 selectables = selectables.concat(starSelectables);
758 }
759 if (selectables.length === 0) {
760 return false;
761 }
762 let selectable;
763 let result = false;
764 for (let i = 0; i < selectables.length; i++) {
765 selectable = selectables[i];
766 result = selectable.finalize(cssSelector, matchedCallback) || result;
767 }
768 return result;
769 }
770 /** @internal */
771 _matchPartial(map, name, cssSelector, matchedCallback) {
772 if (!map || typeof name !== 'string') {
773 return false;
774 }
775 const nestedSelector = map.get(name);
776 if (!nestedSelector) {
777 return false;
778 }
779 // TODO(perf): get rid of recursion and measure again
780 // TODO(perf): don't pass the whole selector into the recursion,
781 // but only the not processed parts
782 return nestedSelector.match(cssSelector, matchedCallback);
783 }
784 }
785 class SelectorListContext {
786 constructor(selectors) {
787 this.selectors = selectors;
788 this.alreadyMatched = false;
789 }
790 }
791 // Store context to pass back selector and context when a selector is matched
792 class SelectorContext {
793 constructor(selector, cbContext, listContext) {
794 this.selector = selector;
795 this.cbContext = cbContext;
796 this.listContext = listContext;
797 this.notSelectors = selector.notSelectors;
798 }
799 finalize(cssSelector, callback) {
800 let result = true;
801 if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
802 const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
803 result = !notMatcher.match(cssSelector, null);
804 }
805 if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
806 if (this.listContext) {
807 this.listContext.alreadyMatched = true;
808 }
809 callback(this.selector, this.cbContext);
810 }
811 return result;
812 }
813 }
814
815 /**
816 * @license
817 * Copyright Google LLC All Rights Reserved.
818 *
819 * Use of this source code is governed by an MIT-style license that can be
820 * found in the LICENSE file at https://angular.io/license
821 */
822 const createInject = makeMetadataFactory('Inject', (token) => ({ token }));
823 const createInjectionToken = makeMetadataFactory('InjectionToken', (desc) => ({ _desc: desc, ɵprov: undefined }));
824 const createAttribute = makeMetadataFactory('Attribute', (attributeName) => ({ attributeName }));
825 // Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
826 // explicitly set. This value will be changed to `true` in v12.
827 // TODO(misko): switch the default in v12 to `true`. See: packages/core/src/metadata/di.ts
828 const emitDistinctChangesOnlyDefaultValue = false;
829 const createContentChildren = makeMetadataFactory('ContentChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)));
830 const createContentChild = makeMetadataFactory('ContentChild', (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data)));
831 const createViewChildren = makeMetadataFactory('ViewChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)));
832 const createViewChild = makeMetadataFactory('ViewChild', (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data)));
833 const createDirective = makeMetadataFactory('Directive', (dir = {}) => dir);
834 var ViewEncapsulation;
835 (function (ViewEncapsulation) {
836 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
837 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
838 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
839 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
840 })(ViewEncapsulation || (ViewEncapsulation = {}));
841 var ChangeDetectionStrategy;
842 (function (ChangeDetectionStrategy) {
843 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
844 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
845 })(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
846 const createComponent = makeMetadataFactory('Component', (c = {}) => (Object.assign({ changeDetection: ChangeDetectionStrategy.Default }, c)));
847 const createPipe = makeMetadataFactory('Pipe', (p) => (Object.assign({ pure: true }, p)));
848 const createInput = makeMetadataFactory('Input', (bindingPropertyName) => ({ bindingPropertyName }));
849 const createOutput = makeMetadataFactory('Output', (bindingPropertyName) => ({ bindingPropertyName }));
850 const createHostBinding = makeMetadataFactory('HostBinding', (hostPropertyName) => ({ hostPropertyName }));
851 const createHostListener = makeMetadataFactory('HostListener', (eventName, args) => ({ eventName, args }));
852 const createNgModule = makeMetadataFactory('NgModule', (ngModule) => ngModule);
853 const createInjectable = makeMetadataFactory('Injectable', (injectable = {}) => injectable);
854 const CUSTOM_ELEMENTS_SCHEMA = {
855 name: 'custom-elements'
856 };
857 const NO_ERRORS_SCHEMA = {
858 name: 'no-errors-schema'
859 };
860 const createOptional = makeMetadataFactory('Optional');
861 const createSelf = makeMetadataFactory('Self');
862 const createSkipSelf = makeMetadataFactory('SkipSelf');
863 const createHost = makeMetadataFactory('Host');
864 const Type = Function;
865 var SecurityContext;
866 (function (SecurityContext) {
867 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
868 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
869 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
870 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
871 SecurityContext[SecurityContext["URL"] = 4] = "URL";
872 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
873 })(SecurityContext || (SecurityContext = {}));
874 var MissingTranslationStrategy;
875 (function (MissingTranslationStrategy) {
876 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
877 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
878 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
879 })(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
880 function makeMetadataFactory(name, props) {
881 // This must be declared as a function, not a fat arrow, so that ES2015 devmode produces code
882 // that works with the static_reflector.ts in the ViewEngine compiler.
883 // In particular, `_registerDecoratorOrConstructor` assumes that the value returned here can be
884 // new'ed.
885 function factory(...args) {
886 const values = props ? props(...args) : {};
887 return Object.assign({ ngMetadataName: name }, values);
888 }
889 factory.isTypeOf = (obj) => obj && obj.ngMetadataName === name;
890 factory.ngMetadataName = name;
891 return factory;
892 }
893 function parserSelectorToSimpleSelector(selector) {
894 const classes = selector.classNames && selector.classNames.length ?
895 [8 /* CLASS */, ...selector.classNames] :
896 [];
897 const elementName = selector.element && selector.element !== '*' ? selector.element : '';
898 return [elementName, ...selector.attrs, ...classes];
899 }
900 function parserSelectorToNegativeSelector(selector) {
901 const classes = selector.classNames && selector.classNames.length ?
902 [8 /* CLASS */, ...selector.classNames] :
903 [];
904 if (selector.element) {
905 return [
906 1 /* NOT */ | 4 /* ELEMENT */, selector.element, ...selector.attrs, ...classes
907 ];
908 }
909 else if (selector.attrs.length) {
910 return [1 /* NOT */ | 2 /* ATTRIBUTE */, ...selector.attrs, ...classes];
911 }
912 else {
913 return selector.classNames && selector.classNames.length ?
914 [1 /* NOT */ | 8 /* CLASS */, ...selector.classNames] :
915 [];
916 }
917 }
918 function parserSelectorToR3Selector(selector) {
919 const positive = parserSelectorToSimpleSelector(selector);
920 const negative = selector.notSelectors && selector.notSelectors.length ?
921 selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) :
922 [];
923 return positive.concat(...negative);
924 }
925 function parseSelectorToR3Selector(selector) {
926 return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
927 }
928
929 /**
930 * @license
931 * Copyright Google LLC All Rights Reserved.
932 *
933 * Use of this source code is governed by an MIT-style license that can be
934 * found in the LICENSE file at https://angular.io/license
935 */
936 //// Types
937 var TypeModifier;
938 (function (TypeModifier) {
939 TypeModifier[TypeModifier["Const"] = 0] = "Const";
940 })(TypeModifier || (TypeModifier = {}));
941 class Type$1 {
942 constructor(modifiers = []) {
943 this.modifiers = modifiers;
944 }
945 hasModifier(modifier) {
946 return this.modifiers.indexOf(modifier) !== -1;
947 }
948 }
949 var BuiltinTypeName;
950 (function (BuiltinTypeName) {
951 BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic";
952 BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool";
953 BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String";
954 BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int";
955 BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number";
956 BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function";
957 BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred";
958 BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None";
959 })(BuiltinTypeName || (BuiltinTypeName = {}));
960 class BuiltinType extends Type$1 {
961 constructor(name, modifiers) {
962 super(modifiers);
963 this.name = name;
964 }
965 visitType(visitor, context) {
966 return visitor.visitBuiltinType(this, context);
967 }
968 }
969 class ExpressionType extends Type$1 {
970 constructor(value, modifiers, typeParams = null) {
971 super(modifiers);
972 this.value = value;
973 this.typeParams = typeParams;
974 }
975 visitType(visitor, context) {
976 return visitor.visitExpressionType(this, context);
977 }
978 }
979 const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
980 const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred);
981 const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool);
982 const INT_TYPE = new BuiltinType(BuiltinTypeName.Int);
983 const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number);
984 const STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
985 const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
986 const NONE_TYPE = new BuiltinType(BuiltinTypeName.None);
987 ///// Expressions
988 var UnaryOperator;
989 (function (UnaryOperator) {
990 UnaryOperator[UnaryOperator["Minus"] = 0] = "Minus";
991 UnaryOperator[UnaryOperator["Plus"] = 1] = "Plus";
992 })(UnaryOperator || (UnaryOperator = {}));
993 var BinaryOperator;
994 (function (BinaryOperator) {
995 BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals";
996 BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals";
997 BinaryOperator[BinaryOperator["Identical"] = 2] = "Identical";
998 BinaryOperator[BinaryOperator["NotIdentical"] = 3] = "NotIdentical";
999 BinaryOperator[BinaryOperator["Minus"] = 4] = "Minus";
1000 BinaryOperator[BinaryOperator["Plus"] = 5] = "Plus";
1001 BinaryOperator[BinaryOperator["Divide"] = 6] = "Divide";
1002 BinaryOperator[BinaryOperator["Multiply"] = 7] = "Multiply";
1003 BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo";
1004 BinaryOperator[BinaryOperator["And"] = 9] = "And";
1005 BinaryOperator[BinaryOperator["Or"] = 10] = "Or";
1006 BinaryOperator[BinaryOperator["BitwiseAnd"] = 11] = "BitwiseAnd";
1007 BinaryOperator[BinaryOperator["Lower"] = 12] = "Lower";
1008 BinaryOperator[BinaryOperator["LowerEquals"] = 13] = "LowerEquals";
1009 BinaryOperator[BinaryOperator["Bigger"] = 14] = "Bigger";
1010 BinaryOperator[BinaryOperator["BiggerEquals"] = 15] = "BiggerEquals";
1011 })(BinaryOperator || (BinaryOperator = {}));
1012 function nullSafeIsEquivalent(base, other) {
1013 if (base == null || other == null) {
1014 return base == other;
1015 }
1016 return base.isEquivalent(other);
1017 }
1018 function areAllEquivalentPredicate(base, other, equivalentPredicate) {
1019 const len = base.length;
1020 if (len !== other.length) {
1021 return false;
1022 }
1023 for (let i = 0; i < len; i++) {
1024 if (!equivalentPredicate(base[i], other[i])) {
1025 return false;
1026 }
1027 }
1028 return true;
1029 }
1030 function areAllEquivalent(base, other) {
1031 return areAllEquivalentPredicate(base, other, (baseElement, otherElement) => baseElement.isEquivalent(otherElement));
1032 }
1033 class Expression {
1034 constructor(type, sourceSpan) {
1035 this.type = type || null;
1036 this.sourceSpan = sourceSpan || null;
1037 }
1038 prop(name, sourceSpan) {
1039 return new ReadPropExpr(this, name, null, sourceSpan);
1040 }
1041 key(index, type, sourceSpan) {
1042 return new ReadKeyExpr(this, index, type, sourceSpan);
1043 }
1044 callMethod(name, params, sourceSpan) {
1045 return new InvokeMethodExpr(this, name, params, null, sourceSpan);
1046 }
1047 callFn(params, sourceSpan, pure) {
1048 return new InvokeFunctionExpr(this, params, null, sourceSpan, pure);
1049 }
1050 instantiate(params, type, sourceSpan) {
1051 return new InstantiateExpr(this, params, type, sourceSpan);
1052 }
1053 conditional(trueCase, falseCase = null, sourceSpan) {
1054 return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan);
1055 }
1056 equals(rhs, sourceSpan) {
1057 return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan);
1058 }
1059 notEquals(rhs, sourceSpan) {
1060 return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan);
1061 }
1062 identical(rhs, sourceSpan) {
1063 return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan);
1064 }
1065 notIdentical(rhs, sourceSpan) {
1066 return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan);
1067 }
1068 minus(rhs, sourceSpan) {
1069 return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan);
1070 }
1071 plus(rhs, sourceSpan) {
1072 return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan);
1073 }
1074 divide(rhs, sourceSpan) {
1075 return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan);
1076 }
1077 multiply(rhs, sourceSpan) {
1078 return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan);
1079 }
1080 modulo(rhs, sourceSpan) {
1081 return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan);
1082 }
1083 and(rhs, sourceSpan) {
1084 return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan);
1085 }
1086 bitwiseAnd(rhs, sourceSpan, parens = true) {
1087 return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens);
1088 }
1089 or(rhs, sourceSpan) {
1090 return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan);
1091 }
1092 lower(rhs, sourceSpan) {
1093 return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan);
1094 }
1095 lowerEquals(rhs, sourceSpan) {
1096 return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan);
1097 }
1098 bigger(rhs, sourceSpan) {
1099 return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan);
1100 }
1101 biggerEquals(rhs, sourceSpan) {
1102 return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan);
1103 }
1104 isBlank(sourceSpan) {
1105 // Note: We use equals by purpose here to compare to null and undefined in JS.
1106 // We use the typed null to allow strictNullChecks to narrow types.
1107 return this.equals(TYPED_NULL_EXPR, sourceSpan);
1108 }
1109 cast(type, sourceSpan) {
1110 return new CastExpr(this, type, sourceSpan);
1111 }
1112 toStmt() {
1113 return new ExpressionStatement(this, null);
1114 }
1115 }
1116 var BuiltinVar;
1117 (function (BuiltinVar) {
1118 BuiltinVar[BuiltinVar["This"] = 0] = "This";
1119 BuiltinVar[BuiltinVar["Super"] = 1] = "Super";
1120 BuiltinVar[BuiltinVar["CatchError"] = 2] = "CatchError";
1121 BuiltinVar[BuiltinVar["CatchStack"] = 3] = "CatchStack";
1122 })(BuiltinVar || (BuiltinVar = {}));
1123 class ReadVarExpr extends Expression {
1124 constructor(name, type, sourceSpan) {
1125 super(type, sourceSpan);
1126 if (typeof name === 'string') {
1127 this.name = name;
1128 this.builtin = null;
1129 }
1130 else {
1131 this.name = null;
1132 this.builtin = name;
1133 }
1134 }
1135 isEquivalent(e) {
1136 return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin;
1137 }
1138 isConstant() {
1139 return false;
1140 }
1141 visitExpression(visitor, context) {
1142 return visitor.visitReadVarExpr(this, context);
1143 }
1144 set(value) {
1145 if (!this.name) {
1146 throw new Error(`Built in variable ${this.builtin} can not be assigned to.`);
1147 }
1148 return new WriteVarExpr(this.name, value, null, this.sourceSpan);
1149 }
1150 }
1151 class TypeofExpr extends Expression {
1152 constructor(expr, type, sourceSpan) {
1153 super(type, sourceSpan);
1154 this.expr = expr;
1155 }
1156 visitExpression(visitor, context) {
1157 return visitor.visitTypeofExpr(this, context);
1158 }
1159 isEquivalent(e) {
1160 return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
1161 }
1162 isConstant() {
1163 return this.expr.isConstant();
1164 }
1165 }
1166 class WrappedNodeExpr extends Expression {
1167 constructor(node, type, sourceSpan) {
1168 super(type, sourceSpan);
1169 this.node = node;
1170 }
1171 isEquivalent(e) {
1172 return e instanceof WrappedNodeExpr && this.node === e.node;
1173 }
1174 isConstant() {
1175 return false;
1176 }
1177 visitExpression(visitor, context) {
1178 return visitor.visitWrappedNodeExpr(this, context);
1179 }
1180 }
1181 class WriteVarExpr extends Expression {
1182 constructor(name, value, type, sourceSpan) {
1183 super(type || value.type, sourceSpan);
1184 this.name = name;
1185 this.value = value;
1186 }
1187 isEquivalent(e) {
1188 return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value);
1189 }
1190 isConstant() {
1191 return false;
1192 }
1193 visitExpression(visitor, context) {
1194 return visitor.visitWriteVarExpr(this, context);
1195 }
1196 toDeclStmt(type, modifiers) {
1197 return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
1198 }
1199 toConstDecl() {
1200 return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]);
1201 }
1202 }
1203 class WriteKeyExpr extends Expression {
1204 constructor(receiver, index, value, type, sourceSpan) {
1205 super(type || value.type, sourceSpan);
1206 this.receiver = receiver;
1207 this.index = index;
1208 this.value = value;
1209 }
1210 isEquivalent(e) {
1211 return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) &&
1212 this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value);
1213 }
1214 isConstant() {
1215 return false;
1216 }
1217 visitExpression(visitor, context) {
1218 return visitor.visitWriteKeyExpr(this, context);
1219 }
1220 }
1221 class WritePropExpr extends Expression {
1222 constructor(receiver, name, value, type, sourceSpan) {
1223 super(type || value.type, sourceSpan);
1224 this.receiver = receiver;
1225 this.name = name;
1226 this.value = value;
1227 }
1228 isEquivalent(e) {
1229 return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) &&
1230 this.name === e.name && this.value.isEquivalent(e.value);
1231 }
1232 isConstant() {
1233 return false;
1234 }
1235 visitExpression(visitor, context) {
1236 return visitor.visitWritePropExpr(this, context);
1237 }
1238 }
1239 var BuiltinMethod;
1240 (function (BuiltinMethod) {
1241 BuiltinMethod[BuiltinMethod["ConcatArray"] = 0] = "ConcatArray";
1242 BuiltinMethod[BuiltinMethod["SubscribeObservable"] = 1] = "SubscribeObservable";
1243 BuiltinMethod[BuiltinMethod["Bind"] = 2] = "Bind";
1244 })(BuiltinMethod || (BuiltinMethod = {}));
1245 class InvokeMethodExpr extends Expression {
1246 constructor(receiver, method, args, type, sourceSpan) {
1247 super(type, sourceSpan);
1248 this.receiver = receiver;
1249 this.args = args;
1250 if (typeof method === 'string') {
1251 this.name = method;
1252 this.builtin = null;
1253 }
1254 else {
1255 this.name = null;
1256 this.builtin = method;
1257 }
1258 }
1259 isEquivalent(e) {
1260 return e instanceof InvokeMethodExpr && this.receiver.isEquivalent(e.receiver) &&
1261 this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args);
1262 }
1263 isConstant() {
1264 return false;
1265 }
1266 visitExpression(visitor, context) {
1267 return visitor.visitInvokeMethodExpr(this, context);
1268 }
1269 }
1270 class InvokeFunctionExpr extends Expression {
1271 constructor(fn, args, type, sourceSpan, pure = false) {
1272 super(type, sourceSpan);
1273 this.fn = fn;
1274 this.args = args;
1275 this.pure = pure;
1276 }
1277 isEquivalent(e) {
1278 return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) &&
1279 areAllEquivalent(this.args, e.args) && this.pure === e.pure;
1280 }
1281 isConstant() {
1282 return false;
1283 }
1284 visitExpression(visitor, context) {
1285 return visitor.visitInvokeFunctionExpr(this, context);
1286 }
1287 }
1288 class TaggedTemplateExpr extends Expression {
1289 constructor(tag, template, type, sourceSpan) {
1290 super(type, sourceSpan);
1291 this.tag = tag;
1292 this.template = template;
1293 }
1294 isEquivalent(e) {
1295 return e instanceof TaggedTemplateExpr && this.tag.isEquivalent(e.tag) &&
1296 areAllEquivalentPredicate(this.template.elements, e.template.elements, (a, b) => a.text === b.text) &&
1297 areAllEquivalent(this.template.expressions, e.template.expressions);
1298 }
1299 isConstant() {
1300 return false;
1301 }
1302 visitExpression(visitor, context) {
1303 return visitor.visitTaggedTemplateExpr(this, context);
1304 }
1305 }
1306 class InstantiateExpr extends Expression {
1307 constructor(classExpr, args, type, sourceSpan) {
1308 super(type, sourceSpan);
1309 this.classExpr = classExpr;
1310 this.args = args;
1311 }
1312 isEquivalent(e) {
1313 return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) &&
1314 areAllEquivalent(this.args, e.args);
1315 }
1316 isConstant() {
1317 return false;
1318 }
1319 visitExpression(visitor, context) {
1320 return visitor.visitInstantiateExpr(this, context);
1321 }
1322 }
1323 class LiteralExpr extends Expression {
1324 constructor(value, type, sourceSpan) {
1325 super(type, sourceSpan);
1326 this.value = value;
1327 }
1328 isEquivalent(e) {
1329 return e instanceof LiteralExpr && this.value === e.value;
1330 }
1331 isConstant() {
1332 return true;
1333 }
1334 visitExpression(visitor, context) {
1335 return visitor.visitLiteralExpr(this, context);
1336 }
1337 }
1338 class TemplateLiteral {
1339 constructor(elements, expressions) {
1340 this.elements = elements;
1341 this.expressions = expressions;
1342 }
1343 }
1344 class TemplateLiteralElement {
1345 constructor(text, sourceSpan, rawText) {
1346 var _a;
1347 this.text = text;
1348 this.sourceSpan = sourceSpan;
1349 // If `rawText` is not provided, try to extract the raw string from its
1350 // associated `sourceSpan`. If that is also not available, "fake" the raw
1351 // string instead by escaping the following control sequences:
1352 // - "\" would otherwise indicate that the next character is a control character.
1353 // - "`" and "${" are template string control sequences that would otherwise prematurely
1354 // indicate the end of the template literal element.
1355 this.rawText = (_a = rawText !== null && rawText !== void 0 ? rawText : sourceSpan === null || sourceSpan === void 0 ? void 0 : sourceSpan.toString()) !== null && _a !== void 0 ? _a : escapeForTemplateLiteral(escapeSlashes(text));
1356 }
1357 }
1358 class MessagePiece {
1359 constructor(text, sourceSpan) {
1360 this.text = text;
1361 this.sourceSpan = sourceSpan;
1362 }
1363 }
1364 class LiteralPiece extends MessagePiece {
1365 }
1366 class PlaceholderPiece extends MessagePiece {
1367 }
1368 class LocalizedString extends Expression {
1369 constructor(metaBlock, messageParts, placeHolderNames, expressions, sourceSpan) {
1370 super(STRING_TYPE, sourceSpan);
1371 this.metaBlock = metaBlock;
1372 this.messageParts = messageParts;
1373 this.placeHolderNames = placeHolderNames;
1374 this.expressions = expressions;
1375 }
1376 isEquivalent(e) {
1377 // return e instanceof LocalizedString && this.message === e.message;
1378 return false;
1379 }
1380 isConstant() {
1381 return false;
1382 }
1383 visitExpression(visitor, context) {
1384 return visitor.visitLocalizedString(this, context);
1385 }
1386 /**
1387 * Serialize the given `meta` and `messagePart` into "cooked" and "raw" strings that can be used
1388 * in a `$localize` tagged string. The format of the metadata is the same as that parsed by
1389 * `parseI18nMeta()`.
1390 *
1391 * @param meta The metadata to serialize
1392 * @param messagePart The first part of the tagged string
1393 */
1394 serializeI18nHead() {
1395 const MEANING_SEPARATOR = '|';
1396 const ID_SEPARATOR = '@@';
1397 const LEGACY_ID_INDICATOR = '␟';
1398 let metaBlock = this.metaBlock.description || '';
1399 if (this.metaBlock.meaning) {
1400 metaBlock = `${this.metaBlock.meaning}${MEANING_SEPARATOR}${metaBlock}`;
1401 }
1402 if (this.metaBlock.customId) {
1403 metaBlock = `${metaBlock}${ID_SEPARATOR}${this.metaBlock.customId}`;
1404 }
1405 if (this.metaBlock.legacyIds) {
1406 this.metaBlock.legacyIds.forEach(legacyId => {
1407 metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`;
1408 });
1409 }
1410 return createCookedRawString(metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0));
1411 }
1412 getMessagePartSourceSpan(i) {
1413 var _a, _b;
1414 return (_b = (_a = this.messageParts[i]) === null || _a === void 0 ? void 0 : _a.sourceSpan) !== null && _b !== void 0 ? _b : this.sourceSpan;
1415 }
1416 getPlaceholderSourceSpan(i) {
1417 var _a, _b, _c, _d;
1418 return (_d = (_b = (_a = this.placeHolderNames[i]) === null || _a === void 0 ? void 0 : _a.sourceSpan) !== null && _b !== void 0 ? _b : (_c = this.expressions[i]) === null || _c === void 0 ? void 0 : _c.sourceSpan) !== null && _d !== void 0 ? _d : this.sourceSpan;
1419 }
1420 /**
1421 * Serialize the given `placeholderName` and `messagePart` into "cooked" and "raw" strings that
1422 * can be used in a `$localize` tagged string.
1423 *
1424 * @param placeholderName The placeholder name to serialize
1425 * @param messagePart The following message string after this placeholder
1426 */
1427 serializeI18nTemplatePart(partIndex) {
1428 const placeholderName = this.placeHolderNames[partIndex - 1].text;
1429 const messagePart = this.messageParts[partIndex];
1430 return createCookedRawString(placeholderName, messagePart.text, this.getMessagePartSourceSpan(partIndex));
1431 }
1432 }
1433 const escapeSlashes = (str) => str.replace(/\\/g, '\\\\');
1434 const escapeStartingColon = (str) => str.replace(/^:/, '\\:');
1435 const escapeColons = (str) => str.replace(/:/g, '\\:');
1436 const escapeForTemplateLiteral = (str) => str.replace(/`/g, '\\`').replace(/\${/g, '$\\{');
1437 /**
1438 * Creates a `{cooked, raw}` object from the `metaBlock` and `messagePart`.
1439 *
1440 * The `raw` text must have various character sequences escaped:
1441 * * "\" would otherwise indicate that the next character is a control character.
1442 * * "`" and "${" are template string control sequences that would otherwise prematurely indicate
1443 * the end of a message part.
1444 * * ":" inside a metablock would prematurely indicate the end of the metablock.
1445 * * ":" at the start of a messagePart with no metablock would erroneously indicate the start of a
1446 * metablock.
1447 *
1448 * @param metaBlock Any metadata that should be prepended to the string
1449 * @param messagePart The message part of the string
1450 */
1451 function createCookedRawString(metaBlock, messagePart, range) {
1452 if (metaBlock === '') {
1453 return {
1454 cooked: messagePart,
1455 raw: escapeForTemplateLiteral(escapeStartingColon(escapeSlashes(messagePart))),
1456 range,
1457 };
1458 }
1459 else {
1460 return {
1461 cooked: `:${metaBlock}:${messagePart}`,
1462 raw: escapeForTemplateLiteral(`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`),
1463 range,
1464 };
1465 }
1466 }
1467 class ExternalExpr extends Expression {
1468 constructor(value, type, typeParams = null, sourceSpan) {
1469 super(type, sourceSpan);
1470 this.value = value;
1471 this.typeParams = typeParams;
1472 }
1473 isEquivalent(e) {
1474 return e instanceof ExternalExpr && this.value.name === e.value.name &&
1475 this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime;
1476 }
1477 isConstant() {
1478 return false;
1479 }
1480 visitExpression(visitor, context) {
1481 return visitor.visitExternalExpr(this, context);
1482 }
1483 }
1484 class ConditionalExpr extends Expression {
1485 constructor(condition, trueCase, falseCase = null, type, sourceSpan) {
1486 super(type || trueCase.type, sourceSpan);
1487 this.condition = condition;
1488 this.falseCase = falseCase;
1489 this.trueCase = trueCase;
1490 }
1491 isEquivalent(e) {
1492 return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) &&
1493 this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
1494 }
1495 isConstant() {
1496 return false;
1497 }
1498 visitExpression(visitor, context) {
1499 return visitor.visitConditionalExpr(this, context);
1500 }
1501 }
1502 class NotExpr extends Expression {
1503 constructor(condition, sourceSpan) {
1504 super(BOOL_TYPE, sourceSpan);
1505 this.condition = condition;
1506 }
1507 isEquivalent(e) {
1508 return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
1509 }
1510 isConstant() {
1511 return false;
1512 }
1513 visitExpression(visitor, context) {
1514 return visitor.visitNotExpr(this, context);
1515 }
1516 }
1517 class AssertNotNull extends Expression {
1518 constructor(condition, sourceSpan) {
1519 super(condition.type, sourceSpan);
1520 this.condition = condition;
1521 }
1522 isEquivalent(e) {
1523 return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition);
1524 }
1525 isConstant() {
1526 return false;
1527 }
1528 visitExpression(visitor, context) {
1529 return visitor.visitAssertNotNullExpr(this, context);
1530 }
1531 }
1532 class CastExpr extends Expression {
1533 constructor(value, type, sourceSpan) {
1534 super(type, sourceSpan);
1535 this.value = value;
1536 }
1537 isEquivalent(e) {
1538 return e instanceof CastExpr && this.value.isEquivalent(e.value);
1539 }
1540 isConstant() {
1541 return false;
1542 }
1543 visitExpression(visitor, context) {
1544 return visitor.visitCastExpr(this, context);
1545 }
1546 }
1547 class FnParam {
1548 constructor(name, type = null) {
1549 this.name = name;
1550 this.type = type;
1551 }
1552 isEquivalent(param) {
1553 return this.name === param.name;
1554 }
1555 }
1556 class FunctionExpr extends Expression {
1557 constructor(params, statements, type, sourceSpan, name) {
1558 super(type, sourceSpan);
1559 this.params = params;
1560 this.statements = statements;
1561 this.name = name;
1562 }
1563 isEquivalent(e) {
1564 return e instanceof FunctionExpr && areAllEquivalent(this.params, e.params) &&
1565 areAllEquivalent(this.statements, e.statements);
1566 }
1567 isConstant() {
1568 return false;
1569 }
1570 visitExpression(visitor, context) {
1571 return visitor.visitFunctionExpr(this, context);
1572 }
1573 toDeclStmt(name, modifiers) {
1574 return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan);
1575 }
1576 }
1577 class UnaryOperatorExpr extends Expression {
1578 constructor(operator, expr, type, sourceSpan, parens = true) {
1579 super(type || NUMBER_TYPE, sourceSpan);
1580 this.operator = operator;
1581 this.expr = expr;
1582 this.parens = parens;
1583 }
1584 isEquivalent(e) {
1585 return e instanceof UnaryOperatorExpr && this.operator === e.operator &&
1586 this.expr.isEquivalent(e.expr);
1587 }
1588 isConstant() {
1589 return false;
1590 }
1591 visitExpression(visitor, context) {
1592 return visitor.visitUnaryOperatorExpr(this, context);
1593 }
1594 }
1595 class BinaryOperatorExpr extends Expression {
1596 constructor(operator, lhs, rhs, type, sourceSpan, parens = true) {
1597 super(type || lhs.type, sourceSpan);
1598 this.operator = operator;
1599 this.rhs = rhs;
1600 this.parens = parens;
1601 this.lhs = lhs;
1602 }
1603 isEquivalent(e) {
1604 return e instanceof BinaryOperatorExpr && this.operator === e.operator &&
1605 this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
1606 }
1607 isConstant() {
1608 return false;
1609 }
1610 visitExpression(visitor, context) {
1611 return visitor.visitBinaryOperatorExpr(this, context);
1612 }
1613 }
1614 class ReadPropExpr extends Expression {
1615 constructor(receiver, name, type, sourceSpan) {
1616 super(type, sourceSpan);
1617 this.receiver = receiver;
1618 this.name = name;
1619 }
1620 isEquivalent(e) {
1621 return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) &&
1622 this.name === e.name;
1623 }
1624 isConstant() {
1625 return false;
1626 }
1627 visitExpression(visitor, context) {
1628 return visitor.visitReadPropExpr(this, context);
1629 }
1630 set(value) {
1631 return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan);
1632 }
1633 }
1634 class ReadKeyExpr extends Expression {
1635 constructor(receiver, index, type, sourceSpan) {
1636 super(type, sourceSpan);
1637 this.receiver = receiver;
1638 this.index = index;
1639 }
1640 isEquivalent(e) {
1641 return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) &&
1642 this.index.isEquivalent(e.index);
1643 }
1644 isConstant() {
1645 return false;
1646 }
1647 visitExpression(visitor, context) {
1648 return visitor.visitReadKeyExpr(this, context);
1649 }
1650 set(value) {
1651 return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan);
1652 }
1653 }
1654 class LiteralArrayExpr extends Expression {
1655 constructor(entries, type, sourceSpan) {
1656 super(type, sourceSpan);
1657 this.entries = entries;
1658 }
1659 isConstant() {
1660 return this.entries.every(e => e.isConstant());
1661 }
1662 isEquivalent(e) {
1663 return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
1664 }
1665 visitExpression(visitor, context) {
1666 return visitor.visitLiteralArrayExpr(this, context);
1667 }
1668 }
1669 class LiteralMapEntry {
1670 constructor(key, value, quoted) {
1671 this.key = key;
1672 this.value = value;
1673 this.quoted = quoted;
1674 }
1675 isEquivalent(e) {
1676 return this.key === e.key && this.value.isEquivalent(e.value);
1677 }
1678 }
1679 class LiteralMapExpr extends Expression {
1680 constructor(entries, type, sourceSpan) {
1681 super(type, sourceSpan);
1682 this.entries = entries;
1683 this.valueType = null;
1684 if (type) {
1685 this.valueType = type.valueType;
1686 }
1687 }
1688 isEquivalent(e) {
1689 return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
1690 }
1691 isConstant() {
1692 return this.entries.every(e => e.value.isConstant());
1693 }
1694 visitExpression(visitor, context) {
1695 return visitor.visitLiteralMapExpr(this, context);
1696 }
1697 }
1698 const THIS_EXPR = new ReadVarExpr(BuiltinVar.This, null, null);
1699 const SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super, null, null);
1700 const CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError, null, null);
1701 const CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack, null, null);
1702 const NULL_EXPR = new LiteralExpr(null, null, null);
1703 const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
1704 //// Statements
1705 var StmtModifier;
1706 (function (StmtModifier) {
1707 StmtModifier[StmtModifier["Final"] = 0] = "Final";
1708 StmtModifier[StmtModifier["Private"] = 1] = "Private";
1709 StmtModifier[StmtModifier["Exported"] = 2] = "Exported";
1710 StmtModifier[StmtModifier["Static"] = 3] = "Static";
1711 })(StmtModifier || (StmtModifier = {}));
1712 class LeadingComment {
1713 constructor(text, multiline, trailingNewline) {
1714 this.text = text;
1715 this.multiline = multiline;
1716 this.trailingNewline = trailingNewline;
1717 }
1718 toString() {
1719 return this.multiline ? ` ${this.text} ` : this.text;
1720 }
1721 }
1722 class JSDocComment extends LeadingComment {
1723 constructor(tags) {
1724 super('', /* multiline */ true, /* trailingNewline */ true);
1725 this.tags = tags;
1726 }
1727 toString() {
1728 return serializeTags(this.tags);
1729 }
1730 }
1731 class Statement {
1732 constructor(modifiers = [], sourceSpan = null, leadingComments) {
1733 this.modifiers = modifiers;
1734 this.sourceSpan = sourceSpan;
1735 this.leadingComments = leadingComments;
1736 }
1737 hasModifier(modifier) {
1738 return this.modifiers.indexOf(modifier) !== -1;
1739 }
1740 addLeadingComment(leadingComment) {
1741 var _a;
1742 this.leadingComments = (_a = this.leadingComments) !== null && _a !== void 0 ? _a : [];
1743 this.leadingComments.push(leadingComment);
1744 }
1745 }
1746 class DeclareVarStmt extends Statement {
1747 constructor(name, value, type, modifiers, sourceSpan, leadingComments) {
1748 super(modifiers, sourceSpan, leadingComments);
1749 this.name = name;
1750 this.value = value;
1751 this.type = type || (value && value.type) || null;
1752 }
1753 isEquivalent(stmt) {
1754 return stmt instanceof DeclareVarStmt && this.name === stmt.name &&
1755 (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value);
1756 }
1757 visitStatement(visitor, context) {
1758 return visitor.visitDeclareVarStmt(this, context);
1759 }
1760 }
1761 class DeclareFunctionStmt extends Statement {
1762 constructor(name, params, statements, type, modifiers, sourceSpan, leadingComments) {
1763 super(modifiers, sourceSpan, leadingComments);
1764 this.name = name;
1765 this.params = params;
1766 this.statements = statements;
1767 this.type = type || null;
1768 }
1769 isEquivalent(stmt) {
1770 return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) &&
1771 areAllEquivalent(this.statements, stmt.statements);
1772 }
1773 visitStatement(visitor, context) {
1774 return visitor.visitDeclareFunctionStmt(this, context);
1775 }
1776 }
1777 class ExpressionStatement extends Statement {
1778 constructor(expr, sourceSpan, leadingComments) {
1779 super([], sourceSpan, leadingComments);
1780 this.expr = expr;
1781 }
1782 isEquivalent(stmt) {
1783 return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr);
1784 }
1785 visitStatement(visitor, context) {
1786 return visitor.visitExpressionStmt(this, context);
1787 }
1788 }
1789 class ReturnStatement extends Statement {
1790 constructor(value, sourceSpan = null, leadingComments) {
1791 super([], sourceSpan, leadingComments);
1792 this.value = value;
1793 }
1794 isEquivalent(stmt) {
1795 return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value);
1796 }
1797 visitStatement(visitor, context) {
1798 return visitor.visitReturnStmt(this, context);
1799 }
1800 }
1801 class IfStmt extends Statement {
1802 constructor(condition, trueCase, falseCase = [], sourceSpan, leadingComments) {
1803 super([], sourceSpan, leadingComments);
1804 this.condition = condition;
1805 this.trueCase = trueCase;
1806 this.falseCase = falseCase;
1807 }
1808 isEquivalent(stmt) {
1809 return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) &&
1810 areAllEquivalent(this.trueCase, stmt.trueCase) &&
1811 areAllEquivalent(this.falseCase, stmt.falseCase);
1812 }
1813 visitStatement(visitor, context) {
1814 return visitor.visitIfStmt(this, context);
1815 }
1816 }
1817 function jsDocComment(tags = []) {
1818 return new JSDocComment(tags);
1819 }
1820 function variable(name, type, sourceSpan) {
1821 return new ReadVarExpr(name, type, sourceSpan);
1822 }
1823 function importExpr(id, typeParams = null, sourceSpan) {
1824 return new ExternalExpr(id, null, typeParams, sourceSpan);
1825 }
1826 function expressionType(expr, typeModifiers, typeParams) {
1827 return new ExpressionType(expr, typeModifiers, typeParams);
1828 }
1829 function typeofExpr(expr) {
1830 return new TypeofExpr(expr);
1831 }
1832 function literalArr(values, type, sourceSpan) {
1833 return new LiteralArrayExpr(values, type, sourceSpan);
1834 }
1835 function literalMap(values, type = null) {
1836 return new LiteralMapExpr(values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null);
1837 }
1838 function not(expr, sourceSpan) {
1839 return new NotExpr(expr, sourceSpan);
1840 }
1841 function assertNotNull(expr, sourceSpan) {
1842 return new AssertNotNull(expr, sourceSpan);
1843 }
1844 function fn(params, body, type, sourceSpan, name) {
1845 return new FunctionExpr(params, body, type, sourceSpan, name);
1846 }
1847 function ifStmt(condition, thenClause, elseClause, sourceSpan, leadingComments) {
1848 return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments);
1849 }
1850 function taggedTemplate(tag, template, type, sourceSpan) {
1851 return new TaggedTemplateExpr(tag, template, type, sourceSpan);
1852 }
1853 function literal(value, type, sourceSpan) {
1854 return new LiteralExpr(value, type, sourceSpan);
1855 }
1856 function localizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan) {
1857 return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan);
1858 }
1859 function isNull(exp) {
1860 return exp instanceof LiteralExpr && exp.value === null;
1861 }
1862 /*
1863 * Serializes a `Tag` into a string.
1864 * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`).
1865 */
1866 function tagToString(tag) {
1867 let out = '';
1868 if (tag.tagName) {
1869 out += ` @${tag.tagName}`;
1870 }
1871 if (tag.text) {
1872 if (tag.text.match(/\/\*|\*\//)) {
1873 throw new Error('JSDoc text cannot contain "/*" and "*/"');
1874 }
1875 out += ' ' + tag.text.replace(/@/g, '\\@');
1876 }
1877 return out;
1878 }
1879 function serializeTags(tags) {
1880 if (tags.length === 0)
1881 return '';
1882 if (tags.length === 1 && tags[0].tagName && !tags[0].text) {
1883 // The JSDOC comment is a single simple tag: e.g `/** @tagname */`.
1884 return `*${tagToString(tags[0])} `;
1885 }
1886 let out = '*\n';
1887 for (const tag of tags) {
1888 out += ' *';
1889 // If the tagToString is multi-line, insert " * " prefixes on lines.
1890 out += tagToString(tag).replace(/\n/g, '\n * ');
1891 out += '\n';
1892 }
1893 out += ' ';
1894 return out;
1895 }
1896
1897 /**
1898 * @license
1899 * Copyright Google LLC All Rights Reserved.
1900 *
1901 * Use of this source code is governed by an MIT-style license that can be
1902 * found in the LICENSE file at https://angular.io/license
1903 */
1904 const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
1905 function dashCaseToCamelCase(input) {
1906 return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase());
1907 }
1908 function splitAtColon(input, defaultValues) {
1909 return _splitAt(input, ':', defaultValues);
1910 }
1911 function splitAtPeriod(input, defaultValues) {
1912 return _splitAt(input, '.', defaultValues);
1913 }
1914 function _splitAt(input, character, defaultValues) {
1915 const characterIndex = input.indexOf(character);
1916 if (characterIndex == -1)
1917 return defaultValues;
1918 return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()];
1919 }
1920 function visitValue(value, visitor, context) {
1921 if (Array.isArray(value)) {
1922 return visitor.visitArray(value, context);
1923 }
1924 if (isStrictStringMap(value)) {
1925 return visitor.visitStringMap(value, context);
1926 }
1927 if (value == null || typeof value == 'string' || typeof value == 'number' ||
1928 typeof value == 'boolean') {
1929 return visitor.visitPrimitive(value, context);
1930 }
1931 return visitor.visitOther(value, context);
1932 }
1933 function isDefined(val) {
1934 return val !== null && val !== undefined;
1935 }
1936 function noUndefined(val) {
1937 return val === undefined ? null : val;
1938 }
1939 class ValueTransformer {
1940 visitArray(arr, context) {
1941 return arr.map(value => visitValue(value, this, context));
1942 }
1943 visitStringMap(map, context) {
1944 const result = {};
1945 Object.keys(map).forEach(key => {
1946 result[key] = visitValue(map[key], this, context);
1947 });
1948 return result;
1949 }
1950 visitPrimitive(value, context) {
1951 return value;
1952 }
1953 visitOther(value, context) {
1954 return value;
1955 }
1956 }
1957 const SyncAsync = {
1958 assertSync: (value) => {
1959 if (isPromise(value)) {
1960 throw new Error(`Illegal state: value cannot be a promise`);
1961 }
1962 return value;
1963 },
1964 then: (value, cb) => {
1965 return isPromise(value) ? value.then(cb) : cb(value);
1966 },
1967 all: (syncAsyncValues) => {
1968 return syncAsyncValues.some(isPromise) ? Promise.all(syncAsyncValues) : syncAsyncValues;
1969 }
1970 };
1971 function error(msg) {
1972 throw new Error(`Internal Error: ${msg}`);
1973 }
1974 function syntaxError(msg, parseErrors) {
1975 const error = Error(msg);
1976 error[ERROR_SYNTAX_ERROR] = true;
1977 if (parseErrors)
1978 error[ERROR_PARSE_ERRORS] = parseErrors;
1979 return error;
1980 }
1981 const ERROR_SYNTAX_ERROR = 'ngSyntaxError';
1982 const ERROR_PARSE_ERRORS = 'ngParseErrors';
1983 const STRING_MAP_PROTO = Object.getPrototypeOf({});
1984 function isStrictStringMap(obj) {
1985 return typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === STRING_MAP_PROTO;
1986 }
1987 function utf8Encode(str) {
1988 let encoded = [];
1989 for (let index = 0; index < str.length; index++) {
1990 let codePoint = str.charCodeAt(index);
1991 // decode surrogate
1992 // see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
1993 if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > (index + 1)) {
1994 const low = str.charCodeAt(index + 1);
1995 if (low >= 0xdc00 && low <= 0xdfff) {
1996 index++;
1997 codePoint = ((codePoint - 0xd800) << 10) + low - 0xdc00 + 0x10000;
1998 }
1999 }
2000 if (codePoint <= 0x7f) {
2001 encoded.push(codePoint);
2002 }
2003 else if (codePoint <= 0x7ff) {
2004 encoded.push(((codePoint >> 6) & 0x1F) | 0xc0, (codePoint & 0x3f) | 0x80);
2005 }
2006 else if (codePoint <= 0xffff) {
2007 encoded.push((codePoint >> 12) | 0xe0, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80);
2008 }
2009 else if (codePoint <= 0x1fffff) {
2010 encoded.push(((codePoint >> 18) & 0x07) | 0xf0, ((codePoint >> 12) & 0x3f) | 0x80, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80);
2011 }
2012 }
2013 return encoded;
2014 }
2015 function stringify(token) {
2016 if (typeof token === 'string') {
2017 return token;
2018 }
2019 if (Array.isArray(token)) {
2020 return '[' + token.map(stringify).join(', ') + ']';
2021 }
2022 if (token == null) {
2023 return '' + token;
2024 }
2025 if (token.overriddenName) {
2026 return `${token.overriddenName}`;
2027 }
2028 if (token.name) {
2029 return `${token.name}`;
2030 }
2031 if (!token.toString) {
2032 return 'object';
2033 }
2034 // WARNING: do not try to `JSON.stringify(token)` here
2035 // see https://github.com/angular/angular/issues/23440
2036 const res = token.toString();
2037 if (res == null) {
2038 return '' + res;
2039 }
2040 const newLineIndex = res.indexOf('\n');
2041 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
2042 }
2043 /**
2044 * Lazily retrieves the reference value from a forwardRef.
2045 */
2046 function resolveForwardRef(type) {
2047 if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__')) {
2048 return type();
2049 }
2050 else {
2051 return type;
2052 }
2053 }
2054 /**
2055 * Determine if the argument is shaped like a Promise
2056 */
2057 function isPromise(obj) {
2058 // allow any Promise/A+ compliant thenable.
2059 // It's up to the caller to ensure that obj.then conforms to the spec
2060 return !!obj && typeof obj.then === 'function';
2061 }
2062 class Version {
2063 constructor(full) {
2064 this.full = full;
2065 const splits = full.split('.');
2066 this.major = splits[0];
2067 this.minor = splits[1];
2068 this.patch = splits.slice(2).join('.');
2069 }
2070 }
2071 const __window = typeof window !== 'undefined' && window;
2072 const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
2073 self instanceof WorkerGlobalScope && self;
2074 const __global = typeof global !== 'undefined' && global;
2075 // Check __global first, because in Node tests both __global and __window may be defined and _global
2076 // should be __global in that case.
2077 const _global = __global || __window || __self;
2078 function newArray(size, value) {
2079 const list = [];
2080 for (let i = 0; i < size; i++) {
2081 list.push(value);
2082 }
2083 return list;
2084 }
2085 /**
2086 * Partitions a given array into 2 arrays, based on a boolean value returned by the condition
2087 * function.
2088 *
2089 * @param arr Input array that should be partitioned
2090 * @param conditionFn Condition function that is called for each item in a given array and returns a
2091 * boolean value.
2092 */
2093 function partitionArray(arr, conditionFn) {
2094 const truthy = [];
2095 const falsy = [];
2096 for (const item of arr) {
2097 (conditionFn(item) ? truthy : falsy).push(item);
2098 }
2099 return [truthy, falsy];
2100 }
2101
2102 /**
2103 * @license
2104 * Copyright Google LLC All Rights Reserved.
2105 *
2106 * Use of this source code is governed by an MIT-style license that can be
2107 * found in the LICENSE file at https://angular.io/license
2108 */
2109 const CONSTANT_PREFIX = '_c';
2110 /**
2111 * `ConstantPool` tries to reuse literal factories when two or more literals are identical.
2112 * We determine whether literals are identical by creating a key out of their AST using the
2113 * `KeyVisitor`. This constant is used to replace dynamic expressions which can't be safely
2114 * converted into a key. E.g. given an expression `{foo: bar()}`, since we don't know what
2115 * the result of `bar` will be, we create a key that looks like `{foo: <unknown>}`. Note
2116 * that we use a variable, rather than something like `null` in order to avoid collisions.
2117 */
2118 const UNKNOWN_VALUE_KEY = variable('<unknown>');
2119 /**
2120 * Context to use when producing a key.
2121 *
2122 * This ensures we see the constant not the reference variable when producing
2123 * a key.
2124 */
2125 const KEY_CONTEXT = {};
2126 /**
2127 * Generally all primitive values are excluded from the `ConstantPool`, but there is an exclusion
2128 * for strings that reach a certain length threshold. This constant defines the length threshold for
2129 * strings.
2130 */
2131 const POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS = 50;
2132 /**
2133 * A node that is a place-holder that allows the node to be replaced when the actual
2134 * node is known.
2135 *
2136 * This allows the constant pool to change an expression from a direct reference to
2137 * a constant to a shared constant. It returns a fix-up node that is later allowed to
2138 * change the referenced expression.
2139 */
2140 class FixupExpression extends Expression {
2141 constructor(resolved) {
2142 super(resolved.type);
2143 this.resolved = resolved;
2144 this.original = resolved;
2145 }
2146 visitExpression(visitor, context) {
2147 if (context === KEY_CONTEXT) {
2148 // When producing a key we want to traverse the constant not the
2149 // variable used to refer to it.
2150 return this.original.visitExpression(visitor, context);
2151 }
2152 else {
2153 return this.resolved.visitExpression(visitor, context);
2154 }
2155 }
2156 isEquivalent(e) {
2157 return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
2158 }
2159 isConstant() {
2160 return true;
2161 }
2162 fixup(expression) {
2163 this.resolved = expression;
2164 this.shared = true;
2165 }
2166 }
2167 /**
2168 * A constant pool allows a code emitter to share constant in an output context.
2169 *
2170 * The constant pool also supports sharing access to ivy definitions references.
2171 */
2172 class ConstantPool {
2173 constructor(isClosureCompilerEnabled = false) {
2174 this.isClosureCompilerEnabled = isClosureCompilerEnabled;
2175 this.statements = [];
2176 this.literals = new Map();
2177 this.literalFactories = new Map();
2178 this.injectorDefinitions = new Map();
2179 this.directiveDefinitions = new Map();
2180 this.componentDefinitions = new Map();
2181 this.pipeDefinitions = new Map();
2182 this.nextNameIndex = 0;
2183 }
2184 getConstLiteral(literal, forceShared) {
2185 if ((literal instanceof LiteralExpr && !isLongStringLiteral(literal)) ||
2186 literal instanceof FixupExpression) {
2187 // Do no put simple literals into the constant pool or try to produce a constant for a
2188 // reference to a constant.
2189 return literal;
2190 }
2191 const key = this.keyOf(literal);
2192 let fixup = this.literals.get(key);
2193 let newValue = false;
2194 if (!fixup) {
2195 fixup = new FixupExpression(literal);
2196 this.literals.set(key, fixup);
2197 newValue = true;
2198 }
2199 if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
2200 // Replace the expression with a variable
2201 const name = this.freshName();
2202 let definition;
2203 let usage;
2204 if (this.isClosureCompilerEnabled && isLongStringLiteral(literal)) {
2205 // For string literals, Closure will **always** inline the string at
2206 // **all** usages, duplicating it each time. For large strings, this
2207 // unnecessarily bloats bundle size. To work around this restriction, we
2208 // wrap the string in a function, and call that function for each usage.
2209 // This tricks Closure into using inline logic for functions instead of
2210 // string literals. Function calls are only inlined if the body is small
2211 // enough to be worth it. By doing this, very large strings will be
2212 // shared across multiple usages, rather than duplicating the string at
2213 // each usage site.
2214 //
2215 // const myStr = function() { return "very very very long string"; };
2216 // const usage1 = myStr();
2217 // const usage2 = myStr();
2218 definition = variable(name).set(new FunctionExpr([], // Params.
2219 [
2220 // Statements.
2221 new ReturnStatement(literal),
2222 ]));
2223 usage = variable(name).callFn([]);
2224 }
2225 else {
2226 // Just declare and use the variable directly, without a function call
2227 // indirection. This saves a few bytes and avoids an unncessary call.
2228 definition = variable(name).set(literal);
2229 usage = variable(name);
2230 }
2231 this.statements.push(definition.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]));
2232 fixup.fixup(usage);
2233 }
2234 return fixup;
2235 }
2236 getDefinition(type, kind, ctx, forceShared = false) {
2237 const definitions = this.definitionsOf(kind);
2238 let fixup = definitions.get(type);
2239 let newValue = false;
2240 if (!fixup) {
2241 const property = this.propertyNameOf(kind);
2242 fixup = new FixupExpression(ctx.importExpr(type).prop(property));
2243 definitions.set(type, fixup);
2244 newValue = true;
2245 }
2246 if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
2247 const name = this.freshName();
2248 this.statements.push(variable(name).set(fixup.resolved).toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]));
2249 fixup.fixup(variable(name));
2250 }
2251 return fixup;
2252 }
2253 getLiteralFactory(literal) {
2254 // Create a pure function that builds an array of a mix of constant and variable expressions
2255 if (literal instanceof LiteralArrayExpr) {
2256 const argumentsForKey = literal.entries.map(e => e.isConstant() ? e : UNKNOWN_VALUE_KEY);
2257 const key = this.keyOf(literalArr(argumentsForKey));
2258 return this._getLiteralFactory(key, literal.entries, entries => literalArr(entries));
2259 }
2260 else {
2261 const expressionForKey = literalMap(literal.entries.map(e => ({
2262 key: e.key,
2263 value: e.value.isConstant() ? e.value : UNKNOWN_VALUE_KEY,
2264 quoted: e.quoted
2265 })));
2266 const key = this.keyOf(expressionForKey);
2267 return this._getLiteralFactory(key, literal.entries.map(e => e.value), entries => literalMap(entries.map((value, index) => ({
2268 key: literal.entries[index].key,
2269 value,
2270 quoted: literal.entries[index].quoted
2271 }))));
2272 }
2273 }
2274 _getLiteralFactory(key, values, resultMap) {
2275 let literalFactory = this.literalFactories.get(key);
2276 const literalFactoryArguments = values.filter((e => !e.isConstant()));
2277 if (!literalFactory) {
2278 const resultExpressions = values.map((e, index) => e.isConstant() ? this.getConstLiteral(e, true) : variable(`a${index}`));
2279 const parameters = resultExpressions.filter(isVariable).map(e => new FnParam(e.name, DYNAMIC_TYPE));
2280 const pureFunctionDeclaration = fn(parameters, [new ReturnStatement(resultMap(resultExpressions))], INFERRED_TYPE);
2281 const name = this.freshName();
2282 this.statements.push(variable(name).set(pureFunctionDeclaration).toDeclStmt(INFERRED_TYPE, [
2283 StmtModifier.Final
2284 ]));
2285 literalFactory = variable(name);
2286 this.literalFactories.set(key, literalFactory);
2287 }
2288 return { literalFactory, literalFactoryArguments };
2289 }
2290 /**
2291 * Produce a unique name.
2292 *
2293 * The name might be unique among different prefixes if any of the prefixes end in
2294 * a digit so the prefix should be a constant string (not based on user input) and
2295 * must not end in a digit.
2296 */
2297 uniqueName(prefix) {
2298 return `${prefix}${this.nextNameIndex++}`;
2299 }
2300 definitionsOf(kind) {
2301 switch (kind) {
2302 case 2 /* Component */:
2303 return this.componentDefinitions;
2304 case 1 /* Directive */:
2305 return this.directiveDefinitions;
2306 case 0 /* Injector */:
2307 return this.injectorDefinitions;
2308 case 3 /* Pipe */:
2309 return this.pipeDefinitions;
2310 }
2311 error(`Unknown definition kind ${kind}`);
2312 return this.componentDefinitions;
2313 }
2314 propertyNameOf(kind) {
2315 switch (kind) {
2316 case 2 /* Component */:
2317 return 'ɵcmp';
2318 case 1 /* Directive */:
2319 return 'ɵdir';
2320 case 0 /* Injector */:
2321 return 'ɵinj';
2322 case 3 /* Pipe */:
2323 return 'ɵpipe';
2324 }
2325 error(`Unknown definition kind ${kind}`);
2326 return '<unknown>';
2327 }
2328 freshName() {
2329 return this.uniqueName(CONSTANT_PREFIX);
2330 }
2331 keyOf(expression) {
2332 return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT);
2333 }
2334 }
2335 /**
2336 * Visitor used to determine if 2 expressions are equivalent and can be shared in the
2337 * `ConstantPool`.
2338 *
2339 * When the id (string) generated by the visitor is equal, expressions are considered equivalent.
2340 */
2341 class KeyVisitor {
2342 constructor() {
2343 this.visitWrappedNodeExpr = invalid;
2344 this.visitWriteVarExpr = invalid;
2345 this.visitWriteKeyExpr = invalid;
2346 this.visitWritePropExpr = invalid;
2347 this.visitInvokeMethodExpr = invalid;
2348 this.visitInvokeFunctionExpr = invalid;
2349 this.visitTaggedTemplateExpr = invalid;
2350 this.visitInstantiateExpr = invalid;
2351 this.visitConditionalExpr = invalid;
2352 this.visitNotExpr = invalid;
2353 this.visitAssertNotNullExpr = invalid;
2354 this.visitCastExpr = invalid;
2355 this.visitFunctionExpr = invalid;
2356 this.visitUnaryOperatorExpr = invalid;
2357 this.visitBinaryOperatorExpr = invalid;
2358 this.visitReadPropExpr = invalid;
2359 this.visitReadKeyExpr = invalid;
2360 this.visitCommaExpr = invalid;
2361 this.visitLocalizedString = invalid;
2362 }
2363 visitLiteralExpr(ast) {
2364 return `${typeof ast.value === 'string' ? '"' + ast.value + '"' : ast.value}`;
2365 }
2366 visitLiteralArrayExpr(ast, context) {
2367 return `[${ast.entries.map(entry => entry.visitExpression(this, context)).join(',')}]`;
2368 }
2369 visitLiteralMapExpr(ast, context) {
2370 const mapKey = (entry) => {
2371 const quote = entry.quoted ? '"' : '';
2372 return `${quote}${entry.key}${quote}`;
2373 };
2374 const mapEntry = (entry) => `${mapKey(entry)}:${entry.value.visitExpression(this, context)}`;
2375 return `{${ast.entries.map(mapEntry).join(',')}`;
2376 }
2377 visitExternalExpr(ast) {
2378 return ast.value.moduleName ? `EX:${ast.value.moduleName}:${ast.value.name}` :
2379 `EX:${ast.value.runtime.name}`;
2380 }
2381 visitReadVarExpr(node) {
2382 return `VAR:${node.name}`;
2383 }
2384 visitTypeofExpr(node, context) {
2385 return `TYPEOF:${node.expr.visitExpression(this, context)}`;
2386 }
2387 }
2388 function invalid(arg) {
2389 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
2390 }
2391 function isVariable(e) {
2392 return e instanceof ReadVarExpr;
2393 }
2394 function isLongStringLiteral(expr) {
2395 return expr instanceof LiteralExpr && typeof expr.value === 'string' &&
2396 expr.value.length >= POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS;
2397 }
2398
2399 /**
2400 * @license
2401 * Copyright Google LLC All Rights Reserved.
2402 *
2403 * Use of this source code is governed by an MIT-style license that can be
2404 * found in the LICENSE file at https://angular.io/license
2405 */
2406 const CORE = '@angular/core';
2407 class Identifiers {
2408 }
2409 Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS = {
2410 name: 'ANALYZE_FOR_ENTRY_COMPONENTS',
2411 moduleName: CORE,
2412 };
2413 Identifiers.ElementRef = { name: 'ElementRef', moduleName: CORE };
2414 Identifiers.NgModuleRef = { name: 'NgModuleRef', moduleName: CORE };
2415 Identifiers.ViewContainerRef = { name: 'ViewContainerRef', moduleName: CORE };
2416 Identifiers.ChangeDetectorRef = {
2417 name: 'ChangeDetectorRef',
2418 moduleName: CORE,
2419 };
2420 Identifiers.QueryList = { name: 'QueryList', moduleName: CORE };
2421 Identifiers.TemplateRef = { name: 'TemplateRef', moduleName: CORE };
2422 Identifiers.Renderer2 = { name: 'Renderer2', moduleName: CORE };
2423 Identifiers.CodegenComponentFactoryResolver = {
2424 name: 'ɵCodegenComponentFactoryResolver',
2425 moduleName: CORE,
2426 };
2427 Identifiers.ComponentFactoryResolver = {
2428 name: 'ComponentFactoryResolver',
2429 moduleName: CORE,
2430 };
2431 Identifiers.ComponentFactory = { name: 'ComponentFactory', moduleName: CORE };
2432 Identifiers.ComponentRef = { name: 'ComponentRef', moduleName: CORE };
2433 Identifiers.NgModuleFactory = { name: 'NgModuleFactory', moduleName: CORE };
2434 Identifiers.createModuleFactory = {
2435 name: 'ɵcmf',
2436 moduleName: CORE,
2437 };
2438 Identifiers.moduleDef = {
2439 name: 'ɵmod',
2440 moduleName: CORE,
2441 };
2442 Identifiers.moduleProviderDef = {
2443 name: 'ɵmpd',
2444 moduleName: CORE,
2445 };
2446 Identifiers.RegisterModuleFactoryFn = {
2447 name: 'ɵregisterModuleFactory',
2448 moduleName: CORE,
2449 };
2450 Identifiers.inject = { name: 'ɵɵinject', moduleName: CORE };
2451 Identifiers.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE };
2452 Identifiers.INJECTOR = { name: 'INJECTOR', moduleName: CORE };
2453 Identifiers.Injector = { name: 'Injector', moduleName: CORE };
2454 Identifiers.ɵɵdefineInjectable = { name: 'ɵɵdefineInjectable', moduleName: CORE };
2455 Identifiers.InjectableDef = { name: 'ɵɵInjectableDef', moduleName: CORE };
2456 Identifiers.ViewEncapsulation = {
2457 name: 'ViewEncapsulation',
2458 moduleName: CORE,
2459 };
2460 Identifiers.ChangeDetectionStrategy = {
2461 name: 'ChangeDetectionStrategy',
2462 moduleName: CORE,
2463 };
2464 Identifiers.SecurityContext = {
2465 name: 'SecurityContext',
2466 moduleName: CORE,
2467 };
2468 Identifiers.LOCALE_ID = { name: 'LOCALE_ID', moduleName: CORE };
2469 Identifiers.TRANSLATIONS_FORMAT = {
2470 name: 'TRANSLATIONS_FORMAT',
2471 moduleName: CORE,
2472 };
2473 Identifiers.inlineInterpolate = {
2474 name: 'ɵinlineInterpolate',
2475 moduleName: CORE,
2476 };
2477 Identifiers.interpolate = { name: 'ɵinterpolate', moduleName: CORE };
2478 Identifiers.EMPTY_ARRAY = { name: 'ɵEMPTY_ARRAY', moduleName: CORE };
2479 Identifiers.EMPTY_MAP = { name: 'ɵEMPTY_MAP', moduleName: CORE };
2480 Identifiers.Renderer = { name: 'Renderer', moduleName: CORE };
2481 Identifiers.viewDef = { name: 'ɵvid', moduleName: CORE };
2482 Identifiers.elementDef = { name: 'ɵeld', moduleName: CORE };
2483 Identifiers.anchorDef = { name: 'ɵand', moduleName: CORE };
2484 Identifiers.textDef = { name: 'ɵted', moduleName: CORE };
2485 Identifiers.directiveDef = { name: 'ɵdid', moduleName: CORE };
2486 Identifiers.providerDef = { name: 'ɵprd', moduleName: CORE };
2487 Identifiers.queryDef = { name: 'ɵqud', moduleName: CORE };
2488 Identifiers.pureArrayDef = { name: 'ɵpad', moduleName: CORE };
2489 Identifiers.pureObjectDef = { name: 'ɵpod', moduleName: CORE };
2490 Identifiers.purePipeDef = { name: 'ɵppd', moduleName: CORE };
2491 Identifiers.pipeDef = { name: 'ɵpid', moduleName: CORE };
2492 Identifiers.nodeValue = { name: 'ɵnov', moduleName: CORE };
2493 Identifiers.ngContentDef = { name: 'ɵncd', moduleName: CORE };
2494 Identifiers.unwrapValue = { name: 'ɵunv', moduleName: CORE };
2495 Identifiers.createRendererType2 = { name: 'ɵcrt', moduleName: CORE };
2496 // type only
2497 Identifiers.RendererType2 = {
2498 name: 'RendererType2',
2499 moduleName: CORE,
2500 };
2501 // type only
2502 Identifiers.ViewDefinition = {
2503 name: 'ɵViewDefinition',
2504 moduleName: CORE,
2505 };
2506 Identifiers.createComponentFactory = { name: 'ɵccf', moduleName: CORE };
2507 Identifiers.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE };
2508 function createTokenForReference(reference) {
2509 return { identifier: { reference: reference } };
2510 }
2511 function createTokenForExternalReference(reflector, reference) {
2512 return createTokenForReference(reflector.resolveExternalReference(reference));
2513 }
2514
2515 /**
2516 * @license
2517 * Copyright Google LLC All Rights Reserved.
2518 *
2519 * Use of this source code is governed by an MIT-style license that can be
2520 * found in the LICENSE file at https://angular.io/license
2521 */
2522 /**
2523 * A token representing the a reference to a static type.
2524 *
2525 * This token is unique for a filePath and name and can be used as a hash table key.
2526 */
2527 class StaticSymbol {
2528 constructor(filePath, name, members) {
2529 this.filePath = filePath;
2530 this.name = name;
2531 this.members = members;
2532 }
2533 assertNoMembers() {
2534 if (this.members.length) {
2535 throw new Error(`Illegal state: symbol without members expected, but got ${JSON.stringify(this)}.`);
2536 }
2537 }
2538 }
2539 /**
2540 * A cache of static symbol used by the StaticReflector to return the same symbol for the
2541 * same symbol values.
2542 */
2543 class StaticSymbolCache {
2544 constructor() {
2545 this.cache = new Map();
2546 }
2547 get(declarationFile, name, members) {
2548 members = members || [];
2549 const memberSuffix = members.length ? `.${members.join('.')}` : '';
2550 const key = `"${declarationFile}".${name}${memberSuffix}`;
2551 let result = this.cache.get(key);
2552 if (!result) {
2553 result = new StaticSymbol(declarationFile, name, members);
2554 this.cache.set(key, result);
2555 }
2556 return result;
2557 }
2558 }
2559
2560 /**
2561 * @license
2562 * Copyright Google LLC All Rights Reserved.
2563 *
2564 * Use of this source code is governed by an MIT-style license that can be
2565 * found in the LICENSE file at https://angular.io/license
2566 */
2567 // group 0: "[prop] or (event) or @trigger"
2568 // group 1: "prop" from "[prop]"
2569 // group 2: "event" from "(event)"
2570 // group 3: "@trigger" from "@trigger"
2571 const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/;
2572 function sanitizeIdentifier(name) {
2573 return name.replace(/\W/g, '_');
2574 }
2575 let _anonymousTypeIndex = 0;
2576 function identifierName(compileIdentifier) {
2577 if (!compileIdentifier || !compileIdentifier.reference) {
2578 return null;
2579 }
2580 const ref = compileIdentifier.reference;
2581 if (ref instanceof StaticSymbol) {
2582 return ref.name;
2583 }
2584 if (ref['__anonymousType']) {
2585 return ref['__anonymousType'];
2586 }
2587 let identifier = stringify(ref);
2588 if (identifier.indexOf('(') >= 0) {
2589 // case: anonymous functions!
2590 identifier = `anonymous_${_anonymousTypeIndex++}`;
2591 ref['__anonymousType'] = identifier;
2592 }
2593 else {
2594 identifier = sanitizeIdentifier(identifier);
2595 }
2596 return identifier;
2597 }
2598 function viewClassName(compType, embeddedTemplateIndex) {
2599 return `View_${identifierName({ reference: compType })}_${embeddedTemplateIndex}`;
2600 }
2601 function rendererTypeName(compType) {
2602 return `RenderType_${identifierName({ reference: compType })}`;
2603 }
2604 function hostViewClassName(compType) {
2605 return `HostView_${identifierName({ reference: compType })}`;
2606 }
2607 function componentFactoryName(compType) {
2608 return `${identifierName({ reference: compType })}NgFactory`;
2609 }
2610 var CompileSummaryKind;
2611 (function (CompileSummaryKind) {
2612 CompileSummaryKind[CompileSummaryKind["Pipe"] = 0] = "Pipe";
2613 CompileSummaryKind[CompileSummaryKind["Directive"] = 1] = "Directive";
2614 CompileSummaryKind[CompileSummaryKind["NgModule"] = 2] = "NgModule";
2615 CompileSummaryKind[CompileSummaryKind["Injectable"] = 3] = "Injectable";
2616 })(CompileSummaryKind || (CompileSummaryKind = {}));
2617 function tokenName(token) {
2618 return token.value != null ? sanitizeIdentifier(token.value) : identifierName(token.identifier);
2619 }
2620 function tokenReference(token) {
2621 if (token.identifier != null) {
2622 return token.identifier.reference;
2623 }
2624 else {
2625 return token.value;
2626 }
2627 }
2628 /**
2629 * Metadata about a stylesheet
2630 */
2631 class CompileStylesheetMetadata {
2632 constructor({ moduleUrl, styles, styleUrls } = {}) {
2633 this.moduleUrl = moduleUrl || null;
2634 this.styles = _normalizeArray(styles);
2635 this.styleUrls = _normalizeArray(styleUrls);
2636 }
2637 }
2638 /**
2639 * Metadata regarding compilation of a template.
2640 */
2641 class CompileTemplateMetadata {
2642 constructor({ encapsulation, template, templateUrl, htmlAst, styles, styleUrls, externalStylesheets, animations, ngContentSelectors, interpolation, isInline, preserveWhitespaces }) {
2643 this.encapsulation = encapsulation;
2644 this.template = template;
2645 this.templateUrl = templateUrl;
2646 this.htmlAst = htmlAst;
2647 this.styles = _normalizeArray(styles);
2648 this.styleUrls = _normalizeArray(styleUrls);
2649 this.externalStylesheets = _normalizeArray(externalStylesheets);
2650 this.animations = animations ? flatten(animations) : [];
2651 this.ngContentSelectors = ngContentSelectors || [];
2652 if (interpolation && interpolation.length != 2) {
2653 throw new Error(`'interpolation' should have a start and an end symbol.`);
2654 }
2655 this.interpolation = interpolation;
2656 this.isInline = isInline;
2657 this.preserveWhitespaces = preserveWhitespaces;
2658 }
2659 toSummary() {
2660 return {
2661 ngContentSelectors: this.ngContentSelectors,
2662 encapsulation: this.encapsulation,
2663 styles: this.styles,
2664 animations: this.animations
2665 };
2666 }
2667 }
2668 /**
2669 * Metadata regarding compilation of a directive.
2670 */
2671 class CompileDirectiveMetadata {
2672 constructor({ isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, hostListeners, hostProperties, hostAttributes, providers, viewProviders, queries, guards, viewQueries, entryComponents, template, componentViewType, rendererType, componentFactory }) {
2673 this.isHost = !!isHost;
2674 this.type = type;
2675 this.isComponent = isComponent;
2676 this.selector = selector;
2677 this.exportAs = exportAs;
2678 this.changeDetection = changeDetection;
2679 this.inputs = inputs;
2680 this.outputs = outputs;
2681 this.hostListeners = hostListeners;
2682 this.hostProperties = hostProperties;
2683 this.hostAttributes = hostAttributes;
2684 this.providers = _normalizeArray(providers);
2685 this.viewProviders = _normalizeArray(viewProviders);
2686 this.queries = _normalizeArray(queries);
2687 this.guards = guards;
2688 this.viewQueries = _normalizeArray(viewQueries);
2689 this.entryComponents = _normalizeArray(entryComponents);
2690 this.template = template;
2691 this.componentViewType = componentViewType;
2692 this.rendererType = rendererType;
2693 this.componentFactory = componentFactory;
2694 }
2695 static create({ isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host, providers, viewProviders, queries, guards, viewQueries, entryComponents, template, componentViewType, rendererType, componentFactory }) {
2696 const hostListeners = {};
2697 const hostProperties = {};
2698 const hostAttributes = {};
2699 if (host != null) {
2700 Object.keys(host).forEach(key => {
2701 const value = host[key];
2702 const matches = key.match(HOST_REG_EXP);
2703 if (matches === null) {
2704 hostAttributes[key] = value;
2705 }
2706 else if (matches[1] != null) {
2707 hostProperties[matches[1]] = value;
2708 }
2709 else if (matches[2] != null) {
2710 hostListeners[matches[2]] = value;
2711 }
2712 });
2713 }
2714 const inputsMap = {};
2715 if (inputs != null) {
2716 inputs.forEach((bindConfig) => {
2717 // canonical syntax: `dirProp: elProp`
2718 // if there is no `:`, use dirProp = elProp
2719 const parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
2720 inputsMap[parts[0]] = parts[1];
2721 });
2722 }
2723 const outputsMap = {};
2724 if (outputs != null) {
2725 outputs.forEach((bindConfig) => {
2726 // canonical syntax: `dirProp: elProp`
2727 // if there is no `:`, use dirProp = elProp
2728 const parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
2729 outputsMap[parts[0]] = parts[1];
2730 });
2731 }
2732 return new CompileDirectiveMetadata({
2733 isHost,
2734 type,
2735 isComponent: !!isComponent,
2736 selector,
2737 exportAs,
2738 changeDetection,
2739 inputs: inputsMap,
2740 outputs: outputsMap,
2741 hostListeners,
2742 hostProperties,
2743 hostAttributes,
2744 providers,
2745 viewProviders,
2746 queries,
2747 guards,
2748 viewQueries,
2749 entryComponents,
2750 template,
2751 componentViewType,
2752 rendererType,
2753 componentFactory,
2754 });
2755 }
2756 toSummary() {
2757 return {
2758 summaryKind: CompileSummaryKind.Directive,
2759 type: this.type,
2760 isComponent: this.isComponent,
2761 selector: this.selector,
2762 exportAs: this.exportAs,
2763 inputs: this.inputs,
2764 outputs: this.outputs,
2765 hostListeners: this.hostListeners,
2766 hostProperties: this.hostProperties,
2767 hostAttributes: this.hostAttributes,
2768 providers: this.providers,
2769 viewProviders: this.viewProviders,
2770 queries: this.queries,
2771 guards: this.guards,
2772 viewQueries: this.viewQueries,
2773 entryComponents: this.entryComponents,
2774 changeDetection: this.changeDetection,
2775 template: this.template && this.template.toSummary(),
2776 componentViewType: this.componentViewType,
2777 rendererType: this.rendererType,
2778 componentFactory: this.componentFactory
2779 };
2780 }
2781 }
2782 class CompilePipeMetadata {
2783 constructor({ type, name, pure }) {
2784 this.type = type;
2785 this.name = name;
2786 this.pure = !!pure;
2787 }
2788 toSummary() {
2789 return {
2790 summaryKind: CompileSummaryKind.Pipe,
2791 type: this.type,
2792 name: this.name,
2793 pure: this.pure
2794 };
2795 }
2796 }
2797 /**
2798 * Metadata regarding compilation of a module.
2799 */
2800 class CompileNgModuleMetadata {
2801 constructor({ type, providers, declaredDirectives, exportedDirectives, declaredPipes, exportedPipes, entryComponents, bootstrapComponents, importedModules, exportedModules, schemas, transitiveModule, id }) {
2802 this.type = type || null;
2803 this.declaredDirectives = _normalizeArray(declaredDirectives);
2804 this.exportedDirectives = _normalizeArray(exportedDirectives);
2805 this.declaredPipes = _normalizeArray(declaredPipes);
2806 this.exportedPipes = _normalizeArray(exportedPipes);
2807 this.providers = _normalizeArray(providers);
2808 this.entryComponents = _normalizeArray(entryComponents);
2809 this.bootstrapComponents = _normalizeArray(bootstrapComponents);
2810 this.importedModules = _normalizeArray(importedModules);
2811 this.exportedModules = _normalizeArray(exportedModules);
2812 this.schemas = _normalizeArray(schemas);
2813 this.id = id || null;
2814 this.transitiveModule = transitiveModule || null;
2815 }
2816 toSummary() {
2817 const module = this.transitiveModule;
2818 return {
2819 summaryKind: CompileSummaryKind.NgModule,
2820 type: this.type,
2821 entryComponents: module.entryComponents,
2822 providers: module.providers,
2823 modules: module.modules,
2824 exportedDirectives: module.exportedDirectives,
2825 exportedPipes: module.exportedPipes
2826 };
2827 }
2828 }
2829 class TransitiveCompileNgModuleMetadata {
2830 constructor() {
2831 this.directivesSet = new Set();
2832 this.directives = [];
2833 this.exportedDirectivesSet = new Set();
2834 this.exportedDirectives = [];
2835 this.pipesSet = new Set();
2836 this.pipes = [];
2837 this.exportedPipesSet = new Set();
2838 this.exportedPipes = [];
2839 this.modulesSet = new Set();
2840 this.modules = [];
2841 this.entryComponentsSet = new Set();
2842 this.entryComponents = [];
2843 this.providers = [];
2844 }
2845 addProvider(provider, module) {
2846 this.providers.push({ provider: provider, module: module });
2847 }
2848 addDirective(id) {
2849 if (!this.directivesSet.has(id.reference)) {
2850 this.directivesSet.add(id.reference);
2851 this.directives.push(id);
2852 }
2853 }
2854 addExportedDirective(id) {
2855 if (!this.exportedDirectivesSet.has(id.reference)) {
2856 this.exportedDirectivesSet.add(id.reference);
2857 this.exportedDirectives.push(id);
2858 }
2859 }
2860 addPipe(id) {
2861 if (!this.pipesSet.has(id.reference)) {
2862 this.pipesSet.add(id.reference);
2863 this.pipes.push(id);
2864 }
2865 }
2866 addExportedPipe(id) {
2867 if (!this.exportedPipesSet.has(id.reference)) {
2868 this.exportedPipesSet.add(id.reference);
2869 this.exportedPipes.push(id);
2870 }
2871 }
2872 addModule(id) {
2873 if (!this.modulesSet.has(id.reference)) {
2874 this.modulesSet.add(id.reference);
2875 this.modules.push(id);
2876 }
2877 }
2878 addEntryComponent(ec) {
2879 if (!this.entryComponentsSet.has(ec.componentType)) {
2880 this.entryComponentsSet.add(ec.componentType);
2881 this.entryComponents.push(ec);
2882 }
2883 }
2884 }
2885 function _normalizeArray(obj) {
2886 return obj || [];
2887 }
2888 class ProviderMeta {
2889 constructor(token, { useClass, useValue, useExisting, useFactory, deps, multi }) {
2890 this.token = token;
2891 this.useClass = useClass || null;
2892 this.useValue = useValue;
2893 this.useExisting = useExisting;
2894 this.useFactory = useFactory || null;
2895 this.dependencies = deps || null;
2896 this.multi = !!multi;
2897 }
2898 }
2899 function flatten(list) {
2900 return list.reduce((flat, item) => {
2901 const flatItem = Array.isArray(item) ? flatten(item) : item;
2902 return flat.concat(flatItem);
2903 }, []);
2904 }
2905 function jitSourceUrl(url) {
2906 // Note: We need 3 "/" so that ng shows up as a separate domain
2907 // in the chrome dev tools.
2908 return url.replace(/(\w+:\/\/[\w:-]+)?(\/+)?/, 'ng:///');
2909 }
2910 function templateSourceUrl(ngModuleType, compMeta, templateMeta) {
2911 let url;
2912 if (templateMeta.isInline) {
2913 if (compMeta.type.reference instanceof StaticSymbol) {
2914 // Note: a .ts file might contain multiple components with inline templates,
2915 // so we need to give them unique urls, as these will be used for sourcemaps.
2916 url = `${compMeta.type.reference.filePath}.${compMeta.type.reference.name}.html`;
2917 }
2918 else {
2919 url = `${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.html`;
2920 }
2921 }
2922 else {
2923 url = templateMeta.templateUrl;
2924 }
2925 return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url);
2926 }
2927
2928 /**
2929 * @license
2930 * Copyright Google LLC All Rights Reserved.
2931 *
2932 * Use of this source code is governed by an MIT-style license that can be
2933 * found in the LICENSE file at https://angular.io/license
2934 */
2935 const CORE$1 = '@angular/core';
2936 class Identifiers$1 {
2937 }
2938 /* Methods */
2939 Identifiers$1.NEW_METHOD = 'factory';
2940 Identifiers$1.TRANSFORM_METHOD = 'transform';
2941 Identifiers$1.PATCH_DEPS = 'patchedDeps';
2942 Identifiers$1.core = { name: null, moduleName: CORE$1 };
2943 /* Instructions */
2944 Identifiers$1.namespaceHTML = { name: 'ɵɵnamespaceHTML', moduleName: CORE$1 };
2945 Identifiers$1.namespaceMathML = { name: 'ɵɵnamespaceMathML', moduleName: CORE$1 };
2946 Identifiers$1.namespaceSVG = { name: 'ɵɵnamespaceSVG', moduleName: CORE$1 };
2947 Identifiers$1.element = { name: 'ɵɵelement', moduleName: CORE$1 };
2948 Identifiers$1.elementStart = { name: 'ɵɵelementStart', moduleName: CORE$1 };
2949 Identifiers$1.elementEnd = { name: 'ɵɵelementEnd', moduleName: CORE$1 };
2950 Identifiers$1.advance = { name: 'ɵɵadvance', moduleName: CORE$1 };
2951 Identifiers$1.syntheticHostProperty = { name: 'ɵɵsyntheticHostProperty', moduleName: CORE$1 };
2952 Identifiers$1.syntheticHostListener = { name: 'ɵɵsyntheticHostListener', moduleName: CORE$1 };
2953 Identifiers$1.attribute = { name: 'ɵɵattribute', moduleName: CORE$1 };
2954 Identifiers$1.attributeInterpolate1 = { name: 'ɵɵattributeInterpolate1', moduleName: CORE$1 };
2955 Identifiers$1.attributeInterpolate2 = { name: 'ɵɵattributeInterpolate2', moduleName: CORE$1 };
2956 Identifiers$1.attributeInterpolate3 = { name: 'ɵɵattributeInterpolate3', moduleName: CORE$1 };
2957 Identifiers$1.attributeInterpolate4 = { name: 'ɵɵattributeInterpolate4', moduleName: CORE$1 };
2958 Identifiers$1.attributeInterpolate5 = { name: 'ɵɵattributeInterpolate5', moduleName: CORE$1 };
2959 Identifiers$1.attributeInterpolate6 = { name: 'ɵɵattributeInterpolate6', moduleName: CORE$1 };
2960 Identifiers$1.attributeInterpolate7 = { name: 'ɵɵattributeInterpolate7', moduleName: CORE$1 };
2961 Identifiers$1.attributeInterpolate8 = { name: 'ɵɵattributeInterpolate8', moduleName: CORE$1 };
2962 Identifiers$1.attributeInterpolateV = { name: 'ɵɵattributeInterpolateV', moduleName: CORE$1 };
2963 Identifiers$1.classProp = { name: 'ɵɵclassProp', moduleName: CORE$1 };
2964 Identifiers$1.elementContainerStart = { name: 'ɵɵelementContainerStart', moduleName: CORE$1 };
2965 Identifiers$1.elementContainerEnd = { name: 'ɵɵelementContainerEnd', moduleName: CORE$1 };
2966 Identifiers$1.elementContainer = { name: 'ɵɵelementContainer', moduleName: CORE$1 };
2967 Identifiers$1.styleMap = { name: 'ɵɵstyleMap', moduleName: CORE$1 };
2968 Identifiers$1.styleMapInterpolate1 = { name: 'ɵɵstyleMapInterpolate1', moduleName: CORE$1 };
2969 Identifiers$1.styleMapInterpolate2 = { name: 'ɵɵstyleMapInterpolate2', moduleName: CORE$1 };
2970 Identifiers$1.styleMapInterpolate3 = { name: 'ɵɵstyleMapInterpolate3', moduleName: CORE$1 };
2971 Identifiers$1.styleMapInterpolate4 = { name: 'ɵɵstyleMapInterpolate4', moduleName: CORE$1 };
2972 Identifiers$1.styleMapInterpolate5 = { name: 'ɵɵstyleMapInterpolate5', moduleName: CORE$1 };
2973 Identifiers$1.styleMapInterpolate6 = { name: 'ɵɵstyleMapInterpolate6', moduleName: CORE$1 };
2974 Identifiers$1.styleMapInterpolate7 = { name: 'ɵɵstyleMapInterpolate7', moduleName: CORE$1 };
2975 Identifiers$1.styleMapInterpolate8 = { name: 'ɵɵstyleMapInterpolate8', moduleName: CORE$1 };
2976 Identifiers$1.styleMapInterpolateV = { name: 'ɵɵstyleMapInterpolateV', moduleName: CORE$1 };
2977 Identifiers$1.classMap = { name: 'ɵɵclassMap', moduleName: CORE$1 };
2978 Identifiers$1.classMapInterpolate1 = { name: 'ɵɵclassMapInterpolate1', moduleName: CORE$1 };
2979 Identifiers$1.classMapInterpolate2 = { name: 'ɵɵclassMapInterpolate2', moduleName: CORE$1 };
2980 Identifiers$1.classMapInterpolate3 = { name: 'ɵɵclassMapInterpolate3', moduleName: CORE$1 };
2981 Identifiers$1.classMapInterpolate4 = { name: 'ɵɵclassMapInterpolate4', moduleName: CORE$1 };
2982 Identifiers$1.classMapInterpolate5 = { name: 'ɵɵclassMapInterpolate5', moduleName: CORE$1 };
2983 Identifiers$1.classMapInterpolate6 = { name: 'ɵɵclassMapInterpolate6', moduleName: CORE$1 };
2984 Identifiers$1.classMapInterpolate7 = { name: 'ɵɵclassMapInterpolate7', moduleName: CORE$1 };
2985 Identifiers$1.classMapInterpolate8 = { name: 'ɵɵclassMapInterpolate8', moduleName: CORE$1 };
2986 Identifiers$1.classMapInterpolateV = { name: 'ɵɵclassMapInterpolateV', moduleName: CORE$1 };
2987 Identifiers$1.styleProp = { name: 'ɵɵstyleProp', moduleName: CORE$1 };
2988 Identifiers$1.stylePropInterpolate1 = { name: 'ɵɵstylePropInterpolate1', moduleName: CORE$1 };
2989 Identifiers$1.stylePropInterpolate2 = { name: 'ɵɵstylePropInterpolate2', moduleName: CORE$1 };
2990 Identifiers$1.stylePropInterpolate3 = { name: 'ɵɵstylePropInterpolate3', moduleName: CORE$1 };
2991 Identifiers$1.stylePropInterpolate4 = { name: 'ɵɵstylePropInterpolate4', moduleName: CORE$1 };
2992 Identifiers$1.stylePropInterpolate5 = { name: 'ɵɵstylePropInterpolate5', moduleName: CORE$1 };
2993 Identifiers$1.stylePropInterpolate6 = { name: 'ɵɵstylePropInterpolate6', moduleName: CORE$1 };
2994 Identifiers$1.stylePropInterpolate7 = { name: 'ɵɵstylePropInterpolate7', moduleName: CORE$1 };
2995 Identifiers$1.stylePropInterpolate8 = { name: 'ɵɵstylePropInterpolate8', moduleName: CORE$1 };
2996 Identifiers$1.stylePropInterpolateV = { name: 'ɵɵstylePropInterpolateV', moduleName: CORE$1 };
2997 Identifiers$1.nextContext = { name: 'ɵɵnextContext', moduleName: CORE$1 };
2998 Identifiers$1.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE$1 };
2999 Identifiers$1.text = { name: 'ɵɵtext', moduleName: CORE$1 };
3000 Identifiers$1.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE$1 };
3001 Identifiers$1.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE$1 };
3002 Identifiers$1.getCurrentView = { name: 'ɵɵgetCurrentView', moduleName: CORE$1 };
3003 Identifiers$1.textInterpolate = { name: 'ɵɵtextInterpolate', moduleName: CORE$1 };
3004 Identifiers$1.textInterpolate1 = { name: 'ɵɵtextInterpolate1', moduleName: CORE$1 };
3005 Identifiers$1.textInterpolate2 = { name: 'ɵɵtextInterpolate2', moduleName: CORE$1 };
3006 Identifiers$1.textInterpolate3 = { name: 'ɵɵtextInterpolate3', moduleName: CORE$1 };
3007 Identifiers$1.textInterpolate4 = { name: 'ɵɵtextInterpolate4', moduleName: CORE$1 };
3008 Identifiers$1.textInterpolate5 = { name: 'ɵɵtextInterpolate5', moduleName: CORE$1 };
3009 Identifiers$1.textInterpolate6 = { name: 'ɵɵtextInterpolate6', moduleName: CORE$1 };
3010 Identifiers$1.textInterpolate7 = { name: 'ɵɵtextInterpolate7', moduleName: CORE$1 };
3011 Identifiers$1.textInterpolate8 = { name: 'ɵɵtextInterpolate8', moduleName: CORE$1 };
3012 Identifiers$1.textInterpolateV = { name: 'ɵɵtextInterpolateV', moduleName: CORE$1 };
3013 Identifiers$1.restoreView = { name: 'ɵɵrestoreView', moduleName: CORE$1 };
3014 Identifiers$1.pureFunction0 = { name: 'ɵɵpureFunction0', moduleName: CORE$1 };
3015 Identifiers$1.pureFunction1 = { name: 'ɵɵpureFunction1', moduleName: CORE$1 };
3016 Identifiers$1.pureFunction2 = { name: 'ɵɵpureFunction2', moduleName: CORE$1 };
3017 Identifiers$1.pureFunction3 = { name: 'ɵɵpureFunction3', moduleName: CORE$1 };
3018 Identifiers$1.pureFunction4 = { name: 'ɵɵpureFunction4', moduleName: CORE$1 };
3019 Identifiers$1.pureFunction5 = { name: 'ɵɵpureFunction5', moduleName: CORE$1 };
3020 Identifiers$1.pureFunction6 = { name: 'ɵɵpureFunction6', moduleName: CORE$1 };
3021 Identifiers$1.pureFunction7 = { name: 'ɵɵpureFunction7', moduleName: CORE$1 };
3022 Identifiers$1.pureFunction8 = { name: 'ɵɵpureFunction8', moduleName: CORE$1 };
3023 Identifiers$1.pureFunctionV = { name: 'ɵɵpureFunctionV', moduleName: CORE$1 };
3024 Identifiers$1.pipeBind1 = { name: 'ɵɵpipeBind1', moduleName: CORE$1 };
3025 Identifiers$1.pipeBind2 = { name: 'ɵɵpipeBind2', moduleName: CORE$1 };
3026 Identifiers$1.pipeBind3 = { name: 'ɵɵpipeBind3', moduleName: CORE$1 };
3027 Identifiers$1.pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE$1 };
3028 Identifiers$1.pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE$1 };
3029 Identifiers$1.hostProperty = { name: 'ɵɵhostProperty', moduleName: CORE$1 };
3030 Identifiers$1.property = { name: 'ɵɵproperty', moduleName: CORE$1 };
3031 Identifiers$1.propertyInterpolate = { name: 'ɵɵpropertyInterpolate', moduleName: CORE$1 };
3032 Identifiers$1.propertyInterpolate1 = { name: 'ɵɵpropertyInterpolate1', moduleName: CORE$1 };
3033 Identifiers$1.propertyInterpolate2 = { name: 'ɵɵpropertyInterpolate2', moduleName: CORE$1 };
3034 Identifiers$1.propertyInterpolate3 = { name: 'ɵɵpropertyInterpolate3', moduleName: CORE$1 };
3035 Identifiers$1.propertyInterpolate4 = { name: 'ɵɵpropertyInterpolate4', moduleName: CORE$1 };
3036 Identifiers$1.propertyInterpolate5 = { name: 'ɵɵpropertyInterpolate5', moduleName: CORE$1 };
3037 Identifiers$1.propertyInterpolate6 = { name: 'ɵɵpropertyInterpolate6', moduleName: CORE$1 };
3038 Identifiers$1.propertyInterpolate7 = { name: 'ɵɵpropertyInterpolate7', moduleName: CORE$1 };
3039 Identifiers$1.propertyInterpolate8 = { name: 'ɵɵpropertyInterpolate8', moduleName: CORE$1 };
3040 Identifiers$1.propertyInterpolateV = { name: 'ɵɵpropertyInterpolateV', moduleName: CORE$1 };
3041 Identifiers$1.i18n = { name: 'ɵɵi18n', moduleName: CORE$1 };
3042 Identifiers$1.i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE$1 };
3043 Identifiers$1.i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE$1 };
3044 Identifiers$1.i18nStart = { name: 'ɵɵi18nStart', moduleName: CORE$1 };
3045 Identifiers$1.i18nEnd = { name: 'ɵɵi18nEnd', moduleName: CORE$1 };
3046 Identifiers$1.i18nApply = { name: 'ɵɵi18nApply', moduleName: CORE$1 };
3047 Identifiers$1.i18nPostprocess = { name: 'ɵɵi18nPostprocess', moduleName: CORE$1 };
3048 Identifiers$1.pipe = { name: 'ɵɵpipe', moduleName: CORE$1 };
3049 Identifiers$1.projection = { name: 'ɵɵprojection', moduleName: CORE$1 };
3050 Identifiers$1.projectionDef = { name: 'ɵɵprojectionDef', moduleName: CORE$1 };
3051 Identifiers$1.reference = { name: 'ɵɵreference', moduleName: CORE$1 };
3052 Identifiers$1.inject = { name: 'ɵɵinject', moduleName: CORE$1 };
3053 Identifiers$1.injectAttribute = { name: 'ɵɵinjectAttribute', moduleName: CORE$1 };
3054 Identifiers$1.injectPipeChangeDetectorRef = { name: 'ɵɵinjectPipeChangeDetectorRef', moduleName: CORE$1 };
3055 Identifiers$1.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE$1 };
3056 Identifiers$1.invalidFactory = { name: 'ɵɵinvalidFactory', moduleName: CORE$1 };
3057 Identifiers$1.invalidFactoryDep = { name: 'ɵɵinvalidFactoryDep', moduleName: CORE$1 };
3058 Identifiers$1.templateRefExtractor = { name: 'ɵɵtemplateRefExtractor', moduleName: CORE$1 };
3059 Identifiers$1.forwardRef = { name: 'forwardRef', moduleName: CORE$1 };
3060 Identifiers$1.resolveForwardRef = { name: 'resolveForwardRef', moduleName: CORE$1 };
3061 Identifiers$1.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE$1 };
3062 Identifiers$1.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE$1 };
3063 Identifiers$1.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE$1 };
3064 Identifiers$1.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE$1 };
3065 Identifiers$1.declareComponent = { name: 'ɵɵngDeclareComponent', moduleName: CORE$1 };
3066 Identifiers$1.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE$1 };
3067 Identifiers$1.ChangeDetectionStrategy = {
3068 name: 'ChangeDetectionStrategy',
3069 moduleName: CORE$1,
3070 };
3071 Identifiers$1.ViewEncapsulation = {
3072 name: 'ViewEncapsulation',
3073 moduleName: CORE$1,
3074 };
3075 Identifiers$1.ComponentDefWithMeta = {
3076 name: 'ɵɵComponentDefWithMeta',
3077 moduleName: CORE$1,
3078 };
3079 Identifiers$1.FactoryDef = {
3080 name: 'ɵɵFactoryDef',
3081 moduleName: CORE$1,
3082 };
3083 Identifiers$1.defineDirective = { name: 'ɵɵdefineDirective', moduleName: CORE$1 };
3084 Identifiers$1.declareDirective = { name: 'ɵɵngDeclareDirective', moduleName: CORE$1 };
3085 Identifiers$1.DirectiveDefWithMeta = {
3086 name: 'ɵɵDirectiveDefWithMeta',
3087 moduleName: CORE$1,
3088 };
3089 Identifiers$1.InjectorDef = {
3090 name: 'ɵɵInjectorDef',
3091 moduleName: CORE$1,
3092 };
3093 Identifiers$1.defineInjector = {
3094 name: 'ɵɵdefineInjector',
3095 moduleName: CORE$1,
3096 };
3097 Identifiers$1.NgModuleDefWithMeta = {
3098 name: 'ɵɵNgModuleDefWithMeta',
3099 moduleName: CORE$1,
3100 };
3101 Identifiers$1.ModuleWithProviders = {
3102 name: 'ModuleWithProviders',
3103 moduleName: CORE$1,
3104 };
3105 Identifiers$1.defineNgModule = { name: 'ɵɵdefineNgModule', moduleName: CORE$1 };
3106 Identifiers$1.setNgModuleScope = { name: 'ɵɵsetNgModuleScope', moduleName: CORE$1 };
3107 Identifiers$1.PipeDefWithMeta = { name: 'ɵɵPipeDefWithMeta', moduleName: CORE$1 };
3108 Identifiers$1.definePipe = { name: 'ɵɵdefinePipe', moduleName: CORE$1 };
3109 Identifiers$1.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE$1 };
3110 Identifiers$1.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE$1 };
3111 Identifiers$1.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE$1 };
3112 Identifiers$1.contentQuery = { name: 'ɵɵcontentQuery', moduleName: CORE$1 };
3113 Identifiers$1.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE$1 };
3114 Identifiers$1.InheritDefinitionFeature = { name: 'ɵɵInheritDefinitionFeature', moduleName: CORE$1 };
3115 Identifiers$1.CopyDefinitionFeature = { name: 'ɵɵCopyDefinitionFeature', moduleName: CORE$1 };
3116 Identifiers$1.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE$1 };
3117 Identifiers$1.listener = { name: 'ɵɵlistener', moduleName: CORE$1 };
3118 Identifiers$1.getFactoryOf = {
3119 name: 'ɵɵgetFactoryOf',
3120 moduleName: CORE$1,
3121 };
3122 Identifiers$1.getInheritedFactory = {
3123 name: 'ɵɵgetInheritedFactory',
3124 moduleName: CORE$1,
3125 };
3126 // sanitization-related functions
3127 Identifiers$1.sanitizeHtml = { name: 'ɵɵsanitizeHtml', moduleName: CORE$1 };
3128 Identifiers$1.sanitizeStyle = { name: 'ɵɵsanitizeStyle', moduleName: CORE$1 };
3129 Identifiers$1.sanitizeResourceUrl = { name: 'ɵɵsanitizeResourceUrl', moduleName: CORE$1 };
3130 Identifiers$1.sanitizeScript = { name: 'ɵɵsanitizeScript', moduleName: CORE$1 };
3131 Identifiers$1.sanitizeUrl = { name: 'ɵɵsanitizeUrl', moduleName: CORE$1 };
3132 Identifiers$1.sanitizeUrlOrResourceUrl = { name: 'ɵɵsanitizeUrlOrResourceUrl', moduleName: CORE$1 };
3133 Identifiers$1.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE$1 };
3134 Identifiers$1.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE$1 };
3135
3136 /**
3137 * @license
3138 * Copyright Google LLC All Rights Reserved.
3139 *
3140 * Use of this source code is governed by an MIT-style license that can be
3141 * found in the LICENSE file at https://angular.io/license
3142 */
3143 // https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
3144 const VERSION = 3;
3145 const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,';
3146 class SourceMapGenerator {
3147 constructor(file = null) {
3148 this.file = file;
3149 this.sourcesContent = new Map();
3150 this.lines = [];
3151 this.lastCol0 = 0;
3152 this.hasMappings = false;
3153 }
3154 // The content is `null` when the content is expected to be loaded using the URL
3155 addSource(url, content = null) {
3156 if (!this.sourcesContent.has(url)) {
3157 this.sourcesContent.set(url, content);
3158 }
3159 return this;
3160 }
3161 addLine() {
3162 this.lines.push([]);
3163 this.lastCol0 = 0;
3164 return this;
3165 }
3166 addMapping(col0, sourceUrl, sourceLine0, sourceCol0) {
3167 if (!this.currentLine) {
3168 throw new Error(`A line must be added before mappings can be added`);
3169 }
3170 if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) {
3171 throw new Error(`Unknown source file "${sourceUrl}"`);
3172 }
3173 if (col0 == null) {
3174 throw new Error(`The column in the generated code must be provided`);
3175 }
3176 if (col0 < this.lastCol0) {
3177 throw new Error(`Mapping should be added in output order`);
3178 }
3179 if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) {
3180 throw new Error(`The source location must be provided when a source url is provided`);
3181 }
3182 this.hasMappings = true;
3183 this.lastCol0 = col0;
3184 this.currentLine.push({ col0, sourceUrl, sourceLine0, sourceCol0 });
3185 return this;
3186 }
3187 /**
3188 * @internal strip this from published d.ts files due to
3189 * https://github.com/microsoft/TypeScript/issues/36216
3190 */
3191 get currentLine() {
3192 return this.lines.slice(-1)[0];
3193 }
3194 toJSON() {
3195 if (!this.hasMappings) {
3196 return null;
3197 }
3198 const sourcesIndex = new Map();
3199 const sources = [];
3200 const sourcesContent = [];
3201 Array.from(this.sourcesContent.keys()).forEach((url, i) => {
3202 sourcesIndex.set(url, i);
3203 sources.push(url);
3204 sourcesContent.push(this.sourcesContent.get(url) || null);
3205 });
3206 let mappings = '';
3207 let lastCol0 = 0;
3208 let lastSourceIndex = 0;
3209 let lastSourceLine0 = 0;
3210 let lastSourceCol0 = 0;
3211 this.lines.forEach(segments => {
3212 lastCol0 = 0;
3213 mappings += segments
3214 .map(segment => {
3215 // zero-based starting column of the line in the generated code
3216 let segAsStr = toBase64VLQ(segment.col0 - lastCol0);
3217 lastCol0 = segment.col0;
3218 if (segment.sourceUrl != null) {
3219 // zero-based index into the “sources” list
3220 segAsStr +=
3221 toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex);
3222 lastSourceIndex = sourcesIndex.get(segment.sourceUrl);
3223 // the zero-based starting line in the original source
3224 segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0);
3225 lastSourceLine0 = segment.sourceLine0;
3226 // the zero-based starting column in the original source
3227 segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0);
3228 lastSourceCol0 = segment.sourceCol0;
3229 }
3230 return segAsStr;
3231 })
3232 .join(',');
3233 mappings += ';';
3234 });
3235 mappings = mappings.slice(0, -1);
3236 return {
3237 'file': this.file || '',
3238 'version': VERSION,
3239 'sourceRoot': '',
3240 'sources': sources,
3241 'sourcesContent': sourcesContent,
3242 'mappings': mappings,
3243 };
3244 }
3245 toJsComment() {
3246 return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) :
3247 '';
3248 }
3249 }
3250 function toBase64String(value) {
3251 let b64 = '';
3252 const encoded = utf8Encode(value);
3253 for (let i = 0; i < encoded.length;) {
3254 const i1 = encoded[i++];
3255 const i2 = i < encoded.length ? encoded[i++] : null;
3256 const i3 = i < encoded.length ? encoded[i++] : null;
3257 b64 += toBase64Digit(i1 >> 2);
3258 b64 += toBase64Digit(((i1 & 3) << 4) | (i2 === null ? 0 : i2 >> 4));
3259 b64 += i2 === null ? '=' : toBase64Digit(((i2 & 15) << 2) | (i3 === null ? 0 : i3 >> 6));
3260 b64 += i2 === null || i3 === null ? '=' : toBase64Digit(i3 & 63);
3261 }
3262 return b64;
3263 }
3264 function toBase64VLQ(value) {
3265 value = value < 0 ? ((-value) << 1) + 1 : value << 1;
3266 let out = '';
3267 do {
3268 let digit = value & 31;
3269 value = value >> 5;
3270 if (value > 0) {
3271 digit = digit | 32;
3272 }
3273 out += toBase64Digit(digit);
3274 } while (value > 0);
3275 return out;
3276 }
3277 const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
3278 function toBase64Digit(value) {
3279 if (value < 0 || value >= 64) {
3280 throw new Error(`Can only encode value in the range [0, 63]`);
3281 }
3282 return B64_DIGITS[value];
3283 }
3284
3285 /**
3286 * @license
3287 * Copyright Google LLC All Rights Reserved.
3288 *
3289 * Use of this source code is governed by an MIT-style license that can be
3290 * found in the LICENSE file at https://angular.io/license
3291 */
3292 const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
3293 const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
3294 const _INDENT_WITH = ' ';
3295 const CATCH_ERROR_VAR$1 = variable('error', null, null);
3296 const CATCH_STACK_VAR$1 = variable('stack', null, null);
3297 class _EmittedLine {
3298 constructor(indent) {
3299 this.indent = indent;
3300 this.partsLength = 0;
3301 this.parts = [];
3302 this.srcSpans = [];
3303 }
3304 }
3305 class EmitterVisitorContext {
3306 constructor(_indent) {
3307 this._indent = _indent;
3308 this._classes = [];
3309 this._preambleLineCount = 0;
3310 this._lines = [new _EmittedLine(_indent)];
3311 }
3312 static createRoot() {
3313 return new EmitterVisitorContext(0);
3314 }
3315 /**
3316 * @internal strip this from published d.ts files due to
3317 * https://github.com/microsoft/TypeScript/issues/36216
3318 */
3319 get _currentLine() {
3320 return this._lines[this._lines.length - 1];
3321 }
3322 println(from, lastPart = '') {
3323 this.print(from || null, lastPart, true);
3324 }
3325 lineIsEmpty() {
3326 return this._currentLine.parts.length === 0;
3327 }
3328 lineLength() {
3329 return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength;
3330 }
3331 print(from, part, newLine = false) {
3332 if (part.length > 0) {
3333 this._currentLine.parts.push(part);
3334 this._currentLine.partsLength += part.length;
3335 this._currentLine.srcSpans.push(from && from.sourceSpan || null);
3336 }
3337 if (newLine) {
3338 this._lines.push(new _EmittedLine(this._indent));
3339 }
3340 }
3341 removeEmptyLastLine() {
3342 if (this.lineIsEmpty()) {
3343 this._lines.pop();
3344 }
3345 }
3346 incIndent() {
3347 this._indent++;
3348 if (this.lineIsEmpty()) {
3349 this._currentLine.indent = this._indent;
3350 }
3351 }
3352 decIndent() {
3353 this._indent--;
3354 if (this.lineIsEmpty()) {
3355 this._currentLine.indent = this._indent;
3356 }
3357 }
3358 pushClass(clazz) {
3359 this._classes.push(clazz);
3360 }
3361 popClass() {
3362 return this._classes.pop();
3363 }
3364 get currentClass() {
3365 return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null;
3366 }
3367 toSource() {
3368 return this.sourceLines
3369 .map(l => l.parts.length > 0 ? _createIndent(l.indent) + l.parts.join('') : '')
3370 .join('\n');
3371 }
3372 toSourceMapGenerator(genFilePath, startsAtLine = 0) {
3373 const map = new SourceMapGenerator(genFilePath);
3374 let firstOffsetMapped = false;
3375 const mapFirstOffsetIfNeeded = () => {
3376 if (!firstOffsetMapped) {
3377 // Add a single space so that tools won't try to load the file from disk.
3378 // Note: We are using virtual urls like `ng:///`, so we have to
3379 // provide a content here.
3380 map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0);
3381 firstOffsetMapped = true;
3382 }
3383 };
3384 for (let i = 0; i < startsAtLine; i++) {
3385 map.addLine();
3386 mapFirstOffsetIfNeeded();
3387 }
3388 this.sourceLines.forEach((line, lineIdx) => {
3389 map.addLine();
3390 const spans = line.srcSpans;
3391 const parts = line.parts;
3392 let col0 = line.indent * _INDENT_WITH.length;
3393 let spanIdx = 0;
3394 // skip leading parts without source spans
3395 while (spanIdx < spans.length && !spans[spanIdx]) {
3396 col0 += parts[spanIdx].length;
3397 spanIdx++;
3398 }
3399 if (spanIdx < spans.length && lineIdx === 0 && col0 === 0) {
3400 firstOffsetMapped = true;
3401 }
3402 else {
3403 mapFirstOffsetIfNeeded();
3404 }
3405 while (spanIdx < spans.length) {
3406 const span = spans[spanIdx];
3407 const source = span.start.file;
3408 const sourceLine = span.start.line;
3409 const sourceCol = span.start.col;
3410 map.addSource(source.url, source.content)
3411 .addMapping(col0, source.url, sourceLine, sourceCol);
3412 col0 += parts[spanIdx].length;
3413 spanIdx++;
3414 // assign parts without span or the same span to the previous segment
3415 while (spanIdx < spans.length && (span === spans[spanIdx] || !spans[spanIdx])) {
3416 col0 += parts[spanIdx].length;
3417 spanIdx++;
3418 }
3419 }
3420 });
3421 return map;
3422 }
3423 setPreambleLineCount(count) {
3424 return this._preambleLineCount = count;
3425 }
3426 spanOf(line, column) {
3427 const emittedLine = this._lines[line - this._preambleLineCount];
3428 if (emittedLine) {
3429 let columnsLeft = column - _createIndent(emittedLine.indent).length;
3430 for (let partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) {
3431 const part = emittedLine.parts[partIndex];
3432 if (part.length > columnsLeft) {
3433 return emittedLine.srcSpans[partIndex];
3434 }
3435 columnsLeft -= part.length;
3436 }
3437 }
3438 return null;
3439 }
3440 /**
3441 * @internal strip this from published d.ts files due to
3442 * https://github.com/microsoft/TypeScript/issues/36216
3443 */
3444 get sourceLines() {
3445 if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) {
3446 return this._lines.slice(0, -1);
3447 }
3448 return this._lines;
3449 }
3450 }
3451 class AbstractEmitterVisitor {
3452 constructor(_escapeDollarInStrings) {
3453 this._escapeDollarInStrings = _escapeDollarInStrings;
3454 }
3455 printLeadingComments(stmt, ctx) {
3456 if (stmt.leadingComments === undefined) {
3457 return;
3458 }
3459 for (const comment of stmt.leadingComments) {
3460 if (comment instanceof JSDocComment) {
3461 ctx.print(stmt, `/*${comment.toString()}*/`, comment.trailingNewline);
3462 }
3463 else {
3464 if (comment.multiline) {
3465 ctx.print(stmt, `/* ${comment.text} */`, comment.trailingNewline);
3466 }
3467 else {
3468 comment.text.split('\n').forEach((line) => {
3469 ctx.println(stmt, `// ${line}`);
3470 });
3471 }
3472 }
3473 }
3474 }
3475 visitExpressionStmt(stmt, ctx) {
3476 this.printLeadingComments(stmt, ctx);
3477 stmt.expr.visitExpression(this, ctx);
3478 ctx.println(stmt, ';');
3479 return null;
3480 }
3481 visitReturnStmt(stmt, ctx) {
3482 this.printLeadingComments(stmt, ctx);
3483 ctx.print(stmt, `return `);
3484 stmt.value.visitExpression(this, ctx);
3485 ctx.println(stmt, ';');
3486 return null;
3487 }
3488 visitIfStmt(stmt, ctx) {
3489 this.printLeadingComments(stmt, ctx);
3490 ctx.print(stmt, `if (`);
3491 stmt.condition.visitExpression(this, ctx);
3492 ctx.print(stmt, `) {`);
3493 const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0;
3494 if (stmt.trueCase.length <= 1 && !hasElseCase) {
3495 ctx.print(stmt, ` `);
3496 this.visitAllStatements(stmt.trueCase, ctx);
3497 ctx.removeEmptyLastLine();
3498 ctx.print(stmt, ` `);
3499 }
3500 else {
3501 ctx.println();
3502 ctx.incIndent();
3503 this.visitAllStatements(stmt.trueCase, ctx);
3504 ctx.decIndent();
3505 if (hasElseCase) {
3506 ctx.println(stmt, `} else {`);
3507 ctx.incIndent();
3508 this.visitAllStatements(stmt.falseCase, ctx);
3509 ctx.decIndent();
3510 }
3511 }
3512 ctx.println(stmt, `}`);
3513 return null;
3514 }
3515 visitThrowStmt(stmt, ctx) {
3516 this.printLeadingComments(stmt, ctx);
3517 ctx.print(stmt, `throw `);
3518 stmt.error.visitExpression(this, ctx);
3519 ctx.println(stmt, `;`);
3520 return null;
3521 }
3522 visitWriteVarExpr(expr, ctx) {
3523 const lineWasEmpty = ctx.lineIsEmpty();
3524 if (!lineWasEmpty) {
3525 ctx.print(expr, '(');
3526 }
3527 ctx.print(expr, `${expr.name} = `);
3528 expr.value.visitExpression(this, ctx);
3529 if (!lineWasEmpty) {
3530 ctx.print(expr, ')');
3531 }
3532 return null;
3533 }
3534 visitWriteKeyExpr(expr, ctx) {
3535 const lineWasEmpty = ctx.lineIsEmpty();
3536 if (!lineWasEmpty) {
3537 ctx.print(expr, '(');
3538 }
3539 expr.receiver.visitExpression(this, ctx);
3540 ctx.print(expr, `[`);
3541 expr.index.visitExpression(this, ctx);
3542 ctx.print(expr, `] = `);
3543 expr.value.visitExpression(this, ctx);
3544 if (!lineWasEmpty) {
3545 ctx.print(expr, ')');
3546 }
3547 return null;
3548 }
3549 visitWritePropExpr(expr, ctx) {
3550 const lineWasEmpty = ctx.lineIsEmpty();
3551 if (!lineWasEmpty) {
3552 ctx.print(expr, '(');
3553 }
3554 expr.receiver.visitExpression(this, ctx);
3555 ctx.print(expr, `.${expr.name} = `);
3556 expr.value.visitExpression(this, ctx);
3557 if (!lineWasEmpty) {
3558 ctx.print(expr, ')');
3559 }
3560 return null;
3561 }
3562 visitInvokeMethodExpr(expr, ctx) {
3563 expr.receiver.visitExpression(this, ctx);
3564 let name = expr.name;
3565 if (expr.builtin != null) {
3566 name = this.getBuiltinMethodName(expr.builtin);
3567 if (name == null) {
3568 // some builtins just mean to skip the call.
3569 return null;
3570 }
3571 }
3572 ctx.print(expr, `.${name}(`);
3573 this.visitAllExpressions(expr.args, ctx, `,`);
3574 ctx.print(expr, `)`);
3575 return null;
3576 }
3577 visitInvokeFunctionExpr(expr, ctx) {
3578 expr.fn.visitExpression(this, ctx);
3579 ctx.print(expr, `(`);
3580 this.visitAllExpressions(expr.args, ctx, ',');
3581 ctx.print(expr, `)`);
3582 return null;
3583 }
3584 visitTaggedTemplateExpr(expr, ctx) {
3585 expr.tag.visitExpression(this, ctx);
3586 ctx.print(expr, '`' + expr.template.elements[0].rawText);
3587 for (let i = 1; i < expr.template.elements.length; i++) {
3588 ctx.print(expr, '${');
3589 expr.template.expressions[i - 1].visitExpression(this, ctx);
3590 ctx.print(expr, `}${expr.template.elements[i].rawText}`);
3591 }
3592 ctx.print(expr, '`');
3593 return null;
3594 }
3595 visitWrappedNodeExpr(ast, ctx) {
3596 throw new Error('Abstract emitter cannot visit WrappedNodeExpr.');
3597 }
3598 visitTypeofExpr(expr, ctx) {
3599 ctx.print(expr, 'typeof ');
3600 expr.expr.visitExpression(this, ctx);
3601 }
3602 visitReadVarExpr(ast, ctx) {
3603 let varName = ast.name;
3604 if (ast.builtin != null) {
3605 switch (ast.builtin) {
3606 case BuiltinVar.Super:
3607 varName = 'super';
3608 break;
3609 case BuiltinVar.This:
3610 varName = 'this';
3611 break;
3612 case BuiltinVar.CatchError:
3613 varName = CATCH_ERROR_VAR$1.name;
3614 break;
3615 case BuiltinVar.CatchStack:
3616 varName = CATCH_STACK_VAR$1.name;
3617 break;
3618 default:
3619 throw new Error(`Unknown builtin variable ${ast.builtin}`);
3620 }
3621 }
3622 ctx.print(ast, varName);
3623 return null;
3624 }
3625 visitInstantiateExpr(ast, ctx) {
3626 ctx.print(ast, `new `);
3627 ast.classExpr.visitExpression(this, ctx);
3628 ctx.print(ast, `(`);
3629 this.visitAllExpressions(ast.args, ctx, ',');
3630 ctx.print(ast, `)`);
3631 return null;
3632 }
3633 visitLiteralExpr(ast, ctx) {
3634 const value = ast.value;
3635 if (typeof value === 'string') {
3636 ctx.print(ast, escapeIdentifier(value, this._escapeDollarInStrings));
3637 }
3638 else {
3639 ctx.print(ast, `${value}`);
3640 }
3641 return null;
3642 }
3643 visitLocalizedString(ast, ctx) {
3644 const head = ast.serializeI18nHead();
3645 ctx.print(ast, '$localize `' + head.raw);
3646 for (let i = 1; i < ast.messageParts.length; i++) {
3647 ctx.print(ast, '${');
3648 ast.expressions[i - 1].visitExpression(this, ctx);
3649 ctx.print(ast, `}${ast.serializeI18nTemplatePart(i).raw}`);
3650 }
3651 ctx.print(ast, '`');
3652 return null;
3653 }
3654 visitConditionalExpr(ast, ctx) {
3655 ctx.print(ast, `(`);
3656 ast.condition.visitExpression(this, ctx);
3657 ctx.print(ast, '? ');
3658 ast.trueCase.visitExpression(this, ctx);
3659 ctx.print(ast, ': ');
3660 ast.falseCase.visitExpression(this, ctx);
3661 ctx.print(ast, `)`);
3662 return null;
3663 }
3664 visitNotExpr(ast, ctx) {
3665 ctx.print(ast, '!');
3666 ast.condition.visitExpression(this, ctx);
3667 return null;
3668 }
3669 visitAssertNotNullExpr(ast, ctx) {
3670 ast.condition.visitExpression(this, ctx);
3671 return null;
3672 }
3673 visitUnaryOperatorExpr(ast, ctx) {
3674 let opStr;
3675 switch (ast.operator) {
3676 case UnaryOperator.Plus:
3677 opStr = '+';
3678 break;
3679 case UnaryOperator.Minus:
3680 opStr = '-';
3681 break;
3682 default:
3683 throw new Error(`Unknown operator ${ast.operator}`);
3684 }
3685 if (ast.parens)
3686 ctx.print(ast, `(`);
3687 ctx.print(ast, opStr);
3688 ast.expr.visitExpression(this, ctx);
3689 if (ast.parens)
3690 ctx.print(ast, `)`);
3691 return null;
3692 }
3693 visitBinaryOperatorExpr(ast, ctx) {
3694 let opStr;
3695 switch (ast.operator) {
3696 case BinaryOperator.Equals:
3697 opStr = '==';
3698 break;
3699 case BinaryOperator.Identical:
3700 opStr = '===';
3701 break;
3702 case BinaryOperator.NotEquals:
3703 opStr = '!=';
3704 break;
3705 case BinaryOperator.NotIdentical:
3706 opStr = '!==';
3707 break;
3708 case BinaryOperator.And:
3709 opStr = '&&';
3710 break;
3711 case BinaryOperator.BitwiseAnd:
3712 opStr = '&';
3713 break;
3714 case BinaryOperator.Or:
3715 opStr = '||';
3716 break;
3717 case BinaryOperator.Plus:
3718 opStr = '+';
3719 break;
3720 case BinaryOperator.Minus:
3721 opStr = '-';
3722 break;
3723 case BinaryOperator.Divide:
3724 opStr = '/';
3725 break;
3726 case BinaryOperator.Multiply:
3727 opStr = '*';
3728 break;
3729 case BinaryOperator.Modulo:
3730 opStr = '%';
3731 break;
3732 case BinaryOperator.Lower:
3733 opStr = '<';
3734 break;
3735 case BinaryOperator.LowerEquals:
3736 opStr = '<=';
3737 break;
3738 case BinaryOperator.Bigger:
3739 opStr = '>';
3740 break;
3741 case BinaryOperator.BiggerEquals:
3742 opStr = '>=';
3743 break;
3744 default:
3745 throw new Error(`Unknown operator ${ast.operator}`);
3746 }
3747 if (ast.parens)
3748 ctx.print(ast, `(`);
3749 ast.lhs.visitExpression(this, ctx);
3750 ctx.print(ast, ` ${opStr} `);
3751 ast.rhs.visitExpression(this, ctx);
3752 if (ast.parens)
3753 ctx.print(ast, `)`);
3754 return null;
3755 }
3756 visitReadPropExpr(ast, ctx) {
3757 ast.receiver.visitExpression(this, ctx);
3758 ctx.print(ast, `.`);
3759 ctx.print(ast, ast.name);
3760 return null;
3761 }
3762 visitReadKeyExpr(ast, ctx) {
3763 ast.receiver.visitExpression(this, ctx);
3764 ctx.print(ast, `[`);
3765 ast.index.visitExpression(this, ctx);
3766 ctx.print(ast, `]`);
3767 return null;
3768 }
3769 visitLiteralArrayExpr(ast, ctx) {
3770 ctx.print(ast, `[`);
3771 this.visitAllExpressions(ast.entries, ctx, ',');
3772 ctx.print(ast, `]`);
3773 return null;
3774 }
3775 visitLiteralMapExpr(ast, ctx) {
3776 ctx.print(ast, `{`);
3777 this.visitAllObjects(entry => {
3778 ctx.print(ast, `${escapeIdentifier(entry.key, this._escapeDollarInStrings, entry.quoted)}:`);
3779 entry.value.visitExpression(this, ctx);
3780 }, ast.entries, ctx, ',');
3781 ctx.print(ast, `}`);
3782 return null;
3783 }
3784 visitCommaExpr(ast, ctx) {
3785 ctx.print(ast, '(');
3786 this.visitAllExpressions(ast.parts, ctx, ',');
3787 ctx.print(ast, ')');
3788 return null;
3789 }
3790 visitAllExpressions(expressions, ctx, separator) {
3791 this.visitAllObjects(expr => expr.visitExpression(this, ctx), expressions, ctx, separator);
3792 }
3793 visitAllObjects(handler, expressions, ctx, separator) {
3794 let incrementedIndent = false;
3795 for (let i = 0; i < expressions.length; i++) {
3796 if (i > 0) {
3797 if (ctx.lineLength() > 80) {
3798 ctx.print(null, separator, true);
3799 if (!incrementedIndent) {
3800 // continuation are marked with double indent.
3801 ctx.incIndent();
3802 ctx.incIndent();
3803 incrementedIndent = true;
3804 }
3805 }
3806 else {
3807 ctx.print(null, separator, false);
3808 }
3809 }
3810 handler(expressions[i]);
3811 }
3812 if (incrementedIndent) {
3813 // continuation are marked with double indent.
3814 ctx.decIndent();
3815 ctx.decIndent();
3816 }
3817 }
3818 visitAllStatements(statements, ctx) {
3819 statements.forEach((stmt) => stmt.visitStatement(this, ctx));
3820 }
3821 }
3822 function escapeIdentifier(input, escapeDollar, alwaysQuote = true) {
3823 if (input == null) {
3824 return null;
3825 }
3826 const body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, (...match) => {
3827 if (match[0] == '$') {
3828 return escapeDollar ? '\\$' : '$';
3829 }
3830 else if (match[0] == '\n') {
3831 return '\\n';
3832 }
3833 else if (match[0] == '\r') {
3834 return '\\r';
3835 }
3836 else {
3837 return `\\${match[0]}`;
3838 }
3839 });
3840 const requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body);
3841 return requiresQuotes ? `'${body}'` : body;
3842 }
3843 function _createIndent(count) {
3844 let res = '';
3845 for (let i = 0; i < count; i++) {
3846 res += _INDENT_WITH;
3847 }
3848 return res;
3849 }
3850
3851 /**
3852 * @license
3853 * Copyright Google LLC All Rights Reserved.
3854 *
3855 * Use of this source code is governed by an MIT-style license that can be
3856 * found in the LICENSE file at https://angular.io/license
3857 */
3858 /**
3859 * Convert an object map with `Expression` values into a `LiteralMapExpr`.
3860 */
3861 function mapToMapExpression(map) {
3862 const result = Object.keys(map).map(key => ({
3863 key,
3864 // The assertion here is because really TypeScript doesn't allow us to express that if the
3865 // key is present, it will have a value, but this is true in reality.
3866 value: map[key],
3867 quoted: false,
3868 }));
3869 return literalMap(result);
3870 }
3871 function typeWithParameters(type, numParams) {
3872 if (numParams === 0) {
3873 return expressionType(type);
3874 }
3875 const params = [];
3876 for (let i = 0; i < numParams; i++) {
3877 params.push(DYNAMIC_TYPE);
3878 }
3879 return expressionType(type, undefined, params);
3880 }
3881 const ANIMATE_SYMBOL_PREFIX = '@';
3882 function prepareSyntheticPropertyName(name) {
3883 return `${ANIMATE_SYMBOL_PREFIX}${name}`;
3884 }
3885 function prepareSyntheticListenerName(name, phase) {
3886 return `${ANIMATE_SYMBOL_PREFIX}${name}.${phase}`;
3887 }
3888 function getSafePropertyAccessString(accessor, name) {
3889 const escapedName = escapeIdentifier(name, false, false);
3890 return escapedName !== name ? `${accessor}[${escapedName}]` : `${accessor}.${name}`;
3891 }
3892 function prepareSyntheticListenerFunctionName(name, phase) {
3893 return `animation_${name}_${phase}`;
3894 }
3895 function jitOnlyGuardedExpression(expr) {
3896 return guardedExpression('ngJitMode', expr);
3897 }
3898 function guardedExpression(guard, expr) {
3899 const guardExpr = new ExternalExpr({ name: guard, moduleName: null });
3900 const guardNotDefined = new BinaryOperatorExpr(BinaryOperator.Identical, new TypeofExpr(guardExpr), literal('undefined'));
3901 const guardUndefinedOrTrue = new BinaryOperatorExpr(BinaryOperator.Or, guardNotDefined, guardExpr, /* type */ undefined,
3902 /* sourceSpan */ undefined, true);
3903 return new BinaryOperatorExpr(BinaryOperator.And, guardUndefinedOrTrue, expr);
3904 }
3905
3906 /**
3907 * @license
3908 * Copyright Google LLC All Rights Reserved.
3909 *
3910 * Use of this source code is governed by an MIT-style license that can be
3911 * found in the LICENSE file at https://angular.io/license
3912 */
3913 class Text {
3914 constructor(value, sourceSpan) {
3915 this.value = value;
3916 this.sourceSpan = sourceSpan;
3917 }
3918 visit(visitor) {
3919 return visitor.visitText(this);
3920 }
3921 }
3922 class BoundText {
3923 constructor(value, sourceSpan, i18n) {
3924 this.value = value;
3925 this.sourceSpan = sourceSpan;
3926 this.i18n = i18n;
3927 }
3928 visit(visitor) {
3929 return visitor.visitBoundText(this);
3930 }
3931 }
3932 /**
3933 * Represents a text attribute in the template.
3934 *
3935 * `valueSpan` may not be present in cases where there is no value `<div a></div>`.
3936 * `keySpan` may also not be present for synthetic attributes from ICU expansions.
3937 */
3938 class TextAttribute {
3939 constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) {
3940 this.name = name;
3941 this.value = value;
3942 this.sourceSpan = sourceSpan;
3943 this.keySpan = keySpan;
3944 this.valueSpan = valueSpan;
3945 this.i18n = i18n;
3946 }
3947 visit(visitor) {
3948 return visitor.visitTextAttribute(this);
3949 }
3950 }
3951 class BoundAttribute {
3952 constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan, i18n) {
3953 this.name = name;
3954 this.type = type;
3955 this.securityContext = securityContext;
3956 this.value = value;
3957 this.unit = unit;
3958 this.sourceSpan = sourceSpan;
3959 this.keySpan = keySpan;
3960 this.valueSpan = valueSpan;
3961 this.i18n = i18n;
3962 }
3963 static fromBoundElementProperty(prop, i18n) {
3964 if (prop.keySpan === undefined) {
3965 throw new Error(`Unexpected state: keySpan must be defined for bound attributes but was not for ${prop.name}: ${prop.sourceSpan}`);
3966 }
3967 return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n);
3968 }
3969 visit(visitor) {
3970 return visitor.visitBoundAttribute(this);
3971 }
3972 }
3973 class BoundEvent {
3974 constructor(name, type, handler, target, phase, sourceSpan, handlerSpan, keySpan) {
3975 this.name = name;
3976 this.type = type;
3977 this.handler = handler;
3978 this.target = target;
3979 this.phase = phase;
3980 this.sourceSpan = sourceSpan;
3981 this.handlerSpan = handlerSpan;
3982 this.keySpan = keySpan;
3983 }
3984 static fromParsedEvent(event) {
3985 const target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
3986 const phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
3987 if (event.keySpan === undefined) {
3988 throw new Error(`Unexpected state: keySpan must be defined for bound event but was not for ${event.name}: ${event.sourceSpan}`);
3989 }
3990 return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan, event.keySpan);
3991 }
3992 visit(visitor) {
3993 return visitor.visitBoundEvent(this);
3994 }
3995 }
3996 class Element {
3997 constructor(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
3998 this.name = name;
3999 this.attributes = attributes;
4000 this.inputs = inputs;
4001 this.outputs = outputs;
4002 this.children = children;
4003 this.references = references;
4004 this.sourceSpan = sourceSpan;
4005 this.startSourceSpan = startSourceSpan;
4006 this.endSourceSpan = endSourceSpan;
4007 this.i18n = i18n;
4008 }
4009 visit(visitor) {
4010 return visitor.visitElement(this);
4011 }
4012 }
4013 class Template {
4014 constructor(tagName, attributes, inputs, outputs, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
4015 this.tagName = tagName;
4016 this.attributes = attributes;
4017 this.inputs = inputs;
4018 this.outputs = outputs;
4019 this.templateAttrs = templateAttrs;
4020 this.children = children;
4021 this.references = references;
4022 this.variables = variables;
4023 this.sourceSpan = sourceSpan;
4024 this.startSourceSpan = startSourceSpan;
4025 this.endSourceSpan = endSourceSpan;
4026 this.i18n = i18n;
4027 }
4028 visit(visitor) {
4029 return visitor.visitTemplate(this);
4030 }
4031 }
4032 class Content {
4033 constructor(selector, attributes, sourceSpan, i18n) {
4034 this.selector = selector;
4035 this.attributes = attributes;
4036 this.sourceSpan = sourceSpan;
4037 this.i18n = i18n;
4038 this.name = 'ng-content';
4039 }
4040 visit(visitor) {
4041 return visitor.visitContent(this);
4042 }
4043 }
4044 class Variable {
4045 constructor(name, value, sourceSpan, keySpan, valueSpan) {
4046 this.name = name;
4047 this.value = value;
4048 this.sourceSpan = sourceSpan;
4049 this.keySpan = keySpan;
4050 this.valueSpan = valueSpan;
4051 }
4052 visit(visitor) {
4053 return visitor.visitVariable(this);
4054 }
4055 }
4056 class Reference {
4057 constructor(name, value, sourceSpan, keySpan, valueSpan) {
4058 this.name = name;
4059 this.value = value;
4060 this.sourceSpan = sourceSpan;
4061 this.keySpan = keySpan;
4062 this.valueSpan = valueSpan;
4063 }
4064 visit(visitor) {
4065 return visitor.visitReference(this);
4066 }
4067 }
4068 class Icu {
4069 constructor(vars, placeholders, sourceSpan, i18n) {
4070 this.vars = vars;
4071 this.placeholders = placeholders;
4072 this.sourceSpan = sourceSpan;
4073 this.i18n = i18n;
4074 }
4075 visit(visitor) {
4076 return visitor.visitIcu(this);
4077 }
4078 }
4079 function visitAll(visitor, nodes) {
4080 const result = [];
4081 if (visitor.visit) {
4082 for (const node of nodes) {
4083 const newNode = visitor.visit(node) || node.visit(visitor);
4084 }
4085 }
4086 else {
4087 for (const node of nodes) {
4088 const newNode = node.visit(visitor);
4089 if (newNode) {
4090 result.push(newNode);
4091 }
4092 }
4093 }
4094 return result;
4095 }
4096
4097 /**
4098 * @license
4099 * Copyright Google LLC All Rights Reserved.
4100 *
4101 * Use of this source code is governed by an MIT-style license that can be
4102 * found in the LICENSE file at https://angular.io/license
4103 */
4104 class Message {
4105 /**
4106 * @param nodes message AST
4107 * @param placeholders maps placeholder names to static content and their source spans
4108 * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages)
4109 * @param meaning
4110 * @param description
4111 * @param customId
4112 */
4113 constructor(nodes, placeholders, placeholderToMessage, meaning, description, customId) {
4114 this.nodes = nodes;
4115 this.placeholders = placeholders;
4116 this.placeholderToMessage = placeholderToMessage;
4117 this.meaning = meaning;
4118 this.description = description;
4119 this.customId = customId;
4120 this.id = this.customId;
4121 /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */
4122 this.legacyIds = [];
4123 if (nodes.length) {
4124 this.sources = [{
4125 filePath: nodes[0].sourceSpan.start.file.url,
4126 startLine: nodes[0].sourceSpan.start.line + 1,
4127 startCol: nodes[0].sourceSpan.start.col + 1,
4128 endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1,
4129 endCol: nodes[0].sourceSpan.start.col + 1
4130 }];
4131 }
4132 else {
4133 this.sources = [];
4134 }
4135 }
4136 }
4137 class Text$1 {
4138 constructor(value, sourceSpan) {
4139 this.value = value;
4140 this.sourceSpan = sourceSpan;
4141 }
4142 visit(visitor, context) {
4143 return visitor.visitText(this, context);
4144 }
4145 }
4146 // TODO(vicb): do we really need this node (vs an array) ?
4147 class Container {
4148 constructor(children, sourceSpan) {
4149 this.children = children;
4150 this.sourceSpan = sourceSpan;
4151 }
4152 visit(visitor, context) {
4153 return visitor.visitContainer(this, context);
4154 }
4155 }
4156 class Icu$1 {
4157 constructor(expression, type, cases, sourceSpan) {
4158 this.expression = expression;
4159 this.type = type;
4160 this.cases = cases;
4161 this.sourceSpan = sourceSpan;
4162 }
4163 visit(visitor, context) {
4164 return visitor.visitIcu(this, context);
4165 }
4166 }
4167 class TagPlaceholder {
4168 constructor(tag, attrs, startName, closeName, children, isVoid,
4169 // TODO sourceSpan should cover all (we need a startSourceSpan and endSourceSpan)
4170 sourceSpan, startSourceSpan, endSourceSpan) {
4171 this.tag = tag;
4172 this.attrs = attrs;
4173 this.startName = startName;
4174 this.closeName = closeName;
4175 this.children = children;
4176 this.isVoid = isVoid;
4177 this.sourceSpan = sourceSpan;
4178 this.startSourceSpan = startSourceSpan;
4179 this.endSourceSpan = endSourceSpan;
4180 }
4181 visit(visitor, context) {
4182 return visitor.visitTagPlaceholder(this, context);
4183 }
4184 }
4185 class Placeholder {
4186 constructor(value, name, sourceSpan) {
4187 this.value = value;
4188 this.name = name;
4189 this.sourceSpan = sourceSpan;
4190 }
4191 visit(visitor, context) {
4192 return visitor.visitPlaceholder(this, context);
4193 }
4194 }
4195 class IcuPlaceholder {
4196 constructor(value, name, sourceSpan) {
4197 this.value = value;
4198 this.name = name;
4199 this.sourceSpan = sourceSpan;
4200 }
4201 visit(visitor, context) {
4202 return visitor.visitIcuPlaceholder(this, context);
4203 }
4204 }
4205
4206 /**
4207 * @license
4208 * Copyright Google LLC All Rights Reserved.
4209 *
4210 * Use of this source code is governed by an MIT-style license that can be
4211 * found in the LICENSE file at https://angular.io/license
4212 */
4213 /**
4214 * Represents a big integer using a buffer of its individual digits, with the least significant
4215 * digit stored at the beginning of the array (little endian).
4216 *
4217 * For performance reasons, each instance is mutable. The addition operation can be done in-place
4218 * to reduce memory pressure of allocation for the digits array.
4219 */
4220 class BigInteger {
4221 /**
4222 * Creates a big integer using its individual digits in little endian storage.
4223 */
4224 constructor(digits) {
4225 this.digits = digits;
4226 }
4227 static zero() {
4228 return new BigInteger([0]);
4229 }
4230 static one() {
4231 return new BigInteger([1]);
4232 }
4233 /**
4234 * Creates a clone of this instance.
4235 */
4236 clone() {
4237 return new BigInteger(this.digits.slice());
4238 }
4239 /**
4240 * Returns a new big integer with the sum of `this` and `other` as its value. This does not mutate
4241 * `this` but instead returns a new instance, unlike `addToSelf`.
4242 */
4243 add(other) {
4244 const result = this.clone();
4245 result.addToSelf(other);
4246 return result;
4247 }
4248 /**
4249 * Adds `other` to the instance itself, thereby mutating its value.
4250 */
4251 addToSelf(other) {
4252 const maxNrOfDigits = Math.max(this.digits.length, other.digits.length);
4253 let carry = 0;
4254 for (let i = 0; i < maxNrOfDigits; i++) {
4255 let digitSum = carry;
4256 if (i < this.digits.length) {
4257 digitSum += this.digits[i];
4258 }
4259 if (i < other.digits.length) {
4260 digitSum += other.digits[i];
4261 }
4262 if (digitSum >= 10) {
4263 this.digits[i] = digitSum - 10;
4264 carry = 1;
4265 }
4266 else {
4267 this.digits[i] = digitSum;
4268 carry = 0;
4269 }
4270 }
4271 // Apply a remaining carry if needed.
4272 if (carry > 0) {
4273 this.digits[maxNrOfDigits] = 1;
4274 }
4275 }
4276 /**
4277 * Builds the decimal string representation of the big integer. As this is stored in
4278 * little endian, the digits are concatenated in reverse order.
4279 */
4280 toString() {
4281 let res = '';
4282 for (let i = this.digits.length - 1; i >= 0; i--) {
4283 res += this.digits[i];
4284 }
4285 return res;
4286 }
4287 }
4288 /**
4289 * Represents a big integer which is optimized for multiplication operations, as its power-of-twos
4290 * are memoized. See `multiplyBy()` for details on the multiplication algorithm.
4291 */
4292 class BigIntForMultiplication {
4293 constructor(value) {
4294 this.powerOfTwos = [value];
4295 }
4296 /**
4297 * Returns the big integer itself.
4298 */
4299 getValue() {
4300 return this.powerOfTwos[0];
4301 }
4302 /**
4303 * Computes the value for `num * b`, where `num` is a JS number and `b` is a big integer. The
4304 * value for `b` is represented by a storage model that is optimized for this computation.
4305 *
4306 * This operation is implemented in N(log2(num)) by continuous halving of the number, where the
4307 * least-significant bit (LSB) is tested in each iteration. If the bit is set, the bit's index is
4308 * used as exponent into the power-of-two multiplication of `b`.
4309 *
4310 * As an example, consider the multiplication num=42, b=1337. In binary 42 is 0b00101010 and the
4311 * algorithm unrolls into the following iterations:
4312 *
4313 * Iteration | num | LSB | b * 2^iter | Add? | product
4314 * -----------|------------|------|------------|------|--------
4315 * 0 | 0b00101010 | 0 | 1337 | No | 0
4316 * 1 | 0b00010101 | 1 | 2674 | Yes | 2674
4317 * 2 | 0b00001010 | 0 | 5348 | No | 2674
4318 * 3 | 0b00000101 | 1 | 10696 | Yes | 13370
4319 * 4 | 0b00000010 | 0 | 21392 | No | 13370
4320 * 5 | 0b00000001 | 1 | 42784 | Yes | 56154
4321 * 6 | 0b00000000 | 0 | 85568 | No | 56154
4322 *
4323 * The computed product of 56154 is indeed the correct result.
4324 *
4325 * The `BigIntForMultiplication` representation for a big integer provides memoized access to the
4326 * power-of-two values to reduce the workload in computing those values.
4327 */
4328 multiplyBy(num) {
4329 const product = BigInteger.zero();
4330 this.multiplyByAndAddTo(num, product);
4331 return product;
4332 }
4333 /**
4334 * See `multiplyBy()` for details. This function allows for the computed product to be added
4335 * directly to the provided result big integer.
4336 */
4337 multiplyByAndAddTo(num, result) {
4338 for (let exponent = 0; num !== 0; num = num >>> 1, exponent++) {
4339 if (num & 1) {
4340 const value = this.getMultipliedByPowerOfTwo(exponent);
4341 result.addToSelf(value);
4342 }
4343 }
4344 }
4345 /**
4346 * Computes and memoizes the big integer value for `this.number * 2^exponent`.
4347 */
4348 getMultipliedByPowerOfTwo(exponent) {
4349 // Compute the powers up until the requested exponent, where each value is computed from its
4350 // predecessor. This is simple as `this.number * 2^(exponent - 1)` only has to be doubled (i.e.
4351 // added to itself) to reach `this.number * 2^exponent`.
4352 for (let i = this.powerOfTwos.length; i <= exponent; i++) {
4353 const previousPower = this.powerOfTwos[i - 1];
4354 this.powerOfTwos[i] = previousPower.add(previousPower);
4355 }
4356 return this.powerOfTwos[exponent];
4357 }
4358 }
4359 /**
4360 * Represents an exponentiation operation for the provided base, of which exponents are computed and
4361 * memoized. The results are represented by a `BigIntForMultiplication` which is tailored for
4362 * multiplication operations by memoizing the power-of-twos. This effectively results in a matrix
4363 * representation that is lazily computed upon request.
4364 */
4365 class BigIntExponentiation {
4366 constructor(base) {
4367 this.base = base;
4368 this.exponents = [new BigIntForMultiplication(BigInteger.one())];
4369 }
4370 /**
4371 * Compute the value for `this.base^exponent`, resulting in a big integer that is optimized for
4372 * further multiplication operations.
4373 */
4374 toThePowerOf(exponent) {
4375 // Compute the results up until the requested exponent, where every value is computed from its
4376 // predecessor. This is because `this.base^(exponent - 1)` only has to be multiplied by `base`
4377 // to reach `this.base^exponent`.
4378 for (let i = this.exponents.length; i <= exponent; i++) {
4379 const value = this.exponents[i - 1].multiplyBy(this.base);
4380 this.exponents[i] = new BigIntForMultiplication(value);
4381 }
4382 return this.exponents[exponent];
4383 }
4384 }
4385
4386 /**
4387 * @license
4388 * Copyright Google LLC All Rights Reserved.
4389 *
4390 * Use of this source code is governed by an MIT-style license that can be
4391 * found in the LICENSE file at https://angular.io/license
4392 */
4393 /**
4394 * Compute the message id using the XLIFF1 digest.
4395 */
4396 function computeDigest(message) {
4397 return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
4398 }
4399 /**
4400 * Return the message id or compute it using the XLIFF2/XMB/$localize digest.
4401 */
4402 function decimalDigest(message) {
4403 return message.id || computeDecimalDigest(message);
4404 }
4405 /**
4406 * Compute the message id using the XLIFF2/XMB/$localize digest.
4407 */
4408 function computeDecimalDigest(message) {
4409 const visitor = new _SerializerIgnoreIcuExpVisitor();
4410 const parts = message.nodes.map(a => a.visit(visitor, null));
4411 return computeMsgId(parts.join(''), message.meaning);
4412 }
4413 /**
4414 * Serialize the i18n ast to something xml-like in order to generate an UID.
4415 *
4416 * The visitor is also used in the i18n parser tests
4417 *
4418 * @internal
4419 */
4420 class _SerializerVisitor {
4421 visitText(text, context) {
4422 return text.value;
4423 }
4424 visitContainer(container, context) {
4425 return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
4426 }
4427 visitIcu(icu, context) {
4428 const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
4429 return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`;
4430 }
4431 visitTagPlaceholder(ph, context) {
4432 return ph.isVoid ?
4433 `<ph tag name="${ph.startName}"/>` :
4434 `<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
4435 }
4436 visitPlaceholder(ph, context) {
4437 return ph.value ? `<ph name="${ph.name}">${ph.value}</ph>` : `<ph name="${ph.name}"/>`;
4438 }
4439 visitIcuPlaceholder(ph, context) {
4440 return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
4441 }
4442 }
4443 const serializerVisitor = new _SerializerVisitor();
4444 function serializeNodes(nodes) {
4445 return nodes.map(a => a.visit(serializerVisitor, null));
4446 }
4447 /**
4448 * Serialize the i18n ast to something xml-like in order to generate an UID.
4449 *
4450 * Ignore the ICU expressions so that message IDs stays identical if only the expression changes.
4451 *
4452 * @internal
4453 */
4454 class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor {
4455 visitIcu(icu, context) {
4456 let strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
4457 // Do not take the expression into account
4458 return `{${icu.type}, ${strCases.join(', ')}}`;
4459 }
4460 }
4461 /**
4462 * Compute the SHA1 of the given string
4463 *
4464 * see https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
4465 *
4466 * WARNING: this function has not been designed not tested with security in mind.
4467 * DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT.
4468 */
4469 function sha1(str) {
4470 const utf8 = utf8Encode(str);
4471 const words32 = bytesToWords32(utf8, Endian.Big);
4472 const len = utf8.length * 8;
4473 const w = newArray(80);
4474 let a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476, e = 0xc3d2e1f0;
4475 words32[len >> 5] |= 0x80 << (24 - len % 32);
4476 words32[((len + 64 >> 9) << 4) + 15] = len;
4477 for (let i = 0; i < words32.length; i += 16) {
4478 const h0 = a, h1 = b, h2 = c, h3 = d, h4 = e;
4479 for (let j = 0; j < 80; j++) {
4480 if (j < 16) {
4481 w[j] = words32[i + j];
4482 }
4483 else {
4484 w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
4485 }
4486 const fkVal = fk(j, b, c, d);
4487 const f = fkVal[0];
4488 const k = fkVal[1];
4489 const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
4490 e = d;
4491 d = c;
4492 c = rol32(b, 30);
4493 b = a;
4494 a = temp;
4495 }
4496 a = add32(a, h0);
4497 b = add32(b, h1);
4498 c = add32(c, h2);
4499 d = add32(d, h3);
4500 e = add32(e, h4);
4501 }
4502 return bytesToHexString(words32ToByteString([a, b, c, d, e]));
4503 }
4504 function fk(index, b, c, d) {
4505 if (index < 20) {
4506 return [(b & c) | (~b & d), 0x5a827999];
4507 }
4508 if (index < 40) {
4509 return [b ^ c ^ d, 0x6ed9eba1];
4510 }
4511 if (index < 60) {
4512 return [(b & c) | (b & d) | (c & d), 0x8f1bbcdc];
4513 }
4514 return [b ^ c ^ d, 0xca62c1d6];
4515 }
4516 /**
4517 * Compute the fingerprint of the given string
4518 *
4519 * The output is 64 bit number encoded as a decimal string
4520 *
4521 * based on:
4522 * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
4523 */
4524 function fingerprint(str) {
4525 const utf8 = utf8Encode(str);
4526 let hi = hash32(utf8, 0);
4527 let lo = hash32(utf8, 102072);
4528 if (hi == 0 && (lo == 0 || lo == 1)) {
4529 hi = hi ^ 0x130f9bef;
4530 lo = lo ^ -0x6b5f56d8;
4531 }
4532 return [hi, lo];
4533 }
4534 function computeMsgId(msg, meaning = '') {
4535 let msgFingerprint = fingerprint(msg);
4536 if (meaning) {
4537 const meaningFingerprint = fingerprint(meaning);
4538 msgFingerprint = add64(rol64(msgFingerprint, 1), meaningFingerprint);
4539 }
4540 const hi = msgFingerprint[0];
4541 const lo = msgFingerprint[1];
4542 return wordsToDecimalString(hi & 0x7fffffff, lo);
4543 }
4544 function hash32(bytes, c) {
4545 let a = 0x9e3779b9, b = 0x9e3779b9;
4546 let i;
4547 const len = bytes.length;
4548 for (i = 0; i + 12 <= len; i += 12) {
4549 a = add32(a, wordAt(bytes, i, Endian.Little));
4550 b = add32(b, wordAt(bytes, i + 4, Endian.Little));
4551 c = add32(c, wordAt(bytes, i + 8, Endian.Little));
4552 const res = mix(a, b, c);
4553 a = res[0], b = res[1], c = res[2];
4554 }
4555 a = add32(a, wordAt(bytes, i, Endian.Little));
4556 b = add32(b, wordAt(bytes, i + 4, Endian.Little));
4557 // the first byte of c is reserved for the length
4558 c = add32(c, len);
4559 c = add32(c, wordAt(bytes, i + 8, Endian.Little) << 8);
4560 return mix(a, b, c)[2];
4561 }
4562 // clang-format off
4563 function mix(a, b, c) {
4564 a = sub32(a, b);
4565 a = sub32(a, c);
4566 a ^= c >>> 13;
4567 b = sub32(b, c);
4568 b = sub32(b, a);
4569 b ^= a << 8;
4570 c = sub32(c, a);
4571 c = sub32(c, b);
4572 c ^= b >>> 13;
4573 a = sub32(a, b);
4574 a = sub32(a, c);
4575 a ^= c >>> 12;
4576 b = sub32(b, c);
4577 b = sub32(b, a);
4578 b ^= a << 16;
4579 c = sub32(c, a);
4580 c = sub32(c, b);
4581 c ^= b >>> 5;
4582 a = sub32(a, b);
4583 a = sub32(a, c);
4584 a ^= c >>> 3;
4585 b = sub32(b, c);
4586 b = sub32(b, a);
4587 b ^= a << 10;
4588 c = sub32(c, a);
4589 c = sub32(c, b);
4590 c ^= b >>> 15;
4591 return [a, b, c];
4592 }
4593 // clang-format on
4594 // Utils
4595 var Endian;
4596 (function (Endian) {
4597 Endian[Endian["Little"] = 0] = "Little";
4598 Endian[Endian["Big"] = 1] = "Big";
4599 })(Endian || (Endian = {}));
4600 function add32(a, b) {
4601 return add32to64(a, b)[1];
4602 }
4603 function add32to64(a, b) {
4604 const low = (a & 0xffff) + (b & 0xffff);
4605 const high = (a >>> 16) + (b >>> 16) + (low >>> 16);
4606 return [high >>> 16, (high << 16) | (low & 0xffff)];
4607 }
4608 function add64(a, b) {
4609 const ah = a[0], al = a[1];
4610 const bh = b[0], bl = b[1];
4611 const result = add32to64(al, bl);
4612 const carry = result[0];
4613 const l = result[1];
4614 const h = add32(add32(ah, bh), carry);
4615 return [h, l];
4616 }
4617 function sub32(a, b) {
4618 const low = (a & 0xffff) - (b & 0xffff);
4619 const high = (a >> 16) - (b >> 16) + (low >> 16);
4620 return (high << 16) | (low & 0xffff);
4621 }
4622 // Rotate a 32b number left `count` position
4623 function rol32(a, count) {
4624 return (a << count) | (a >>> (32 - count));
4625 }
4626 // Rotate a 64b number left `count` position
4627 function rol64(num, count) {
4628 const hi = num[0], lo = num[1];
4629 const h = (hi << count) | (lo >>> (32 - count));
4630 const l = (lo << count) | (hi >>> (32 - count));
4631 return [h, l];
4632 }
4633 function bytesToWords32(bytes, endian) {
4634 const size = (bytes.length + 3) >>> 2;
4635 const words32 = [];
4636 for (let i = 0; i < size; i++) {
4637 words32[i] = wordAt(bytes, i * 4, endian);
4638 }
4639 return words32;
4640 }
4641 function byteAt(bytes, index) {
4642 return index >= bytes.length ? 0 : bytes[index];
4643 }
4644 function wordAt(bytes, index, endian) {
4645 let word = 0;
4646 if (endian === Endian.Big) {
4647 for (let i = 0; i < 4; i++) {
4648 word += byteAt(bytes, index + i) << (24 - 8 * i);
4649 }
4650 }
4651 else {
4652 for (let i = 0; i < 4; i++) {
4653 word += byteAt(bytes, index + i) << 8 * i;
4654 }
4655 }
4656 return word;
4657 }
4658 function words32ToByteString(words32) {
4659 return words32.reduce((bytes, word) => bytes.concat(word32ToByteString(word)), []);
4660 }
4661 function word32ToByteString(word) {
4662 let bytes = [];
4663 for (let i = 0; i < 4; i++) {
4664 bytes.push((word >>> 8 * (3 - i)) & 0xff);
4665 }
4666 return bytes;
4667 }
4668 function bytesToHexString(bytes) {
4669 let hex = '';
4670 for (let i = 0; i < bytes.length; i++) {
4671 const b = byteAt(bytes, i);
4672 hex += (b >>> 4).toString(16) + (b & 0x0f).toString(16);
4673 }
4674 return hex.toLowerCase();
4675 }
4676 /**
4677 * Create a shared exponentiation pool for base-256 computations. This shared pool provides memoized
4678 * power-of-256 results with memoized power-of-two computations for efficient multiplication.
4679 *
4680 * For our purposes, this can be safely stored as a global without memory concerns. The reason is
4681 * that we encode two words, so only need the 0th (for the low word) and 4th (for the high word)
4682 * exponent.
4683 */
4684 const base256 = new BigIntExponentiation(256);
4685 /**
4686 * Represents two 32-bit words as a single decimal number. This requires a big integer storage
4687 * model as JS numbers are not accurate enough to represent the 64-bit number.
4688 *
4689 * Based on https://www.danvk.org/hex2dec.html
4690 */
4691 function wordsToDecimalString(hi, lo) {
4692 // Encode the four bytes in lo in the lower digits of the decimal number.
4693 // Note: the multiplication results in lo itself but represented by a big integer using its
4694 // decimal digits.
4695 const decimal = base256.toThePowerOf(0).multiplyBy(lo);
4696 // Encode the four bytes in hi above the four lo bytes. lo is a maximum of (2^8)^4, which is why
4697 // this multiplication factor is applied.
4698 base256.toThePowerOf(4).multiplyByAndAddTo(hi, decimal);
4699 return decimal.toString();
4700 }
4701
4702 /**
4703 * @license
4704 * Copyright Google LLC All Rights Reserved.
4705 *
4706 * Use of this source code is governed by an MIT-style license that can be
4707 * found in the LICENSE file at https://angular.io/license
4708 */
4709 // XMB/XTB placeholders can only contain A-Z, 0-9 and _
4710 function toPublicName(internalName) {
4711 return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_');
4712 }
4713
4714 /**
4715 * @license
4716 * Copyright Google LLC All Rights Reserved.
4717 *
4718 * Use of this source code is governed by an MIT-style license that can be
4719 * found in the LICENSE file at https://angular.io/license
4720 */
4721 /* Closure variables holding messages must be named `MSG_[A-Z0-9]+` */
4722 const CLOSURE_TRANSLATION_VAR_PREFIX = 'MSG_';
4723 /**
4724 * Prefix for non-`goog.getMsg` i18n-related vars.
4725 * Note: the prefix uses lowercase characters intentionally due to a Closure behavior that
4726 * considers variables like `I18N_0` as constants and throws an error when their value changes.
4727 */
4728 const TRANSLATION_VAR_PREFIX = 'i18n_';
4729 /** Name of the i18n attributes **/
4730 const I18N_ATTR = 'i18n';
4731 const I18N_ATTR_PREFIX = 'i18n-';
4732 /** Prefix of var expressions used in ICUs */
4733 const I18N_ICU_VAR_PREFIX = 'VAR_';
4734 /** Prefix of ICU expressions for post processing */
4735 const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
4736 /** Placeholder wrapper for i18n expressions **/
4737 const I18N_PLACEHOLDER_SYMBOL = '�';
4738 function isI18nAttribute(name) {
4739 return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
4740 }
4741 function isI18nRootNode(meta) {
4742 return meta instanceof Message;
4743 }
4744 function isSingleI18nIcu(meta) {
4745 return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu$1;
4746 }
4747 function hasI18nMeta(node) {
4748 return !!node.i18n;
4749 }
4750 function hasI18nAttrs(element) {
4751 return element.attrs.some((attr) => isI18nAttribute(attr.name));
4752 }
4753 function icuFromI18nMessage(message) {
4754 return message.nodes[0];
4755 }
4756 function wrapI18nPlaceholder(content, contextId = 0) {
4757 const blockId = contextId > 0 ? `:${contextId}` : '';
4758 return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`;
4759 }
4760 function assembleI18nBoundString(strings, bindingStartIndex = 0, contextId = 0) {
4761 if (!strings.length)
4762 return '';
4763 let acc = '';
4764 const lastIdx = strings.length - 1;
4765 for (let i = 0; i < lastIdx; i++) {
4766 acc += `${strings[i]}${wrapI18nPlaceholder(bindingStartIndex + i, contextId)}`;
4767 }
4768 acc += strings[lastIdx];
4769 return acc;
4770 }
4771 function getSeqNumberGenerator(startsAt = 0) {
4772 let current = startsAt;
4773 return () => current++;
4774 }
4775 function placeholdersToParams(placeholders) {
4776 const params = {};
4777 placeholders.forEach((values, key) => {
4778 params[key] = literal(values.length > 1 ? `[${values.join('|')}]` : values[0]);
4779 });
4780 return params;
4781 }
4782 function updatePlaceholderMap(map, name, ...values) {
4783 const current = map.get(name) || [];
4784 current.push(...values);
4785 map.set(name, current);
4786 }
4787 function assembleBoundTextPlaceholders(meta, bindingStartIndex = 0, contextId = 0) {
4788 const startIdx = bindingStartIndex;
4789 const placeholders = new Map();
4790 const node = meta instanceof Message ? meta.nodes.find(node => node instanceof Container) : meta;
4791 if (node) {
4792 node
4793 .children
4794 .filter((child) => child instanceof Placeholder)
4795 .forEach((child, idx) => {
4796 const content = wrapI18nPlaceholder(startIdx + idx, contextId);
4797 updatePlaceholderMap(placeholders, child.name, content);
4798 });
4799 }
4800 return placeholders;
4801 }
4802 /**
4803 * Format the placeholder names in a map of placeholders to expressions.
4804 *
4805 * The placeholder names are converted from "internal" format (e.g. `START_TAG_DIV_1`) to "external"
4806 * format (e.g. `startTagDiv_1`).
4807 *
4808 * @param params A map of placeholder names to expressions.
4809 * @param useCamelCase whether to camelCase the placeholder name when formatting.
4810 * @returns A new map of formatted placeholder names to expressions.
4811 */
4812 function i18nFormatPlaceholderNames(params = {}, useCamelCase) {
4813 const _params = {};
4814 if (params && Object.keys(params).length) {
4815 Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key, useCamelCase)] = params[key]);
4816 }
4817 return _params;
4818 }
4819 /**
4820 * Converts internal placeholder names to public-facing format
4821 * (for example to use in goog.getMsg call).
4822 * Example: `START_TAG_DIV_1` is converted to `startTagDiv_1`.
4823 *
4824 * @param name The placeholder name that should be formatted
4825 * @returns Formatted placeholder name
4826 */
4827 function formatI18nPlaceholderName(name, useCamelCase = true) {
4828 const publicName = toPublicName(name);
4829 if (!useCamelCase) {
4830 return publicName;
4831 }
4832 const chunks = publicName.split('_');
4833 if (chunks.length === 1) {
4834 // if no "_" found - just lowercase the value
4835 return name.toLowerCase();
4836 }
4837 let postfix;
4838 // eject last element if it's a number
4839 if (/^\d+$/.test(chunks[chunks.length - 1])) {
4840 postfix = chunks.pop();
4841 }
4842 let raw = chunks.shift().toLowerCase();
4843 if (chunks.length) {
4844 raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join('');
4845 }
4846 return postfix ? `${raw}_${postfix}` : raw;
4847 }
4848 /**
4849 * Generates a prefix for translation const name.
4850 *
4851 * @param extra Additional local prefix that should be injected into translation var name
4852 * @returns Complete translation const prefix
4853 */
4854 function getTranslationConstPrefix(extra) {
4855 return `${CLOSURE_TRANSLATION_VAR_PREFIX}${extra}`.toUpperCase();
4856 }
4857 /**
4858 * Generate AST to declare a variable. E.g. `var I18N_1;`.
4859 * @param variable the name of the variable to declare.
4860 */
4861 function declareI18nVariable(variable) {
4862 return new DeclareVarStmt(variable.name, undefined, INFERRED_TYPE, undefined, variable.sourceSpan);
4863 }
4864
4865 /**
4866 * @license
4867 * Copyright Google LLC All Rights Reserved.
4868 *
4869 * Use of this source code is governed by an MIT-style license that can be
4870 * found in the LICENSE file at https://angular.io/license
4871 */
4872 /**
4873 * Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in
4874 * quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may
4875 * bot work in some cases when object keys are mangled by minifier.
4876 *
4877 * TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with
4878 * inputs that contain potentially unsafe chars.
4879 */
4880 const UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/;
4881 /** Name of the temporary to use during data binding */
4882 const TEMPORARY_NAME = '_t';
4883 /** Name of the context parameter passed into a template function */
4884 const CONTEXT_NAME = 'ctx';
4885 /** Name of the RenderFlag passed into a template function */
4886 const RENDER_FLAGS = 'rf';
4887 /** The prefix reference variables */
4888 const REFERENCE_PREFIX = '_r';
4889 /** The name of the implicit context reference */
4890 const IMPLICIT_REFERENCE = '$implicit';
4891 /** Non bindable attribute name **/
4892 const NON_BINDABLE_ATTR = 'ngNonBindable';
4893 /**
4894 * Creates an allocator for a temporary variable.
4895 *
4896 * A variable declaration is added to the statements the first time the allocator is invoked.
4897 */
4898 function temporaryAllocator(statements, name) {
4899 let temp = null;
4900 return () => {
4901 if (!temp) {
4902 statements.push(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE));
4903 temp = variable(name);
4904 }
4905 return temp;
4906 };
4907 }
4908 function unsupported(feature) {
4909 if (this) {
4910 throw new Error(`Builder ${this.constructor.name} doesn't support ${feature} yet`);
4911 }
4912 throw new Error(`Feature ${feature} is not supported yet`);
4913 }
4914 function invalid$1(arg) {
4915 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
4916 }
4917 function asLiteral(value) {
4918 if (Array.isArray(value)) {
4919 return literalArr(value.map(asLiteral));
4920 }
4921 return literal(value, INFERRED_TYPE);
4922 }
4923 function conditionallyCreateMapObjectLiteral(keys, keepDeclared) {
4924 if (Object.getOwnPropertyNames(keys).length > 0) {
4925 return mapToExpression(keys, keepDeclared);
4926 }
4927 return null;
4928 }
4929 function mapToExpression(map, keepDeclared) {
4930 return literalMap(Object.getOwnPropertyNames(map).map(key => {
4931 // canonical syntax: `dirProp: publicProp`
4932 // if there is no `:`, use dirProp = elProp
4933 const value = map[key];
4934 let declaredName;
4935 let publicName;
4936 let minifiedName;
4937 let needsDeclaredName;
4938 if (Array.isArray(value)) {
4939 [publicName, declaredName] = value;
4940 minifiedName = key;
4941 needsDeclaredName = publicName !== declaredName;
4942 }
4943 else {
4944 [declaredName, publicName] = splitAtColon(key, [key, value]);
4945 minifiedName = declaredName;
4946 // Only include the declared name if extracted from the key, i.e. the key contains a colon.
4947 // Otherwise the declared name should be omitted even if it is different from the public name,
4948 // as it may have already been minified.
4949 needsDeclaredName = publicName !== declaredName && key.includes(':');
4950 }
4951 return {
4952 key: minifiedName,
4953 // put quotes around keys that contain potentially unsafe characters
4954 quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName),
4955 value: (keepDeclared && needsDeclaredName) ?
4956 literalArr([asLiteral(publicName), asLiteral(declaredName)]) :
4957 asLiteral(publicName)
4958 };
4959 }));
4960 }
4961 /**
4962 * Remove trailing null nodes as they are implied.
4963 */
4964 function trimTrailingNulls(parameters) {
4965 while (isNull(parameters[parameters.length - 1])) {
4966 parameters.pop();
4967 }
4968 return parameters;
4969 }
4970 function getQueryPredicate(query, constantPool) {
4971 if (Array.isArray(query.predicate)) {
4972 let predicate = [];
4973 query.predicate.forEach((selector) => {
4974 // Each item in predicates array may contain strings with comma-separated refs
4975 // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them
4976 // as separate array entities
4977 const selectors = selector.split(',').map(token => literal(token.trim()));
4978 predicate.push(...selectors);
4979 });
4980 return constantPool.getConstLiteral(literalArr(predicate), true);
4981 }
4982 else {
4983 return query.predicate;
4984 }
4985 }
4986 /**
4987 * A representation for an object literal used during codegen of definition objects. The generic
4988 * type `T` allows to reference a documented type of the generated structure, such that the
4989 * property names that are set can be resolved to their documented declaration.
4990 */
4991 class DefinitionMap {
4992 constructor() {
4993 this.values = [];
4994 }
4995 set(key, value) {
4996 if (value) {
4997 this.values.push({ key: key, value, quoted: false });
4998 }
4999 }
5000 toLiteralMap() {
5001 return literalMap(this.values);
5002 }
5003 }
5004 /**
5005 * Extract a map of properties to values for a given element or template node, which can be used
5006 * by the directive matching machinery.
5007 *
5008 * @param elOrTpl the element or template in question
5009 * @return an object set up for directive matching. For attributes on the element/template, this
5010 * object maps a property name to its (static) value. For any bindings, this map simply maps the
5011 * property name to an empty string.
5012 */
5013 function getAttrsForDirectiveMatching(elOrTpl) {
5014 const attributesMap = {};
5015 if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') {
5016 elOrTpl.templateAttrs.forEach(a => attributesMap[a.name] = '');
5017 }
5018 else {
5019 elOrTpl.attributes.forEach(a => {
5020 if (!isI18nAttribute(a.name)) {
5021 attributesMap[a.name] = a.value;
5022 }
5023 });
5024 elOrTpl.inputs.forEach(i => {
5025 attributesMap[i.name] = '';
5026 });
5027 elOrTpl.outputs.forEach(o => {
5028 attributesMap[o.name] = '';
5029 });
5030 }
5031 return attributesMap;
5032 }
5033 /** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */
5034 function chainedInstruction(reference, calls, span) {
5035 let expression = importExpr(reference, null, span);
5036 if (calls.length > 0) {
5037 for (let i = 0; i < calls.length; i++) {
5038 expression = expression.callFn(calls[i], span);
5039 }
5040 }
5041 else {
5042 // Add a blank invocation, in case the `calls` array is empty.
5043 expression = expression.callFn([], span);
5044 }
5045 return expression;
5046 }
5047 /**
5048 * Gets the number of arguments expected to be passed to a generated instruction in the case of
5049 * interpolation instructions.
5050 * @param interpolation An interpolation ast
5051 */
5052 function getInterpolationArgsLength(interpolation) {
5053 const { expressions, strings } = interpolation;
5054 if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
5055 // If the interpolation has one interpolated value, but the prefix and suffix are both empty
5056 // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
5057 // `textInterpolate`.
5058 return 1;
5059 }
5060 else {
5061 return expressions.length + strings.length;
5062 }
5063 }
5064
5065 /**
5066 * @license
5067 * Copyright Google LLC All Rights Reserved.
5068 *
5069 * Use of this source code is governed by an MIT-style license that can be
5070 * found in the LICENSE file at https://angular.io/license
5071 */
5072 var R3FactoryDelegateType;
5073 (function (R3FactoryDelegateType) {
5074 R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class";
5075 R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function";
5076 R3FactoryDelegateType[R3FactoryDelegateType["Factory"] = 2] = "Factory";
5077 })(R3FactoryDelegateType || (R3FactoryDelegateType = {}));
5078 var R3FactoryTarget;
5079 (function (R3FactoryTarget) {
5080 R3FactoryTarget[R3FactoryTarget["Directive"] = 0] = "Directive";
5081 R3FactoryTarget[R3FactoryTarget["Component"] = 1] = "Component";
5082 R3FactoryTarget[R3FactoryTarget["Injectable"] = 2] = "Injectable";
5083 R3FactoryTarget[R3FactoryTarget["Pipe"] = 3] = "Pipe";
5084 R3FactoryTarget[R3FactoryTarget["NgModule"] = 4] = "NgModule";
5085 })(R3FactoryTarget || (R3FactoryTarget = {}));
5086 /**
5087 * Resolved type of a dependency.
5088 *
5089 * Occasionally, dependencies will have special significance which is known statically. In that
5090 * case the `R3ResolvedDependencyType` informs the factory generator that a particular dependency
5091 * should be generated specially (usually by calling a special injection function instead of the
5092 * standard one).
5093 */
5094 var R3ResolvedDependencyType;
5095 (function (R3ResolvedDependencyType) {
5096 /**
5097 * A normal token dependency.
5098 */
5099 R3ResolvedDependencyType[R3ResolvedDependencyType["Token"] = 0] = "Token";
5100 /**
5101 * The dependency is for an attribute.
5102 *
5103 * The token expression is a string representing the attribute name.
5104 */
5105 R3ResolvedDependencyType[R3ResolvedDependencyType["Attribute"] = 1] = "Attribute";
5106 /**
5107 * Injecting the `ChangeDetectorRef` token. Needs special handling when injected into a pipe.
5108 */
5109 R3ResolvedDependencyType[R3ResolvedDependencyType["ChangeDetectorRef"] = 2] = "ChangeDetectorRef";
5110 /**
5111 * An invalid dependency (no token could be determined). An error should be thrown at runtime.
5112 */
5113 R3ResolvedDependencyType[R3ResolvedDependencyType["Invalid"] = 3] = "Invalid";
5114 })(R3ResolvedDependencyType || (R3ResolvedDependencyType = {}));
5115 /**
5116 * Construct a factory function expression for the given `R3FactoryMetadata`.
5117 */
5118 function compileFactoryFunction(meta) {
5119 const t = variable('t');
5120 const statements = [];
5121 let ctorDepsType = NONE_TYPE;
5122 // The type to instantiate via constructor invocation. If there is no delegated factory, meaning
5123 // this type is always created by constructor invocation, then this is the type-to-create
5124 // parameter provided by the user (t) if specified, or the current type if not. If there is a
5125 // delegated factory (which is used to create the current type) then this is only the type-to-
5126 // create parameter (t).
5127 const typeForCtor = !isDelegatedMetadata(meta) ?
5128 new BinaryOperatorExpr(BinaryOperator.Or, t, meta.internalType) :
5129 t;
5130 let ctorExpr = null;
5131 if (meta.deps !== null) {
5132 // There is a constructor (either explicitly or implicitly defined).
5133 if (meta.deps !== 'invalid') {
5134 ctorExpr = new InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.injectFn, meta.target === R3FactoryTarget.Pipe));
5135 ctorDepsType = createCtorDepsType(meta.deps);
5136 }
5137 }
5138 else {
5139 const baseFactory = variable(${meta.name}_BaseFactory`);
5140 const getInheritedFactory = importExpr(Identifiers$1.getInheritedFactory);
5141 const baseFactoryStmt = baseFactory
5142 .set(getInheritedFactory.callFn([meta.internalType], /* sourceSpan */ undefined, /* pure */ true))
5143 .toDeclStmt(INFERRED_TYPE, [StmtModifier.Exported, StmtModifier.Final]);
5144 statements.push(baseFactoryStmt);
5145 // There is no constructor, use the base class' factory to construct typeForCtor.
5146 ctorExpr = baseFactory.callFn([typeForCtor]);
5147 }
5148 const ctorExprFinal = ctorExpr;
5149 const body = [];
5150 let retExpr = null;
5151 function makeConditionalFactory(nonCtorExpr) {
5152 const r = variable('r');
5153 body.push(r.set(NULL_EXPR).toDeclStmt());
5154 let ctorStmt = null;
5155 if (ctorExprFinal !== null) {
5156 ctorStmt = r.set(ctorExprFinal).toStmt();
5157 }
5158 else {
5159 ctorStmt = importExpr(Identifiers$1.invalidFactory).callFn([]).toStmt();
5160 }
5161 body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()]));
5162 return r;
5163 }
5164 if (isDelegatedMetadata(meta) && meta.delegateType === R3FactoryDelegateType.Factory) {
5165 const delegateFactory = variable(${meta.name}_BaseFactory`);
5166 const getFactoryOf = importExpr(Identifiers$1.getFactoryOf);
5167 if (meta.delegate.isEquivalent(meta.internalType)) {
5168 throw new Error(`Illegal state: compiling factory that delegates to itself`);
5169 }
5170 const delegateFactoryStmt = delegateFactory.set(getFactoryOf.callFn([meta.delegate])).toDeclStmt(INFERRED_TYPE, [
5171 StmtModifier.Exported, StmtModifier.Final
5172 ]);
5173 statements.push(delegateFactoryStmt);
5174 retExpr = makeConditionalFactory(delegateFactory.callFn([]));
5175 }
5176 else if (isDelegatedMetadata(meta)) {
5177 // This type is created with a delegated factory. If a type parameter is not specified, call
5178 // the factory instead.
5179 const delegateArgs = injectDependencies(meta.delegateDeps, meta.injectFn, meta.target === R3FactoryTarget.Pipe);
5180 // Either call `new delegate(...)` or `delegate(...)` depending on meta.delegateType.
5181 const factoryExpr = new (meta.delegateType === R3FactoryDelegateType.Class ?
5182 InstantiateExpr :
5183 InvokeFunctionExpr)(meta.delegate, delegateArgs);
5184 retExpr = makeConditionalFactory(factoryExpr);
5185 }
5186 else if (isExpressionFactoryMetadata(meta)) {
5187 // TODO(alxhub): decide whether to lower the value here or in the caller
5188 retExpr = makeConditionalFactory(meta.expression);
5189 }
5190 else {
5191 retExpr = ctorExpr;
5192 }
5193 if (retExpr !== null) {
5194 body.push(new ReturnStatement(retExpr));
5195 }
5196 else {
5197 body.push(importExpr(Identifiers$1.invalidFactory).callFn([]).toStmt());
5198 }
5199 return {
5200 factory: fn([new FnParam('t', DYNAMIC_TYPE)], body, INFERRED_TYPE, undefined, `${meta.name}_Factory`),
5201 statements,
5202 type: expressionType(importExpr(Identifiers$1.FactoryDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType]))
5203 };
5204 }
5205 function injectDependencies(deps, injectFn, isPipe) {
5206 return deps.map((dep, index) => compileInjectDependency(dep, injectFn, isPipe, index));
5207 }
5208 function compileInjectDependency(dep, injectFn, isPipe, index) {
5209 // Interpret the dependency according to its resolved type.
5210 switch (dep.resolved) {
5211 case R3ResolvedDependencyType.Token:
5212 case R3ResolvedDependencyType.ChangeDetectorRef:
5213 // Build up the injection flags according to the metadata.
5214 const flags = 0 /* Default */ | (dep.self ? 2 /* Self */ : 0) |
5215 (dep.skipSelf ? 4 /* SkipSelf */ : 0) | (dep.host ? 1 /* Host */ : 0) |
5216 (dep.optional ? 8 /* Optional */ : 0);
5217 // If this dependency is optional or otherwise has non-default flags, then additional
5218 // parameters describing how to inject the dependency must be passed to the inject function
5219 // that's being used.
5220 let flagsParam = (flags !== 0 /* Default */ || dep.optional) ? literal(flags) : null;
5221 // We have a separate instruction for injecting ChangeDetectorRef into a pipe.
5222 if (isPipe && dep.resolved === R3ResolvedDependencyType.ChangeDetectorRef) {
5223 return importExpr(Identifiers$1.injectPipeChangeDetectorRef).callFn(flagsParam ? [flagsParam] : []);
5224 }
5225 // Build up the arguments to the injectFn call.
5226 const injectArgs = [dep.token];
5227 if (flagsParam) {
5228 injectArgs.push(flagsParam);
5229 }
5230 return importExpr(injectFn).callFn(injectArgs);
5231 case R3ResolvedDependencyType.Attribute:
5232 // In the case of attributes, the attribute name in question is given as the token.
5233 return importExpr(Identifiers$1.injectAttribute).callFn([dep.token]);
5234 case R3ResolvedDependencyType.Invalid:
5235 return importExpr(Identifiers$1.invalidFactoryDep).callFn([literal(index)]);
5236 default:
5237 return unsupported(`Unknown R3ResolvedDependencyType: ${R3ResolvedDependencyType[dep.resolved]}`);
5238 }
5239 }
5240 function createCtorDepsType(deps) {
5241 let hasTypes = false;
5242 const attributeTypes = deps.map(dep => {
5243 const type = createCtorDepType(dep);
5244 if (type !== null) {
5245 hasTypes = true;
5246 return type;
5247 }
5248 else {
5249 return literal(null);
5250 }
5251 });
5252 if (hasTypes) {
5253 return expressionType(literalArr(attributeTypes));
5254 }
5255 else {
5256 return NONE_TYPE;
5257 }
5258 }
5259 function createCtorDepType(dep) {
5260 const entries = [];
5261 if (dep.resolved === R3ResolvedDependencyType.Attribute) {
5262 if (dep.attribute !== null) {
5263 entries.push({ key: 'attribute', value: dep.attribute, quoted: false });
5264 }
5265 }
5266 if (dep.optional) {
5267 entries.push({ key: 'optional', value: literal(true), quoted: false });
5268 }
5269 if (dep.host) {
5270 entries.push({ key: 'host', value: literal(true), quoted: false });
5271 }
5272 if (dep.self) {
5273 entries.push({ key: 'self', value: literal(true), quoted: false });
5274 }
5275 if (dep.skipSelf) {
5276 entries.push({ key: 'skipSelf', value: literal(true), quoted: false });
5277 }
5278 return entries.length > 0 ? literalMap(entries) : null;
5279 }
5280 function isDelegatedMetadata(meta) {
5281 return meta.delegateType !== undefined;
5282 }
5283 function isExpressionFactoryMetadata(meta) {
5284 return meta.expression !== undefined;
5285 }
5286
5287 /**
5288 * @license
5289 * Copyright Google LLC All Rights Reserved.
5290 *
5291 * Use of this source code is governed by an MIT-style license that can be
5292 * found in the LICENSE file at https://angular.io/license
5293 */
5294 function compileInjectable(meta) {
5295 let result = null;
5296 const factoryMeta = {
5297 name: meta.name,
5298 type: meta.type,
5299 internalType: meta.internalType,
5300 typeArgumentCount: meta.typeArgumentCount,
5301 deps: [],
5302 injectFn: Identifiers.inject,
5303 target: R3FactoryTarget.Injectable,
5304 };
5305 if (meta.useClass !== undefined) {
5306 // meta.useClass has two modes of operation. Either deps are specified, in which case `new` is
5307 // used to instantiate the class with dependencies injected, or deps are not specified and
5308 // the factory of the class is used to instantiate it.
5309 //
5310 // A special case exists for useClass: Type where Type is the injectable type itself and no
5311 // deps are specified, in which case 'useClass' is effectively ignored.
5312 const useClassOnSelf = meta.useClass.isEquivalent(meta.internalType);
5313 let deps = undefined;
5314 if (meta.userDeps !== undefined) {
5315 deps = meta.userDeps;
5316 }
5317 if (deps !== undefined) {
5318 // factory: () => new meta.useClass(...deps)
5319 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useClass, delegateDeps: deps, delegateType: R3FactoryDelegateType.Class }));
5320 }
5321 else if (useClassOnSelf) {
5322 result = compileFactoryFunction(factoryMeta);
5323 }
5324 else {
5325 result = delegateToFactory(meta.type.value, meta.useClass);
5326 }
5327 }
5328 else if (meta.useFactory !== undefined) {
5329 if (meta.userDeps !== undefined) {
5330 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useFactory, delegateDeps: meta.userDeps || [], delegateType: R3FactoryDelegateType.Function }));
5331 }
5332 else {
5333 result = {
5334 statements: [],
5335 factory: fn([], [new ReturnStatement(meta.useFactory.callFn([]))])
5336 };
5337 }
5338 }
5339 else if (meta.useValue !== undefined) {
5340 // Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for
5341 // client code because meta.useValue is an Expression which will be defined even if the actual
5342 // value is undefined.
5343 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: meta.useValue }));
5344 }
5345 else if (meta.useExisting !== undefined) {
5346 // useExisting is an `inject` call on the existing token.
5347 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: importExpr(Identifiers.inject).callFn([meta.useExisting]) }));
5348 }
5349 else {
5350 result = delegateToFactory(meta.type.value, meta.internalType);
5351 }
5352 const token = meta.internalType;
5353 const injectableProps = { token, factory: result.factory };
5354 // Only generate providedIn property if it has a non-null value
5355 if (meta.providedIn.value !== null) {
5356 injectableProps.providedIn = meta.providedIn;
5357 }
5358 const expression = importExpr(Identifiers.ɵɵdefineInjectable).callFn([mapToMapExpression(injectableProps)]);
5359 const type = new ExpressionType(importExpr(Identifiers.InjectableDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount)]));
5360 return {
5361 expression,
5362 type,
5363 statements: result.statements,
5364 };
5365 }
5366 function delegateToFactory(type, internalType) {
5367 return {
5368 statements: [],
5369 // If types are the same, we can generate `factory: type.ɵfac`
5370 // If types are different, we have to generate a wrapper function to ensure
5371 // the internal type has been resolved (`factory: function(t) { return type.ɵfac(t); }`)
5372 factory: type.node === internalType.node ?
5373 internalType.prop('ɵfac') :
5374 fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement(internalType.callMethod('ɵfac', [variable('t')]))])
5375 };
5376 }
5377
5378 /**
5379 * @license
5380 * Copyright Google LLC All Rights Reserved.
5381 *
5382 * Use of this source code is governed by an MIT-style license that can be
5383 * found in the LICENSE file at https://angular.io/license
5384 */
5385 function assertArrayOfStrings(identifier, value) {
5386 if (value == null) {
5387 return;
5388 }
5389 if (!Array.isArray(value)) {
5390 throw new Error(`Expected '${identifier}' to be an array of strings.`);
5391 }
5392 for (let i = 0; i < value.length; i += 1) {
5393 if (typeof value[i] !== 'string') {
5394 throw new Error(`Expected '${identifier}' to be an array of strings.`);
5395 }
5396 }
5397 }
5398 const UNUSABLE_INTERPOLATION_REGEXPS = [
5399 /^\s*$/,
5400 /[<>]/,
5401 /^[{}]$/,
5402 /&(#|[a-z])/i,
5403 /^\/\//,
5404 ];
5405 function assertInterpolationSymbols(identifier, value) {
5406 if (value != null && !(Array.isArray(value) && value.length == 2)) {
5407 throw new Error(`Expected '${identifier}' to be an array, [start, end].`);
5408 }
5409 else if (value != null) {
5410 const start = value[0];
5411 const end = value[1];
5412 // Check for unusable interpolation symbols
5413 UNUSABLE_INTERPOLATION_REGEXPS.forEach(regexp => {
5414 if (regexp.test(start) || regexp.test(end)) {
5415 throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`);
5416 }
5417 });
5418 }
5419 }
5420
5421 /**
5422 * @license
5423 * Copyright Google LLC All Rights Reserved.
5424 *
5425 * Use of this source code is governed by an MIT-style license that can be
5426 * found in the LICENSE file at https://angular.io/license
5427 */
5428 class InterpolationConfig {
5429 constructor(start, end) {
5430 this.start = start;
5431 this.end = end;
5432 }
5433 static fromArray(markers) {
5434 if (!markers) {
5435 return DEFAULT_INTERPOLATION_CONFIG;
5436 }
5437 assertInterpolationSymbols('interpolation', markers);
5438 return new InterpolationConfig(markers[0], markers[1]);
5439 }
5440 }
5441 const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}');
5442
5443 /**
5444 * @license
5445 * Copyright Google LLC All Rights Reserved.
5446 *
5447 * Use of this source code is governed by an MIT-style license that can be
5448 * found in the LICENSE file at https://angular.io/license
5449 */
5450 /**
5451 * In TypeScript, tagged template functions expect a "template object", which is an array of
5452 * "cooked" strings plus a `raw` property that contains an array of "raw" strings. This is
5453 * typically constructed with a function called `__makeTemplateObject(cooked, raw)`, but it may not
5454 * be available in all environments.
5455 *
5456 * This is a JavaScript polyfill that uses __makeTemplateObject when it's available, but otherwise
5457 * creates an inline helper with the same functionality.
5458 *
5459 * In the inline function, if `Object.defineProperty` is available we use that to attach the `raw`
5460 * array.
5461 */
5462 const makeTemplateObjectPolyfill = '(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})';
5463 class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
5464 constructor() {
5465 super(false);
5466 }
5467 visitDeclareClassStmt(stmt, ctx) {
5468 ctx.pushClass(stmt);
5469 this._visitClassConstructor(stmt, ctx);
5470 if (stmt.parent != null) {
5471 ctx.print(stmt, `${stmt.name}.prototype = Object.create(`);
5472 stmt.parent.visitExpression(this, ctx);
5473 ctx.println(stmt, `.prototype);`);
5474 }
5475 stmt.getters.forEach((getter) => this._visitClassGetter(stmt, getter, ctx));
5476 stmt.methods.forEach((method) => this._visitClassMethod(stmt, method, ctx));
5477 ctx.popClass();
5478 return null;
5479 }
5480 _visitClassConstructor(stmt, ctx) {
5481 ctx.print(stmt, `function ${stmt.name}(`);
5482 if (stmt.constructorMethod != null) {
5483 this._visitParams(stmt.constructorMethod.params, ctx);
5484 }
5485 ctx.println(stmt, `) {`);
5486 ctx.incIndent();
5487 if (stmt.constructorMethod != null) {
5488 if (stmt.constructorMethod.body.length > 0) {
5489 ctx.println(stmt, `var self = this;`);
5490 this.visitAllStatements(stmt.constructorMethod.body, ctx);
5491 }
5492 }
5493 ctx.decIndent();
5494 ctx.println(stmt, `}`);
5495 }
5496 _visitClassGetter(stmt, getter, ctx) {
5497 ctx.println(stmt, `Object.defineProperty(${stmt.name}.prototype, '${getter.name}', { get: function() {`);
5498 ctx.incIndent();
5499 if (getter.body.length > 0) {
5500 ctx.println(stmt, `var self = this;`);
5501 this.visitAllStatements(getter.body, ctx);
5502 }
5503 ctx.decIndent();
5504 ctx.println(stmt, `}});`);
5505 }
5506 _visitClassMethod(stmt, method, ctx) {
5507 ctx.print(stmt, `${stmt.name}.prototype.${method.name} = function(`);
5508 this._visitParams(method.params, ctx);
5509 ctx.println(stmt, `) {`);
5510 ctx.incIndent();
5511 if (method.body.length > 0) {
5512 ctx.println(stmt, `var self = this;`);
5513 this.visitAllStatements(method.body, ctx);
5514 }
5515 ctx.decIndent();
5516 ctx.println(stmt, `};`);
5517 }
5518 visitWrappedNodeExpr(ast, ctx) {
5519 throw new Error('Cannot emit a WrappedNodeExpr in Javascript.');
5520 }
5521 visitReadVarExpr(ast, ctx) {
5522 if (ast.builtin === BuiltinVar.This) {
5523 ctx.print(ast, 'self');
5524 }
5525 else if (ast.builtin === BuiltinVar.Super) {
5526 throw new Error(`'super' needs to be handled at a parent ast node, not at the variable level!`);
5527 }
5528 else {
5529 super.visitReadVarExpr(ast, ctx);
5530 }
5531 return null;
5532 }
5533 visitDeclareVarStmt(stmt, ctx) {
5534 ctx.print(stmt, `var ${stmt.name}`);
5535 if (stmt.value) {
5536 ctx.print(stmt, ' = ');
5537 stmt.value.visitExpression(this, ctx);
5538 }
5539 ctx.println(stmt, `;`);
5540 return null;
5541 }
5542 visitCastExpr(ast, ctx) {
5543 ast.value.visitExpression(this, ctx);
5544 return null;
5545 }
5546 visitInvokeFunctionExpr(expr, ctx) {
5547 const fnExpr = expr.fn;
5548 if (fnExpr instanceof ReadVarExpr && fnExpr.builtin === BuiltinVar.Super) {
5549 ctx.currentClass.parent.visitExpression(this, ctx);
5550 ctx.print(expr, `.call(this`);
5551 if (expr.args.length > 0) {
5552 ctx.print(expr, `, `);
5553 this.visitAllExpressions(expr.args, ctx, ',');
5554 }
5555 ctx.print(expr, `)`);
5556 }
5557 else {
5558 super.visitInvokeFunctionExpr(expr, ctx);
5559 }
5560 return null;
5561 }
5562 visitTaggedTemplateExpr(ast, ctx) {
5563 // The following convoluted piece of code is effectively the downlevelled equivalent of
5564 // ```
5565 // tag`...`
5566 // ```
5567 // which is effectively like:
5568 // ```
5569 // tag(__makeTemplateObject(cooked, raw), expression1, expression2, ...);
5570 // ```
5571 const elements = ast.template.elements;
5572 ast.tag.visitExpression(this, ctx);
5573 ctx.print(ast, `(${makeTemplateObjectPolyfill}(`);
5574 ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.text, false)).join(', ')}], `);
5575 ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.rawText, false)).join(', ')}])`);
5576 ast.template.expressions.forEach(expression => {
5577 ctx.print(ast, ', ');
5578 expression.visitExpression(this, ctx);
5579 });
5580 ctx.print(ast, ')');
5581 return null;
5582 }
5583 visitFunctionExpr(ast, ctx) {
5584 ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`);
5585 this._visitParams(ast.params, ctx);
5586 ctx.println(ast, `) {`);
5587 ctx.incIndent();
5588 this.visitAllStatements(ast.statements, ctx);
5589 ctx.decIndent();
5590 ctx.print(ast, `}`);
5591 return null;
5592 }
5593 visitDeclareFunctionStmt(stmt, ctx) {
5594 ctx.print(stmt, `function ${stmt.name}(`);
5595 this._visitParams(stmt.params, ctx);
5596 ctx.println(stmt, `) {`);
5597 ctx.incIndent();
5598 this.visitAllStatements(stmt.statements, ctx);
5599 ctx.decIndent();
5600 ctx.println(stmt, `}`);
5601 return null;
5602 }
5603 visitTryCatchStmt(stmt, ctx) {
5604 ctx.println(stmt, `try {`);
5605 ctx.incIndent();
5606 this.visitAllStatements(stmt.bodyStmts, ctx);
5607 ctx.decIndent();
5608 ctx.println(stmt, `} catch (${CATCH_ERROR_VAR$1.name}) {`);
5609 ctx.incIndent();
5610 const catchStmts = [CATCH_STACK_VAR$1.set(CATCH_ERROR_VAR$1.prop('stack')).toDeclStmt(null, [
5611 StmtModifier.Final
5612 ])].concat(stmt.catchStmts);
5613 this.visitAllStatements(catchStmts, ctx);
5614 ctx.decIndent();
5615 ctx.println(stmt, `}`);
5616 return null;
5617 }
5618 visitLocalizedString(ast, ctx) {
5619 // The following convoluted piece of code is effectively the downlevelled equivalent of
5620 // ```
5621 // $localize `...`
5622 // ```
5623 // which is effectively like:
5624 // ```
5625 // $localize(__makeTemplateObject(cooked, raw), expression1, expression2, ...);
5626 // ```
5627 ctx.print(ast, `$localize(${makeTemplateObjectPolyfill}(`);
5628 const parts = [ast.serializeI18nHead()];
5629 for (let i = 1; i < ast.messageParts.length; i++) {
5630 parts.push(ast.serializeI18nTemplatePart(i));
5631 }
5632 ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.cooked, false)).join(', ')}], `);
5633 ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.raw, false)).join(', ')}])`);
5634 ast.expressions.forEach(expression => {
5635 ctx.print(ast, ', ');
5636 expression.visitExpression(this, ctx);
5637 });
5638 ctx.print(ast, ')');
5639 return null;
5640 }
5641 _visitParams(params, ctx) {
5642 this.visitAllObjects(param => ctx.print(null, param.name), params, ctx, ',');
5643 }
5644 getBuiltinMethodName(method) {
5645 let name;
5646 switch (method) {
5647 case BuiltinMethod.ConcatArray:
5648 name = 'concat';
5649 break;
5650 case BuiltinMethod.SubscribeObservable:
5651 name = 'subscribe';
5652 break;
5653 case BuiltinMethod.Bind:
5654 name = 'bind';
5655 break;
5656 default:
5657 throw new Error(`Unknown builtin method: ${method}`);
5658 }
5659 return name;
5660 }
5661 }
5662
5663 /**
5664 * @license
5665 * Copyright Google LLC All Rights Reserved.
5666 *
5667 * Use of this source code is governed by an MIT-style license that can be
5668 * found in the LICENSE file at https://angular.io/license
5669 */
5670 /**
5671 * The Trusted Types policy, or null if Trusted Types are not
5672 * enabled/supported, or undefined if the policy has not been created yet.
5673 */
5674 let policy;
5675 /**
5676 * Returns the Trusted Types policy, or null if Trusted Types are not
5677 * enabled/supported. The first call to this function will create the policy.
5678 */
5679 function getPolicy() {
5680 if (policy === undefined) {
5681 policy = null;
5682 if (_global.trustedTypes) {
5683 try {
5684 policy =
5685 _global.trustedTypes.createPolicy('angular#unsafe-jit', {
5686 createScript: (s) => s,
5687 });
5688 }
5689 catch (_a) {
5690 // trustedTypes.createPolicy throws if called with a name that is
5691 // already registered, even in report-only mode. Until the API changes,
5692 // catch the error not to break the applications functionally. In such
5693 // cases, the code will fall back to using strings.
5694 }
5695 }
5696 }
5697 return policy;
5698 }
5699 /**
5700 * Unsafely promote a string to a TrustedScript, falling back to strings when
5701 * Trusted Types are not available.
5702 * @security In particular, it must be assured that the provided string will
5703 * never cause an XSS vulnerability if used in a context that will be
5704 * interpreted and executed as a script by a browser, e.g. when calling eval.
5705 */
5706 function trustedScriptFromString(script) {
5707 var _a;
5708 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
5709 }
5710 /**
5711 * Unsafely call the Function constructor with the given string arguments. It
5712 * is only available in development mode, and should be stripped out of
5713 * production code.
5714 * @security This is a security-sensitive function; any use of this function
5715 * must go through security review. In particular, it must be assured that it
5716 * is only called from the JIT compiler, as use in other code can lead to XSS
5717 * vulnerabilities.
5718 */
5719 function newTrustedFunctionForJIT(...args) {
5720 if (!_global.trustedTypes) {
5721 // In environments that don't support Trusted Types, fall back to the most
5722 // straightforward implementation:
5723 return new Function(...args);
5724 }
5725 // Chrome currently does not support passing TrustedScript to the Function
5726 // constructor. The following implements the workaround proposed on the page
5727 // below, where the Chromium bug is also referenced:
5728 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
5729 const fnArgs = args.slice(0, -1).join(',');
5730 const fnBody = args.pop().toString();
5731 const body = `(function anonymous(${fnArgs}
5732) { ${fnBody}
5733})`;
5734 // Using eval directly confuses the compiler and prevents this module from
5735 // being stripped out of JS binaries even if not used. The global['eval']
5736 // indirection fixes that.
5737 const fn = _global['eval'](trustedScriptFromString(body));
5738 // To completely mimic the behavior of calling "new Function", two more
5739 // things need to happen:
5740 // 1. Stringifying the resulting function should return its source code
5741 fn.toString = () => body;
5742 // 2. When calling the resulting function, `this` should refer to `global`
5743 return fn.bind(_global);
5744 // When Trusted Types support in Function constructors is widely available,
5745 // the implementation of this function can be simplified to:
5746 // return new Function(...args.map(a => trustedScriptFromString(a)));
5747 }
5748
5749 /**
5750 * @license
5751 * Copyright Google LLC All Rights Reserved.
5752 *
5753 * Use of this source code is governed by an MIT-style license that can be
5754 * found in the LICENSE file at https://angular.io/license
5755 */
5756 /**
5757 * A helper class to manage the evaluation of JIT generated code.
5758 */
5759 class JitEvaluator {
5760 /**
5761 *
5762 * @param sourceUrl The URL of the generated code.
5763 * @param statements An array of Angular statement AST nodes to be evaluated.
5764 * @param reflector A helper used when converting the statements to executable code.
5765 * @param createSourceMaps If true then create a source-map for the generated code and include it
5766 * inline as a source-map comment.
5767 * @returns A map of all the variables in the generated code.
5768 */
5769 evaluateStatements(sourceUrl, statements, reflector, createSourceMaps) {
5770 const converter = new JitEmitterVisitor(reflector);
5771 const ctx = EmitterVisitorContext.createRoot();
5772 // Ensure generated code is in strict mode
5773 if (statements.length > 0 && !isUseStrictStatement(statements[0])) {
5774 statements = [
5775 literal('use strict').toStmt(),
5776 ...statements,
5777 ];
5778 }
5779 converter.visitAllStatements(statements, ctx);
5780 converter.createReturnStmt(ctx);
5781 return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps);
5782 }
5783 /**
5784 * Evaluate a piece of JIT generated code.
5785 * @param sourceUrl The URL of this generated code.
5786 * @param ctx A context object that contains an AST of the code to be evaluated.
5787 * @param vars A map containing the names and values of variables that the evaluated code might
5788 * reference.
5789 * @param createSourceMap If true then create a source-map for the generated code and include it
5790 * inline as a source-map comment.
5791 * @returns The result of evaluating the code.
5792 */
5793 evaluateCode(sourceUrl, ctx, vars, createSourceMap) {
5794 let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`;
5795 const fnArgNames = [];
5796 const fnArgValues = [];
5797 for (const argName in vars) {
5798 fnArgValues.push(vars[argName]);
5799 fnArgNames.push(argName);
5800 }
5801 if (createSourceMap) {
5802 // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise
5803 // E.g. ```
5804 // function anonymous(a,b,c
5805 // /**/) { ... }```
5806 // We don't want to hard code this fact, so we auto detect it via an empty function first.
5807 const emptyFn = newTrustedFunctionForJIT(...fnArgNames.concat('return null;')).toString();
5808 const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
5809 fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`;
5810 }
5811 const fn = newTrustedFunctionForJIT(...fnArgNames.concat(fnBody));
5812 return this.executeFunction(fn, fnArgValues);
5813 }
5814 /**
5815 * Execute a JIT generated function by calling it.
5816 *
5817 * This method can be overridden in tests to capture the functions that are generated
5818 * by this `JitEvaluator` class.
5819 *
5820 * @param fn A function to execute.
5821 * @param args The arguments to pass to the function being executed.
5822 * @returns The return value of the executed function.
5823 */
5824 executeFunction(fn, args) {
5825 return fn(...args);
5826 }
5827 }
5828 /**
5829 * An Angular AST visitor that converts AST nodes into executable JavaScript code.
5830 */
5831 class JitEmitterVisitor extends AbstractJsEmitterVisitor {
5832 constructor(reflector) {
5833 super();
5834 this.reflector = reflector;
5835 this._evalArgNames = [];
5836 this._evalArgValues = [];
5837 this._evalExportedVars = [];
5838 }
5839 createReturnStmt(ctx) {
5840 const stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(resultVar => new LiteralMapEntry(resultVar, variable(resultVar), false))));
5841 stmt.visitStatement(this, ctx);
5842 }
5843 getArgs() {
5844 const result = {};
5845 for (let i = 0; i < this._evalArgNames.length; i++) {
5846 result[this._evalArgNames[i]] = this._evalArgValues[i];
5847 }
5848 return result;
5849 }
5850 visitExternalExpr(ast, ctx) {
5851 this._emitReferenceToExternal(ast, this.reflector.resolveExternalReference(ast.value), ctx);
5852 return null;
5853 }
5854 visitWrappedNodeExpr(ast, ctx) {
5855 this._emitReferenceToExternal(ast, ast.node, ctx);
5856 return null;
5857 }
5858 visitDeclareVarStmt(stmt, ctx) {
5859 if (stmt.hasModifier(StmtModifier.Exported)) {
5860 this._evalExportedVars.push(stmt.name);
5861 }
5862 return super.visitDeclareVarStmt(stmt, ctx);
5863 }
5864 visitDeclareFunctionStmt(stmt, ctx) {
5865 if (stmt.hasModifier(StmtModifier.Exported)) {
5866 this._evalExportedVars.push(stmt.name);
5867 }
5868 return super.visitDeclareFunctionStmt(stmt, ctx);
5869 }
5870 visitDeclareClassStmt(stmt, ctx) {
5871 if (stmt.hasModifier(StmtModifier.Exported)) {
5872 this._evalExportedVars.push(stmt.name);
5873 }
5874 return super.visitDeclareClassStmt(stmt, ctx);
5875 }
5876 _emitReferenceToExternal(ast, value, ctx) {
5877 let id = this._evalArgValues.indexOf(value);
5878 if (id === -1) {
5879 id = this._evalArgValues.length;
5880 this._evalArgValues.push(value);
5881 const name = identifierName({ reference: value }) || 'val';
5882 this._evalArgNames.push(`jit_${name}_${id}`);
5883 }
5884 ctx.print(ast, this._evalArgNames[id]);
5885 }
5886 }
5887 function isUseStrictStatement(statement) {
5888 return statement.isEquivalent(literal('use strict').toStmt());
5889 }
5890
5891 /**
5892 * @license
5893 * Copyright Google LLC All Rights Reserved.
5894 *
5895 * Use of this source code is governed by an MIT-style license that can be
5896 * found in the LICENSE file at https://angular.io/license
5897 */
5898 const $EOF = 0;
5899 const $BSPACE = 8;
5900 const $TAB = 9;
5901 const $LF = 10;
5902 const $VTAB = 11;
5903 const $FF = 12;
5904 const $CR = 13;
5905 const $SPACE = 32;
5906 const $BANG = 33;
5907 const $DQ = 34;
5908 const $HASH = 35;
5909 const $$ = 36;
5910 const $PERCENT = 37;
5911 const $AMPERSAND = 38;
5912 const $SQ = 39;
5913 const $LPAREN = 40;
5914 const $RPAREN = 41;
5915 const $STAR = 42;
5916 const $PLUS = 43;
5917 const $COMMA = 44;
5918 const $MINUS = 45;
5919 const $PERIOD = 46;
5920 const $SLASH = 47;
5921 const $COLON = 58;
5922 const $SEMICOLON = 59;
5923 const $LT = 60;
5924 const $EQ = 61;
5925 const $GT = 62;
5926 const $QUESTION = 63;
5927 const $0 = 48;
5928 const $7 = 55;
5929 const $9 = 57;
5930 const $A = 65;
5931 const $E = 69;
5932 const $F = 70;
5933 const $X = 88;
5934 const $Z = 90;
5935 const $LBRACKET = 91;
5936 const $BACKSLASH = 92;
5937 const $RBRACKET = 93;
5938 const $CARET = 94;
5939 const $_ = 95;
5940 const $a = 97;
5941 const $b = 98;
5942 const $e = 101;
5943 const $f = 102;
5944 const $n = 110;
5945 const $r = 114;
5946 const $t = 116;
5947 const $u = 117;
5948 const $v = 118;
5949 const $x = 120;
5950 const $z = 122;
5951 const $LBRACE = 123;
5952 const $BAR = 124;
5953 const $RBRACE = 125;
5954 const $NBSP = 160;
5955 const $BT = 96;
5956 function isWhitespace(code) {
5957 return (code >= $TAB && code <= $SPACE) || (code == $NBSP);
5958 }
5959 function isDigit(code) {
5960 return $0 <= code && code <= $9;
5961 }
5962 function isAsciiLetter(code) {
5963 return code >= $a && code <= $z || code >= $A && code <= $Z;
5964 }
5965 function isAsciiHexDigit(code) {
5966 return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code);
5967 }
5968 function isNewLine(code) {
5969 return code === $LF || code === $CR;
5970 }
5971 function isOctalDigit(code) {
5972 return $0 <= code && code <= $7;
5973 }
5974
5975 /**
5976 * @license
5977 * Copyright Google LLC All Rights Reserved.
5978 *
5979 * Use of this source code is governed by an MIT-style license that can be
5980 * found in the LICENSE file at https://angular.io/license
5981 */
5982 class ParseLocation {
5983 constructor(file, offset, line, col) {
5984 this.file = file;
5985 this.offset = offset;
5986 this.line = line;
5987 this.col = col;
5988 }
5989 toString() {
5990 return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url;
5991 }
5992 moveBy(delta) {
5993 const source = this.file.content;
5994 const len = source.length;
5995 let offset = this.offset;
5996 let line = this.line;
5997 let col = this.col;
5998 while (offset > 0 && delta < 0) {
5999 offset--;
6000 delta++;
6001 const ch = source.charCodeAt(offset);
6002 if (ch == $LF) {
6003 line--;
6004 const priorLine = source.substr(0, offset - 1).lastIndexOf(String.fromCharCode($LF));
6005 col = priorLine > 0 ? offset - priorLine : offset;
6006 }
6007 else {
6008 col--;
6009 }
6010 }
6011 while (offset < len && delta > 0) {
6012 const ch = source.charCodeAt(offset);
6013 offset++;
6014 delta--;
6015 if (ch == $LF) {
6016 line++;
6017 col = 0;
6018 }
6019 else {
6020 col++;
6021 }
6022 }
6023 return new ParseLocation(this.file, offset, line, col);
6024 }
6025 // Return the source around the location
6026 // Up to `maxChars` or `maxLines` on each side of the location
6027 getContext(maxChars, maxLines) {
6028 const content = this.file.content;
6029 let startOffset = this.offset;
6030 if (startOffset != null) {
6031 if (startOffset > content.length - 1) {
6032 startOffset = content.length - 1;
6033 }
6034 let endOffset = startOffset;
6035 let ctxChars = 0;
6036 let ctxLines = 0;
6037 while (ctxChars < maxChars && startOffset > 0) {
6038 startOffset--;
6039 ctxChars++;
6040 if (content[startOffset] == '\n') {
6041 if (++ctxLines == maxLines) {
6042 break;
6043 }
6044 }
6045 }
6046 ctxChars = 0;
6047 ctxLines = 0;
6048 while (ctxChars < maxChars && endOffset < content.length - 1) {
6049 endOffset++;
6050 ctxChars++;
6051 if (content[endOffset] == '\n') {
6052 if (++ctxLines == maxLines) {
6053 break;
6054 }
6055 }
6056 }
6057 return {
6058 before: content.substring(startOffset, this.offset),
6059 after: content.substring(this.offset, endOffset + 1),
6060 };
6061 }
6062 return null;
6063 }
6064 }
6065 class ParseSourceFile {
6066 constructor(content, url) {
6067 this.content = content;
6068 this.url = url;
6069 }
6070 }
6071 class ParseSourceSpan {
6072 /**
6073 * Create an object that holds information about spans of tokens/nodes captured during
6074 * lexing/parsing of text.
6075 *
6076 * @param start
6077 * The location of the start of the span (having skipped leading trivia).
6078 * Skipping leading trivia makes source-spans more "user friendly", since things like HTML
6079 * elements will appear to begin at the start of the opening tag, rather than at the start of any
6080 * leading trivia, which could include newlines.
6081 *
6082 * @param end
6083 * The location of the end of the span.
6084 *
6085 * @param fullStart
6086 * The start of the token without skipping the leading trivia.
6087 * This is used by tooling that splits tokens further, such as extracting Angular interpolations
6088 * from text tokens. Such tooling creates new source-spans relative to the original token's
6089 * source-span. If leading trivia characters have been skipped then the new source-spans may be
6090 * incorrectly offset.
6091 *
6092 * @param details
6093 * Additional information (such as identifier names) that should be associated with the span.
6094 */
6095 constructor(start, end, fullStart = start, details = null) {
6096 this.start = start;
6097 this.end = end;
6098 this.fullStart = fullStart;
6099 this.details = details;
6100 }
6101 toString() {
6102 return this.start.file.content.substring(this.start.offset, this.end.offset);
6103 }
6104 }
6105 var ParseErrorLevel;
6106 (function (ParseErrorLevel) {
6107 ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING";
6108 ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR";
6109 })(ParseErrorLevel || (ParseErrorLevel = {}));
6110 class ParseError {
6111 constructor(span, msg, level = ParseErrorLevel.ERROR) {
6112 this.span = span;
6113 this.msg = msg;
6114 this.level = level;
6115 }
6116 contextualMessage() {
6117 const ctx = this.span.start.getContext(100, 3);
6118 return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` :
6119 this.msg;
6120 }
6121 toString() {
6122 const details = this.span.details ? `, ${this.span.details}` : '';
6123 return `${this.contextualMessage()}: ${this.span.start}${details}`;
6124 }
6125 }
6126 /**
6127 * Generates Source Span object for a given R3 Type for JIT mode.
6128 *
6129 * @param kind Component or Directive.
6130 * @param typeName name of the Component or Directive.
6131 * @param sourceUrl reference to Component or Directive source.
6132 * @returns instance of ParseSourceSpan that represent a given Component or Directive.
6133 */
6134 function r3JitTypeSourceSpan(kind, typeName, sourceUrl) {
6135 const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`;
6136 const sourceFile = new ParseSourceFile('', sourceFileName);
6137 return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
6138 }
6139
6140 /**
6141 * @license
6142 * Copyright Google LLC All Rights Reserved.
6143 *
6144 * Use of this source code is governed by an MIT-style license that can be
6145 * found in the LICENSE file at https://angular.io/license
6146 */
6147 /**
6148 * Implementation of `CompileReflector` which resolves references to @angular/core
6149 * symbols at runtime, according to a consumer-provided mapping.
6150 *
6151 * Only supports `resolveExternalReference`, all other methods throw.
6152 */
6153 class R3JitReflector {
6154 constructor(context) {
6155 this.context = context;
6156 }
6157 resolveExternalReference(ref) {
6158 // This reflector only handles @angular/core imports.
6159 if (ref.moduleName !== '@angular/core') {
6160 throw new Error(`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`);
6161 }
6162 if (!this.context.hasOwnProperty(ref.name)) {
6163 throw new Error(`No value provided for @angular/core symbol '${ref.name}'.`);
6164 }
6165 return this.context[ref.name];
6166 }
6167 parameters(typeOrFunc) {
6168 throw new Error('Not implemented.');
6169 }
6170 annotations(typeOrFunc) {
6171 throw new Error('Not implemented.');
6172 }
6173 shallowAnnotations(typeOrFunc) {
6174 throw new Error('Not implemented.');
6175 }
6176 tryAnnotations(typeOrFunc) {
6177 throw new Error('Not implemented.');
6178 }
6179 propMetadata(typeOrFunc) {
6180 throw new Error('Not implemented.');
6181 }
6182 hasLifecycleHook(type, lcProperty) {
6183 throw new Error('Not implemented.');
6184 }
6185 guards(typeOrFunc) {
6186 throw new Error('Not implemented.');
6187 }
6188 componentModuleUrl(type, cmpMetadata) {
6189 throw new Error('Not implemented.');
6190 }
6191 }
6192
6193 /**
6194 * @license
6195 * Copyright Google LLC All Rights Reserved.
6196 *
6197 * Use of this source code is governed by an MIT-style license that can be
6198 * found in the LICENSE file at https://angular.io/license
6199 */
6200 function mapLiteral(obj, quoted = false) {
6201 return literalMap(Object.keys(obj).map(key => ({
6202 key,
6203 quoted,
6204 value: obj[key],
6205 })));
6206 }
6207
6208 /**
6209 * @license
6210 * Copyright Google LLC All Rights Reserved.
6211 *
6212 * Use of this source code is governed by an MIT-style license that can be
6213 * found in the LICENSE file at https://angular.io/license
6214 */
6215 /**
6216 * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
6217 */
6218 function compileNgModule(meta) {
6219 const { internalType, type: moduleType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, emitInline, id } = meta;
6220 const additionalStatements = [];
6221 const definitionMap = { type: internalType };
6222 // Only generate the keys in the metadata if the arrays have values.
6223 if (bootstrap.length) {
6224 definitionMap.bootstrap = refsToArray(bootstrap, containsForwardDecls);
6225 }
6226 // If requested to emit scope information inline, pass the declarations, imports and exports to
6227 // the `ɵɵdefineNgModule` call. The JIT compilation uses this.
6228 if (emitInline) {
6229 if (declarations.length) {
6230 definitionMap.declarations = refsToArray(declarations, containsForwardDecls);
6231 }
6232 if (imports.length) {
6233 definitionMap.imports = refsToArray(imports, containsForwardDecls);
6234 }
6235 if (exports.length) {
6236 definitionMap.exports = refsToArray(exports, containsForwardDecls);
6237 }
6238 }
6239 // If not emitting inline, the scope information is not passed into `ɵɵdefineNgModule` as it would
6240 // prevent tree-shaking of the declarations, imports and exports references.
6241 else {
6242 const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta);
6243 if (setNgModuleScopeCall !== null) {
6244 additionalStatements.push(setNgModuleScopeCall);
6245 }
6246 }
6247 if (schemas && schemas.length) {
6248 definitionMap.schemas = literalArr(schemas.map(ref => ref.value));
6249 }
6250 if (id) {
6251 definitionMap.id = id;
6252 }
6253 const expression = importExpr(Identifiers$1.defineNgModule).callFn([mapToMapExpression(definitionMap)]);
6254 const type = new ExpressionType(importExpr(Identifiers$1.NgModuleDefWithMeta, [
6255 new ExpressionType(moduleType.type), tupleTypeOf(declarations), tupleTypeOf(imports),
6256 tupleTypeOf(exports)
6257 ]));
6258 return { expression, type, additionalStatements };
6259 }
6260 /**
6261 * Generates a function call to `ɵɵsetNgModuleScope` with all necessary information so that the
6262 * transitive module scope can be computed during runtime in JIT mode. This call is marked pure
6263 * such that the references to declarations, imports and exports may be elided causing these
6264 * symbols to become tree-shakeable.
6265 */
6266 function generateSetNgModuleScopeCall(meta) {
6267 const { adjacentType: moduleType, declarations, imports, exports, containsForwardDecls } = meta;
6268 const scopeMap = {};
6269 if (declarations.length) {
6270 scopeMap.declarations = refsToArray(declarations, containsForwardDecls);
6271 }
6272 if (imports.length) {
6273 scopeMap.imports = refsToArray(imports, containsForwardDecls);
6274 }
6275 if (exports.length) {
6276 scopeMap.exports = refsToArray(exports, containsForwardDecls);
6277 }
6278 if (Object.keys(scopeMap).length === 0) {
6279 return null;
6280 }
6281 // setNgModuleScope(...)
6282 const fnCall = new InvokeFunctionExpr(
6283 /* fn */ importExpr(Identifiers$1.setNgModuleScope),
6284 /* args */ [moduleType, mapToMapExpression(scopeMap)]);
6285 // (ngJitMode guard) && setNgModuleScope(...)
6286 const guardedCall = jitOnlyGuardedExpression(fnCall);
6287 // function() { (ngJitMode guard) && setNgModuleScope(...); }
6288 const iife = new FunctionExpr(
6289 /* params */ [],
6290 /* statements */ [guardedCall.toStmt()]);
6291 // (function() { (ngJitMode guard) && setNgModuleScope(...); })()
6292 const iifeCall = new InvokeFunctionExpr(
6293 /* fn */ iife,
6294 /* args */ []);
6295 return iifeCall.toStmt();
6296 }
6297 function compileInjector(meta) {
6298 const result = compileFactoryFunction({
6299 name: meta.name,
6300 type: meta.type,
6301 internalType: meta.internalType,
6302 typeArgumentCount: 0,
6303 deps: meta.deps,
6304 injectFn: Identifiers$1.inject,
6305 target: R3FactoryTarget.NgModule,
6306 });
6307 const definitionMap = {
6308 factory: result.factory,
6309 };
6310 if (meta.providers !== null) {
6311 definitionMap.providers = meta.providers;
6312 }
6313 if (meta.imports.length > 0) {
6314 definitionMap.imports = literalArr(meta.imports);
6315 }
6316 const expression = importExpr(Identifiers$1.defineInjector).callFn([mapToMapExpression(definitionMap)]);
6317 const type = new ExpressionType(importExpr(Identifiers$1.InjectorDef, [new ExpressionType(meta.type.type)]));
6318 return { expression, type, statements: result.statements };
6319 }
6320 function tupleTypeOf(exp) {
6321 const types = exp.map(ref => typeofExpr(ref.type));
6322 return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE;
6323 }
6324 function refsToArray(refs, shouldForwardDeclare) {
6325 const values = literalArr(refs.map(ref => ref.value));
6326 return shouldForwardDeclare ? fn([], [new ReturnStatement(values)]) : values;
6327 }
6328
6329 /**
6330 * @license
6331 * Copyright Google LLC All Rights Reserved.
6332 *
6333 * Use of this source code is governed by an MIT-style license that can be
6334 * found in the LICENSE file at https://angular.io/license
6335 */
6336 function compilePipeFromMetadata(metadata) {
6337 const definitionMapValues = [];
6338 // e.g. `name: 'myPipe'`
6339 definitionMapValues.push({ key: 'name', value: literal(metadata.pipeName), quoted: false });
6340 // e.g. `type: MyPipe`
6341 definitionMapValues.push({ key: 'type', value: metadata.type.value, quoted: false });
6342 // e.g. `pure: true`
6343 definitionMapValues.push({ key: 'pure', value: literal(metadata.pure), quoted: false });
6344 const expression = importExpr(Identifiers$1.definePipe).callFn([literalMap(definitionMapValues)]);
6345 const type = new ExpressionType(importExpr(Identifiers$1.PipeDefWithMeta, [
6346 typeWithParameters(metadata.type.type, metadata.typeArgumentCount),
6347 new ExpressionType(new LiteralExpr(metadata.pipeName)),
6348 ]));
6349 return { expression, type };
6350 }
6351
6352 /**
6353 * @license
6354 * Copyright Google LLC All Rights Reserved.
6355 *
6356 * Use of this source code is governed by an MIT-style license that can be
6357 * found in the LICENSE file at https://angular.io/license
6358 */
6359 class ParserError {
6360 constructor(message, input, errLocation, ctxLocation) {
6361 this.input = input;
6362 this.errLocation = errLocation;
6363 this.ctxLocation = ctxLocation;
6364 this.message = `Parser Error: ${message} ${errLocation} [${input}] in ${ctxLocation}`;
6365 }
6366 }
6367 class ParseSpan {
6368 constructor(start, end) {
6369 this.start = start;
6370 this.end = end;
6371 }
6372 toAbsolute(absoluteOffset) {
6373 return new AbsoluteSourceSpan(absoluteOffset + this.start, absoluteOffset + this.end);
6374 }
6375 }
6376 class AST {
6377 constructor(span,
6378 /**
6379 * Absolute location of the expression AST in a source code file.
6380 */
6381 sourceSpan) {
6382 this.span = span;
6383 this.sourceSpan = sourceSpan;
6384 }
6385 visit(visitor, context = null) {
6386 return null;
6387 }
6388 toString() {
6389 return 'AST';
6390 }
6391 }
6392 class ASTWithName extends AST {
6393 constructor(span, sourceSpan, nameSpan) {
6394 super(span, sourceSpan);
6395 this.nameSpan = nameSpan;
6396 }
6397 }
6398 /**
6399 * Represents a quoted expression of the form:
6400 *
6401 * quote = prefix `:` uninterpretedExpression
6402 * prefix = identifier
6403 * uninterpretedExpression = arbitrary string
6404 *
6405 * A quoted expression is meant to be pre-processed by an AST transformer that
6406 * converts it into another AST that no longer contains quoted expressions.
6407 * It is meant to allow third-party developers to extend Angular template
6408 * expression language. The `uninterpretedExpression` part of the quote is
6409 * therefore not interpreted by the Angular's own expression parser.
6410 */
6411 class Quote extends AST {
6412 constructor(span, sourceSpan, prefix, uninterpretedExpression, location) {
6413 super(span, sourceSpan);
6414 this.prefix = prefix;
6415 this.uninterpretedExpression = uninterpretedExpression;
6416 this.location = location;
6417 }
6418 visit(visitor, context = null) {
6419 return visitor.visitQuote(this, context);
6420 }
6421 toString() {
6422 return 'Quote';
6423 }
6424 }
6425 class EmptyExpr extends AST {
6426 visit(visitor, context = null) {
6427 // do nothing
6428 }
6429 }
6430 class ImplicitReceiver extends AST {
6431 visit(visitor, context = null) {
6432 return visitor.visitImplicitReceiver(this, context);
6433 }
6434 }
6435 /**
6436 * Receiver when something is accessed through `this` (e.g. `this.foo`). Note that this class
6437 * inherits from `ImplicitReceiver`, because accessing something through `this` is treated the
6438 * same as accessing it implicitly inside of an Angular template (e.g. `[attr.title]="this.title"`
6439 * is the same as `[attr.title]="title"`.). Inheriting allows for the `this` accesses to be treated
6440 * the same as implicit ones, except for a couple of exceptions like `$event` and `$any`.
6441 * TODO: we should find a way for this class not to extend from `ImplicitReceiver` in the future.
6442 */
6443 class ThisReceiver extends ImplicitReceiver {
6444 visit(visitor, context = null) {
6445 var _a;
6446 return (_a = visitor.visitThisReceiver) === null || _a === void 0 ? void 0 : _a.call(visitor, this, context);
6447 }
6448 }
6449 /**
6450 * Multiple expressions separated by a semicolon.
6451 */
6452 class Chain extends AST {
6453 constructor(span, sourceSpan, expressions) {
6454 super(span, sourceSpan);
6455 this.expressions = expressions;
6456 }
6457 visit(visitor, context = null) {
6458 return visitor.visitChain(this, context);
6459 }
6460 }
6461 class Conditional extends AST {
6462 constructor(span, sourceSpan, condition, trueExp, falseExp) {
6463 super(span, sourceSpan);
6464 this.condition = condition;
6465 this.trueExp = trueExp;
6466 this.falseExp = falseExp;
6467 }
6468 visit(visitor, context = null) {
6469 return visitor.visitConditional(this, context);
6470 }
6471 }
6472 class PropertyRead extends ASTWithName {
6473 constructor(span, sourceSpan, nameSpan, receiver, name) {
6474 super(span, sourceSpan, nameSpan);
6475 this.receiver = receiver;
6476 this.name = name;
6477 }
6478 visit(visitor, context = null) {
6479 return visitor.visitPropertyRead(this, context);
6480 }
6481 }
6482 class PropertyWrite extends ASTWithName {
6483 constructor(span, sourceSpan, nameSpan, receiver, name, value) {
6484 super(span, sourceSpan, nameSpan);
6485 this.receiver = receiver;
6486 this.name = name;
6487 this.value = value;
6488 }
6489 visit(visitor, context = null) {
6490 return visitor.visitPropertyWrite(this, context);
6491 }
6492 }
6493 class SafePropertyRead extends ASTWithName {
6494 constructor(span, sourceSpan, nameSpan, receiver, name) {
6495 super(span, sourceSpan, nameSpan);
6496 this.receiver = receiver;
6497 this.name = name;
6498 }
6499 visit(visitor, context = null) {
6500 return visitor.visitSafePropertyRead(this, context);
6501 }
6502 }
6503 class KeyedRead extends AST {
6504 constructor(span, sourceSpan, obj, key) {
6505 super(span, sourceSpan);
6506 this.obj = obj;
6507 this.key = key;
6508 }
6509 visit(visitor, context = null) {
6510 return visitor.visitKeyedRead(this, context);
6511 }
6512 }
6513 class KeyedWrite extends AST {
6514 constructor(span, sourceSpan, obj, key, value) {
6515 super(span, sourceSpan);
6516 this.obj = obj;
6517 this.key = key;
6518 this.value = value;
6519 }
6520 visit(visitor, context = null) {
6521 return visitor.visitKeyedWrite(this, context);
6522 }
6523 }
6524 class BindingPipe extends ASTWithName {
6525 constructor(span, sourceSpan, exp, name, args, nameSpan) {
6526 super(span, sourceSpan, nameSpan);
6527 this.exp = exp;
6528 this.name = name;
6529 this.args = args;
6530 }
6531 visit(visitor, context = null) {
6532 return visitor.visitPipe(this, context);
6533 }
6534 }
6535 class LiteralPrimitive extends AST {
6536 constructor(span, sourceSpan, value) {
6537 super(span, sourceSpan);
6538 this.value = value;
6539 }
6540 visit(visitor, context = null) {
6541 return visitor.visitLiteralPrimitive(this, context);
6542 }
6543 }
6544 class LiteralArray extends AST {
6545 constructor(span, sourceSpan, expressions) {
6546 super(span, sourceSpan);
6547 this.expressions = expressions;
6548 }
6549 visit(visitor, context = null) {
6550 return visitor.visitLiteralArray(this, context);
6551 }
6552 }
6553 class LiteralMap extends AST {
6554 constructor(span, sourceSpan, keys, values) {
6555 super(span, sourceSpan);
6556 this.keys = keys;
6557 this.values = values;
6558 }
6559 visit(visitor, context = null) {
6560 return visitor.visitLiteralMap(this, context);
6561 }
6562 }
6563 class Interpolation extends AST {
6564 constructor(span, sourceSpan, strings, expressions) {
6565 super(span, sourceSpan);
6566 this.strings = strings;
6567 this.expressions = expressions;
6568 }
6569 visit(visitor, context = null) {
6570 return visitor.visitInterpolation(this, context);
6571 }
6572 }
6573 class Binary extends AST {
6574 constructor(span, sourceSpan, operation, left, right) {
6575 super(span, sourceSpan);
6576 this.operation = operation;
6577 this.left = left;
6578 this.right = right;
6579 }
6580 visit(visitor, context = null) {
6581 return visitor.visitBinary(this, context);
6582 }
6583 }
6584 /**
6585 * For backwards compatibility reasons, `Unary` inherits from `Binary` and mimics the binary AST
6586 * node that was originally used. This inheritance relation can be deleted in some future major,
6587 * after consumers have been given a chance to fully support Unary.
6588 */
6589 class Unary extends Binary {
6590 /**
6591 * During the deprecation period this constructor is private, to avoid consumers from creating
6592 * a `Unary` with the fallback properties for `Binary`.
6593 */
6594 constructor(span, sourceSpan, operator, expr, binaryOp, binaryLeft, binaryRight) {
6595 super(span, sourceSpan, binaryOp, binaryLeft, binaryRight);
6596 this.operator = operator;
6597 this.expr = expr;
6598 }
6599 /**
6600 * Creates a unary minus expression "-x", represented as `Binary` using "0 - x".
6601 */
6602 static createMinus(span, sourceSpan, expr) {
6603 return new Unary(span, sourceSpan, '-', expr, '-', new LiteralPrimitive(span, sourceSpan, 0), expr);
6604 }
6605 /**
6606 * Creates a unary plus expression "+x", represented as `Binary` using "x - 0".
6607 */
6608 static createPlus(span, sourceSpan, expr) {
6609 return new Unary(span, sourceSpan, '+', expr, '-', expr, new LiteralPrimitive(span, sourceSpan, 0));
6610 }
6611 visit(visitor, context = null) {
6612 if (visitor.visitUnary !== undefined) {
6613 return visitor.visitUnary(this, context);
6614 }
6615 return visitor.visitBinary(this, context);
6616 }
6617 }
6618 class PrefixNot extends AST {
6619 constructor(span, sourceSpan, expression) {
6620 super(span, sourceSpan);
6621 this.expression = expression;
6622 }
6623 visit(visitor, context = null) {
6624 return visitor.visitPrefixNot(this, context);
6625 }
6626 }
6627 class NonNullAssert extends AST {
6628 constructor(span, sourceSpan, expression) {
6629 super(span, sourceSpan);
6630 this.expression = expression;
6631 }
6632 visit(visitor, context = null) {
6633 return visitor.visitNonNullAssert(this, context);
6634 }
6635 }
6636 class MethodCall extends ASTWithName {
6637 constructor(span, sourceSpan, nameSpan, receiver, name, args) {
6638 super(span, sourceSpan, nameSpan);
6639 this.receiver = receiver;
6640 this.name = name;
6641 this.args = args;
6642 }
6643 visit(visitor, context = null) {
6644 return visitor.visitMethodCall(this, context);
6645 }
6646 }
6647 class SafeMethodCall extends ASTWithName {
6648 constructor(span, sourceSpan, nameSpan, receiver, name, args) {
6649 super(span, sourceSpan, nameSpan);
6650 this.receiver = receiver;
6651 this.name = name;
6652 this.args = args;
6653 }
6654 visit(visitor, context = null) {
6655 return visitor.visitSafeMethodCall(this, context);
6656 }
6657 }
6658 class FunctionCall extends AST {
6659 constructor(span, sourceSpan, target, args) {
6660 super(span, sourceSpan);
6661 this.target = target;
6662 this.args = args;
6663 }
6664 visit(visitor, context = null) {
6665 return visitor.visitFunctionCall(this, context);
6666 }
6667 }
6668 /**
6669 * Records the absolute position of a text span in a source file, where `start` and `end` are the
6670 * starting and ending byte offsets, respectively, of the text span in a source file.
6671 */
6672 class AbsoluteSourceSpan {
6673 constructor(start, end) {
6674 this.start = start;
6675 this.end = end;
6676 }
6677 }
6678 class ASTWithSource extends AST {
6679 constructor(ast, source, location, absoluteOffset, errors) {
6680 super(new ParseSpan(0, source === null ? 0 : source.length), new AbsoluteSourceSpan(absoluteOffset, source === null ? absoluteOffset : absoluteOffset + source.length));
6681 this.ast = ast;
6682 this.source = source;
6683 this.location = location;
6684 this.errors = errors;
6685 }
6686 visit(visitor, context = null) {
6687 if (visitor.visitASTWithSource) {
6688 return visitor.visitASTWithSource(this, context);
6689 }
6690 return this.ast.visit(visitor, context);
6691 }
6692 toString() {
6693 return `${this.source} in ${this.location}`;
6694 }
6695 }
6696 class VariableBinding {
6697 /**
6698 * @param sourceSpan entire span of the binding.
6699 * @param key name of the LHS along with its span.
6700 * @param value optional value for the RHS along with its span.
6701 */
6702 constructor(sourceSpan, key, value) {
6703 this.sourceSpan = sourceSpan;
6704 this.key = key;
6705 this.value = value;
6706 }
6707 }
6708 class ExpressionBinding {
6709 /**
6710 * @param sourceSpan entire span of the binding.
6711 * @param key binding name, like ngForOf, ngForTrackBy, ngIf, along with its
6712 * span. Note that the length of the span may not be the same as
6713 * `key.source.length`. For example,
6714 * 1. key.source = ngFor, key.span is for "ngFor"
6715 * 2. key.source = ngForOf, key.span is for "of"
6716 * 3. key.source = ngForTrackBy, key.span is for "trackBy"
6717 * @param value optional expression for the RHS.
6718 */
6719 constructor(sourceSpan, key, value) {
6720 this.sourceSpan = sourceSpan;
6721 this.key = key;
6722 this.value = value;
6723 }
6724 }
6725 class RecursiveAstVisitor {
6726 visit(ast, context) {
6727 // The default implementation just visits every node.
6728 // Classes that extend RecursiveAstVisitor should override this function
6729 // to selectively visit the specified node.
6730 ast.visit(this, context);
6731 }
6732 visitUnary(ast, context) {
6733 this.visit(ast.expr, context);
6734 }
6735 visitBinary(ast, context) {
6736 this.visit(ast.left, context);
6737 this.visit(ast.right, context);
6738 }
6739 visitChain(ast, context) {
6740 this.visitAll(ast.expressions, context);
6741 }
6742 visitConditional(ast, context) {
6743 this.visit(ast.condition, context);
6744 this.visit(ast.trueExp, context);
6745 this.visit(ast.falseExp, context);
6746 }
6747 visitPipe(ast, context) {
6748 this.visit(ast.exp, context);
6749 this.visitAll(ast.args, context);
6750 }
6751 visitFunctionCall(ast, context) {
6752 if (ast.target) {
6753 this.visit(ast.target, context);
6754 }
6755 this.visitAll(ast.args, context);
6756 }
6757 visitImplicitReceiver(ast, context) { }
6758 visitThisReceiver(ast, context) { }
6759 visitInterpolation(ast, context) {
6760 this.visitAll(ast.expressions, context);
6761 }
6762 visitKeyedRead(ast, context) {
6763 this.visit(ast.obj, context);
6764 this.visit(ast.key, context);
6765 }
6766 visitKeyedWrite(ast, context) {
6767 this.visit(ast.obj, context);
6768 this.visit(ast.key, context);
6769 this.visit(ast.value, context);
6770 }
6771 visitLiteralArray(ast, context) {
6772 this.visitAll(ast.expressions, context);
6773 }
6774 visitLiteralMap(ast, context) {
6775 this.visitAll(ast.values, context);
6776 }
6777 visitLiteralPrimitive(ast, context) { }
6778 visitMethodCall(ast, context) {
6779 this.visit(ast.receiver, context);
6780 this.visitAll(ast.args, context);
6781 }
6782 visitPrefixNot(ast, context) {
6783 this.visit(ast.expression, context);
6784 }
6785 visitNonNullAssert(ast, context) {
6786 this.visit(ast.expression, context);
6787 }
6788 visitPropertyRead(ast, context) {
6789 this.visit(ast.receiver, context);
6790 }
6791 visitPropertyWrite(ast, context) {
6792 this.visit(ast.receiver, context);
6793 this.visit(ast.value, context);
6794 }
6795 visitSafePropertyRead(ast, context) {
6796 this.visit(ast.receiver, context);
6797 }
6798 visitSafeMethodCall(ast, context) {
6799 this.visit(ast.receiver, context);
6800 this.visitAll(ast.args, context);
6801 }
6802 visitQuote(ast, context) { }
6803 // This is not part of the AstVisitor interface, just a helper method
6804 visitAll(asts, context) {
6805 for (const ast of asts) {
6806 this.visit(ast, context);
6807 }
6808 }
6809 }
6810 class AstTransformer {
6811 visitImplicitReceiver(ast, context) {
6812 return ast;
6813 }
6814 visitThisReceiver(ast, context) {
6815 return ast;
6816 }
6817 visitInterpolation(ast, context) {
6818 return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
6819 }
6820 visitLiteralPrimitive(ast, context) {
6821 return new LiteralPrimitive(ast.span, ast.sourceSpan, ast.value);
6822 }
6823 visitPropertyRead(ast, context) {
6824 return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
6825 }
6826 visitPropertyWrite(ast, context) {
6827 return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, ast.value.visit(this));
6828 }
6829 visitSafePropertyRead(ast, context) {
6830 return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
6831 }
6832 visitMethodCall(ast, context) {
6833 return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
6834 }
6835 visitSafeMethodCall(ast, context) {
6836 return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
6837 }
6838 visitFunctionCall(ast, context) {
6839 return new FunctionCall(ast.span, ast.sourceSpan, ast.target.visit(this), this.visitAll(ast.args));
6840 }
6841 visitLiteralArray(ast, context) {
6842 return new LiteralArray(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
6843 }
6844 visitLiteralMap(ast, context) {
6845 return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, this.visitAll(ast.values));
6846 }
6847 visitUnary(ast, context) {
6848 switch (ast.operator) {
6849 case '+':
6850 return Unary.createPlus(ast.span, ast.sourceSpan, ast.expr.visit(this));
6851 case '-':
6852 return Unary.createMinus(ast.span, ast.sourceSpan, ast.expr.visit(this));
6853 default:
6854 throw new Error(`Unknown unary operator ${ast.operator}`);
6855 }
6856 }
6857 visitBinary(ast, context) {
6858 return new Binary(ast.span, ast.sourceSpan, ast.operation, ast.left.visit(this), ast.right.visit(this));
6859 }
6860 visitPrefixNot(ast, context) {
6861 return new PrefixNot(ast.span, ast.sourceSpan, ast.expression.visit(this));
6862 }
6863 visitNonNullAssert(ast, context) {
6864 return new NonNullAssert(ast.span, ast.sourceSpan, ast.expression.visit(this));
6865 }
6866 visitConditional(ast, context) {
6867 return new Conditional(ast.span, ast.sourceSpan, ast.condition.visit(this), ast.trueExp.visit(this), ast.falseExp.visit(this));
6868 }
6869 visitPipe(ast, context) {
6870 return new BindingPipe(ast.span, ast.sourceSpan, ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.nameSpan);
6871 }
6872 visitKeyedRead(ast, context) {
6873 return new KeyedRead(ast.span, ast.sourceSpan, ast.obj.visit(this), ast.key.visit(this));
6874 }
6875 visitKeyedWrite(ast, context) {
6876 return new KeyedWrite(ast.span, ast.sourceSpan, ast.obj.visit(this), ast.key.visit(this), ast.value.visit(this));
6877 }
6878 visitAll(asts) {
6879 const res = [];
6880 for (let i = 0; i < asts.length; ++i) {
6881 res[i] = asts[i].visit(this);
6882 }
6883 return res;
6884 }
6885 visitChain(ast, context) {
6886 return new Chain(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
6887 }
6888 visitQuote(ast, context) {
6889 return new Quote(ast.span, ast.sourceSpan, ast.prefix, ast.uninterpretedExpression, ast.location);
6890 }
6891 }
6892 // A transformer that only creates new nodes if the transformer makes a change or
6893 // a change is made a child node.
6894 class AstMemoryEfficientTransformer {
6895 visitImplicitReceiver(ast, context) {
6896 return ast;
6897 }
6898 visitThisReceiver(ast, context) {
6899 return ast;
6900 }
6901 visitInterpolation(ast, context) {
6902 const expressions = this.visitAll(ast.expressions);
6903 if (expressions !== ast.expressions)
6904 return new Interpolation(ast.span, ast.sourceSpan, ast.strings, expressions);
6905 return ast;
6906 }
6907 visitLiteralPrimitive(ast, context) {
6908 return ast;
6909 }
6910 visitPropertyRead(ast, context) {
6911 const receiver = ast.receiver.visit(this);
6912 if (receiver !== ast.receiver) {
6913 return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
6914 }
6915 return ast;
6916 }
6917 visitPropertyWrite(ast, context) {
6918 const receiver = ast.receiver.visit(this);
6919 const value = ast.value.visit(this);
6920 if (receiver !== ast.receiver || value !== ast.value) {
6921 return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, value);
6922 }
6923 return ast;
6924 }
6925 visitSafePropertyRead(ast, context) {
6926 const receiver = ast.receiver.visit(this);
6927 if (receiver !== ast.receiver) {
6928 return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
6929 }
6930 return ast;
6931 }
6932 visitMethodCall(ast, context) {
6933 const receiver = ast.receiver.visit(this);
6934 const args = this.visitAll(ast.args);
6935 if (receiver !== ast.receiver || args !== ast.args) {
6936 return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args);
6937 }
6938 return ast;
6939 }
6940 visitSafeMethodCall(ast, context) {
6941 const receiver = ast.receiver.visit(this);
6942 const args = this.visitAll(ast.args);
6943 if (receiver !== ast.receiver || args !== ast.args) {
6944 return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args);
6945 }
6946 return ast;
6947 }
6948 visitFunctionCall(ast, context) {
6949 const target = ast.target && ast.target.visit(this);
6950 const args = this.visitAll(ast.args);
6951 if (target !== ast.target || args !== ast.args) {
6952 return new FunctionCall(ast.span, ast.sourceSpan, target, args);
6953 }
6954 return ast;
6955 }
6956 visitLiteralArray(ast, context) {
6957 const expressions = this.visitAll(ast.expressions);
6958 if (expressions !== ast.expressions) {
6959 return new LiteralArray(ast.span, ast.sourceSpan, expressions);
6960 }
6961 return ast;
6962 }
6963 visitLiteralMap(ast, context) {
6964 const values = this.visitAll(ast.values);
6965 if (values !== ast.values) {
6966 return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, values);
6967 }
6968 return ast;
6969 }
6970 visitUnary(ast, context) {
6971 const expr = ast.expr.visit(this);
6972 if (expr !== ast.expr) {
6973 switch (ast.operator) {
6974 case '+':
6975 return Unary.createPlus(ast.span, ast.sourceSpan, expr);
6976 case '-':
6977 return Unary.createMinus(ast.span, ast.sourceSpan, expr);
6978 default:
6979 throw new Error(`Unknown unary operator ${ast.operator}`);
6980 }
6981 }
6982 return ast;
6983 }
6984 visitBinary(ast, context) {
6985 const left = ast.left.visit(this);
6986 const right = ast.right.visit(this);
6987 if (left !== ast.left || right !== ast.right) {
6988 return new Binary(ast.span, ast.sourceSpan, ast.operation, left, right);
6989 }
6990 return ast;
6991 }
6992 visitPrefixNot(ast, context) {
6993 const expression = ast.expression.visit(this);
6994 if (expression !== ast.expression) {
6995 return new PrefixNot(ast.span, ast.sourceSpan, expression);
6996 }
6997 return ast;
6998 }
6999 visitNonNullAssert(ast, context) {
7000 const expression = ast.expression.visit(this);
7001 if (expression !== ast.expression) {
7002 return new NonNullAssert(ast.span, ast.sourceSpan, expression);
7003 }
7004 return ast;
7005 }
7006 visitConditional(ast, context) {
7007 const condition = ast.condition.visit(this);
7008 const trueExp = ast.trueExp.visit(this);
7009 const falseExp = ast.falseExp.visit(this);
7010 if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== ast.falseExp) {
7011 return new Conditional(ast.span, ast.sourceSpan, condition, trueExp, falseExp);
7012 }
7013 return ast;
7014 }
7015 visitPipe(ast, context) {
7016 const exp = ast.exp.visit(this);
7017 const args = this.visitAll(ast.args);
7018 if (exp !== ast.exp || args !== ast.args) {
7019 return new BindingPipe(ast.span, ast.sourceSpan, exp, ast.name, args, ast.nameSpan);
7020 }
7021 return ast;
7022 }
7023 visitKeyedRead(ast, context) {
7024 const obj = ast.obj.visit(this);
7025 const key = ast.key.visit(this);
7026 if (obj !== ast.obj || key !== ast.key) {
7027 return new KeyedRead(ast.span, ast.sourceSpan, obj, key);
7028 }
7029 return ast;
7030 }
7031 visitKeyedWrite(ast, context) {
7032 const obj = ast.obj.visit(this);
7033 const key = ast.key.visit(this);
7034 const value = ast.value.visit(this);
7035 if (obj !== ast.obj || key !== ast.key || value !== ast.value) {
7036 return new KeyedWrite(ast.span, ast.sourceSpan, obj, key, value);
7037 }
7038 return ast;
7039 }
7040 visitAll(asts) {
7041 const res = [];
7042 let modified = false;
7043 for (let i = 0; i < asts.length; ++i) {
7044 const original = asts[i];
7045 const value = original.visit(this);
7046 res[i] = value;
7047 modified = modified || value !== original;
7048 }
7049 return modified ? res : asts;
7050 }
7051 visitChain(ast, context) {
7052 const expressions = this.visitAll(ast.expressions);
7053 if (expressions !== ast.expressions) {
7054 return new Chain(ast.span, ast.sourceSpan, expressions);
7055 }
7056 return ast;
7057 }
7058 visitQuote(ast, context) {
7059 return ast;
7060 }
7061 }
7062 // Bindings
7063 class ParsedProperty {
7064 constructor(name, expression, type,
7065 // TODO(FW-2095): `keySpan` should really be required but allows `undefined` so VE does
7066 // not need to be updated. Make `keySpan` required when VE is removed.
7067 sourceSpan, keySpan, valueSpan) {
7068 this.name = name;
7069 this.expression = expression;
7070 this.type = type;
7071 this.sourceSpan = sourceSpan;
7072 this.keySpan = keySpan;
7073 this.valueSpan = valueSpan;
7074 this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR;
7075 this.isAnimation = this.type === ParsedPropertyType.ANIMATION;
7076 }
7077 }
7078 var ParsedPropertyType;
7079 (function (ParsedPropertyType) {
7080 ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT";
7081 ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
7082 ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION";
7083 })(ParsedPropertyType || (ParsedPropertyType = {}));
7084 class ParsedEvent {
7085 // Regular events have a target
7086 // Animation events have a phase
7087 constructor(name, targetOrPhase, type, handler, sourceSpan,
7088 // TODO(FW-2095): keySpan should be required but was made optional to avoid changing VE
7089 handlerSpan, keySpan) {
7090 this.name = name;
7091 this.targetOrPhase = targetOrPhase;
7092 this.type = type;
7093 this.handler = handler;
7094 this.sourceSpan = sourceSpan;
7095 this.handlerSpan = handlerSpan;
7096 this.keySpan = keySpan;
7097 }
7098 }
7099 /**
7100 * ParsedVariable represents a variable declaration in a microsyntax expression.
7101 */
7102 class ParsedVariable {
7103 constructor(name, value, sourceSpan, keySpan, valueSpan) {
7104 this.name = name;
7105 this.value = value;
7106 this.sourceSpan = sourceSpan;
7107 this.keySpan = keySpan;
7108 this.valueSpan = valueSpan;
7109 }
7110 }
7111 class BoundElementProperty {
7112 constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan) {
7113 this.name = name;
7114 this.type = type;
7115 this.securityContext = securityContext;
7116 this.value = value;
7117 this.unit = unit;
7118 this.sourceSpan = sourceSpan;
7119 this.keySpan = keySpan;
7120 this.valueSpan = valueSpan;
7121 }
7122 }
7123
7124 /**
7125 * @license
7126 * Copyright Google LLC All Rights Reserved.
7127 *
7128 * Use of this source code is governed by an MIT-style license that can be
7129 * found in the LICENSE file at https://angular.io/license
7130 */
7131 class EventHandlerVars {
7132 }
7133 EventHandlerVars.event = variable('$event');
7134 class ConvertActionBindingResult {
7135 constructor(
7136 /**
7137 * Render2 compatible statements,
7138 */
7139 stmts,
7140 /**
7141 * Variable name used with render2 compatible statements.
7142 */
7143 allowDefault) {
7144 this.stmts = stmts;
7145 this.allowDefault = allowDefault;
7146 /**
7147 * This is bit of a hack. It converts statements which render2 expects to statements which are
7148 * expected by render3.
7149 *
7150 * Example: `<div click="doSomething($event)">` will generate:
7151 *
7152 * Render3:
7153 * ```
7154 * const pd_b:any = ((<any>ctx.doSomething($event)) !== false);
7155 * return pd_b;
7156 * ```
7157 *
7158 * but render2 expects:
7159 * ```
7160 * return ctx.doSomething($event);
7161 * ```
7162 */
7163 // TODO(misko): remove this hack once we no longer support ViewEngine.
7164 this.render3Stmts = stmts.map((statement) => {
7165 if (statement instanceof DeclareVarStmt && statement.name == allowDefault.name &&
7166 statement.value instanceof BinaryOperatorExpr) {
7167 const lhs = statement.value.lhs;
7168 return new ReturnStatement(lhs.value);
7169 }
7170 return statement;
7171 });
7172 }
7173 }
7174 /**
7175 * Converts the given expression AST into an executable output AST, assuming the expression is
7176 * used in an action binding (e.g. an event handler).
7177 */
7178 function convertActionBinding(localResolver, implicitReceiver, action, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses, globals) {
7179 if (!localResolver) {
7180 localResolver = new DefaultLocalResolver(globals);
7181 }
7182 const actionWithoutBuiltins = convertPropertyBindingBuiltins({
7183 createLiteralArrayConverter: (argCount) => {
7184 // Note: no caching for literal arrays in actions.
7185 return (args) => literalArr(args);
7186 },
7187 createLiteralMapConverter: (keys) => {
7188 // Note: no caching for literal maps in actions.
7189 return (values) => {
7190 const entries = keys.map((k, i) => ({
7191 key: k.key,
7192 value: values[i],
7193 quoted: k.quoted,
7194 }));
7195 return literalMap(entries);
7196 };
7197 },
7198 createPipeConverter: (name) => {
7199 throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`);
7200 }
7201 }, action);
7202 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses);
7203 const actionStmts = [];
7204 flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
7205 prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
7206 if (visitor.usesImplicitReceiver) {
7207 localResolver.notifyImplicitReceiverUse();
7208 }
7209 const lastIndex = actionStmts.length - 1;
7210 let preventDefaultVar = null;
7211 if (lastIndex >= 0) {
7212 const lastStatement = actionStmts[lastIndex];
7213 const returnExpr = convertStmtIntoExpression(lastStatement);
7214 if (returnExpr) {
7215 // Note: We need to cast the result of the method call to dynamic,
7216 // as it might be a void method!
7217 preventDefaultVar = createPreventDefaultVar(bindingId);
7218 actionStmts[lastIndex] =
7219 preventDefaultVar.set(returnExpr.cast(DYNAMIC_TYPE).notIdentical(literal(false)))
7220 .toDeclStmt(null, [StmtModifier.Final]);
7221 }
7222 }
7223 return new ConvertActionBindingResult(actionStmts, preventDefaultVar);
7224 }
7225 function convertPropertyBindingBuiltins(converterFactory, ast) {
7226 return convertBuiltins(converterFactory, ast);
7227 }
7228 class ConvertPropertyBindingResult {
7229 constructor(stmts, currValExpr) {
7230 this.stmts = stmts;
7231 this.currValExpr = currValExpr;
7232 }
7233 }
7234 var BindingForm;
7235 (function (BindingForm) {
7236 // The general form of binding expression, supports all expressions.
7237 BindingForm[BindingForm["General"] = 0] = "General";
7238 // Try to generate a simple binding (no temporaries or statements)
7239 // otherwise generate a general binding
7240 BindingForm[BindingForm["TrySimple"] = 1] = "TrySimple";
7241 // Inlines assignment of temporaries into the generated expression. The result may still
7242 // have statements attached for declarations of temporary variables.
7243 // This is the only relevant form for Ivy, the other forms are only used in ViewEngine.
7244 BindingForm[BindingForm["Expression"] = 2] = "Expression";
7245 })(BindingForm || (BindingForm = {}));
7246 /**
7247 * Converts the given expression AST into an executable output AST, assuming the expression
7248 * is used in property binding. The expression has to be preprocessed via
7249 * `convertPropertyBindingBuiltins`.
7250 */
7251 function convertPropertyBinding(localResolver, implicitReceiver, expressionWithoutBuiltins, bindingId, form, interpolationFunction) {
7252 if (!localResolver) {
7253 localResolver = new DefaultLocalResolver();
7254 }
7255 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
7256 const outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
7257 const stmts = getStatementsFromVisitor(visitor, bindingId);
7258 if (visitor.usesImplicitReceiver) {
7259 localResolver.notifyImplicitReceiverUse();
7260 }
7261 if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) {
7262 return new ConvertPropertyBindingResult([], outputExpr);
7263 }
7264 else if (form === BindingForm.Expression) {
7265 return new ConvertPropertyBindingResult(stmts, outputExpr);
7266 }
7267 const currValExpr = createCurrValueExpr(bindingId);
7268 stmts.push(currValExpr.set(outputExpr).toDeclStmt(DYNAMIC_TYPE, [StmtModifier.Final]));
7269 return new ConvertPropertyBindingResult(stmts, currValExpr);
7270 }
7271 /**
7272 * Given some expression, such as a binding or interpolation expression, and a context expression to
7273 * look values up on, visit each facet of the given expression resolving values from the context
7274 * expression such that a list of arguments can be derived from the found values that can be used as
7275 * arguments to an external update instruction.
7276 *
7277 * @param localResolver The resolver to use to look up expressions by name appropriately
7278 * @param contextVariableExpression The expression representing the context variable used to create
7279 * the final argument expressions
7280 * @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to
7281 * be resolved and what arguments list to build.
7282 * @param bindingId A name prefix used to create temporary variable names if they're needed for the
7283 * arguments generated
7284 * @returns An array of expressions that can be passed as arguments to instruction expressions like
7285 * `o.importExpr(R3.propertyInterpolate).callFn(result)`
7286 */
7287 function convertUpdateArguments(localResolver, contextVariableExpression, expressionWithArgumentsToExtract, bindingId) {
7288 const visitor = new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, undefined);
7289 const outputExpr = expressionWithArgumentsToExtract.visit(visitor, _Mode.Expression);
7290 if (visitor.usesImplicitReceiver) {
7291 localResolver.notifyImplicitReceiverUse();
7292 }
7293 const stmts = getStatementsFromVisitor(visitor, bindingId);
7294 // Removing the first argument, because it was a length for ViewEngine, not Ivy.
7295 let args = outputExpr.args.slice(1);
7296 if (expressionWithArgumentsToExtract instanceof Interpolation) {
7297 // If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the
7298 // args returned to just the value, because we're going to pass it to a special instruction.
7299 const strings = expressionWithArgumentsToExtract.strings;
7300 if (args.length === 3 && strings[0] === '' && strings[1] === '') {
7301 // Single argument interpolate instructions.
7302 args = [args[1]];
7303 }
7304 else if (args.length >= 19) {
7305 // 19 or more arguments must be passed to the `interpolateV`-style instructions, which accept
7306 // an array of arguments
7307 args = [literalArr(args)];
7308 }
7309 }
7310 return { stmts, args };
7311 }
7312 function getStatementsFromVisitor(visitor, bindingId) {
7313 const stmts = [];
7314 for (let i = 0; i < visitor.temporaryCount; i++) {
7315 stmts.push(temporaryDeclaration(bindingId, i));
7316 }
7317 return stmts;
7318 }
7319 function convertBuiltins(converterFactory, ast) {
7320 const visitor = new _BuiltinAstConverter(converterFactory);
7321 return ast.visit(visitor);
7322 }
7323 function temporaryName(bindingId, temporaryNumber) {
7324 return `tmp_${bindingId}_${temporaryNumber}`;
7325 }
7326 function temporaryDeclaration(bindingId, temporaryNumber) {
7327 return new DeclareVarStmt(temporaryName(bindingId, temporaryNumber), NULL_EXPR);
7328 }
7329 function prependTemporaryDecls(temporaryCount, bindingId, statements) {
7330 for (let i = temporaryCount - 1; i >= 0; i--) {
7331 statements.unshift(temporaryDeclaration(bindingId, i));
7332 }
7333 }
7334 var _Mode;
7335 (function (_Mode) {
7336 _Mode[_Mode["Statement"] = 0] = "Statement";
7337 _Mode[_Mode["Expression"] = 1] = "Expression";
7338 })(_Mode || (_Mode = {}));
7339 function ensureStatementMode(mode, ast) {
7340 if (mode !== _Mode.Statement) {
7341 throw new Error(`Expected a statement, but saw ${ast}`);
7342 }
7343 }
7344 function ensureExpressionMode(mode, ast) {
7345 if (mode !== _Mode.Expression) {
7346 throw new Error(`Expected an expression, but saw ${ast}`);
7347 }
7348 }
7349 function convertToStatementIfNeeded(mode, expr) {
7350 if (mode === _Mode.Statement) {
7351 return expr.toStmt();
7352 }
7353 else {
7354 return expr;
7355 }
7356 }
7357 class _BuiltinAstConverter extends AstTransformer {
7358 constructor(_converterFactory) {
7359 super();
7360 this._converterFactory = _converterFactory;
7361 }
7362 visitPipe(ast, context) {
7363 const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context));
7364 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createPipeConverter(ast.name, args.length));
7365 }
7366 visitLiteralArray(ast, context) {
7367 const args = ast.expressions.map(ast => ast.visit(this, context));
7368 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralArrayConverter(ast.expressions.length));
7369 }
7370 visitLiteralMap(ast, context) {
7371 const args = ast.values.map(ast => ast.visit(this, context));
7372 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralMapConverter(ast.keys));
7373 }
7374 }
7375 class _AstToIrVisitor {
7376 constructor(_localResolver, _implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses) {
7377 this._localResolver = _localResolver;
7378 this._implicitReceiver = _implicitReceiver;
7379 this.bindingId = bindingId;
7380 this.interpolationFunction = interpolationFunction;
7381 this.baseSourceSpan = baseSourceSpan;
7382 this.implicitReceiverAccesses = implicitReceiverAccesses;
7383 this._nodeMap = new Map();
7384 this._resultMap = new Map();
7385 this._currentTemporary = 0;
7386 this.temporaryCount = 0;
7387 this.usesImplicitReceiver = false;
7388 }
7389 visitUnary(ast, mode) {
7390 let op;
7391 switch (ast.operator) {
7392 case '+':
7393 op = UnaryOperator.Plus;
7394 break;
7395 case '-':
7396 op = UnaryOperator.Minus;
7397 break;
7398 default:
7399 throw new Error(`Unsupported operator ${ast.operator}`);
7400 }
7401 return convertToStatementIfNeeded(mode, new UnaryOperatorExpr(op, this._visit(ast.expr, _Mode.Expression), undefined, this.convertSourceSpan(ast.span)));
7402 }
7403 visitBinary(ast, mode) {
7404 let op;
7405 switch (ast.operation) {
7406 case '+':
7407 op = BinaryOperator.Plus;
7408 break;
7409 case '-':
7410 op = BinaryOperator.Minus;
7411 break;
7412 case '*':
7413 op = BinaryOperator.Multiply;
7414 break;
7415 case '/':
7416 op = BinaryOperator.Divide;
7417 break;
7418 case '%':
7419 op = BinaryOperator.Modulo;
7420 break;
7421 case '&&':
7422 op = BinaryOperator.And;
7423 break;
7424 case '||':
7425 op = BinaryOperator.Or;
7426 break;
7427 case '==':
7428 op = BinaryOperator.Equals;
7429 break;
7430 case '!=':
7431 op = BinaryOperator.NotEquals;
7432 break;
7433 case '===':
7434 op = BinaryOperator.Identical;
7435 break;
7436 case '!==':
7437 op = BinaryOperator.NotIdentical;
7438 break;
7439 case '<':
7440 op = BinaryOperator.Lower;
7441 break;
7442 case '>':
7443 op = BinaryOperator.Bigger;
7444 break;
7445 case '<=':
7446 op = BinaryOperator.LowerEquals;
7447 break;
7448 case '>=':
7449 op = BinaryOperator.BiggerEquals;
7450 break;
7451 default:
7452 throw new Error(`Unsupported operation ${ast.operation}`);
7453 }
7454 return convertToStatementIfNeeded(mode, new BinaryOperatorExpr(op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression), undefined, this.convertSourceSpan(ast.span)));
7455 }
7456 visitChain(ast, mode) {
7457 ensureStatementMode(mode, ast);
7458 return this.visitAll(ast.expressions, mode);
7459 }
7460 visitConditional(ast, mode) {
7461 const value = this._visit(ast.condition, _Mode.Expression);
7462 return convertToStatementIfNeeded(mode, value.conditional(this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span)));
7463 }
7464 visitPipe(ast, mode) {
7465 throw new Error(`Illegal state: Pipes should have been converted into functions. Pipe: ${ast.name}`);
7466 }
7467 visitFunctionCall(ast, mode) {
7468 const convertedArgs = this.visitAll(ast.args, _Mode.Expression);
7469 let fnResult;
7470 if (ast instanceof BuiltinFunctionCall) {
7471 fnResult = ast.converter(convertedArgs);
7472 }
7473 else {
7474 fnResult = this._visit(ast.target, _Mode.Expression)
7475 .callFn(convertedArgs, this.convertSourceSpan(ast.span));
7476 }
7477 return convertToStatementIfNeeded(mode, fnResult);
7478 }
7479 visitImplicitReceiver(ast, mode) {
7480 ensureExpressionMode(mode, ast);
7481 this.usesImplicitReceiver = true;
7482 return this._implicitReceiver;
7483 }
7484 visitThisReceiver(ast, mode) {
7485 return this.visitImplicitReceiver(ast, mode);
7486 }
7487 visitInterpolation(ast, mode) {
7488 ensureExpressionMode(mode, ast);
7489 const args = [literal(ast.expressions.length)];
7490 for (let i = 0; i < ast.strings.length - 1; i++) {
7491 args.push(literal(ast.strings[i]));
7492 args.push(this._visit(ast.expressions[i], _Mode.Expression));
7493 }
7494 args.push(literal(ast.strings[ast.strings.length - 1]));
7495 if (this.interpolationFunction) {
7496 return this.interpolationFunction(args);
7497 }
7498 return ast.expressions.length <= 9 ?
7499 importExpr(Identifiers.inlineInterpolate).callFn(args) :
7500 importExpr(Identifiers.interpolate).callFn([
7501 args[0], literalArr(args.slice(1), undefined, this.convertSourceSpan(ast.span))
7502 ]);
7503 }
7504 visitKeyedRead(ast, mode) {
7505 const leftMostSafe = this.leftMostSafeNode(ast);
7506 if (leftMostSafe) {
7507 return this.convertSafeAccess(ast, leftMostSafe, mode);
7508 }
7509 else {
7510 return convertToStatementIfNeeded(mode, this._visit(ast.obj, _Mode.Expression).key(this._visit(ast.key, _Mode.Expression)));
7511 }
7512 }
7513 visitKeyedWrite(ast, mode) {
7514 const obj = this._visit(ast.obj, _Mode.Expression);
7515 const key = this._visit(ast.key, _Mode.Expression);
7516 const value = this._visit(ast.value, _Mode.Expression);
7517 return convertToStatementIfNeeded(mode, obj.key(key).set(value));
7518 }
7519 visitLiteralArray(ast, mode) {
7520 throw new Error(`Illegal State: literal arrays should have been converted into functions`);
7521 }
7522 visitLiteralMap(ast, mode) {
7523 throw new Error(`Illegal State: literal maps should have been converted into functions`);
7524 }
7525 visitLiteralPrimitive(ast, mode) {
7526 // For literal values of null, undefined, true, or false allow type interference
7527 // to infer the type.
7528 const type = ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
7529 INFERRED_TYPE :
7530 undefined;
7531 return convertToStatementIfNeeded(mode, literal(ast.value, type, this.convertSourceSpan(ast.span)));
7532 }
7533 _getLocal(name, receiver) {
7534 var _a;
7535 if (((_a = this._localResolver.globals) === null || _a === void 0 ? void 0 : _a.has(name)) && receiver instanceof ThisReceiver) {
7536 return null;
7537 }
7538 return this._localResolver.getLocal(name);
7539 }
7540 visitMethodCall(ast, mode) {
7541 if (ast.receiver instanceof ImplicitReceiver &&
7542 !(ast.receiver instanceof ThisReceiver) && ast.name === '$any') {
7543 const args = this.visitAll(ast.args, _Mode.Expression);
7544 if (args.length != 1) {
7545 throw new Error(`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
7546 }
7547 return args[0].cast(DYNAMIC_TYPE, this.convertSourceSpan(ast.span));
7548 }
7549 const leftMostSafe = this.leftMostSafeNode(ast);
7550 if (leftMostSafe) {
7551 return this.convertSafeAccess(ast, leftMostSafe, mode);
7552 }
7553 else {
7554 const args = this.visitAll(ast.args, _Mode.Expression);
7555 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7556 let result = null;
7557 const receiver = this._visit(ast.receiver, _Mode.Expression);
7558 if (receiver === this._implicitReceiver) {
7559 const varExpr = this._getLocal(ast.name, ast.receiver);
7560 if (varExpr) {
7561 // Restore the previous "usesImplicitReceiver" state since the implicit
7562 // receiver has been replaced with a resolved local expression.
7563 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7564 result = varExpr.callFn(args);
7565 this.addImplicitReceiverAccess(ast.name);
7566 }
7567 }
7568 if (result == null) {
7569 result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span));
7570 }
7571 return convertToStatementIfNeeded(mode, result);
7572 }
7573 }
7574 visitPrefixNot(ast, mode) {
7575 return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression)));
7576 }
7577 visitNonNullAssert(ast, mode) {
7578 return convertToStatementIfNeeded(mode, assertNotNull(this._visit(ast.expression, _Mode.Expression)));
7579 }
7580 visitPropertyRead(ast, mode) {
7581 const leftMostSafe = this.leftMostSafeNode(ast);
7582 if (leftMostSafe) {
7583 return this.convertSafeAccess(ast, leftMostSafe, mode);
7584 }
7585 else {
7586 let result = null;
7587 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7588 const receiver = this._visit(ast.receiver, _Mode.Expression);
7589 if (receiver === this._implicitReceiver) {
7590 result = this._getLocal(ast.name, ast.receiver);
7591 if (result) {
7592 // Restore the previous "usesImplicitReceiver" state since the implicit
7593 // receiver has been replaced with a resolved local expression.
7594 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7595 this.addImplicitReceiverAccess(ast.name);
7596 }
7597 }
7598 if (result == null) {
7599 result = receiver.prop(ast.name);
7600 }
7601 return convertToStatementIfNeeded(mode, result);
7602 }
7603 }
7604 visitPropertyWrite(ast, mode) {
7605 const receiver = this._visit(ast.receiver, _Mode.Expression);
7606 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7607 let varExpr = null;
7608 if (receiver === this._implicitReceiver) {
7609 const localExpr = this._getLocal(ast.name, ast.receiver);
7610 if (localExpr) {
7611 if (localExpr instanceof ReadPropExpr) {
7612 // If the local variable is a property read expression, it's a reference
7613 // to a 'context.property' value and will be used as the target of the
7614 // write expression.
7615 varExpr = localExpr;
7616 // Restore the previous "usesImplicitReceiver" state since the implicit
7617 // receiver has been replaced with a resolved local expression.
7618 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7619 this.addImplicitReceiverAccess(ast.name);
7620 }
7621 else {
7622 // Otherwise it's an error.
7623 const receiver = ast.name;
7624 const value = (ast.value instanceof PropertyRead) ? ast.value.name : undefined;
7625 throw new Error(`Cannot assign value "${value}" to template variable "${receiver}". Template variables are read-only.`);
7626 }
7627 }
7628 }
7629 // If no local expression could be produced, use the original receiver's
7630 // property as the target.
7631 if (varExpr === null) {
7632 varExpr = receiver.prop(ast.name);
7633 }
7634 return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression)));
7635 }
7636 visitSafePropertyRead(ast, mode) {
7637 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7638 }
7639 visitSafeMethodCall(ast, mode) {
7640 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7641 }
7642 visitAll(asts, mode) {
7643 return asts.map(ast => this._visit(ast, mode));
7644 }
7645 visitQuote(ast, mode) {
7646 throw new Error(`Quotes are not supported for evaluation!
7647 Statement: ${ast.uninterpretedExpression} located at ${ast.location}`);
7648 }
7649 _visit(ast, mode) {
7650 const result = this._resultMap.get(ast);
7651 if (result)
7652 return result;
7653 return (this._nodeMap.get(ast) || ast).visit(this, mode);
7654 }
7655 convertSafeAccess(ast, leftMostSafe, mode) {
7656 // If the expression contains a safe access node on the left it needs to be converted to
7657 // an expression that guards the access to the member by checking the receiver for blank. As
7658 // execution proceeds from left to right, the left most part of the expression must be guarded
7659 // first but, because member access is left associative, the right side of the expression is at
7660 // the top of the AST. The desired result requires lifting a copy of the left part of the
7661 // expression up to test it for blank before generating the unguarded version.
7662 // Consider, for example the following expression: a?.b.c?.d.e
7663 // This results in the ast:
7664 // .
7665 // / \
7666 // ?. e
7667 // / \
7668 // . d
7669 // / \
7670 // ?. c
7671 // / \
7672 // a b
7673 // The following tree should be generated:
7674 //
7675 // /---- ? ----\
7676 // / | \
7677 // a /--- ? ---\ null
7678 // / | \
7679 // . . null
7680 // / \ / \
7681 // . c . e
7682 // / \ / \
7683 // a b . d
7684 // / \
7685 // . c
7686 // / \
7687 // a b
7688 //
7689 // Notice that the first guard condition is the left hand of the left most safe access node
7690 // which comes in as leftMostSafe to this routine.
7691 let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression);
7692 let temporary = undefined;
7693 if (this.needsTemporary(leftMostSafe.receiver)) {
7694 // If the expression has method calls or pipes then we need to save the result into a
7695 // temporary variable to avoid calling stateful or impure code more than once.
7696 temporary = this.allocateTemporary();
7697 // Preserve the result in the temporary variable
7698 guardedExpression = temporary.set(guardedExpression);
7699 // Ensure all further references to the guarded expression refer to the temporary instead.
7700 this._resultMap.set(leftMostSafe.receiver, temporary);
7701 }
7702 const condition = guardedExpression.isBlank();
7703 // Convert the ast to an unguarded access to the receiver's member. The map will substitute
7704 // leftMostNode with its unguarded version in the call to `this.visit()`.
7705 if (leftMostSafe instanceof SafeMethodCall) {
7706 this._nodeMap.set(leftMostSafe, new MethodCall(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args));
7707 }
7708 else {
7709 this._nodeMap.set(leftMostSafe, new PropertyRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name));
7710 }
7711 // Recursively convert the node now without the guarded member access.
7712 const access = this._visit(ast, _Mode.Expression);
7713 // Remove the mapping. This is not strictly required as the converter only traverses each node
7714 // once but is safer if the conversion is changed to traverse the nodes more than once.
7715 this._nodeMap.delete(leftMostSafe);
7716 // If we allocated a temporary, release it.
7717 if (temporary) {
7718 this.releaseTemporary(temporary);
7719 }
7720 // Produce the conditional
7721 return convertToStatementIfNeeded(mode, condition.conditional(literal(null), access));
7722 }
7723 // Given an expression of the form a?.b.c?.d.e then the left most safe node is
7724 // the (a?.b). The . and ?. are left associative thus can be rewritten as:
7725 // ((((a?.c).b).c)?.d).e. This returns the most deeply nested safe read or
7726 // safe method call as this needs to be transformed initially to:
7727 // a == null ? null : a.c.b.c?.d.e
7728 // then to:
7729 // a == null ? null : a.b.c == null ? null : a.b.c.d.e
7730 leftMostSafeNode(ast) {
7731 const visit = (visitor, ast) => {
7732 return (this._nodeMap.get(ast) || ast).visit(visitor);
7733 };
7734 return ast.visit({
7735 visitUnary(ast) {
7736 return null;
7737 },
7738 visitBinary(ast) {
7739 return null;
7740 },
7741 visitChain(ast) {
7742 return null;
7743 },
7744 visitConditional(ast) {
7745 return null;
7746 },
7747 visitFunctionCall(ast) {
7748 return null;
7749 },
7750 visitImplicitReceiver(ast) {
7751 return null;
7752 },
7753 visitThisReceiver(ast) {
7754 return null;
7755 },
7756 visitInterpolation(ast) {
7757 return null;
7758 },
7759 visitKeyedRead(ast) {
7760 return visit(this, ast.obj);
7761 },
7762 visitKeyedWrite(ast) {
7763 return null;
7764 },
7765 visitLiteralArray(ast) {
7766 return null;
7767 },
7768 visitLiteralMap(ast) {
7769 return null;
7770 },
7771 visitLiteralPrimitive(ast) {
7772 return null;
7773 },
7774 visitMethodCall(ast) {
7775 return visit(this, ast.receiver);
7776 },
7777 visitPipe(ast) {
7778 return null;
7779 },
7780 visitPrefixNot(ast) {
7781 return null;
7782 },
7783 visitNonNullAssert(ast) {
7784 return null;
7785 },
7786 visitPropertyRead(ast) {
7787 return visit(this, ast.receiver);
7788 },
7789 visitPropertyWrite(ast) {
7790 return null;
7791 },
7792 visitQuote(ast) {
7793 return null;
7794 },
7795 visitSafeMethodCall(ast) {
7796 return visit(this, ast.receiver) || ast;
7797 },
7798 visitSafePropertyRead(ast) {
7799 return visit(this, ast.receiver) || ast;
7800 }
7801 });
7802 }
7803 // Returns true of the AST includes a method or a pipe indicating that, if the
7804 // expression is used as the target of a safe property or method access then
7805 // the expression should be stored into a temporary variable.
7806 needsTemporary(ast) {
7807 const visit = (visitor, ast) => {
7808 return ast && (this._nodeMap.get(ast) || ast).visit(visitor);
7809 };
7810 const visitSome = (visitor, ast) => {
7811 return ast.some(ast => visit(visitor, ast));
7812 };
7813 return ast.visit({
7814 visitUnary(ast) {
7815 return visit(this, ast.expr);
7816 },
7817 visitBinary(ast) {
7818 return visit(this, ast.left) || visit(this, ast.right);
7819 },
7820 visitChain(ast) {
7821 return false;
7822 },
7823 visitConditional(ast) {
7824 return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp);
7825 },
7826 visitFunctionCall(ast) {
7827 return true;
7828 },
7829 visitImplicitReceiver(ast) {
7830 return false;
7831 },
7832 visitThisReceiver(ast) {
7833 return false;
7834 },
7835 visitInterpolation(ast) {
7836 return visitSome(this, ast.expressions);
7837 },
7838 visitKeyedRead(ast) {
7839 return false;
7840 },
7841 visitKeyedWrite(ast) {
7842 return false;
7843 },
7844 visitLiteralArray(ast) {
7845 return true;
7846 },
7847 visitLiteralMap(ast) {
7848 return true;
7849 },
7850 visitLiteralPrimitive(ast) {
7851 return false;
7852 },
7853 visitMethodCall(ast) {
7854 return true;
7855 },
7856 visitPipe(ast) {
7857 return true;
7858 },
7859 visitPrefixNot(ast) {
7860 return visit(this, ast.expression);
7861 },
7862 visitNonNullAssert(ast) {
7863 return visit(this, ast.expression);
7864 },
7865 visitPropertyRead(ast) {
7866 return false;
7867 },
7868 visitPropertyWrite(ast) {
7869 return false;
7870 },
7871 visitQuote(ast) {
7872 return false;
7873 },
7874 visitSafeMethodCall(ast) {
7875 return true;
7876 },
7877 visitSafePropertyRead(ast) {
7878 return false;
7879 }
7880 });
7881 }
7882 allocateTemporary() {
7883 const tempNumber = this._currentTemporary++;
7884 this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount);
7885 return new ReadVarExpr(temporaryName(this.bindingId, tempNumber));
7886 }
7887 releaseTemporary(temporary) {
7888 this._currentTemporary--;
7889 if (temporary.name != temporaryName(this.bindingId, this._currentTemporary)) {
7890 throw new Error(`Temporary ${temporary.name} released out of order`);
7891 }
7892 }
7893 /**
7894 * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`.
7895 *
7896 * `ParseSpan` objects are relative to the start of the expression.
7897 * This method converts these to full `ParseSourceSpan` objects that
7898 * show where the span is within the overall source file.
7899 *
7900 * @param span the relative span to convert.
7901 * @returns a `ParseSourceSpan` for the given span or null if no
7902 * `baseSourceSpan` was provided to this class.
7903 */
7904 convertSourceSpan(span) {
7905 if (this.baseSourceSpan) {
7906 const start = this.baseSourceSpan.start.moveBy(span.start);
7907 const end = this.baseSourceSpan.start.moveBy(span.end);
7908 const fullStart = this.baseSourceSpan.fullStart.moveBy(span.start);
7909 return new ParseSourceSpan(start, end, fullStart);
7910 }
7911 else {
7912 return null;
7913 }
7914 }
7915 /** Adds the name of an AST to the list of implicit receiver accesses. */
7916 addImplicitReceiverAccess(name) {
7917 if (this.implicitReceiverAccesses) {
7918 this.implicitReceiverAccesses.add(name);
7919 }
7920 }
7921 }
7922 function flattenStatements(arg, output) {
7923 if (Array.isArray(arg)) {
7924 arg.forEach((entry) => flattenStatements(entry, output));
7925 }
7926 else {
7927 output.push(arg);
7928 }
7929 }
7930 class DefaultLocalResolver {
7931 constructor(globals) {
7932 this.globals = globals;
7933 }
7934 notifyImplicitReceiverUse() { }
7935 getLocal(name) {
7936 if (name === EventHandlerVars.event.name) {
7937 return EventHandlerVars.event;
7938 }
7939 return null;
7940 }
7941 }
7942 function createCurrValueExpr(bindingId) {
7943 return variable(`currVal_${bindingId}`); // fix syntax highlighting: `
7944 }
7945 function createPreventDefaultVar(bindingId) {
7946 return variable(`pd_${bindingId}`);
7947 }
7948 function convertStmtIntoExpression(stmt) {
7949 if (stmt instanceof ExpressionStatement) {
7950 return stmt.expr;
7951 }
7952 else if (stmt instanceof ReturnStatement) {
7953 return stmt.value;
7954 }
7955 return null;
7956 }
7957 class BuiltinFunctionCall extends FunctionCall {
7958 constructor(span, sourceSpan, args, converter) {
7959 super(span, sourceSpan, null, args);
7960 this.args = args;
7961 this.converter = converter;
7962 }
7963 }
7964
7965 /**
7966 * @license
7967 * Copyright Google LLC All Rights Reserved.
7968 *
7969 * Use of this source code is governed by an MIT-style license that can be
7970 * found in the LICENSE file at https://angular.io/license
7971 */
7972 /**
7973 * This file is a port of shadowCSS from webcomponents.js to TypeScript.
7974 *
7975 * Please make sure to keep to edits in sync with the source file.
7976 *
7977 * Source:
7978 * https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
7979 *
7980 * The original file level comment is reproduced below
7981 */
7982 /*
7983 This is a limited shim for ShadowDOM css styling.
7984 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles
7985
7986 The intention here is to support only the styling features which can be
7987 relatively simply implemented. The goal is to allow users to avoid the
7988 most obvious pitfalls and do so without compromising performance significantly.
7989 For ShadowDOM styling that's not covered here, a set of best practices
7990 can be provided that should allow users to accomplish more complex styling.
7991
7992 The following is a list of specific ShadowDOM styling features and a brief
7993 discussion of the approach used to shim.
7994
7995 Shimmed features:
7996
7997 * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
7998 element using the :host rule. To shim this feature, the :host styles are
7999 reformatted and prefixed with a given scope name and promoted to a
8000 document level stylesheet.
8001 For example, given a scope name of .foo, a rule like this:
8002
8003 :host {
8004 background: red;
8005 }
8006 }
8007
8008 becomes:
8009
8010 .foo {
8011 background: red;
8012 }
8013
8014 * encapsulation: Styles defined within ShadowDOM, apply only to
8015 dom inside the ShadowDOM. Polymer uses one of two techniques to implement
8016 this feature.
8017
8018 By default, rules are prefixed with the host element tag name
8019 as a descendant selector. This ensures styling does not leak out of the 'top'
8020 of the element's ShadowDOM. For example,
8021
8022 div {
8023 font-weight: bold;
8024 }
8025
8026 becomes:
8027
8028 x-foo div {
8029 font-weight: bold;
8030 }
8031
8032 becomes:
8033
8034
8035 Alternatively, if WebComponents.ShadowCSS.strictStyling is set to true then
8036 selectors are scoped by adding an attribute selector suffix to each
8037 simple selector that contains the host element tag name. Each element
8038 in the element's ShadowDOM template is also given the scope attribute.
8039 Thus, these rules match only elements that have the scope attribute.
8040 For example, given a scope name of x-foo, a rule like this:
8041
8042 div {
8043 font-weight: bold;
8044 }
8045
8046 becomes:
8047
8048 div[x-foo] {
8049 font-weight: bold;
8050 }
8051
8052 Note that elements that are dynamically added to a scope must have the scope
8053 selector added to them manually.
8054
8055 * upper/lower bound encapsulation: Styles which are defined outside a
8056 shadowRoot should not cross the ShadowDOM boundary and should not apply
8057 inside a shadowRoot.
8058
8059 This styling behavior is not emulated. Some possible ways to do this that
8060 were rejected due to complexity and/or performance concerns include: (1) reset
8061 every possible property for every possible selector for a given scope name;
8062 (2) re-implement css in javascript.
8063
8064 As an alternative, users should make sure to use selectors
8065 specific to the scope in which they are working.
8066
8067 * ::distributed: This behavior is not emulated. It's often not necessary
8068 to style the contents of a specific insertion point and instead, descendants
8069 of the host element can be styled selectively. Users can also create an
8070 extra node around an insertion point and style that node's contents
8071 via descendent selectors. For example, with a shadowRoot like this:
8072
8073 <style>
8074 ::content(div) {
8075 background: red;
8076 }
8077 </style>
8078 <content></content>
8079
8080 could become:
8081
8082 <style>
8083 / *@polyfill .content-container div * /
8084 ::content(div) {
8085 background: red;
8086 }
8087 </style>
8088 <div class="content-container">
8089 <content></content>
8090 </div>
8091
8092 Note the use of @polyfill in the comment above a ShadowDOM specific style
8093 declaration. This is a directive to the styling shim to use the selector
8094 in comments in lieu of the next selector when running under polyfill.
8095 */
8096 class ShadowCss {
8097 constructor() {
8098 this.strictStyling = true;
8099 }
8100 /*
8101 * Shim some cssText with the given selector. Returns cssText that can
8102 * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css).
8103 *
8104 * When strictStyling is true:
8105 * - selector is the attribute added to all elements inside the host,
8106 * - hostSelector is the attribute added to the host itself.
8107 */
8108 shimCssText(cssText, selector, hostSelector = '') {
8109 const commentsWithHash = extractCommentsWithHash(cssText);
8110 cssText = stripComments(cssText);
8111 cssText = this._insertDirectives(cssText);
8112 const scopedCssText = this._scopeCssText(cssText, selector, hostSelector);
8113 return [scopedCssText, ...commentsWithHash].join('\n');
8114 }
8115 _insertDirectives(cssText) {
8116 cssText = this._insertPolyfillDirectivesInCssText(cssText);
8117 return this._insertPolyfillRulesInCssText(cssText);
8118 }
8119 /*
8120 * Process styles to convert native ShadowDOM rules that will trip
8121 * up the css parser; we rely on decorating the stylesheet with inert rules.
8122 *
8123 * For example, we convert this rule:
8124 *
8125 * polyfill-next-selector { content: ':host menu-item'; }
8126 * ::content menu-item {
8127 *
8128 * to this:
8129 *
8130 * scopeName menu-item {
8131 *
8132 **/
8133 _insertPolyfillDirectivesInCssText(cssText) {
8134 // Difference with webcomponents.js: does not handle comments
8135 return cssText.replace(_cssContentNextSelectorRe, function (...m) {
8136 return m[2] + '{';
8137 });
8138 }
8139 /*
8140 * Process styles to add rules which will only apply under the polyfill
8141 *
8142 * For example, we convert this rule:
8143 *
8144 * polyfill-rule {
8145 * content: ':host menu-item';
8146 * ...
8147 * }
8148 *
8149 * to this:
8150 *
8151 * scopeName menu-item {...}
8152 *
8153 **/
8154 _insertPolyfillRulesInCssText(cssText) {
8155 // Difference with webcomponents.js: does not handle comments
8156 return cssText.replace(_cssContentRuleRe, (...m) => {
8157 const rule = m[0].replace(m[1], '').replace(m[2], '');
8158 return m[4] + rule;
8159 });
8160 }
8161 /* Ensure styles are scoped. Pseudo-scoping takes a rule like:
8162 *
8163 * .foo {... }
8164 *
8165 * and converts this to
8166 *
8167 * scopeName .foo { ... }
8168 */
8169 _scopeCssText(cssText, scopeSelector, hostSelector) {
8170 const unscopedRules = this._extractUnscopedRulesFromCssText(cssText);
8171 // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively
8172 cssText = this._insertPolyfillHostInCssText(cssText);
8173 cssText = this._convertColonHost(cssText);
8174 cssText = this._convertColonHostContext(cssText);
8175 cssText = this._convertShadowDOMSelectors(cssText);
8176 if (scopeSelector) {
8177 cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
8178 }
8179 cssText = cssText + '\n' + unscopedRules;
8180 return cssText.trim();
8181 }
8182 /*
8183 * Process styles to add rules which will only apply under the polyfill
8184 * and do not process via CSSOM. (CSSOM is destructive to rules on rare
8185 * occasions, e.g. -webkit-calc on Safari.)
8186 * For example, we convert this rule:
8187 *
8188 * @polyfill-unscoped-rule {
8189 * content: 'menu-item';
8190 * ... }
8191 *
8192 * to this:
8193 *
8194 * menu-item {...}
8195 *
8196 **/
8197 _extractUnscopedRulesFromCssText(cssText) {
8198 // Difference with webcomponents.js: does not handle comments
8199 let r = '';
8200 let m;
8201 _cssContentUnscopedRuleRe.lastIndex = 0;
8202 while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
8203 const rule = m[0].replace(m[2], '').replace(m[1], m[4]);
8204 r += rule + '\n\n';
8205 }
8206 return r;
8207 }
8208 /*
8209 * convert a rule like :host(.foo) > .bar { }
8210 *
8211 * to
8212 *
8213 * .foo<scopeName> > .bar
8214 */
8215 _convertColonHost(cssText) {
8216 return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer);
8217 }
8218 /*
8219 * convert a rule like :host-context(.foo) > .bar { }
8220 *
8221 * to
8222 *
8223 * .foo<scopeName> > .bar, .foo scopeName > .bar { }
8224 *
8225 * and
8226 *
8227 * :host-context(.foo:host) .bar { ... }
8228 *
8229 * to
8230 *
8231 * .foo<scopeName> .bar { ... }
8232 */
8233 _convertColonHostContext(cssText) {
8234 return this._convertColonRule(cssText, _cssColonHostContextRe, this._colonHostContextPartReplacer);
8235 }
8236 _convertColonRule(cssText, regExp, partReplacer) {
8237 // m[1] = :host(-context), m[2] = contents of (), m[3] rest of rule
8238 return cssText.replace(regExp, function (...m) {
8239 if (m[2]) {
8240 const parts = m[2].split(',');
8241 const r = [];
8242 for (let i = 0; i < parts.length; i++) {
8243 const p = parts[i].trim();
8244 if (!p)
8245 break;
8246 r.push(partReplacer(_polyfillHostNoCombinator, p, m[3]));
8247 }
8248 return r.join(',');
8249 }
8250 else {
8251 return _polyfillHostNoCombinator + m[3];
8252 }
8253 });
8254 }
8255 _colonHostContextPartReplacer(host, part, suffix) {
8256 if (part.indexOf(_polyfillHost) > -1) {
8257 return this._colonHostPartReplacer(host, part, suffix);
8258 }
8259 else {
8260 return host + part + suffix + ', ' + part + ' ' + host + suffix;
8261 }
8262 }
8263 _colonHostPartReplacer(host, part, suffix) {
8264 return host + part.replace(_polyfillHost, '') + suffix;
8265 }
8266 /*
8267 * Convert combinators like ::shadow and pseudo-elements like ::content
8268 * by replacing with space.
8269 */
8270 _convertShadowDOMSelectors(cssText) {
8271 return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText);
8272 }
8273 // change a selector like 'div' to 'name div'
8274 _scopeSelectors(cssText, scopeSelector, hostSelector) {
8275 return processRules(cssText, (rule) => {
8276 let selector = rule.selector;
8277 let content = rule.content;
8278 if (rule.selector[0] != '@') {
8279 selector =
8280 this._scopeSelector(rule.selector, scopeSelector, hostSelector, this.strictStyling);
8281 }
8282 else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') ||
8283 rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) {
8284 content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
8285 }
8286 return new CssRule(selector, content);
8287 });
8288 }
8289 _scopeSelector(selector, scopeSelector, hostSelector, strict) {
8290 return selector.split(',')
8291 .map(part => part.trim().split(_shadowDeepSelectors))
8292 .map((deepParts) => {
8293 const [shallowPart, ...otherParts] = deepParts;
8294 const applyScope = (shallowPart) => {
8295 if (this._selectorNeedsScoping(shallowPart, scopeSelector)) {
8296 return strict ?
8297 this._applyStrictSelectorScope(shallowPart, scopeSelector, hostSelector) :
8298 this._applySelectorScope(shallowPart, scopeSelector, hostSelector);
8299 }
8300 else {
8301 return shallowPart;
8302 }
8303 };
8304 return [applyScope(shallowPart), ...otherParts].join(' ');
8305 })
8306 .join(', ');
8307 }
8308 _selectorNeedsScoping(selector, scopeSelector) {
8309 const re = this._makeScopeMatcher(scopeSelector);
8310 return !re.test(selector);
8311 }
8312 _makeScopeMatcher(scopeSelector) {
8313 const lre = /\[/g;
8314 const rre = /\]/g;
8315 scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
8316 return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
8317 }
8318 _applySelectorScope(selector, scopeSelector, hostSelector) {
8319 // Difference from webcomponents.js: scopeSelector could not be an array
8320 return this._applySimpleSelectorScope(selector, scopeSelector, hostSelector);
8321 }
8322 // scope via name and [is=name]
8323 _applySimpleSelectorScope(selector, scopeSelector, hostSelector) {
8324 // In Android browser, the lastIndex is not reset when the regex is used in String.replace()
8325 _polyfillHostRe.lastIndex = 0;
8326 if (_polyfillHostRe.test(selector)) {
8327 const replaceBy = this.strictStyling ? `[${hostSelector}]` : scopeSelector;
8328 return selector
8329 .replace(_polyfillHostNoCombinatorRe, (hnc, selector) => {
8330 return selector.replace(/([^:]*)(:*)(.*)/, (_, before, colon, after) => {
8331 return before + replaceBy + colon + after;
8332 });
8333 })
8334 .replace(_polyfillHostRe, replaceBy + ' ');
8335 }
8336 return scopeSelector + ' ' + selector;
8337 }
8338 // return a selector with [name] suffix on each simple selector
8339 // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */
8340 _applyStrictSelectorScope(selector, scopeSelector, hostSelector) {
8341 const isRe = /\[is=([^\]]*)\]/g;
8342 scopeSelector = scopeSelector.replace(isRe, (_, ...parts) => parts[0]);
8343 const attrName = '[' + scopeSelector + ']';
8344 const _scopeSelectorPart = (p) => {
8345 let scopedP = p.trim();
8346 if (!scopedP) {
8347 return '';
8348 }
8349 if (p.indexOf(_polyfillHostNoCombinator) > -1) {
8350 scopedP = this._applySimpleSelectorScope(p, scopeSelector, hostSelector);
8351 }
8352 else {
8353 // remove :host since it should be unnecessary
8354 const t = p.replace(_polyfillHostRe, '');
8355 if (t.length > 0) {
8356 const matches = t.match(/([^:]*)(:*)(.*)/);
8357 if (matches) {
8358 scopedP = matches[1] + attrName + matches[2] + matches[3];
8359 }
8360 }
8361 }
8362 return scopedP;
8363 };
8364 const safeContent = new SafeSelector(selector);
8365 selector = safeContent.content();
8366 let scopedSelector = '';
8367 let startIndex = 0;
8368 let res;
8369 const sep = /( |>|\+|~(?!=))\s*/g;
8370 // If a selector appears before :host it should not be shimmed as it
8371 // matches on ancestor elements and not on elements in the host's shadow
8372 // `:host-context(div)` is transformed to
8373 // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator`
8374 // the `div` is not part of the component in the 2nd selectors and should not be scoped.
8375 // Historically `component-tag:host` was matching the component so we also want to preserve
8376 // this behavior to avoid breaking legacy apps (it should not match).
8377 // The behavior should be:
8378 // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything)
8379 // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a
8380 // `:host-context(tag)`)
8381 const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;
8382 // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present
8383 let shouldScope = !hasHost;
8384 while ((res = sep.exec(selector)) !== null) {
8385 const separator = res[1];
8386 const part = selector.slice(startIndex, res.index).trim();
8387 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
8388 const scopedPart = shouldScope ? _scopeSelectorPart(part) : part;
8389 scopedSelector += `${scopedPart} ${separator} `;
8390 startIndex = sep.lastIndex;
8391 }
8392 const part = selector.substring(startIndex);
8393 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
8394 scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;
8395 // replace the placeholders with their original values
8396 return safeContent.restore(scopedSelector);
8397 }
8398 _insertPolyfillHostInCssText(selector) {
8399 return selector.replace(_colonHostContextRe, _polyfillHostContext)
8400 .replace(_colonHostRe, _polyfillHost);
8401 }
8402 }
8403 class SafeSelector {
8404 constructor(selector) {
8405 this.placeholders = [];
8406 this.index = 0;
8407 // Replaces attribute selectors with placeholders.
8408 // The WS in [attr="va lue"] would otherwise be interpreted as a selector separator.
8409 selector = this._escapeRegexMatches(selector, /(\[[^\]]*\])/g);
8410 // CSS allows for certain special characters to be used in selectors if they're escaped.
8411 // E.g. `.foo:blue` won't match a class called `foo:blue`, because the colon denotes a
8412 // pseudo-class, but writing `.foo\:blue` will match, because the colon was escaped.
8413 // Replace all escape sequences (`\` followed by a character) with a placeholder so
8414 // that our handling of pseudo-selectors doesn't mess with them.
8415 selector = this._escapeRegexMatches(selector, /(\\.)/g);
8416 // Replaces the expression in `:nth-child(2n + 1)` with a placeholder.
8417 // WS and "+" would otherwise be interpreted as selector separators.
8418 this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => {
8419 const replaceBy = `__ph-${this.index}__`;
8420 this.placeholders.push(exp);
8421 this.index++;
8422 return pseudo + replaceBy;
8423 });
8424 }
8425 restore(content) {
8426 return content.replace(/__ph-(\d+)__/g, (_ph, index) => this.placeholders[+index]);
8427 }
8428 content() {
8429 return this._content;
8430 }
8431 /**
8432 * Replaces all of the substrings that match a regex within a
8433 * special string (e.g. `__ph-0__`, `__ph-1__`, etc).
8434 */
8435 _escapeRegexMatches(content, pattern) {
8436 return content.replace(pattern, (_, keep) => {
8437 const replaceBy = `__ph-${this.index}__`;
8438 this.placeholders.push(keep);
8439 this.index++;
8440 return replaceBy;
8441 });
8442 }
8443 }
8444 const _cssContentNextSelectorRe = /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim;
8445 const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
8446 const _cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
8447 const _polyfillHost = '-shadowcsshost';
8448 // note: :host-context pre-processed to -shadowcsshostcontext.
8449 const _polyfillHostContext = '-shadowcsscontext';
8450 const _parenSuffix = ')(?:\\((' +
8451 '(?:\\([^)(]*\\)|[^)(]*)+?' +
8452 ')\\))?([^,{]*)';
8453 const _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim');
8454 const _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim');
8455 const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
8456 const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
8457 const _shadowDOMSelectorsRe = [
8458 /::shadow/g,
8459 /::content/g,
8460 // Deprecated selectors
8461 /\/shadow-deep\//g,
8462 /\/shadow\//g,
8463 ];
8464 // The deep combinator is deprecated in the CSS spec
8465 // Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future.
8466 // see https://github.com/angular/angular/pull/17677
8467 const _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g;
8468 const _selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$';
8469 const _polyfillHostRe = /-shadowcsshost/gim;
8470 const _colonHostRe = /:host/gim;
8471 const _colonHostContextRe = /:host-context/gim;
8472 const _commentRe = /\/\*\s*[\s\S]*?\*\//g;
8473 function stripComments(input) {
8474 return input.replace(_commentRe, '');
8475 }
8476 const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g;
8477 function extractCommentsWithHash(input) {
8478 return input.match(_commentWithHashRe) || [];
8479 }
8480 const BLOCK_PLACEHOLDER = '%BLOCK%';
8481 const QUOTE_PLACEHOLDER = '%QUOTED%';
8482 const _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g;
8483 const _quotedRe = /%QUOTED%/g;
8484 const CONTENT_PAIRS = new Map([['{', '}']]);
8485 const QUOTE_PAIRS = new Map([[`"`, `"`], [`'`, `'`]]);
8486 class CssRule {
8487 constructor(selector, content) {
8488 this.selector = selector;
8489 this.content = content;
8490 }
8491 }
8492 function processRules(input, ruleCallback) {
8493 const inputWithEscapedQuotes = escapeBlocks(input, QUOTE_PAIRS, QUOTE_PLACEHOLDER);
8494 const inputWithEscapedBlocks = escapeBlocks(inputWithEscapedQuotes.escapedString, CONTENT_PAIRS, BLOCK_PLACEHOLDER);
8495 let nextBlockIndex = 0;
8496 let nextQuoteIndex = 0;
8497 return inputWithEscapedBlocks.escapedString
8498 .replace(_ruleRe, (...m) => {
8499 const selector = m[2];
8500 let content = '';
8501 let suffix = m[4];
8502 let contentPrefix = '';
8503 if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
8504 content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
8505 suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
8506 contentPrefix = '{';
8507 }
8508 const rule = ruleCallback(new CssRule(selector, content));
8509 return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
8510 })
8511 .replace(_quotedRe, () => inputWithEscapedQuotes.blocks[nextQuoteIndex++]);
8512 }
8513 class StringWithEscapedBlocks {
8514 constructor(escapedString, blocks) {
8515 this.escapedString = escapedString;
8516 this.blocks = blocks;
8517 }
8518 }
8519 function escapeBlocks(input, charPairs, placeholder) {
8520 const resultParts = [];
8521 const escapedBlocks = [];
8522 let openCharCount = 0;
8523 let nonBlockStartIndex = 0;
8524 let blockStartIndex = -1;
8525 let openChar;
8526 let closeChar;
8527 for (let i = 0; i < input.length; i++) {
8528 const char = input[i];
8529 if (char === '\\') {
8530 i++;
8531 }
8532 else if (char === closeChar) {
8533 openCharCount--;
8534 if (openCharCount === 0) {
8535 escapedBlocks.push(input.substring(blockStartIndex, i));
8536 resultParts.push(placeholder);
8537 nonBlockStartIndex = i;
8538 blockStartIndex = -1;
8539 openChar = closeChar = undefined;
8540 }
8541 }
8542 else if (char === openChar) {
8543 openCharCount++;
8544 }
8545 else if (openCharCount === 0 && charPairs.has(char)) {
8546 openChar = char;
8547 closeChar = charPairs.get(char);
8548 openCharCount = 1;
8549 blockStartIndex = i + 1;
8550 resultParts.push(input.substring(nonBlockStartIndex, blockStartIndex));
8551 }
8552 }
8553 if (blockStartIndex !== -1) {
8554 escapedBlocks.push(input.substring(blockStartIndex));
8555 resultParts.push(placeholder);
8556 }
8557 else {
8558 resultParts.push(input.substring(nonBlockStartIndex));
8559 }
8560 return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
8561 }
8562
8563 /**
8564 * @license
8565 * Copyright Google LLC All Rights Reserved.
8566 *
8567 * Use of this source code is governed by an MIT-style license that can be
8568 * found in the LICENSE file at https://angular.io/license
8569 */
8570 const COMPONENT_VARIABLE = '%COMP%';
8571 const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
8572 const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
8573
8574 /**
8575 * @license
8576 * Copyright Google LLC All Rights Reserved.
8577 *
8578 * Use of this source code is governed by an MIT-style license that can be
8579 * found in the LICENSE file at https://angular.io/license
8580 */
8581 /**
8582 * A path is an ordered set of elements. Typically a path is to a
8583 * particular offset in a source file. The head of the list is the top
8584 * most node. The tail is the node that contains the offset directly.
8585 *
8586 * For example, the expression `a + b + c` might have an ast that looks
8587 * like:
8588 * +
8589 * / \
8590 * a +
8591 * / \
8592 * b c
8593 *
8594 * The path to the node at offset 9 would be `['+' at 1-10, '+' at 7-10,
8595 * 'c' at 9-10]` and the path the node at offset 1 would be
8596 * `['+' at 1-10, 'a' at 1-2]`.
8597 */
8598 class AstPath {
8599 constructor(path, position = -1) {
8600 this.path = path;
8601 this.position = position;
8602 }
8603 get empty() {
8604 return !this.path || !this.path.length;
8605 }
8606 get head() {
8607 return this.path[0];
8608 }
8609 get tail() {
8610 return this.path[this.path.length - 1];
8611 }
8612 parentOf(node) {
8613 return node && this.path[this.path.indexOf(node) - 1];
8614 }
8615 childOf(node) {
8616 return this.path[this.path.indexOf(node) + 1];
8617 }
8618 first(ctor) {
8619 for (let i = this.path.length - 1; i >= 0; i--) {
8620 let item = this.path[i];
8621 if (item instanceof ctor)
8622 return item;
8623 }
8624 }
8625 push(node) {
8626 this.path.push(node);
8627 }
8628 pop() {
8629 return this.path.pop();
8630 }
8631 }
8632
8633 /**
8634 * @license
8635 * Copyright Google LLC All Rights Reserved.
8636 *
8637 * Use of this source code is governed by an MIT-style license that can be
8638 * found in the LICENSE file at https://angular.io/license
8639 */
8640 class NodeWithI18n {
8641 constructor(sourceSpan, i18n) {
8642 this.sourceSpan = sourceSpan;
8643 this.i18n = i18n;
8644 }
8645 }
8646 class Text$2 extends NodeWithI18n {
8647 constructor(value, sourceSpan, i18n) {
8648 super(sourceSpan, i18n);
8649 this.value = value;
8650 }
8651 visit(visitor, context) {
8652 return visitor.visitText(this, context);
8653 }
8654 }
8655 class Expansion extends NodeWithI18n {
8656 constructor(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) {
8657 super(sourceSpan, i18n);
8658 this.switchValue = switchValue;
8659 this.type = type;
8660 this.cases = cases;
8661 this.switchValueSourceSpan = switchValueSourceSpan;
8662 }
8663 visit(visitor, context) {
8664 return visitor.visitExpansion(this, context);
8665 }
8666 }
8667 class ExpansionCase {
8668 constructor(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) {
8669 this.value = value;
8670 this.expression = expression;
8671 this.sourceSpan = sourceSpan;
8672 this.valueSourceSpan = valueSourceSpan;
8673 this.expSourceSpan = expSourceSpan;
8674 }
8675 visit(visitor, context) {
8676 return visitor.visitExpansionCase(this, context);
8677 }
8678 }
8679 class Attribute extends NodeWithI18n {
8680 constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) {
8681 super(sourceSpan, i18n);
8682 this.name = name;
8683 this.value = value;
8684 this.keySpan = keySpan;
8685 this.valueSpan = valueSpan;
8686 }
8687 visit(visitor, context) {
8688 return visitor.visitAttribute(this, context);
8689 }
8690 }
8691 class Element$1 extends NodeWithI18n {
8692 constructor(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
8693 super(sourceSpan, i18n);
8694 this.name = name;
8695 this.attrs = attrs;
8696 this.children = children;
8697 this.startSourceSpan = startSourceSpan;
8698 this.endSourceSpan = endSourceSpan;
8699 }
8700 visit(visitor, context) {
8701 return visitor.visitElement(this, context);
8702 }
8703 }
8704 class Comment {
8705 constructor(value, sourceSpan) {
8706 this.value = value;
8707 this.sourceSpan = sourceSpan;
8708 }
8709 visit(visitor, context) {
8710 return visitor.visitComment(this, context);
8711 }
8712 }
8713 function visitAll$1(visitor, nodes, context = null) {
8714 const result = [];
8715 const visit = visitor.visit ?
8716 (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) :
8717 (ast) => ast.visit(visitor, context);
8718 nodes.forEach(ast => {
8719 const astResult = visit(ast);
8720 if (astResult) {
8721 result.push(astResult);
8722 }
8723 });
8724 return result;
8725 }
8726 class RecursiveVisitor {
8727 constructor() { }
8728 visitElement(ast, context) {
8729 this.visitChildren(context, visit => {
8730 visit(ast.attrs);
8731 visit(ast.children);
8732 });
8733 }
8734 visitAttribute(ast, context) { }
8735 visitText(ast, context) { }
8736 visitComment(ast, context) { }
8737 visitExpansion(ast, context) {
8738 return this.visitChildren(context, visit => {
8739 visit(ast.cases);
8740 });
8741 }
8742 visitExpansionCase(ast, context) { }
8743 visitChildren(context, cb) {
8744 let results = [];
8745 let t = this;
8746 function visit(children) {
8747 if (children)
8748 results.push(visitAll$1(t, children, context));
8749 }
8750 cb(visit);
8751 return Array.prototype.concat.apply([], results);
8752 }
8753 }
8754
8755 /**
8756 * @license
8757 * Copyright Google LLC All Rights Reserved.
8758 *
8759 * Use of this source code is governed by an MIT-style license that can be
8760 * found in the LICENSE file at https://angular.io/license
8761 */
8762 var TokenType;
8763 (function (TokenType) {
8764 TokenType[TokenType["TAG_OPEN_START"] = 0] = "TAG_OPEN_START";
8765 TokenType[TokenType["TAG_OPEN_END"] = 1] = "TAG_OPEN_END";
8766 TokenType[TokenType["TAG_OPEN_END_VOID"] = 2] = "TAG_OPEN_END_VOID";
8767 TokenType[TokenType["TAG_CLOSE"] = 3] = "TAG_CLOSE";
8768 TokenType[TokenType["INCOMPLETE_TAG_OPEN"] = 4] = "INCOMPLETE_TAG_OPEN";
8769 TokenType[TokenType["TEXT"] = 5] = "TEXT";
8770 TokenType[TokenType["ESCAPABLE_RAW_TEXT"] = 6] = "ESCAPABLE_RAW_TEXT";
8771 TokenType[TokenType["RAW_TEXT"] = 7] = "RAW_TEXT";
8772 TokenType[TokenType["COMMENT_START"] = 8] = "COMMENT_START";
8773 TokenType[TokenType["COMMENT_END"] = 9] = "COMMENT_END";
8774 TokenType[TokenType["CDATA_START"] = 10] = "CDATA_START";
8775 TokenType[TokenType["CDATA_END"] = 11] = "CDATA_END";
8776 TokenType[TokenType["ATTR_NAME"] = 12] = "ATTR_NAME";
8777 TokenType[TokenType["ATTR_QUOTE"] = 13] = "ATTR_QUOTE";
8778 TokenType[TokenType["ATTR_VALUE"] = 14] = "ATTR_VALUE";
8779 TokenType[TokenType["DOC_TYPE"] = 15] = "DOC_TYPE";
8780 TokenType[TokenType["EXPANSION_FORM_START"] = 16] = "EXPANSION_FORM_START";
8781 TokenType[TokenType["EXPANSION_CASE_VALUE"] = 17] = "EXPANSION_CASE_VALUE";
8782 TokenType[TokenType["EXPANSION_CASE_EXP_START"] = 18] = "EXPANSION_CASE_EXP_START";
8783 TokenType[TokenType["EXPANSION_CASE_EXP_END"] = 19] = "EXPANSION_CASE_EXP_END";
8784 TokenType[TokenType["EXPANSION_FORM_END"] = 20] = "EXPANSION_FORM_END";
8785 TokenType[TokenType["EOF"] = 21] = "EOF";
8786 })(TokenType || (TokenType = {}));
8787 class Token {
8788 constructor(type, parts, sourceSpan) {
8789 this.type = type;
8790 this.parts = parts;
8791 this.sourceSpan = sourceSpan;
8792 }
8793 }
8794 class TokenError extends ParseError {
8795 constructor(errorMsg, tokenType, span) {
8796 super(span, errorMsg);
8797 this.tokenType = tokenType;
8798 }
8799 }
8800 class TokenizeResult {
8801 constructor(tokens, errors, nonNormalizedIcuExpressions) {
8802 this.tokens = tokens;
8803 this.errors = errors;
8804 this.nonNormalizedIcuExpressions = nonNormalizedIcuExpressions;
8805 }
8806 }
8807 function tokenize(source, url, getTagDefinition, options = {}) {
8808 const tokenizer = new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options);
8809 tokenizer.tokenize();
8810 return new TokenizeResult(mergeTextTokens(tokenizer.tokens), tokenizer.errors, tokenizer.nonNormalizedIcuExpressions);
8811 }
8812 const _CR_OR_CRLF_REGEXP = /\r\n?/g;
8813 function _unexpectedCharacterErrorMsg(charCode) {
8814 const char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode);
8815 return `Unexpected character "${char}"`;
8816 }
8817 function _unknownEntityErrorMsg(entitySrc) {
8818 return `Unknown entity "${entitySrc}" - use the "&#<decimal>;" or "&#x<hex>;" syntax`;
8819 }
8820 function _unparsableEntityErrorMsg(type, entityStr) {
8821 return `Unable to parse entity "${entityStr}" - ${type} character reference entities must end with ";"`;
8822 }
8823 var CharacterReferenceType;
8824 (function (CharacterReferenceType) {
8825 CharacterReferenceType["HEX"] = "hexadecimal";
8826 CharacterReferenceType["DEC"] = "decimal";
8827 })(CharacterReferenceType || (CharacterReferenceType = {}));
8828 class _ControlFlowError {
8829 constructor(error) {
8830 this.error = error;
8831 }
8832 }
8833 // See https://www.w3.org/TR/html51/syntax.html#writing-html-documents
8834 class _Tokenizer {
8835 /**
8836 * @param _file The html source file being tokenized.
8837 * @param _getTagDefinition A function that will retrieve a tag definition for a given tag name.
8838 * @param options Configuration of the tokenization.
8839 */
8840 constructor(_file, _getTagDefinition, options) {
8841 this._getTagDefinition = _getTagDefinition;
8842 this._currentTokenStart = null;
8843 this._currentTokenType = null;
8844 this._expansionCaseStack = [];
8845 this._inInterpolation = false;
8846 this.tokens = [];
8847 this.errors = [];
8848 this.nonNormalizedIcuExpressions = [];
8849 this._tokenizeIcu = options.tokenizeExpansionForms || false;
8850 this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
8851 this._leadingTriviaCodePoints =
8852 options.leadingTriviaChars && options.leadingTriviaChars.map(c => c.codePointAt(0) || 0);
8853 const range = options.range || { endPos: _file.content.length, startPos: 0, startLine: 0, startCol: 0 };
8854 this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) :
8855 new PlainCharacterCursor(_file, range);
8856 this._preserveLineEndings = options.preserveLineEndings || false;
8857 this._escapedString = options.escapedString || false;
8858 this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
8859 try {
8860 this._cursor.init();
8861 }
8862 catch (e) {
8863 this.handleError(e);
8864 }
8865 }
8866 _processCarriageReturns(content) {
8867 if (this._preserveLineEndings) {
8868 return content;
8869 }
8870 // https://www.w3.org/TR/html51/syntax.html#preprocessing-the-input-stream
8871 // In order to keep the original position in the source, we can not
8872 // pre-process it.
8873 // Instead CRs are processed right before instantiating the tokens.
8874 return content.replace(_CR_OR_CRLF_REGEXP, '\n');
8875 }
8876 tokenize() {
8877 while (this._cursor.peek() !== $EOF) {
8878 const start = this._cursor.clone();
8879 try {
8880 if (this._attemptCharCode($LT)) {
8881 if (this._attemptCharCode($BANG)) {
8882 if (this._attemptCharCode($LBRACKET)) {
8883 this._consumeCdata(start);
8884 }
8885 else if (this._attemptCharCode($MINUS)) {
8886 this._consumeComment(start);
8887 }
8888 else {
8889 this._consumeDocType(start);
8890 }
8891 }
8892 else if (this._attemptCharCode($SLASH)) {
8893 this._consumeTagClose(start);
8894 }
8895 else {
8896 this._consumeTagOpen(start);
8897 }
8898 }
8899 else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
8900 this._consumeText();
8901 }
8902 }
8903 catch (e) {
8904 this.handleError(e);
8905 }
8906 }
8907 this._beginToken(TokenType.EOF);
8908 this._endToken([]);
8909 }
8910 /**
8911 * @returns whether an ICU token has been created
8912 * @internal
8913 */
8914 _tokenizeExpansionForm() {
8915 if (this.isExpansionFormStart()) {
8916 this._consumeExpansionFormStart();
8917 return true;
8918 }
8919 if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) {
8920 this._consumeExpansionCaseStart();
8921 return true;
8922 }
8923 if (this._cursor.peek() === $RBRACE) {
8924 if (this._isInExpansionCase()) {
8925 this._consumeExpansionCaseEnd();
8926 return true;
8927 }
8928 if (this._isInExpansionForm()) {
8929 this._consumeExpansionFormEnd();
8930 return true;
8931 }
8932 }
8933 return false;
8934 }
8935 _beginToken(type, start = this._cursor.clone()) {
8936 this._currentTokenStart = start;
8937 this._currentTokenType = type;
8938 }
8939 _endToken(parts, end) {
8940 if (this._currentTokenStart === null) {
8941 throw new TokenError('Programming error - attempted to end a token when there was no start to the token', this._currentTokenType, this._cursor.getSpan(end));
8942 }
8943 if (this._currentTokenType === null) {
8944 throw new TokenError('Programming error - attempted to end a token which has no token type', null, this._cursor.getSpan(this._currentTokenStart));
8945 }
8946 const token = new Token(this._currentTokenType, parts, this._cursor.getSpan(this._currentTokenStart, this._leadingTriviaCodePoints));
8947 this.tokens.push(token);
8948 this._currentTokenStart = null;
8949 this._currentTokenType = null;
8950 return token;
8951 }
8952 _createError(msg, span) {
8953 if (this._isInExpansionForm()) {
8954 msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`;
8955 }
8956 const error = new TokenError(msg, this._currentTokenType, span);
8957 this._currentTokenStart = null;
8958 this._currentTokenType = null;
8959 return new _ControlFlowError(error);
8960 }
8961 handleError(e) {
8962 if (e instanceof CursorError) {
8963 e = this._createError(e.msg, this._cursor.getSpan(e.cursor));
8964 }
8965 if (e instanceof _ControlFlowError) {
8966 this.errors.push(e.error);
8967 }
8968 else {
8969 throw e;
8970 }
8971 }
8972 _attemptCharCode(charCode) {
8973 if (this._cursor.peek() === charCode) {
8974 this._cursor.advance();
8975 return true;
8976 }
8977 return false;
8978 }
8979 _attemptCharCodeCaseInsensitive(charCode) {
8980 if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCode)) {
8981 this._cursor.advance();
8982 return true;
8983 }
8984 return false;
8985 }
8986 _requireCharCode(charCode) {
8987 const location = this._cursor.clone();
8988 if (!this._attemptCharCode(charCode)) {
8989 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
8990 }
8991 }
8992 _attemptStr(chars) {
8993 const len = chars.length;
8994 if (this._cursor.charsLeft() < len) {
8995 return false;
8996 }
8997 const initialPosition = this._cursor.clone();
8998 for (let i = 0; i < len; i++) {
8999 if (!this._attemptCharCode(chars.charCodeAt(i))) {
9000 // If attempting to parse the string fails, we want to reset the parser
9001 // to where it was before the attempt
9002 this._cursor = initialPosition;
9003 return false;
9004 }
9005 }
9006 return true;
9007 }
9008 _attemptStrCaseInsensitive(chars) {
9009 for (let i = 0; i < chars.length; i++) {
9010 if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) {
9011 return false;
9012 }
9013 }
9014 return true;
9015 }
9016 _requireStr(chars) {
9017 const location = this._cursor.clone();
9018 if (!this._attemptStr(chars)) {
9019 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
9020 }
9021 }
9022 _attemptCharCodeUntilFn(predicate) {
9023 while (!predicate(this._cursor.peek())) {
9024 this._cursor.advance();
9025 }
9026 }
9027 _requireCharCodeUntilFn(predicate, len) {
9028 const start = this._cursor.clone();
9029 this._attemptCharCodeUntilFn(predicate);
9030 if (this._cursor.diff(start) < len) {
9031 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
9032 }
9033 }
9034 _attemptUntilChar(char) {
9035 while (this._cursor.peek() !== char) {
9036 this._cursor.advance();
9037 }
9038 }
9039 _readChar(decodeEntities) {
9040 if (decodeEntities && this._cursor.peek() === $AMPERSAND) {
9041 return this._decodeEntity();
9042 }
9043 else {
9044 // Don't rely upon reading directly from `_input` as the actual char value
9045 // may have been generated from an escape sequence.
9046 const char = String.fromCodePoint(this._cursor.peek());
9047 this._cursor.advance();
9048 return char;
9049 }
9050 }
9051 _decodeEntity() {
9052 const start = this._cursor.clone();
9053 this._cursor.advance();
9054 if (this._attemptCharCode($HASH)) {
9055 const isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
9056 const codeStart = this._cursor.clone();
9057 this._attemptCharCodeUntilFn(isDigitEntityEnd);
9058 if (this._cursor.peek() != $SEMICOLON) {
9059 // Advance cursor to include the peeked character in the string provided to the error
9060 // message.
9061 this._cursor.advance();
9062 const entityType = isHex ? CharacterReferenceType.HEX : CharacterReferenceType.DEC;
9063 throw this._createError(_unparsableEntityErrorMsg(entityType, this._cursor.getChars(start)), this._cursor.getSpan());
9064 }
9065 const strNum = this._cursor.getChars(codeStart);
9066 this._cursor.advance();
9067 try {
9068 const charCode = parseInt(strNum, isHex ? 16 : 10);
9069 return String.fromCharCode(charCode);
9070 }
9071 catch (_a) {
9072 throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan());
9073 }
9074 }
9075 else {
9076 const nameStart = this._cursor.clone();
9077 this._attemptCharCodeUntilFn(isNamedEntityEnd);
9078 if (this._cursor.peek() != $SEMICOLON) {
9079 this._cursor = nameStart;
9080 return '&';
9081 }
9082 const name = this._cursor.getChars(nameStart);
9083 this._cursor.advance();
9084 const char = NAMED_ENTITIES[name];
9085 if (!char) {
9086 throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
9087 }
9088 return char;
9089 }
9090 }
9091 _consumeRawText(decodeEntities, endMarkerPredicate) {
9092 this._beginToken(decodeEntities ? TokenType.ESCAPABLE_RAW_TEXT : TokenType.RAW_TEXT);
9093 const parts = [];
9094 while (true) {
9095 const tagCloseStart = this._cursor.clone();
9096 const foundEndMarker = endMarkerPredicate();
9097 this._cursor = tagCloseStart;
9098 if (foundEndMarker) {
9099 break;
9100 }
9101 parts.push(this._readChar(decodeEntities));
9102 }
9103 return this._endToken([this._processCarriageReturns(parts.join(''))]);
9104 }
9105 _consumeComment(start) {
9106 this._beginToken(TokenType.COMMENT_START, start);
9107 this._requireCharCode($MINUS);
9108 this._endToken([]);
9109 this._consumeRawText(false, () => this._attemptStr('-->'));
9110 this._beginToken(TokenType.COMMENT_END);
9111 this._requireStr('-->');
9112 this._endToken([]);
9113 }
9114 _consumeCdata(start) {
9115 this._beginToken(TokenType.CDATA_START, start);
9116 this._requireStr('CDATA[');
9117 this._endToken([]);
9118 this._consumeRawText(false, () => this._attemptStr(']]>'));
9119 this._beginToken(TokenType.CDATA_END);
9120 this._requireStr(']]>');
9121 this._endToken([]);
9122 }
9123 _consumeDocType(start) {
9124 this._beginToken(TokenType.DOC_TYPE, start);
9125 const contentStart = this._cursor.clone();
9126 this._attemptUntilChar($GT);
9127 const content = this._cursor.getChars(contentStart);
9128 this._cursor.advance();
9129 this._endToken([content]);
9130 }
9131 _consumePrefixAndName() {
9132 const nameOrPrefixStart = this._cursor.clone();
9133 let prefix = '';
9134 while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) {
9135 this._cursor.advance();
9136 }
9137 let nameStart;
9138 if (this._cursor.peek() === $COLON) {
9139 prefix = this._cursor.getChars(nameOrPrefixStart);
9140 this._cursor.advance();
9141 nameStart = this._cursor.clone();
9142 }
9143 else {
9144 nameStart = nameOrPrefixStart;
9145 }
9146 this._requireCharCodeUntilFn(isNameEnd, prefix === '' ? 0 : 1);
9147 const name = this._cursor.getChars(nameStart);
9148 return [prefix, name];
9149 }
9150 _consumeTagOpen(start) {
9151 let tagName;
9152 let prefix;
9153 let openTagToken;
9154 try {
9155 if (!isAsciiLetter(this._cursor.peek())) {
9156 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
9157 }
9158 openTagToken = this._consumeTagOpenStart(start);
9159 prefix = openTagToken.parts[0];
9160 tagName = openTagToken.parts[1];
9161 this._attemptCharCodeUntilFn(isNotWhitespace);
9162 while (this._cursor.peek() !== $SLASH && this._cursor.peek() !== $GT &&
9163 this._cursor.peek() !== $LT) {
9164 this._consumeAttributeName();
9165 this._attemptCharCodeUntilFn(isNotWhitespace);
9166 if (this._attemptCharCode($EQ)) {
9167 this._attemptCharCodeUntilFn(isNotWhitespace);
9168 this._consumeAttributeValue();
9169 }
9170 this._attemptCharCodeUntilFn(isNotWhitespace);
9171 }
9172 this._consumeTagOpenEnd();
9173 }
9174 catch (e) {
9175 if (e instanceof _ControlFlowError) {
9176 if (openTagToken) {
9177 // We errored before we could close the opening tag, so it is incomplete.
9178 openTagToken.type = TokenType.INCOMPLETE_TAG_OPEN;
9179 }
9180 else {
9181 // When the start tag is invalid, assume we want a "<" as text.
9182 // Back to back text tokens are merged at the end.
9183 this._beginToken(TokenType.TEXT, start);
9184 this._endToken(['<']);
9185 }
9186 return;
9187 }
9188 throw e;
9189 }
9190 const contentTokenType = this._getTagDefinition(tagName).getContentType(prefix);
9191 if (contentTokenType === TagContentType.RAW_TEXT) {
9192 this._consumeRawTextWithTagClose(prefix, tagName, false);
9193 }
9194 else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) {
9195 this._consumeRawTextWithTagClose(prefix, tagName, true);
9196 }
9197 }
9198 _consumeRawTextWithTagClose(prefix, tagName, decodeEntities) {
9199 this._consumeRawText(decodeEntities, () => {
9200 if (!this._attemptCharCode($LT))
9201 return false;
9202 if (!this._attemptCharCode($SLASH))
9203 return false;
9204 this._attemptCharCodeUntilFn(isNotWhitespace);
9205 if (!this._attemptStrCaseInsensitive(tagName))
9206 return false;
9207 this._attemptCharCodeUntilFn(isNotWhitespace);
9208 return this._attemptCharCode($GT);
9209 });
9210 this._beginToken(TokenType.TAG_CLOSE);
9211 this._requireCharCodeUntilFn(code => code === $GT, 3);
9212 this._cursor.advance(); // Consume the `>`
9213 this._endToken([prefix, tagName]);
9214 }
9215 _consumeTagOpenStart(start) {
9216 this._beginToken(TokenType.TAG_OPEN_START, start);
9217 const parts = this._consumePrefixAndName();
9218 return this._endToken(parts);
9219 }
9220 _consumeAttributeName() {
9221 const attrNameStart = this._cursor.peek();
9222 if (attrNameStart === $SQ || attrNameStart === $DQ) {
9223 throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
9224 }
9225 this._beginToken(TokenType.ATTR_NAME);
9226 const prefixAndName = this._consumePrefixAndName();
9227 this._endToken(prefixAndName);
9228 }
9229 _consumeAttributeValue() {
9230 let value;
9231 if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
9232 this._beginToken(TokenType.ATTR_QUOTE);
9233 const quoteChar = this._cursor.peek();
9234 this._cursor.advance();
9235 this._endToken([String.fromCodePoint(quoteChar)]);
9236 this._beginToken(TokenType.ATTR_VALUE);
9237 const parts = [];
9238 while (this._cursor.peek() !== quoteChar) {
9239 parts.push(this._readChar(true));
9240 }
9241 value = parts.join('');
9242 this._endToken([this._processCarriageReturns(value)]);
9243 this._beginToken(TokenType.ATTR_QUOTE);
9244 this._cursor.advance();
9245 this._endToken([String.fromCodePoint(quoteChar)]);
9246 }
9247 else {
9248 this._beginToken(TokenType.ATTR_VALUE);
9249 const valueStart = this._cursor.clone();
9250 this._requireCharCodeUntilFn(isNameEnd, 1);
9251 value = this._cursor.getChars(valueStart);
9252 this._endToken([this._processCarriageReturns(value)]);
9253 }
9254 }
9255 _consumeTagOpenEnd() {
9256 const tokenType = this._attemptCharCode($SLASH) ? TokenType.TAG_OPEN_END_VOID : TokenType.TAG_OPEN_END;
9257 this._beginToken(tokenType);
9258 this._requireCharCode($GT);
9259 this._endToken([]);
9260 }
9261 _consumeTagClose(start) {
9262 this._beginToken(TokenType.TAG_CLOSE, start);
9263 this._attemptCharCodeUntilFn(isNotWhitespace);
9264 const prefixAndName = this._consumePrefixAndName();
9265 this._attemptCharCodeUntilFn(isNotWhitespace);
9266 this._requireCharCode($GT);
9267 this._endToken(prefixAndName);
9268 }
9269 _consumeExpansionFormStart() {
9270 this._beginToken(TokenType.EXPANSION_FORM_START);
9271 this._requireCharCode($LBRACE);
9272 this._endToken([]);
9273 this._expansionCaseStack.push(TokenType.EXPANSION_FORM_START);
9274 this._beginToken(TokenType.RAW_TEXT);
9275 const condition = this._readUntil($COMMA);
9276 const normalizedCondition = this._processCarriageReturns(condition);
9277 if (this._i18nNormalizeLineEndingsInICUs) {
9278 // We explicitly want to normalize line endings for this text.
9279 this._endToken([normalizedCondition]);
9280 }
9281 else {
9282 // We are not normalizing line endings.
9283 const conditionToken = this._endToken([condition]);
9284 if (normalizedCondition !== condition) {
9285 this.nonNormalizedIcuExpressions.push(conditionToken);
9286 }
9287 }
9288 this._requireCharCode($COMMA);
9289 this._attemptCharCodeUntilFn(isNotWhitespace);
9290 this._beginToken(TokenType.RAW_TEXT);
9291 const type = this._readUntil($COMMA);
9292 this._endToken([type]);
9293 this._requireCharCode($COMMA);
9294 this._attemptCharCodeUntilFn(isNotWhitespace);
9295 }
9296 _consumeExpansionCaseStart() {
9297 this._beginToken(TokenType.EXPANSION_CASE_VALUE);
9298 const value = this._readUntil($LBRACE).trim();
9299 this._endToken([value]);
9300 this._attemptCharCodeUntilFn(isNotWhitespace);
9301 this._beginToken(TokenType.EXPANSION_CASE_EXP_START);
9302 this._requireCharCode($LBRACE);
9303 this._endToken([]);
9304 this._attemptCharCodeUntilFn(isNotWhitespace);
9305 this._expansionCaseStack.push(TokenType.EXPANSION_CASE_EXP_START);
9306 }
9307 _consumeExpansionCaseEnd() {
9308 this._beginToken(TokenType.EXPANSION_CASE_EXP_END);
9309 this._requireCharCode($RBRACE);
9310 this._endToken([]);
9311 this._attemptCharCodeUntilFn(isNotWhitespace);
9312 this._expansionCaseStack.pop();
9313 }
9314 _consumeExpansionFormEnd() {
9315 this._beginToken(TokenType.EXPANSION_FORM_END);
9316 this._requireCharCode($RBRACE);
9317 this._endToken([]);
9318 this._expansionCaseStack.pop();
9319 }
9320 _consumeText() {
9321 const start = this._cursor.clone();
9322 this._beginToken(TokenType.TEXT, start);
9323 const parts = [];
9324 do {
9325 if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) {
9326 parts.push(this._interpolationConfig.start);
9327 this._inInterpolation = true;
9328 }
9329 else if (this._interpolationConfig && this._inInterpolation &&
9330 this._attemptStr(this._interpolationConfig.end)) {
9331 parts.push(this._interpolationConfig.end);
9332 this._inInterpolation = false;
9333 }
9334 else {
9335 parts.push(this._readChar(true));
9336 }
9337 } while (!this._isTextEnd());
9338 this._endToken([this._processCarriageReturns(parts.join(''))]);
9339 }
9340 _isTextEnd() {
9341 if (this._cursor.peek() === $LT || this._cursor.peek() === $EOF) {
9342 return true;
9343 }
9344 if (this._tokenizeIcu && !this._inInterpolation) {
9345 if (this.isExpansionFormStart()) {
9346 // start of an expansion form
9347 return true;
9348 }
9349 if (this._cursor.peek() === $RBRACE && this._isInExpansionCase()) {
9350 // end of and expansion case
9351 return true;
9352 }
9353 }
9354 return false;
9355 }
9356 _readUntil(char) {
9357 const start = this._cursor.clone();
9358 this._attemptUntilChar(char);
9359 return this._cursor.getChars(start);
9360 }
9361 _isInExpansionCase() {
9362 return this._expansionCaseStack.length > 0 &&
9363 this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
9364 TokenType.EXPANSION_CASE_EXP_START;
9365 }
9366 _isInExpansionForm() {
9367 return this._expansionCaseStack.length > 0 &&
9368 this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
9369 TokenType.EXPANSION_FORM_START;
9370 }
9371 isExpansionFormStart() {
9372 if (this._cursor.peek() !== $LBRACE) {
9373 return false;
9374 }
9375 if (this._interpolationConfig) {
9376 const start = this._cursor.clone();
9377 const isInterpolation = this._attemptStr(this._interpolationConfig.start);
9378 this._cursor = start;
9379 return !isInterpolation;
9380 }
9381 return true;
9382 }
9383 }
9384 function isNotWhitespace(code) {
9385 return !isWhitespace(code) || code === $EOF;
9386 }
9387 function isNameEnd(code) {
9388 return isWhitespace(code) || code === $GT || code === $LT ||
9389 code === $SLASH || code === $SQ || code === $DQ || code === $EQ;
9390 }
9391 function isPrefixEnd(code) {
9392 return (code < $a || $z < code) && (code < $A || $Z < code) &&
9393 (code < $0 || code > $9);
9394 }
9395 function isDigitEntityEnd(code) {
9396 return code == $SEMICOLON || code == $EOF || !isAsciiHexDigit(code);
9397 }
9398 function isNamedEntityEnd(code) {
9399 return code == $SEMICOLON || code == $EOF || !isAsciiLetter(code);
9400 }
9401 function isExpansionCaseStart(peek) {
9402 return peek !== $RBRACE;
9403 }
9404 function compareCharCodeCaseInsensitive(code1, code2) {
9405 return toUpperCaseCharCode(code1) == toUpperCaseCharCode(code2);
9406 }
9407 function toUpperCaseCharCode(code) {
9408 return code >= $a && code <= $z ? code - $a + $A : code;
9409 }
9410 function mergeTextTokens(srcTokens) {
9411 const dstTokens = [];
9412 let lastDstToken = undefined;
9413 for (let i = 0; i < srcTokens.length; i++) {
9414 const token = srcTokens[i];
9415 if (lastDstToken && lastDstToken.type == TokenType.TEXT && token.type == TokenType.TEXT) {
9416 lastDstToken.parts[0] += token.parts[0];
9417 lastDstToken.sourceSpan.end = token.sourceSpan.end;
9418 }
9419 else {
9420 lastDstToken = token;
9421 dstTokens.push(lastDstToken);
9422 }
9423 }
9424 return dstTokens;
9425 }
9426 class PlainCharacterCursor {
9427 constructor(fileOrCursor, range) {
9428 if (fileOrCursor instanceof PlainCharacterCursor) {
9429 this.file = fileOrCursor.file;
9430 this.input = fileOrCursor.input;
9431 this.end = fileOrCursor.end;
9432 const state = fileOrCursor.state;
9433 // Note: avoid using `{...fileOrCursor.state}` here as that has a severe performance penalty.
9434 // In ES5 bundles the object spread operator is translated into the `__assign` helper, which
9435 // is not optimized by VMs as efficiently as a raw object literal. Since this constructor is
9436 // called in tight loops, this difference matters.
9437 this.state = {
9438 peek: state.peek,
9439 offset: state.offset,
9440 line: state.line,
9441 column: state.column,
9442 };
9443 }
9444 else {
9445 if (!range) {
9446 throw new Error('Programming error: the range argument must be provided with a file argument.');
9447 }
9448 this.file = fileOrCursor;
9449 this.input = fileOrCursor.content;
9450 this.end = range.endPos;
9451 this.state = {
9452 peek: -1,
9453 offset: range.startPos,
9454 line: range.startLine,
9455 column: range.startCol,
9456 };
9457 }
9458 }
9459 clone() {
9460 return new PlainCharacterCursor(this);
9461 }
9462 peek() {
9463 return this.state.peek;
9464 }
9465 charsLeft() {
9466 return this.end - this.state.offset;
9467 }
9468 diff(other) {
9469 return this.state.offset - other.state.offset;
9470 }
9471 advance() {
9472 this.advanceState(this.state);
9473 }
9474 init() {
9475 this.updatePeek(this.state);
9476 }
9477 getSpan(start, leadingTriviaCodePoints) {
9478 start = start || this;
9479 let fullStart = start;
9480 if (leadingTriviaCodePoints) {
9481 while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) {
9482 if (fullStart === start) {
9483 start = start.clone();
9484 }
9485 start.advance();
9486 }
9487 }
9488 const startLocation = this.locationFromCursor(start);
9489 const endLocation = this.locationFromCursor(this);
9490 const fullStartLocation = fullStart !== start ? this.locationFromCursor(fullStart) : startLocation;
9491 return new ParseSourceSpan(startLocation, endLocation, fullStartLocation);
9492 }
9493 getChars(start) {
9494 return this.input.substring(start.state.offset, this.state.offset);
9495 }
9496 charAt(pos) {
9497 return this.input.charCodeAt(pos);
9498 }
9499 advanceState(state) {
9500 if (state.offset >= this.end) {
9501 this.state = state;
9502 throw new CursorError('Unexpected character "EOF"', this);
9503 }
9504 const currentChar = this.charAt(state.offset);
9505 if (currentChar === $LF) {
9506 state.line++;
9507 state.column = 0;
9508 }
9509 else if (!isNewLine(currentChar)) {
9510 state.column++;
9511 }
9512 state.offset++;
9513 this.updatePeek(state);
9514 }
9515 updatePeek(state) {
9516 state.peek = state.offset >= this.end ? $EOF : this.charAt(state.offset);
9517 }
9518 locationFromCursor(cursor) {
9519 return new ParseLocation(cursor.file, cursor.state.offset, cursor.state.line, cursor.state.column);
9520 }
9521 }
9522 class EscapedCharacterCursor extends PlainCharacterCursor {
9523 constructor(fileOrCursor, range) {
9524 if (fileOrCursor instanceof EscapedCharacterCursor) {
9525 super(fileOrCursor);
9526 this.internalState = Object.assign({}, fileOrCursor.internalState);
9527 }
9528 else {
9529 super(fileOrCursor, range);
9530 this.internalState = this.state;
9531 }
9532 }
9533 advance() {
9534 this.state = this.internalState;
9535 super.advance();
9536 this.processEscapeSequence();
9537 }
9538 init() {
9539 super.init();
9540 this.processEscapeSequence();
9541 }
9542 clone() {
9543 return new EscapedCharacterCursor(this);
9544 }
9545 getChars(start) {
9546 const cursor = start.clone();
9547 let chars = '';
9548 while (cursor.internalState.offset < this.internalState.offset) {
9549 chars += String.fromCodePoint(cursor.peek());
9550 cursor.advance();
9551 }
9552 return chars;
9553 }
9554 /**
9555 * Process the escape sequence that starts at the current position in the text.
9556 *
9557 * This method is called to ensure that `peek` has the unescaped value of escape sequences.
9558 */
9559 processEscapeSequence() {
9560 const peek = () => this.internalState.peek;
9561 if (peek() === $BACKSLASH) {
9562 // We have hit an escape sequence so we need the internal state to become independent
9563 // of the external state.
9564 this.internalState = Object.assign({}, this.state);
9565 // Move past the backslash
9566 this.advanceState(this.internalState);
9567 // First check for standard control char sequences
9568 if (peek() === $n) {
9569 this.state.peek = $LF;
9570 }
9571 else if (peek() === $r) {
9572 this.state.peek = $CR;
9573 }
9574 else if (peek() === $v) {
9575 this.state.peek = $VTAB;
9576 }
9577 else if (peek() === $t) {
9578 this.state.peek = $TAB;
9579 }
9580 else if (peek() === $b) {
9581 this.state.peek = $BSPACE;
9582 }
9583 else if (peek() === $f) {
9584 this.state.peek = $FF;
9585 }
9586 // Now consider more complex sequences
9587 else if (peek() === $u) {
9588 // Unicode code-point sequence
9589 this.advanceState(this.internalState); // advance past the `u` char
9590 if (peek() === $LBRACE) {
9591 // Variable length Unicode, e.g. `\x{123}`
9592 this.advanceState(this.internalState); // advance past the `{` char
9593 // Advance past the variable number of hex digits until we hit a `}` char
9594 const digitStart = this.clone();
9595 let length = 0;
9596 while (peek() !== $RBRACE) {
9597 this.advanceState(this.internalState);
9598 length++;
9599 }
9600 this.state.peek = this.decodeHexDigits(digitStart, length);
9601 }
9602 else {
9603 // Fixed length Unicode, e.g. `\u1234`
9604 const digitStart = this.clone();
9605 this.advanceState(this.internalState);
9606 this.advanceState(this.internalState);
9607 this.advanceState(this.internalState);
9608 this.state.peek = this.decodeHexDigits(digitStart, 4);
9609 }
9610 }
9611 else if (peek() === $x) {
9612 // Hex char code, e.g. `\x2F`
9613 this.advanceState(this.internalState); // advance past the `x` char
9614 const digitStart = this.clone();
9615 this.advanceState(this.internalState);
9616 this.state.peek = this.decodeHexDigits(digitStart, 2);
9617 }
9618 else if (isOctalDigit(peek())) {
9619 // Octal char code, e.g. `\012`,
9620 let octal = '';
9621 let length = 0;
9622 let previous = this.clone();
9623 while (isOctalDigit(peek()) && length < 3) {
9624 previous = this.clone();
9625 octal += String.fromCodePoint(peek());
9626 this.advanceState(this.internalState);
9627 length++;
9628 }
9629 this.state.peek = parseInt(octal, 8);
9630 // Backup one char
9631 this.internalState = previous.internalState;
9632 }
9633 else if (isNewLine(this.internalState.peek)) {
9634 // Line continuation `\` followed by a new line
9635 this.advanceState(this.internalState); // advance over the newline
9636 this.state = this.internalState;
9637 }
9638 else {
9639 // If none of the `if` blocks were executed then we just have an escaped normal character.
9640 // In that case we just, effectively, skip the backslash from the character.
9641 this.state.peek = this.internalState.peek;
9642 }
9643 }
9644 }
9645 decodeHexDigits(start, length) {
9646 const hex = this.input.substr(start.internalState.offset, length);
9647 const charCode = parseInt(hex, 16);
9648 if (!isNaN(charCode)) {
9649 return charCode;
9650 }
9651 else {
9652 start.state = start.internalState;
9653 throw new CursorError('Invalid hexadecimal escape sequence', start);
9654 }
9655 }
9656 }
9657 class CursorError {
9658 constructor(msg, cursor) {
9659 this.msg = msg;
9660 this.cursor = cursor;
9661 }
9662 }
9663
9664 /**
9665 * @license
9666 * Copyright Google LLC All Rights Reserved.
9667 *
9668 * Use of this source code is governed by an MIT-style license that can be
9669 * found in the LICENSE file at https://angular.io/license
9670 */
9671 class TreeError extends ParseError {
9672 constructor(elementName, span, msg) {
9673 super(span, msg);
9674 this.elementName = elementName;
9675 }
9676 static create(elementName, span, msg) {
9677 return new TreeError(elementName, span, msg);
9678 }
9679 }
9680 class ParseTreeResult {
9681 constructor(rootNodes, errors) {
9682 this.rootNodes = rootNodes;
9683 this.errors = errors;
9684 }
9685 }
9686 class Parser {
9687 constructor(getTagDefinition) {
9688 this.getTagDefinition = getTagDefinition;
9689 }
9690 parse(source, url, options) {
9691 const tokenizeResult = tokenize(source, url, this.getTagDefinition, options);
9692 const parser = new _TreeBuilder(tokenizeResult.tokens, this.getTagDefinition);
9693 parser.build();
9694 return new ParseTreeResult(parser.rootNodes, tokenizeResult.errors.concat(parser.errors));
9695 }
9696 }
9697 class _TreeBuilder {
9698 constructor(tokens, getTagDefinition) {
9699 this.tokens = tokens;
9700 this.getTagDefinition = getTagDefinition;
9701 this._index = -1;
9702 this._elementStack = [];
9703 this.rootNodes = [];
9704 this.errors = [];
9705 this._advance();
9706 }
9707 build() {
9708 while (this._peek.type !== TokenType.EOF) {
9709 if (this._peek.type === TokenType.TAG_OPEN_START ||
9710 this._peek.type === TokenType.INCOMPLETE_TAG_OPEN) {
9711 this._consumeStartTag(this._advance());
9712 }
9713 else if (this._peek.type === TokenType.TAG_CLOSE) {
9714 this._consumeEndTag(this._advance());
9715 }
9716 else if (this._peek.type === TokenType.CDATA_START) {
9717 this._closeVoidElement();
9718 this._consumeCdata(this._advance());
9719 }
9720 else if (this._peek.type === TokenType.COMMENT_START) {
9721 this._closeVoidElement();
9722 this._consumeComment(this._advance());
9723 }
9724 else if (this._peek.type === TokenType.TEXT || this._peek.type === TokenType.RAW_TEXT ||
9725 this._peek.type === TokenType.ESCAPABLE_RAW_TEXT) {
9726 this._closeVoidElement();
9727 this._consumeText(this._advance());
9728 }
9729 else if (this._peek.type === TokenType.EXPANSION_FORM_START) {
9730 this._consumeExpansion(this._advance());
9731 }
9732 else {
9733 // Skip all other tokens...
9734 this._advance();
9735 }
9736 }
9737 }
9738 _advance() {
9739 const prev = this._peek;
9740 if (this._index < this.tokens.length - 1) {
9741 // Note: there is always an EOF token at the end
9742 this._index++;
9743 }
9744 this._peek = this.tokens[this._index];
9745 return prev;
9746 }
9747 _advanceIf(type) {
9748 if (this._peek.type === type) {
9749 return this._advance();
9750 }
9751 return null;
9752 }
9753 _consumeCdata(_startToken) {
9754 this._consumeText(this._advance());
9755 this._advanceIf(TokenType.CDATA_END);
9756 }
9757 _consumeComment(token) {
9758 const text = this._advanceIf(TokenType.RAW_TEXT);
9759 this._advanceIf(TokenType.COMMENT_END);
9760 const value = text != null ? text.parts[0].trim() : null;
9761 this._addToParent(new Comment(value, token.sourceSpan));
9762 }
9763 _consumeExpansion(token) {
9764 const switchValue = this._advance();
9765 const type = this._advance();
9766 const cases = [];
9767 // read =
9768 while (this._peek.type === TokenType.EXPANSION_CASE_VALUE) {
9769 const expCase = this._parseExpansionCase();
9770 if (!expCase)
9771 return; // error
9772 cases.push(expCase);
9773 }
9774 // read the final }
9775 if (this._peek.type !== TokenType.EXPANSION_FORM_END) {
9776 this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`));
9777 return;
9778 }
9779 const sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end, token.sourceSpan.fullStart);
9780 this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan));
9781 this._advance();
9782 }
9783 _parseExpansionCase() {
9784 const value = this._advance();
9785 // read {
9786 if (this._peek.type !== TokenType.EXPANSION_CASE_EXP_START) {
9787 this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`));
9788 return null;
9789 }
9790 // read until }
9791 const start = this._advance();
9792 const exp = this._collectExpansionExpTokens(start);
9793 if (!exp)
9794 return null;
9795 const end = this._advance();
9796 exp.push(new Token(TokenType.EOF, [], end.sourceSpan));
9797 // parse everything in between { and }
9798 const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
9799 expansionCaseParser.build();
9800 if (expansionCaseParser.errors.length > 0) {
9801 this.errors = this.errors.concat(expansionCaseParser.errors);
9802 return null;
9803 }
9804 const sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end, value.sourceSpan.fullStart);
9805 const expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end, start.sourceSpan.fullStart);
9806 return new ExpansionCase(value.parts[0], expansionCaseParser.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan);
9807 }
9808 _collectExpansionExpTokens(start) {
9809 const exp = [];
9810 const expansionFormStack = [TokenType.EXPANSION_CASE_EXP_START];
9811 while (true) {
9812 if (this._peek.type === TokenType.EXPANSION_FORM_START ||
9813 this._peek.type === TokenType.EXPANSION_CASE_EXP_START) {
9814 expansionFormStack.push(this._peek.type);
9815 }
9816 if (this._peek.type === TokenType.EXPANSION_CASE_EXP_END) {
9817 if (lastOnStack(expansionFormStack, TokenType.EXPANSION_CASE_EXP_START)) {
9818 expansionFormStack.pop();
9819 if (expansionFormStack.length == 0)
9820 return exp;
9821 }
9822 else {
9823 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9824 return null;
9825 }
9826 }
9827 if (this._peek.type === TokenType.EXPANSION_FORM_END) {
9828 if (lastOnStack(expansionFormStack, TokenType.EXPANSION_FORM_START)) {
9829 expansionFormStack.pop();
9830 }
9831 else {
9832 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9833 return null;
9834 }
9835 }
9836 if (this._peek.type === TokenType.EOF) {
9837 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9838 return null;
9839 }
9840 exp.push(this._advance());
9841 }
9842 }
9843 _consumeText(token) {
9844 let text = token.parts[0];
9845 if (text.length > 0 && text[0] == '\n') {
9846 const parent = this._getParentElement();
9847 if (parent != null && parent.children.length == 0 &&
9848 this.getTagDefinition(parent.name).ignoreFirstLf) {
9849 text = text.substring(1);
9850 }
9851 }
9852 if (text.length > 0) {
9853 this._addToParent(new Text$2(text, token.sourceSpan));
9854 }
9855 }
9856 _closeVoidElement() {
9857 const el = this._getParentElement();
9858 if (el && this.getTagDefinition(el.name).isVoid) {
9859 this._elementStack.pop();
9860 }
9861 }
9862 _consumeStartTag(startTagToken) {
9863 const [prefix, name] = startTagToken.parts;
9864 const attrs = [];
9865 while (this._peek.type === TokenType.ATTR_NAME) {
9866 attrs.push(this._consumeAttr(this._advance()));
9867 }
9868 const fullName = this._getElementFullName(prefix, name, this._getParentElement());
9869 let selfClosing = false;
9870 // Note: There could have been a tokenizer error
9871 // so that we don't get a token for the end tag...
9872 if (this._peek.type === TokenType.TAG_OPEN_END_VOID) {
9873 this._advance();
9874 selfClosing = true;
9875 const tagDef = this.getTagDefinition(fullName);
9876 if (!(tagDef.canSelfClose || getNsPrefix(fullName) !== null || tagDef.isVoid)) {
9877 this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void and foreign elements can be self closed "${startTagToken.parts[1]}"`));
9878 }
9879 }
9880 else if (this._peek.type === TokenType.TAG_OPEN_END) {
9881 this._advance();
9882 selfClosing = false;
9883 }
9884 const end = this._peek.sourceSpan.fullStart;
9885 const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
9886 // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
9887 const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
9888 const el = new Element$1(fullName, attrs, [], span, startSpan, undefined);
9889 this._pushElement(el);
9890 if (selfClosing) {
9891 // Elements that are self-closed have their `endSourceSpan` set to the full span, as the
9892 // element start tag also represents the end tag.
9893 this._popElement(fullName, span);
9894 }
9895 else if (startTagToken.type === TokenType.INCOMPLETE_TAG_OPEN) {
9896 // We already know the opening tag is not complete, so it is unlikely it has a corresponding
9897 // close tag. Let's optimistically parse it as a full element and emit an error.
9898 this._popElement(fullName, null);
9899 this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
9900 }
9901 }
9902 _pushElement(el) {
9903 const parentEl = this._getParentElement();
9904 if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
9905 this._elementStack.pop();
9906 }
9907 this._addToParent(el);
9908 this._elementStack.push(el);
9909 }
9910 _consumeEndTag(endTagToken) {
9911 const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
9912 if (this.getTagDefinition(fullName).isVoid) {
9913 this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
9914 }
9915 else if (!this._popElement(fullName, endTagToken.sourceSpan)) {
9916 const errMsg = `Unexpected closing tag "${fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`;
9917 this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
9918 }
9919 }
9920 /**
9921 * Closes the nearest element with the tag name `fullName` in the parse tree.
9922 * `endSourceSpan` is the span of the closing tag, or null if the element does
9923 * not have a closing tag (for example, this happens when an incomplete
9924 * opening tag is recovered).
9925 */
9926 _popElement(fullName, endSourceSpan) {
9927 for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
9928 const el = this._elementStack[stackIndex];
9929 if (el.name == fullName) {
9930 // Record the parse span with the element that is being closed. Any elements that are
9931 // removed from the element stack at this point are closed implicitly, so they won't get
9932 // an end source span (as there is no explicit closing element).
9933 el.endSourceSpan = endSourceSpan;
9934 el.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : el.sourceSpan.end;
9935 this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
9936 return true;
9937 }
9938 if (!this.getTagDefinition(el.name).closedByParent) {
9939 return false;
9940 }
9941 }
9942 return false;
9943 }
9944 _consumeAttr(attrName) {
9945 const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
9946 let end = attrName.sourceSpan.end;
9947 let value = '';
9948 let valueSpan = undefined;
9949 if (this._peek.type === TokenType.ATTR_QUOTE) {
9950 this._advance();
9951 }
9952 if (this._peek.type === TokenType.ATTR_VALUE) {
9953 const valueToken = this._advance();
9954 value = valueToken.parts[0];
9955 end = valueToken.sourceSpan.end;
9956 valueSpan = valueToken.sourceSpan;
9957 }
9958 if (this._peek.type === TokenType.ATTR_QUOTE) {
9959 const quoteToken = this._advance();
9960 end = quoteToken.sourceSpan.end;
9961 }
9962 const keySpan = new ParseSourceSpan(attrName.sourceSpan.start, attrName.sourceSpan.end);
9963 return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end, attrName.sourceSpan.fullStart), keySpan, valueSpan);
9964 }
9965 _getParentElement() {
9966 return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
9967 }
9968 _addToParent(node) {
9969 const parent = this._getParentElement();
9970 if (parent != null) {
9971 parent.children.push(node);
9972 }
9973 else {
9974 this.rootNodes.push(node);
9975 }
9976 }
9977 _getElementFullName(prefix, localName, parentElement) {
9978 if (prefix === '') {
9979 prefix = this.getTagDefinition(localName).implicitNamespacePrefix || '';
9980 if (prefix === '' && parentElement != null) {
9981 const parentTagName = splitNsName(parentElement.name)[1];
9982 const parentTagDefinition = this.getTagDefinition(parentTagName);
9983 if (!parentTagDefinition.preventNamespaceInheritance) {
9984 prefix = getNsPrefix(parentElement.name);
9985 }
9986 }
9987 }
9988 return mergeNsAndName(prefix, localName);
9989 }
9990 }
9991 function lastOnStack(stack, element) {
9992 return stack.length > 0 && stack[stack.length - 1] === element;
9993 }
9994
9995 /**
9996 * @license
9997 * Copyright Google LLC All Rights Reserved.
9998 *
9999 * Use of this source code is governed by an MIT-style license that can be
10000 * found in the LICENSE file at https://angular.io/license
10001 */
10002 class HtmlParser extends Parser {
10003 constructor() {
10004 super(getHtmlTagDefinition);
10005 }
10006 parse(source, url, options) {
10007 return super.parse(source, url, options);
10008 }
10009 }
10010
10011 /**
10012 * @license
10013 * Copyright Google LLC All Rights Reserved.
10014 *
10015 * Use of this source code is governed by an MIT-style license that can be
10016 * found in the LICENSE file at https://angular.io/license
10017 */
10018 const PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces';
10019 const SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']);
10020 // Equivalent to \s with \u00a0 (non-breaking space) excluded.
10021 // Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
10022 const WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
10023 const NO_WS_REGEXP = new RegExp(`[^${WS_CHARS}]`);
10024 const WS_REPLACE_REGEXP = new RegExp(`[${WS_CHARS}]{2,}`, 'g');
10025 function hasPreserveWhitespacesAttr(attrs) {
10026 return attrs.some((attr) => attr.name === PRESERVE_WS_ATTR_NAME);
10027 }
10028 /**
10029 * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
10030 * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
10031 * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
10032 * and later on replaced by a space. We are re-implementing the same idea here.
10033 */
10034 function replaceNgsp(value) {
10035 // lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE
10036 return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' ');
10037 }
10038 /**
10039 * This visitor can walk HTML parse tree and remove / trim text nodes using the following rules:
10040 * - consider spaces, tabs and new lines as whitespace characters;
10041 * - drop text nodes consisting of whitespace characters only;
10042 * - for all other text nodes replace consecutive whitespace characters with one space;
10043 * - convert &ngsp; pseudo-entity to a single space;
10044 *
10045 * Removal and trimming of whitespaces have positive performance impact (less code to generate
10046 * while compiling templates, faster view creation). At the same time it can be "destructive"
10047 * in some cases (whitespaces can influence layout). Because of the potential of breaking layout
10048 * this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for
10049 * whitespace removal. The default option for whitespace removal will be revisited in Angular 6
10050 * and might be changed to "on" by default.
10051 */
10052 class WhitespaceVisitor {
10053 visitElement(element, context) {
10054 if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
10055 // don't descent into elements where we need to preserve whitespaces
10056 // but still visit all attributes to eliminate one used as a market to preserve WS
10057 return new Element$1(element.name, visitAll$1(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
10058 }
10059 return new Element$1(element.name, element.attrs, visitAllWithSiblings(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
10060 }
10061 visitAttribute(attribute, context) {
10062 return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null;
10063 }
10064 visitText(text, context) {
10065 const isNotBlank = text.value.match(NO_WS_REGEXP);
10066 const hasExpansionSibling = context &&
10067 (context.prev instanceof Expansion || context.next instanceof Expansion);
10068 if (isNotBlank || hasExpansionSibling) {
10069 return new Text$2(replaceNgsp(text.value).replace(WS_REPLACE_REGEXP, ' '), text.sourceSpan, text.i18n);
10070 }
10071 return null;
10072 }
10073 visitComment(comment, context) {
10074 return comment;
10075 }
10076 visitExpansion(expansion, context) {
10077 return expansion;
10078 }
10079 visitExpansionCase(expansionCase, context) {
10080 return expansionCase;
10081 }
10082 }
10083 function removeWhitespaces(htmlAstWithErrors) {
10084 return new ParseTreeResult(visitAll$1(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors);
10085 }
10086 function visitAllWithSiblings(visitor, nodes) {
10087 const result = [];
10088 nodes.forEach((ast, i) => {
10089 const context = { prev: nodes[i - 1], next: nodes[i + 1] };
10090 const astResult = ast.visit(visitor, context);
10091 if (astResult) {
10092 result.push(astResult);
10093 }
10094 });
10095 return result;
10096 }
10097
10098 /**
10099 * @license
10100 * Copyright Google LLC All Rights Reserved.
10101 *
10102 * Use of this source code is governed by an MIT-style license that can be
10103 * found in the LICENSE file at https://angular.io/license
10104 */
10105 // http://cldr.unicode.org/index/cldr-spec/plural-rules
10106 const PLURAL_CASES = ['zero', 'one', 'two', 'few', 'many', 'other'];
10107 /**
10108 * Expands special forms into elements.
10109 *
10110 * For example,
10111 *
10112 * ```
10113 * { messages.length, plural,
10114 * =0 {zero}
10115 * =1 {one}
10116 * other {more than one}
10117 * }
10118 * ```
10119 *
10120 * will be expanded into
10121 *
10122 * ```
10123 * <ng-container [ngPlural]="messages.length">
10124 * <ng-template ngPluralCase="=0">zero</ng-template>
10125 * <ng-template ngPluralCase="=1">one</ng-template>
10126 * <ng-template ngPluralCase="other">more than one</ng-template>
10127 * </ng-container>
10128 * ```
10129 */
10130 function expandNodes(nodes) {
10131 const expander = new _Expander();
10132 return new ExpansionResult(visitAll$1(expander, nodes), expander.isExpanded, expander.errors);
10133 }
10134 class ExpansionResult {
10135 constructor(nodes, expanded, errors) {
10136 this.nodes = nodes;
10137 this.expanded = expanded;
10138 this.errors = errors;
10139 }
10140 }
10141 class ExpansionError extends ParseError {
10142 constructor(span, errorMsg) {
10143 super(span, errorMsg);
10144 }
10145 }
10146 /**
10147 * Expand expansion forms (plural, select) to directives
10148 *
10149 * @internal
10150 */
10151 class _Expander {
10152 constructor() {
10153 this.isExpanded = false;
10154 this.errors = [];
10155 }
10156 visitElement(element, context) {
10157 return new Element$1(element.name, element.attrs, visitAll$1(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
10158 }
10159 visitAttribute(attribute, context) {
10160 return attribute;
10161 }
10162 visitText(text, context) {
10163 return text;
10164 }
10165 visitComment(comment, context) {
10166 return comment;
10167 }
10168 visitExpansion(icu, context) {
10169 this.isExpanded = true;
10170 return icu.type == 'plural' ? _expandPluralForm(icu, this.errors) :
10171 _expandDefaultForm(icu, this.errors);
10172 }
10173 visitExpansionCase(icuCase, context) {
10174 throw new Error('Should not be reached');
10175 }
10176 }
10177 // Plural forms are expanded to `NgPlural` and `NgPluralCase`s
10178 function _expandPluralForm(ast, errors) {
10179 const children = ast.cases.map(c => {
10180 if (PLURAL_CASES.indexOf(c.value) == -1 && !c.value.match(/^=\d+$/)) {
10181 errors.push(new ExpansionError(c.valueSourceSpan, `Plural cases should be "=<number>" or one of ${PLURAL_CASES.join(', ')}`));
10182 }
10183 const expansionResult = expandNodes(c.expression);
10184 errors.push(...expansionResult.errors);
10185 return new Element$1(`ng-template`, [new Attribute('ngPluralCase', `${c.value}`, c.valueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
10186 });
10187 const switchAttr = new Attribute('[ngPlural]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* i18n */);
10188 return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
10189 }
10190 // ICU messages (excluding plural form) are expanded to `NgSwitch` and `NgSwitchCase`s
10191 function _expandDefaultForm(ast, errors) {
10192 const children = ast.cases.map(c => {
10193 const expansionResult = expandNodes(c.expression);
10194 errors.push(...expansionResult.errors);
10195 if (c.value === 'other') {
10196 // other is the default case when no values match
10197 return new Element$1(`ng-template`, [new Attribute('ngSwitchDefault', '', c.valueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
10198 }
10199 return new Element$1(`ng-template`, [new Attribute('ngSwitchCase', `${c.value}`, c.valueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
10200 });
10201 const switchAttr = new Attribute('[ngSwitch]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* i18n */);
10202 return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
10203 }
10204
10205 /**
10206 * @license
10207 * Copyright Google LLC All Rights Reserved.
10208 *
10209 * Use of this source code is governed by an MIT-style license that can be
10210 * found in the LICENSE file at https://angular.io/license
10211 */
10212 /**
10213 * A segment of text within the template.
10214 */
10215 class TextAst {
10216 constructor(value, ngContentIndex, sourceSpan) {
10217 this.value = value;
10218 this.ngContentIndex = ngContentIndex;
10219 this.sourceSpan = sourceSpan;
10220 }
10221 visit(visitor, context) {
10222 return visitor.visitText(this, context);
10223 }
10224 }
10225 /**
10226 * A bound expression within the text of a template.
10227 */
10228 class BoundTextAst {
10229 constructor(value, ngContentIndex, sourceSpan) {
10230 this.value = value;
10231 this.ngContentIndex = ngContentIndex;
10232 this.sourceSpan = sourceSpan;
10233 }
10234 visit(visitor, context) {
10235 return visitor.visitBoundText(this, context);
10236 }
10237 }
10238 /**
10239 * A plain attribute on an element.
10240 */
10241 class AttrAst {
10242 constructor(name, value, sourceSpan) {
10243 this.name = name;
10244 this.value = value;
10245 this.sourceSpan = sourceSpan;
10246 }
10247 visit(visitor, context) {
10248 return visitor.visitAttr(this, context);
10249 }
10250 }
10251 const BoundPropertyMapping = {
10252 [4 /* Animation */]: 4 /* Animation */,
10253 [1 /* Attribute */]: 1 /* Attribute */,
10254 [2 /* Class */]: 2 /* Class */,
10255 [0 /* Property */]: 0 /* Property */,
10256 [3 /* Style */]: 3 /* Style */,
10257 };
10258 /**
10259 * A binding for an element property (e.g. `[property]="expression"`) or an animation trigger (e.g.
10260 * `[@trigger]="stateExp"`)
10261 */
10262 class BoundElementPropertyAst {
10263 constructor(name, type, securityContext, value, unit, sourceSpan) {
10264 this.name = name;
10265 this.type = type;
10266 this.securityContext = securityContext;
10267 this.value = value;
10268 this.unit = unit;
10269 this.sourceSpan = sourceSpan;
10270 this.isAnimation = this.type === 4 /* Animation */;
10271 }
10272 static fromBoundProperty(prop) {
10273 const type = BoundPropertyMapping[prop.type];
10274 return new BoundElementPropertyAst(prop.name, type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan);
10275 }
10276 visit(visitor, context) {
10277 return visitor.visitElementProperty(this, context);
10278 }
10279 }
10280 /**
10281 * A binding for an element event (e.g. `(event)="handler()"`) or an animation trigger event (e.g.
10282 * `(@trigger.phase)="callback($event)"`).
10283 */
10284 class BoundEventAst {
10285 constructor(name, target, phase, handler, sourceSpan, handlerSpan) {
10286 this.name = name;
10287 this.target = target;
10288 this.phase = phase;
10289 this.handler = handler;
10290 this.sourceSpan = sourceSpan;
10291 this.handlerSpan = handlerSpan;
10292 this.fullName = BoundEventAst.calcFullName(this.name, this.target, this.phase);
10293 this.isAnimation = !!this.phase;
10294 }
10295 static calcFullName(name, target, phase) {
10296 if (target) {
10297 return `${target}:${name}`;
10298 }
10299 if (phase) {
10300 return `@${name}.${phase}`;
10301 }
10302 return name;
10303 }
10304 static fromParsedEvent(event) {
10305 const target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
10306 const phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
10307 return new BoundEventAst(event.name, target, phase, event.handler, event.sourceSpan, event.handlerSpan);
10308 }
10309 visit(visitor, context) {
10310 return visitor.visitEvent(this, context);
10311 }
10312 }
10313 /**
10314 * A reference declaration on an element (e.g. `let someName="expression"`).
10315 */
10316 class ReferenceAst {
10317 constructor(name, value, originalValue, sourceSpan) {
10318 this.name = name;
10319 this.value = value;
10320 this.originalValue = originalValue;
10321 this.sourceSpan = sourceSpan;
10322 }
10323 visit(visitor, context) {
10324 return visitor.visitReference(this, context);
10325 }
10326 }
10327 /**
10328 * A variable declaration on a <ng-template> (e.g. `var-someName="someLocalName"`).
10329 */
10330 class VariableAst {
10331 constructor(name, value, sourceSpan, valueSpan) {
10332 this.name = name;
10333 this.value = value;
10334 this.sourceSpan = sourceSpan;
10335 this.valueSpan = valueSpan;
10336 }
10337 static fromParsedVariable(v) {
10338 return new VariableAst(v.name, v.value, v.sourceSpan, v.valueSpan);
10339 }
10340 visit(visitor, context) {
10341 return visitor.visitVariable(this, context);
10342 }
10343 }
10344 /**
10345 * An element declaration in a template.
10346 */
10347 class ElementAst {
10348 constructor(name, attrs, inputs, outputs, references, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan, endSourceSpan) {
10349 this.name = name;
10350 this.attrs = attrs;
10351 this.inputs = inputs;
10352 this.outputs = outputs;
10353 this.references = references;
10354 this.directives = directives;
10355 this.providers = providers;
10356 this.hasViewContainer = hasViewContainer;
10357 this.queryMatches = queryMatches;
10358 this.children = children;
10359 this.ngContentIndex = ngContentIndex;
10360 this.sourceSpan = sourceSpan;
10361 this.endSourceSpan = endSourceSpan;
10362 }
10363 visit(visitor, context) {
10364 return visitor.visitElement(this, context);
10365 }
10366 }
10367 /**
10368 * A `<ng-template>` element included in an Angular template.
10369 */
10370 class EmbeddedTemplateAst {
10371 constructor(attrs, outputs, references, variables, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan) {
10372 this.attrs = attrs;
10373 this.outputs = outputs;
10374 this.references = references;
10375 this.variables = variables;
10376 this.directives = directives;
10377 this.providers = providers;
10378 this.hasViewContainer = hasViewContainer;
10379 this.queryMatches = queryMatches;
10380 this.children = children;
10381 this.ngContentIndex = ngContentIndex;
10382 this.sourceSpan = sourceSpan;
10383 }
10384 visit(visitor, context) {
10385 return visitor.visitEmbeddedTemplate(this, context);
10386 }
10387 }
10388 /**
10389 * A directive property with a bound value (e.g. `*ngIf="condition").
10390 */
10391 class BoundDirectivePropertyAst {
10392 constructor(directiveName, templateName, value, sourceSpan) {
10393 this.directiveName = directiveName;
10394 this.templateName = templateName;
10395 this.value = value;
10396 this.sourceSpan = sourceSpan;
10397 }
10398 visit(visitor, context) {
10399 return visitor.visitDirectiveProperty(this, context);
10400 }
10401 }
10402 /**
10403 * A directive declared on an element.
10404 */
10405 class DirectiveAst {
10406 constructor(directive, inputs, hostProperties, hostEvents, contentQueryStartId, sourceSpan) {
10407 this.directive = directive;
10408 this.inputs = inputs;
10409 this.hostProperties = hostProperties;
10410 this.hostEvents = hostEvents;
10411 this.contentQueryStartId = contentQueryStartId;
10412 this.sourceSpan = sourceSpan;
10413 }
10414 visit(visitor, context) {
10415 return visitor.visitDirective(this, context);
10416 }
10417 }
10418 /**
10419 * A provider declared on an element
10420 */
10421 class ProviderAst {
10422 constructor(token, multiProvider, eager, providers, providerType, lifecycleHooks, sourceSpan, isModule) {
10423 this.token = token;
10424 this.multiProvider = multiProvider;
10425 this.eager = eager;
10426 this.providers = providers;
10427 this.providerType = providerType;
10428 this.lifecycleHooks = lifecycleHooks;
10429 this.sourceSpan = sourceSpan;
10430 this.isModule = isModule;
10431 }
10432 visit(visitor, context) {
10433 // No visit method in the visitor for now...
10434 return null;
10435 }
10436 }
10437 var ProviderAstType;
10438 (function (ProviderAstType) {
10439 ProviderAstType[ProviderAstType["PublicService"] = 0] = "PublicService";
10440 ProviderAstType[ProviderAstType["PrivateService"] = 1] = "PrivateService";
10441 ProviderAstType[ProviderAstType["Component"] = 2] = "Component";
10442 ProviderAstType[ProviderAstType["Directive"] = 3] = "Directive";
10443 ProviderAstType[ProviderAstType["Builtin"] = 4] = "Builtin";
10444 })(ProviderAstType || (ProviderAstType = {}));
10445 /**
10446 * Position where content is to be projected (instance of `<ng-content>` in a template).
10447 */
10448 class NgContentAst {
10449 constructor(index, ngContentIndex, sourceSpan) {
10450 this.index = index;
10451 this.ngContentIndex = ngContentIndex;
10452 this.sourceSpan = sourceSpan;
10453 }
10454 visit(visitor, context) {
10455 return visitor.visitNgContent(this, context);
10456 }
10457 }
10458 /**
10459 * A visitor that accepts each node but doesn't do anything. It is intended to be used
10460 * as the base class for a visitor that is only interested in a subset of the node types.
10461 */
10462 class NullTemplateVisitor {
10463 visitNgContent(ast, context) { }
10464 visitEmbeddedTemplate(ast, context) { }
10465 visitElement(ast, context) { }
10466 visitReference(ast, context) { }
10467 visitVariable(ast, context) { }
10468 visitEvent(ast, context) { }
10469 visitElementProperty(ast, context) { }
10470 visitAttr(ast, context) { }
10471 visitBoundText(ast, context) { }
10472 visitText(ast, context) { }
10473 visitDirective(ast, context) { }
10474 visitDirectiveProperty(ast, context) { }
10475 }
10476 /**
10477 * Base class that can be used to build a visitor that visits each node
10478 * in an template ast recursively.
10479 */
10480 class RecursiveTemplateAstVisitor extends NullTemplateVisitor {
10481 constructor() {
10482 super();
10483 }
10484 // Nodes with children
10485 visitEmbeddedTemplate(ast, context) {
10486 return this.visitChildren(context, visit => {
10487 visit(ast.attrs);
10488 visit(ast.references);
10489 visit(ast.variables);
10490 visit(ast.directives);
10491 visit(ast.providers);
10492 visit(ast.children);
10493 });
10494 }
10495 visitElement(ast, context) {
10496 return this.visitChildren(context, visit => {
10497 visit(ast.attrs);
10498 visit(ast.inputs);
10499 visit(ast.outputs);
10500 visit(ast.references);
10501 visit(ast.directives);
10502 visit(ast.providers);
10503 visit(ast.children);
10504 });
10505 }
10506 visitDirective(ast, context) {
10507 return this.visitChildren(context, visit => {
10508 visit(ast.inputs);
10509 visit(ast.hostProperties);
10510 visit(ast.hostEvents);
10511 });
10512 }
10513 visitChildren(context, cb) {
10514 let results = [];
10515 let t = this;
10516 function visit(children) {
10517 if (children && children.length)
10518 results.push(templateVisitAll(t, children, context));
10519 }
10520 cb(visit);
10521 return Array.prototype.concat.apply([], results);
10522 }
10523 }
10524 /**
10525 * Visit every node in a list of {@link TemplateAst}s with the given {@link TemplateAstVisitor}.
10526 */
10527 function templateVisitAll(visitor, asts, context = null) {
10528 const result = [];
10529 const visit = visitor.visit ?
10530 (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) :
10531 (ast) => ast.visit(visitor, context);
10532 asts.forEach(ast => {
10533 const astResult = visit(ast);
10534 if (astResult) {
10535 result.push(astResult);
10536 }
10537 });
10538 return result;
10539 }
10540
10541 /**
10542 * @license
10543 * Copyright Google LLC All Rights Reserved.
10544 *
10545 * Use of this source code is governed by an MIT-style license that can be
10546 * found in the LICENSE file at https://angular.io/license
10547 */
10548 class ProviderError extends ParseError {
10549 constructor(message, span) {
10550 super(span, message);
10551 }
10552 }
10553 class ProviderViewContext {
10554 constructor(reflector, component) {
10555 this.reflector = reflector;
10556 this.component = component;
10557 this.errors = [];
10558 this.viewQueries = _getViewQueries(component);
10559 this.viewProviders = new Map();
10560 component.viewProviders.forEach((provider) => {
10561 if (this.viewProviders.get(tokenReference(provider.token)) == null) {
10562 this.viewProviders.set(tokenReference(provider.token), true);
10563 }
10564 });
10565 }
10566 }
10567 class ProviderElementContext {
10568 constructor(viewContext, _parent, _isViewRoot, _directiveAsts, attrs, refs, isTemplate, contentQueryStartId, _sourceSpan) {
10569 this.viewContext = viewContext;
10570 this._parent = _parent;
10571 this._isViewRoot = _isViewRoot;
10572 this._directiveAsts = _directiveAsts;
10573 this._sourceSpan = _sourceSpan;
10574 this._transformedProviders = new Map();
10575 this._seenProviders = new Map();
10576 this._queriedTokens = new Map();
10577 this.transformedHasViewContainer = false;
10578 this._attrs = {};
10579 attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
10580 const directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
10581 this._allProviders =
10582 _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, viewContext.errors);
10583 this._contentQueries = _getContentQueries(contentQueryStartId, directivesMeta);
10584 Array.from(this._allProviders.values()).forEach((provider) => {
10585 this._addQueryReadsTo(provider.token, provider.token, this._queriedTokens);
10586 });
10587 if (isTemplate) {
10588 const templateRefId = createTokenForExternalReference(this.viewContext.reflector, Identifiers.TemplateRef);
10589 this._addQueryReadsTo(templateRefId, templateRefId, this._queriedTokens);
10590 }
10591 refs.forEach((refAst) => {
10592 let defaultQueryValue = refAst.value ||
10593 createTokenForExternalReference(this.viewContext.reflector, Identifiers.ElementRef);
10594 this._addQueryReadsTo({ value: refAst.name }, defaultQueryValue, this._queriedTokens);
10595 });
10596 if (this._queriedTokens.get(this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef))) {
10597 this.transformedHasViewContainer = true;
10598 }
10599 // create the providers that we know are eager first
10600 Array.from(this._allProviders.values()).forEach((provider) => {
10601 const eager = provider.eager || this._queriedTokens.get(tokenReference(provider.token));
10602 if (eager) {
10603 this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
10604 }
10605 });
10606 }
10607 afterElement() {
10608 // collect lazy providers
10609 Array.from(this._allProviders.values()).forEach((provider) => {
10610 this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
10611 });
10612 }
10613 get transformProviders() {
10614 // Note: Maps keep their insertion order.
10615 const lazyProviders = [];
10616 const eagerProviders = [];
10617 this._transformedProviders.forEach(provider => {
10618 if (provider.eager) {
10619 eagerProviders.push(provider);
10620 }
10621 else {
10622 lazyProviders.push(provider);
10623 }
10624 });
10625 return lazyProviders.concat(eagerProviders);
10626 }
10627 get transformedDirectiveAsts() {
10628 const sortedProviderTypes = this.transformProviders.map(provider => provider.token.identifier);
10629 const sortedDirectives = this._directiveAsts.slice();
10630 sortedDirectives.sort((dir1, dir2) => sortedProviderTypes.indexOf(dir1.directive.type) -
10631 sortedProviderTypes.indexOf(dir2.directive.type));
10632 return sortedDirectives;
10633 }
10634 get queryMatches() {
10635 const allMatches = [];
10636 this._queriedTokens.forEach((matches) => {
10637 allMatches.push(...matches);
10638 });
10639 return allMatches;
10640 }
10641 _addQueryReadsTo(token, defaultValue, queryReadTokens) {
10642 this._getQueriesFor(token).forEach((query) => {
10643 const queryValue = query.meta.read || defaultValue;
10644 const tokenRef = tokenReference(queryValue);
10645 let queryMatches = queryReadTokens.get(tokenRef);
10646 if (!queryMatches) {
10647 queryMatches = [];
10648 queryReadTokens.set(tokenRef, queryMatches);
10649 }
10650 queryMatches.push({ queryId: query.queryId, value: queryValue });
10651 });
10652 }
10653 _getQueriesFor(token) {
10654 const result = [];
10655 let currentEl = this;
10656 let distance = 0;
10657 let queries;
10658 while (currentEl !== null) {
10659 queries = currentEl._contentQueries.get(tokenReference(token));
10660 if (queries) {
10661 result.push(...queries.filter((query) => query.meta.descendants || distance <= 1));
10662 }
10663 if (currentEl._directiveAsts.length > 0) {
10664 distance++;
10665 }
10666 currentEl = currentEl._parent;
10667 }
10668 queries = this.viewContext.viewQueries.get(tokenReference(token));
10669 if (queries) {
10670 result.push(...queries);
10671 }
10672 return result;
10673 }
10674 _getOrCreateLocalProvider(requestingProviderType, token, eager) {
10675 const resolvedProvider = this._allProviders.get(tokenReference(token));
10676 if (!resolvedProvider ||
10677 ((requestingProviderType === ProviderAstType.Directive ||
10678 requestingProviderType === ProviderAstType.PublicService) &&
10679 resolvedProvider.providerType === ProviderAstType.PrivateService) ||
10680 ((requestingProviderType === ProviderAstType.PrivateService ||
10681 requestingProviderType === ProviderAstType.PublicService) &&
10682 resolvedProvider.providerType === ProviderAstType.Builtin)) {
10683 return null;
10684 }
10685 let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
10686 if (transformedProviderAst) {
10687 return transformedProviderAst;
10688 }
10689 if (this._seenProviders.get(tokenReference(token)) != null) {
10690 this.viewContext.errors.push(new ProviderError(`Cannot instantiate cyclic dependency! ${tokenName(token)}`, this._sourceSpan));
10691 return null;
10692 }
10693 this._seenProviders.set(tokenReference(token), true);
10694 const transformedProviders = resolvedProvider.providers.map((provider) => {
10695 let transformedUseValue = provider.useValue;
10696 let transformedUseExisting = provider.useExisting;
10697 let transformedDeps = undefined;
10698 if (provider.useExisting != null) {
10699 const existingDiDep = this._getDependency(resolvedProvider.providerType, { token: provider.useExisting }, eager);
10700 if (existingDiDep.token != null) {
10701 transformedUseExisting = existingDiDep.token;
10702 }
10703 else {
10704 transformedUseExisting = null;
10705 transformedUseValue = existingDiDep.value;
10706 }
10707 }
10708 else if (provider.useFactory) {
10709 const deps = provider.deps || provider.useFactory.diDeps;
10710 transformedDeps =
10711 deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
10712 }
10713 else if (provider.useClass) {
10714 const deps = provider.deps || provider.useClass.diDeps;
10715 transformedDeps =
10716 deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
10717 }
10718 return _transformProvider(provider, {
10719 useExisting: transformedUseExisting,
10720 useValue: transformedUseValue,
10721 deps: transformedDeps
10722 });
10723 });
10724 transformedProviderAst =
10725 _transformProviderAst(resolvedProvider, { eager: eager, providers: transformedProviders });
10726 this._transformedProviders.set(tokenReference(token), transformedProviderAst);
10727 return transformedProviderAst;
10728 }
10729 _getLocalDependency(requestingProviderType, dep, eager = false) {
10730 if (dep.isAttribute) {
10731 const attrValue = this._attrs[dep.token.value];
10732 return { isValue: true, value: attrValue == null ? null : attrValue };
10733 }
10734 if (dep.token != null) {
10735 // access builtints
10736 if ((requestingProviderType === ProviderAstType.Directive ||
10737 requestingProviderType === ProviderAstType.Component)) {
10738 if (tokenReference(dep.token) ===
10739 this.viewContext.reflector.resolveExternalReference(Identifiers.Renderer) ||
10740 tokenReference(dep.token) ===
10741 this.viewContext.reflector.resolveExternalReference(Identifiers.ElementRef) ||
10742 tokenReference(dep.token) ===
10743 this.viewContext.reflector.resolveExternalReference(Identifiers.ChangeDetectorRef) ||
10744 tokenReference(dep.token) ===
10745 this.viewContext.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
10746 return dep;
10747 }
10748 if (tokenReference(dep.token) ===
10749 this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
10750 this.transformedHasViewContainer = true;
10751 }
10752 }
10753 // access the injector
10754 if (tokenReference(dep.token) ===
10755 this.viewContext.reflector.resolveExternalReference(Identifiers.Injector)) {
10756 return dep;
10757 }
10758 // access providers
10759 if (this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager) != null) {
10760 return dep;
10761 }
10762 }
10763 return null;
10764 }
10765 _getDependency(requestingProviderType, dep, eager = false) {
10766 let currElement = this;
10767 let currEager = eager;
10768 let result = null;
10769 if (!dep.isSkipSelf) {
10770 result = this._getLocalDependency(requestingProviderType, dep, eager);
10771 }
10772 if (dep.isSelf) {
10773 if (!result && dep.isOptional) {
10774 result = { isValue: true, value: null };
10775 }
10776 }
10777 else {
10778 // check parent elements
10779 while (!result && currElement._parent) {
10780 const prevElement = currElement;
10781 currElement = currElement._parent;
10782 if (prevElement._isViewRoot) {
10783 currEager = false;
10784 }
10785 result = currElement._getLocalDependency(ProviderAstType.PublicService, dep, currEager);
10786 }
10787 // check @Host restriction
10788 if (!result) {
10789 if (!dep.isHost || this.viewContext.component.isHost ||
10790 this.viewContext.component.type.reference === tokenReference(dep.token) ||
10791 this.viewContext.viewProviders.get(tokenReference(dep.token)) != null) {
10792 result = dep;
10793 }
10794 else {
10795 result = dep.isOptional ? { isValue: true, value: null } : null;
10796 }
10797 }
10798 }
10799 if (!result) {
10800 this.viewContext.errors.push(new ProviderError(`No provider for ${tokenName(dep.token)}`, this._sourceSpan));
10801 }
10802 return result;
10803 }
10804 }
10805 function _transformProvider(provider, { useExisting, useValue, deps }) {
10806 return {
10807 token: provider.token,
10808 useClass: provider.useClass,
10809 useExisting: useExisting,
10810 useFactory: provider.useFactory,
10811 useValue: useValue,
10812 deps: deps,
10813 multi: provider.multi
10814 };
10815 }
10816 function _transformProviderAst(provider, { eager, providers }) {
10817 return new ProviderAst(provider.token, provider.multiProvider, provider.eager || eager, providers, provider.providerType, provider.lifecycleHooks, provider.sourceSpan, provider.isModule);
10818 }
10819 function _resolveProvidersFromDirectives(directives, sourceSpan, targetErrors) {
10820 const providersByToken = new Map();
10821 directives.forEach((directive) => {
10822 const dirProvider = { token: { identifier: directive.type }, useClass: directive.type };
10823 _resolveProviders([dirProvider], directive.isComponent ? ProviderAstType.Component : ProviderAstType.Directive, true, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10824 });
10825 // Note: directives need to be able to overwrite providers of a component!
10826 const directivesWithComponentFirst = directives.filter(dir => dir.isComponent).concat(directives.filter(dir => !dir.isComponent));
10827 directivesWithComponentFirst.forEach((directive) => {
10828 _resolveProviders(directive.providers, ProviderAstType.PublicService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10829 _resolveProviders(directive.viewProviders, ProviderAstType.PrivateService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10830 });
10831 return providersByToken;
10832 }
10833 function _resolveProviders(providers, providerType, eager, sourceSpan, targetErrors, targetProvidersByToken, isModule) {
10834 providers.forEach((provider) => {
10835 let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
10836 if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
10837 targetErrors.push(new ProviderError(`Mixing multi and non multi provider is not possible for token ${tokenName(resolvedProvider.token)}`, sourceSpan));
10838 }
10839 if (!resolvedProvider) {
10840 const lifecycleHooks = provider.token.identifier &&
10841 provider.token.identifier.lifecycleHooks ?
10842 provider.token.identifier.lifecycleHooks :
10843 [];
10844 const isUseValue = !(provider.useClass || provider.useExisting || provider.useFactory);
10845 resolvedProvider = new ProviderAst(provider.token, !!provider.multi, eager || isUseValue, [provider], providerType, lifecycleHooks, sourceSpan, isModule);
10846 targetProvidersByToken.set(tokenReference(provider.token), resolvedProvider);
10847 }
10848 else {
10849 if (!provider.multi) {
10850 resolvedProvider.providers.length = 0;
10851 }
10852 resolvedProvider.providers.push(provider);
10853 }
10854 });
10855 }
10856 function _getViewQueries(component) {
10857 // Note: queries start with id 1 so we can use the number in a Bloom filter!
10858 let viewQueryId = 1;
10859 const viewQueries = new Map();
10860 if (component.viewQueries) {
10861 component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, { meta: query, queryId: viewQueryId++ }));
10862 }
10863 return viewQueries;
10864 }
10865 function _getContentQueries(contentQueryStartId, directives) {
10866 let contentQueryId = contentQueryStartId;
10867 const contentQueries = new Map();
10868 directives.forEach((directive, directiveIndex) => {
10869 if (directive.queries) {
10870 directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, { meta: query, queryId: contentQueryId++ }));
10871 }
10872 });
10873 return contentQueries;
10874 }
10875 function _addQueryToTokenMap(map, query) {
10876 query.meta.selectors.forEach((token) => {
10877 let entry = map.get(tokenReference(token));
10878 if (!entry) {
10879 entry = [];
10880 map.set(tokenReference(token), entry);
10881 }
10882 entry.push(query);
10883 });
10884 }
10885
10886 /**
10887 * @license
10888 * Copyright Google LLC All Rights Reserved.
10889 *
10890 * Use of this source code is governed by an MIT-style license that can be
10891 * found in the LICENSE file at https://angular.io/license
10892 */
10893 class StyleWithImports {
10894 constructor(style, styleUrls) {
10895 this.style = style;
10896 this.styleUrls = styleUrls;
10897 }
10898 }
10899 function isStyleUrlResolvable(url) {
10900 if (url == null || url.length === 0 || url[0] == '/')
10901 return false;
10902 const schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP);
10903 return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset';
10904 }
10905 /**
10906 * Rewrites stylesheets by resolving and removing the @import urls that
10907 * are either relative or don't have a `package:` scheme
10908 */
10909 function extractStyleUrls(resolver, baseUrl, cssText) {
10910 const foundUrls = [];
10911 const modifiedCssText = cssText.replace(CSS_STRIPPABLE_COMMENT_REGEXP, '')
10912 .replace(CSS_IMPORT_REGEXP, (...m) => {
10913 const url = m[1] || m[2];
10914 if (!isStyleUrlResolvable(url)) {
10915 // Do not attempt to resolve non-package absolute URLs with URI
10916 // scheme
10917 return m[0];
10918 }
10919 foundUrls.push(resolver.resolve(baseUrl, url));
10920 return '';
10921 });
10922 return new StyleWithImports(modifiedCssText, foundUrls);
10923 }
10924 const CSS_IMPORT_REGEXP = /@import\s+(?:url\()?\s*(?:(?:['"]([^'"]*))|([^;\)\s]*))[^;]*;?/g;
10925 const CSS_STRIPPABLE_COMMENT_REGEXP = /\/\*(?!#\s*(?:sourceURL|sourceMappingURL)=)[\s\S]+?\*\//g;
10926 const URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/;
10927
10928 /**
10929 * @license
10930 * Copyright Google LLC All Rights Reserved.
10931 *
10932 * Use of this source code is governed by an MIT-style license that can be
10933 * found in the LICENSE file at https://angular.io/license
10934 */
10935 const PROPERTY_PARTS_SEPARATOR = '.';
10936 const ATTRIBUTE_PREFIX = 'attr';
10937 const CLASS_PREFIX = 'class';
10938 const STYLE_PREFIX = 'style';
10939 const TEMPLATE_ATTR_PREFIX = '*';
10940 const ANIMATE_PROP_PREFIX = 'animate-';
10941 /**
10942 * Parses bindings in templates and in the directive host area.
10943 */
10944 class BindingParser {
10945 constructor(_exprParser, _interpolationConfig, _schemaRegistry, pipes, errors) {
10946 this._exprParser = _exprParser;
10947 this._interpolationConfig = _interpolationConfig;
10948 this._schemaRegistry = _schemaRegistry;
10949 this.errors = errors;
10950 this.pipesByName = null;
10951 this._usedPipes = new Map();
10952 // When the `pipes` parameter is `null`, do not check for used pipes
10953 // This is used in IVY when we might not know the available pipes at compile time
10954 if (pipes) {
10955 const pipesByName = new Map();
10956 pipes.forEach(pipe => pipesByName.set(pipe.name, pipe));
10957 this.pipesByName = pipesByName;
10958 }
10959 }
10960 get interpolationConfig() {
10961 return this._interpolationConfig;
10962 }
10963 getUsedPipes() {
10964 return Array.from(this._usedPipes.values());
10965 }
10966 createBoundHostProperties(dirMeta, sourceSpan) {
10967 if (dirMeta.hostProperties) {
10968 const boundProps = [];
10969 Object.keys(dirMeta.hostProperties).forEach(propName => {
10970 const expression = dirMeta.hostProperties[propName];
10971 if (typeof expression === 'string') {
10972 this.parsePropertyBinding(propName, expression, true, sourceSpan, sourceSpan.start.offset, undefined, [],
10973 // Use the `sourceSpan` for `keySpan`. This isn't really accurate, but neither is the
10974 // sourceSpan, as it represents the sourceSpan of the host itself rather than the
10975 // source of the host binding (which doesn't exist in the template). Regardless,
10976 // neither of these values are used in Ivy but are only here to satisfy the function
10977 // signature. This should likely be refactored in the future so that `sourceSpan`
10978 // isn't being used inaccurately.
10979 boundProps, sourceSpan);
10980 }
10981 else {
10982 this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
10983 }
10984 });
10985 return boundProps;
10986 }
10987 return null;
10988 }
10989 createDirectiveHostPropertyAsts(dirMeta, elementSelector, sourceSpan) {
10990 const boundProps = this.createBoundHostProperties(dirMeta, sourceSpan);
10991 return boundProps &&
10992 boundProps.map((prop) => this.createBoundElementProperty(elementSelector, prop));
10993 }
10994 createDirectiveHostEventAsts(dirMeta, sourceSpan) {
10995 if (dirMeta.hostListeners) {
10996 const targetEvents = [];
10997 Object.keys(dirMeta.hostListeners).forEach(propName => {
10998 const expression = dirMeta.hostListeners[propName];
10999 if (typeof expression === 'string') {
11000 // Use the `sourceSpan` for `keySpan` and `handlerSpan`. This isn't really accurate, but
11001 // neither is the `sourceSpan`, as it represents the `sourceSpan` of the host itself
11002 // rather than the source of the host binding (which doesn't exist in the template).
11003 // Regardless, neither of these values are used in Ivy but are only here to satisfy the
11004 // function signature. This should likely be refactored in the future so that `sourceSpan`
11005 // isn't being used inaccurately.
11006 this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents, sourceSpan);
11007 }
11008 else {
11009 this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
11010 }
11011 });
11012 return targetEvents;
11013 }
11014 return null;
11015 }
11016 parseInterpolation(value, sourceSpan) {
11017 const sourceInfo = sourceSpan.start.toString();
11018 const absoluteOffset = sourceSpan.fullStart.offset;
11019 try {
11020 const ast = this._exprParser.parseInterpolation(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11021 if (ast)
11022 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11023 this._checkPipes(ast, sourceSpan);
11024 return ast;
11025 }
11026 catch (e) {
11027 this._reportError(`${e}`, sourceSpan);
11028 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11029 }
11030 }
11031 /**
11032 * Similar to `parseInterpolation`, but treats the provided string as a single expression
11033 * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
11034 * This is used for parsing the switch expression in ICUs.
11035 */
11036 parseInterpolationExpression(expression, sourceSpan) {
11037 const sourceInfo = sourceSpan.start.toString();
11038 const absoluteOffset = sourceSpan.start.offset;
11039 try {
11040 const ast = this._exprParser.parseInterpolationExpression(expression, sourceInfo, absoluteOffset);
11041 if (ast)
11042 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11043 this._checkPipes(ast, sourceSpan);
11044 return ast;
11045 }
11046 catch (e) {
11047 this._reportError(`${e}`, sourceSpan);
11048 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11049 }
11050 }
11051 /**
11052 * Parses the bindings in a microsyntax expression, and converts them to
11053 * `ParsedProperty` or `ParsedVariable`.
11054 *
11055 * @param tplKey template binding name
11056 * @param tplValue template binding value
11057 * @param sourceSpan span of template binding relative to entire the template
11058 * @param absoluteValueOffset start of the tplValue relative to the entire template
11059 * @param targetMatchableAttrs potential attributes to match in the template
11060 * @param targetProps target property bindings in the template
11061 * @param targetVars target variables in the template
11062 */
11063 parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) {
11064 const absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX.length;
11065 const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
11066 for (const binding of bindings) {
11067 // sourceSpan is for the entire HTML attribute. bindingSpan is for a particular
11068 // binding within the microsyntax expression so it's more narrow than sourceSpan.
11069 const bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan);
11070 const key = binding.key.source;
11071 const keySpan = moveParseSourceSpan(sourceSpan, binding.key.span);
11072 if (binding instanceof VariableBinding) {
11073 const value = binding.value ? binding.value.source : '$implicit';
11074 const valueSpan = binding.value ? moveParseSourceSpan(sourceSpan, binding.value.span) : undefined;
11075 targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan));
11076 }
11077 else if (binding.value) {
11078 const srcSpan = isIvyAst ? bindingSpan : sourceSpan;
11079 const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
11080 this._parsePropertyAst(key, binding.value, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11081 }
11082 else {
11083 targetMatchableAttrs.push([key, '' /* value */]);
11084 // Since this is a literal attribute with no RHS, source span should be
11085 // just the key span.
11086 this.parseLiteralAttr(key, null /* value */, keySpan, absoluteValueOffset, undefined /* valueSpan */, targetMatchableAttrs, targetProps, keySpan);
11087 }
11088 }
11089 }
11090 /**
11091 * Parses the bindings in a microsyntax expression, e.g.
11092 * ```
11093 * <tag *tplKey="let value1 = prop; let value2 = localVar">
11094 * ```
11095 *
11096 * @param tplKey template binding name
11097 * @param tplValue template binding value
11098 * @param sourceSpan span of template binding relative to entire the template
11099 * @param absoluteKeyOffset start of the `tplKey`
11100 * @param absoluteValueOffset start of the `tplValue`
11101 */
11102 _parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) {
11103 const sourceInfo = sourceSpan.start.toString();
11104 try {
11105 const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo, absoluteKeyOffset, absoluteValueOffset);
11106 this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
11107 bindingsResult.templateBindings.forEach((binding) => {
11108 if (binding.value instanceof ASTWithSource) {
11109 this._checkPipes(binding.value, sourceSpan);
11110 }
11111 });
11112 bindingsResult.warnings.forEach((warning) => {
11113 this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING);
11114 });
11115 return bindingsResult.templateBindings;
11116 }
11117 catch (e) {
11118 this._reportError(`${e}`, sourceSpan);
11119 return [];
11120 }
11121 }
11122 parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs,
11123 // TODO(atscott): keySpan is only optional here so VE template parser implementation does not
11124 // have to change This should be required when VE is removed.
11125 targetProps, keySpan) {
11126 if (isAnimationLabel(name)) {
11127 name = name.substring(1);
11128 if (keySpan !== undefined) {
11129 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
11130 }
11131 if (value) {
11132 this._reportError(`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
11133 ` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`, sourceSpan, ParseErrorLevel.ERROR);
11134 }
11135 this._parseAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11136 }
11137 else {
11138 targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
11139 }
11140 }
11141 parsePropertyBinding(name, expression, isHost, sourceSpan, absoluteOffset, valueSpan,
11142 // TODO(atscott): keySpan is only optional here so VE template parser implementation does not
11143 // have to change This should be required when VE is removed.
11144 targetMatchableAttrs, targetProps, keySpan) {
11145 if (name.length === 0) {
11146 this._reportError(`Property name is missing in binding`, sourceSpan);
11147 }
11148 let isAnimationProp = false;
11149 if (name.startsWith(ANIMATE_PROP_PREFIX)) {
11150 isAnimationProp = true;
11151 name = name.substring(ANIMATE_PROP_PREFIX.length);
11152 if (keySpan !== undefined) {
11153 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
11154 }
11155 }
11156 else if (isAnimationLabel(name)) {
11157 isAnimationProp = true;
11158 name = name.substring(1);
11159 if (keySpan !== undefined) {
11160 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
11161 }
11162 }
11163 if (isAnimationProp) {
11164 this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11165 }
11166 else {
11167 this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11168 }
11169 }
11170 parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs,
11171 // TODO(atscott): keySpan is only optional here so VE template parser implementation does not
11172 // have to change This should be required when VE is removed.
11173 targetProps, keySpan) {
11174 const expr = this.parseInterpolation(value, valueSpan || sourceSpan);
11175 if (expr) {
11176 this._parsePropertyAst(name, expr, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11177 return true;
11178 }
11179 return false;
11180 }
11181 _parsePropertyAst(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
11182 targetMatchableAttrs.push([name, ast.source]);
11183 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
11184 }
11185 _parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
11186 if (name.length === 0) {
11187 this._reportError('Animation trigger is missing', sourceSpan);
11188 }
11189 // This will occur when a @trigger is not paired with an expression.
11190 // For animations it is valid to not have an expression since */void
11191 // states will be applied by angular when the element is attached/detached
11192 const ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
11193 targetMatchableAttrs.push([name, ast.source]);
11194 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
11195 }
11196 _parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
11197 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
11198 try {
11199 const ast = isHostBinding ?
11200 this._exprParser.parseSimpleBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig) :
11201 this._exprParser.parseBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11202 if (ast)
11203 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11204 this._checkPipes(ast, sourceSpan);
11205 return ast;
11206 }
11207 catch (e) {
11208 this._reportError(`${e}`, sourceSpan);
11209 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11210 }
11211 }
11212 createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) {
11213 if (boundProp.isAnimation) {
11214 return new BoundElementProperty(boundProp.name, 4 /* Animation */, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
11215 }
11216 let unit = null;
11217 let bindingType = undefined;
11218 let boundPropertyName = null;
11219 const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
11220 let securityContexts = undefined;
11221 // Check for special cases (prefix style, attr, class)
11222 if (parts.length > 1) {
11223 if (parts[0] == ATTRIBUTE_PREFIX) {
11224 boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR);
11225 if (!skipValidation) {
11226 this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
11227 }
11228 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
11229 const nsSeparatorIdx = boundPropertyName.indexOf(':');
11230 if (nsSeparatorIdx > -1) {
11231 const ns = boundPropertyName.substring(0, nsSeparatorIdx);
11232 const name = boundPropertyName.substring(nsSeparatorIdx + 1);
11233 boundPropertyName = mergeNsAndName(ns, name);
11234 }
11235 bindingType = 1 /* Attribute */;
11236 }
11237 else if (parts[0] == CLASS_PREFIX) {
11238 boundPropertyName = parts[1];
11239 bindingType = 2 /* Class */;
11240 securityContexts = [SecurityContext.NONE];
11241 }
11242 else if (parts[0] == STYLE_PREFIX) {
11243 unit = parts.length > 2 ? parts[2] : null;
11244 boundPropertyName = parts[1];
11245 bindingType = 3 /* Style */;
11246 securityContexts = [SecurityContext.STYLE];
11247 }
11248 }
11249 // If not a special case, use the full property name
11250 if (boundPropertyName === null) {
11251 const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
11252 boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
11253 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
11254 bindingType = 0 /* Property */;
11255 if (!skipValidation) {
11256 this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
11257 }
11258 }
11259 return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
11260 }
11261 // TODO: keySpan should be required but was made optional to avoid changing VE parser.
11262 parseEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
11263 if (name.length === 0) {
11264 this._reportError(`Event name is missing in binding`, sourceSpan);
11265 }
11266 if (isAnimationLabel(name)) {
11267 name = name.substr(1);
11268 if (keySpan !== undefined) {
11269 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
11270 }
11271 this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
11272 }
11273 else {
11274 this._parseRegularEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
11275 }
11276 }
11277 calcPossibleSecurityContexts(selector, propName, isAttribute) {
11278 const prop = this._schemaRegistry.getMappedPropName(propName);
11279 return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
11280 }
11281 _parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
11282 const matches = splitAtPeriod(name, [name, '']);
11283 const eventName = matches[0];
11284 const phase = matches[1].toLowerCase();
11285 const ast = this._parseAction(expression, handlerSpan);
11286 targetEvents.push(new ParsedEvent(eventName, phase, 1 /* Animation */, ast, sourceSpan, handlerSpan, keySpan));
11287 if (eventName.length === 0) {
11288 this._reportError(`Animation event name is missing in binding`, sourceSpan);
11289 }
11290 if (phase) {
11291 if (phase !== 'start' && phase !== 'done') {
11292 this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan);
11293 }
11294 }
11295 else {
11296 this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan);
11297 }
11298 }
11299 _parseRegularEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
11300 // long format: 'target: eventName'
11301 const [target, eventName] = splitAtColon(name, [null, name]);
11302 const ast = this._parseAction(expression, handlerSpan);
11303 targetMatchableAttrs.push([name, ast.source]);
11304 targetEvents.push(new ParsedEvent(eventName, target, 0 /* Regular */, ast, sourceSpan, handlerSpan, keySpan));
11305 // Don't detect directives for event names for now,
11306 // so don't add the event name to the matchableAttrs
11307 }
11308 _parseAction(value, sourceSpan) {
11309 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString();
11310 const absoluteOffset = (sourceSpan && sourceSpan.start) ? sourceSpan.start.offset : 0;
11311 try {
11312 const ast = this._exprParser.parseAction(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11313 if (ast) {
11314 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11315 }
11316 if (!ast || ast.ast instanceof EmptyExpr) {
11317 this._reportError(`Empty expressions are not allowed`, sourceSpan);
11318 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11319 }
11320 this._checkPipes(ast, sourceSpan);
11321 return ast;
11322 }
11323 catch (e) {
11324 this._reportError(`${e}`, sourceSpan);
11325 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11326 }
11327 }
11328 _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
11329 this.errors.push(new ParseError(sourceSpan, message, level));
11330 }
11331 _reportExpressionParserErrors(errors, sourceSpan) {
11332 for (const error of errors) {
11333 this._reportError(error.message, sourceSpan);
11334 }
11335 }
11336 // Make sure all the used pipes are known in `this.pipesByName`
11337 _checkPipes(ast, sourceSpan) {
11338 if (ast && this.pipesByName) {
11339 const collector = new PipeCollector();
11340 ast.visit(collector);
11341 collector.pipes.forEach((ast, pipeName) => {
11342 const pipeMeta = this.pipesByName.get(pipeName);
11343 if (!pipeMeta) {
11344 this._reportError(`The pipe '${pipeName}' could not be found`, new ParseSourceSpan(sourceSpan.start.moveBy(ast.span.start), sourceSpan.start.moveBy(ast.span.end)));
11345 }
11346 else {
11347 this._usedPipes.set(pipeName, pipeMeta);
11348 }
11349 });
11350 }
11351 }
11352 /**
11353 * @param propName the name of the property / attribute
11354 * @param sourceSpan
11355 * @param isAttr true when binding to an attribute
11356 */
11357 _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) {
11358 const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
11359 this._schemaRegistry.validateProperty(propName);
11360 if (report.error) {
11361 this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
11362 }
11363 }
11364 }
11365 class PipeCollector extends RecursiveAstVisitor {
11366 constructor() {
11367 super(...arguments);
11368 this.pipes = new Map();
11369 }
11370 visitPipe(ast, context) {
11371 this.pipes.set(ast.name, ast);
11372 ast.exp.visit(this);
11373 this.visitAll(ast.args, context);
11374 return null;
11375 }
11376 }
11377 function isAnimationLabel(name) {
11378 return name[0] == '@';
11379 }
11380 function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
11381 const ctxs = [];
11382 CssSelector.parse(selector).forEach((selector) => {
11383 const elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
11384 const notElementNames = new Set(selector.notSelectors.filter(selector => selector.isElementSelector())
11385 .map((selector) => selector.element));
11386 const possibleElementNames = elementNames.filter(elementName => !notElementNames.has(elementName));
11387 ctxs.push(...possibleElementNames.map(elementName => registry.securityContext(elementName, propName, isAttribute)));
11388 });
11389 return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
11390 }
11391 /**
11392 * Compute a new ParseSourceSpan based off an original `sourceSpan` by using
11393 * absolute offsets from the specified `absoluteSpan`.
11394 *
11395 * @param sourceSpan original source span
11396 * @param absoluteSpan absolute source span to move to
11397 */
11398 function moveParseSourceSpan(sourceSpan, absoluteSpan) {
11399 // The difference of two absolute offsets provide the relative offset
11400 const startDiff = absoluteSpan.start - sourceSpan.start.offset;
11401 const endDiff = absoluteSpan.end - sourceSpan.end.offset;
11402 return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details);
11403 }
11404
11405 /**
11406 * @license
11407 * Copyright Google LLC All Rights Reserved.
11408 *
11409 * Use of this source code is governed by an MIT-style license that can be
11410 * found in the LICENSE file at https://angular.io/license
11411 */
11412 const NG_CONTENT_SELECT_ATTR = 'select';
11413 const LINK_ELEMENT = 'link';
11414 const LINK_STYLE_REL_ATTR = 'rel';
11415 const LINK_STYLE_HREF_ATTR = 'href';
11416 const LINK_STYLE_REL_VALUE = 'stylesheet';
11417 const STYLE_ELEMENT = 'style';
11418 const SCRIPT_ELEMENT = 'script';
11419 const NG_NON_BINDABLE_ATTR = 'ngNonBindable';
11420 const NG_PROJECT_AS = 'ngProjectAs';
11421 function preparseElement(ast) {
11422 let selectAttr = null;
11423 let hrefAttr = null;
11424 let relAttr = null;
11425 let nonBindable = false;
11426 let projectAs = '';
11427 ast.attrs.forEach(attr => {
11428 const lcAttrName = attr.name.toLowerCase();
11429 if (lcAttrName == NG_CONTENT_SELECT_ATTR) {
11430 selectAttr = attr.value;
11431 }
11432 else if (lcAttrName == LINK_STYLE_HREF_ATTR) {
11433 hrefAttr = attr.value;
11434 }
11435 else if (lcAttrName == LINK_STYLE_REL_ATTR) {
11436 relAttr = attr.value;
11437 }
11438 else if (attr.name == NG_NON_BINDABLE_ATTR) {
11439 nonBindable = true;
11440 }
11441 else if (attr.name == NG_PROJECT_AS) {
11442 if (attr.value.length > 0) {
11443 projectAs = attr.value;
11444 }
11445 }
11446 });
11447 selectAttr = normalizeNgContentSelect(selectAttr);
11448 const nodeName = ast.name.toLowerCase();
11449 let type = PreparsedElementType.OTHER;
11450 if (isNgContent(nodeName)) {
11451 type = PreparsedElementType.NG_CONTENT;
11452 }
11453 else if (nodeName == STYLE_ELEMENT) {
11454 type = PreparsedElementType.STYLE;
11455 }
11456 else if (nodeName == SCRIPT_ELEMENT) {
11457 type = PreparsedElementType.SCRIPT;
11458 }
11459 else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
11460 type = PreparsedElementType.STYLESHEET;
11461 }
11462 return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs);
11463 }
11464 var PreparsedElementType;
11465 (function (PreparsedElementType) {
11466 PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT";
11467 PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE";
11468 PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET";
11469 PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT";
11470 PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER";
11471 })(PreparsedElementType || (PreparsedElementType = {}));
11472 class PreparsedElement {
11473 constructor(type, selectAttr, hrefAttr, nonBindable, projectAs) {
11474 this.type = type;
11475 this.selectAttr = selectAttr;
11476 this.hrefAttr = hrefAttr;
11477 this.nonBindable = nonBindable;
11478 this.projectAs = projectAs;
11479 }
11480 }
11481 function normalizeNgContentSelect(selectAttr) {
11482 if (selectAttr === null || selectAttr.length === 0) {
11483 return '*';
11484 }
11485 return selectAttr;
11486 }
11487
11488 /**
11489 * @license
11490 * Copyright Google LLC All Rights Reserved.
11491 *
11492 * Use of this source code is governed by an MIT-style license that can be
11493 * found in the LICENSE file at https://angular.io/license
11494 */
11495 const BIND_NAME_REGEXP = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/;
11496 // Group 1 = "bind-"
11497 const KW_BIND_IDX = 1;
11498 // Group 2 = "let-"
11499 const KW_LET_IDX = 2;
11500 // Group 3 = "ref-/#"
11501 const KW_REF_IDX = 3;
11502 // Group 4 = "on-"
11503 const KW_ON_IDX = 4;
11504 // Group 5 = "bindon-"
11505 const KW_BINDON_IDX = 5;
11506 // Group 6 = "@"
11507 const KW_AT_IDX = 6;
11508 // Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
11509 const IDENT_KW_IDX = 7;
11510 // Group 8 = identifier inside [()]
11511 const IDENT_BANANA_BOX_IDX = 8;
11512 // Group 9 = identifier inside []
11513 const IDENT_PROPERTY_IDX = 9;
11514 // Group 10 = identifier inside ()
11515 const IDENT_EVENT_IDX = 10;
11516 const TEMPLATE_ATTR_PREFIX$1 = '*';
11517 const CLASS_ATTR = 'class';
11518 let _TEXT_CSS_SELECTOR;
11519 function TEXT_CSS_SELECTOR() {
11520 if (!_TEXT_CSS_SELECTOR) {
11521 _TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
11522 }
11523 return _TEXT_CSS_SELECTOR;
11524 }
11525 class TemplateParseError extends ParseError {
11526 constructor(message, span, level) {
11527 super(span, message, level);
11528 }
11529 }
11530 class TemplateParseResult {
11531 constructor(templateAst, usedPipes, errors) {
11532 this.templateAst = templateAst;
11533 this.usedPipes = usedPipes;
11534 this.errors = errors;
11535 }
11536 }
11537 class TemplateParser {
11538 constructor(_config, _reflector, _exprParser, _schemaRegistry, _htmlParser, _console, transforms) {
11539 this._config = _config;
11540 this._reflector = _reflector;
11541 this._exprParser = _exprParser;
11542 this._schemaRegistry = _schemaRegistry;
11543 this._htmlParser = _htmlParser;
11544 this._console = _console;
11545 this.transforms = transforms;
11546 }
11547 get expressionParser() {
11548 return this._exprParser;
11549 }
11550 parse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
11551 var _a;
11552 const result = this.tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
11553 const warnings = result.errors.filter(error => error.level === ParseErrorLevel.WARNING);
11554 const errors = result.errors.filter(error => error.level === ParseErrorLevel.ERROR);
11555 if (warnings.length > 0) {
11556 (_a = this._console) === null || _a === void 0 ? void 0 : _a.warn(`Template parse warnings:\n${warnings.join('\n')}`);
11557 }
11558 if (errors.length > 0) {
11559 const errorString = errors.join('\n');
11560 throw syntaxError(`Template parse errors:\n${errorString}`, errors);
11561 }
11562 return { template: result.templateAst, pipes: result.usedPipes };
11563 }
11564 tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
11565 let htmlParseResult = typeof template === 'string' ?
11566 this._htmlParser.parse(template, templateUrl, {
11567 tokenizeExpansionForms: true,
11568 interpolationConfig: this.getInterpolationConfig(component)
11569 }) :
11570 template;
11571 if (!preserveWhitespaces) {
11572 htmlParseResult = removeWhitespaces(htmlParseResult);
11573 }
11574 return this.tryParseHtml(this.expandHtml(htmlParseResult), component, directives, pipes, schemas);
11575 }
11576 tryParseHtml(htmlAstWithErrors, component, directives, pipes, schemas) {
11577 let result;
11578 const errors = htmlAstWithErrors.errors;
11579 const usedPipes = [];
11580 if (htmlAstWithErrors.rootNodes.length > 0) {
11581 const uniqDirectives = removeSummaryDuplicates(directives);
11582 const uniqPipes = removeSummaryDuplicates(pipes);
11583 const providerViewContext = new ProviderViewContext(this._reflector, component);
11584 let interpolationConfig = undefined;
11585 if (component.template && component.template.interpolation) {
11586 interpolationConfig = {
11587 start: component.template.interpolation[0],
11588 end: component.template.interpolation[1]
11589 };
11590 }
11591 const bindingParser = new BindingParser(this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors);
11592 const parseVisitor = new TemplateParseVisitor(this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas, errors);
11593 result = visitAll$1(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
11594 errors.push(...providerViewContext.errors);
11595 usedPipes.push(...bindingParser.getUsedPipes());
11596 }
11597 else {
11598 result = [];
11599 }
11600 this._assertNoReferenceDuplicationOnTemplate(result, errors);
11601 if (errors.length > 0) {
11602 return new TemplateParseResult(result, usedPipes, errors);
11603 }
11604 if (this.transforms) {
11605 this.transforms.forEach((transform) => {
11606 result = templateVisitAll(transform, result);
11607 });
11608 }
11609 return new TemplateParseResult(result, usedPipes, errors);
11610 }
11611 expandHtml(htmlAstWithErrors, forced = false) {
11612 const errors = htmlAstWithErrors.errors;
11613 if (errors.length == 0 || forced) {
11614 // Transform ICU messages to angular directives
11615 const expandedHtmlAst = expandNodes(htmlAstWithErrors.rootNodes);
11616 errors.push(...expandedHtmlAst.errors);
11617 htmlAstWithErrors = new ParseTreeResult(expandedHtmlAst.nodes, errors);
11618 }
11619 return htmlAstWithErrors;
11620 }
11621 getInterpolationConfig(component) {
11622 if (component.template) {
11623 return InterpolationConfig.fromArray(component.template.interpolation);
11624 }
11625 return undefined;
11626 }
11627 /** @internal */
11628 _assertNoReferenceDuplicationOnTemplate(result, errors) {
11629 const existingReferences = [];
11630 result.filter(element => !!element.references)
11631 .forEach(element => element.references.forEach((reference) => {
11632 const name = reference.name;
11633 if (existingReferences.indexOf(name) < 0) {
11634 existingReferences.push(name);
11635 }
11636 else {
11637 const error = new TemplateParseError(`Reference "#${name}" is defined several times`, reference.sourceSpan, ParseErrorLevel.ERROR);
11638 errors.push(error);
11639 }
11640 }));
11641 }
11642 }
11643 class TemplateParseVisitor {
11644 constructor(reflector, config, providerViewContext, directives, _bindingParser, _schemaRegistry, _schemas, _targetErrors) {
11645 this.reflector = reflector;
11646 this.config = config;
11647 this.providerViewContext = providerViewContext;
11648 this._bindingParser = _bindingParser;
11649 this._schemaRegistry = _schemaRegistry;
11650 this._schemas = _schemas;
11651 this._targetErrors = _targetErrors;
11652 this.selectorMatcher = new SelectorMatcher();
11653 this.directivesIndex = new Map();
11654 this.ngContentCount = 0;
11655 // Note: queries start with id 1 so we can use the number in a Bloom filter!
11656 this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
11657 directives.forEach((directive, index) => {
11658 const selector = CssSelector.parse(directive.selector);
11659 this.selectorMatcher.addSelectables(selector, directive);
11660 this.directivesIndex.set(directive, index);
11661 });
11662 }
11663 visitExpansion(expansion, context) {
11664 return null;
11665 }
11666 visitExpansionCase(expansionCase, context) {
11667 return null;
11668 }
11669 visitText(text, parent) {
11670 const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
11671 const valueNoNgsp = replaceNgsp(text.value);
11672 const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan);
11673 return expr ? new BoundTextAst(expr, ngContentIndex, text.sourceSpan) :
11674 new TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan);
11675 }
11676 visitAttribute(attribute, context) {
11677 return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
11678 }
11679 visitComment(comment, context) {
11680 return null;
11681 }
11682 visitElement(element, parent) {
11683 const queryStartIndex = this.contentQueryStartId;
11684 const elName = element.name;
11685 const preparsedElement = preparseElement(element);
11686 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
11687 preparsedElement.type === PreparsedElementType.STYLE) {
11688 // Skipping <script> for security reasons
11689 // Skipping <style> as we already processed them
11690 // in the StyleCompiler
11691 return null;
11692 }
11693 if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
11694 isStyleUrlResolvable(preparsedElement.hrefAttr)) {
11695 // Skipping stylesheets with either relative urls or package scheme as we already processed
11696 // them in the StyleCompiler
11697 return null;
11698 }
11699 const matchableAttrs = [];
11700 const elementOrDirectiveProps = [];
11701 const elementOrDirectiveRefs = [];
11702 const elementVars = [];
11703 const events = [];
11704 const templateElementOrDirectiveProps = [];
11705 const templateMatchableAttrs = [];
11706 const templateElementVars = [];
11707 let hasInlineTemplates = false;
11708 const attrs = [];
11709 const isTemplateElement = isNgTemplate(element.name);
11710 element.attrs.forEach(attr => {
11711 const parsedVariables = [];
11712 const hasBinding = this._parseAttr(isTemplateElement, attr, matchableAttrs, elementOrDirectiveProps, events, elementOrDirectiveRefs, elementVars);
11713 elementVars.push(...parsedVariables.map(v => VariableAst.fromParsedVariable(v)));
11714 let templateValue;
11715 let templateKey;
11716 const normalizedName = this._normalizeAttributeName(attr.name);
11717 if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX$1)) {
11718 templateValue = attr.value;
11719 templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX$1.length);
11720 }
11721 const hasTemplateBinding = templateValue != null;
11722 if (hasTemplateBinding) {
11723 if (hasInlineTemplates) {
11724 this._reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attr.sourceSpan);
11725 }
11726 hasInlineTemplates = true;
11727 const parsedVariables = [];
11728 const absoluteOffset = (attr.valueSpan || attr.sourceSpan).start.offset;
11729 this._bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attr.sourceSpan, absoluteOffset, templateMatchableAttrs, templateElementOrDirectiveProps, parsedVariables, false /* isIvyAst */);
11730 templateElementVars.push(...parsedVariables.map(v => VariableAst.fromParsedVariable(v)));
11731 }
11732 if (!hasBinding && !hasTemplateBinding) {
11733 // don't include the bindings as attributes as well in the AST
11734 attrs.push(this.visitAttribute(attr, null));
11735 matchableAttrs.push([attr.name, attr.value]);
11736 }
11737 });
11738 const elementCssSelector = createElementCssSelector(elName, matchableAttrs);
11739 const { directives: directiveMetas, matchElement } = this._parseDirectives(this.selectorMatcher, elementCssSelector);
11740 const references = [];
11741 const boundDirectivePropNames = new Set();
11742 const directiveAsts = this._createDirectiveAsts(isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps, elementOrDirectiveRefs, element.sourceSpan, references, boundDirectivePropNames);
11743 const elementProps = this._createElementPropertyAsts(element.name, elementOrDirectiveProps, boundDirectivePropNames);
11744 const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
11745 const providerContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot, directiveAsts, attrs, references, isTemplateElement, queryStartIndex, element.sourceSpan);
11746 const children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, ElementContext.create(isTemplateElement, directiveAsts, isTemplateElement ? parent.providerContext : providerContext));
11747 providerContext.afterElement();
11748 // Override the actual selector when the `ngProjectAs` attribute is provided
11749 const projectionSelector = preparsedElement.projectAs != '' ?
11750 CssSelector.parse(preparsedElement.projectAs)[0] :
11751 elementCssSelector;
11752 const ngContentIndex = parent.findNgContentIndex(projectionSelector);
11753 let parsedElement;
11754 if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
11755 // `<ng-content>` element
11756 if (element.children && !element.children.every(_isEmptyTextNode)) {
11757 this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
11758 }
11759 parsedElement = new NgContentAst(this.ngContentCount++, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
11760 }
11761 else if (isTemplateElement) {
11762 // `<ng-template>` element
11763 this._assertAllEventsPublishedByDirectives(directiveAsts, events);
11764 this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps, element.sourceSpan);
11765 parsedElement = new EmbeddedTemplateAst(attrs, events, references, elementVars, providerContext.transformedDirectiveAsts, providerContext.transformProviders, providerContext.transformedHasViewContainer, providerContext.queryMatches, children, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
11766 }
11767 else {
11768 // element other than `<ng-content>` and `<ng-template>`
11769 this._assertElementExists(matchElement, element);
11770 this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
11771 const ngContentIndex = hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
11772 parsedElement = new ElementAst(elName, attrs, elementProps, events, references, providerContext.transformedDirectiveAsts, providerContext.transformProviders, providerContext.transformedHasViewContainer, providerContext.queryMatches, children, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan, element.endSourceSpan || null);
11773 }
11774 if (hasInlineTemplates) {
11775 // The element as a *-attribute
11776 const templateQueryStartIndex = this.contentQueryStartId;
11777 const templateSelector = createElementCssSelector('ng-template', templateMatchableAttrs);
11778 const { directives } = this._parseDirectives(this.selectorMatcher, templateSelector);
11779 const templateBoundDirectivePropNames = new Set();
11780 const templateDirectiveAsts = this._createDirectiveAsts(true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan, [], templateBoundDirectivePropNames);
11781 const templateElementProps = this._createElementPropertyAsts(elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames);
11782 this._assertNoComponentsNorElementBindingsOnTemplate(templateDirectiveAsts, templateElementProps, element.sourceSpan);
11783 const templateProviderContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, parent.isTemplateElement, templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan);
11784 templateProviderContext.afterElement();
11785 parsedElement = new EmbeddedTemplateAst([], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts, templateProviderContext.transformProviders, templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches, [parsedElement], ngContentIndex, element.sourceSpan);
11786 }
11787 return parsedElement;
11788 }
11789 _parseAttr(isTemplateElement, attr, targetMatchableAttrs, targetProps, targetEvents, targetRefs, targetVars) {
11790 const name = this._normalizeAttributeName(attr.name);
11791 const value = attr.value;
11792 const srcSpan = attr.sourceSpan;
11793 const absoluteOffset = attr.valueSpan ? attr.valueSpan.start.offset : srcSpan.start.offset;
11794 const boundEvents = [];
11795 const bindParts = name.match(BIND_NAME_REGEXP);
11796 let hasBinding = false;
11797 if (bindParts !== null) {
11798 hasBinding = true;
11799 if (bindParts[KW_BIND_IDX] != null) {
11800 this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11801 }
11802 else if (bindParts[KW_LET_IDX]) {
11803 if (isTemplateElement) {
11804 const identifier = bindParts[IDENT_KW_IDX];
11805 this._parseVariable(identifier, value, srcSpan, targetVars);
11806 }
11807 else {
11808 this._reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
11809 }
11810 }
11811 else if (bindParts[KW_REF_IDX]) {
11812 const identifier = bindParts[IDENT_KW_IDX];
11813 this._parseReference(identifier, value, srcSpan, targetRefs);
11814 }
11815 else if (bindParts[KW_ON_IDX]) {
11816 this._bindingParser.parseEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11817 }
11818 else if (bindParts[KW_BINDON_IDX]) {
11819 this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11820 this._parseAssignmentEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11821 }
11822 else if (bindParts[KW_AT_IDX]) {
11823 this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11824 }
11825 else if (bindParts[IDENT_BANANA_BOX_IDX]) {
11826 this._bindingParser.parsePropertyBinding(bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11827 this._parseAssignmentEvent(bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11828 }
11829 else if (bindParts[IDENT_PROPERTY_IDX]) {
11830 this._bindingParser.parsePropertyBinding(bindParts[IDENT_PROPERTY_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11831 }
11832 else if (bindParts[IDENT_EVENT_IDX]) {
11833 this._bindingParser.parseEvent(bindParts[IDENT_EVENT_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11834 }
11835 }
11836 else {
11837 hasBinding = this._bindingParser.parsePropertyInterpolation(name, value, srcSpan, attr.valueSpan, targetMatchableAttrs, targetProps);
11838 }
11839 if (!hasBinding) {
11840 this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11841 }
11842 targetEvents.push(...boundEvents.map(e => BoundEventAst.fromParsedEvent(e)));
11843 return hasBinding;
11844 }
11845 _normalizeAttributeName(attrName) {
11846 return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
11847 }
11848 _parseVariable(identifier, value, sourceSpan, targetVars) {
11849 if (identifier.indexOf('-') > -1) {
11850 this._reportError(`"-" is not allowed in variable names`, sourceSpan);
11851 }
11852 else if (identifier.length === 0) {
11853 this._reportError(`Variable does not have a name`, sourceSpan);
11854 }
11855 targetVars.push(new VariableAst(identifier, value, sourceSpan));
11856 }
11857 _parseReference(identifier, value, sourceSpan, targetRefs) {
11858 if (identifier.indexOf('-') > -1) {
11859 this._reportError(`"-" is not allowed in reference names`, sourceSpan);
11860 }
11861 else if (identifier.length === 0) {
11862 this._reportError(`Reference does not have a name`, sourceSpan);
11863 }
11864 targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
11865 }
11866 _parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, targetEvents) {
11867 this._bindingParser.parseEvent(`${name}Change`, `${expression}=$event`, sourceSpan, valueSpan, targetMatchableAttrs, targetEvents);
11868 }
11869 _parseDirectives(selectorMatcher, elementCssSelector) {
11870 // Need to sort the directives so that we get consistent results throughout,
11871 // as selectorMatcher uses Maps inside.
11872 // Also deduplicate directives as they might match more than one time!
11873 const directives = newArray(this.directivesIndex.size);
11874 // Whether any directive selector matches on the element name
11875 let matchElement = false;
11876 selectorMatcher.match(elementCssSelector, (selector, directive) => {
11877 directives[this.directivesIndex.get(directive)] = directive;
11878 matchElement = matchElement || selector.hasElementSelector();
11879 });
11880 return {
11881 directives: directives.filter(dir => !!dir),
11882 matchElement,
11883 };
11884 }
11885 _createDirectiveAsts(isTemplateElement, elementName, directives, props, elementOrDirectiveRefs, elementSourceSpan, targetReferences, targetBoundDirectivePropNames) {
11886 const matchedReferences = new Set();
11887 let component = null;
11888 const directiveAsts = directives.map((directive) => {
11889 const sourceSpan = new ParseSourceSpan(elementSourceSpan.start, elementSourceSpan.end, elementSourceSpan.fullStart, `Directive ${identifierName(directive.type)}`);
11890 if (directive.isComponent) {
11891 component = directive;
11892 }
11893 const directiveProperties = [];
11894 const boundProperties = this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan);
11895 let hostProperties = boundProperties.map(prop => BoundElementPropertyAst.fromBoundProperty(prop));
11896 // Note: We need to check the host properties here as well,
11897 // as we don't know the element name in the DirectiveWrapperCompiler yet.
11898 hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);
11899 const parsedEvents = this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan);
11900 this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties, targetBoundDirectivePropNames);
11901 elementOrDirectiveRefs.forEach((elOrDirRef) => {
11902 if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
11903 (elOrDirRef.isReferenceToDirective(directive))) {
11904 targetReferences.push(new ReferenceAst(elOrDirRef.name, createTokenForReference(directive.type.reference), elOrDirRef.value, elOrDirRef.sourceSpan));
11905 matchedReferences.add(elOrDirRef.name);
11906 }
11907 });
11908 const hostEvents = parsedEvents.map(e => BoundEventAst.fromParsedEvent(e));
11909 const contentQueryStartId = this.contentQueryStartId;
11910 this.contentQueryStartId += directive.queries.length;
11911 return new DirectiveAst(directive, directiveProperties, hostProperties, hostEvents, contentQueryStartId, sourceSpan);
11912 });
11913 elementOrDirectiveRefs.forEach((elOrDirRef) => {
11914 if (elOrDirRef.value.length > 0) {
11915 if (!matchedReferences.has(elOrDirRef.name)) {
11916 this._reportError(`There is no directive with "exportAs" set to "${elOrDirRef.value}"`, elOrDirRef.sourceSpan);
11917 }
11918 }
11919 else if (!component) {
11920 let refToken = null;
11921 if (isTemplateElement) {
11922 refToken = createTokenForExternalReference(this.reflector, Identifiers.TemplateRef);
11923 }
11924 targetReferences.push(new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.value, elOrDirRef.sourceSpan));
11925 }
11926 });
11927 return directiveAsts;
11928 }
11929 _createDirectivePropertyAsts(directiveProperties, boundProps, targetBoundDirectiveProps, targetBoundDirectivePropNames) {
11930 if (directiveProperties) {
11931 const boundPropsByName = new Map();
11932 boundProps.forEach(boundProp => {
11933 const prevValue = boundPropsByName.get(boundProp.name);
11934 if (!prevValue || prevValue.isLiteral) {
11935 // give [a]="b" a higher precedence than a="b" on the same element
11936 boundPropsByName.set(boundProp.name, boundProp);
11937 }
11938 });
11939 Object.keys(directiveProperties).forEach(dirProp => {
11940 const elProp = directiveProperties[dirProp];
11941 const boundProp = boundPropsByName.get(elProp);
11942 // Bindings are optional, so this binding only needs to be set up if an expression is given.
11943 if (boundProp) {
11944 targetBoundDirectivePropNames.add(boundProp.name);
11945 if (!isEmptyExpression(boundProp.expression)) {
11946 targetBoundDirectiveProps.push(new BoundDirectivePropertyAst(dirProp, boundProp.name, boundProp.expression, boundProp.sourceSpan));
11947 }
11948 }
11949 });
11950 }
11951 }
11952 _createElementPropertyAsts(elementName, props, boundDirectivePropNames) {
11953 const boundElementProps = [];
11954 props.forEach((prop) => {
11955 if (!prop.isLiteral && !boundDirectivePropNames.has(prop.name)) {
11956 const boundProp = this._bindingParser.createBoundElementProperty(elementName, prop);
11957 boundElementProps.push(BoundElementPropertyAst.fromBoundProperty(boundProp));
11958 }
11959 });
11960 return this._checkPropertiesInSchema(elementName, boundElementProps);
11961 }
11962 _findComponentDirectives(directives) {
11963 return directives.filter(directive => directive.directive.isComponent);
11964 }
11965 _findComponentDirectiveNames(directives) {
11966 return this._findComponentDirectives(directives)
11967 .map(directive => identifierName(directive.directive.type));
11968 }
11969 _assertOnlyOneComponent(directives, sourceSpan) {
11970 const componentTypeNames = this._findComponentDirectiveNames(directives);
11971 if (componentTypeNames.length > 1) {
11972 this._reportError(`More than one component matched on this element.\n` +
11973 `Make sure that only one component's selector can match a given element.\n` +
11974 `Conflicting components: ${componentTypeNames.join(',')}`, sourceSpan);
11975 }
11976 }
11977 /**
11978 * Make sure that non-angular tags conform to the schemas.
11979 *
11980 * Note: An element is considered an angular tag when at least one directive selector matches the
11981 * tag name.
11982 *
11983 * @param matchElement Whether any directive has matched on the tag name
11984 * @param element the html element
11985 */
11986 _assertElementExists(matchElement, element) {
11987 const elName = element.name.replace(/^:xhtml:/, '');
11988 if (!matchElement && !this._schemaRegistry.hasElement(elName, this._schemas)) {
11989 let errorMsg = `'${elName}' is not a known element:\n`;
11990 errorMsg += `1. If '${elName}' is an Angular component, then verify that it is part of this module.\n`;
11991 if (elName.indexOf('-') > -1) {
11992 errorMsg += `2. If '${elName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`;
11993 }
11994 else {
11995 errorMsg +=
11996 `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
11997 }
11998 this._reportError(errorMsg, element.sourceSpan);
11999 }
12000 }
12001 _assertNoComponentsNorElementBindingsOnTemplate(directives, elementProps, sourceSpan) {
12002 const componentTypeNames = this._findComponentDirectiveNames(directives);
12003 if (componentTypeNames.length > 0) {
12004 this._reportError(`Components on an embedded template: ${componentTypeNames.join(',')}`, sourceSpan);
12005 }
12006 elementProps.forEach(prop => {
12007 this._reportError(`Property binding ${prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, sourceSpan);
12008 });
12009 }
12010 _assertAllEventsPublishedByDirectives(directives, events) {
12011 const allDirectiveEvents = new Set();
12012 directives.forEach(directive => {
12013 Object.keys(directive.directive.outputs).forEach(k => {
12014 const eventName = directive.directive.outputs[k];
12015 allDirectiveEvents.add(eventName);
12016 });
12017 });
12018 events.forEach(event => {
12019 if (event.target != null || !allDirectiveEvents.has(event.name)) {
12020 this._reportError(`Event binding ${event
12021 .fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, event.sourceSpan);
12022 }
12023 });
12024 }
12025 _checkPropertiesInSchema(elementName, boundProps) {
12026 // Note: We can't filter out empty expressions before this method,
12027 // as we still want to validate them!
12028 return boundProps.filter((boundProp) => {
12029 if (boundProp.type === 0 /* Property */ &&
12030 !this._schemaRegistry.hasProperty(elementName, boundProp.name, this._schemas)) {
12031 let errorMsg = `Can't bind to '${boundProp.name}' since it isn't a known property of '${elementName}'.`;
12032 if (elementName.startsWith('ng-')) {
12033 errorMsg +=
12034 `\n1. If '${boundProp
12035 .name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` +
12036 `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
12037 }
12038 else if (elementName.indexOf('-') > -1) {
12039 errorMsg +=
12040 `\n1. If '${elementName}' is an Angular component and it has '${boundProp.name}' input, then verify that it is part of this module.` +
12041 `\n2. If '${elementName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` +
12042 `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
12043 }
12044 this._reportError(errorMsg, boundProp.sourceSpan);
12045 }
12046 return !isEmptyExpression(boundProp.value);
12047 });
12048 }
12049 _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
12050 this._targetErrors.push(new ParseError(sourceSpan, message, level));
12051 }
12052 }
12053 class NonBindableVisitor {
12054 visitElement(ast, parent) {
12055 const preparsedElement = preparseElement(ast);
12056 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
12057 preparsedElement.type === PreparsedElementType.STYLE ||
12058 preparsedElement.type === PreparsedElementType.STYLESHEET) {
12059 // Skipping <script> for security reasons
12060 // Skipping <style> and stylesheets as we already processed them
12061 // in the StyleCompiler
12062 return null;
12063 }
12064 const attrNameAndValues = ast.attrs.map((attr) => [attr.name, attr.value]);
12065 const selector = createElementCssSelector(ast.name, attrNameAndValues);
12066 const ngContentIndex = parent.findNgContentIndex(selector);
12067 const children = visitAll$1(this, ast.children, EMPTY_ELEMENT_CONTEXT);
12068 return new ElementAst(ast.name, visitAll$1(this, ast.attrs), [], [], [], [], [], false, [], children, ngContentIndex, ast.sourceSpan, ast.endSourceSpan);
12069 }
12070 visitComment(comment, context) {
12071 return null;
12072 }
12073 visitAttribute(attribute, context) {
12074 return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
12075 }
12076 visitText(text, parent) {
12077 const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
12078 return new TextAst(text.value, ngContentIndex, text.sourceSpan);
12079 }
12080 visitExpansion(expansion, context) {
12081 return expansion;
12082 }
12083 visitExpansionCase(expansionCase, context) {
12084 return expansionCase;
12085 }
12086 }
12087 /**
12088 * A reference to an element or directive in a template. E.g., the reference in this template:
12089 *
12090 * <div #myMenu="coolMenu">
12091 *
12092 * would be {name: 'myMenu', value: 'coolMenu', sourceSpan: ...}
12093 */
12094 class ElementOrDirectiveRef {
12095 constructor(name, value, sourceSpan) {
12096 this.name = name;
12097 this.value = value;
12098 this.sourceSpan = sourceSpan;
12099 }
12100 /** Gets whether this is a reference to the given directive. */
12101 isReferenceToDirective(directive) {
12102 return splitExportAs(directive.exportAs).indexOf(this.value) !== -1;
12103 }
12104 }
12105 /** Splits a raw, potentially comma-delimited `exportAs` value into an array of names. */
12106 function splitExportAs(exportAs) {
12107 return exportAs ? exportAs.split(',').map(e => e.trim()) : [];
12108 }
12109 function splitClasses(classAttrValue) {
12110 return classAttrValue.trim().split(/\s+/g);
12111 }
12112 class ElementContext {
12113 constructor(isTemplateElement, _ngContentIndexMatcher, _wildcardNgContentIndex, providerContext) {
12114 this.isTemplateElement = isTemplateElement;
12115 this._ngContentIndexMatcher = _ngContentIndexMatcher;
12116 this._wildcardNgContentIndex = _wildcardNgContentIndex;
12117 this.providerContext = providerContext;
12118 }
12119 static create(isTemplateElement, directives, providerContext) {
12120 const matcher = new SelectorMatcher();
12121 let wildcardNgContentIndex = null;
12122 const component = directives.find(directive => directive.directive.isComponent);
12123 if (component) {
12124 const ngContentSelectors = component.directive.template.ngContentSelectors;
12125 for (let i = 0; i < ngContentSelectors.length; i++) {
12126 const selector = ngContentSelectors[i];
12127 if (selector === '*') {
12128 wildcardNgContentIndex = i;
12129 }
12130 else {
12131 matcher.addSelectables(CssSelector.parse(ngContentSelectors[i]), i);
12132 }
12133 }
12134 }
12135 return new ElementContext(isTemplateElement, matcher, wildcardNgContentIndex, providerContext);
12136 }
12137 findNgContentIndex(selector) {
12138 const ngContentIndices = [];
12139 this._ngContentIndexMatcher.match(selector, (selector, ngContentIndex) => {
12140 ngContentIndices.push(ngContentIndex);
12141 });
12142 ngContentIndices.sort();
12143 if (this._wildcardNgContentIndex != null) {
12144 ngContentIndices.push(this._wildcardNgContentIndex);
12145 }
12146 return ngContentIndices.length > 0 ? ngContentIndices[0] : null;
12147 }
12148 }
12149 function createElementCssSelector(elementName, attributes) {
12150 const cssSelector = new CssSelector();
12151 const elNameNoNs = splitNsName(elementName)[1];
12152 cssSelector.setElement(elNameNoNs);
12153 for (let i = 0; i < attributes.length; i++) {
12154 const attrName = attributes[i][0];
12155 const attrNameNoNs = splitNsName(attrName)[1];
12156 const attrValue = attributes[i][1];
12157 cssSelector.addAttribute(attrNameNoNs, attrValue);
12158 if (attrName.toLowerCase() == CLASS_ATTR) {
12159 const classes = splitClasses(attrValue);
12160 classes.forEach(className => cssSelector.addClassName(className));
12161 }
12162 }
12163 return cssSelector;
12164 }
12165 const EMPTY_ELEMENT_CONTEXT = new ElementContext(true, new SelectorMatcher(), null, null);
12166 const NON_BINDABLE_VISITOR = new NonBindableVisitor();
12167 function _isEmptyTextNode(node) {
12168 return node instanceof Text$2 && node.value.trim().length == 0;
12169 }
12170 function removeSummaryDuplicates(items) {
12171 const map = new Map();
12172 items.forEach((item) => {
12173 if (!map.get(item.type.reference)) {
12174 map.set(item.type.reference, item);
12175 }
12176 });
12177 return Array.from(map.values());
12178 }
12179 function isEmptyExpression(ast) {
12180 if (ast instanceof ASTWithSource) {
12181 ast = ast.ast;
12182 }
12183 return ast instanceof EmptyExpr;
12184 }
12185
12186 /**
12187 * @license
12188 * Copyright Google LLC All Rights Reserved.
12189 *
12190 * Use of this source code is governed by an MIT-style license that can be
12191 * found in the LICENSE file at https://angular.io/license
12192 */
12193 /**
12194 * Parses string representation of a style and converts it into object literal.
12195 *
12196 * @param value string representation of style as used in the `style` attribute in HTML.
12197 * Example: `color: red; height: auto`.
12198 * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
12199 * 'auto']`
12200 */
12201 function parse(value) {
12202 // we use a string array here instead of a string map
12203 // because a string-map is not guaranteed to retain the
12204 // order of the entries whereas a string array can be
12205 // constructed in a [key, value, key, value] format.
12206 const styles = [];
12207 let i = 0;
12208 let parenDepth = 0;
12209 let quote = 0 /* QuoteNone */;
12210 let valueStart = 0;
12211 let propStart = 0;
12212 let currentProp = null;
12213 let valueHasQuotes = false;
12214 while (i < value.length) {
12215 const token = value.charCodeAt(i++);
12216 switch (token) {
12217 case 40 /* OpenParen */:
12218 parenDepth++;
12219 break;
12220 case 41 /* CloseParen */:
12221 parenDepth--;
12222 break;
12223 case 39 /* QuoteSingle */:
12224 // valueStart needs to be there since prop values don't
12225 // have quotes in CSS
12226 valueHasQuotes = valueHasQuotes || valueStart > 0;
12227 if (quote === 0 /* QuoteNone */) {
12228 quote = 39 /* QuoteSingle */;
12229 }
12230 else if (quote === 39 /* QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
12231 quote = 0 /* QuoteNone */;
12232 }
12233 break;
12234 case 34 /* QuoteDouble */:
12235 // same logic as above
12236 valueHasQuotes = valueHasQuotes || valueStart > 0;
12237 if (quote === 0 /* QuoteNone */) {
12238 quote = 34 /* QuoteDouble */;
12239 }
12240 else if (quote === 34 /* QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
12241 quote = 0 /* QuoteNone */;
12242 }
12243 break;
12244 case 58 /* Colon */:
12245 if (!currentProp && parenDepth === 0 && quote === 0 /* QuoteNone */) {
12246 currentProp = hyphenate(value.substring(propStart, i - 1).trim());
12247 valueStart = i;
12248 }
12249 break;
12250 case 59 /* Semicolon */:
12251 if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* QuoteNone */) {
12252 const styleVal = value.substring(valueStart, i - 1).trim();
12253 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
12254 propStart = i;
12255 valueStart = 0;
12256 currentProp = null;
12257 valueHasQuotes = false;
12258 }
12259 break;
12260 }
12261 }
12262 if (currentProp && valueStart) {
12263 const styleVal = value.substr(valueStart).trim();
12264 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
12265 }
12266 return styles;
12267 }
12268 function stripUnnecessaryQuotes(value) {
12269 const qS = value.charCodeAt(0);
12270 const qE = value.charCodeAt(value.length - 1);
12271 if (qS == qE && (qS == 39 /* QuoteSingle */ || qS == 34 /* QuoteDouble */)) {
12272 const tempValue = value.substring(1, value.length - 1);
12273 // special case to avoid using a multi-quoted string that was just chomped
12274 // (e.g. `font-family: "Verdana", "sans-serif"`)
12275 if (tempValue.indexOf('\'') == -1 && tempValue.indexOf('"') == -1) {
12276 value = tempValue;
12277 }
12278 }
12279 return value;
12280 }
12281 function hyphenate(value) {
12282 return value
12283 .replace(/[a-z][A-Z]/g, v => {
12284 return v.charAt(0) + '-' + v.charAt(1);
12285 })
12286 .toLowerCase();
12287 }
12288
12289 const IMPORTANT_FLAG = '!important';
12290 /**
12291 * Minimum amount of binding slots required in the runtime for style/class bindings.
12292 *
12293 * Styling in Angular uses up two slots in the runtime LView/TData data structures to
12294 * record binding data, property information and metadata.
12295 *
12296 * When a binding is registered it will place the following information in the `LView`:
12297 *
12298 * slot 1) binding value
12299 * slot 2) cached value (all other values collected before it in string form)
12300 *
12301 * When a binding is registered it will place the following information in the `TData`:
12302 *
12303 * slot 1) prop name
12304 * slot 2) binding index that points to the previous style/class binding (and some extra config
12305 * values)
12306 *
12307 * Let's imagine we have a binding that looks like so:
12308 *
12309 * ```
12310 * <div [style.width]="x" [style.height]="y">
12311 * ```
12312 *
12313 * Our `LView` and `TData` data-structures look like so:
12314 *
12315 * ```typescript
12316 * LView = [
12317 * // ...
12318 * x, // value of x
12319 * "width: x",
12320 *
12321 * y, // value of y
12322 * "width: x; height: y",
12323 * // ...
12324 * ];
12325 *
12326 * TData = [
12327 * // ...
12328 * "width", // binding slot 20
12329 * 0,
12330 *
12331 * "height",
12332 * 20,
12333 * // ...
12334 * ];
12335 * ```
12336 *
12337 * */
12338 const MIN_STYLING_BINDING_SLOTS_REQUIRED = 2;
12339 /**
12340 * Produces creation/update instructions for all styling bindings (class and style)
12341 *
12342 * It also produces the creation instruction to register all initial styling values
12343 * (which are all the static class="..." and style="..." attribute values that exist
12344 * on an element within a template).
12345 *
12346 * The builder class below handles producing instructions for the following cases:
12347 *
12348 * - Static style/class attributes (style="..." and class="...")
12349 * - Dynamic style/class map bindings ([style]="map" and [class]="map|string")
12350 * - Dynamic style/class property bindings ([style.prop]="exp" and [class.name]="exp")
12351 *
12352 * Due to the complex relationship of all of these cases, the instructions generated
12353 * for these attributes/properties/bindings must be done so in the correct order. The
12354 * order which these must be generated is as follows:
12355 *
12356 * if (createMode) {
12357 * styling(...)
12358 * }
12359 * if (updateMode) {
12360 * styleMap(...)
12361 * classMap(...)
12362 * styleProp(...)
12363 * classProp(...)
12364 * }
12365 *
12366 * The creation/update methods within the builder class produce these instructions.
12367 */
12368 class StylingBuilder {
12369 constructor(_directiveExpr) {
12370 this._directiveExpr = _directiveExpr;
12371 /** Whether or not there are any static styling values present */
12372 this._hasInitialValues = false;
12373 /**
12374 * Whether or not there are any styling bindings present
12375 * (i.e. `[style]`, `[class]`, `[style.prop]` or `[class.name]`)
12376 */
12377 this.hasBindings = false;
12378 this.hasBindingsWithPipes = false;
12379 /** the input for [class] (if it exists) */
12380 this._classMapInput = null;
12381 /** the input for [style] (if it exists) */
12382 this._styleMapInput = null;
12383 /** an array of each [style.prop] input */
12384 this._singleStyleInputs = null;
12385 /** an array of each [class.name] input */
12386 this._singleClassInputs = null;
12387 this._lastStylingInput = null;
12388 this._firstStylingInput = null;
12389 // maps are used instead of hash maps because a Map will
12390 // retain the ordering of the keys
12391 /**
12392 * Represents the location of each style binding in the template
12393 * (e.g. `<div [style.width]="w" [style.height]="h">` implies
12394 * that `width=0` and `height=1`)
12395 */
12396 this._stylesIndex = new Map();
12397 /**
12398 * Represents the location of each class binding in the template
12399 * (e.g. `<div [class.big]="b" [class.hidden]="h">` implies
12400 * that `big=0` and `hidden=1`)
12401 */
12402 this._classesIndex = new Map();
12403 this._initialStyleValues = [];
12404 this._initialClassValues = [];
12405 }
12406 /**
12407 * Registers a given input to the styling builder to be later used when producing AOT code.
12408 *
12409 * The code below will only accept the input if it is somehow tied to styling (whether it be
12410 * style/class bindings or static style/class attributes).
12411 */
12412 registerBoundInput(input) {
12413 // [attr.style] or [attr.class] are skipped in the code below,
12414 // they should not be treated as styling-based bindings since
12415 // they are intended to be written directly to the attr and
12416 // will therefore skip all style/class resolution that is present
12417 // with style="", [style]="" and [style.prop]="", class="",
12418 // [class.prop]="". [class]="" assignments
12419 let binding = null;
12420 let name = input.name;
12421 switch (input.type) {
12422 case 0 /* Property */:
12423 binding = this.registerInputBasedOnName(name, input.value, input.sourceSpan);
12424 break;
12425 case 3 /* Style */:
12426 binding = this.registerStyleInput(name, false, input.value, input.sourceSpan, input.unit);
12427 break;
12428 case 2 /* Class */:
12429 binding = this.registerClassInput(name, false, input.value, input.sourceSpan);
12430 break;
12431 }
12432 return binding ? true : false;
12433 }
12434 registerInputBasedOnName(name, expression, sourceSpan) {
12435 let binding = null;
12436 const prefix = name.substring(0, 6);
12437 const isStyle = name === 'style' || prefix === 'style.' || prefix === 'style!';
12438 const isClass = !isStyle && (name === 'class' || prefix === 'class.' || prefix === 'class!');
12439 if (isStyle || isClass) {
12440 const isMapBased = name.charAt(5) !== '.'; // style.prop or class.prop makes this a no
12441 const property = name.substr(isMapBased ? 5 : 6); // the dot explains why there's a +1
12442 if (isStyle) {
12443 binding = this.registerStyleInput(property, isMapBased, expression, sourceSpan);
12444 }
12445 else {
12446 binding = this.registerClassInput(property, isMapBased, expression, sourceSpan);
12447 }
12448 }
12449 return binding;
12450 }
12451 registerStyleInput(name, isMapBased, value, sourceSpan, suffix) {
12452 if (isEmptyExpression(value)) {
12453 return null;
12454 }
12455 name = normalizePropName(name);
12456 const { property, hasOverrideFlag, suffix: bindingSuffix } = parseProperty(name);
12457 suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
12458 const entry = { name: property, suffix: suffix, value, sourceSpan, hasOverrideFlag };
12459 if (isMapBased) {
12460 this._styleMapInput = entry;
12461 }
12462 else {
12463 (this._singleStyleInputs = this._singleStyleInputs || []).push(entry);
12464 registerIntoMap(this._stylesIndex, property);
12465 }
12466 this._lastStylingInput = entry;
12467 this._firstStylingInput = this._firstStylingInput || entry;
12468 this._checkForPipes(value);
12469 this.hasBindings = true;
12470 return entry;
12471 }
12472 registerClassInput(name, isMapBased, value, sourceSpan) {
12473 if (isEmptyExpression(value)) {
12474 return null;
12475 }
12476 const { property, hasOverrideFlag } = parseProperty(name);
12477 const entry = { name: property, value, sourceSpan, hasOverrideFlag, suffix: null };
12478 if (isMapBased) {
12479 if (this._classMapInput) {
12480 throw new Error('[class] and [className] bindings cannot be used on the same element simultaneously');
12481 }
12482 this._classMapInput = entry;
12483 }
12484 else {
12485 (this._singleClassInputs = this._singleClassInputs || []).push(entry);
12486 registerIntoMap(this._classesIndex, property);
12487 }
12488 this._lastStylingInput = entry;
12489 this._firstStylingInput = this._firstStylingInput || entry;
12490 this._checkForPipes(value);
12491 this.hasBindings = true;
12492 return entry;
12493 }
12494 _checkForPipes(value) {
12495 if ((value instanceof ASTWithSource) && (value.ast instanceof BindingPipe)) {
12496 this.hasBindingsWithPipes = true;
12497 }
12498 }
12499 /**
12500 * Registers the element's static style string value to the builder.
12501 *
12502 * @param value the style string (e.g. `width:100px; height:200px;`)
12503 */
12504 registerStyleAttr(value) {
12505 this._initialStyleValues = parse(value);
12506 this._hasInitialValues = true;
12507 }
12508 /**
12509 * Registers the element's static class string value to the builder.
12510 *
12511 * @param value the className string (e.g. `disabled gold zoom`)
12512 */
12513 registerClassAttr(value) {
12514 this._initialClassValues = value.trim().split(/\s+/g);
12515 this._hasInitialValues = true;
12516 }
12517 /**
12518 * Appends all styling-related expressions to the provided attrs array.
12519 *
12520 * @param attrs an existing array where each of the styling expressions
12521 * will be inserted into.
12522 */
12523 populateInitialStylingAttrs(attrs) {
12524 // [CLASS_MARKER, 'foo', 'bar', 'baz' ...]
12525 if (this._initialClassValues.length) {
12526 attrs.push(literal(1 /* Classes */));
12527 for (let i = 0; i < this._initialClassValues.length; i++) {
12528 attrs.push(literal(this._initialClassValues[i]));
12529 }
12530 }
12531 // [STYLE_MARKER, 'width', '200px', 'height', '100px', ...]
12532 if (this._initialStyleValues.length) {
12533 attrs.push(literal(2 /* Styles */));
12534 for (let i = 0; i < this._initialStyleValues.length; i += 2) {
12535 attrs.push(literal(this._initialStyleValues[i]), literal(this._initialStyleValues[i + 1]));
12536 }
12537 }
12538 }
12539 /**
12540 * Builds an instruction with all the expressions and parameters for `elementHostAttrs`.
12541 *
12542 * The instruction generation code below is used for producing the AOT statement code which is
12543 * responsible for registering initial styles (within a directive hostBindings' creation block),
12544 * as well as any of the provided attribute values, to the directive host element.
12545 */
12546 assignHostAttrs(attrs, definitionMap) {
12547 if (this._directiveExpr && (attrs.length || this._hasInitialValues)) {
12548 this.populateInitialStylingAttrs(attrs);
12549 definitionMap.set('hostAttrs', literalArr(attrs));
12550 }
12551 }
12552 /**
12553 * Builds an instruction with all the expressions and parameters for `classMap`.
12554 *
12555 * The instruction data will contain all expressions for `classMap` to function
12556 * which includes the `[class]` expression params.
12557 */
12558 buildClassMapInstruction(valueConverter) {
12559 if (this._classMapInput) {
12560 return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput);
12561 }
12562 return null;
12563 }
12564 /**
12565 * Builds an instruction with all the expressions and parameters for `styleMap`.
12566 *
12567 * The instruction data will contain all expressions for `styleMap` to function
12568 * which includes the `[style]` expression params.
12569 */
12570 buildStyleMapInstruction(valueConverter) {
12571 if (this._styleMapInput) {
12572 return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput);
12573 }
12574 return null;
12575 }
12576 _buildMapBasedInstruction(valueConverter, isClassBased, stylingInput) {
12577 // each styling binding value is stored in the LView
12578 // map-based bindings allocate two slots: one for the
12579 // previous binding value and another for the previous
12580 // className or style attribute value.
12581 let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
12582 // these values must be outside of the update block so that they can
12583 // be evaluated (the AST visit call) during creation time so that any
12584 // pipes can be picked up in time before the template is built
12585 const mapValue = stylingInput.value.visit(valueConverter);
12586 let reference;
12587 if (mapValue instanceof Interpolation) {
12588 totalBindingSlotsRequired += mapValue.expressions.length;
12589 reference = isClassBased ? getClassMapInterpolationExpression(mapValue) :
12590 getStyleMapInterpolationExpression(mapValue);
12591 }
12592 else {
12593 reference = isClassBased ? Identifiers$1.classMap : Identifiers$1.styleMap;
12594 }
12595 return {
12596 reference,
12597 calls: [{
12598 supportsInterpolation: true,
12599 sourceSpan: stylingInput.sourceSpan,
12600 allocateBindingSlots: totalBindingSlotsRequired,
12601 params: (convertFn) => {
12602 const convertResult = convertFn(mapValue);
12603 const params = Array.isArray(convertResult) ? convertResult : [convertResult];
12604 return params;
12605 }
12606 }]
12607 };
12608 }
12609 _buildSingleInputs(reference, inputs, valueConverter, getInterpolationExpressionFn, isClassBased) {
12610 const instructions = [];
12611 inputs.forEach(input => {
12612 const previousInstruction = instructions[instructions.length - 1];
12613 const value = input.value.visit(valueConverter);
12614 let referenceForCall = reference;
12615 // each styling binding value is stored in the LView
12616 // but there are two values stored for each binding:
12617 // 1) the value itself
12618 // 2) an intermediate value (concatenation of style up to this point).
12619 // We need to store the intermediate value so that we don't allocate
12620 // the strings on each CD.
12621 let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
12622 if (value instanceof Interpolation) {
12623 totalBindingSlotsRequired += value.expressions.length;
12624 if (getInterpolationExpressionFn) {
12625 referenceForCall = getInterpolationExpressionFn(value);
12626 }
12627 }
12628 const call = {
12629 sourceSpan: input.sourceSpan,
12630 allocateBindingSlots: totalBindingSlotsRequired,
12631 supportsInterpolation: !!getInterpolationExpressionFn,
12632 params: (convertFn) => {
12633 // params => stylingProp(propName, value, suffix)
12634 const params = [];
12635 params.push(literal(input.name));
12636 const convertResult = convertFn(value);
12637 if (Array.isArray(convertResult)) {
12638 params.push(...convertResult);
12639 }
12640 else {
12641 params.push(convertResult);
12642 }
12643 // [style.prop] bindings may use suffix values (e.g. px, em, etc...), therefore,
12644 // if that is detected then we need to pass that in as an optional param.
12645 if (!isClassBased && input.suffix !== null) {
12646 params.push(literal(input.suffix));
12647 }
12648 return params;
12649 }
12650 };
12651 // If we ended up generating a call to the same instruction as the previous styling property
12652 // we can chain the calls together safely to save some bytes, otherwise we have to generate
12653 // a separate instruction call. This is primarily a concern with interpolation instructions
12654 // where we may start off with one `reference`, but end up using another based on the
12655 // number of interpolations.
12656 if (previousInstruction && previousInstruction.reference === referenceForCall) {
12657 previousInstruction.calls.push(call);
12658 }
12659 else {
12660 instructions.push({ reference: referenceForCall, calls: [call] });
12661 }
12662 });
12663 return instructions;
12664 }
12665 _buildClassInputs(valueConverter) {
12666 if (this._singleClassInputs) {
12667 return this._buildSingleInputs(Identifiers$1.classProp, this._singleClassInputs, valueConverter, null, true);
12668 }
12669 return [];
12670 }
12671 _buildStyleInputs(valueConverter) {
12672 if (this._singleStyleInputs) {
12673 return this._buildSingleInputs(Identifiers$1.styleProp, this._singleStyleInputs, valueConverter, getStylePropInterpolationExpression, false);
12674 }
12675 return [];
12676 }
12677 /**
12678 * Constructs all instructions which contain the expressions that will be placed
12679 * into the update block of a template function or a directive hostBindings function.
12680 */
12681 buildUpdateLevelInstructions(valueConverter) {
12682 const instructions = [];
12683 if (this.hasBindings) {
12684 const styleMapInstruction = this.buildStyleMapInstruction(valueConverter);
12685 if (styleMapInstruction) {
12686 instructions.push(styleMapInstruction);
12687 }
12688 const classMapInstruction = this.buildClassMapInstruction(valueConverter);
12689 if (classMapInstruction) {
12690 instructions.push(classMapInstruction);
12691 }
12692 instructions.push(...this._buildStyleInputs(valueConverter));
12693 instructions.push(...this._buildClassInputs(valueConverter));
12694 }
12695 return instructions;
12696 }
12697 }
12698 function registerIntoMap(map, key) {
12699 if (!map.has(key)) {
12700 map.set(key, map.size);
12701 }
12702 }
12703 function parseProperty(name) {
12704 let hasOverrideFlag = false;
12705 const overrideIndex = name.indexOf(IMPORTANT_FLAG);
12706 if (overrideIndex !== -1) {
12707 name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
12708 hasOverrideFlag = true;
12709 }
12710 let suffix = null;
12711 let property = name;
12712 const unitIndex = name.lastIndexOf('.');
12713 if (unitIndex > 0) {
12714 suffix = name.substr(unitIndex + 1);
12715 property = name.substring(0, unitIndex);
12716 }
12717 return { property, suffix, hasOverrideFlag };
12718 }
12719 /**
12720 * Gets the instruction to generate for an interpolated class map.
12721 * @param interpolation An Interpolation AST
12722 */
12723 function getClassMapInterpolationExpression(interpolation) {
12724 switch (getInterpolationArgsLength(interpolation)) {
12725 case 1:
12726 return Identifiers$1.classMap;
12727 case 3:
12728 return Identifiers$1.classMapInterpolate1;
12729 case 5:
12730 return Identifiers$1.classMapInterpolate2;
12731 case 7:
12732 return Identifiers$1.classMapInterpolate3;
12733 case 9:
12734 return Identifiers$1.classMapInterpolate4;
12735 case 11:
12736 return Identifiers$1.classMapInterpolate5;
12737 case 13:
12738 return Identifiers$1.classMapInterpolate6;
12739 case 15:
12740 return Identifiers$1.classMapInterpolate7;
12741 case 17:
12742 return Identifiers$1.classMapInterpolate8;
12743 default:
12744 return Identifiers$1.classMapInterpolateV;
12745 }
12746 }
12747 /**
12748 * Gets the instruction to generate for an interpolated style map.
12749 * @param interpolation An Interpolation AST
12750 */
12751 function getStyleMapInterpolationExpression(interpolation) {
12752 switch (getInterpolationArgsLength(interpolation)) {
12753 case 1:
12754 return Identifiers$1.styleMap;
12755 case 3:
12756 return Identifiers$1.styleMapInterpolate1;
12757 case 5:
12758 return Identifiers$1.styleMapInterpolate2;
12759 case 7:
12760 return Identifiers$1.styleMapInterpolate3;
12761 case 9:
12762 return Identifiers$1.styleMapInterpolate4;
12763 case 11:
12764 return Identifiers$1.styleMapInterpolate5;
12765 case 13:
12766 return Identifiers$1.styleMapInterpolate6;
12767 case 15:
12768 return Identifiers$1.styleMapInterpolate7;
12769 case 17:
12770 return Identifiers$1.styleMapInterpolate8;
12771 default:
12772 return Identifiers$1.styleMapInterpolateV;
12773 }
12774 }
12775 /**
12776 * Gets the instruction to generate for an interpolated style prop.
12777 * @param interpolation An Interpolation AST
12778 */
12779 function getStylePropInterpolationExpression(interpolation) {
12780 switch (getInterpolationArgsLength(interpolation)) {
12781 case 1:
12782 return Identifiers$1.styleProp;
12783 case 3:
12784 return Identifiers$1.stylePropInterpolate1;
12785 case 5:
12786 return Identifiers$1.stylePropInterpolate2;
12787 case 7:
12788 return Identifiers$1.stylePropInterpolate3;
12789 case 9:
12790 return Identifiers$1.stylePropInterpolate4;
12791 case 11:
12792 return Identifiers$1.stylePropInterpolate5;
12793 case 13:
12794 return Identifiers$1.stylePropInterpolate6;
12795 case 15:
12796 return Identifiers$1.stylePropInterpolate7;
12797 case 17:
12798 return Identifiers$1.stylePropInterpolate8;
12799 default:
12800 return Identifiers$1.stylePropInterpolateV;
12801 }
12802 }
12803 function normalizePropName(prop) {
12804 return hyphenate(prop);
12805 }
12806
12807 /**
12808 * @license
12809 * Copyright Google LLC All Rights Reserved.
12810 *
12811 * Use of this source code is governed by an MIT-style license that can be
12812 * found in the LICENSE file at https://angular.io/license
12813 */
12814 var TokenType$1;
12815 (function (TokenType) {
12816 TokenType[TokenType["Character"] = 0] = "Character";
12817 TokenType[TokenType["Identifier"] = 1] = "Identifier";
12818 TokenType[TokenType["Keyword"] = 2] = "Keyword";
12819 TokenType[TokenType["String"] = 3] = "String";
12820 TokenType[TokenType["Operator"] = 4] = "Operator";
12821 TokenType[TokenType["Number"] = 5] = "Number";
12822 TokenType[TokenType["Error"] = 6] = "Error";
12823 })(TokenType$1 || (TokenType$1 = {}));
12824 const KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
12825 class Lexer {
12826 tokenize(text) {
12827 const scanner = new _Scanner(text);
12828 const tokens = [];
12829 let token = scanner.scanToken();
12830 while (token != null) {
12831 tokens.push(token);
12832 token = scanner.scanToken();
12833 }
12834 return tokens;
12835 }
12836 }
12837 class Token$1 {
12838 constructor(index, end, type, numValue, strValue) {
12839 this.index = index;
12840 this.end = end;
12841 this.type = type;
12842 this.numValue = numValue;
12843 this.strValue = strValue;
12844 }
12845 isCharacter(code) {
12846 return this.type == TokenType$1.Character && this.numValue == code;
12847 }
12848 isNumber() {
12849 return this.type == TokenType$1.Number;
12850 }
12851 isString() {
12852 return this.type == TokenType$1.String;
12853 }
12854 isOperator(operator) {
12855 return this.type == TokenType$1.Operator && this.strValue == operator;
12856 }
12857 isIdentifier() {
12858 return this.type == TokenType$1.Identifier;
12859 }
12860 isKeyword() {
12861 return this.type == TokenType$1.Keyword;
12862 }
12863 isKeywordLet() {
12864 return this.type == TokenType$1.Keyword && this.strValue == 'let';
12865 }
12866 isKeywordAs() {
12867 return this.type == TokenType$1.Keyword && this.strValue == 'as';
12868 }
12869 isKeywordNull() {
12870 return this.type == TokenType$1.Keyword && this.strValue == 'null';
12871 }
12872 isKeywordUndefined() {
12873 return this.type == TokenType$1.Keyword && this.strValue == 'undefined';
12874 }
12875 isKeywordTrue() {
12876 return this.type == TokenType$1.Keyword && this.strValue == 'true';
12877 }
12878 isKeywordFalse() {
12879 return this.type == TokenType$1.Keyword && this.strValue == 'false';
12880 }
12881 isKeywordThis() {
12882 return this.type == TokenType$1.Keyword && this.strValue == 'this';
12883 }
12884 isError() {
12885 return this.type == TokenType$1.Error;
12886 }
12887 toNumber() {
12888 return this.type == TokenType$1.Number ? this.numValue : -1;
12889 }
12890 toString() {
12891 switch (this.type) {
12892 case TokenType$1.Character:
12893 case TokenType$1.Identifier:
12894 case TokenType$1.Keyword:
12895 case TokenType$1.Operator:
12896 case TokenType$1.String:
12897 case TokenType$1.Error:
12898 return this.strValue;
12899 case TokenType$1.Number:
12900 return this.numValue.toString();
12901 default:
12902 return null;
12903 }
12904 }
12905 }
12906 function newCharacterToken(index, end, code) {
12907 return new Token$1(index, end, TokenType$1.Character, code, String.fromCharCode(code));
12908 }
12909 function newIdentifierToken(index, end, text) {
12910 return new Token$1(index, end, TokenType$1.Identifier, 0, text);
12911 }
12912 function newKeywordToken(index, end, text) {
12913 return new Token$1(index, end, TokenType$1.Keyword, 0, text);
12914 }
12915 function newOperatorToken(index, end, text) {
12916 return new Token$1(index, end, TokenType$1.Operator, 0, text);
12917 }
12918 function newStringToken(index, end, text) {
12919 return new Token$1(index, end, TokenType$1.String, 0, text);
12920 }
12921 function newNumberToken(index, end, n) {
12922 return new Token$1(index, end, TokenType$1.Number, n, '');
12923 }
12924 function newErrorToken(index, end, message) {
12925 return new Token$1(index, end, TokenType$1.Error, 0, message);
12926 }
12927 const EOF = new Token$1(-1, -1, TokenType$1.Character, 0, '');
12928 class _Scanner {
12929 constructor(input) {
12930 this.input = input;
12931 this.peek = 0;
12932 this.index = -1;
12933 this.length = input.length;
12934 this.advance();
12935 }
12936 advance() {
12937 this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index);
12938 }
12939 scanToken() {
12940 const input = this.input, length = this.length;
12941 let peek = this.peek, index = this.index;
12942 // Skip whitespace.
12943 while (peek <= $SPACE) {
12944 if (++index >= length) {
12945 peek = $EOF;
12946 break;
12947 }
12948 else {
12949 peek = input.charCodeAt(index);
12950 }
12951 }
12952 this.peek = peek;
12953 this.index = index;
12954 if (index >= length) {
12955 return null;
12956 }
12957 // Handle identifiers and numbers.
12958 if (isIdentifierStart(peek))
12959 return this.scanIdentifier();
12960 if (isDigit(peek))
12961 return this.scanNumber(index);
12962 const start = index;
12963 switch (peek) {
12964 case $PERIOD:
12965 this.advance();
12966 return isDigit(this.peek) ? this.scanNumber(start) :
12967 newCharacterToken(start, this.index, $PERIOD);
12968 case $LPAREN:
12969 case $RPAREN:
12970 case $LBRACE:
12971 case $RBRACE:
12972 case $LBRACKET:
12973 case $RBRACKET:
12974 case $COMMA:
12975 case $COLON:
12976 case $SEMICOLON:
12977 return this.scanCharacter(start, peek);
12978 case $SQ:
12979 case $DQ:
12980 return this.scanString();
12981 case $HASH:
12982 case $PLUS:
12983 case $MINUS:
12984 case $STAR:
12985 case $SLASH:
12986 case $PERCENT:
12987 case $CARET:
12988 return this.scanOperator(start, String.fromCharCode(peek));
12989 case $QUESTION:
12990 return this.scanComplexOperator(start, '?', $PERIOD, '.');
12991 case $LT:
12992 case $GT:
12993 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=');
12994 case $BANG:
12995 case $EQ:
12996 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=', $EQ, '=');
12997 case $AMPERSAND:
12998 return this.scanComplexOperator(start, '&', $AMPERSAND, '&');
12999 case $BAR:
13000 return this.scanComplexOperator(start, '|', $BAR, '|');
13001 case $NBSP:
13002 while (isWhitespace(this.peek))
13003 this.advance();
13004 return this.scanToken();
13005 }
13006 this.advance();
13007 return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0);
13008 }
13009 scanCharacter(start, code) {
13010 this.advance();
13011 return newCharacterToken(start, this.index, code);
13012 }
13013 scanOperator(start, str) {
13014 this.advance();
13015 return newOperatorToken(start, this.index, str);
13016 }
13017 /**
13018 * Tokenize a 2/3 char long operator
13019 *
13020 * @param start start index in the expression
13021 * @param one first symbol (always part of the operator)
13022 * @param twoCode code point for the second symbol
13023 * @param two second symbol (part of the operator when the second code point matches)
13024 * @param threeCode code point for the third symbol
13025 * @param three third symbol (part of the operator when provided and matches source expression)
13026 */
13027 scanComplexOperator(start, one, twoCode, two, threeCode, three) {
13028 this.advance();
13029 let str = one;
13030 if (this.peek == twoCode) {
13031 this.advance();
13032 str += two;
13033 }
13034 if (threeCode != null && this.peek == threeCode) {
13035 this.advance();
13036 str += three;
13037 }
13038 return newOperatorToken(start, this.index, str);
13039 }
13040 scanIdentifier() {
13041 const start = this.index;
13042 this.advance();
13043 while (isIdentifierPart(this.peek))
13044 this.advance();
13045 const str = this.input.substring(start, this.index);
13046 return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, this.index, str) :
13047 newIdentifierToken(start, this.index, str);
13048 }
13049 scanNumber(start) {
13050 let simple = (this.index === start);
13051 this.advance(); // Skip initial digit.
13052 while (true) {
13053 if (isDigit(this.peek)) ;
13054 else if (this.peek == $PERIOD) {
13055 simple = false;
13056 }
13057 else if (isExponentStart(this.peek)) {
13058 this.advance();
13059 if (isExponentSign(this.peek))
13060 this.advance();
13061 if (!isDigit(this.peek))
13062 return this.error('Invalid exponent', -1);
13063 simple = false;
13064 }
13065 else {
13066 break;
13067 }
13068 this.advance();
13069 }
13070 const str = this.input.substring(start, this.index);
13071 const value = simple ? parseIntAutoRadix(str) : parseFloat(str);
13072 return newNumberToken(start, this.index, value);
13073 }
13074 scanString() {
13075 const start = this.index;
13076 const quote = this.peek;
13077 this.advance(); // Skip initial quote.
13078 let buffer = '';
13079 let marker = this.index;
13080 const input = this.input;
13081 while (this.peek != quote) {
13082 if (this.peek == $BACKSLASH) {
13083 buffer += input.substring(marker, this.index);
13084 this.advance();
13085 let unescapedCode;
13086 // Workaround for TS2.1-introduced type strictness
13087 this.peek = this.peek;
13088 if (this.peek == $u) {
13089 // 4 character hex code for unicode character.
13090 const hex = input.substring(this.index + 1, this.index + 5);
13091 if (/^[0-9a-f]+$/i.test(hex)) {
13092 unescapedCode = parseInt(hex, 16);
13093 }
13094 else {
13095 return this.error(`Invalid unicode escape [\\u${hex}]`, 0);
13096 }
13097 for (let i = 0; i < 5; i++) {
13098 this.advance();
13099 }
13100 }
13101 else {
13102 unescapedCode = unescape(this.peek);
13103 this.advance();
13104 }
13105 buffer += String.fromCharCode(unescapedCode);
13106 marker = this.index;
13107 }
13108 else if (this.peek == $EOF) {
13109 return this.error('Unterminated quote', 0);
13110 }
13111 else {
13112 this.advance();
13113 }
13114 }
13115 const last = input.substring(marker, this.index);
13116 this.advance(); // Skip terminating quote.
13117 return newStringToken(start, this.index, buffer + last);
13118 }
13119 error(message, offset) {
13120 const position = this.index + offset;
13121 return newErrorToken(position, this.index, `Lexer Error: ${message} at column ${position} in expression [${this.input}]`);
13122 }
13123 }
13124 function isIdentifierStart(code) {
13125 return ($a <= code && code <= $z) || ($A <= code && code <= $Z) ||
13126 (code == $_) || (code == $$);
13127 }
13128 function isIdentifier(input) {
13129 if (input.length == 0)
13130 return false;
13131 const scanner = new _Scanner(input);
13132 if (!isIdentifierStart(scanner.peek))
13133 return false;
13134 scanner.advance();
13135 while (scanner.peek !== $EOF) {
13136 if (!isIdentifierPart(scanner.peek))
13137 return false;
13138 scanner.advance();
13139 }
13140 return true;
13141 }
13142 function isIdentifierPart(code) {
13143 return isAsciiLetter(code) || isDigit(code) || (code == $_) ||
13144 (code == $$);
13145 }
13146 function isExponentStart(code) {
13147 return code == $e || code == $E;
13148 }
13149 function isExponentSign(code) {
13150 return code == $MINUS || code == $PLUS;
13151 }
13152 function isQuote(code) {
13153 return code === $SQ || code === $DQ || code === $BT;
13154 }
13155 function unescape(code) {
13156 switch (code) {
13157 case $n:
13158 return $LF;
13159 case $f:
13160 return $FF;
13161 case $r:
13162 return $CR;
13163 case $t:
13164 return $TAB;
13165 case $v:
13166 return $VTAB;
13167 default:
13168 return code;
13169 }
13170 }
13171 function parseIntAutoRadix(text) {
13172 const result = parseInt(text);
13173 if (isNaN(result)) {
13174 throw new Error('Invalid integer literal when parsing ' + text);
13175 }
13176 return result;
13177 }
13178
13179 /**
13180 * @license
13181 * Copyright Google LLC All Rights Reserved.
13182 *
13183 * Use of this source code is governed by an MIT-style license that can be
13184 * found in the LICENSE file at https://angular.io/license
13185 */
13186 class SplitInterpolation {
13187 constructor(strings, expressions, offsets) {
13188 this.strings = strings;
13189 this.expressions = expressions;
13190 this.offsets = offsets;
13191 }
13192 }
13193 class TemplateBindingParseResult {
13194 constructor(templateBindings, warnings, errors) {
13195 this.templateBindings = templateBindings;
13196 this.warnings = warnings;
13197 this.errors = errors;
13198 }
13199 }
13200 class Parser$1 {
13201 constructor(_lexer) {
13202 this._lexer = _lexer;
13203 this.errors = [];
13204 this.simpleExpressionChecker = SimpleExpressionChecker;
13205 }
13206 parseAction(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13207 this._checkNoInterpolation(input, location, interpolationConfig);
13208 const sourceToLex = this._stripComments(input);
13209 const tokens = this._lexer.tokenize(this._stripComments(input));
13210 const ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, true, this.errors, input.length - sourceToLex.length)
13211 .parseChain();
13212 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
13213 }
13214 parseBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13215 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
13216 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
13217 }
13218 checkSimpleExpression(ast) {
13219 const checker = new this.simpleExpressionChecker();
13220 ast.visit(checker);
13221 return checker.errors;
13222 }
13223 parseSimpleBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13224 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
13225 const errors = this.checkSimpleExpression(ast);
13226 if (errors.length > 0) {
13227 this._reportError(`Host binding expression cannot contain ${errors.join(' ')}`, input, location);
13228 }
13229 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
13230 }
13231 _reportError(message, input, errLocation, ctxLocation) {
13232 this.errors.push(new ParserError(message, input, errLocation, ctxLocation));
13233 }
13234 _parseBindingAst(input, location, absoluteOffset, interpolationConfig) {
13235 // Quotes expressions use 3rd-party expression language. We don't want to use
13236 // our lexer or parser for that, so we check for that ahead of time.
13237 const quote = this._parseQuote(input, location, absoluteOffset);
13238 if (quote != null) {
13239 return quote;
13240 }
13241 this._checkNoInterpolation(input, location, interpolationConfig);
13242 const sourceToLex = this._stripComments(input);
13243 const tokens = this._lexer.tokenize(sourceToLex);
13244 return new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, input.length - sourceToLex.length)
13245 .parseChain();
13246 }
13247 _parseQuote(input, location, absoluteOffset) {
13248 if (input == null)
13249 return null;
13250 const prefixSeparatorIndex = input.indexOf(':');
13251 if (prefixSeparatorIndex == -1)
13252 return null;
13253 const prefix = input.substring(0, prefixSeparatorIndex).trim();
13254 if (!isIdentifier(prefix))
13255 return null;
13256 const uninterpretedExpression = input.substring(prefixSeparatorIndex + 1);
13257 const span = new ParseSpan(0, input.length);
13258 return new Quote(span, span.toAbsolute(absoluteOffset), prefix, uninterpretedExpression, location);
13259 }
13260 /**
13261 * Parse microsyntax template expression and return a list of bindings or
13262 * parsing errors in case the given expression is invalid.
13263 *
13264 * For example,
13265 * ```
13266 * <div *ngFor="let item of items">
13267 * ^ ^ absoluteValueOffset for `templateValue`
13268 * absoluteKeyOffset for `templateKey`
13269 * ```
13270 * contains three bindings:
13271 * 1. ngFor -> null
13272 * 2. item -> NgForOfContext.$implicit
13273 * 3. ngForOf -> items
13274 *
13275 * This is apparent from the de-sugared template:
13276 * ```
13277 * <ng-template ngFor let-item [ngForOf]="items">
13278 * ```
13279 *
13280 * @param templateKey name of directive, without the * prefix. For example: ngIf, ngFor
13281 * @param templateValue RHS of the microsyntax attribute
13282 * @param templateUrl template filename if it's external, component filename if it's inline
13283 * @param absoluteKeyOffset start of the `templateKey`
13284 * @param absoluteValueOffset start of the `templateValue`
13285 */
13286 parseTemplateBindings(templateKey, templateValue, templateUrl, absoluteKeyOffset, absoluteValueOffset) {
13287 const tokens = this._lexer.tokenize(templateValue);
13288 const parser = new _ParseAST(templateValue, templateUrl, absoluteValueOffset, tokens, templateValue.length, false /* parseAction */, this.errors, 0 /* relative offset */);
13289 return parser.parseTemplateBindings({
13290 source: templateKey,
13291 span: new AbsoluteSourceSpan(absoluteKeyOffset, absoluteKeyOffset + templateKey.length),
13292 });
13293 }
13294 parseInterpolation(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13295 const { strings, expressions, offsets } = this.splitInterpolation(input, location, interpolationConfig);
13296 if (expressions.length === 0)
13297 return null;
13298 const expressionNodes = [];
13299 for (let i = 0; i < expressions.length; ++i) {
13300 const expressionText = expressions[i].text;
13301 const sourceToLex = this._stripComments(expressionText);
13302 const tokens = this._lexer.tokenize(sourceToLex);
13303 const ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, offsets[i] + (expressionText.length - sourceToLex.length))
13304 .parseChain();
13305 expressionNodes.push(ast);
13306 }
13307 return this.createInterpolationAst(strings.map(s => s.text), expressionNodes, input, location, absoluteOffset);
13308 }
13309 /**
13310 * Similar to `parseInterpolation`, but treats the provided string as a single expression
13311 * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
13312 * This is used for parsing the switch expression in ICUs.
13313 */
13314 parseInterpolationExpression(expression, location, absoluteOffset) {
13315 const sourceToLex = this._stripComments(expression);
13316 const tokens = this._lexer.tokenize(sourceToLex);
13317 const ast = new _ParseAST(expression, location, absoluteOffset, tokens, sourceToLex.length,
13318 /* parseAction */ false, this.errors, 0)
13319 .parseChain();
13320 const strings = ['', '']; // The prefix and suffix strings are both empty
13321 return this.createInterpolationAst(strings, [ast], expression, location, absoluteOffset);
13322 }
13323 createInterpolationAst(strings, expressions, input, location, absoluteOffset) {
13324 const span = new ParseSpan(0, input.length);
13325 const interpolation = new Interpolation(span, span.toAbsolute(absoluteOffset), strings, expressions);
13326 return new ASTWithSource(interpolation, input, location, absoluteOffset, this.errors);
13327 }
13328 /**
13329 * Splits a string of text into "raw" text segments and expressions present in interpolations in
13330 * the string.
13331 * Returns `null` if there are no interpolations, otherwise a
13332 * `SplitInterpolation` with splits that look like
13333 * <raw text> <expression> <raw text> ... <raw text> <expression> <raw text>
13334 */
13335 splitInterpolation(input, location, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13336 const strings = [];
13337 const expressions = [];
13338 const offsets = [];
13339 let i = 0;
13340 let atInterpolation = false;
13341 let extendLastString = false;
13342 let { start: interpStart, end: interpEnd } = interpolationConfig;
13343 while (i < input.length) {
13344 if (!atInterpolation) {
13345 // parse until starting {{
13346 const start = i;
13347 i = input.indexOf(interpStart, i);
13348 if (i === -1) {
13349 i = input.length;
13350 }
13351 const text = input.substring(start, i);
13352 strings.push({ text, start, end: i });
13353 atInterpolation = true;
13354 }
13355 else {
13356 // parse from starting {{ to ending }} while ignoring content inside quotes.
13357 const fullStart = i;
13358 const exprStart = fullStart + interpStart.length;
13359 const exprEnd = this._getInterpolationEndIndex(input, interpEnd, exprStart);
13360 if (exprEnd === -1) {
13361 // Could not find the end of the interpolation; do not parse an expression.
13362 // Instead we should extend the content on the last raw string.
13363 atInterpolation = false;
13364 extendLastString = true;
13365 break;
13366 }
13367 const fullEnd = exprEnd + interpEnd.length;
13368 const text = input.substring(exprStart, exprEnd);
13369 if (text.trim().length === 0) {
13370 this._reportError('Blank expressions are not allowed in interpolated strings', input, `at column ${i} in`, location);
13371 }
13372 expressions.push({ text, start: fullStart, end: fullEnd });
13373 offsets.push(exprStart);
13374 i = fullEnd;
13375 atInterpolation = false;
13376 }
13377 }
13378 if (!atInterpolation) {
13379 // If we are now at a text section, add the remaining content as a raw string.
13380 if (extendLastString) {
13381 const piece = strings[strings.length - 1];
13382 piece.text += input.substring(i);
13383 piece.end = input.length;
13384 }
13385 else {
13386 strings.push({ text: input.substring(i), start: i, end: input.length });
13387 }
13388 }
13389 return new SplitInterpolation(strings, expressions, offsets);
13390 }
13391 wrapLiteralPrimitive(input, location, absoluteOffset) {
13392 const span = new ParseSpan(0, input == null ? 0 : input.length);
13393 return new ASTWithSource(new LiteralPrimitive(span, span.toAbsolute(absoluteOffset), input), input, location, absoluteOffset, this.errors);
13394 }
13395 _stripComments(input) {
13396 const i = this._commentStart(input);
13397 return i != null ? input.substring(0, i).trim() : input;
13398 }
13399 _commentStart(input) {
13400 let outerQuote = null;
13401 for (let i = 0; i < input.length - 1; i++) {
13402 const char = input.charCodeAt(i);
13403 const nextChar = input.charCodeAt(i + 1);
13404 if (char === $SLASH && nextChar == $SLASH && outerQuote == null)
13405 return i;
13406 if (outerQuote === char) {
13407 outerQuote = null;
13408 }
13409 else if (outerQuote == null && isQuote(char)) {
13410 outerQuote = char;
13411 }
13412 }
13413 return null;
13414 }
13415 _checkNoInterpolation(input, location, { start, end }) {
13416 let startIndex = -1;
13417 let endIndex = -1;
13418 for (const charIndex of this._forEachUnquotedChar(input, 0)) {
13419 if (startIndex === -1) {
13420 if (input.startsWith(start)) {
13421 startIndex = charIndex;
13422 }
13423 }
13424 else {
13425 endIndex = this._getInterpolationEndIndex(input, end, charIndex);
13426 if (endIndex > -1) {
13427 break;
13428 }
13429 }
13430 }
13431 if (startIndex > -1 && endIndex > -1) {
13432 this._reportError(`Got interpolation (${start}${end}) where expression was expected`, input, `at column ${startIndex} in`, location);
13433 }
13434 }
13435 /**
13436 * Finds the index of the end of an interpolation expression
13437 * while ignoring comments and quoted content.
13438 */
13439 _getInterpolationEndIndex(input, expressionEnd, start) {
13440 for (const charIndex of this._forEachUnquotedChar(input, start)) {
13441 if (input.startsWith(expressionEnd, charIndex)) {
13442 return charIndex;
13443 }
13444 // Nothing else in the expression matters after we've
13445 // hit a comment so look directly for the end token.
13446 if (input.startsWith('//', charIndex)) {
13447 return input.indexOf(expressionEnd, charIndex);
13448 }
13449 }
13450 return -1;
13451 }
13452 /**
13453 * Generator used to iterate over the character indexes of a string that are outside of quotes.
13454 * @param input String to loop through.
13455 * @param start Index within the string at which to start.
13456 */
13457 *_forEachUnquotedChar(input, start) {
13458 let currentQuote = null;
13459 let escapeCount = 0;
13460 for (let i = start; i < input.length; i++) {
13461 const char = input[i];
13462 // Skip the characters inside quotes. Note that we only care about the outer-most
13463 // quotes matching up and we need to account for escape characters.
13464 if (isQuote(input.charCodeAt(i)) && (currentQuote === null || currentQuote === char) &&
13465 escapeCount % 2 === 0) {
13466 currentQuote = currentQuote === null ? char : null;
13467 }
13468 else if (currentQuote === null) {
13469 yield i;
13470 }
13471 escapeCount = char === '\\' ? escapeCount + 1 : 0;
13472 }
13473 }
13474 }
13475 class IvyParser extends Parser$1 {
13476 constructor() {
13477 super(...arguments);
13478 this.simpleExpressionChecker = IvySimpleExpressionChecker;
13479 }
13480 }
13481 /** Describes a stateful context an expression parser is in. */
13482 var ParseContextFlags;
13483 (function (ParseContextFlags) {
13484 ParseContextFlags[ParseContextFlags["None"] = 0] = "None";
13485 /**
13486 * A Writable context is one in which a value may be written to an lvalue.
13487 * For example, after we see a property access, we may expect a write to the
13488 * property via the "=" operator.
13489 * prop
13490 * ^ possible "=" after
13491 */
13492 ParseContextFlags[ParseContextFlags["Writable"] = 1] = "Writable";
13493 })(ParseContextFlags || (ParseContextFlags = {}));
13494 class _ParseAST {
13495 constructor(input, location, absoluteOffset, tokens, inputLength, parseAction, errors, offset) {
13496 this.input = input;
13497 this.location = location;
13498 this.absoluteOffset = absoluteOffset;
13499 this.tokens = tokens;
13500 this.inputLength = inputLength;
13501 this.parseAction = parseAction;
13502 this.errors = errors;
13503 this.offset = offset;
13504 this.rparensExpected = 0;
13505 this.rbracketsExpected = 0;
13506 this.rbracesExpected = 0;
13507 this.context = ParseContextFlags.None;
13508 // Cache of expression start and input indeces to the absolute source span they map to, used to
13509 // prevent creating superfluous source spans in `sourceSpan`.
13510 // A serial of the expression start and input index is used for mapping because both are stateful
13511 // and may change for subsequent expressions visited by the parser.
13512 this.sourceSpanCache = new Map();
13513 this.index = 0;
13514 }
13515 peek(offset) {
13516 const i = this.index + offset;
13517 return i < this.tokens.length ? this.tokens[i] : EOF;
13518 }
13519 get next() {
13520 return this.peek(0);
13521 }
13522 /** Whether all the parser input has been processed. */
13523 get atEOF() {
13524 return this.index >= this.tokens.length;
13525 }
13526 /**
13527 * Index of the next token to be processed, or the end of the last token if all have been
13528 * processed.
13529 */
13530 get inputIndex() {
13531 return this.atEOF ? this.currentEndIndex : this.next.index + this.offset;
13532 }
13533 /**
13534 * End index of the last processed token, or the start of the first token if none have been
13535 * processed.
13536 */
13537 get currentEndIndex() {
13538 if (this.index > 0) {
13539 const curToken = this.peek(-1);
13540 return curToken.end + this.offset;
13541 }
13542 // No tokens have been processed yet; return the next token's start or the length of the input
13543 // if there is no token.
13544 if (this.tokens.length === 0) {
13545 return this.inputLength + this.offset;
13546 }
13547 return this.next.index + this.offset;
13548 }
13549 /**
13550 * Returns the absolute offset of the start of the current token.
13551 */
13552 get currentAbsoluteOffset() {
13553 return this.absoluteOffset + this.inputIndex;
13554 }
13555 /**
13556 * Retrieve a `ParseSpan` from `start` to the current position (or to `artificialEndIndex` if
13557 * provided).
13558 *
13559 * @param start Position from which the `ParseSpan` will start.
13560 * @param artificialEndIndex Optional ending index to be used if provided (and if greater than the
13561 * natural ending index)
13562 */
13563 span(start, artificialEndIndex) {
13564 let endIndex = this.currentEndIndex;
13565 if (artificialEndIndex !== undefined && artificialEndIndex > this.currentEndIndex) {
13566 endIndex = artificialEndIndex;
13567 }
13568 return new ParseSpan(start, endIndex);
13569 }
13570 sourceSpan(start, artificialEndIndex) {
13571 const serial = `${start}@${this.inputIndex}:${artificialEndIndex}`;
13572 if (!this.sourceSpanCache.has(serial)) {
13573 this.sourceSpanCache.set(serial, this.span(start, artificialEndIndex).toAbsolute(this.absoluteOffset));
13574 }
13575 return this.sourceSpanCache.get(serial);
13576 }
13577 advance() {
13578 this.index++;
13579 }
13580 /**
13581 * Executes a callback in the provided context.
13582 */
13583 withContext(context, cb) {
13584 this.context |= context;
13585 const ret = cb();
13586 this.context ^= context;
13587 return ret;
13588 }
13589 consumeOptionalCharacter(code) {
13590 if (this.next.isCharacter(code)) {
13591 this.advance();
13592 return true;
13593 }
13594 else {
13595 return false;
13596 }
13597 }
13598 peekKeywordLet() {
13599 return this.next.isKeywordLet();
13600 }
13601 peekKeywordAs() {
13602 return this.next.isKeywordAs();
13603 }
13604 /**
13605 * Consumes an expected character, otherwise emits an error about the missing expected character
13606 * and skips over the token stream until reaching a recoverable point.
13607 *
13608 * See `this.error` and `this.skip` for more details.
13609 */
13610 expectCharacter(code) {
13611 if (this.consumeOptionalCharacter(code))
13612 return;
13613 this.error(`Missing expected ${String.fromCharCode(code)}`);
13614 }
13615 consumeOptionalOperator(op) {
13616 if (this.next.isOperator(op)) {
13617 this.advance();
13618 return true;
13619 }
13620 else {
13621 return false;
13622 }
13623 }
13624 expectOperator(operator) {
13625 if (this.consumeOptionalOperator(operator))
13626 return;
13627 this.error(`Missing expected operator ${operator}`);
13628 }
13629 prettyPrintToken(tok) {
13630 return tok === EOF ? 'end of input' : `token ${tok}`;
13631 }
13632 expectIdentifierOrKeyword() {
13633 const n = this.next;
13634 if (!n.isIdentifier() && !n.isKeyword()) {
13635 this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier or keyword`);
13636 return null;
13637 }
13638 this.advance();
13639 return n.toString();
13640 }
13641 expectIdentifierOrKeywordOrString() {
13642 const n = this.next;
13643 if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) {
13644 this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier, keyword, or string`);
13645 return '';
13646 }
13647 this.advance();
13648 return n.toString();
13649 }
13650 parseChain() {
13651 const exprs = [];
13652 const start = this.inputIndex;
13653 while (this.index < this.tokens.length) {
13654 const expr = this.parsePipe();
13655 exprs.push(expr);
13656 if (this.consumeOptionalCharacter($SEMICOLON)) {
13657 if (!this.parseAction) {
13658 this.error('Binding expression cannot contain chained expression');
13659 }
13660 while (this.consumeOptionalCharacter($SEMICOLON)) {
13661 } // read all semicolons
13662 }
13663 else if (this.index < this.tokens.length) {
13664 this.error(`Unexpected token '${this.next}'`);
13665 }
13666 }
13667 if (exprs.length == 0) {
13668 // We have no expressions so create an empty expression that spans the entire input length
13669 const artificialStart = this.offset;
13670 const artificialEnd = this.offset + this.inputLength;
13671 return new EmptyExpr(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd));
13672 }
13673 if (exprs.length == 1)
13674 return exprs[0];
13675 return new Chain(this.span(start), this.sourceSpan(start), exprs);
13676 }
13677 parsePipe() {
13678 const start = this.inputIndex;
13679 let result = this.parseExpression();
13680 if (this.consumeOptionalOperator('|')) {
13681 if (this.parseAction) {
13682 this.error('Cannot have a pipe in an action expression');
13683 }
13684 do {
13685 const nameStart = this.inputIndex;
13686 let nameId = this.expectIdentifierOrKeyword();
13687 let nameSpan;
13688 let fullSpanEnd = undefined;
13689 if (nameId !== null) {
13690 nameSpan = this.sourceSpan(nameStart);
13691 }
13692 else {
13693 // No valid identifier was found, so we'll assume an empty pipe name ('').
13694 nameId = '';
13695 // However, there may have been whitespace present between the pipe character and the next
13696 // token in the sequence (or the end of input). We want to track this whitespace so that
13697 // the `BindingPipe` we produce covers not just the pipe character, but any trailing
13698 // whitespace beyond it. Another way of thinking about this is that the zero-length name
13699 // is assumed to be at the end of any whitespace beyond the pipe character.
13700 //
13701 // Therefore, we push the end of the `ParseSpan` for this pipe all the way up to the
13702 // beginning of the next token, or until the end of input if the next token is EOF.
13703 fullSpanEnd = this.next.index !== -1 ? this.next.index : this.inputLength + this.offset;
13704 // The `nameSpan` for an empty pipe name is zero-length at the end of any whitespace
13705 // beyond the pipe character.
13706 nameSpan = new ParseSpan(fullSpanEnd, fullSpanEnd).toAbsolute(this.absoluteOffset);
13707 }
13708 const args = [];
13709 while (this.consumeOptionalCharacter($COLON)) {
13710 args.push(this.parseExpression());
13711 // If there are additional expressions beyond the name, then the artificial end for the
13712 // name is no longer relevant.
13713 }
13714 result = new BindingPipe(this.span(start), this.sourceSpan(start, fullSpanEnd), result, nameId, args, nameSpan);
13715 } while (this.consumeOptionalOperator('|'));
13716 }
13717 return result;
13718 }
13719 parseExpression() {
13720 return this.parseConditional();
13721 }
13722 parseConditional() {
13723 const start = this.inputIndex;
13724 const result = this.parseLogicalOr();
13725 if (this.consumeOptionalOperator('?')) {
13726 const yes = this.parsePipe();
13727 let no;
13728 if (!this.consumeOptionalCharacter($COLON)) {
13729 const end = this.inputIndex;
13730 const expression = this.input.substring(start, end);
13731 this.error(`Conditional expression ${expression} requires all 3 expressions`);
13732 no = new EmptyExpr(this.span(start), this.sourceSpan(start));
13733 }
13734 else {
13735 no = this.parsePipe();
13736 }
13737 return new Conditional(this.span(start), this.sourceSpan(start), result, yes, no);
13738 }
13739 else {
13740 return result;
13741 }
13742 }
13743 parseLogicalOr() {
13744 // '||'
13745 const start = this.inputIndex;
13746 let result = this.parseLogicalAnd();
13747 while (this.consumeOptionalOperator('||')) {
13748 const right = this.parseLogicalAnd();
13749 result = new Binary(this.span(start), this.sourceSpan(start), '||', result, right);
13750 }
13751 return result;
13752 }
13753 parseLogicalAnd() {
13754 // '&&'
13755 const start = this.inputIndex;
13756 let result = this.parseEquality();
13757 while (this.consumeOptionalOperator('&&')) {
13758 const right = this.parseEquality();
13759 result = new Binary(this.span(start), this.sourceSpan(start), '&&', result, right);
13760 }
13761 return result;
13762 }
13763 parseEquality() {
13764 // '==','!=','===','!=='
13765 const start = this.inputIndex;
13766 let result = this.parseRelational();
13767 while (this.next.type == TokenType$1.Operator) {
13768 const operator = this.next.strValue;
13769 switch (operator) {
13770 case '==':
13771 case '===':
13772 case '!=':
13773 case '!==':
13774 this.advance();
13775 const right = this.parseRelational();
13776 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13777 continue;
13778 }
13779 break;
13780 }
13781 return result;
13782 }
13783 parseRelational() {
13784 // '<', '>', '<=', '>='
13785 const start = this.inputIndex;
13786 let result = this.parseAdditive();
13787 while (this.next.type == TokenType$1.Operator) {
13788 const operator = this.next.strValue;
13789 switch (operator) {
13790 case '<':
13791 case '>':
13792 case '<=':
13793 case '>=':
13794 this.advance();
13795 const right = this.parseAdditive();
13796 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13797 continue;
13798 }
13799 break;
13800 }
13801 return result;
13802 }
13803 parseAdditive() {
13804 // '+', '-'
13805 const start = this.inputIndex;
13806 let result = this.parseMultiplicative();
13807 while (this.next.type == TokenType$1.Operator) {
13808 const operator = this.next.strValue;
13809 switch (operator) {
13810 case '+':
13811 case '-':
13812 this.advance();
13813 let right = this.parseMultiplicative();
13814 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13815 continue;
13816 }
13817 break;
13818 }
13819 return result;
13820 }
13821 parseMultiplicative() {
13822 // '*', '%', '/'
13823 const start = this.inputIndex;
13824 let result = this.parsePrefix();
13825 while (this.next.type == TokenType$1.Operator) {
13826 const operator = this.next.strValue;
13827 switch (operator) {
13828 case '*':
13829 case '%':
13830 case '/':
13831 this.advance();
13832 let right = this.parsePrefix();
13833 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13834 continue;
13835 }
13836 break;
13837 }
13838 return result;
13839 }
13840 parsePrefix() {
13841 if (this.next.type == TokenType$1.Operator) {
13842 const start = this.inputIndex;
13843 const operator = this.next.strValue;
13844 let result;
13845 switch (operator) {
13846 case '+':
13847 this.advance();
13848 result = this.parsePrefix();
13849 return Unary.createPlus(this.span(start), this.sourceSpan(start), result);
13850 case '-':
13851 this.advance();
13852 result = this.parsePrefix();
13853 return Unary.createMinus(this.span(start), this.sourceSpan(start), result);
13854 case '!':
13855 this.advance();
13856 result = this.parsePrefix();
13857 return new PrefixNot(this.span(start), this.sourceSpan(start), result);
13858 }
13859 }
13860 return this.parseCallChain();
13861 }
13862 parseCallChain() {
13863 const start = this.inputIndex;
13864 let result = this.parsePrimary();
13865 while (true) {
13866 if (this.consumeOptionalCharacter($PERIOD)) {
13867 result = this.parseAccessMemberOrMethodCall(result, start, false);
13868 }
13869 else if (this.consumeOptionalOperator('?.')) {
13870 result = this.parseAccessMemberOrMethodCall(result, start, true);
13871 }
13872 else if (this.consumeOptionalCharacter($LBRACKET)) {
13873 this.withContext(ParseContextFlags.Writable, () => {
13874 this.rbracketsExpected++;
13875 const key = this.parsePipe();
13876 if (key instanceof EmptyExpr) {
13877 this.error(`Key access cannot be empty`);
13878 }
13879 this.rbracketsExpected--;
13880 this.expectCharacter($RBRACKET);
13881 if (this.consumeOptionalOperator('=')) {
13882 const value = this.parseConditional();
13883 result = new KeyedWrite(this.span(start), this.sourceSpan(start), result, key, value);
13884 }
13885 else {
13886 result = new KeyedRead(this.span(start), this.sourceSpan(start), result, key);
13887 }
13888 });
13889 }
13890 else if (this.consumeOptionalCharacter($LPAREN)) {
13891 this.rparensExpected++;
13892 const args = this.parseCallArguments();
13893 this.rparensExpected--;
13894 this.expectCharacter($RPAREN);
13895 result = new FunctionCall(this.span(start), this.sourceSpan(start), result, args);
13896 }
13897 else if (this.consumeOptionalOperator('!')) {
13898 result = new NonNullAssert(this.span(start), this.sourceSpan(start), result);
13899 }
13900 else {
13901 return result;
13902 }
13903 }
13904 }
13905 parsePrimary() {
13906 const start = this.inputIndex;
13907 if (this.consumeOptionalCharacter($LPAREN)) {
13908 this.rparensExpected++;
13909 const result = this.parsePipe();
13910 this.rparensExpected--;
13911 this.expectCharacter($RPAREN);
13912 return result;
13913 }
13914 else if (this.next.isKeywordNull()) {
13915 this.advance();
13916 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), null);
13917 }
13918 else if (this.next.isKeywordUndefined()) {
13919 this.advance();
13920 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), void 0);
13921 }
13922 else if (this.next.isKeywordTrue()) {
13923 this.advance();
13924 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), true);
13925 }
13926 else if (this.next.isKeywordFalse()) {
13927 this.advance();
13928 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), false);
13929 }
13930 else if (this.next.isKeywordThis()) {
13931 this.advance();
13932 return new ThisReceiver(this.span(start), this.sourceSpan(start));
13933 }
13934 else if (this.consumeOptionalCharacter($LBRACKET)) {
13935 this.rbracketsExpected++;
13936 const elements = this.parseExpressionList($RBRACKET);
13937 this.rbracketsExpected--;
13938 this.expectCharacter($RBRACKET);
13939 return new LiteralArray(this.span(start), this.sourceSpan(start), elements);
13940 }
13941 else if (this.next.isCharacter($LBRACE)) {
13942 return this.parseLiteralMap();
13943 }
13944 else if (this.next.isIdentifier()) {
13945 return this.parseAccessMemberOrMethodCall(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false);
13946 }
13947 else if (this.next.isNumber()) {
13948 const value = this.next.toNumber();
13949 this.advance();
13950 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value);
13951 }
13952 else if (this.next.isString()) {
13953 const literalValue = this.next.toString();
13954 this.advance();
13955 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), literalValue);
13956 }
13957 else if (this.index >= this.tokens.length) {
13958 this.error(`Unexpected end of expression: ${this.input}`);
13959 return new EmptyExpr(this.span(start), this.sourceSpan(start));
13960 }
13961 else {
13962 this.error(`Unexpected token ${this.next}`);
13963 return new EmptyExpr(this.span(start), this.sourceSpan(start));
13964 }
13965 }
13966 parseExpressionList(terminator) {
13967 const result = [];
13968 do {
13969 if (!this.next.isCharacter(terminator)) {
13970 result.push(this.parsePipe());
13971 }
13972 else {
13973 break;
13974 }
13975 } while (this.consumeOptionalCharacter($COMMA));
13976 return result;
13977 }
13978 parseLiteralMap() {
13979 const keys = [];
13980 const values = [];
13981 const start = this.inputIndex;
13982 this.expectCharacter($LBRACE);
13983 if (!this.consumeOptionalCharacter($RBRACE)) {
13984 this.rbracesExpected++;
13985 do {
13986 const quoted = this.next.isString();
13987 const key = this.expectIdentifierOrKeywordOrString();
13988 keys.push({ key, quoted });
13989 this.expectCharacter($COLON);
13990 values.push(this.parsePipe());
13991 } while (this.consumeOptionalCharacter($COMMA));
13992 this.rbracesExpected--;
13993 this.expectCharacter($RBRACE);
13994 }
13995 return new LiteralMap(this.span(start), this.sourceSpan(start), keys, values);
13996 }
13997 parseAccessMemberOrMethodCall(receiver, start, isSafe = false) {
13998 const nameStart = this.inputIndex;
13999 const id = this.withContext(ParseContextFlags.Writable, () => {
14000 var _a;
14001 const id = (_a = this.expectIdentifierOrKeyword()) !== null && _a !== void 0 ? _a : '';
14002 if (id.length === 0) {
14003 this.error(`Expected identifier for property access`, receiver.span.end);
14004 }
14005 return id;
14006 });
14007 const nameSpan = this.sourceSpan(nameStart);
14008 if (this.consumeOptionalCharacter($LPAREN)) {
14009 this.rparensExpected++;
14010 const args = this.parseCallArguments();
14011 this.expectCharacter($RPAREN);
14012 this.rparensExpected--;
14013 const span = this.span(start);
14014 const sourceSpan = this.sourceSpan(start);
14015 return isSafe ? new SafeMethodCall(span, sourceSpan, nameSpan, receiver, id, args) :
14016 new MethodCall(span, sourceSpan, nameSpan, receiver, id, args);
14017 }
14018 else {
14019 if (isSafe) {
14020 if (this.consumeOptionalOperator('=')) {
14021 this.error('The \'?.\' operator cannot be used in the assignment');
14022 return new EmptyExpr(this.span(start), this.sourceSpan(start));
14023 }
14024 else {
14025 return new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
14026 }
14027 }
14028 else {
14029 if (this.consumeOptionalOperator('=')) {
14030 if (!this.parseAction) {
14031 this.error('Bindings cannot contain assignments');
14032 return new EmptyExpr(this.span(start), this.sourceSpan(start));
14033 }
14034 const value = this.parseConditional();
14035 return new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, receiver, id, value);
14036 }
14037 else {
14038 return new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
14039 }
14040 }
14041 }
14042 }
14043 parseCallArguments() {
14044 if (this.next.isCharacter($RPAREN))
14045 return [];
14046 const positionals = [];
14047 do {
14048 positionals.push(this.parsePipe());
14049 } while (this.consumeOptionalCharacter($COMMA));
14050 return positionals;
14051 }
14052 /**
14053 * Parses an identifier, a keyword, a string with an optional `-` in between,
14054 * and returns the string along with its absolute source span.
14055 */
14056 expectTemplateBindingKey() {
14057 let result = '';
14058 let operatorFound = false;
14059 const start = this.currentAbsoluteOffset;
14060 do {
14061 result += this.expectIdentifierOrKeywordOrString();
14062 operatorFound = this.consumeOptionalOperator('-');
14063 if (operatorFound) {
14064 result += '-';
14065 }
14066 } while (operatorFound);
14067 return {
14068 source: result,
14069 span: new AbsoluteSourceSpan(start, start + result.length),
14070 };
14071 }
14072 /**
14073 * Parse microsyntax template expression and return a list of bindings or
14074 * parsing errors in case the given expression is invalid.
14075 *
14076 * For example,
14077 * ```
14078 * <div *ngFor="let item of items; index as i; trackBy: func">
14079 * ```
14080 * contains five bindings:
14081 * 1. ngFor -> null
14082 * 2. item -> NgForOfContext.$implicit
14083 * 3. ngForOf -> items
14084 * 4. i -> NgForOfContext.index
14085 * 5. ngForTrackBy -> func
14086 *
14087 * For a full description of the microsyntax grammar, see
14088 * https://gist.github.com/mhevery/d3530294cff2e4a1b3fe15ff75d08855
14089 *
14090 * @param templateKey name of the microsyntax directive, like ngIf, ngFor,
14091 * without the *, along with its absolute span.
14092 */
14093 parseTemplateBindings(templateKey) {
14094 const bindings = [];
14095 // The first binding is for the template key itself
14096 // In *ngFor="let item of items", key = "ngFor", value = null
14097 // In *ngIf="cond | pipe", key = "ngIf", value = "cond | pipe"
14098 bindings.push(...this.parseDirectiveKeywordBindings(templateKey));
14099 while (this.index < this.tokens.length) {
14100 // If it starts with 'let', then this must be variable declaration
14101 const letBinding = this.parseLetBinding();
14102 if (letBinding) {
14103 bindings.push(letBinding);
14104 }
14105 else {
14106 // Two possible cases here, either `value "as" key` or
14107 // "directive-keyword expression". We don't know which case, but both
14108 // "value" and "directive-keyword" are template binding key, so consume
14109 // the key first.
14110 const key = this.expectTemplateBindingKey();
14111 // Peek at the next token, if it is "as" then this must be variable
14112 // declaration.
14113 const binding = this.parseAsBinding(key);
14114 if (binding) {
14115 bindings.push(binding);
14116 }
14117 else {
14118 // Otherwise the key must be a directive keyword, like "of". Transform
14119 // the key to actual key. Eg. of -> ngForOf, trackBy -> ngForTrackBy
14120 key.source =
14121 templateKey.source + key.source.charAt(0).toUpperCase() + key.source.substring(1);
14122 bindings.push(...this.parseDirectiveKeywordBindings(key));
14123 }
14124 }
14125 this.consumeStatementTerminator();
14126 }
14127 return new TemplateBindingParseResult(bindings, [] /* warnings */, this.errors);
14128 }
14129 /**
14130 * Parse a directive keyword, followed by a mandatory expression.
14131 * For example, "of items", "trackBy: func".
14132 * The bindings are: ngForOf -> items, ngForTrackBy -> func
14133 * There could be an optional "as" binding that follows the expression.
14134 * For example,
14135 * ```
14136 * *ngFor="let item of items | slice:0:1 as collection".
14137 * ^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
14138 * keyword bound target optional 'as' binding
14139 * ```
14140 *
14141 * @param key binding key, for example, ngFor, ngIf, ngForOf, along with its
14142 * absolute span.
14143 */
14144 parseDirectiveKeywordBindings(key) {
14145 const bindings = [];
14146 this.consumeOptionalCharacter($COLON); // trackBy: trackByFunction
14147 const value = this.getDirectiveBoundTarget();
14148 let spanEnd = this.currentAbsoluteOffset;
14149 // The binding could optionally be followed by "as". For example,
14150 // *ngIf="cond | pipe as x". In this case, the key in the "as" binding
14151 // is "x" and the value is the template key itself ("ngIf"). Note that the
14152 // 'key' in the current context now becomes the "value" in the next binding.
14153 const asBinding = this.parseAsBinding(key);
14154 if (!asBinding) {
14155 this.consumeStatementTerminator();
14156 spanEnd = this.currentAbsoluteOffset;
14157 }
14158 const sourceSpan = new AbsoluteSourceSpan(key.span.start, spanEnd);
14159 bindings.push(new ExpressionBinding(sourceSpan, key, value));
14160 if (asBinding) {
14161 bindings.push(asBinding);
14162 }
14163 return bindings;
14164 }
14165 /**
14166 * Return the expression AST for the bound target of a directive keyword
14167 * binding. For example,
14168 * ```
14169 * *ngIf="condition | pipe"
14170 * ^^^^^^^^^^^^^^^^ bound target for "ngIf"
14171 * *ngFor="let item of items"
14172 * ^^^^^ bound target for "ngForOf"
14173 * ```
14174 */
14175 getDirectiveBoundTarget() {
14176 if (this.next === EOF || this.peekKeywordAs() || this.peekKeywordLet()) {
14177 return null;
14178 }
14179 const ast = this.parsePipe(); // example: "condition | async"
14180 const { start, end } = ast.span;
14181 const value = this.input.substring(start, end);
14182 return new ASTWithSource(ast, value, this.location, this.absoluteOffset + start, this.errors);
14183 }
14184 /**
14185 * Return the binding for a variable declared using `as`. Note that the order
14186 * of the key-value pair in this declaration is reversed. For example,
14187 * ```
14188 * *ngFor="let item of items; index as i"
14189 * ^^^^^ ^
14190 * value key
14191 * ```
14192 *
14193 * @param value name of the value in the declaration, "ngIf" in the example
14194 * above, along with its absolute span.
14195 */
14196 parseAsBinding(value) {
14197 if (!this.peekKeywordAs()) {
14198 return null;
14199 }
14200 this.advance(); // consume the 'as' keyword
14201 const key = this.expectTemplateBindingKey();
14202 this.consumeStatementTerminator();
14203 const sourceSpan = new AbsoluteSourceSpan(value.span.start, this.currentAbsoluteOffset);
14204 return new VariableBinding(sourceSpan, key, value);
14205 }
14206 /**
14207 * Return the binding for a variable declared using `let`. For example,
14208 * ```
14209 * *ngFor="let item of items; let i=index;"
14210 * ^^^^^^^^ ^^^^^^^^^^^
14211 * ```
14212 * In the first binding, `item` is bound to `NgForOfContext.$implicit`.
14213 * In the second binding, `i` is bound to `NgForOfContext.index`.
14214 */
14215 parseLetBinding() {
14216 if (!this.peekKeywordLet()) {
14217 return null;
14218 }
14219 const spanStart = this.currentAbsoluteOffset;
14220 this.advance(); // consume the 'let' keyword
14221 const key = this.expectTemplateBindingKey();
14222 let value = null;
14223 if (this.consumeOptionalOperator('=')) {
14224 value = this.expectTemplateBindingKey();
14225 }
14226 this.consumeStatementTerminator();
14227 const sourceSpan = new AbsoluteSourceSpan(spanStart, this.currentAbsoluteOffset);
14228 return new VariableBinding(sourceSpan, key, value);
14229 }
14230 /**
14231 * Consume the optional statement terminator: semicolon or comma.
14232 */
14233 consumeStatementTerminator() {
14234 this.consumeOptionalCharacter($SEMICOLON) || this.consumeOptionalCharacter($COMMA);
14235 }
14236 /**
14237 * Records an error and skips over the token stream until reaching a recoverable point. See
14238 * `this.skip` for more details on token skipping.
14239 */
14240 error(message, index = null) {
14241 this.errors.push(new ParserError(message, this.input, this.locationText(index), this.location));
14242 this.skip();
14243 }
14244 locationText(index = null) {
14245 if (index == null)
14246 index = this.index;
14247 return (index < this.tokens.length) ? `at column ${this.tokens[index].index + 1} in` :
14248 `at the end of the expression`;
14249 }
14250 /**
14251 * Error recovery should skip tokens until it encounters a recovery point.
14252 *
14253 * The following are treated as unconditional recovery points:
14254 * - end of input
14255 * - ';' (parseChain() is always the root production, and it expects a ';')
14256 * - '|' (since pipes may be chained and each pipe expression may be treated independently)
14257 *
14258 * The following are conditional recovery points:
14259 * - ')', '}', ']' if one of calling productions is expecting one of these symbols
14260 * - This allows skip() to recover from errors such as '(a.) + 1' allowing more of the AST to
14261 * be retained (it doesn't skip any tokens as the ')' is retained because of the '(' begins
14262 * an '(' <expr> ')' production).
14263 * The recovery points of grouping symbols must be conditional as they must be skipped if
14264 * none of the calling productions are not expecting the closing token else we will never
14265 * make progress in the case of an extraneous group closing symbol (such as a stray ')').
14266 * That is, we skip a closing symbol if we are not in a grouping production.
14267 * - '=' in a `Writable` context
14268 * - In this context, we are able to recover after seeing the `=` operator, which
14269 * signals the presence of an independent rvalue expression following the `=` operator.
14270 *
14271 * If a production expects one of these token it increments the corresponding nesting count,
14272 * and then decrements it just prior to checking if the token is in the input.
14273 */
14274 skip() {
14275 let n = this.next;
14276 while (this.index < this.tokens.length && !n.isCharacter($SEMICOLON) &&
14277 !n.isOperator('|') && (this.rparensExpected <= 0 || !n.isCharacter($RPAREN)) &&
14278 (this.rbracesExpected <= 0 || !n.isCharacter($RBRACE)) &&
14279 (this.rbracketsExpected <= 0 || !n.isCharacter($RBRACKET)) &&
14280 (!(this.context & ParseContextFlags.Writable) || !n.isOperator('='))) {
14281 if (this.next.isError()) {
14282 this.errors.push(new ParserError(this.next.toString(), this.input, this.locationText(), this.location));
14283 }
14284 this.advance();
14285 n = this.next;
14286 }
14287 }
14288 }
14289 class SimpleExpressionChecker {
14290 constructor() {
14291 this.errors = [];
14292 }
14293 visitImplicitReceiver(ast, context) { }
14294 visitThisReceiver(ast, context) { }
14295 visitInterpolation(ast, context) { }
14296 visitLiteralPrimitive(ast, context) { }
14297 visitPropertyRead(ast, context) { }
14298 visitPropertyWrite(ast, context) { }
14299 visitSafePropertyRead(ast, context) { }
14300 visitMethodCall(ast, context) { }
14301 visitSafeMethodCall(ast, context) { }
14302 visitFunctionCall(ast, context) { }
14303 visitLiteralArray(ast, context) {
14304 this.visitAll(ast.expressions, context);
14305 }
14306 visitLiteralMap(ast, context) {
14307 this.visitAll(ast.values, context);
14308 }
14309 visitUnary(ast, context) { }
14310 visitBinary(ast, context) { }
14311 visitPrefixNot(ast, context) { }
14312 visitNonNullAssert(ast, context) { }
14313 visitConditional(ast, context) { }
14314 visitPipe(ast, context) {
14315 this.errors.push('pipes');
14316 }
14317 visitKeyedRead(ast, context) { }
14318 visitKeyedWrite(ast, context) { }
14319 visitAll(asts, context) {
14320 return asts.map(node => node.visit(this, context));
14321 }
14322 visitChain(ast, context) { }
14323 visitQuote(ast, context) { }
14324 }
14325 /**
14326 * This class implements SimpleExpressionChecker used in View Engine and performs more strict checks
14327 * to make sure host bindings do not contain pipes. In View Engine, having pipes in host bindings is
14328 * not supported as well, but in some cases (like `!(value | async)`) the error is not triggered at
14329 * compile time. In order to preserve View Engine behavior, more strict checks are introduced for
14330 * Ivy mode only.
14331 */
14332 class IvySimpleExpressionChecker extends RecursiveAstVisitor {
14333 constructor() {
14334 super(...arguments);
14335 this.errors = [];
14336 }
14337 visitPipe() {
14338 this.errors.push('pipes');
14339 }
14340 }
14341
14342 /**
14343 * @license
14344 * Copyright Google LLC All Rights Reserved.
14345 *
14346 * Use of this source code is governed by an MIT-style license that can be
14347 * found in the LICENSE file at https://angular.io/license
14348 */
14349 // =================================================================================================
14350 // =================================================================================================
14351 // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
14352 // =================================================================================================
14353 // =================================================================================================
14354 //
14355 // DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
14356 // Reach out to mprobst for details.
14357 //
14358 // =================================================================================================
14359 /** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */
14360 let _SECURITY_SCHEMA;
14361 function SECURITY_SCHEMA() {
14362 if (!_SECURITY_SCHEMA) {
14363 _SECURITY_SCHEMA = {};
14364 // Case is insignificant below, all element and attribute names are lower-cased for lookup.
14365 registerContext(SecurityContext.HTML, [
14366 'iframe|srcdoc',
14367 '*|innerHTML',
14368 '*|outerHTML',
14369 ]);
14370 registerContext(SecurityContext.STYLE, ['*|style']);
14371 // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
14372 registerContext(SecurityContext.URL, [
14373 '*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href',
14374 'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action',
14375 'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite',
14376 'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src',
14377 ]);
14378 registerContext(SecurityContext.RESOURCE_URL, [
14379 'applet|code',
14380 'applet|codebase',
14381 'base|href',
14382 'embed|src',
14383 'frame|src',
14384 'head|profile',
14385 'html|manifest',
14386 'iframe|src',
14387 'link|href',
14388 'media|src',
14389 'object|codebase',
14390 'object|data',
14391 'script|src',
14392 ]);
14393 }
14394 return _SECURITY_SCHEMA;
14395 }
14396 function registerContext(ctx, specs) {
14397 for (const spec of specs)
14398 _SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
14399 }
14400
14401 /**
14402 * @license
14403 * Copyright Google LLC All Rights Reserved.
14404 *
14405 * Use of this source code is governed by an MIT-style license that can be
14406 * found in the LICENSE file at https://angular.io/license
14407 */
14408 class ElementSchemaRegistry {
14409 }
14410
14411 /**
14412 * @license
14413 * Copyright Google LLC All Rights Reserved.
14414 *
14415 * Use of this source code is governed by an MIT-style license that can be
14416 * found in the LICENSE file at https://angular.io/license
14417 */
14418 const BOOLEAN = 'boolean';
14419 const NUMBER = 'number';
14420 const STRING = 'string';
14421 const OBJECT = 'object';
14422 /**
14423 * This array represents the DOM schema. It encodes inheritance, properties, and events.
14424 *
14425 * ## Overview
14426 *
14427 * Each line represents one kind of element. The `element_inheritance` and properties are joined
14428 * using `element_inheritance|properties` syntax.
14429 *
14430 * ## Element Inheritance
14431 *
14432 * The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
14433 * Here the individual elements are separated by `,` (commas). Every element in the list
14434 * has identical properties.
14435 *
14436 * An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
14437 * specified then `""` (blank) element is assumed.
14438 *
14439 * NOTE: The blank element inherits from root `[Element]` element, the super element of all
14440 * elements.
14441 *
14442 * NOTE an element prefix such as `:svg:` has no special meaning to the schema.
14443 *
14444 * ## Properties
14445 *
14446 * Each element has a set of properties separated by `,` (commas). Each property can be prefixed
14447 * by a special character designating its type:
14448 *
14449 * - (no prefix): property is a string.
14450 * - `*`: property represents an event.
14451 * - `!`: property is a boolean.
14452 * - `#`: property is a number.
14453 * - `%`: property is an object.
14454 *
14455 * ## Query
14456 *
14457 * The class creates an internal squas representation which allows to easily answer the query of
14458 * if a given property exist on a given element.
14459 *
14460 * NOTE: We don't yet support querying for types or events.
14461 * NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder,
14462 * see dom_element_schema_registry_spec.ts
14463 */
14464 // =================================================================================================
14465 // =================================================================================================
14466 // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
14467 // =================================================================================================
14468 // =================================================================================================
14469 //
14470 // DO NOT EDIT THIS DOM SCHEMA WITHOUT A SECURITY REVIEW!
14471 //
14472 // Newly added properties must be security reviewed and assigned an appropriate SecurityContext in
14473 // dom_security_schema.ts. Reach out to mprobst & rjamet for details.
14474 //
14475 // =================================================================================================
14476 const SCHEMA = [
14477 '[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop,slot' +
14478 /* added manually to avoid breaking changes */
14479 ',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored',
14480 '[HTMLElement]^[Element]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
14481 'abbr,address,article,aside,b,bdi,bdo,cite,code,dd,dfn,dt,em,figcaption,figure,footer,header,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,section,small,strong,sub,sup,u,var,wbr^[HTMLElement]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
14482 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume',
14483 ':svg:^[HTMLElement]|*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,%style,#tabIndex',
14484 ':svg:graphics^:svg:|',
14485 ':svg:animation^:svg:|*begin,*end,*repeat',
14486 ':svg:geometry^:svg:|',
14487 ':svg:componentTransferFunction^:svg:|',
14488 ':svg:gradient^:svg:|',
14489 ':svg:textContent^:svg:graphics|',
14490 ':svg:textPositioning^:svg:textContent|',
14491 'a^[HTMLElement]|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,referrerPolicy,rel,rev,search,shape,target,text,type,username',
14492 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username',
14493 'audio^media|',
14494 'br^[HTMLElement]|clear',
14495 'base^[HTMLElement]|href,target',
14496 'body^[HTMLElement]|aLink,background,bgColor,link,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink',
14497 'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
14498 'canvas^[HTMLElement]|#height,#width',
14499 'content^[HTMLElement]|select',
14500 'dl^[HTMLElement]|!compact',
14501 'datalist^[HTMLElement]|',
14502 'details^[HTMLElement]|!open',
14503 'dialog^[HTMLElement]|!open,returnValue',
14504 'dir^[HTMLElement]|!compact',
14505 'div^[HTMLElement]|align',
14506 'embed^[HTMLElement]|align,height,name,src,type,width',
14507 'fieldset^[HTMLElement]|!disabled,name',
14508 'font^[HTMLElement]|color,face,size',
14509 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
14510 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
14511 'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
14512 'hr^[HTMLElement]|align,color,!noShade,size,width',
14513 'head^[HTMLElement]|',
14514 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align',
14515 'html^[HTMLElement]|version',
14516 'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width',
14517 'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width',
14518 'input^[HTMLElement]|accept,align,alt,autocapitalize,autocomplete,!autofocus,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width',
14519 'li^[HTMLElement]|type,#value',
14520 'label^[HTMLElement]|htmlFor',
14521 'legend^[HTMLElement]|align',
14522 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type',
14523 'map^[HTMLElement]|name',
14524 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
14525 'menu^[HTMLElement]|!compact',
14526 'meta^[HTMLElement]|content,httpEquiv,name,scheme',
14527 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value',
14528 'ins,del^[HTMLElement]|cite,dateTime',
14529 'ol^[HTMLElement]|!compact,!reversed,#start,type',
14530 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
14531 'optgroup^[HTMLElement]|!disabled,label',
14532 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value',
14533 'output^[HTMLElement]|defaultValue,%htmlFor,name,value',
14534 'p^[HTMLElement]|align',
14535 'param^[HTMLElement]|name,type,value,valueType',
14536 'picture^[HTMLElement]|',
14537 'pre^[HTMLElement]|#width',
14538 'progress^[HTMLElement]|#max,#value',
14539 'q,blockquote,cite^[HTMLElement]|',
14540 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
14541 'select^[HTMLElement]|!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
14542 'shadow^[HTMLElement]|',
14543 'slot^[HTMLElement]|name',
14544 'source^[HTMLElement]|media,sizes,src,srcset,type',
14545 'span^[HTMLElement]|',
14546 'style^[HTMLElement]|!disabled,media,type',
14547 'caption^[HTMLElement]|align',
14548 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
14549 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width',
14550 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
14551 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign',
14552 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign',
14553 'template^[HTMLElement]|',
14554 'textarea^[HTMLElement]|autocapitalize,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
14555 'title^[HTMLElement]|text',
14556 'track^[HTMLElement]|!default,kind,label,src,srclang',
14557 'ul^[HTMLElement]|!compact,type',
14558 'unknown^[HTMLElement]|',
14559 'video^media|#height,poster,#width',
14560 ':svg:a^:svg:graphics|',
14561 ':svg:animate^:svg:animation|',
14562 ':svg:animateMotion^:svg:animation|',
14563 ':svg:animateTransform^:svg:animation|',
14564 ':svg:circle^:svg:geometry|',
14565 ':svg:clipPath^:svg:graphics|',
14566 ':svg:defs^:svg:graphics|',
14567 ':svg:desc^:svg:|',
14568 ':svg:discard^:svg:|',
14569 ':svg:ellipse^:svg:geometry|',
14570 ':svg:feBlend^:svg:|',
14571 ':svg:feColorMatrix^:svg:|',
14572 ':svg:feComponentTransfer^:svg:|',
14573 ':svg:feComposite^:svg:|',
14574 ':svg:feConvolveMatrix^:svg:|',
14575 ':svg:feDiffuseLighting^:svg:|',
14576 ':svg:feDisplacementMap^:svg:|',
14577 ':svg:feDistantLight^:svg:|',
14578 ':svg:feDropShadow^:svg:|',
14579 ':svg:feFlood^:svg:|',
14580 ':svg:feFuncA^:svg:componentTransferFunction|',
14581 ':svg:feFuncB^:svg:componentTransferFunction|',
14582 ':svg:feFuncG^:svg:componentTransferFunction|',
14583 ':svg:feFuncR^:svg:componentTransferFunction|',
14584 ':svg:feGaussianBlur^:svg:|',
14585 ':svg:feImage^:svg:|',
14586 ':svg:feMerge^:svg:|',
14587 ':svg:feMergeNode^:svg:|',
14588 ':svg:feMorphology^:svg:|',
14589 ':svg:feOffset^:svg:|',
14590 ':svg:fePointLight^:svg:|',
14591 ':svg:feSpecularLighting^:svg:|',
14592 ':svg:feSpotLight^:svg:|',
14593 ':svg:feTile^:svg:|',
14594 ':svg:feTurbulence^:svg:|',
14595 ':svg:filter^:svg:|',
14596 ':svg:foreignObject^:svg:graphics|',
14597 ':svg:g^:svg:graphics|',
14598 ':svg:image^:svg:graphics|',
14599 ':svg:line^:svg:geometry|',
14600 ':svg:linearGradient^:svg:gradient|',
14601 ':svg:mpath^:svg:|',
14602 ':svg:marker^:svg:|',
14603 ':svg:mask^:svg:|',
14604 ':svg:metadata^:svg:|',
14605 ':svg:path^:svg:geometry|',
14606 ':svg:pattern^:svg:|',
14607 ':svg:polygon^:svg:geometry|',
14608 ':svg:polyline^:svg:geometry|',
14609 ':svg:radialGradient^:svg:gradient|',
14610 ':svg:rect^:svg:geometry|',
14611 ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan',
14612 ':svg:script^:svg:|type',
14613 ':svg:set^:svg:animation|',
14614 ':svg:stop^:svg:|',
14615 ':svg:style^:svg:|!disabled,media,title,type',
14616 ':svg:switch^:svg:graphics|',
14617 ':svg:symbol^:svg:|',
14618 ':svg:tspan^:svg:textPositioning|',
14619 ':svg:text^:svg:textPositioning|',
14620 ':svg:textPath^:svg:textContent|',
14621 ':svg:title^:svg:|',
14622 ':svg:use^:svg:graphics|',
14623 ':svg:view^:svg:|#zoomAndPan',
14624 'data^[HTMLElement]|value',
14625 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name',
14626 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
14627 'summary^[HTMLElement]|',
14628 'time^[HTMLElement]|dateTime',
14629 ':svg:cursor^:svg:|',
14630 ];
14631 const _ATTR_TO_PROP = {
14632 'class': 'className',
14633 'for': 'htmlFor',
14634 'formaction': 'formAction',
14635 'innerHtml': 'innerHTML',
14636 'readonly': 'readOnly',
14637 'tabindex': 'tabIndex',
14638 };
14639 // Invert _ATTR_TO_PROP.
14640 const _PROP_TO_ATTR = Object.keys(_ATTR_TO_PROP).reduce((inverted, attr) => {
14641 inverted[_ATTR_TO_PROP[attr]] = attr;
14642 return inverted;
14643 }, {});
14644 class DomElementSchemaRegistry extends ElementSchemaRegistry {
14645 constructor() {
14646 super();
14647 this._schema = {};
14648 SCHEMA.forEach(encodedType => {
14649 const type = {};
14650 const [strType, strProperties] = encodedType.split('|');
14651 const properties = strProperties.split(',');
14652 const [typeNames, superName] = strType.split('^');
14653 typeNames.split(',').forEach(tag => this._schema[tag.toLowerCase()] = type);
14654 const superType = superName && this._schema[superName.toLowerCase()];
14655 if (superType) {
14656 Object.keys(superType).forEach((prop) => {
14657 type[prop] = superType[prop];
14658 });
14659 }
14660 properties.forEach((property) => {
14661 if (property.length > 0) {
14662 switch (property[0]) {
14663 case '*':
14664 // We don't yet support events.
14665 // If ever allowing to bind to events, GO THROUGH A SECURITY REVIEW, allowing events
14666 // will
14667 // almost certainly introduce bad XSS vulnerabilities.
14668 // type[property.substring(1)] = EVENT;
14669 break;
14670 case '!':
14671 type[property.substring(1)] = BOOLEAN;
14672 break;
14673 case '#':
14674 type[property.substring(1)] = NUMBER;
14675 break;
14676 case '%':
14677 type[property.substring(1)] = OBJECT;
14678 break;
14679 default:
14680 type[property] = STRING;
14681 }
14682 }
14683 });
14684 });
14685 }
14686 hasProperty(tagName, propName, schemaMetas) {
14687 if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) {
14688 return true;
14689 }
14690 if (tagName.indexOf('-') > -1) {
14691 if (isNgContainer(tagName) || isNgContent(tagName)) {
14692 return false;
14693 }
14694 if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
14695 // Can't tell now as we don't know which properties a custom element will get
14696 // once it is instantiated
14697 return true;
14698 }
14699 }
14700 const elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
14701 return !!elementProperties[propName];
14702 }
14703 hasElement(tagName, schemaMetas) {
14704 if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) {
14705 return true;
14706 }
14707 if (tagName.indexOf('-') > -1) {
14708 if (isNgContainer(tagName) || isNgContent(tagName)) {
14709 return true;
14710 }
14711 if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
14712 // Allow any custom elements
14713 return true;
14714 }
14715 }
14716 return !!this._schema[tagName.toLowerCase()];
14717 }
14718 /**
14719 * securityContext returns the security context for the given property on the given DOM tag.
14720 *
14721 * Tag and property name are statically known and cannot change at runtime, i.e. it is not
14722 * possible to bind a value into a changing attribute or tag name.
14723 *
14724 * The filtering is based on a list of allowed tags|attributes. All attributes in the schema
14725 * above are assumed to have the 'NONE' security context, i.e. that they are safe inert
14726 * string values. Only specific well known attack vectors are assigned their appropriate context.
14727 */
14728 securityContext(tagName, propName, isAttribute) {
14729 if (isAttribute) {
14730 // NB: For security purposes, use the mapped property name, not the attribute name.
14731 propName = this.getMappedPropName(propName);
14732 }
14733 // Make sure comparisons are case insensitive, so that case differences between attribute and
14734 // property names do not have a security impact.
14735 tagName = tagName.toLowerCase();
14736 propName = propName.toLowerCase();
14737 let ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
14738 if (ctx) {
14739 return ctx;
14740 }
14741 ctx = SECURITY_SCHEMA()['*|' + propName];
14742 return ctx ? ctx : SecurityContext.NONE;
14743 }
14744 getMappedPropName(propName) {
14745 return _ATTR_TO_PROP[propName] || propName;
14746 }
14747 getDefaultComponentElementName() {
14748 return 'ng-component';
14749 }
14750 validateProperty(name) {
14751 if (name.toLowerCase().startsWith('on')) {
14752 const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
14753 `please use (${name.slice(2)})=...` +
14754 `\nIf '${name}' is a directive input, make sure the directive is imported by the` +
14755 ` current module.`;
14756 return { error: true, msg: msg };
14757 }
14758 else {
14759 return { error: false };
14760 }
14761 }
14762 validateAttribute(name) {
14763 if (name.toLowerCase().startsWith('on')) {
14764 const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
14765 `please use (${name.slice(2)})=...`;
14766 return { error: true, msg: msg };
14767 }
14768 else {
14769 return { error: false };
14770 }
14771 }
14772 allKnownElementNames() {
14773 return Object.keys(this._schema);
14774 }
14775 allKnownAttributesOfElement(tagName) {
14776 const elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
14777 // Convert properties to attributes.
14778 return Object.keys(elementProperties).map(prop => { var _a; return (_a = _PROP_TO_ATTR[prop]) !== null && _a !== void 0 ? _a : prop; });
14779 }
14780 normalizeAnimationStyleProperty(propName) {
14781 return dashCaseToCamelCase(propName);
14782 }
14783 normalizeAnimationStyleValue(camelCaseProp, userProvidedProp, val) {
14784 let unit = '';
14785 const strVal = val.toString().trim();
14786 let errorMsg = null;
14787 if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
14788 if (typeof val === 'number') {
14789 unit = 'px';
14790 }
14791 else {
14792 const valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/);
14793 if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
14794 errorMsg = `Please provide a CSS unit value for ${userProvidedProp}:${val}`;
14795 }
14796 }
14797 }
14798 return { error: errorMsg, value: strVal + unit };
14799 }
14800 }
14801 function _isPixelDimensionStyle(prop) {
14802 switch (prop) {
14803 case 'width':
14804 case 'height':
14805 case 'minWidth':
14806 case 'minHeight':
14807 case 'maxWidth':
14808 case 'maxHeight':
14809 case 'left':
14810 case 'top':
14811 case 'bottom':
14812 case 'right':
14813 case 'fontSize':
14814 case 'outlineWidth':
14815 case 'outlineOffset':
14816 case 'paddingTop':
14817 case 'paddingLeft':
14818 case 'paddingBottom':
14819 case 'paddingRight':
14820 case 'marginTop':
14821 case 'marginLeft':
14822 case 'marginBottom':
14823 case 'marginRight':
14824 case 'borderRadius':
14825 case 'borderWidth':
14826 case 'borderTopWidth':
14827 case 'borderLeftWidth':
14828 case 'borderRightWidth':
14829 case 'borderBottomWidth':
14830 case 'textIndent':
14831 return true;
14832 default:
14833 return false;
14834 }
14835 }
14836
14837 /**
14838 * @license
14839 * Copyright Google LLC All Rights Reserved.
14840 *
14841 * Use of this source code is governed by an MIT-style license that can be
14842 * found in the LICENSE file at https://angular.io/license
14843 */
14844 /**
14845 * Set of tagName|propertyName corresponding to Trusted Types sinks. Properties applying to all
14846 * tags use '*'.
14847 *
14848 * Extracted from, and should be kept in sync with
14849 * https://w3c.github.io/webappsec-trusted-types/dist/spec/#integrations
14850 */
14851 const TRUSTED_TYPES_SINKS = new Set([
14852 // NOTE: All strings in this set *must* be lowercase!
14853 // TrustedHTML
14854 'iframe|srcdoc',
14855 '*|innerhtml',
14856 '*|outerhtml',
14857 // NB: no TrustedScript here, as the corresponding tags are stripped by the compiler.
14858 // TrustedScriptURL
14859 'embed|src',
14860 'object|codebase',
14861 'object|data',
14862 ]);
14863 /**
14864 * isTrustedTypesSink returns true if the given property on the given DOM tag is a Trusted Types
14865 * sink. In that case, use `ElementSchemaRegistry.securityContext` to determine which particular
14866 * Trusted Type is required for values passed to the sink:
14867 * - SecurityContext.HTML corresponds to TrustedHTML
14868 * - SecurityContext.RESOURCE_URL corresponds to TrustedScriptURL
14869 */
14870 function isTrustedTypesSink(tagName, propName) {
14871 // Make sure comparisons are case insensitive, so that case differences between attribute and
14872 // property names do not have a security impact.
14873 tagName = tagName.toLowerCase();
14874 propName = propName.toLowerCase();
14875 return TRUSTED_TYPES_SINKS.has(tagName + '|' + propName) ||
14876 TRUSTED_TYPES_SINKS.has('*|' + propName);
14877 }
14878
14879 /**
14880 * @license
14881 * Copyright Google LLC All Rights Reserved.
14882 *
14883 * Use of this source code is governed by an MIT-style license that can be
14884 * found in the LICENSE file at https://angular.io/license
14885 */
14886 const BIND_NAME_REGEXP$1 = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
14887 // Group 1 = "bind-"
14888 const KW_BIND_IDX$1 = 1;
14889 // Group 2 = "let-"
14890 const KW_LET_IDX$1 = 2;
14891 // Group 3 = "ref-/#"
14892 const KW_REF_IDX$1 = 3;
14893 // Group 4 = "on-"
14894 const KW_ON_IDX$1 = 4;
14895 // Group 5 = "bindon-"
14896 const KW_BINDON_IDX$1 = 5;
14897 // Group 6 = "@"
14898 const KW_AT_IDX$1 = 6;
14899 // Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
14900 const IDENT_KW_IDX$1 = 7;
14901 const BINDING_DELIMS = {
14902 BANANA_BOX: { start: '[(', end: ')]' },
14903 PROPERTY: { start: '[', end: ']' },
14904 EVENT: { start: '(', end: ')' },
14905 };
14906 const TEMPLATE_ATTR_PREFIX$2 = '*';
14907 function htmlAstToRender3Ast(htmlNodes, bindingParser) {
14908 const transformer = new HtmlAstToIvyAst(bindingParser);
14909 const ivyNodes = visitAll$1(transformer, htmlNodes);
14910 // Errors might originate in either the binding parser or the html to ivy transformer
14911 const allErrors = bindingParser.errors.concat(transformer.errors);
14912 return {
14913 nodes: ivyNodes,
14914 errors: allErrors,
14915 styleUrls: transformer.styleUrls,
14916 styles: transformer.styles,
14917 ngContentSelectors: transformer.ngContentSelectors,
14918 };
14919 }
14920 class HtmlAstToIvyAst {
14921 constructor(bindingParser) {
14922 this.bindingParser = bindingParser;
14923 this.errors = [];
14924 this.styles = [];
14925 this.styleUrls = [];
14926 this.ngContentSelectors = [];
14927 this.inI18nBlock = false;
14928 }
14929 // HTML visitor
14930 visitElement(element) {
14931 const isI18nRootElement = isI18nRootNode(element.i18n);
14932 if (isI18nRootElement) {
14933 if (this.inI18nBlock) {
14934 this.reportError('Cannot mark an element as translatable inside of a translatable section. Please remove the nested i18n marker.', element.sourceSpan);
14935 }
14936 this.inI18nBlock = true;
14937 }
14938 const preparsedElement = preparseElement(element);
14939 if (preparsedElement.type === PreparsedElementType.SCRIPT) {
14940 return null;
14941 }
14942 else if (preparsedElement.type === PreparsedElementType.STYLE) {
14943 const contents = textContents(element);
14944 if (contents !== null) {
14945 this.styles.push(contents);
14946 }
14947 return null;
14948 }
14949 else if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
14950 isStyleUrlResolvable(preparsedElement.hrefAttr)) {
14951 this.styleUrls.push(preparsedElement.hrefAttr);
14952 return null;
14953 }
14954 // Whether the element is a `<ng-template>`
14955 const isTemplateElement = isNgTemplate(element.name);
14956 const parsedProperties = [];
14957 const boundEvents = [];
14958 const variables = [];
14959 const references = [];
14960 const attributes = [];
14961 const i18nAttrsMeta = {};
14962 const templateParsedProperties = [];
14963 const templateVariables = [];
14964 // Whether the element has any *-attribute
14965 let elementHasInlineTemplate = false;
14966 for (const attribute of element.attrs) {
14967 let hasBinding = false;
14968 const normalizedName = normalizeAttributeName(attribute.name);
14969 // `*attr` defines template bindings
14970 let isTemplateBinding = false;
14971 if (attribute.i18n) {
14972 i18nAttrsMeta[attribute.name] = attribute.i18n;
14973 }
14974 if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX$2)) {
14975 // *-attributes
14976 if (elementHasInlineTemplate) {
14977 this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan);
14978 }
14979 isTemplateBinding = true;
14980 elementHasInlineTemplate = true;
14981 const templateValue = attribute.value;
14982 const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX$2.length);
14983 const parsedVariables = [];
14984 const absoluteValueOffset = attribute.valueSpan ?
14985 attribute.valueSpan.start.offset :
14986 // If there is no value span the attribute does not have a value, like `attr` in
14987 //`<div attr></div>`. In this case, point to one character beyond the last character of
14988 // the attribute name.
14989 attribute.sourceSpan.start.offset + attribute.name.length;
14990 this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true /* isIvyAst */);
14991 templateVariables.push(...parsedVariables.map(v => new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan)));
14992 }
14993 else {
14994 // Check for variables, events, property bindings, interpolation
14995 hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
14996 }
14997 if (!hasBinding && !isTemplateBinding) {
14998 // don't include the bindings as attributes as well in the AST
14999 attributes.push(this.visitAttribute(attribute));
15000 }
15001 }
15002 const children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR$1 : this, element.children);
15003 let parsedElement;
15004 if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
15005 // `<ng-content>`
15006 if (element.children &&
15007 !element.children.every((node) => isEmptyTextNode(node) || isCommentNode(node))) {
15008 this.reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
15009 }
15010 const selector = preparsedElement.selectAttr;
15011 const attrs = element.attrs.map(attr => this.visitAttribute(attr));
15012 parsedElement = new Content(selector, attrs, element.sourceSpan, element.i18n);
15013 this.ngContentSelectors.push(selector);
15014 }
15015 else if (isTemplateElement) {
15016 // `<ng-template>`
15017 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
15018 parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, [ /* no template attributes */], children, references, variables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
15019 }
15020 else {
15021 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
15022 parsedElement = new Element(element.name, attributes, attrs.bound, boundEvents, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
15023 }
15024 if (elementHasInlineTemplate) {
15025 // If this node is an inline-template (e.g. has *ngFor) then we need to create a template
15026 // node that contains this node.
15027 // Moreover, if the node is an element, then we need to hoist its attributes to the template
15028 // node for matching against content projection selectors.
15029 const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
15030 const templateAttrs = [];
15031 attrs.literal.forEach(attr => templateAttrs.push(attr));
15032 attrs.bound.forEach(attr => templateAttrs.push(attr));
15033 const hoistedAttrs = parsedElement instanceof Element ?
15034 {
15035 attributes: parsedElement.attributes,
15036 inputs: parsedElement.inputs,
15037 outputs: parsedElement.outputs,
15038 } :
15039 { attributes: [], inputs: [], outputs: [] };
15040 // For <ng-template>s with structural directives on them, avoid passing i18n information to
15041 // the wrapping template to prevent unnecessary i18n instructions from being generated. The
15042 // necessary i18n meta information will be extracted from child elements.
15043 const i18n = isTemplateElement && isI18nRootElement ? undefined : element.i18n;
15044 // TODO(pk): test for this case
15045 parsedElement = new Template(parsedElement.name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, templateAttrs, [parsedElement], [ /* no references */], templateVariables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, i18n);
15046 }
15047 if (isI18nRootElement) {
15048 this.inI18nBlock = false;
15049 }
15050 return parsedElement;
15051 }
15052 visitAttribute(attribute) {
15053 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
15054 }
15055 visitText(text) {
15056 return this._visitTextWithInterpolation(text.value, text.sourceSpan, text.i18n);
15057 }
15058 visitExpansion(expansion) {
15059 if (!expansion.i18n) {
15060 // do not generate Icu in case it was created
15061 // outside of i18n block in a template
15062 return null;
15063 }
15064 if (!isI18nRootNode(expansion.i18n)) {
15065 throw new Error(`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${expansion.sourceSpan.toString()}. Expected a "Message"`);
15066 }
15067 const message = expansion.i18n;
15068 const vars = {};
15069 const placeholders = {};
15070 // extract VARs from ICUs - we process them separately while
15071 // assembling resulting message via goog.getMsg function, since
15072 // we need to pass them to top-level goog.getMsg call
15073 Object.keys(message.placeholders).forEach(key => {
15074 const value = message.placeholders[key];
15075 if (key.startsWith(I18N_ICU_VAR_PREFIX)) {
15076 // Currently when the `plural` or `select` keywords in an ICU contain trailing spaces (e.g.
15077 // `{count, select , ...}`), these spaces are also included into the key names in ICU vars
15078 // (e.g. "VAR_SELECT "). These trailing spaces are not desirable, since they will later be
15079 // converted into `_` symbols while normalizing placeholder names, which might lead to
15080 // mismatches at runtime (i.e. placeholder will not be replaced with the correct value).
15081 const formattedKey = key.trim();
15082 const ast = this.bindingParser.parseInterpolationExpression(value.text, value.sourceSpan);
15083 vars[formattedKey] = new BoundText(ast, value.sourceSpan);
15084 }
15085 else {
15086 placeholders[key] = this._visitTextWithInterpolation(value.text, value.sourceSpan);
15087 }
15088 });
15089 return new Icu(vars, placeholders, expansion.sourceSpan, message);
15090 }
15091 visitExpansionCase(expansionCase) {
15092 return null;
15093 }
15094 visitComment(comment) {
15095 return null;
15096 }
15097 // convert view engine `ParsedProperty` to a format suitable for IVY
15098 extractAttributes(elementName, properties, i18nPropsMeta) {
15099 const bound = [];
15100 const literal = [];
15101 properties.forEach(prop => {
15102 const i18n = i18nPropsMeta[prop.name];
15103 if (prop.isLiteral) {
15104 literal.push(new TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n));
15105 }
15106 else {
15107 // Note that validation is skipped and property mapping is disabled
15108 // due to the fact that we need to make sure a given prop is not an
15109 // input of a directive and directive matching happens at runtime.
15110 const bep = this.bindingParser.createBoundElementProperty(elementName, prop, /* skipValidation */ true, /* mapPropertyName */ false);
15111 bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n));
15112 }
15113 });
15114 return { bound, literal };
15115 }
15116 parseAttribute(isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) {
15117 const name = normalizeAttributeName(attribute.name);
15118 const value = attribute.value;
15119 const srcSpan = attribute.sourceSpan;
15120 const absoluteOffset = attribute.valueSpan ? attribute.valueSpan.start.offset : srcSpan.start.offset;
15121 function createKeySpan(srcSpan, prefix, identifier) {
15122 // We need to adjust the start location for the keySpan to account for the removed 'data-'
15123 // prefix from `normalizeAttributeName`.
15124 const normalizationAdjustment = attribute.name.length - name.length;
15125 const keySpanStart = srcSpan.start.moveBy(prefix.length + normalizationAdjustment);
15126 const keySpanEnd = keySpanStart.moveBy(identifier.length);
15127 return new ParseSourceSpan(keySpanStart, keySpanEnd, keySpanStart, identifier);
15128 }
15129 const bindParts = name.match(BIND_NAME_REGEXP$1);
15130 if (bindParts) {
15131 if (bindParts[KW_BIND_IDX$1] != null) {
15132 const identifier = bindParts[IDENT_KW_IDX$1];
15133 const keySpan = createKeySpan(srcSpan, bindParts[KW_BIND_IDX$1], identifier);
15134 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15135 }
15136 else if (bindParts[KW_LET_IDX$1]) {
15137 if (isTemplateElement) {
15138 const identifier = bindParts[IDENT_KW_IDX$1];
15139 const keySpan = createKeySpan(srcSpan, bindParts[KW_LET_IDX$1], identifier);
15140 this.parseVariable(identifier, value, srcSpan, keySpan, attribute.valueSpan, variables);
15141 }
15142 else {
15143 this.reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
15144 }
15145 }
15146 else if (bindParts[KW_REF_IDX$1]) {
15147 const identifier = bindParts[IDENT_KW_IDX$1];
15148 const keySpan = createKeySpan(srcSpan, bindParts[KW_REF_IDX$1], identifier);
15149 this.parseReference(identifier, value, srcSpan, keySpan, attribute.valueSpan, references);
15150 }
15151 else if (bindParts[KW_ON_IDX$1]) {
15152 const events = [];
15153 const identifier = bindParts[IDENT_KW_IDX$1];
15154 const keySpan = createKeySpan(srcSpan, bindParts[KW_ON_IDX$1], identifier);
15155 this.bindingParser.parseEvent(identifier, value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
15156 addEvents(events, boundEvents);
15157 }
15158 else if (bindParts[KW_BINDON_IDX$1]) {
15159 const identifier = bindParts[IDENT_KW_IDX$1];
15160 const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX$1], identifier);
15161 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15162 this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
15163 }
15164 else if (bindParts[KW_AT_IDX$1]) {
15165 const keySpan = createKeySpan(srcSpan, '', name);
15166 this.bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15167 }
15168 return true;
15169 }
15170 // We didn't see a kw-prefixed property binding, but we have not yet checked
15171 // for the []/()/[()] syntax.
15172 let delims = null;
15173 if (name.startsWith(BINDING_DELIMS.BANANA_BOX.start)) {
15174 delims = BINDING_DELIMS.BANANA_BOX;
15175 }
15176 else if (name.startsWith(BINDING_DELIMS.PROPERTY.start)) {
15177 delims = BINDING_DELIMS.PROPERTY;
15178 }
15179 else if (name.startsWith(BINDING_DELIMS.EVENT.start)) {
15180 delims = BINDING_DELIMS.EVENT;
15181 }
15182 if (delims !== null &&
15183 // NOTE: older versions of the parser would match a start/end delimited
15184 // binding iff the property name was terminated by the ending delimiter
15185 // and the identifier in the binding was non-empty.
15186 // TODO(ayazhafiz): update this to handle malformed bindings.
15187 name.endsWith(delims.end) && name.length > delims.start.length + delims.end.length) {
15188 const identifier = name.substring(delims.start.length, name.length - delims.end.length);
15189 const keySpan = createKeySpan(srcSpan, delims.start, identifier);
15190 if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
15191 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15192 this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
15193 }
15194 else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
15195 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15196 }
15197 else {
15198 const events = [];
15199 this.bindingParser.parseEvent(identifier, value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
15200 addEvents(events, boundEvents);
15201 }
15202 return true;
15203 }
15204 // No explicit binding found.
15205 const keySpan = createKeySpan(srcSpan, '' /* prefix */, name);
15206 const hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15207 return hasBinding;
15208 }
15209 _visitTextWithInterpolation(value, sourceSpan, i18n) {
15210 const valueNoNgsp = replaceNgsp(value);
15211 const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan);
15212 return expr ? new BoundText(expr, sourceSpan, i18n) : new Text(valueNoNgsp, sourceSpan);
15213 }
15214 parseVariable(identifier, value, sourceSpan, keySpan, valueSpan, variables) {
15215 if (identifier.indexOf('-') > -1) {
15216 this.reportError(`"-" is not allowed in variable names`, sourceSpan);
15217 }
15218 else if (identifier.length === 0) {
15219 this.reportError(`Variable does not have a name`, sourceSpan);
15220 }
15221 variables.push(new Variable(identifier, value, sourceSpan, keySpan, valueSpan));
15222 }
15223 parseReference(identifier, value, sourceSpan, keySpan, valueSpan, references) {
15224 if (identifier.indexOf('-') > -1) {
15225 this.reportError(`"-" is not allowed in reference names`, sourceSpan);
15226 }
15227 else if (identifier.length === 0) {
15228 this.reportError(`Reference does not have a name`, sourceSpan);
15229 }
15230 else if (references.some(reference => reference.name === identifier)) {
15231 this.reportError(`Reference "#${identifier}" is defined more than once`, sourceSpan);
15232 }
15233 references.push(new Reference(identifier, value, sourceSpan, keySpan, valueSpan));
15234 }
15235 parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) {
15236 const events = [];
15237 this.bindingParser.parseEvent(`${name}Change`, `${expression}=$event`, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
15238 addEvents(events, boundEvents);
15239 }
15240 reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
15241 this.errors.push(new ParseError(sourceSpan, message, level));
15242 }
15243 }
15244 class NonBindableVisitor$1 {
15245 visitElement(ast) {
15246 const preparsedElement = preparseElement(ast);
15247 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
15248 preparsedElement.type === PreparsedElementType.STYLE ||
15249 preparsedElement.type === PreparsedElementType.STYLESHEET) {
15250 // Skipping <script> for security reasons
15251 // Skipping <style> and stylesheets as we already processed them
15252 // in the StyleCompiler
15253 return null;
15254 }
15255 const children = visitAll$1(this, ast.children, null);
15256 return new Element(ast.name, visitAll$1(this, ast.attrs),
15257 /* inputs */ [], /* outputs */ [], children, /* references */ [], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
15258 }
15259 visitComment(comment) {
15260 return null;
15261 }
15262 visitAttribute(attribute) {
15263 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
15264 }
15265 visitText(text) {
15266 return new Text(text.value, text.sourceSpan);
15267 }
15268 visitExpansion(expansion) {
15269 return null;
15270 }
15271 visitExpansionCase(expansionCase) {
15272 return null;
15273 }
15274 }
15275 const NON_BINDABLE_VISITOR$1 = new NonBindableVisitor$1();
15276 function normalizeAttributeName(attrName) {
15277 return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
15278 }
15279 function addEvents(events, boundEvents) {
15280 boundEvents.push(...events.map(e => BoundEvent.fromParsedEvent(e)));
15281 }
15282 function isEmptyTextNode(node) {
15283 return node instanceof Text$2 && node.value.trim().length == 0;
15284 }
15285 function isCommentNode(node) {
15286 return node instanceof Comment;
15287 }
15288 function textContents(node) {
15289 if (node.children.length !== 1 || !(node.children[0] instanceof Text$2)) {
15290 return null;
15291 }
15292 else {
15293 return node.children[0].value;
15294 }
15295 }
15296
15297 /**
15298 * @license
15299 * Copyright Google LLC All Rights Reserved.
15300 *
15301 * Use of this source code is governed by an MIT-style license that can be
15302 * found in the LICENSE file at https://angular.io/license
15303 */
15304 var TagType;
15305 (function (TagType) {
15306 TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
15307 TagType[TagType["TEMPLATE"] = 1] = "TEMPLATE";
15308 })(TagType || (TagType = {}));
15309 /**
15310 * Generates an object that is used as a shared state between parent and all child contexts.
15311 */
15312 function setupRegistry() {
15313 return { getUniqueId: getSeqNumberGenerator(), icus: new Map() };
15314 }
15315 /**
15316 * I18nContext is a helper class which keeps track of all i18n-related aspects
15317 * (accumulates placeholders, bindings, etc) between i18nStart and i18nEnd instructions.
15318 *
15319 * When we enter a nested template, the top-level context is being passed down
15320 * to the nested component, which uses this context to generate a child instance
15321 * of I18nContext class (to handle nested template) and at the end, reconciles it back
15322 * with the parent context.
15323 *
15324 * @param index Instruction index of i18nStart, which initiates this context
15325 * @param ref Reference to a translation const that represents the content if thus context
15326 * @param level Nestng level defined for child contexts
15327 * @param templateIndex Instruction index of a template which this context belongs to
15328 * @param meta Meta information (id, meaning, description, etc) associated with this context
15329 */
15330 class I18nContext {
15331 constructor(index, ref, level = 0, templateIndex = null, meta, registry) {
15332 this.index = index;
15333 this.ref = ref;
15334 this.level = level;
15335 this.templateIndex = templateIndex;
15336 this.meta = meta;
15337 this.registry = registry;
15338 this.bindings = new Set();
15339 this.placeholders = new Map();
15340 this.isEmitted = false;
15341 this._unresolvedCtxCount = 0;
15342 this._registry = registry || setupRegistry();
15343 this.id = this._registry.getUniqueId();
15344 }
15345 appendTag(type, node, index, closed) {
15346 if (node.isVoid && closed) {
15347 return; // ignore "close" for void tags
15348 }
15349 const ph = node.isVoid || !closed ? node.startName : node.closeName;
15350 const content = { type, index, ctx: this.id, isVoid: node.isVoid, closed };
15351 updatePlaceholderMap(this.placeholders, ph, content);
15352 }
15353 get icus() {
15354 return this._registry.icus;
15355 }
15356 get isRoot() {
15357 return this.level === 0;
15358 }
15359 get isResolved() {
15360 return this._unresolvedCtxCount === 0;
15361 }
15362 getSerializedPlaceholders() {
15363 const result = new Map();
15364 this.placeholders.forEach((values, key) => result.set(key, values.map(serializePlaceholderValue)));
15365 return result;
15366 }
15367 // public API to accumulate i18n-related content
15368 appendBinding(binding) {
15369 this.bindings.add(binding);
15370 }
15371 appendIcu(name, ref) {
15372 updatePlaceholderMap(this._registry.icus, name, ref);
15373 }
15374 appendBoundText(node) {
15375 const phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id);
15376 phs.forEach((values, key) => updatePlaceholderMap(this.placeholders, key, ...values));
15377 }
15378 appendTemplate(node, index) {
15379 // add open and close tags at the same time,
15380 // since we process nested templates separately
15381 this.appendTag(TagType.TEMPLATE, node, index, false);
15382 this.appendTag(TagType.TEMPLATE, node, index, true);
15383 this._unresolvedCtxCount++;
15384 }
15385 appendElement(node, index, closed) {
15386 this.appendTag(TagType.ELEMENT, node, index, closed);
15387 }
15388 appendProjection(node, index) {
15389 // Add open and close tags at the same time, since `<ng-content>` has no content,
15390 // so when we come across `<ng-content>` we can register both open and close tags.
15391 // Note: runtime i18n logic doesn't distinguish `<ng-content>` tag placeholders and
15392 // regular element tag placeholders, so we generate element placeholders for both types.
15393 this.appendTag(TagType.ELEMENT, node, index, false);
15394 this.appendTag(TagType.ELEMENT, node, index, true);
15395 }
15396 /**
15397 * Generates an instance of a child context based on the root one,
15398 * when we enter a nested template within I18n section.
15399 *
15400 * @param index Instruction index of corresponding i18nStart, which initiates this context
15401 * @param templateIndex Instruction index of a template which this context belongs to
15402 * @param meta Meta information (id, meaning, description, etc) associated with this context
15403 *
15404 * @returns I18nContext instance
15405 */
15406 forkChildContext(index, templateIndex, meta) {
15407 return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry);
15408 }
15409 /**
15410 * Reconciles child context into parent one once the end of the i18n block is reached (i18nEnd).
15411 *
15412 * @param context Child I18nContext instance to be reconciled with parent context.
15413 */
15414 reconcileChildContext(context) {
15415 // set the right context id for open and close
15416 // template tags, so we can use it as sub-block ids
15417 ['start', 'close'].forEach((op) => {
15418 const key = context.meta[`${op}Name`];
15419 const phs = this.placeholders.get(key) || [];
15420 const tag = phs.find(findTemplateFn(this.id, context.templateIndex));
15421 if (tag) {
15422 tag.ctx = context.id;
15423 }
15424 });
15425 // reconcile placeholders
15426 const childPhs = context.placeholders;
15427 childPhs.forEach((values, key) => {
15428 const phs = this.placeholders.get(key);
15429 if (!phs) {
15430 this.placeholders.set(key, values);
15431 return;
15432 }
15433 // try to find matching template...
15434 const tmplIdx = phs.findIndex(findTemplateFn(context.id, context.templateIndex));
15435 if (tmplIdx >= 0) {
15436 // ... if found - replace it with nested template content
15437 const isCloseTag = key.startsWith('CLOSE');
15438 const isTemplateTag = key.endsWith('NG-TEMPLATE');
15439 if (isTemplateTag) {
15440 // current template's content is placed before or after
15441 // parent template tag, depending on the open/close atrribute
15442 phs.splice(tmplIdx + (isCloseTag ? 0 : 1), 0, ...values);
15443 }
15444 else {
15445 const idx = isCloseTag ? values.length - 1 : 0;
15446 values[idx].tmpl = phs[tmplIdx];
15447 phs.splice(tmplIdx, 1, ...values);
15448 }
15449 }
15450 else {
15451 // ... otherwise just append content to placeholder value
15452 phs.push(...values);
15453 }
15454 this.placeholders.set(key, phs);
15455 });
15456 this._unresolvedCtxCount--;
15457 }
15458 }
15459 //
15460 // Helper methods
15461 //
15462 function wrap(symbol, index, contextId, closed) {
15463 const state = closed ? '/' : '';
15464 return wrapI18nPlaceholder(`${state}${symbol}${index}`, contextId);
15465 }
15466 function wrapTag(symbol, { index, ctx, isVoid }, closed) {
15467 return isVoid ? wrap(symbol, index, ctx) + wrap(symbol, index, ctx, true) :
15468 wrap(symbol, index, ctx, closed);
15469 }
15470 function findTemplateFn(ctx, templateIndex) {
15471 return (token) => typeof token === 'object' && token.type === TagType.TEMPLATE &&
15472 token.index === templateIndex && token.ctx === ctx;
15473 }
15474 function serializePlaceholderValue(value) {
15475 const element = (data, closed) => wrapTag('#', data, closed);
15476 const template = (data, closed) => wrapTag('*', data, closed);
15477 switch (value.type) {
15478 case TagType.ELEMENT:
15479 // close element tag
15480 if (value.closed) {
15481 return element(value, true) + (value.tmpl ? template(value.tmpl, true) : '');
15482 }
15483 // open element tag that also initiates a template
15484 if (value.tmpl) {
15485 return template(value.tmpl) + element(value) +
15486 (value.isVoid ? template(value.tmpl, true) : '');
15487 }
15488 return element(value);
15489 case TagType.TEMPLATE:
15490 return template(value, value.closed);
15491 default:
15492 return value;
15493 }
15494 }
15495
15496 /**
15497 * @license
15498 * Copyright Google LLC All Rights Reserved.
15499 *
15500 * Use of this source code is governed by an MIT-style license that can be
15501 * found in the LICENSE file at https://angular.io/license
15502 */
15503 class IcuSerializerVisitor {
15504 visitText(text) {
15505 return text.value;
15506 }
15507 visitContainer(container) {
15508 return container.children.map(child => child.visit(this)).join('');
15509 }
15510 visitIcu(icu) {
15511 const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
15512 const result = `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`;
15513 return result;
15514 }
15515 visitTagPlaceholder(ph) {
15516 return ph.isVoid ?
15517 this.formatPh(ph.startName) :
15518 `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
15519 }
15520 visitPlaceholder(ph) {
15521 return this.formatPh(ph.name);
15522 }
15523 visitIcuPlaceholder(ph, context) {
15524 return this.formatPh(ph.name);
15525 }
15526 formatPh(value) {
15527 return `{${formatI18nPlaceholderName(value, /* useCamelCase */ false)}}`;
15528 }
15529 }
15530 const serializer = new IcuSerializerVisitor();
15531 function serializeIcuNode(icu) {
15532 return icu.visit(serializer);
15533 }
15534
15535 /**
15536 * @license
15537 * Copyright Google LLC All Rights Reserved.
15538 *
15539 * Use of this source code is governed by an MIT-style license that can be
15540 * found in the LICENSE file at https://angular.io/license
15541 */
15542 const TAG_TO_PLACEHOLDER_NAMES = {
15543 'A': 'LINK',
15544 'B': 'BOLD_TEXT',
15545 'BR': 'LINE_BREAK',
15546 'EM': 'EMPHASISED_TEXT',
15547 'H1': 'HEADING_LEVEL1',
15548 'H2': 'HEADING_LEVEL2',
15549 'H3': 'HEADING_LEVEL3',
15550 'H4': 'HEADING_LEVEL4',
15551 'H5': 'HEADING_LEVEL5',
15552 'H6': 'HEADING_LEVEL6',
15553 'HR': 'HORIZONTAL_RULE',
15554 'I': 'ITALIC_TEXT',
15555 'LI': 'LIST_ITEM',
15556 'LINK': 'MEDIA_LINK',
15557 'OL': 'ORDERED_LIST',
15558 'P': 'PARAGRAPH',
15559 'Q': 'QUOTATION',
15560 'S': 'STRIKETHROUGH_TEXT',
15561 'SMALL': 'SMALL_TEXT',
15562 'SUB': 'SUBSTRIPT',
15563 'SUP': 'SUPERSCRIPT',
15564 'TBODY': 'TABLE_BODY',
15565 'TD': 'TABLE_CELL',
15566 'TFOOT': 'TABLE_FOOTER',
15567 'TH': 'TABLE_HEADER_CELL',
15568 'THEAD': 'TABLE_HEADER',
15569 'TR': 'TABLE_ROW',
15570 'TT': 'MONOSPACED_TEXT',
15571 'U': 'UNDERLINED_TEXT',
15572 'UL': 'UNORDERED_LIST',
15573 };
15574 /**
15575 * Creates unique names for placeholder with different content.
15576 *
15577 * Returns the same placeholder name when the content is identical.
15578 */
15579 class PlaceholderRegistry {
15580 constructor() {
15581 // Count the occurrence of the base name top generate a unique name
15582 this._placeHolderNameCounts = {};
15583 // Maps signature to placeholder names
15584 this._signatureToName = {};
15585 }
15586 getStartTagPlaceholderName(tag, attrs, isVoid) {
15587 const signature = this._hashTag(tag, attrs, isVoid);
15588 if (this._signatureToName[signature]) {
15589 return this._signatureToName[signature];
15590 }
15591 const upperTag = tag.toUpperCase();
15592 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
15593 const name = this._generateUniqueName(isVoid ? baseName : `START_${baseName}`);
15594 this._signatureToName[signature] = name;
15595 return name;
15596 }
15597 getCloseTagPlaceholderName(tag) {
15598 const signature = this._hashClosingTag(tag);
15599 if (this._signatureToName[signature]) {
15600 return this._signatureToName[signature];
15601 }
15602 const upperTag = tag.toUpperCase();
15603 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
15604 const name = this._generateUniqueName(`CLOSE_${baseName}`);
15605 this._signatureToName[signature] = name;
15606 return name;
15607 }
15608 getPlaceholderName(name, content) {
15609 const upperName = name.toUpperCase();
15610 const signature = `PH: ${upperName}=${content}`;
15611 if (this._signatureToName[signature]) {
15612 return this._signatureToName[signature];
15613 }
15614 const uniqueName = this._generateUniqueName(upperName);
15615 this._signatureToName[signature] = uniqueName;
15616 return uniqueName;
15617 }
15618 getUniquePlaceholder(name) {
15619 return this._generateUniqueName(name.toUpperCase());
15620 }
15621 // Generate a hash for a tag - does not take attribute order into account
15622 _hashTag(tag, attrs, isVoid) {
15623 const start = `<${tag}`;
15624 const strAttrs = Object.keys(attrs).sort().map((name) => ` ${name}=${attrs[name]}`).join('');
15625 const end = isVoid ? '/>' : `></${tag}>`;
15626 return start + strAttrs + end;
15627 }
15628 _hashClosingTag(tag) {
15629 return this._hashTag(`/${tag}`, {}, false);
15630 }
15631 _generateUniqueName(base) {
15632 const seen = this._placeHolderNameCounts.hasOwnProperty(base);
15633 if (!seen) {
15634 this._placeHolderNameCounts[base] = 1;
15635 return base;
15636 }
15637 const id = this._placeHolderNameCounts[base];
15638 this._placeHolderNameCounts[base] = id + 1;
15639 return `${base}_${id}`;
15640 }
15641 }
15642
15643 /**
15644 * @license
15645 * Copyright Google LLC All Rights Reserved.
15646 *
15647 * Use of this source code is governed by an MIT-style license that can be
15648 * found in the LICENSE file at https://angular.io/license
15649 */
15650 const _expParser = new Parser$1(new Lexer());
15651 /**
15652 * Returns a function converting html nodes to an i18n Message given an interpolationConfig
15653 */
15654 function createI18nMessageFactory(interpolationConfig) {
15655 const visitor = new _I18nVisitor(_expParser, interpolationConfig);
15656 return (nodes, meaning, description, customId, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn);
15657 }
15658 function noopVisitNodeFn(_html, i18n) {
15659 return i18n;
15660 }
15661 class _I18nVisitor {
15662 constructor(_expressionParser, _interpolationConfig) {
15663 this._expressionParser = _expressionParser;
15664 this._interpolationConfig = _interpolationConfig;
15665 }
15666 toI18nMessage(nodes, meaning = '', description = '', customId = '', visitNodeFn) {
15667 const context = {
15668 isIcu: nodes.length == 1 && nodes[0] instanceof Expansion,
15669 icuDepth: 0,
15670 placeholderRegistry: new PlaceholderRegistry(),
15671 placeholderToContent: {},
15672 placeholderToMessage: {},
15673 visitNodeFn: visitNodeFn || noopVisitNodeFn,
15674 };
15675 const i18nodes = visitAll$1(this, nodes, context);
15676 return new Message(i18nodes, context.placeholderToContent, context.placeholderToMessage, meaning, description, customId);
15677 }
15678 visitElement(el, context) {
15679 var _a;
15680 const children = visitAll$1(this, el.children, context);
15681 const attrs = {};
15682 el.attrs.forEach(attr => {
15683 // Do not visit the attributes, translatable ones are top-level ASTs
15684 attrs[attr.name] = attr.value;
15685 });
15686 const isVoid = getHtmlTagDefinition(el.name).isVoid;
15687 const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
15688 context.placeholderToContent[startPhName] = {
15689 text: el.startSourceSpan.toString(),
15690 sourceSpan: el.startSourceSpan,
15691 };
15692 let closePhName = '';
15693 if (!isVoid) {
15694 closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(el.name);
15695 context.placeholderToContent[closePhName] = {
15696 text: `</${el.name}>`,
15697 sourceSpan: (_a = el.endSourceSpan) !== null && _a !== void 0 ? _a : el.sourceSpan,
15698 };
15699 }
15700 const node = new TagPlaceholder(el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
15701 return context.visitNodeFn(el, node);
15702 }
15703 visitAttribute(attribute, context) {
15704 const node = this._visitTextWithInterpolation(attribute.value, attribute.valueSpan || attribute.sourceSpan, context, attribute.i18n);
15705 return context.visitNodeFn(attribute, node);
15706 }
15707 visitText(text, context) {
15708 const node = this._visitTextWithInterpolation(text.value, text.sourceSpan, context, text.i18n);
15709 return context.visitNodeFn(text, node);
15710 }
15711 visitComment(comment, context) {
15712 return null;
15713 }
15714 visitExpansion(icu, context) {
15715 context.icuDepth++;
15716 const i18nIcuCases = {};
15717 const i18nIcu = new Icu$1(icu.switchValue, icu.type, i18nIcuCases, icu.sourceSpan);
15718 icu.cases.forEach((caze) => {
15719 i18nIcuCases[caze.value] = new Container(caze.expression.map((node) => node.visit(this, context)), caze.expSourceSpan);
15720 });
15721 context.icuDepth--;
15722 if (context.isIcu || context.icuDepth > 0) {
15723 // Returns an ICU node when:
15724 // - the message (vs a part of the message) is an ICU message, or
15725 // - the ICU message is nested.
15726 const expPh = context.placeholderRegistry.getUniquePlaceholder(`VAR_${icu.type}`);
15727 i18nIcu.expressionPlaceholder = expPh;
15728 context.placeholderToContent[expPh] = {
15729 text: icu.switchValue,
15730 sourceSpan: icu.switchValueSourceSpan,
15731 };
15732 return context.visitNodeFn(icu, i18nIcu);
15733 }
15734 // Else returns a placeholder
15735 // ICU placeholders should not be replaced with their original content but with the their
15736 // translations.
15737 // TODO(vicb): add a html.Node -> i18n.Message cache to avoid having to re-create the msg
15738 const phName = context.placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
15739 context.placeholderToMessage[phName] = this.toI18nMessage([icu], '', '', '', undefined);
15740 const node = new IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
15741 return context.visitNodeFn(icu, node);
15742 }
15743 visitExpansionCase(_icuCase, _context) {
15744 throw new Error('Unreachable code');
15745 }
15746 /**
15747 * Split the, potentially interpolated, text up into text and placeholder pieces.
15748 *
15749 * @param text The potentially interpolated string to be split.
15750 * @param sourceSpan The span of the whole of the `text` string.
15751 * @param context The current context of the visitor, used to compute and store placeholders.
15752 * @param previousI18n Any i18n metadata associated with this `text` from a previous pass.
15753 */
15754 _visitTextWithInterpolation(text, sourceSpan, context, previousI18n) {
15755 const { strings, expressions } = this._expressionParser.splitInterpolation(text, sourceSpan.start.toString(), this._interpolationConfig);
15756 // No expressions, return a single text.
15757 if (expressions.length === 0) {
15758 return new Text$1(text, sourceSpan);
15759 }
15760 // Return a sequence of `Text` and `Placeholder` nodes grouped in a `Container`.
15761 const nodes = [];
15762 for (let i = 0; i < strings.length - 1; i++) {
15763 this._addText(nodes, strings[i], sourceSpan);
15764 this._addPlaceholder(nodes, context, expressions[i], sourceSpan);
15765 }
15766 // The last index contains no expression
15767 this._addText(nodes, strings[strings.length - 1], sourceSpan);
15768 // Whitespace removal may have invalidated the interpolation source-spans.
15769 reusePreviousSourceSpans(nodes, previousI18n);
15770 return new Container(nodes, sourceSpan);
15771 }
15772 /**
15773 * Create a new `Text` node from the `textPiece` and add it to the `nodes` collection.
15774 *
15775 * @param nodes The nodes to which the created `Text` node should be added.
15776 * @param textPiece The text and relative span information for this `Text` node.
15777 * @param interpolationSpan The span of the whole interpolated text.
15778 */
15779 _addText(nodes, textPiece, interpolationSpan) {
15780 if (textPiece.text.length > 0) {
15781 // No need to add empty strings
15782 const stringSpan = getOffsetSourceSpan(interpolationSpan, textPiece);
15783 nodes.push(new Text$1(textPiece.text, stringSpan));
15784 }
15785 }
15786 /**
15787 * Create a new `Placeholder` node from the `expression` and add it to the `nodes` collection.
15788 *
15789 * @param nodes The nodes to which the created `Text` node should be added.
15790 * @param context The current context of the visitor, used to compute and store placeholders.
15791 * @param expression The expression text and relative span information for this `Placeholder`
15792 * node.
15793 * @param interpolationSpan The span of the whole interpolated text.
15794 */
15795 _addPlaceholder(nodes, context, expression, interpolationSpan) {
15796 const sourceSpan = getOffsetSourceSpan(interpolationSpan, expression);
15797 const baseName = extractPlaceholderName(expression.text) || 'INTERPOLATION';
15798 const phName = context.placeholderRegistry.getPlaceholderName(baseName, expression.text);
15799 const text = this._interpolationConfig.start + expression.text + this._interpolationConfig.end;
15800 context.placeholderToContent[phName] = { text, sourceSpan };
15801 nodes.push(new Placeholder(expression.text, phName, sourceSpan));
15802 }
15803 }
15804 /**
15805 * Re-use the source-spans from `previousI18n` metadata for the `nodes`.
15806 *
15807 * Whitespace removal can invalidate the source-spans of interpolation nodes, so we
15808 * reuse the source-span stored from a previous pass before the whitespace was removed.
15809 *
15810 * @param nodes The `Text` and `Placeholder` nodes to be processed.
15811 * @param previousI18n Any i18n metadata for these `nodes` stored from a previous pass.
15812 */
15813 function reusePreviousSourceSpans(nodes, previousI18n) {
15814 if (previousI18n instanceof Message) {
15815 // The `previousI18n` is an i18n `Message`, so we are processing an `Attribute` with i18n
15816 // metadata. The `Message` should consist only of a single `Container` that contains the
15817 // parts (`Text` and `Placeholder`) to process.
15818 assertSingleContainerMessage(previousI18n);
15819 previousI18n = previousI18n.nodes[0];
15820 }
15821 if (previousI18n instanceof Container) {
15822 // The `previousI18n` is a `Container`, which means that this is a second i18n extraction pass
15823 // after whitespace has been removed from the AST ndoes.
15824 assertEquivalentNodes(previousI18n.children, nodes);
15825 // Reuse the source-spans from the first pass.
15826 for (let i = 0; i < nodes.length; i++) {
15827 nodes[i].sourceSpan = previousI18n.children[i].sourceSpan;
15828 }
15829 }
15830 }
15831 /**
15832 * Asserts that the `message` contains exactly one `Container` node.
15833 */
15834 function assertSingleContainerMessage(message) {
15835 const nodes = message.nodes;
15836 if (nodes.length !== 1 || !(nodes[0] instanceof Container)) {
15837 throw new Error('Unexpected previous i18n message - expected it to consist of only a single `Container` node.');
15838 }
15839 }
15840 /**
15841 * Asserts that the `previousNodes` and `node` collections have the same number of elements and
15842 * corresponding elements have the same node type.
15843 */
15844 function assertEquivalentNodes(previousNodes, nodes) {
15845 if (previousNodes.length !== nodes.length) {
15846 throw new Error('The number of i18n message children changed between first and second pass.');
15847 }
15848 if (previousNodes.some((node, i) => nodes[i].constructor !== node.constructor)) {
15849 throw new Error('The types of the i18n message children changed between first and second pass.');
15850 }
15851 }
15852 /**
15853 * Create a new `ParseSourceSpan` from the `sourceSpan`, offset by the `start` and `end` values.
15854 */
15855 function getOffsetSourceSpan(sourceSpan, { start, end }) {
15856 return new ParseSourceSpan(sourceSpan.fullStart.moveBy(start), sourceSpan.fullStart.moveBy(end));
15857 }
15858 const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
15859 function extractPlaceholderName(input) {
15860 return input.split(_CUSTOM_PH_EXP)[2];
15861 }
15862
15863 /**
15864 * @license
15865 * Copyright Google LLC All Rights Reserved.
15866 *
15867 * Use of this source code is governed by an MIT-style license that can be
15868 * found in the LICENSE file at https://angular.io/license
15869 */
15870 /**
15871 * An i18n error.
15872 */
15873 class I18nError extends ParseError {
15874 constructor(span, msg) {
15875 super(span, msg);
15876 }
15877 }
15878
15879 /**
15880 * @license
15881 * Copyright Google LLC All Rights Reserved.
15882 *
15883 * Use of this source code is governed by an MIT-style license that can be
15884 * found in the LICENSE file at https://angular.io/license
15885 */
15886 const setI18nRefs = (htmlNode, i18nNode) => {
15887 if (htmlNode instanceof NodeWithI18n) {
15888 if (i18nNode instanceof IcuPlaceholder && htmlNode.i18n instanceof Message) {
15889 // This html node represents an ICU but this is a second processing pass, and the legacy id
15890 // was computed in the previous pass and stored in the `i18n` property as a message.
15891 // We are about to wipe out that property so capture the previous message to be reused when
15892 // generating the message for this ICU later. See `_generateI18nMessage()`.
15893 i18nNode.previousMessage = htmlNode.i18n;
15894 }
15895 htmlNode.i18n = i18nNode;
15896 }
15897 return i18nNode;
15898 };
15899 /**
15900 * This visitor walks over HTML parse tree and converts information stored in
15901 * i18n-related attributes ("i18n" and "i18n-*") into i18n meta object that is
15902 * stored with other element's and attribute's information.
15903 */
15904 class I18nMetaVisitor {
15905 constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false) {
15906 this.interpolationConfig = interpolationConfig;
15907 this.keepI18nAttrs = keepI18nAttrs;
15908 this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat;
15909 // whether visited nodes contain i18n information
15910 this.hasI18nMeta = false;
15911 this._errors = [];
15912 // i18n message generation factory
15913 this._createI18nMessage = createI18nMessageFactory(this.interpolationConfig);
15914 }
15915 _generateI18nMessage(nodes, meta = '', visitNodeFn) {
15916 const { meaning, description, customId } = this._parseMetadata(meta);
15917 const message = this._createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
15918 this._setMessageId(message, meta);
15919 this._setLegacyIds(message, meta);
15920 return message;
15921 }
15922 visitAllWithErrors(nodes) {
15923 const result = nodes.map(node => node.visit(this, null));
15924 return new ParseTreeResult(result, this._errors);
15925 }
15926 visitElement(element) {
15927 if (hasI18nAttrs(element)) {
15928 this.hasI18nMeta = true;
15929 const attrs = [];
15930 const attrsMeta = {};
15931 for (const attr of element.attrs) {
15932 if (attr.name === I18N_ATTR) {
15933 // root 'i18n' node attribute
15934 const i18n = element.i18n || attr.value;
15935 const message = this._generateI18nMessage(element.children, i18n, setI18nRefs);
15936 // do not assign empty i18n meta
15937 if (message.nodes.length) {
15938 element.i18n = message;
15939 }
15940 }
15941 else if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
15942 // 'i18n-*' attributes
15943 const name = attr.name.slice(I18N_ATTR_PREFIX.length);
15944 if (isTrustedTypesSink(element.name, name)) {
15945 this._reportError(attr, `Translating attribute '${name}' is disallowed for security reasons.`);
15946 }
15947 else {
15948 attrsMeta[name] = attr.value;
15949 }
15950 }
15951 else {
15952 // non-i18n attributes
15953 attrs.push(attr);
15954 }
15955 }
15956 // set i18n meta for attributes
15957 if (Object.keys(attrsMeta).length) {
15958 for (const attr of attrs) {
15959 const meta = attrsMeta[attr.name];
15960 // do not create translation for empty attributes
15961 if (meta !== undefined && attr.value) {
15962 attr.i18n = this._generateI18nMessage([attr], attr.i18n || meta);
15963 }
15964 }
15965 }
15966 if (!this.keepI18nAttrs) {
15967 // update element's attributes,
15968 // keeping only non-i18n related ones
15969 element.attrs = attrs;
15970 }
15971 }
15972 visitAll$1(this, element.children, element.i18n);
15973 return element;
15974 }
15975 visitExpansion(expansion, currentMessage) {
15976 let message;
15977 const meta = expansion.i18n;
15978 this.hasI18nMeta = true;
15979 if (meta instanceof IcuPlaceholder) {
15980 // set ICU placeholder name (e.g. "ICU_1"),
15981 // generated while processing root element contents,
15982 // so we can reference it when we output translation
15983 const name = meta.name;
15984 message = this._generateI18nMessage([expansion], meta);
15985 const icu = icuFromI18nMessage(message);
15986 icu.name = name;
15987 }
15988 else {
15989 // ICU is a top level message, try to use metadata from container element if provided via
15990 // `context` argument. Note: context may not be available for standalone ICUs (without
15991 // wrapping element), so fallback to ICU metadata in this case.
15992 message = this._generateI18nMessage([expansion], currentMessage || meta);
15993 }
15994 expansion.i18n = message;
15995 return expansion;
15996 }
15997 visitText(text) {
15998 return text;
15999 }
16000 visitAttribute(attribute) {
16001 return attribute;
16002 }
16003 visitComment(comment) {
16004 return comment;
16005 }
16006 visitExpansionCase(expansionCase) {
16007 return expansionCase;
16008 }
16009 /**
16010 * Parse the general form `meta` passed into extract the explicit metadata needed to create a
16011 * `Message`.
16012 *
16013 * There are three possibilities for the `meta` variable
16014 * 1) a string from an `i18n` template attribute: parse it to extract the metadata values.
16015 * 2) a `Message` from a previous processing pass: reuse the metadata values in the message.
16016 * 4) other: ignore this and just process the message metadata as normal
16017 *
16018 * @param meta the bucket that holds information about the message
16019 * @returns the parsed metadata.
16020 */
16021 _parseMetadata(meta) {
16022 return typeof meta === 'string' ? parseI18nMeta(meta) :
16023 meta instanceof Message ? meta : {};
16024 }
16025 /**
16026 * Generate (or restore) message id if not specified already.
16027 */
16028 _setMessageId(message, meta) {
16029 if (!message.id) {
16030 message.id = meta instanceof Message && meta.id || decimalDigest(message);
16031 }
16032 }
16033 /**
16034 * Update the `message` with a `legacyId` if necessary.
16035 *
16036 * @param message the message whose legacy id should be set
16037 * @param meta information about the message being processed
16038 */
16039 _setLegacyIds(message, meta) {
16040 if (this.enableI18nLegacyMessageIdFormat) {
16041 message.legacyIds = [computeDigest(message), computeDecimalDigest(message)];
16042 }
16043 else if (typeof meta !== 'string') {
16044 // This occurs if we are doing the 2nd pass after whitespace removal (see `parseTemplate()` in
16045 // `packages/compiler/src/render3/view/template.ts`).
16046 // In that case we want to reuse the legacy message generated in the 1st pass (see
16047 // `setI18nRefs()`).
16048 const previousMessage = meta instanceof Message ?
16049 meta :
16050 meta instanceof IcuPlaceholder ? meta.previousMessage : undefined;
16051 message.legacyIds = previousMessage ? previousMessage.legacyIds : [];
16052 }
16053 }
16054 _reportError(node, msg) {
16055 this._errors.push(new I18nError(node.sourceSpan, msg));
16056 }
16057 }
16058 /** I18n separators for metadata **/
16059 const I18N_MEANING_SEPARATOR = '|';
16060 const I18N_ID_SEPARATOR = '@@';
16061 /**
16062 * Parses i18n metas like:
16063 * - "@@id",
16064 * - "description[@@id]",
16065 * - "meaning|description[@@id]"
16066 * and returns an object with parsed output.
16067 *
16068 * @param meta String that represents i18n meta
16069 * @returns Object with id, meaning and description fields
16070 */
16071 function parseI18nMeta(meta = '') {
16072 let customId;
16073 let meaning;
16074 let description;
16075 meta = meta.trim();
16076 if (meta) {
16077 const idIndex = meta.indexOf(I18N_ID_SEPARATOR);
16078 const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
16079 let meaningAndDesc;
16080 [meaningAndDesc, customId] =
16081 (idIndex > -1) ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''];
16082 [meaning, description] = (descIndex > -1) ?
16083 [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
16084 ['', meaningAndDesc];
16085 }
16086 return { customId, meaning, description };
16087 }
16088 // Converts i18n meta information for a message (id, description, meaning)
16089 // to a JsDoc statement formatted as expected by the Closure compiler.
16090 function i18nMetaToJSDoc(meta) {
16091 const tags = [];
16092 if (meta.description) {
16093 tags.push({ tagName: "desc" /* Desc */, text: meta.description });
16094 }
16095 if (meta.meaning) {
16096 tags.push({ tagName: "meaning" /* Meaning */, text: meta.meaning });
16097 }
16098 return tags.length == 0 ? null : jsDocComment(tags);
16099 }
16100
16101 /** Closure uses `goog.getMsg(message)` to lookup translations */
16102 const GOOG_GET_MSG = 'goog.getMsg';
16103 function createGoogleGetMsgStatements(variable$1, message, closureVar, params) {
16104 const messageString = serializeI18nMessageForGetMsg(message);
16105 const args = [literal(messageString)];
16106 if (Object.keys(params).length) {
16107 args.push(mapLiteral(params, true));
16108 }
16109 // /**
16110 // * @desc description of message
16111 // * @meaning meaning of message
16112 // */
16113 // const MSG_... = goog.getMsg(..);
16114 // I18N_X = MSG_...;
16115 const googGetMsgStmt = closureVar.set(variable(GOOG_GET_MSG).callFn(args)).toConstDecl();
16116 const metaComment = i18nMetaToJSDoc(message);
16117 if (metaComment !== null) {
16118 googGetMsgStmt.addLeadingComment(metaComment);
16119 }
16120 const i18nAssignmentStmt = new ExpressionStatement(variable$1.set(closureVar));
16121 return [googGetMsgStmt, i18nAssignmentStmt];
16122 }
16123 /**
16124 * This visitor walks over i18n tree and generates its string representation, including ICUs and
16125 * placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format.
16126 */
16127 class GetMsgSerializerVisitor {
16128 formatPh(value) {
16129 return `{$${formatI18nPlaceholderName(value)}}`;
16130 }
16131 visitText(text) {
16132 return text.value;
16133 }
16134 visitContainer(container) {
16135 return container.children.map(child => child.visit(this)).join('');
16136 }
16137 visitIcu(icu) {
16138 return serializeIcuNode(icu);
16139 }
16140 visitTagPlaceholder(ph) {
16141 return ph.isVoid ?
16142 this.formatPh(ph.startName) :
16143 `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
16144 }
16145 visitPlaceholder(ph) {
16146 return this.formatPh(ph.name);
16147 }
16148 visitIcuPlaceholder(ph, context) {
16149 return this.formatPh(ph.name);
16150 }
16151 }
16152 const serializerVisitor$1 = new GetMsgSerializerVisitor();
16153 function serializeI18nMessageForGetMsg(message) {
16154 return message.nodes.map(node => node.visit(serializerVisitor$1, null)).join('');
16155 }
16156
16157 function createLocalizeStatements(variable, message, params) {
16158 const { messageParts, placeHolders } = serializeI18nMessageForLocalize(message);
16159 const sourceSpan = getSourceSpan(message);
16160 const expressions = placeHolders.map(ph => params[ph.text]);
16161 const localizedString$1 = localizedString(message, messageParts, placeHolders, expressions, sourceSpan);
16162 const variableInitialization = variable.set(localizedString$1);
16163 return [new ExpressionStatement(variableInitialization)];
16164 }
16165 /**
16166 * This visitor walks over an i18n tree, capturing literal strings and placeholders.
16167 *
16168 * The result can be used for generating the `$localize` tagged template literals.
16169 */
16170 class LocalizeSerializerVisitor {
16171 visitText(text, context) {
16172 if (context[context.length - 1] instanceof LiteralPiece) {
16173 // Two literal pieces in a row means that there was some comment node in-between.
16174 context[context.length - 1].text += text.value;
16175 }
16176 else {
16177 context.push(new LiteralPiece(text.value, text.sourceSpan));
16178 }
16179 }
16180 visitContainer(container, context) {
16181 container.children.forEach(child => child.visit(this, context));
16182 }
16183 visitIcu(icu, context) {
16184 context.push(new LiteralPiece(serializeIcuNode(icu), icu.sourceSpan));
16185 }
16186 visitTagPlaceholder(ph, context) {
16187 var _a, _b;
16188 context.push(this.createPlaceholderPiece(ph.startName, (_a = ph.startSourceSpan) !== null && _a !== void 0 ? _a : ph.sourceSpan));
16189 if (!ph.isVoid) {
16190 ph.children.forEach(child => child.visit(this, context));
16191 context.push(this.createPlaceholderPiece(ph.closeName, (_b = ph.endSourceSpan) !== null && _b !== void 0 ? _b : ph.sourceSpan));
16192 }
16193 }
16194 visitPlaceholder(ph, context) {
16195 context.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
16196 }
16197 visitIcuPlaceholder(ph, context) {
16198 context.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
16199 }
16200 createPlaceholderPiece(name, sourceSpan) {
16201 return new PlaceholderPiece(formatI18nPlaceholderName(name, /* useCamelCase */ false), sourceSpan);
16202 }
16203 }
16204 const serializerVisitor$2 = new LocalizeSerializerVisitor();
16205 /**
16206 * Serialize an i18n message into two arrays: messageParts and placeholders.
16207 *
16208 * These arrays will be used to generate `$localize` tagged template literals.
16209 *
16210 * @param message The message to be serialized.
16211 * @returns an object containing the messageParts and placeholders.
16212 */
16213 function serializeI18nMessageForLocalize(message) {
16214 const pieces = [];
16215 message.nodes.forEach(node => node.visit(serializerVisitor$2, pieces));
16216 return processMessagePieces(pieces);
16217 }
16218 function getSourceSpan(message) {
16219 const startNode = message.nodes[0];
16220 const endNode = message.nodes[message.nodes.length - 1];
16221 return new ParseSourceSpan(startNode.sourceSpan.start, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details);
16222 }
16223 /**
16224 * Convert the list of serialized MessagePieces into two arrays.
16225 *
16226 * One contains the literal string pieces and the other the placeholders that will be replaced by
16227 * expressions when rendering `$localize` tagged template literals.
16228 *
16229 * @param pieces The pieces to process.
16230 * @returns an object containing the messageParts and placeholders.
16231 */
16232 function processMessagePieces(pieces) {
16233 const messageParts = [];
16234 const placeHolders = [];
16235 if (pieces[0] instanceof PlaceholderPiece) {
16236 // The first piece was a placeholder so we need to add an initial empty message part.
16237 messageParts.push(createEmptyMessagePart(pieces[0].sourceSpan.start));
16238 }
16239 for (let i = 0; i < pieces.length; i++) {
16240 const part = pieces[i];
16241 if (part instanceof LiteralPiece) {
16242 messageParts.push(part);
16243 }
16244 else {
16245 placeHolders.push(part);
16246 if (pieces[i - 1] instanceof PlaceholderPiece) {
16247 // There were two placeholders in a row, so we need to add an empty message part.
16248 messageParts.push(createEmptyMessagePart(pieces[i - 1].sourceSpan.end));
16249 }
16250 }
16251 }
16252 if (pieces[pieces.length - 1] instanceof PlaceholderPiece) {
16253 // The last piece was a placeholder so we need to add a final empty message part.
16254 messageParts.push(createEmptyMessagePart(pieces[pieces.length - 1].sourceSpan.end));
16255 }
16256 return { messageParts, placeHolders };
16257 }
16258 function createEmptyMessagePart(location) {
16259 return new LiteralPiece('', new ParseSourceSpan(location, location));
16260 }
16261
16262 /**
16263 * @license
16264 * Copyright Google LLC All Rights Reserved.
16265 *
16266 * Use of this source code is governed by an MIT-style license that can be
16267 * found in the LICENSE file at https://angular.io/license
16268 */
16269 // Selector attribute name of `<ng-content>`
16270 const NG_CONTENT_SELECT_ATTR$1 = 'select';
16271 // Attribute name of `ngProjectAs`.
16272 const NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs';
16273 // Global symbols available only inside event bindings.
16274 const EVENT_BINDING_SCOPE_GLOBALS = new Set(['$event']);
16275 // List of supported global targets for event listeners
16276 const GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers$1.resolveWindow], ['document', Identifiers$1.resolveDocument], ['body', Identifiers$1.resolveBody]]);
16277 const LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t'];
16278 // if (rf & flags) { .. }
16279 function renderFlagCheckIfStmt(flags, statements) {
16280 return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null, false), statements);
16281 }
16282 function prepareEventListenerParameters(eventAst, handlerName = null, scope = null) {
16283 const { type, name, target, phase, handler } = eventAst;
16284 if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) {
16285 throw new Error(`Unexpected global target '${target}' defined for '${name}' event.
16286 Supported list of global targets: ${Array.from(GLOBAL_TARGET_RESOLVERS.keys())}.`);
16287 }
16288 const eventArgumentName = '$event';
16289 const implicitReceiverAccesses = new Set();
16290 const implicitReceiverExpr = (scope === null || scope.bindingLevel === 0) ?
16291 variable(CONTEXT_NAME) :
16292 scope.getOrCreateSharedContextVar(0);
16293 const bindingExpr = convertActionBinding(scope, implicitReceiverExpr, handler, 'b', () => error('Unexpected interpolation'), eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS);
16294 const statements = [];
16295 if (scope) {
16296 statements.push(...scope.restoreViewStatement());
16297 statements.push(...scope.variableDeclarations());
16298 }
16299 statements.push(...bindingExpr.render3Stmts);
16300 const eventName = type === 1 /* Animation */ ? prepareSyntheticListenerName(name, phase) : name;
16301 const fnName = handlerName && sanitizeIdentifier(handlerName);
16302 const fnArgs = [];
16303 if (implicitReceiverAccesses.has(eventArgumentName)) {
16304 fnArgs.push(new FnParam(eventArgumentName, DYNAMIC_TYPE));
16305 }
16306 const handlerFn = fn(fnArgs, statements, INFERRED_TYPE, null, fnName);
16307 const params = [literal(eventName), handlerFn];
16308 if (target) {
16309 params.push(literal(false), // `useCapture` flag, defaults to `false`
16310 importExpr(GLOBAL_TARGET_RESOLVERS.get(target)));
16311 }
16312 return params;
16313 }
16314 function createComponentDefConsts() {
16315 return {
16316 prepareStatements: [],
16317 constExpressions: [],
16318 i18nVarRefsCache: new Map(),
16319 };
16320 }
16321 class TemplateDefinitionBuilder {
16322 constructor(constantPool, parentBindingScope, level = 0, contextName, i18nContext, templateIndex, templateName, directiveMatcher, directives, pipeTypeByName, pipes, _namespace, relativeContextFilePath, i18nUseExternalIds, _constants = createComponentDefConsts()) {
16323 this.constantPool = constantPool;
16324 this.level = level;
16325 this.contextName = contextName;
16326 this.i18nContext = i18nContext;
16327 this.templateIndex = templateIndex;
16328 this.templateName = templateName;
16329 this.directiveMatcher = directiveMatcher;
16330 this.directives = directives;
16331 this.pipeTypeByName = pipeTypeByName;
16332 this.pipes = pipes;
16333 this._namespace = _namespace;
16334 this.i18nUseExternalIds = i18nUseExternalIds;
16335 this._constants = _constants;
16336 this._dataIndex = 0;
16337 this._bindingContext = 0;
16338 this._prefixCode = [];
16339 /**
16340 * List of callbacks to generate creation mode instructions. We store them here as we process
16341 * the template so bindings in listeners are resolved only once all nodes have been visited.
16342 * This ensures all local refs and context variables are available for matching.
16343 */
16344 this._creationCodeFns = [];
16345 /**
16346 * List of callbacks to generate update mode instructions. We store them here as we process
16347 * the template so bindings are resolved only once all nodes have been visited. This ensures
16348 * all local refs and context variables are available for matching.
16349 */
16350 this._updateCodeFns = [];
16351 /** Index of the currently-selected node. */
16352 this._currentIndex = 0;
16353 /** Temporary variable declarations generated from visiting pipes, literals, etc. */
16354 this._tempVariables = [];
16355 /**
16356 * List of callbacks to build nested templates. Nested templates must not be visited until
16357 * after the parent template has finished visiting all of its nodes. This ensures that all
16358 * local ref bindings in nested templates are able to find local ref values if the refs
16359 * are defined after the template declaration.
16360 */
16361 this._nestedTemplateFns = [];
16362 this._unsupported = unsupported;
16363 // i18n context local to this template
16364 this.i18n = null;
16365 // Number of slots to reserve for pureFunctions
16366 this._pureFunctionSlots = 0;
16367 // Number of binding slots
16368 this._bindingSlots = 0;
16369 // Projection slots found in the template. Projection slots can distribute projected
16370 // nodes based on a selector, or can just use the wildcard selector to match
16371 // all nodes which aren't matching any selector.
16372 this._ngContentReservedSlots = [];
16373 // Number of non-default selectors found in all parent templates of this template. We need to
16374 // track it to properly adjust projection slot index in the `projection` instruction.
16375 this._ngContentSelectorsOffset = 0;
16376 // Expression that should be used as implicit receiver when converting template
16377 // expressions to output AST.
16378 this._implicitReceiverExpr = null;
16379 // These should be handled in the template or element directly.
16380 this.visitReference = invalid$1;
16381 this.visitVariable = invalid$1;
16382 this.visitTextAttribute = invalid$1;
16383 this.visitBoundAttribute = invalid$1;
16384 this.visitBoundEvent = invalid$1;
16385 this._bindingScope = parentBindingScope.nestedScope(level);
16386 // Turn the relative context file path into an identifier by replacing non-alphanumeric
16387 // characters with underscores.
16388 this.fileBasedI18nSuffix = relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_') + '_';
16389 this._valueConverter = new ValueConverter(constantPool, () => this.allocateDataSlot(), (numSlots) => this.allocatePureFunctionSlots(numSlots), (name, localName, slot, value) => {
16390 const pipeType = pipeTypeByName.get(name);
16391 if (pipeType) {
16392 this.pipes.add(pipeType);
16393 }
16394 this._bindingScope.set(this.level, localName, value);
16395 this.creationInstruction(null, Identifiers$1.pipe, [literal(slot), literal(name)]);
16396 });
16397 }
16398 buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n) {
16399 this._ngContentSelectorsOffset = ngContentSelectorsOffset;
16400 if (this._namespace !== Identifiers$1.namespaceHTML) {
16401 this.creationInstruction(null, this._namespace);
16402 }
16403 // Create variable bindings
16404 variables.forEach(v => this.registerContextVariables(v));
16405 // Initiate i18n context in case:
16406 // - this template has parent i18n context
16407 // - or the template has i18n meta associated with it,
16408 // but it's not initiated by the Element (e.g. <ng-template i18n>)
16409 const initI18nContext = this.i18nContext ||
16410 (isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) &&
16411 !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n));
16412 const selfClosingI18nInstruction = hasTextChildrenOnly(nodes);
16413 if (initI18nContext) {
16414 this.i18nStart(null, i18n, selfClosingI18nInstruction);
16415 }
16416 // This is the initial pass through the nodes of this template. In this pass, we
16417 // queue all creation mode and update mode instructions for generation in the second
16418 // pass. It's necessary to separate the passes to ensure local refs are defined before
16419 // resolving bindings. We also count bindings in this pass as we walk bound expressions.
16420 visitAll(this, nodes);
16421 // Add total binding count to pure function count so pure function instructions are
16422 // generated with the correct slot offset when update instructions are processed.
16423 this._pureFunctionSlots += this._bindingSlots;
16424 // Pipes are walked in the first pass (to enqueue `pipe()` creation instructions and
16425 // `pipeBind` update instructions), so we have to update the slot offsets manually
16426 // to account for bindings.
16427 this._valueConverter.updatePipeSlotOffsets(this._bindingSlots);
16428 // Nested templates must be processed before creation instructions so template()
16429 // instructions can be generated with the correct internal const count.
16430 this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn());
16431 // Output the `projectionDef` instruction when some `<ng-content>` tags are present.
16432 // The `projectionDef` instruction is only emitted for the component template and
16433 // is skipped for nested templates (<ng-template> tags).
16434 if (this.level === 0 && this._ngContentReservedSlots.length) {
16435 const parameters = [];
16436 // By default the `projectionDef` instructions creates one slot for the wildcard
16437 // selector if no parameters are passed. Therefore we only want to allocate a new
16438 // array for the projection slots if the default projection slot is not sufficient.
16439 if (this._ngContentReservedSlots.length > 1 || this._ngContentReservedSlots[0] !== '*') {
16440 const r3ReservedSlots = this._ngContentReservedSlots.map(s => s !== '*' ? parseSelectorToR3Selector(s) : s);
16441 parameters.push(this.constantPool.getConstLiteral(asLiteral(r3ReservedSlots), true));
16442 }
16443 // Since we accumulate ngContent selectors while processing template elements,
16444 // we *prepend* `projectionDef` to creation instructions block, to put it before
16445 // any `projection` instructions
16446 this.creationInstruction(null, Identifiers$1.projectionDef, parameters, /* prepend */ true);
16447 }
16448 if (initI18nContext) {
16449 this.i18nEnd(null, selfClosingI18nInstruction);
16450 }
16451 // Generate all the creation mode instructions (e.g. resolve bindings in listeners)
16452 const creationStatements = this._creationCodeFns.map((fn) => fn());
16453 // Generate all the update mode instructions (e.g. resolve property or text bindings)
16454 const updateStatements = this._updateCodeFns.map((fn) => fn());
16455 // Variable declaration must occur after binding resolution so we can generate context
16456 // instructions that build on each other.
16457 // e.g. const b = nextContext().$implicit(); const b = nextContext();
16458 const creationVariables = this._bindingScope.viewSnapshotStatements();
16459 const updateVariables = this._bindingScope.variableDeclarations().concat(this._tempVariables);
16460 const creationBlock = creationStatements.length > 0 ?
16461 [renderFlagCheckIfStmt(1 /* Create */, creationVariables.concat(creationStatements))] :
16462 [];
16463 const updateBlock = updateStatements.length > 0 ?
16464 [renderFlagCheckIfStmt(2 /* Update */, updateVariables.concat(updateStatements))] :
16465 [];
16466 return fn(
16467 // i.e. (rf: RenderFlags, ctx: any)
16468 [new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
16469 // Temporary variable declarations for query refresh (i.e. let _t: any;)
16470 ...this._prefixCode,
16471 // Creating mode (i.e. if (rf & RenderFlags.Create) { ... })
16472 ...creationBlock,
16473 // Binding and refresh mode (i.e. if (rf & RenderFlags.Update) {...})
16474 ...updateBlock,
16475 ], INFERRED_TYPE, null, this.templateName);
16476 }
16477 // LocalResolver
16478 getLocal(name) {
16479 return this._bindingScope.get(name);
16480 }
16481 // LocalResolver
16482 notifyImplicitReceiverUse() {
16483 this._bindingScope.notifyImplicitReceiverUse();
16484 }
16485 i18nTranslate(message, params = {}, ref, transformFn) {
16486 const _ref = ref || this.i18nGenerateMainBlockVar();
16487 // Closure Compiler requires const names to start with `MSG_` but disallows any other const to
16488 // start with `MSG_`. We define a variable starting with `MSG_` just for the `goog.getMsg` call
16489 const closureVar = this.i18nGenerateClosureVar(message.id);
16490 const statements = getTranslationDeclStmts(message, _ref, closureVar, params, transformFn);
16491 this._constants.prepareStatements.push(...statements);
16492 return _ref;
16493 }
16494 registerContextVariables(variable$1) {
16495 const scopedName = this._bindingScope.freshReferenceName();
16496 const retrievalLevel = this.level;
16497 const lhs = variable(variable$1.name + scopedName);
16498 this._bindingScope.set(retrievalLevel, variable$1.name, lhs, 1 /* CONTEXT */, (scope, relativeLevel) => {
16499 let rhs;
16500 if (scope.bindingLevel === retrievalLevel) {
16501 // e.g. ctx
16502 rhs = variable(CONTEXT_NAME);
16503 }
16504 else {
16505 const sharedCtxVar = scope.getSharedContextName(retrievalLevel);
16506 // e.g. ctx_r0 OR x(2);
16507 rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel);
16508 }
16509 // e.g. const $item$ = x(2).$implicit;
16510 return [lhs.set(rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()];
16511 });
16512 }
16513 i18nAppendBindings(expressions) {
16514 if (expressions.length > 0) {
16515 expressions.forEach(expression => this.i18n.appendBinding(expression));
16516 }
16517 }
16518 i18nBindProps(props) {
16519 const bound = {};
16520 Object.keys(props).forEach(key => {
16521 const prop = props[key];
16522 if (prop instanceof Text) {
16523 bound[key] = literal(prop.value);
16524 }
16525 else {
16526 const value = prop.value.visit(this._valueConverter);
16527 this.allocateBindingSlots(value);
16528 if (value instanceof Interpolation) {
16529 const { strings, expressions } = value;
16530 const { id, bindings } = this.i18n;
16531 const label = assembleI18nBoundString(strings, bindings.size, id);
16532 this.i18nAppendBindings(expressions);
16533 bound[key] = literal(label);
16534 }
16535 }
16536 });
16537 return bound;
16538 }
16539 // Generates top level vars for i18n blocks (i.e. `i18n_N`).
16540 i18nGenerateMainBlockVar() {
16541 return variable(this.constantPool.uniqueName(TRANSLATION_VAR_PREFIX));
16542 }
16543 // Generates vars with Closure-specific names for i18n blocks (i.e. `MSG_XXX`).
16544 i18nGenerateClosureVar(messageId) {
16545 let name;
16546 const suffix = this.fileBasedI18nSuffix.toUpperCase();
16547 if (this.i18nUseExternalIds) {
16548 const prefix = getTranslationConstPrefix(`EXTERNAL_`);
16549 const uniqueSuffix = this.constantPool.uniqueName(suffix);
16550 name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`;
16551 }
16552 else {
16553 const prefix = getTranslationConstPrefix(suffix);
16554 name = this.constantPool.uniqueName(prefix);
16555 }
16556 return variable(name);
16557 }
16558 i18nUpdateRef(context) {
16559 const { icus, meta, isRoot, isResolved, isEmitted } = context;
16560 if (isRoot && isResolved && !isEmitted && !isSingleI18nIcu(meta)) {
16561 context.isEmitted = true;
16562 const placeholders = context.getSerializedPlaceholders();
16563 let icuMapping = {};
16564 let params = placeholders.size ? placeholdersToParams(placeholders) : {};
16565 if (icus.size) {
16566 icus.forEach((refs, key) => {
16567 if (refs.length === 1) {
16568 // if we have one ICU defined for a given
16569 // placeholder - just output its reference
16570 params[key] = refs[0];
16571 }
16572 else {
16573 // ... otherwise we need to activate post-processing
16574 // to replace ICU placeholders with proper values
16575 const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX}${key}`);
16576 params[key] = literal(placeholder);
16577 icuMapping[key] = literalArr(refs);
16578 }
16579 });
16580 }
16581 // translation requires post processing in 2 cases:
16582 // - if we have placeholders with multiple values (ex. `START_DIV`: [�#1�, �#2�, ...])
16583 // - if we have multiple ICUs that refer to the same placeholder name
16584 const needsPostprocessing = Array.from(placeholders.values()).some((value) => value.length > 1) ||
16585 Object.keys(icuMapping).length;
16586 let transformFn;
16587 if (needsPostprocessing) {
16588 transformFn = (raw) => {
16589 const args = [raw];
16590 if (Object.keys(icuMapping).length) {
16591 args.push(mapLiteral(icuMapping, true));
16592 }
16593 return instruction(null, Identifiers$1.i18nPostprocess, args);
16594 };
16595 }
16596 this.i18nTranslate(meta, params, context.ref, transformFn);
16597 }
16598 }
16599 i18nStart(span = null, meta, selfClosing) {
16600 const index = this.allocateDataSlot();
16601 this.i18n = this.i18nContext ?
16602 this.i18nContext.forkChildContext(index, this.templateIndex, meta) :
16603 new I18nContext(index, this.i18nGenerateMainBlockVar(), 0, this.templateIndex, meta);
16604 // generate i18nStart instruction
16605 const { id, ref } = this.i18n;
16606 const params = [literal(index), this.addToConsts(ref)];
16607 if (id > 0) {
16608 // do not push 3rd argument (sub-block id)
16609 // into i18nStart call for top level i18n context
16610 params.push(literal(id));
16611 }
16612 this.creationInstruction(span, selfClosing ? Identifiers$1.i18n : Identifiers$1.i18nStart, params);
16613 }
16614 i18nEnd(span = null, selfClosing) {
16615 if (!this.i18n) {
16616 throw new Error('i18nEnd is executed with no i18n context present');
16617 }
16618 if (this.i18nContext) {
16619 this.i18nContext.reconcileChildContext(this.i18n);
16620 this.i18nUpdateRef(this.i18nContext);
16621 }
16622 else {
16623 this.i18nUpdateRef(this.i18n);
16624 }
16625 // setup accumulated bindings
16626 const { index, bindings } = this.i18n;
16627 if (bindings.size) {
16628 const chainBindings = [];
16629 bindings.forEach(binding => {
16630 chainBindings.push({ sourceSpan: span, value: () => this.convertPropertyBinding(binding) });
16631 });
16632 // for i18n block, advance to the most recent element index (by taking the current number of
16633 // elements and subtracting one) before invoking `i18nExp` instructions, to make sure the
16634 // necessary lifecycle hooks of components/directives are properly flushed.
16635 this.updateInstructionChainWithAdvance(this.getConstCount() - 1, Identifiers$1.i18nExp, chainBindings);
16636 this.updateInstruction(span, Identifiers$1.i18nApply, [literal(index)]);
16637 }
16638 if (!selfClosing) {
16639 this.creationInstruction(span, Identifiers$1.i18nEnd);
16640 }
16641 this.i18n = null; // reset local i18n context
16642 }
16643 i18nAttributesInstruction(nodeIndex, attrs, sourceSpan) {
16644 let hasBindings = false;
16645 const i18nAttrArgs = [];
16646 const bindings = [];
16647 attrs.forEach(attr => {
16648 const message = attr.i18n;
16649 const converted = attr.value.visit(this._valueConverter);
16650 this.allocateBindingSlots(converted);
16651 if (converted instanceof Interpolation) {
16652 const placeholders = assembleBoundTextPlaceholders(message);
16653 const params = placeholdersToParams(placeholders);
16654 i18nAttrArgs.push(literal(attr.name), this.i18nTranslate(message, params));
16655 converted.expressions.forEach(expression => {
16656 hasBindings = true;
16657 bindings.push({
16658 sourceSpan,
16659 value: () => this.convertPropertyBinding(expression),
16660 });
16661 });
16662 }
16663 });
16664 if (bindings.length > 0) {
16665 this.updateInstructionChainWithAdvance(nodeIndex, Identifiers$1.i18nExp, bindings);
16666 }
16667 if (i18nAttrArgs.length > 0) {
16668 const index = literal(this.allocateDataSlot());
16669 const constIndex = this.addToConsts(literalArr(i18nAttrArgs));
16670 this.creationInstruction(sourceSpan, Identifiers$1.i18nAttributes, [index, constIndex]);
16671 if (hasBindings) {
16672 this.updateInstruction(sourceSpan, Identifiers$1.i18nApply, [index]);
16673 }
16674 }
16675 }
16676 getNamespaceInstruction(namespaceKey) {
16677 switch (namespaceKey) {
16678 case 'math':
16679 return Identifiers$1.namespaceMathML;
16680 case 'svg':
16681 return Identifiers$1.namespaceSVG;
16682 default:
16683 return Identifiers$1.namespaceHTML;
16684 }
16685 }
16686 addNamespaceInstruction(nsInstruction, element) {
16687 this._namespace = nsInstruction;
16688 this.creationInstruction(element.startSourceSpan, nsInstruction);
16689 }
16690 /**
16691 * Adds an update instruction for an interpolated property or attribute, such as
16692 * `prop="{{value}}"` or `attr.title="{{value}}"`
16693 */
16694 interpolatedUpdateInstruction(instruction, elementIndex, attrName, input, value, params) {
16695 this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, instruction, () => [literal(attrName), ...this.getUpdateInstructionArguments(value), ...params]);
16696 }
16697 visitContent(ngContent) {
16698 const slot = this.allocateDataSlot();
16699 const projectionSlotIdx = this._ngContentSelectorsOffset + this._ngContentReservedSlots.length;
16700 const parameters = [literal(slot)];
16701 this._ngContentReservedSlots.push(ngContent.selector);
16702 const nonContentSelectAttributes = ngContent.attributes.filter(attr => attr.name.toLowerCase() !== NG_CONTENT_SELECT_ATTR$1);
16703 const attributes = this.getAttributeExpressions(ngContent.name, nonContentSelectAttributes, [], []);
16704 if (attributes.length > 0) {
16705 parameters.push(literal(projectionSlotIdx), literalArr(attributes));
16706 }
16707 else if (projectionSlotIdx !== 0) {
16708 parameters.push(literal(projectionSlotIdx));
16709 }
16710 this.creationInstruction(ngContent.sourceSpan, Identifiers$1.projection, parameters);
16711 if (this.i18n) {
16712 this.i18n.appendProjection(ngContent.i18n, slot);
16713 }
16714 }
16715 visitElement(element) {
16716 var _a, _b;
16717 const elementIndex = this.allocateDataSlot();
16718 const stylingBuilder = new StylingBuilder(null);
16719 let isNonBindableMode = false;
16720 const isI18nRootElement = isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n);
16721 const outputAttrs = [];
16722 const [namespaceKey, elementName] = splitNsName(element.name);
16723 const isNgContainer$1 = isNgContainer(element.name);
16724 // Handle styling, i18n, ngNonBindable attributes
16725 for (const attr of element.attributes) {
16726 const { name, value } = attr;
16727 if (name === NON_BINDABLE_ATTR) {
16728 isNonBindableMode = true;
16729 }
16730 else if (name === 'style') {
16731 stylingBuilder.registerStyleAttr(value);
16732 }
16733 else if (name === 'class') {
16734 stylingBuilder.registerClassAttr(value);
16735 }
16736 else {
16737 outputAttrs.push(attr);
16738 }
16739 }
16740 // Match directives on non i18n attributes
16741 this.matchDirectives(element.name, element);
16742 // Regular element or ng-container creation mode
16743 const parameters = [literal(elementIndex)];
16744 if (!isNgContainer$1) {
16745 parameters.push(literal(elementName));
16746 }
16747 // Add the attributes
16748 const allOtherInputs = [];
16749 const boundI18nAttrs = [];
16750 element.inputs.forEach(input => {
16751 const stylingInputWasSet = stylingBuilder.registerBoundInput(input);
16752 if (!stylingInputWasSet) {
16753 if (input.type === 0 /* Property */ && input.i18n) {
16754 boundI18nAttrs.push(input);
16755 }
16756 else {
16757 allOtherInputs.push(input);
16758 }
16759 }
16760 });
16761 // add attributes for directive and projection matching purposes
16762 const attributes = this.getAttributeExpressions(element.name, outputAttrs, allOtherInputs, element.outputs, stylingBuilder, [], boundI18nAttrs);
16763 parameters.push(this.addAttrsToConsts(attributes));
16764 // local refs (ex.: <div #foo #bar="baz">)
16765 const refs = this.prepareRefsArray(element.references);
16766 parameters.push(this.addToConsts(refs));
16767 const wasInNamespace = this._namespace;
16768 const currentNamespace = this.getNamespaceInstruction(namespaceKey);
16769 // If the namespace is changing now, include an instruction to change it
16770 // during element creation.
16771 if (currentNamespace !== wasInNamespace) {
16772 this.addNamespaceInstruction(currentNamespace, element);
16773 }
16774 if (this.i18n) {
16775 this.i18n.appendElement(element.i18n, elementIndex);
16776 }
16777 // Note that we do not append text node instructions and ICUs inside i18n section,
16778 // so we exclude them while calculating whether current element has children
16779 const hasChildren = (!isI18nRootElement && this.i18n) ? !hasTextChildrenOnly(element.children) :
16780 element.children.length > 0;
16781 const createSelfClosingInstruction = !stylingBuilder.hasBindingsWithPipes &&
16782 element.outputs.length === 0 && boundI18nAttrs.length === 0 && !hasChildren;
16783 const createSelfClosingI18nInstruction = !createSelfClosingInstruction && hasTextChildrenOnly(element.children);
16784 if (createSelfClosingInstruction) {
16785 this.creationInstruction(element.sourceSpan, isNgContainer$1 ? Identifiers$1.elementContainer : Identifiers$1.element, trimTrailingNulls(parameters));
16786 }
16787 else {
16788 this.creationInstruction(element.startSourceSpan, isNgContainer$1 ? Identifiers$1.elementContainerStart : Identifiers$1.elementStart, trimTrailingNulls(parameters));
16789 if (isNonBindableMode) {
16790 this.creationInstruction(element.startSourceSpan, Identifiers$1.disableBindings);
16791 }
16792 if (boundI18nAttrs.length > 0) {
16793 this.i18nAttributesInstruction(elementIndex, boundI18nAttrs, (_a = element.startSourceSpan) !== null && _a !== void 0 ? _a : element.sourceSpan);
16794 }
16795 // Generate Listeners (outputs)
16796 if (element.outputs.length > 0) {
16797 const listeners = element.outputs.map((outputAst) => ({
16798 sourceSpan: outputAst.sourceSpan,
16799 params: this.prepareListenerParameter(element.name, outputAst, elementIndex)
16800 }));
16801 this.creationInstructionChain(Identifiers$1.listener, listeners);
16802 }
16803 // Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
16804 // listeners, to make sure i18nAttributes instruction targets current element at runtime.
16805 if (isI18nRootElement) {
16806 this.i18nStart(element.startSourceSpan, element.i18n, createSelfClosingI18nInstruction);
16807 }
16808 }
16809 // the code here will collect all update-level styling instructions and add them to the
16810 // update block of the template function AOT code. Instructions like `styleProp`,
16811 // `styleMap`, `classMap`, `classProp`
16812 // are all generated and assigned in the code below.
16813 const stylingInstructions = stylingBuilder.buildUpdateLevelInstructions(this._valueConverter);
16814 const limit = stylingInstructions.length - 1;
16815 for (let i = 0; i <= limit; i++) {
16816 const instruction = stylingInstructions[i];
16817 this._bindingSlots += this.processStylingUpdateInstruction(elementIndex, instruction);
16818 }
16819 // the reason why `undefined` is used is because the renderer understands this as a
16820 // special value to symbolize that there is no RHS to this binding
16821 // TODO (matsko): revisit this once FW-959 is approached
16822 const emptyValueBindInstruction = literal(undefined);
16823 const propertyBindings = [];
16824 const attributeBindings = [];
16825 // Generate element input bindings
16826 allOtherInputs.forEach(input => {
16827 const inputType = input.type;
16828 if (inputType === 4 /* Animation */) {
16829 const value = input.value.visit(this._valueConverter);
16830 // animation bindings can be presented in the following formats:
16831 // 1. [@binding]="fooExp"
16832 // 2. [@binding]="{value:fooExp, params:{...}}"
16833 // 3. [@binding]
16834 // 4. @binding
16835 // All formats will be valid for when a synthetic binding is created.
16836 // The reasoning for this is because the renderer should get each
16837 // synthetic binding value in the order of the array that they are
16838 // defined in...
16839 const hasValue = value instanceof LiteralPrimitive ? !!value.value : true;
16840 this.allocateBindingSlots(value);
16841 propertyBindings.push({
16842 name: prepareSyntheticPropertyName(input.name),
16843 sourceSpan: input.sourceSpan,
16844 value: () => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction
16845 });
16846 }
16847 else {
16848 // we must skip attributes with associated i18n context, since these attributes are handled
16849 // separately and corresponding `i18nExp` and `i18nApply` instructions will be generated
16850 if (input.i18n)
16851 return;
16852 const value = input.value.visit(this._valueConverter);
16853 if (value !== undefined) {
16854 const params = [];
16855 const [attrNamespace, attrName] = splitNsName(input.name);
16856 const isAttributeBinding = inputType === 1 /* Attribute */;
16857 const sanitizationRef = resolveSanitizationFn(input.securityContext, isAttributeBinding);
16858 if (sanitizationRef)
16859 params.push(sanitizationRef);
16860 if (attrNamespace) {
16861 const namespaceLiteral = literal(attrNamespace);
16862 if (sanitizationRef) {
16863 params.push(namespaceLiteral);
16864 }
16865 else {
16866 // If there wasn't a sanitization ref, we need to add
16867 // an extra param so that we can pass in the namespace.
16868 params.push(literal(null), namespaceLiteral);
16869 }
16870 }
16871 this.allocateBindingSlots(value);
16872 if (inputType === 0 /* Property */) {
16873 if (value instanceof Interpolation) {
16874 // prop="{{value}}" and friends
16875 this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), elementIndex, attrName, input, value, params);
16876 }
16877 else {
16878 // [prop]="value"
16879 // Collect all the properties so that we can chain into a single function at the end.
16880 propertyBindings.push({
16881 name: attrName,
16882 sourceSpan: input.sourceSpan,
16883 value: () => this.convertPropertyBinding(value),
16884 params
16885 });
16886 }
16887 }
16888 else if (inputType === 1 /* Attribute */) {
16889 if (value instanceof Interpolation && getInterpolationArgsLength(value) > 1) {
16890 // attr.name="text{{value}}" and friends
16891 this.interpolatedUpdateInstruction(getAttributeInterpolationExpression(value), elementIndex, attrName, input, value, params);
16892 }
16893 else {
16894 const boundValue = value instanceof Interpolation ? value.expressions[0] : value;
16895 // [attr.name]="value" or attr.name="{{value}}"
16896 // Collect the attribute bindings so that they can be chained at the end.
16897 attributeBindings.push({
16898 name: attrName,
16899 sourceSpan: input.sourceSpan,
16900 value: () => this.convertPropertyBinding(boundValue),
16901 params
16902 });
16903 }
16904 }
16905 else {
16906 // class prop
16907 this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, Identifiers$1.classProp, () => {
16908 return [
16909 literal(elementIndex), literal(attrName), this.convertPropertyBinding(value),
16910 ...params
16911 ];
16912 });
16913 }
16914 }
16915 }
16916 });
16917 if (propertyBindings.length > 0) {
16918 this.updateInstructionChainWithAdvance(elementIndex, Identifiers$1.property, propertyBindings);
16919 }
16920 if (attributeBindings.length > 0) {
16921 this.updateInstructionChainWithAdvance(elementIndex, Identifiers$1.attribute, attributeBindings);
16922 }
16923 // Traverse element child nodes
16924 visitAll(this, element.children);
16925 if (!isI18nRootElement && this.i18n) {
16926 this.i18n.appendElement(element.i18n, elementIndex, true);
16927 }
16928 if (!createSelfClosingInstruction) {
16929 // Finish element construction mode.
16930 const span = (_b = element.endSourceSpan) !== null && _b !== void 0 ? _b : element.sourceSpan;
16931 if (isI18nRootElement) {
16932 this.i18nEnd(span, createSelfClosingI18nInstruction);
16933 }
16934 if (isNonBindableMode) {
16935 this.creationInstruction(span, Identifiers$1.enableBindings);
16936 }
16937 this.creationInstruction(span, isNgContainer$1 ? Identifiers$1.elementContainerEnd : Identifiers$1.elementEnd);
16938 }
16939 }
16940 visitTemplate(template) {
16941 var _a;
16942 const NG_TEMPLATE_TAG_NAME = 'ng-template';
16943 const templateIndex = this.allocateDataSlot();
16944 if (this.i18n) {
16945 this.i18n.appendTemplate(template.i18n, templateIndex);
16946 }
16947 const tagName = sanitizeIdentifier(template.tagName || '');
16948 const contextName = `${this.contextName}${tagName ? '_' + tagName : ''}_${templateIndex}`;
16949 const templateName = `${contextName}_Template`;
16950 const parameters = [
16951 literal(templateIndex),
16952 variable(templateName),
16953 // We don't care about the tag's namespace here, because we infer
16954 // it based on the parent nodes inside the template instruction.
16955 literal(template.tagName ? splitNsName(template.tagName)[1] : template.tagName),
16956 ];
16957 // find directives matching on a given <ng-template> node
16958 this.matchDirectives(NG_TEMPLATE_TAG_NAME, template);
16959 // prepare attributes parameter (including attributes used for directive matching)
16960 const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
16961 parameters.push(this.addAttrsToConsts(attrsExprs));
16962 // local refs (ex.: <ng-template #foo>)
16963 if (template.references && template.references.length) {
16964 const refs = this.prepareRefsArray(template.references);
16965 parameters.push(this.addToConsts(refs));
16966 parameters.push(importExpr(Identifiers$1.templateRefExtractor));
16967 }
16968 // Create the template function
16969 const templateVisitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, templateIndex, templateName, this.directiveMatcher, this.directives, this.pipeTypeByName, this.pipes, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this._constants);
16970 // Nested templates must not be visited until after their parent templates have completed
16971 // processing, so they are queued here until after the initial pass. Otherwise, we wouldn't
16972 // be able to support bindings in nested templates to local refs that occur after the
16973 // template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
16974 this._nestedTemplateFns.push(() => {
16975 const templateFunctionExpr = templateVisitor.buildTemplateFunction(template.children, template.variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, template.i18n);
16976 this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName));
16977 if (templateVisitor._ngContentReservedSlots.length) {
16978 this._ngContentReservedSlots.push(...templateVisitor._ngContentReservedSlots);
16979 }
16980 });
16981 // e.g. template(1, MyComp_Template_1)
16982 this.creationInstruction(template.sourceSpan, Identifiers$1.templateCreate, () => {
16983 parameters.splice(2, 0, literal(templateVisitor.getConstCount()), literal(templateVisitor.getVarCount()));
16984 return trimTrailingNulls(parameters);
16985 });
16986 // handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al;
16987 this.templatePropertyBindings(templateIndex, template.templateAttrs);
16988 // Only add normal input/output binding instructions on explicit <ng-template> elements.
16989 if (template.tagName === NG_TEMPLATE_TAG_NAME) {
16990 const [i18nInputs, inputs] = partitionArray(template.inputs, hasI18nMeta);
16991 // Add i18n attributes that may act as inputs to directives. If such attributes are present,
16992 // generate `i18nAttributes` instruction. Note: we generate it only for explicit <ng-template>
16993 // elements, in case of inline templates, corresponding instructions will be generated in the
16994 // nested template function.
16995 if (i18nInputs.length > 0) {
16996 this.i18nAttributesInstruction(templateIndex, i18nInputs, (_a = template.startSourceSpan) !== null && _a !== void 0 ? _a : template.sourceSpan);
16997 }
16998 // Add the input bindings
16999 if (inputs.length > 0) {
17000 this.templatePropertyBindings(templateIndex, inputs);
17001 }
17002 // Generate listeners for directive output
17003 if (template.outputs.length > 0) {
17004 const listeners = template.outputs.map((outputAst) => ({
17005 sourceSpan: outputAst.sourceSpan,
17006 params: this.prepareListenerParameter('ng_template', outputAst, templateIndex)
17007 }));
17008 this.creationInstructionChain(Identifiers$1.listener, listeners);
17009 }
17010 }
17011 }
17012 visitBoundText(text) {
17013 if (this.i18n) {
17014 const value = text.value.visit(this._valueConverter);
17015 this.allocateBindingSlots(value);
17016 if (value instanceof Interpolation) {
17017 this.i18n.appendBoundText(text.i18n);
17018 this.i18nAppendBindings(value.expressions);
17019 }
17020 return;
17021 }
17022 const nodeIndex = this.allocateDataSlot();
17023 this.creationInstruction(text.sourceSpan, Identifiers$1.text, [literal(nodeIndex)]);
17024 const value = text.value.visit(this._valueConverter);
17025 this.allocateBindingSlots(value);
17026 if (value instanceof Interpolation) {
17027 this.updateInstructionWithAdvance(nodeIndex, text.sourceSpan, getTextInterpolationExpression(value), () => this.getUpdateInstructionArguments(value));
17028 }
17029 else {
17030 error('Text nodes should be interpolated and never bound directly.');
17031 }
17032 }
17033 visitText(text) {
17034 // when a text element is located within a translatable
17035 // block, we exclude this text element from instructions set,
17036 // since it will be captured in i18n content and processed at runtime
17037 if (!this.i18n) {
17038 this.creationInstruction(text.sourceSpan, Identifiers$1.text, [literal(this.allocateDataSlot()), literal(text.value)]);
17039 }
17040 }
17041 visitIcu(icu) {
17042 let initWasInvoked = false;
17043 // if an ICU was created outside of i18n block, we still treat
17044 // it as a translatable entity and invoke i18nStart and i18nEnd
17045 // to generate i18n context and the necessary instructions
17046 if (!this.i18n) {
17047 initWasInvoked = true;
17048 this.i18nStart(null, icu.i18n, true);
17049 }
17050 const i18n = this.i18n;
17051 const vars = this.i18nBindProps(icu.vars);
17052 const placeholders = this.i18nBindProps(icu.placeholders);
17053 // output ICU directly and keep ICU reference in context
17054 const message = icu.i18n;
17055 // we always need post-processing function for ICUs, to make sure that:
17056 // - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note:
17057 // `goog.getMsg` does not process ICUs and uses the `{PLACEHOLDER}` format for placeholders
17058 // inside ICUs)
17059 // - all ICU vars (such as `VAR_SELECT` or `VAR_PLURAL`) are replaced with correct values
17060 const transformFn = (raw) => {
17061 const params = Object.assign(Object.assign({}, vars), placeholders);
17062 const formatted = i18nFormatPlaceholderNames(params, /* useCamelCase */ false);
17063 return instruction(null, Identifiers$1.i18nPostprocess, [raw, mapLiteral(formatted, true)]);
17064 };
17065 // in case the whole i18n message is a single ICU - we do not need to
17066 // create a separate top-level translation, we can use the root ref instead
17067 // and make this ICU a top-level translation
17068 // note: ICU placeholders are replaced with actual values in `i18nPostprocess` function
17069 // separately, so we do not pass placeholders into `i18nTranslate` function.
17070 if (isSingleI18nIcu(i18n.meta)) {
17071 this.i18nTranslate(message, /* placeholders */ {}, i18n.ref, transformFn);
17072 }
17073 else {
17074 // output ICU directly and keep ICU reference in context
17075 const ref = this.i18nTranslate(message, /* placeholders */ {}, /* ref */ undefined, transformFn);
17076 i18n.appendIcu(icuFromI18nMessage(message).name, ref);
17077 }
17078 if (initWasInvoked) {
17079 this.i18nEnd(null, true);
17080 }
17081 return null;
17082 }
17083 allocateDataSlot() {
17084 return this._dataIndex++;
17085 }
17086 getConstCount() {
17087 return this._dataIndex;
17088 }
17089 getVarCount() {
17090 return this._pureFunctionSlots;
17091 }
17092 getConsts() {
17093 return this._constants;
17094 }
17095 getNgContentSelectors() {
17096 return this._ngContentReservedSlots.length ?
17097 this.constantPool.getConstLiteral(asLiteral(this._ngContentReservedSlots), true) :
17098 null;
17099 }
17100 bindingContext() {
17101 return `${this._bindingContext++}`;
17102 }
17103 templatePropertyBindings(templateIndex, attrs) {
17104 const propertyBindings = [];
17105 attrs.forEach(input => {
17106 if (input instanceof BoundAttribute) {
17107 const value = input.value.visit(this._valueConverter);
17108 if (value !== undefined) {
17109 this.allocateBindingSlots(value);
17110 if (value instanceof Interpolation) {
17111 // Params typically contain attribute namespace and value sanitizer, which is applicable
17112 // for regular HTML elements, but not applicable for <ng-template> (since props act as
17113 // inputs to directives), so keep params array empty.
17114 const params = [];
17115 // prop="{{value}}" case
17116 this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), templateIndex, input.name, input, value, params);
17117 }
17118 else {
17119 // [prop]="value" case
17120 propertyBindings.push({
17121 name: input.name,
17122 sourceSpan: input.sourceSpan,
17123 value: () => this.convertPropertyBinding(value)
17124 });
17125 }
17126 }
17127 }
17128 });
17129 if (propertyBindings.length > 0) {
17130 this.updateInstructionChainWithAdvance(templateIndex, Identifiers$1.property, propertyBindings);
17131 }
17132 }
17133 // Bindings must only be resolved after all local refs have been visited, so all
17134 // instructions are queued in callbacks that execute once the initial pass has completed.
17135 // Otherwise, we wouldn't be able to support local refs that are defined after their
17136 // bindings. e.g. {{ foo }} <div #foo></div>
17137 instructionFn(fns, span, reference, paramsOrFn, prepend = false) {
17138 fns[prepend ? 'unshift' : 'push'](() => {
17139 const params = Array.isArray(paramsOrFn) ? paramsOrFn : paramsOrFn();
17140 return instruction(span, reference, params).toStmt();
17141 });
17142 }
17143 processStylingUpdateInstruction(elementIndex, instruction) {
17144 let allocateBindingSlots = 0;
17145 if (instruction) {
17146 const calls = [];
17147 instruction.calls.forEach(call => {
17148 allocateBindingSlots += call.allocateBindingSlots;
17149 calls.push({
17150 sourceSpan: call.sourceSpan,
17151 value: () => {
17152 return call.params(value => (call.supportsInterpolation && value instanceof Interpolation) ?
17153 this.getUpdateInstructionArguments(value) :
17154 this.convertPropertyBinding(value));
17155 }
17156 });
17157 });
17158 this.updateInstructionChainWithAdvance(elementIndex, instruction.reference, calls);
17159 }
17160 return allocateBindingSlots;
17161 }
17162 creationInstruction(span, reference, paramsOrFn, prepend) {
17163 this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend);
17164 }
17165 creationInstructionChain(reference, calls) {
17166 const span = calls.length ? calls[0].sourceSpan : null;
17167 this._creationCodeFns.push(() => {
17168 return chainedInstruction(reference, calls.map(call => call.params()), span).toStmt();
17169 });
17170 }
17171 updateInstructionWithAdvance(nodeIndex, span, reference, paramsOrFn) {
17172 this.addAdvanceInstructionIfNecessary(nodeIndex, span);
17173 this.updateInstruction(span, reference, paramsOrFn);
17174 }
17175 updateInstruction(span, reference, paramsOrFn) {
17176 this.instructionFn(this._updateCodeFns, span, reference, paramsOrFn || []);
17177 }
17178 updateInstructionChain(reference, bindings) {
17179 const span = bindings.length ? bindings[0].sourceSpan : null;
17180 this._updateCodeFns.push(() => {
17181 const calls = bindings.map(property => {
17182 const value = property.value();
17183 const fnParams = Array.isArray(value) ? value : [value];
17184 if (property.params) {
17185 fnParams.push(...property.params);
17186 }
17187 if (property.name) {
17188 // We want the property name to always be the first function parameter.
17189 fnParams.unshift(literal(property.name));
17190 }
17191 return fnParams;
17192 });
17193 return chainedInstruction(reference, calls, span).toStmt();
17194 });
17195 }
17196 updateInstructionChainWithAdvance(nodeIndex, reference, bindings) {
17197 this.addAdvanceInstructionIfNecessary(nodeIndex, bindings.length ? bindings[0].sourceSpan : null);
17198 this.updateInstructionChain(reference, bindings);
17199 }
17200 addAdvanceInstructionIfNecessary(nodeIndex, span) {
17201 if (nodeIndex !== this._currentIndex) {
17202 const delta = nodeIndex - this._currentIndex;
17203 if (delta < 1) {
17204 throw new Error('advance instruction can only go forwards');
17205 }
17206 this.instructionFn(this._updateCodeFns, span, Identifiers$1.advance, [literal(delta)]);
17207 this._currentIndex = nodeIndex;
17208 }
17209 }
17210 allocatePureFunctionSlots(numSlots) {
17211 const originalSlots = this._pureFunctionSlots;
17212 this._pureFunctionSlots += numSlots;
17213 return originalSlots;
17214 }
17215 allocateBindingSlots(value) {
17216 this._bindingSlots += value instanceof Interpolation ? value.expressions.length : 1;
17217 }
17218 /**
17219 * Gets an expression that refers to the implicit receiver. The implicit
17220 * receiver is always the root level context.
17221 */
17222 getImplicitReceiverExpr() {
17223 if (this._implicitReceiverExpr) {
17224 return this._implicitReceiverExpr;
17225 }
17226 return this._implicitReceiverExpr = this.level === 0 ?
17227 variable(CONTEXT_NAME) :
17228 this._bindingScope.getOrCreateSharedContextVar(0);
17229 }
17230 convertPropertyBinding(value) {
17231 const convertedPropertyBinding = convertPropertyBinding(this, this.getImplicitReceiverExpr(), value, this.bindingContext(), BindingForm.Expression, () => error('Unexpected interpolation'));
17232 const valExpr = convertedPropertyBinding.currValExpr;
17233 this._tempVariables.push(...convertedPropertyBinding.stmts);
17234 return valExpr;
17235 }
17236 /**
17237 * Gets a list of argument expressions to pass to an update instruction expression. Also updates
17238 * the temp variables state with temp variables that were identified as needing to be created
17239 * while visiting the arguments.
17240 * @param value The original expression we will be resolving an arguments list from.
17241 */
17242 getUpdateInstructionArguments(value) {
17243 const { args, stmts } = convertUpdateArguments(this, this.getImplicitReceiverExpr(), value, this.bindingContext());
17244 this._tempVariables.push(...stmts);
17245 return args;
17246 }
17247 matchDirectives(elementName, elOrTpl) {
17248 if (this.directiveMatcher) {
17249 const selector = createCssSelector(elementName, getAttrsForDirectiveMatching(elOrTpl));
17250 this.directiveMatcher.match(selector, (cssSelector, staticType) => {
17251 this.directives.add(staticType);
17252 });
17253 }
17254 }
17255 /**
17256 * Prepares all attribute expression values for the `TAttributes` array.
17257 *
17258 * The purpose of this function is to properly construct an attributes array that
17259 * is passed into the `elementStart` (or just `element`) functions. Because there
17260 * are many different types of attributes, the array needs to be constructed in a
17261 * special way so that `elementStart` can properly evaluate them.
17262 *
17263 * The format looks like this:
17264 *
17265 * ```
17266 * attrs = [prop, value, prop2, value2,
17267 * PROJECT_AS, selector,
17268 * CLASSES, class1, class2,
17269 * STYLES, style1, value1, style2, value2,
17270 * BINDINGS, name1, name2, name3,
17271 * TEMPLATE, name4, name5, name6,
17272 * I18N, name7, name8, ...]
17273 * ```
17274 *
17275 * Note that this function will fully ignore all synthetic (@foo) attribute values
17276 * because those values are intended to always be generated as property instructions.
17277 */
17278 getAttributeExpressions(elementName, renderAttributes, inputs, outputs, styles, templateAttrs = [], boundI18nAttrs = []) {
17279 const alreadySeen = new Set();
17280 const attrExprs = [];
17281 let ngProjectAsAttr;
17282 for (const attr of renderAttributes) {
17283 if (attr.name === NG_PROJECT_AS_ATTR_NAME) {
17284 ngProjectAsAttr = attr;
17285 }
17286 // Note that static i18n attributes aren't in the i18n array,
17287 // because they're treated in the same way as regular attributes.
17288 if (attr.i18n) {
17289 // When i18n attributes are present on elements with structural directives
17290 // (e.g. `<div *ngIf title="Hello" i18n-title>`), we want to avoid generating
17291 // duplicate i18n translation blocks for `ɵɵtemplate` and `ɵɵelement` instruction
17292 // attributes. So we do a cache lookup to see if suitable i18n translation block
17293 // already exists.
17294 const { i18nVarRefsCache } = this._constants;
17295 let i18nVarRef;
17296 if (i18nVarRefsCache.has(attr.i18n)) {
17297 i18nVarRef = i18nVarRefsCache.get(attr.i18n);
17298 }
17299 else {
17300 i18nVarRef = this.i18nTranslate(attr.i18n);
17301 i18nVarRefsCache.set(attr.i18n, i18nVarRef);
17302 }
17303 attrExprs.push(literal(attr.name), i18nVarRef);
17304 }
17305 else {
17306 attrExprs.push(...getAttributeNameLiterals(attr.name), trustedConstAttribute(elementName, attr));
17307 }
17308 }
17309 // Keep ngProjectAs next to the other name, value pairs so we can verify that we match
17310 // ngProjectAs marker in the attribute name slot.
17311 if (ngProjectAsAttr) {
17312 attrExprs.push(...getNgProjectAsLiteral(ngProjectAsAttr));
17313 }
17314 function addAttrExpr(key, value) {
17315 if (typeof key === 'string') {
17316 if (!alreadySeen.has(key)) {
17317 attrExprs.push(...getAttributeNameLiterals(key));
17318 value !== undefined && attrExprs.push(value);
17319 alreadySeen.add(key);
17320 }
17321 }
17322 else {
17323 attrExprs.push(literal(key));
17324 }
17325 }
17326 // it's important that this occurs before BINDINGS and TEMPLATE because once `elementStart`
17327 // comes across the BINDINGS or TEMPLATE markers then it will continue reading each value as
17328 // as single property value cell by cell.
17329 if (styles) {
17330 styles.populateInitialStylingAttrs(attrExprs);
17331 }
17332 if (inputs.length || outputs.length) {
17333 const attrsLengthBeforeInputs = attrExprs.length;
17334 for (let i = 0; i < inputs.length; i++) {
17335 const input = inputs[i];
17336 // We don't want the animation and attribute bindings in the
17337 // attributes array since they aren't used for directive matching.
17338 if (input.type !== 4 /* Animation */ && input.type !== 1 /* Attribute */) {
17339 addAttrExpr(input.name);
17340 }
17341 }
17342 for (let i = 0; i < outputs.length; i++) {
17343 const output = outputs[i];
17344 if (output.type !== 1 /* Animation */) {
17345 addAttrExpr(output.name);
17346 }
17347 }
17348 // this is a cheap way of adding the marker only after all the input/output
17349 // values have been filtered (by not including the animation ones) and added
17350 // to the expressions. The marker is important because it tells the runtime
17351 // code that this is where attributes without values start...
17352 if (attrExprs.length !== attrsLengthBeforeInputs) {
17353 attrExprs.splice(attrsLengthBeforeInputs, 0, literal(3 /* Bindings */));
17354 }
17355 }
17356 if (templateAttrs.length) {
17357 attrExprs.push(literal(4 /* Template */));
17358 templateAttrs.forEach(attr => addAttrExpr(attr.name));
17359 }
17360 if (boundI18nAttrs.length) {
17361 attrExprs.push(literal(6 /* I18n */));
17362 boundI18nAttrs.forEach(attr => addAttrExpr(attr.name));
17363 }
17364 return attrExprs;
17365 }
17366 addToConsts(expression) {
17367 if (isNull(expression)) {
17368 return TYPED_NULL_EXPR;
17369 }
17370 const consts = this._constants.constExpressions;
17371 // Try to reuse a literal that's already in the array, if possible.
17372 for (let i = 0; i < consts.length; i++) {
17373 if (consts[i].isEquivalent(expression)) {
17374 return literal(i);
17375 }
17376 }
17377 return literal(consts.push(expression) - 1);
17378 }
17379 addAttrsToConsts(attrs) {
17380 return attrs.length > 0 ? this.addToConsts(literalArr(attrs)) : TYPED_NULL_EXPR;
17381 }
17382 prepareRefsArray(references) {
17383 if (!references || references.length === 0) {
17384 return TYPED_NULL_EXPR;
17385 }
17386 const refsParam = flatten(references.map(reference => {
17387 const slot = this.allocateDataSlot();
17388 // Generate the update temporary.
17389 const variableName = this._bindingScope.freshReferenceName();
17390 const retrievalLevel = this.level;
17391 const lhs = variable(variableName);
17392 this._bindingScope.set(retrievalLevel, reference.name, lhs, 0 /* DEFAULT */, (scope, relativeLevel) => {
17393 // e.g. nextContext(2);
17394 const nextContextStmt = relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : [];
17395 // e.g. const $foo$ = reference(1);
17396 const refExpr = lhs.set(importExpr(Identifiers$1.reference).callFn([literal(slot)]));
17397 return nextContextStmt.concat(refExpr.toConstDecl());
17398 }, true);
17399 return [reference.name, reference.value];
17400 }));
17401 return asLiteral(refsParam);
17402 }
17403 prepareListenerParameter(tagName, outputAst, index) {
17404 return () => {
17405 const eventName = outputAst.name;
17406 const bindingFnName = outputAst.type === 1 /* Animation */ ?
17407 // synthetic @listener.foo values are treated the exact same as are standard listeners
17408 prepareSyntheticListenerFunctionName(eventName, outputAst.phase) :
17409 sanitizeIdentifier(eventName);
17410 const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`;
17411 const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel, EVENT_BINDING_SCOPE_GLOBALS);
17412 return prepareEventListenerParameters(outputAst, handlerName, scope);
17413 };
17414 }
17415 }
17416 class ValueConverter extends AstMemoryEfficientTransformer {
17417 constructor(constantPool, allocateSlot, allocatePureFunctionSlots, definePipe) {
17418 super();
17419 this.constantPool = constantPool;
17420 this.allocateSlot = allocateSlot;
17421 this.allocatePureFunctionSlots = allocatePureFunctionSlots;
17422 this.definePipe = definePipe;
17423 this._pipeBindExprs = [];
17424 }
17425 // AstMemoryEfficientTransformer
17426 visitPipe(pipe, context) {
17427 // Allocate a slot to create the pipe
17428 const slot = this.allocateSlot();
17429 const slotPseudoLocal = `PIPE:${slot}`;
17430 // Allocate one slot for the result plus one slot per pipe argument
17431 const pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length);
17432 const target = new PropertyRead(pipe.span, pipe.sourceSpan, pipe.nameSpan, new ImplicitReceiver(pipe.span, pipe.sourceSpan), slotPseudoLocal);
17433 const { identifier, isVarLength } = pipeBindingCallInfo(pipe.args);
17434 this.definePipe(pipe.name, slotPseudoLocal, slot, importExpr(identifier));
17435 const args = [pipe.exp, ...pipe.args];
17436 const convertedArgs = isVarLength ?
17437 this.visitAll([new LiteralArray(pipe.span, pipe.sourceSpan, args)]) :
17438 this.visitAll(args);
17439 const pipeBindExpr = new FunctionCall(pipe.span, pipe.sourceSpan, target, [
17440 new LiteralPrimitive(pipe.span, pipe.sourceSpan, slot),
17441 new LiteralPrimitive(pipe.span, pipe.sourceSpan, pureFunctionSlot),
17442 ...convertedArgs,
17443 ]);
17444 this._pipeBindExprs.push(pipeBindExpr);
17445 return pipeBindExpr;
17446 }
17447 updatePipeSlotOffsets(bindingSlots) {
17448 this._pipeBindExprs.forEach((pipe) => {
17449 // update the slot offset arg (index 1) to account for binding slots
17450 const slotOffset = pipe.args[1];
17451 slotOffset.value += bindingSlots;
17452 });
17453 }
17454 visitLiteralArray(array, context) {
17455 return new BuiltinFunctionCall(array.span, array.sourceSpan, this.visitAll(array.expressions), values => {
17456 // If the literal has calculated (non-literal) elements transform it into
17457 // calls to literal factories that compose the literal and will cache intermediate
17458 // values.
17459 const literal = literalArr(values);
17460 return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
17461 });
17462 }
17463 visitLiteralMap(map, context) {
17464 return new BuiltinFunctionCall(map.span, map.sourceSpan, this.visitAll(map.values), values => {
17465 // If the literal has calculated (non-literal) elements transform it into
17466 // calls to literal factories that compose the literal and will cache intermediate
17467 // values.
17468 const literal = literalMap(values.map((value, index) => ({ key: map.keys[index].key, value, quoted: map.keys[index].quoted })));
17469 return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
17470 });
17471 }
17472 }
17473 // Pipes always have at least one parameter, the value they operate on
17474 const pipeBindingIdentifiers = [Identifiers$1.pipeBind1, Identifiers$1.pipeBind2, Identifiers$1.pipeBind3, Identifiers$1.pipeBind4];
17475 function pipeBindingCallInfo(args) {
17476 const identifier = pipeBindingIdentifiers[args.length];
17477 return {
17478 identifier: identifier || Identifiers$1.pipeBindV,
17479 isVarLength: !identifier,
17480 };
17481 }
17482 const pureFunctionIdentifiers = [
17483 Identifiers$1.pureFunction0, Identifiers$1.pureFunction1, Identifiers$1.pureFunction2, Identifiers$1.pureFunction3, Identifiers$1.pureFunction4,
17484 Identifiers$1.pureFunction5, Identifiers$1.pureFunction6, Identifiers$1.pureFunction7, Identifiers$1.pureFunction8
17485 ];
17486 function pureFunctionCallInfo(args) {
17487 const identifier = pureFunctionIdentifiers[args.length];
17488 return {
17489 identifier: identifier || Identifiers$1.pureFunctionV,
17490 isVarLength: !identifier,
17491 };
17492 }
17493 function instruction(span, reference, params) {
17494 return importExpr(reference, null, span).callFn(params, span);
17495 }
17496 // e.g. x(2);
17497 function generateNextContextExpr(relativeLevelDiff) {
17498 return importExpr(Identifiers$1.nextContext)
17499 .callFn(relativeLevelDiff > 1 ? [literal(relativeLevelDiff)] : []);
17500 }
17501 function getLiteralFactory(constantPool, literal$1, allocateSlots) {
17502 const { literalFactory, literalFactoryArguments } = constantPool.getLiteralFactory(literal$1);
17503 // Allocate 1 slot for the result plus 1 per argument
17504 const startSlot = allocateSlots(1 + literalFactoryArguments.length);
17505 const { identifier, isVarLength } = pureFunctionCallInfo(literalFactoryArguments);
17506 // Literal factories are pure functions that only need to be re-invoked when the parameters
17507 // change.
17508 const args = [literal(startSlot), literalFactory];
17509 if (isVarLength) {
17510 args.push(literalArr(literalFactoryArguments));
17511 }
17512 else {
17513 args.push(...literalFactoryArguments);
17514 }
17515 return importExpr(identifier).callFn(args);
17516 }
17517 /**
17518 * Gets an array of literals that can be added to an expression
17519 * to represent the name and namespace of an attribute. E.g.
17520 * `:xlink:href` turns into `[AttributeMarker.NamespaceURI, 'xlink', 'href']`.
17521 *
17522 * @param name Name of the attribute, including the namespace.
17523 */
17524 function getAttributeNameLiterals(name) {
17525 const [attributeNamespace, attributeName] = splitNsName(name);
17526 const nameLiteral = literal(attributeName);
17527 if (attributeNamespace) {
17528 return [
17529 literal(0 /* NamespaceURI */), literal(attributeNamespace), nameLiteral
17530 ];
17531 }
17532 return [nameLiteral];
17533 }
17534 /** The prefix used to get a shared context in BindingScope's map. */
17535 const SHARED_CONTEXT_KEY = '$$shared_ctx$$';
17536 class BindingScope {
17537 constructor(bindingLevel = 0, parent = null, globals) {
17538 this.bindingLevel = bindingLevel;
17539 this.parent = parent;
17540 this.globals = globals;
17541 /** Keeps a map from local variables to their BindingData. */
17542 this.map = new Map();
17543 this.referenceNameIndex = 0;
17544 this.restoreViewVariable = null;
17545 if (globals !== undefined) {
17546 for (const name of globals) {
17547 this.set(0, name, variable(name));
17548 }
17549 }
17550 }
17551 static createRootScope() {
17552 return new BindingScope();
17553 }
17554 get(name) {
17555 let current = this;
17556 while (current) {
17557 let value = current.map.get(name);
17558 if (value != null) {
17559 if (current !== this) {
17560 // make a local copy and reset the `declare` state
17561 value = {
17562 retrievalLevel: value.retrievalLevel,
17563 lhs: value.lhs,
17564 declareLocalCallback: value.declareLocalCallback,
17565 declare: false,
17566 priority: value.priority,
17567 localRef: value.localRef
17568 };
17569 // Cache the value locally.
17570 this.map.set(name, value);
17571 // Possibly generate a shared context var
17572 this.maybeGenerateSharedContextVar(value);
17573 this.maybeRestoreView(value.retrievalLevel, value.localRef);
17574 }
17575 if (value.declareLocalCallback && !value.declare) {
17576 value.declare = true;
17577 }
17578 return value.lhs;
17579 }
17580 current = current.parent;
17581 }
17582 // If we get to this point, we are looking for a property on the top level component
17583 // - If level === 0, we are on the top and don't need to re-declare `ctx`.
17584 // - If level > 0, we are in an embedded view. We need to retrieve the name of the
17585 // local var we used to store the component context, e.g. const $comp$ = x();
17586 return this.bindingLevel === 0 ? null : this.getComponentProperty(name);
17587 }
17588 /**
17589 * Create a local variable for later reference.
17590 *
17591 * @param retrievalLevel The level from which this value can be retrieved
17592 * @param name Name of the variable.
17593 * @param lhs AST representing the left hand side of the `let lhs = rhs;`.
17594 * @param priority The sorting priority of this var
17595 * @param declareLocalCallback The callback to invoke when declaring this local var
17596 * @param localRef Whether or not this is a local ref
17597 */
17598 set(retrievalLevel, name, lhs, priority = 0 /* DEFAULT */, declareLocalCallback, localRef) {
17599 if (this.map.has(name)) {
17600 if (localRef) {
17601 // Do not throw an error if it's a local ref and do not update existing value,
17602 // so the first defined ref is always returned.
17603 return this;
17604 }
17605 error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`);
17606 }
17607 this.map.set(name, {
17608 retrievalLevel: retrievalLevel,
17609 lhs: lhs,
17610 declare: false,
17611 declareLocalCallback: declareLocalCallback,
17612 priority: priority,
17613 localRef: localRef || false
17614 });
17615 return this;
17616 }
17617 // Implemented as part of LocalResolver.
17618 getLocal(name) {
17619 return this.get(name);
17620 }
17621 // Implemented as part of LocalResolver.
17622 notifyImplicitReceiverUse() {
17623 if (this.bindingLevel !== 0) {
17624 // Since the implicit receiver is accessed in an embedded view, we need to
17625 // ensure that we declare a shared context variable for the current template
17626 // in the update variables.
17627 this.map.get(SHARED_CONTEXT_KEY + 0).declare = true;
17628 }
17629 }
17630 nestedScope(level, globals) {
17631 const newScope = new BindingScope(level, this, globals);
17632 if (level > 0)
17633 newScope.generateSharedContextVar(0);
17634 return newScope;
17635 }
17636 /**
17637 * Gets or creates a shared context variable and returns its expression. Note that
17638 * this does not mean that the shared variable will be declared. Variables in the
17639 * binding scope will be only declared if they are used.
17640 */
17641 getOrCreateSharedContextVar(retrievalLevel) {
17642 const bindingKey = SHARED_CONTEXT_KEY + retrievalLevel;
17643 if (!this.map.has(bindingKey)) {
17644 this.generateSharedContextVar(retrievalLevel);
17645 }
17646 // Shared context variables are always generated as "ReadVarExpr".
17647 return this.map.get(bindingKey).lhs;
17648 }
17649 getSharedContextName(retrievalLevel) {
17650 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + retrievalLevel);
17651 // Shared context variables are always generated as "ReadVarExpr".
17652 return sharedCtxObj && sharedCtxObj.declare ? sharedCtxObj.lhs : null;
17653 }
17654 maybeGenerateSharedContextVar(value) {
17655 if (value.priority === 1 /* CONTEXT */ &&
17656 value.retrievalLevel < this.bindingLevel) {
17657 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + value.retrievalLevel);
17658 if (sharedCtxObj) {
17659 sharedCtxObj.declare = true;
17660 }
17661 else {
17662 this.generateSharedContextVar(value.retrievalLevel);
17663 }
17664 }
17665 }
17666 generateSharedContextVar(retrievalLevel) {
17667 const lhs = variable(CONTEXT_NAME + this.freshReferenceName());
17668 this.map.set(SHARED_CONTEXT_KEY + retrievalLevel, {
17669 retrievalLevel: retrievalLevel,
17670 lhs: lhs,
17671 declareLocalCallback: (scope, relativeLevel) => {
17672 // const ctx_r0 = nextContext(2);
17673 return [lhs.set(generateNextContextExpr(relativeLevel)).toConstDecl()];
17674 },
17675 declare: false,
17676 priority: 2 /* SHARED_CONTEXT */,
17677 localRef: false
17678 });
17679 }
17680 getComponentProperty(name) {
17681 const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
17682 componentValue.declare = true;
17683 this.maybeRestoreView(0, false);
17684 return componentValue.lhs.prop(name);
17685 }
17686 maybeRestoreView(retrievalLevel, localRefLookup) {
17687 // We want to restore the current view in listener fns if:
17688 // 1 - we are accessing a value in a parent view, which requires walking the view tree rather
17689 // than using the ctx arg. In this case, the retrieval and binding level will be different.
17690 // 2 - we are looking up a local ref, which requires restoring the view where the local
17691 // ref is stored
17692 if (this.isListenerScope() && (retrievalLevel < this.bindingLevel || localRefLookup)) {
17693 if (!this.parent.restoreViewVariable) {
17694 // parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction
17695 this.parent.restoreViewVariable = variable(this.parent.freshReferenceName());
17696 }
17697 this.restoreViewVariable = this.parent.restoreViewVariable;
17698 }
17699 }
17700 restoreViewStatement() {
17701 // restoreView($state$);
17702 return this.restoreViewVariable ?
17703 [instruction(null, Identifiers$1.restoreView, [this.restoreViewVariable]).toStmt()] :
17704 [];
17705 }
17706 viewSnapshotStatements() {
17707 // const $state$ = getCurrentView();
17708 const getCurrentViewInstruction = instruction(null, Identifiers$1.getCurrentView, []);
17709 return this.restoreViewVariable ?
17710 [this.restoreViewVariable.set(getCurrentViewInstruction).toConstDecl()] :
17711 [];
17712 }
17713 isListenerScope() {
17714 return this.parent && this.parent.bindingLevel === this.bindingLevel;
17715 }
17716 variableDeclarations() {
17717 let currentContextLevel = 0;
17718 return Array.from(this.map.values())
17719 .filter(value => value.declare)
17720 .sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority)
17721 .reduce((stmts, value) => {
17722 const levelDiff = this.bindingLevel - value.retrievalLevel;
17723 const currStmts = value.declareLocalCallback(this, levelDiff - currentContextLevel);
17724 currentContextLevel = levelDiff;
17725 return stmts.concat(currStmts);
17726 }, []);
17727 }
17728 freshReferenceName() {
17729 let current = this;
17730 // Find the top scope as it maintains the global reference count
17731 while (current.parent)
17732 current = current.parent;
17733 const ref = `${REFERENCE_PREFIX}${current.referenceNameIndex++}`;
17734 return ref;
17735 }
17736 }
17737 /**
17738 * Creates a `CssSelector` given a tag name and a map of attributes
17739 */
17740 function createCssSelector(elementName, attributes) {
17741 const cssSelector = new CssSelector();
17742 const elementNameNoNs = splitNsName(elementName)[1];
17743 cssSelector.setElement(elementNameNoNs);
17744 Object.getOwnPropertyNames(attributes).forEach((name) => {
17745 const nameNoNs = splitNsName(name)[1];
17746 const value = attributes[name];
17747 cssSelector.addAttribute(nameNoNs, value);
17748 if (name.toLowerCase() === 'class') {
17749 const classes = value.trim().split(/\s+/);
17750 classes.forEach(className => cssSelector.addClassName(className));
17751 }
17752 });
17753 return cssSelector;
17754 }
17755 /**
17756 * Creates an array of expressions out of an `ngProjectAs` attributes
17757 * which can be added to the instruction parameters.
17758 */
17759 function getNgProjectAsLiteral(attribute) {
17760 // Parse the attribute value into a CssSelectorList. Note that we only take the
17761 // first selector, because we don't support multiple selectors in ngProjectAs.
17762 const parsedR3Selector = parseSelectorToR3Selector(attribute.value)[0];
17763 return [literal(5 /* ProjectAs */), asLiteral(parsedR3Selector)];
17764 }
17765 /**
17766 * Gets the instruction to generate for an interpolated property
17767 * @param interpolation An Interpolation AST
17768 */
17769 function getPropertyInterpolationExpression(interpolation) {
17770 switch (getInterpolationArgsLength(interpolation)) {
17771 case 1:
17772 return Identifiers$1.propertyInterpolate;
17773 case 3:
17774 return Identifiers$1.propertyInterpolate1;
17775 case 5:
17776 return Identifiers$1.propertyInterpolate2;
17777 case 7:
17778 return Identifiers$1.propertyInterpolate3;
17779 case 9:
17780 return Identifiers$1.propertyInterpolate4;
17781 case 11:
17782 return Identifiers$1.propertyInterpolate5;
17783 case 13:
17784 return Identifiers$1.propertyInterpolate6;
17785 case 15:
17786 return Identifiers$1.propertyInterpolate7;
17787 case 17:
17788 return Identifiers$1.propertyInterpolate8;
17789 default:
17790 return Identifiers$1.propertyInterpolateV;
17791 }
17792 }
17793 /**
17794 * Gets the instruction to generate for an interpolated attribute
17795 * @param interpolation An Interpolation AST
17796 */
17797 function getAttributeInterpolationExpression(interpolation) {
17798 switch (getInterpolationArgsLength(interpolation)) {
17799 case 3:
17800 return Identifiers$1.attributeInterpolate1;
17801 case 5:
17802 return Identifiers$1.attributeInterpolate2;
17803 case 7:
17804 return Identifiers$1.attributeInterpolate3;
17805 case 9:
17806 return Identifiers$1.attributeInterpolate4;
17807 case 11:
17808 return Identifiers$1.attributeInterpolate5;
17809 case 13:
17810 return Identifiers$1.attributeInterpolate6;
17811 case 15:
17812 return Identifiers$1.attributeInterpolate7;
17813 case 17:
17814 return Identifiers$1.attributeInterpolate8;
17815 default:
17816 return Identifiers$1.attributeInterpolateV;
17817 }
17818 }
17819 /**
17820 * Gets the instruction to generate for interpolated text.
17821 * @param interpolation An Interpolation AST
17822 */
17823 function getTextInterpolationExpression(interpolation) {
17824 switch (getInterpolationArgsLength(interpolation)) {
17825 case 1:
17826 return Identifiers$1.textInterpolate;
17827 case 3:
17828 return Identifiers$1.textInterpolate1;
17829 case 5:
17830 return Identifiers$1.textInterpolate2;
17831 case 7:
17832 return Identifiers$1.textInterpolate3;
17833 case 9:
17834 return Identifiers$1.textInterpolate4;
17835 case 11:
17836 return Identifiers$1.textInterpolate5;
17837 case 13:
17838 return Identifiers$1.textInterpolate6;
17839 case 15:
17840 return Identifiers$1.textInterpolate7;
17841 case 17:
17842 return Identifiers$1.textInterpolate8;
17843 default:
17844 return Identifiers$1.textInterpolateV;
17845 }
17846 }
17847 /**
17848 * Parse a template into render3 `Node`s and additional metadata, with no other dependencies.
17849 *
17850 * @param template text of the template to parse
17851 * @param templateUrl URL to use for source mapping of the parsed template
17852 * @param options options to modify how the template is parsed
17853 */
17854 function parseTemplate(template, templateUrl, options = {}) {
17855 var _a;
17856 const { interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat } = options;
17857 const isInline = (_a = options.isInline) !== null && _a !== void 0 ? _a : false;
17858 const bindingParser = makeBindingParser(interpolationConfig);
17859 const htmlParser = new HtmlParser();
17860 const parseResult = htmlParser.parse(template, templateUrl, Object.assign(Object.assign({ leadingTriviaChars: LEADING_TRIVIA_CHARS }, options), { tokenizeExpansionForms: true }));
17861 if (parseResult.errors && parseResult.errors.length > 0) {
17862 // TODO(ayazhafiz): we may not always want to bail out at this point (e.g. in
17863 // the context of a language service).
17864 return {
17865 interpolationConfig,
17866 preserveWhitespaces,
17867 template,
17868 templateUrl,
17869 isInline,
17870 errors: parseResult.errors,
17871 nodes: [],
17872 styleUrls: [],
17873 styles: [],
17874 ngContentSelectors: []
17875 };
17876 }
17877 let rootNodes = parseResult.rootNodes;
17878 // process i18n meta information (scan attributes, generate ids)
17879 // before we run whitespace removal process, because existing i18n
17880 // extraction process (ng extract-i18n) relies on a raw content to generate
17881 // message ids
17882 const i18nMetaVisitor = new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ !preserveWhitespaces, enableI18nLegacyMessageIdFormat);
17883 const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
17884 if (i18nMetaResult.errors && i18nMetaResult.errors.length > 0) {
17885 return {
17886 interpolationConfig,
17887 preserveWhitespaces,
17888 template,
17889 templateUrl,
17890 isInline,
17891 errors: i18nMetaResult.errors,
17892 nodes: [],
17893 styleUrls: [],
17894 styles: [],
17895 ngContentSelectors: []
17896 };
17897 }
17898 rootNodes = i18nMetaResult.rootNodes;
17899 if (!preserveWhitespaces) {
17900 rootNodes = visitAll$1(new WhitespaceVisitor(), rootNodes);
17901 // run i18n meta visitor again in case whitespaces are removed (because that might affect
17902 // generated i18n message content) and first pass indicated that i18n content is present in a
17903 // template. During this pass i18n IDs generated at the first pass will be preserved, so we can
17904 // mimic existing extraction process (ng extract-i18n)
17905 if (i18nMetaVisitor.hasI18nMeta) {
17906 rootNodes = visitAll$1(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
17907 }
17908 }
17909 const { nodes, errors, styleUrls, styles, ngContentSelectors } = htmlAstToRender3Ast(rootNodes, bindingParser);
17910 return {
17911 interpolationConfig,
17912 preserveWhitespaces,
17913 errors: errors.length > 0 ? errors : null,
17914 template,
17915 templateUrl,
17916 isInline,
17917 nodes,
17918 styleUrls,
17919 styles,
17920 ngContentSelectors
17921 };
17922 }
17923 const elementRegistry = new DomElementSchemaRegistry();
17924 /**
17925 * Construct a `BindingParser` with a default configuration.
17926 */
17927 function makeBindingParser(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
17928 return new BindingParser(new IvyParser(new Lexer()), interpolationConfig, elementRegistry, null, []);
17929 }
17930 function resolveSanitizationFn(context, isAttribute) {
17931 switch (context) {
17932 case SecurityContext.HTML:
17933 return importExpr(Identifiers$1.sanitizeHtml);
17934 case SecurityContext.SCRIPT:
17935 return importExpr(Identifiers$1.sanitizeScript);
17936 case SecurityContext.STYLE:
17937 // the compiler does not fill in an instruction for [style.prop?] binding
17938 // values because the style algorithm knows internally what props are subject
17939 // to sanitization (only [attr.style] values are explicitly sanitized)
17940 return isAttribute ? importExpr(Identifiers$1.sanitizeStyle) : null;
17941 case SecurityContext.URL:
17942 return importExpr(Identifiers$1.sanitizeUrl);
17943 case SecurityContext.RESOURCE_URL:
17944 return importExpr(Identifiers$1.sanitizeResourceUrl);
17945 default:
17946 return null;
17947 }
17948 }
17949 function trustedConstAttribute(tagName, attr) {
17950 const value = asLiteral(attr.value);
17951 if (isTrustedTypesSink(tagName, attr.name)) {
17952 switch (elementRegistry.securityContext(tagName, attr.name, /* isAttribute */ true)) {
17953 case SecurityContext.HTML:
17954 return taggedTemplate(importExpr(Identifiers$1.trustConstantHtml), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
17955 // NB: no SecurityContext.SCRIPT here, as the corresponding tags are stripped by the compiler.
17956 case SecurityContext.RESOURCE_URL:
17957 return taggedTemplate(importExpr(Identifiers$1.trustConstantResourceUrl), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
17958 default:
17959 return value;
17960 }
17961 }
17962 else {
17963 return value;
17964 }
17965 }
17966 function isSingleElementTemplate(children) {
17967 return children.length === 1 && children[0] instanceof Element;
17968 }
17969 function isTextNode(node) {
17970 return node instanceof Text || node instanceof BoundText || node instanceof Icu;
17971 }
17972 function hasTextChildrenOnly(children) {
17973 return children.every(isTextNode);
17974 }
17975 /** Name of the global variable that is used to determine if we use Closure translations or not */
17976 const NG_I18N_CLOSURE_MODE = 'ngI18nClosureMode';
17977 /**
17978 * Generate statements that define a given translation message.
17979 *
17980 * ```
17981 * var I18N_1;
17982 * if (typeof ngI18nClosureMode !== undefined && ngI18nClosureMode) {
17983 * var MSG_EXTERNAL_XXX = goog.getMsg(
17984 * "Some message with {$interpolation}!",
17985 * { "interpolation": "\uFFFD0\uFFFD" }
17986 * );
17987 * I18N_1 = MSG_EXTERNAL_XXX;
17988 * }
17989 * else {
17990 * I18N_1 = $localize`Some message with ${'\uFFFD0\uFFFD'}!`;
17991 * }
17992 * ```
17993 *
17994 * @param message The original i18n AST message node
17995 * @param variable The variable that will be assigned the translation, e.g. `I18N_1`.
17996 * @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
17997 * @param params Object mapping placeholder names to their values (e.g.
17998 * `{ "interpolation": "\uFFFD0\uFFFD" }`).
17999 * @param transformFn Optional transformation function that will be applied to the translation (e.g.
18000 * post-processing).
18001 * @returns An array of statements that defined a given translation.
18002 */
18003 function getTranslationDeclStmts(message, variable, closureVar, params = {}, transformFn) {
18004 const statements = [
18005 declareI18nVariable(variable),
18006 ifStmt(createClosureModeGuard(), createGoogleGetMsgStatements(variable, message, closureVar, i18nFormatPlaceholderNames(params, /* useCamelCase */ true)), createLocalizeStatements(variable, message, i18nFormatPlaceholderNames(params, /* useCamelCase */ false))),
18007 ];
18008 if (transformFn) {
18009 statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
18010 }
18011 return statements;
18012 }
18013 /**
18014 * Create the expression that will be used to guard the closure mode block
18015 * It is equivalent to:
18016 *
18017 * ```
18018 * typeof ngI18nClosureMode !== undefined && ngI18nClosureMode
18019 * ```
18020 */
18021 function createClosureModeGuard() {
18022 return typeofExpr(variable(NG_I18N_CLOSURE_MODE))
18023 .notIdentical(literal('undefined', STRING_TYPE))
18024 .and(variable(NG_I18N_CLOSURE_MODE));
18025 }
18026
18027 /**
18028 * @license
18029 * Copyright Google LLC All Rights Reserved.
18030 *
18031 * Use of this source code is governed by an MIT-style license that can be
18032 * found in the LICENSE file at https://angular.io/license
18033 */
18034 // This regex matches any binding names that contain the "attr." prefix, e.g. "attr.required"
18035 // If there is a match, the first matching group will contain the attribute name to bind.
18036 const ATTR_REGEX = /attr\.([^\]]+)/;
18037 function baseDirectiveFields(meta, constantPool, bindingParser) {
18038 const definitionMap = new DefinitionMap();
18039 const selectors = parseSelectorToR3Selector(meta.selector);
18040 // e.g. `type: MyDirective`
18041 definitionMap.set('type', meta.internalType);
18042 // e.g. `selectors: [['', 'someDir', '']]`
18043 if (selectors.length > 0) {
18044 definitionMap.set('selectors', asLiteral(selectors));
18045 }
18046 if (meta.queries.length > 0) {
18047 // e.g. `contentQueries: (rf, ctx, dirIndex) => { ... }
18048 definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name));
18049 }
18050 if (meta.viewQueries.length) {
18051 definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name));
18052 }
18053 // e.g. `hostBindings: (rf, ctx) => { ... }
18054 definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', meta.name, definitionMap));
18055 // e.g 'inputs: {a: 'a'}`
18056 definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
18057 // e.g 'outputs: {a: 'a'}`
18058 definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
18059 if (meta.exportAs !== null) {
18060 definitionMap.set('exportAs', literalArr(meta.exportAs.map(e => literal(e))));
18061 }
18062 return definitionMap;
18063 }
18064 /**
18065 * Add features to the definition map.
18066 */
18067 function addFeatures(definitionMap, meta) {
18068 // e.g. `features: [NgOnChangesFeature]`
18069 const features = [];
18070 const providers = meta.providers;
18071 const viewProviders = meta.viewProviders;
18072 if (providers || viewProviders) {
18073 const args = [providers || new LiteralArrayExpr([])];
18074 if (viewProviders) {
18075 args.push(viewProviders);
18076 }
18077 features.push(importExpr(Identifiers$1.ProvidersFeature).callFn(args));
18078 }
18079 if (meta.usesInheritance) {
18080 features.push(importExpr(Identifiers$1.InheritDefinitionFeature));
18081 }
18082 if (meta.fullInheritance) {
18083 features.push(importExpr(Identifiers$1.CopyDefinitionFeature));
18084 }
18085 if (meta.lifecycle.usesOnChanges) {
18086 features.push(importExpr(Identifiers$1.NgOnChangesFeature));
18087 }
18088 if (features.length) {
18089 definitionMap.set('features', literalArr(features));
18090 }
18091 }
18092 /**
18093 * Compile a directive for the render3 runtime as defined by the `R3DirectiveMetadata`.
18094 */
18095 function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
18096 const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
18097 addFeatures(definitionMap, meta);
18098 const expression = importExpr(Identifiers$1.defineDirective).callFn([definitionMap.toLiteralMap()]);
18099 const type = createDirectiveType(meta);
18100 return { expression, type };
18101 }
18102 /**
18103 * Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
18104 */
18105 function compileComponentFromMetadata(meta, constantPool, bindingParser) {
18106 const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
18107 addFeatures(definitionMap, meta);
18108 const selector = meta.selector && CssSelector.parse(meta.selector);
18109 const firstSelector = selector && selector[0];
18110 // e.g. `attr: ["class", ".my.app"]`
18111 // This is optional an only included if the first selector of a component specifies attributes.
18112 if (firstSelector) {
18113 const selectorAttributes = firstSelector.getAttrs();
18114 if (selectorAttributes.length) {
18115 definitionMap.set('attrs', constantPool.getConstLiteral(literalArr(selectorAttributes.map(value => value != null ? literal(value) : literal(undefined))),
18116 /* forceShared */ true));
18117 }
18118 }
18119 // Generate the CSS matcher that recognize directive
18120 let directiveMatcher = null;
18121 if (meta.directives.length > 0) {
18122 const matcher = new SelectorMatcher();
18123 for (const { selector, type } of meta.directives) {
18124 matcher.addSelectables(CssSelector.parse(selector), type);
18125 }
18126 directiveMatcher = matcher;
18127 }
18128 // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
18129 const templateTypeName = meta.name;
18130 const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
18131 const directivesUsed = new Set();
18132 const pipesUsed = new Set();
18133 const changeDetection = meta.changeDetection;
18134 const template = meta.template;
18135 const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, Identifiers$1.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);
18136 const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
18137 // We need to provide this so that dynamically generated components know what
18138 // projected content blocks to pass through to the component when it is instantiated.
18139 const ngContentSelectors = templateBuilder.getNgContentSelectors();
18140 if (ngContentSelectors) {
18141 definitionMap.set('ngContentSelectors', ngContentSelectors);
18142 }
18143 // e.g. `decls: 2`
18144 definitionMap.set('decls', literal(templateBuilder.getConstCount()));
18145 // e.g. `vars: 2`
18146 definitionMap.set('vars', literal(templateBuilder.getVarCount()));
18147 // Generate `consts` section of ComponentDef:
18148 // - either as an array:
18149 // `consts: [['one', 'two'], ['three', 'four']]`
18150 // - or as a factory function in case additional statements are present (to support i18n):
18151 // `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0]; }`
18152 const { constExpressions, prepareStatements } = templateBuilder.getConsts();
18153 if (constExpressions.length > 0) {
18154 let constsExpr = literalArr(constExpressions);
18155 // Prepare statements are present - turn `consts` into a function.
18156 if (prepareStatements.length > 0) {
18157 constsExpr = fn([], [...prepareStatements, new ReturnStatement(constsExpr)]);
18158 }
18159 definitionMap.set('consts', constsExpr);
18160 }
18161 definitionMap.set('template', templateFunctionExpression);
18162 // e.g. `directives: [MyDirective]`
18163 if (directivesUsed.size) {
18164 const directivesList = literalArr(Array.from(directivesUsed));
18165 const directivesExpr = compileDeclarationList(directivesList, meta.declarationListEmitMode);
18166 definitionMap.set('directives', directivesExpr);
18167 }
18168 // e.g. `pipes: [MyPipe]`
18169 if (pipesUsed.size) {
18170 const pipesList = literalArr(Array.from(pipesUsed));
18171 const pipesExpr = compileDeclarationList(pipesList, meta.declarationListEmitMode);
18172 definitionMap.set('pipes', pipesExpr);
18173 }
18174 if (meta.encapsulation === null) {
18175 meta.encapsulation = ViewEncapsulation.Emulated;
18176 }
18177 // e.g. `styles: [str1, str2]`
18178 if (meta.styles && meta.styles.length) {
18179 const styleValues = meta.encapsulation == ViewEncapsulation.Emulated ?
18180 compileStyles(meta.styles, CONTENT_ATTR, HOST_ATTR) :
18181 meta.styles;
18182 const strings = styleValues.map(str => constantPool.getConstLiteral(literal(str)));
18183 definitionMap.set('styles', literalArr(strings));
18184 }
18185 else if (meta.encapsulation === ViewEncapsulation.Emulated) {
18186 // If there is no style, don't generate css selectors on elements
18187 meta.encapsulation = ViewEncapsulation.None;
18188 }
18189 // Only set view encapsulation if it's not the default value
18190 if (meta.encapsulation !== ViewEncapsulation.Emulated) {
18191 definitionMap.set('encapsulation', literal(meta.encapsulation));
18192 }
18193 // e.g. `animation: [trigger('123', [])]`
18194 if (meta.animations !== null) {
18195 definitionMap.set('data', literalMap([{ key: 'animation', value: meta.animations, quoted: false }]));
18196 }
18197 // Only set the change detection flag if it's defined and it's not the default.
18198 if (changeDetection != null && changeDetection !== ChangeDetectionStrategy.Default) {
18199 definitionMap.set('changeDetection', literal(changeDetection));
18200 }
18201 const expression = importExpr(Identifiers$1.defineComponent).callFn([definitionMap.toLiteralMap()]);
18202 const type = createComponentType(meta);
18203 return { expression, type };
18204 }
18205 /**
18206 * Creates the type specification from the component meta. This type is inserted into .d.ts files
18207 * to be consumed by upstream compilations.
18208 */
18209 function createComponentType(meta) {
18210 const typeParams = createDirectiveTypeParams(meta);
18211 typeParams.push(stringArrayAsType(meta.template.ngContentSelectors));
18212 return expressionType(importExpr(Identifiers$1.ComponentDefWithMeta, typeParams));
18213 }
18214 /**
18215 * Compiles the array literal of declarations into an expression according to the provided emit
18216 * mode.
18217 */
18218 function compileDeclarationList(list, mode) {
18219 switch (mode) {
18220 case 0 /* Direct */:
18221 // directives: [MyDir],
18222 return list;
18223 case 1 /* Closure */:
18224 // directives: function () { return [MyDir]; }
18225 return fn([], [new ReturnStatement(list)]);
18226 case 2 /* ClosureResolved */:
18227 // directives: function () { return [MyDir].map(ng.resolveForwardRef); }
18228 const resolvedList = list.callMethod('map', [importExpr(Identifiers$1.resolveForwardRef)]);
18229 return fn([], [new ReturnStatement(resolvedList)]);
18230 }
18231 }
18232 function prepareQueryParams(query, constantPool) {
18233 const parameters = [getQueryPredicate(query, constantPool), literal(toQueryFlags(query))];
18234 if (query.read) {
18235 parameters.push(query.read);
18236 }
18237 return parameters;
18238 }
18239 /**
18240 * Translates query flags into `TQueryFlags` type in packages/core/src/render3/interfaces/query.ts
18241 * @param query
18242 */
18243 function toQueryFlags(query) {
18244 return (query.descendants ? 1 /* descendants */ : 0 /* none */) |
18245 (query.static ? 2 /* isStatic */ : 0 /* none */) |
18246 (query.emitDistinctChangesOnly ? 4 /* emitDistinctChangesOnly */ : 0 /* none */);
18247 }
18248 function convertAttributesToExpressions(attributes) {
18249 const values = [];
18250 for (let key of Object.getOwnPropertyNames(attributes)) {
18251 const value = attributes[key];
18252 values.push(literal(key), value);
18253 }
18254 return values;
18255 }
18256 // Define and update any content queries
18257 function createContentQueriesFunction(queries, constantPool, name) {
18258 const createStatements = [];
18259 const updateStatements = [];
18260 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
18261 for (const query of queries) {
18262 // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null);
18263 createStatements.push(importExpr(Identifiers$1.contentQuery)
18264 .callFn([variable('dirIndex'), ...prepareQueryParams(query, constantPool)])
18265 .toStmt());
18266 // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
18267 const temporary = tempAllocator();
18268 const getQueryList = importExpr(Identifiers$1.loadQuery).callFn([]);
18269 const refresh = importExpr(Identifiers$1.queryRefresh).callFn([temporary.set(getQueryList)]);
18270 const updateDirective = variable(CONTEXT_NAME)
18271 .prop(query.propertyName)
18272 .set(query.first ? temporary.prop('first') : temporary);
18273 updateStatements.push(refresh.and(updateDirective).toStmt());
18274 }
18275 const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
18276 return fn([
18277 new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null),
18278 new FnParam('dirIndex', null)
18279 ], [
18280 renderFlagCheckIfStmt(1 /* Create */, createStatements),
18281 renderFlagCheckIfStmt(2 /* Update */, updateStatements)
18282 ], INFERRED_TYPE, null, contentQueriesFnName);
18283 }
18284 function stringAsType(str) {
18285 return expressionType(literal(str));
18286 }
18287 function stringMapAsType(map) {
18288 const mapValues = Object.keys(map).map(key => {
18289 const value = Array.isArray(map[key]) ? map[key][0] : map[key];
18290 return {
18291 key,
18292 value: literal(value),
18293 quoted: true,
18294 };
18295 });
18296 return expressionType(literalMap(mapValues));
18297 }
18298 function stringArrayAsType(arr) {
18299 return arr.length > 0 ? expressionType(literalArr(arr.map(value => literal(value)))) :
18300 NONE_TYPE;
18301 }
18302 function createDirectiveTypeParams(meta) {
18303 // On the type side, remove newlines from the selector as it will need to fit into a TypeScript
18304 // string literal, which must be on one line.
18305 const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null;
18306 return [
18307 typeWithParameters(meta.type.type, meta.typeArgumentCount),
18308 selectorForType !== null ? stringAsType(selectorForType) : NONE_TYPE,
18309 meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : NONE_TYPE,
18310 stringMapAsType(meta.inputs),
18311 stringMapAsType(meta.outputs),
18312 stringArrayAsType(meta.queries.map(q => q.propertyName)),
18313 ];
18314 }
18315 /**
18316 * Creates the type specification from the directive meta. This type is inserted into .d.ts files
18317 * to be consumed by upstream compilations.
18318 */
18319 function createDirectiveType(meta) {
18320 const typeParams = createDirectiveTypeParams(meta);
18321 return expressionType(importExpr(Identifiers$1.DirectiveDefWithMeta, typeParams));
18322 }
18323 // Define and update any view queries
18324 function createViewQueriesFunction(viewQueries, constantPool, name) {
18325 const createStatements = [];
18326 const updateStatements = [];
18327 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
18328 viewQueries.forEach((query) => {
18329 // creation, e.g. r3.viewQuery(somePredicate, true);
18330 const queryDefinition = importExpr(Identifiers$1.viewQuery).callFn(prepareQueryParams(query, constantPool));
18331 createStatements.push(queryDefinition.toStmt());
18332 // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
18333 const temporary = tempAllocator();
18334 const getQueryList = importExpr(Identifiers$1.loadQuery).callFn([]);
18335 const refresh = importExpr(Identifiers$1.queryRefresh).callFn([temporary.set(getQueryList)]);
18336 const updateDirective = variable(CONTEXT_NAME)
18337 .prop(query.propertyName)
18338 .set(query.first ? temporary.prop('first') : temporary);
18339 updateStatements.push(refresh.and(updateDirective).toStmt());
18340 });
18341 const viewQueryFnName = name ? `${name}_Query` : null;
18342 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
18343 renderFlagCheckIfStmt(1 /* Create */, createStatements),
18344 renderFlagCheckIfStmt(2 /* Update */, updateStatements)
18345 ], INFERRED_TYPE, null, viewQueryFnName);
18346 }
18347 // Return a host binding function or null if one is not necessary.
18348 function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name, definitionMap) {
18349 const bindingContext = variable(CONTEXT_NAME);
18350 const styleBuilder = new StylingBuilder(bindingContext);
18351 const { styleAttr, classAttr } = hostBindingsMetadata.specialAttributes;
18352 if (styleAttr !== undefined) {
18353 styleBuilder.registerStyleAttr(styleAttr);
18354 }
18355 if (classAttr !== undefined) {
18356 styleBuilder.registerClassAttr(classAttr);
18357 }
18358 const createStatements = [];
18359 const updateStatements = [];
18360 const hostBindingSourceSpan = typeSourceSpan;
18361 const directiveSummary = metadataAsSummary(hostBindingsMetadata);
18362 // Calculate host event bindings
18363 const eventBindings = bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan);
18364 if (eventBindings && eventBindings.length) {
18365 const listeners = createHostListeners(eventBindings, name);
18366 createStatements.push(...listeners);
18367 }
18368 // Calculate the host property bindings
18369 const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan);
18370 const allOtherBindings = [];
18371 // We need to calculate the total amount of binding slots required by
18372 // all the instructions together before any value conversions happen.
18373 // Value conversions may require additional slots for interpolation and
18374 // bindings with pipes. These calculates happen after this block.
18375 let totalHostVarsCount = 0;
18376 bindings && bindings.forEach((binding) => {
18377 const stylingInputWasSet = styleBuilder.registerInputBasedOnName(binding.name, binding.expression, hostBindingSourceSpan);
18378 if (stylingInputWasSet) {
18379 totalHostVarsCount += MIN_STYLING_BINDING_SLOTS_REQUIRED;
18380 }
18381 else {
18382 allOtherBindings.push(binding);
18383 totalHostVarsCount++;
18384 }
18385 });
18386 let valueConverter;
18387 const getValueConverter = () => {
18388 if (!valueConverter) {
18389 const hostVarsCountFn = (numSlots) => {
18390 const originalVarsCount = totalHostVarsCount;
18391 totalHostVarsCount += numSlots;
18392 return originalVarsCount;
18393 };
18394 valueConverter = new ValueConverter(constantPool, () => error('Unexpected node'), // new nodes are illegal here
18395 hostVarsCountFn, () => error('Unexpected pipe')); // pipes are illegal here
18396 }
18397 return valueConverter;
18398 };
18399 const propertyBindings = [];
18400 const attributeBindings = [];
18401 const syntheticHostBindings = [];
18402 allOtherBindings.forEach((binding) => {
18403 // resolve literal arrays and literal objects
18404 const value = binding.expression.visit(getValueConverter());
18405 const bindingExpr = bindingFn(bindingContext, value);
18406 const { bindingName, instruction, isAttribute } = getBindingNameAndInstruction(binding);
18407 const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
18408 .filter(context => context !== SecurityContext.NONE);
18409 let sanitizerFn = null;
18410 if (securityContexts.length) {
18411 if (securityContexts.length === 2 &&
18412 securityContexts.indexOf(SecurityContext.URL) > -1 &&
18413 securityContexts.indexOf(SecurityContext.RESOURCE_URL) > -1) {
18414 // Special case for some URL attributes (such as "src" and "href") that may be a part
18415 // of different security contexts. In this case we use special santitization function and
18416 // select the actual sanitizer at runtime based on a tag name that is provided while
18417 // invoking sanitization function.
18418 sanitizerFn = importExpr(Identifiers$1.sanitizeUrlOrResourceUrl);
18419 }
18420 else {
18421 sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute);
18422 }
18423 }
18424 const instructionParams = [literal(bindingName), bindingExpr.currValExpr];
18425 if (sanitizerFn) {
18426 instructionParams.push(sanitizerFn);
18427 }
18428 updateStatements.push(...bindingExpr.stmts);
18429 if (instruction === Identifiers$1.hostProperty) {
18430 propertyBindings.push(instructionParams);
18431 }
18432 else if (instruction === Identifiers$1.attribute) {
18433 attributeBindings.push(instructionParams);
18434 }
18435 else if (instruction === Identifiers$1.syntheticHostProperty) {
18436 syntheticHostBindings.push(instructionParams);
18437 }
18438 else {
18439 updateStatements.push(importExpr(instruction).callFn(instructionParams).toStmt());
18440 }
18441 });
18442 if (propertyBindings.length > 0) {
18443 updateStatements.push(chainedInstruction(Identifiers$1.hostProperty, propertyBindings).toStmt());
18444 }
18445 if (attributeBindings.length > 0) {
18446 updateStatements.push(chainedInstruction(Identifiers$1.attribute, attributeBindings).toStmt());
18447 }
18448 if (syntheticHostBindings.length > 0) {
18449 updateStatements.push(chainedInstruction(Identifiers$1.syntheticHostProperty, syntheticHostBindings).toStmt());
18450 }
18451 // since we're dealing with directives/components and both have hostBinding
18452 // functions, we need to generate a special hostAttrs instruction that deals
18453 // with both the assignment of styling as well as static attributes to the host
18454 // element. The instruction below will instruct all initial styling (styling
18455 // that is inside of a host binding within a directive/component) to be attached
18456 // to the host element alongside any of the provided host attributes that were
18457 // collected earlier.
18458 const hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes);
18459 styleBuilder.assignHostAttrs(hostAttrs, definitionMap);
18460 if (styleBuilder.hasBindings) {
18461 // finally each binding that was registered in the statement above will need to be added to
18462 // the update block of a component/directive templateFn/hostBindingsFn so that the bindings
18463 // are evaluated and updated for the element.
18464 styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(instruction => {
18465 if (instruction.calls.length > 0) {
18466 const calls = [];
18467 instruction.calls.forEach(call => {
18468 // we subtract a value of `1` here because the binding slot was already allocated
18469 // at the top of this method when all the input bindings were counted.
18470 totalHostVarsCount +=
18471 Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
18472 calls.push(convertStylingCall(call, bindingContext, bindingFn));
18473 });
18474 updateStatements.push(chainedInstruction(instruction.reference, calls).toStmt());
18475 }
18476 });
18477 }
18478 if (totalHostVarsCount) {
18479 definitionMap.set('hostVars', literal(totalHostVarsCount));
18480 }
18481 if (createStatements.length > 0 || updateStatements.length > 0) {
18482 const hostBindingsFnName = name ? `${name}_HostBindings` : null;
18483 const statements = [];
18484 if (createStatements.length > 0) {
18485 statements.push(renderFlagCheckIfStmt(1 /* Create */, createStatements));
18486 }
18487 if (updateStatements.length > 0) {
18488 statements.push(renderFlagCheckIfStmt(2 /* Update */, updateStatements));
18489 }
18490 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], statements, INFERRED_TYPE, null, hostBindingsFnName);
18491 }
18492 return null;
18493 }
18494 function bindingFn(implicit, value) {
18495 return convertPropertyBinding(null, implicit, value, 'b', BindingForm.Expression, () => error('Unexpected interpolation'));
18496 }
18497 function convertStylingCall(call, bindingContext, bindingFn) {
18498 return call.params(value => bindingFn(bindingContext, value).currValExpr);
18499 }
18500 function getBindingNameAndInstruction(binding) {
18501 let bindingName = binding.name;
18502 let instruction;
18503 // Check to see if this is an attr binding or a property binding
18504 const attrMatches = bindingName.match(ATTR_REGEX);
18505 if (attrMatches) {
18506 bindingName = attrMatches[1];
18507 instruction = Identifiers$1.attribute;
18508 }
18509 else {
18510 if (binding.isAnimation) {
18511 bindingName = prepareSyntheticPropertyName(bindingName);
18512 // host bindings that have a synthetic property (e.g. @foo) should always be rendered
18513 // in the context of the component and not the parent. Therefore there is a special
18514 // compatibility instruction available for this purpose.
18515 instruction = Identifiers$1.syntheticHostProperty;
18516 }
18517 else {
18518 instruction = Identifiers$1.hostProperty;
18519 }
18520 }
18521 return { bindingName, instruction, isAttribute: !!attrMatches };
18522 }
18523 function createHostListeners(eventBindings, name) {
18524 const listeners = [];
18525 const syntheticListeners = [];
18526 const instructions = [];
18527 eventBindings.forEach(binding => {
18528 let bindingName = binding.name && sanitizeIdentifier(binding.name);
18529 const bindingFnName = binding.type === 1 /* Animation */ ?
18530 prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) :
18531 bindingName;
18532 const handlerName = name && bindingName ? `${name}_${bindingFnName}_HostBindingHandler` : null;
18533 const params = prepareEventListenerParameters(BoundEvent.fromParsedEvent(binding), handlerName);
18534 if (binding.type == 1 /* Animation */) {
18535 syntheticListeners.push(params);
18536 }
18537 else {
18538 listeners.push(params);
18539 }
18540 });
18541 if (syntheticListeners.length > 0) {
18542 instructions.push(chainedInstruction(Identifiers$1.syntheticHostListener, syntheticListeners).toStmt());
18543 }
18544 if (listeners.length > 0) {
18545 instructions.push(chainedInstruction(Identifiers$1.listener, listeners).toStmt());
18546 }
18547 return instructions;
18548 }
18549 function metadataAsSummary(meta) {
18550 // clang-format off
18551 return {
18552 // This is used by the BindingParser, which only deals with listeners and properties. There's no
18553 // need to pass attributes to it.
18554 hostAttributes: {},
18555 hostListeners: meta.listeners,
18556 hostProperties: meta.properties,
18557 };
18558 // clang-format on
18559 }
18560 const HOST_REG_EXP$1 = /^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/;
18561 function parseHostBindings(host) {
18562 const attributes = {};
18563 const listeners = {};
18564 const properties = {};
18565 const specialAttributes = {};
18566 for (const key of Object.keys(host)) {
18567 const value = host[key];
18568 const matches = key.match(HOST_REG_EXP$1);
18569 if (matches === null) {
18570 switch (key) {
18571 case 'class':
18572 if (typeof value !== 'string') {
18573 // TODO(alxhub): make this a diagnostic.
18574 throw new Error(`Class binding must be string`);
18575 }
18576 specialAttributes.classAttr = value;
18577 break;
18578 case 'style':
18579 if (typeof value !== 'string') {
18580 // TODO(alxhub): make this a diagnostic.
18581 throw new Error(`Style binding must be string`);
18582 }
18583 specialAttributes.styleAttr = value;
18584 break;
18585 default:
18586 if (typeof value === 'string') {
18587 attributes[key] = literal(value);
18588 }
18589 else {
18590 attributes[key] = value;
18591 }
18592 }
18593 }
18594 else if (matches[1 /* Binding */] != null) {
18595 if (typeof value !== 'string') {
18596 // TODO(alxhub): make this a diagnostic.
18597 throw new Error(`Property binding must be string`);
18598 }
18599 // synthetic properties (the ones that have a `@` as a prefix)
18600 // are still treated the same as regular properties. Therefore
18601 // there is no point in storing them in a separate map.
18602 properties[matches[1 /* Binding */]] = value;
18603 }
18604 else if (matches[2 /* Event */] != null) {
18605 if (typeof value !== 'string') {
18606 // TODO(alxhub): make this a diagnostic.
18607 throw new Error(`Event binding must be string`);
18608 }
18609 listeners[matches[2 /* Event */]] = value;
18610 }
18611 }
18612 return { attributes, listeners, properties, specialAttributes };
18613 }
18614 /**
18615 * Verifies host bindings and returns the list of errors (if any). Empty array indicates that a
18616 * given set of host bindings has no errors.
18617 *
18618 * @param bindings set of host bindings to verify.
18619 * @param sourceSpan source span where host bindings were defined.
18620 * @returns array of errors associated with a given set of host bindings.
18621 */
18622 function verifyHostBindings(bindings, sourceSpan) {
18623 const summary = metadataAsSummary(bindings);
18624 // TODO: abstract out host bindings verification logic and use it instead of
18625 // creating events and properties ASTs to detect errors (FW-996)
18626 const bindingParser = makeBindingParser();
18627 bindingParser.createDirectiveHostEventAsts(summary, sourceSpan);
18628 bindingParser.createBoundHostProperties(summary, sourceSpan);
18629 return bindingParser.errors;
18630 }
18631 function compileStyles(styles, selector, hostSelector) {
18632 const shadowCss = new ShadowCss();
18633 return styles.map(style => {
18634 return shadowCss.shimCssText(style, selector, hostSelector);
18635 });
18636 }
18637
18638 /**
18639 * @license
18640 * Copyright Google LLC All Rights Reserved.
18641 *
18642 * Use of this source code is governed by an MIT-style license that can be
18643 * found in the LICENSE file at https://angular.io/license
18644 */
18645 /**
18646 * An interface for retrieving documents by URL that the compiler uses
18647 * to load templates.
18648 */
18649 class ResourceLoader {
18650 get(url) {
18651 return '';
18652 }
18653 }
18654
18655 /**
18656 * @license
18657 * Copyright Google LLC All Rights Reserved.
18658 *
18659 * Use of this source code is governed by an MIT-style license that can be
18660 * found in the LICENSE file at https://angular.io/license
18661 */
18662 class CompilerFacadeImpl {
18663 constructor(jitEvaluator = new JitEvaluator()) {
18664 this.jitEvaluator = jitEvaluator;
18665 this.R3ResolvedDependencyType = R3ResolvedDependencyType;
18666 this.R3FactoryTarget = R3FactoryTarget;
18667 this.ResourceLoader = ResourceLoader;
18668 this.elementSchemaRegistry = new DomElementSchemaRegistry();
18669 }
18670 compilePipe(angularCoreEnv, sourceMapUrl, facade) {
18671 const metadata = {
18672 name: facade.name,
18673 type: wrapReference(facade.type),
18674 internalType: new WrappedNodeExpr(facade.type),
18675 typeArgumentCount: facade.typeArgumentCount,
18676 deps: convertR3DependencyMetadataArray(facade.deps),
18677 pipeName: facade.pipeName,
18678 pure: facade.pure,
18679 };
18680 const res = compilePipeFromMetadata(metadata);
18681 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
18682 }
18683 compileInjectable(angularCoreEnv, sourceMapUrl, facade) {
18684 const { expression, statements } = compileInjectable({
18685 name: facade.name,
18686 type: wrapReference(facade.type),
18687 internalType: new WrappedNodeExpr(facade.type),
18688 typeArgumentCount: facade.typeArgumentCount,
18689 providedIn: computeProvidedIn(facade.providedIn),
18690 useClass: wrapExpression(facade, USE_CLASS),
18691 useFactory: wrapExpression(facade, USE_FACTORY),
18692 useValue: wrapExpression(facade, USE_VALUE),
18693 useExisting: wrapExpression(facade, USE_EXISTING),
18694 userDeps: convertR3DependencyMetadataArray(facade.userDeps) || undefined,
18695 });
18696 return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
18697 }
18698 compileInjector(angularCoreEnv, sourceMapUrl, facade) {
18699 const meta = {
18700 name: facade.name,
18701 type: wrapReference(facade.type),
18702 internalType: new WrappedNodeExpr(facade.type),
18703 deps: convertR3DependencyMetadataArray(facade.deps),
18704 providers: new WrappedNodeExpr(facade.providers),
18705 imports: facade.imports.map(i => new WrappedNodeExpr(i)),
18706 };
18707 const res = compileInjector(meta);
18708 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
18709 }
18710 compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
18711 const meta = {
18712 type: wrapReference(facade.type),
18713 internalType: new WrappedNodeExpr(facade.type),
18714 adjacentType: new WrappedNodeExpr(facade.type),
18715 bootstrap: facade.bootstrap.map(wrapReference),
18716 declarations: facade.declarations.map(wrapReference),
18717 imports: facade.imports.map(wrapReference),
18718 exports: facade.exports.map(wrapReference),
18719 emitInline: true,
18720 containsForwardDecls: false,
18721 schemas: facade.schemas ? facade.schemas.map(wrapReference) : null,
18722 id: facade.id ? new WrappedNodeExpr(facade.id) : null,
18723 };
18724 const res = compileNgModule(meta);
18725 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
18726 }
18727 compileDirective(angularCoreEnv, sourceMapUrl, facade) {
18728 const meta = convertDirectiveFacadeToMetadata(facade);
18729 return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
18730 }
18731 compileDirectiveDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
18732 const typeSourceSpan = this.createParseSourceSpan('Directive', declaration.type.name, sourceMapUrl);
18733 const meta = convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan);
18734 return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
18735 }
18736 compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta) {
18737 const constantPool = new ConstantPool();
18738 const bindingParser = makeBindingParser();
18739 const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser);
18740 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
18741 }
18742 compileComponent(angularCoreEnv, sourceMapUrl, facade) {
18743 // Parse the template and check for errors.
18744 const { template, interpolation } = parseJitTemplate(facade.template, facade.name, sourceMapUrl, facade.preserveWhitespaces, facade.interpolation);
18745 // Compile the component metadata, including template, into an expression.
18746 const meta = Object.assign(Object.assign(Object.assign({}, facade), convertDirectiveFacadeToMetadata(facade)), { selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(), template, declarationListEmitMode: 0 /* Direct */, styles: [...facade.styles, ...template.styles], encapsulation: facade.encapsulation, interpolation, changeDetection: facade.changeDetection, animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) :
18747 null, relativeContextFilePath: '', i18nUseExternalIds: true });
18748 const jitExpressionSourceMap = `ng:///${facade.name}.js`;
18749 return this.compileComponentFromMeta(angularCoreEnv, jitExpressionSourceMap, meta);
18750 }
18751 compileComponentDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
18752 const typeSourceSpan = this.createParseSourceSpan('Component', declaration.type.name, sourceMapUrl);
18753 const meta = convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl);
18754 return this.compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta);
18755 }
18756 compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta) {
18757 const constantPool = new ConstantPool();
18758 const bindingParser = makeBindingParser(meta.interpolation);
18759 const res = compileComponentFromMetadata(meta, constantPool, bindingParser);
18760 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
18761 }
18762 compileFactory(angularCoreEnv, sourceMapUrl, meta) {
18763 const factoryRes = compileFactoryFunction({
18764 name: meta.name,
18765 type: wrapReference(meta.type),
18766 internalType: new WrappedNodeExpr(meta.type),
18767 typeArgumentCount: meta.typeArgumentCount,
18768 deps: convertR3DependencyMetadataArray(meta.deps),
18769 injectFn: meta.injectFn === 'directiveInject' ? Identifiers.directiveInject :
18770 Identifiers.inject,
18771 target: meta.target,
18772 });
18773 return this.jitExpression(factoryRes.factory, angularCoreEnv, sourceMapUrl, factoryRes.statements);
18774 }
18775 createParseSourceSpan(kind, typeName, sourceUrl) {
18776 return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
18777 }
18778 /**
18779 * JIT compiles an expression and returns the result of executing that expression.
18780 *
18781 * @param def the definition which will be compiled and executed to get the value to patch
18782 * @param context an object map of @angular/core symbol names to symbols which will be available
18783 * in the context of the compiled expression
18784 * @param sourceUrl a URL to use for the source map of the compiled expression
18785 * @param preStatements a collection of statements that should be evaluated before the expression.
18786 */
18787 jitExpression(def, context, sourceUrl, preStatements) {
18788 // The ConstantPool may contain Statements which declare variables used in the final expression.
18789 // Therefore, its statements need to precede the actual JIT operation. The final statement is a
18790 // declaration of $def which is set to the expression being compiled.
18791 const statements = [
18792 ...preStatements,
18793 new DeclareVarStmt('$def', def, undefined, [StmtModifier.Exported]),
18794 ];
18795 const res = this.jitEvaluator.evaluateStatements(sourceUrl, statements, new R3JitReflector(context), /* enableSourceMaps */ true);
18796 return res['$def'];
18797 }
18798 }
18799 const USE_CLASS = Object.keys({ useClass: null })[0];
18800 const USE_FACTORY = Object.keys({ useFactory: null })[0];
18801 const USE_VALUE = Object.keys({ useValue: null })[0];
18802 const USE_EXISTING = Object.keys({ useExisting: null })[0];
18803 const wrapReference = function (value) {
18804 const wrapped = new WrappedNodeExpr(value);
18805 return { value: wrapped, type: wrapped };
18806 };
18807 function convertToR3QueryMetadata(facade) {
18808 return Object.assign(Object.assign({}, facade), { predicate: Array.isArray(facade.predicate) ? facade.predicate :
18809 new WrappedNodeExpr(facade.predicate), read: facade.read ? new WrappedNodeExpr(facade.read) : null, static: facade.static, emitDistinctChangesOnly: facade.emitDistinctChangesOnly });
18810 }
18811 function convertQueryDeclarationToMetadata(declaration) {
18812 var _a, _b, _c, _d;
18813 return {
18814 propertyName: declaration.propertyName,
18815 first: (_a = declaration.first) !== null && _a !== void 0 ? _a : false,
18816 predicate: Array.isArray(declaration.predicate) ? declaration.predicate :
18817 new WrappedNodeExpr(declaration.predicate),
18818 descendants: (_b = declaration.descendants) !== null && _b !== void 0 ? _b : false,
18819 read: declaration.read ? new WrappedNodeExpr(declaration.read) : null,
18820 static: (_c = declaration.static) !== null && _c !== void 0 ? _c : false,
18821 emitDistinctChangesOnly: (_d = declaration.emitDistinctChangesOnly) !== null && _d !== void 0 ? _d : true,
18822 };
18823 }
18824 function convertDirectiveFacadeToMetadata(facade) {
18825 const inputsFromMetadata = parseInputOutputs(facade.inputs || []);
18826 const outputsFromMetadata = parseInputOutputs(facade.outputs || []);
18827 const propMetadata = facade.propMetadata;
18828 const inputsFromType = {};
18829 const outputsFromType = {};
18830 for (const field in propMetadata) {
18831 if (propMetadata.hasOwnProperty(field)) {
18832 propMetadata[field].forEach(ann => {
18833 if (isInput(ann)) {
18834 inputsFromType[field] =
18835 ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field;
18836 }
18837 else if (isOutput(ann)) {
18838 outputsFromType[field] = ann.bindingPropertyName || field;
18839 }
18840 });
18841 }
18842 }
18843 return Object.assign(Object.assign({}, facade), { typeSourceSpan: facade.typeSourceSpan, type: wrapReference(facade.type), internalType: new WrappedNodeExpr(facade.type), deps: convertR3DependencyMetadataArray(facade.deps), host: extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host), inputs: Object.assign(Object.assign({}, inputsFromMetadata), inputsFromType), outputs: Object.assign(Object.assign({}, outputsFromMetadata), outputsFromType), queries: facade.queries.map(convertToR3QueryMetadata), providers: facade.providers != null ? new WrappedNodeExpr(facade.providers) : null, viewQueries: facade.viewQueries.map(convertToR3QueryMetadata), fullInheritance: false });
18844 }
18845 function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
18846 var _a, _b, _c, _d, _e, _f, _g, _h;
18847 return {
18848 name: declaration.type.name,
18849 type: wrapReference(declaration.type),
18850 typeSourceSpan,
18851 internalType: new WrappedNodeExpr(declaration.type),
18852 selector: (_a = declaration.selector) !== null && _a !== void 0 ? _a : null,
18853 inputs: (_b = declaration.inputs) !== null && _b !== void 0 ? _b : {},
18854 outputs: (_c = declaration.outputs) !== null && _c !== void 0 ? _c : {},
18855 host: convertHostDeclarationToMetadata(declaration.host),
18856 queries: ((_d = declaration.queries) !== null && _d !== void 0 ? _d : []).map(convertQueryDeclarationToMetadata),
18857 viewQueries: ((_e = declaration.viewQueries) !== null && _e !== void 0 ? _e : []).map(convertQueryDeclarationToMetadata),
18858 providers: declaration.providers !== undefined ? new WrappedNodeExpr(declaration.providers) :
18859 null,
18860 exportAs: (_f = declaration.exportAs) !== null && _f !== void 0 ? _f : null,
18861 usesInheritance: (_g = declaration.usesInheritance) !== null && _g !== void 0 ? _g : false,
18862 lifecycle: { usesOnChanges: (_h = declaration.usesOnChanges) !== null && _h !== void 0 ? _h : false },
18863 deps: null,
18864 typeArgumentCount: 0,
18865 fullInheritance: false,
18866 };
18867 }
18868 function convertHostDeclarationToMetadata(host = {}) {
18869 var _a, _b, _c;
18870 return {
18871 attributes: convertOpaqueValuesToExpressions((_a = host.attributes) !== null && _a !== void 0 ? _a : {}),
18872 listeners: (_b = host.listeners) !== null && _b !== void 0 ? _b : {},
18873 properties: (_c = host.properties) !== null && _c !== void 0 ? _c : {},
18874 specialAttributes: {
18875 classAttr: host.classAttribute,
18876 styleAttr: host.styleAttribute,
18877 },
18878 };
18879 }
18880 function convertOpaqueValuesToExpressions(obj) {
18881 const result = {};
18882 for (const key of Object.keys(obj)) {
18883 result[key] = new WrappedNodeExpr(obj[key]);
18884 }
18885 return result;
18886 }
18887 function convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl) {
18888 var _a, _b, _c, _d, _e;
18889 const { template, interpolation } = parseJitTemplate(declaration.template, declaration.type.name, sourceMapUrl, (_a = declaration.preserveWhitespaces) !== null && _a !== void 0 ? _a : false, declaration.interpolation);
18890 return Object.assign(Object.assign({}, convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan)), { template, styles: (_b = declaration.styles) !== null && _b !== void 0 ? _b : [], directives: ((_c = declaration.directives) !== null && _c !== void 0 ? _c : []).map(convertUsedDirectiveDeclarationToMetadata), pipes: convertUsedPipesToMetadata(declaration.pipes), viewProviders: declaration.viewProviders !== undefined ?
18891 new WrappedNodeExpr(declaration.viewProviders) :
18892 null, animations: declaration.animations !== undefined ? new WrappedNodeExpr(declaration.animations) :
18893 null, changeDetection: (_d = declaration.changeDetection) !== null && _d !== void 0 ? _d : ChangeDetectionStrategy.Default, encapsulation: (_e = declaration.encapsulation) !== null && _e !== void 0 ? _e : ViewEncapsulation.Emulated, interpolation, declarationListEmitMode: 2 /* ClosureResolved */, relativeContextFilePath: '', i18nUseExternalIds: true });
18894 }
18895 function convertUsedDirectiveDeclarationToMetadata(declaration) {
18896 var _a, _b, _c;
18897 return {
18898 selector: declaration.selector,
18899 type: new WrappedNodeExpr(declaration.type),
18900 inputs: (_a = declaration.inputs) !== null && _a !== void 0 ? _a : [],
18901 outputs: (_b = declaration.outputs) !== null && _b !== void 0 ? _b : [],
18902 exportAs: (_c = declaration.exportAs) !== null && _c !== void 0 ? _c : null,
18903 };
18904 }
18905 function convertUsedPipesToMetadata(declaredPipes) {
18906 const pipes = new Map();
18907 if (declaredPipes === undefined) {
18908 return pipes;
18909 }
18910 for (const pipeName of Object.keys(declaredPipes)) {
18911 const pipeType = declaredPipes[pipeName];
18912 pipes.set(pipeName, new WrappedNodeExpr(pipeType));
18913 }
18914 return pipes;
18915 }
18916 function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
18917 const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
18918 // Parse the template and check for errors.
18919 const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces: preserveWhitespaces, interpolationConfig });
18920 if (parsed.errors !== null) {
18921 const errors = parsed.errors.map(err => err.toString()).join(', ');
18922 throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
18923 }
18924 return { template: parsed, interpolation: interpolationConfig };
18925 }
18926 function wrapExpression(obj, property) {
18927 if (obj.hasOwnProperty(property)) {
18928 return new WrappedNodeExpr(obj[property]);
18929 }
18930 else {
18931 return undefined;
18932 }
18933 }
18934 function computeProvidedIn(providedIn) {
18935 if (providedIn == null || typeof providedIn === 'string') {
18936 return new LiteralExpr(providedIn);
18937 }
18938 else {
18939 return new WrappedNodeExpr(providedIn);
18940 }
18941 }
18942 function convertR3DependencyMetadata(facade) {
18943 let tokenExpr;
18944 if (facade.token === null) {
18945 tokenExpr = new LiteralExpr(null);
18946 }
18947 else if (facade.resolved === R3ResolvedDependencyType.Attribute) {
18948 tokenExpr = new LiteralExpr(facade.token);
18949 }
18950 else {
18951 tokenExpr = new WrappedNodeExpr(facade.token);
18952 }
18953 return {
18954 token: tokenExpr,
18955 attribute: null,
18956 resolved: facade.resolved,
18957 host: facade.host,
18958 optional: facade.optional,
18959 self: facade.self,
18960 skipSelf: facade.skipSelf,
18961 };
18962 }
18963 function convertR3DependencyMetadataArray(facades) {
18964 return facades == null ? null : facades.map(convertR3DependencyMetadata);
18965 }
18966 function extractHostBindings(propMetadata, sourceSpan, host) {
18967 // First parse the declarations from the metadata.
18968 const bindings = parseHostBindings(host || {});
18969 // After that check host bindings for errors
18970 const errors = verifyHostBindings(bindings, sourceSpan);
18971 if (errors.length) {
18972 throw new Error(errors.map((error) => error.msg).join('\n'));
18973 }
18974 // Next, loop over the properties of the object, looking for @HostBinding and @HostListener.
18975 for (const field in propMetadata) {
18976 if (propMetadata.hasOwnProperty(field)) {
18977 propMetadata[field].forEach(ann => {
18978 if (isHostBinding(ann)) {
18979 // Since this is a decorator, we know that the value is a class member. Always access it
18980 // through `this` so that further down the line it can't be confused for a literal value
18981 // (e.g. if there's a property called `true`).
18982 bindings.properties[ann.hostPropertyName || field] =
18983 getSafePropertyAccessString('this', field);
18984 }
18985 else if (isHostListener(ann)) {
18986 bindings.listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`;
18987 }
18988 });
18989 }
18990 }
18991 return bindings;
18992 }
18993 function isHostBinding(value) {
18994 return value.ngMetadataName === 'HostBinding';
18995 }
18996 function isHostListener(value) {
18997 return value.ngMetadataName === 'HostListener';
18998 }
18999 function isInput(value) {
19000 return value.ngMetadataName === 'Input';
19001 }
19002 function isOutput(value) {
19003 return value.ngMetadataName === 'Output';
19004 }
19005 function parseInputOutputs(values) {
19006 return values.reduce((map, value) => {
19007 const [field, property] = value.split(',').map(piece => piece.trim());
19008 map[field] = property || field;
19009 return map;
19010 }, {});
19011 }
19012 function publishFacade(global) {
19013 const ng = global.ng || (global.ng = {});
19014 ng.ɵcompilerFacade = new CompilerFacadeImpl();
19015 }
19016
19017 /**
19018 * @license
19019 * Copyright Google LLC All Rights Reserved.
19020 *
19021 * Use of this source code is governed by an MIT-style license that can be
19022 * found in the LICENSE file at https://angular.io/license
19023 */
19024 const VERSION$1 = new Version('11.2.0');
19025
19026 /**
19027 * @license
19028 * Copyright Google LLC All Rights Reserved.
19029 *
19030 * Use of this source code is governed by an MIT-style license that can be
19031 * found in the LICENSE file at https://angular.io/license
19032 */
19033 class CompilerConfig {
19034 constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, jitDevMode = false, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
19035 this.defaultEncapsulation = defaultEncapsulation;
19036 this.useJit = !!useJit;
19037 this.jitDevMode = !!jitDevMode;
19038 this.missingTranslation = missingTranslation;
19039 this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
19040 this.strictInjectionParameters = strictInjectionParameters === true;
19041 }
19042 }
19043 function preserveWhitespacesDefault(preserveWhitespacesOption, defaultSetting = false) {
19044 return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
19045 }
19046
19047 /**
19048 * @license
19049 * Copyright Google LLC All Rights Reserved.
19050 *
19051 * Use of this source code is governed by an MIT-style license that can be
19052 * found in the LICENSE file at https://angular.io/license
19053 */
19054 class DirectiveNormalizer {
19055 constructor(_resourceLoader, _urlResolver, _htmlParser, _config) {
19056 this._resourceLoader = _resourceLoader;
19057 this._urlResolver = _urlResolver;
19058 this._htmlParser = _htmlParser;
19059 this._config = _config;
19060 this._resourceLoaderCache = new Map();
19061 }
19062 clearCache() {
19063 this._resourceLoaderCache.clear();
19064 }
19065 clearCacheFor(normalizedDirective) {
19066 if (!normalizedDirective.isComponent) {
19067 return;
19068 }
19069 const template = normalizedDirective.template;
19070 this._resourceLoaderCache.delete(template.templateUrl);
19071 template.externalStylesheets.forEach((stylesheet) => {
19072 this._resourceLoaderCache.delete(stylesheet.moduleUrl);
19073 });
19074 }
19075 _fetch(url) {
19076 let result = this._resourceLoaderCache.get(url);
19077 if (!result) {
19078 result = this._resourceLoader.get(url);
19079 this._resourceLoaderCache.set(url, result);
19080 }
19081 return result;
19082 }
19083 normalizeTemplate(prenormData) {
19084 if (isDefined(prenormData.template)) {
19085 if (isDefined(prenormData.templateUrl)) {
19086 throw syntaxError(`'${stringify(prenormData
19087 .componentType)}' component cannot define both template and templateUrl`);
19088 }
19089 if (typeof prenormData.template !== 'string') {
19090 throw syntaxError(`The template specified for component ${stringify(prenormData.componentType)} is not a string`);
19091 }
19092 }
19093 else if (isDefined(prenormData.templateUrl)) {
19094 if (typeof prenormData.templateUrl !== 'string') {
19095 throw syntaxError(`The templateUrl specified for component ${stringify(prenormData.componentType)} is not a string`);
19096 }
19097 }
19098 else {
19099 throw syntaxError(`No template specified for component ${stringify(prenormData.componentType)}`);
19100 }
19101 if (isDefined(prenormData.preserveWhitespaces) &&
19102 typeof prenormData.preserveWhitespaces !== 'boolean') {
19103 throw syntaxError(`The preserveWhitespaces option for component ${stringify(prenormData.componentType)} must be a boolean`);
19104 }
19105 return SyncAsync.then(this._preParseTemplate(prenormData), (preparsedTemplate) => this._normalizeTemplateMetadata(prenormData, preparsedTemplate));
19106 }
19107 _preParseTemplate(prenomData) {
19108 let template;
19109 let templateUrl;
19110 if (prenomData.template != null) {
19111 template = prenomData.template;
19112 templateUrl = prenomData.moduleUrl;
19113 }
19114 else {
19115 templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl);
19116 template = this._fetch(templateUrl);
19117 }
19118 return SyncAsync.then(template, (template) => this._preparseLoadedTemplate(prenomData, template, templateUrl));
19119 }
19120 _preparseLoadedTemplate(prenormData, template, templateAbsUrl) {
19121 const isInline = !!prenormData.template;
19122 const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation);
19123 const templateUrl = templateSourceUrl({ reference: prenormData.ngModuleType }, { type: { reference: prenormData.componentType } }, { isInline, templateUrl: templateAbsUrl });
19124 const rootNodesAndErrors = this._htmlParser.parse(template, templateUrl, { tokenizeExpansionForms: true, interpolationConfig });
19125 if (rootNodesAndErrors.errors.length > 0) {
19126 const errorString = rootNodesAndErrors.errors.join('\n');
19127 throw syntaxError(`Template parse errors:\n${errorString}`);
19128 }
19129 const templateMetadataStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: prenormData.styles, moduleUrl: prenormData.moduleUrl }));
19130 const visitor = new TemplatePreparseVisitor();
19131 visitAll$1(visitor, rootNodesAndErrors.rootNodes);
19132 const templateStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl }));
19133 const styles = templateMetadataStyles.styles.concat(templateStyles.styles);
19134 const inlineStyleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
19135 const styleUrls = this
19136 ._normalizeStylesheet(new CompileStylesheetMetadata({ styleUrls: prenormData.styleUrls, moduleUrl: prenormData.moduleUrl }))
19137 .styleUrls;
19138 return {
19139 template,
19140 templateUrl: templateAbsUrl,
19141 isInline,
19142 htmlAst: rootNodesAndErrors,
19143 styles,
19144 inlineStyleUrls,
19145 styleUrls,
19146 ngContentSelectors: visitor.ngContentSelectors,
19147 };
19148 }
19149 _normalizeTemplateMetadata(prenormData, preparsedTemplate) {
19150 return SyncAsync.then(this._loadMissingExternalStylesheets(preparsedTemplate.styleUrls.concat(preparsedTemplate.inlineStyleUrls)), (externalStylesheets) => this._normalizeLoadedTemplateMetadata(prenormData, preparsedTemplate, externalStylesheets));
19151 }
19152 _normalizeLoadedTemplateMetadata(prenormData, preparsedTemplate, stylesheets) {
19153 // Algorithm:
19154 // - produce exactly 1 entry per original styleUrl in
19155 // CompileTemplateMetadata.externalStylesheets with all styles inlined
19156 // - inline all styles that are referenced by the template into CompileTemplateMetadata.styles.
19157 // Reason: be able to determine how many stylesheets there are even without loading
19158 // the template nor the stylesheets, so we can create a stub for TypeScript always synchronously
19159 // (as resource loading may be async)
19160 const styles = [...preparsedTemplate.styles];
19161 this._inlineStyles(preparsedTemplate.inlineStyleUrls, stylesheets, styles);
19162 const styleUrls = preparsedTemplate.styleUrls;
19163 const externalStylesheets = styleUrls.map(styleUrl => {
19164 const stylesheet = stylesheets.get(styleUrl);
19165 const styles = [...stylesheet.styles];
19166 this._inlineStyles(stylesheet.styleUrls, stylesheets, styles);
19167 return new CompileStylesheetMetadata({ moduleUrl: styleUrl, styles: styles });
19168 });
19169 let encapsulation = prenormData.encapsulation;
19170 if (encapsulation == null) {
19171 encapsulation = this._config.defaultEncapsulation;
19172 }
19173 if (encapsulation === ViewEncapsulation.Emulated && styles.length === 0 &&
19174 styleUrls.length === 0) {
19175 encapsulation = ViewEncapsulation.None;
19176 }
19177 return new CompileTemplateMetadata({
19178 encapsulation,
19179 template: preparsedTemplate.template,
19180 templateUrl: preparsedTemplate.templateUrl,
19181 htmlAst: preparsedTemplate.htmlAst,
19182 styles,
19183 styleUrls,
19184 ngContentSelectors: preparsedTemplate.ngContentSelectors,
19185 animations: prenormData.animations,
19186 interpolation: prenormData.interpolation,
19187 isInline: preparsedTemplate.isInline,
19188 externalStylesheets,
19189 preserveWhitespaces: preserveWhitespacesDefault(prenormData.preserveWhitespaces, this._config.preserveWhitespaces),
19190 });
19191 }
19192 _inlineStyles(styleUrls, stylesheets, targetStyles) {
19193 styleUrls.forEach(styleUrl => {
19194 const stylesheet = stylesheets.get(styleUrl);
19195 stylesheet.styles.forEach(style => targetStyles.push(style));
19196 this._inlineStyles(stylesheet.styleUrls, stylesheets, targetStyles);
19197 });
19198 }
19199 _loadMissingExternalStylesheets(styleUrls, loadedStylesheets = new Map()) {
19200 return SyncAsync.then(SyncAsync.all(styleUrls.filter((styleUrl) => !loadedStylesheets.has(styleUrl))
19201 .map(styleUrl => SyncAsync.then(this._fetch(styleUrl), (loadedStyle) => {
19202 const stylesheet = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: [loadedStyle], moduleUrl: styleUrl }));
19203 loadedStylesheets.set(styleUrl, stylesheet);
19204 return this._loadMissingExternalStylesheets(stylesheet.styleUrls, loadedStylesheets);
19205 }))), (_) => loadedStylesheets);
19206 }
19207 _normalizeStylesheet(stylesheet) {
19208 const moduleUrl = stylesheet.moduleUrl;
19209 const allStyleUrls = stylesheet.styleUrls.filter(isStyleUrlResolvable)
19210 .map(url => this._urlResolver.resolve(moduleUrl, url));
19211 const allStyles = stylesheet.styles.map(style => {
19212 const styleWithImports = extractStyleUrls(this._urlResolver, moduleUrl, style);
19213 allStyleUrls.push(...styleWithImports.styleUrls);
19214 return styleWithImports.style;
19215 });
19216 return new CompileStylesheetMetadata({ styles: allStyles, styleUrls: allStyleUrls, moduleUrl: moduleUrl });
19217 }
19218 }
19219 class TemplatePreparseVisitor {
19220 constructor() {
19221 this.ngContentSelectors = [];
19222 this.styles = [];
19223 this.styleUrls = [];
19224 this.ngNonBindableStackCount = 0;
19225 }
19226 visitElement(ast, context) {
19227 const preparsedElement = preparseElement(ast);
19228 switch (preparsedElement.type) {
19229 case PreparsedElementType.NG_CONTENT:
19230 if (this.ngNonBindableStackCount === 0) {
19231 this.ngContentSelectors.push(preparsedElement.selectAttr);
19232 }
19233 break;
19234 case PreparsedElementType.STYLE:
19235 let textContent = '';
19236 ast.children.forEach(child => {
19237 if (child instanceof Text$2) {
19238 textContent += child.value;
19239 }
19240 });
19241 this.styles.push(textContent);
19242 break;
19243 case PreparsedElementType.STYLESHEET:
19244 this.styleUrls.push(preparsedElement.hrefAttr);
19245 break;
19246 }
19247 if (preparsedElement.nonBindable) {
19248 this.ngNonBindableStackCount++;
19249 }
19250 visitAll$1(this, ast.children);
19251 if (preparsedElement.nonBindable) {
19252 this.ngNonBindableStackCount--;
19253 }
19254 return null;
19255 }
19256 visitExpansion(ast, context) {
19257 visitAll$1(this, ast.cases);
19258 }
19259 visitExpansionCase(ast, context) {
19260 visitAll$1(this, ast.expression);
19261 }
19262 visitComment(ast, context) {
19263 return null;
19264 }
19265 visitAttribute(ast, context) {
19266 return null;
19267 }
19268 visitText(ast, context) {
19269 return null;
19270 }
19271 }
19272
19273 /**
19274 * @license
19275 * Copyright Google LLC All Rights Reserved.
19276 *
19277 * Use of this source code is governed by an MIT-style license that can be
19278 * found in the LICENSE file at https://angular.io/license
19279 */
19280 const QUERY_METADATA_IDENTIFIERS = [
19281 createViewChild,
19282 createViewChildren,
19283 createContentChild,
19284 createContentChildren,
19285 ];
19286 /*
19287 * Resolve a `Type` for {@link Directive}.
19288 *
19289 * This interface can be overridden by the application developer to create custom behavior.
19290 *
19291 * See {@link Compiler}
19292 */
19293 class DirectiveResolver {
19294 constructor(_reflector) {
19295 this._reflector = _reflector;
19296 }
19297 isDirective(type) {
19298 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
19299 return typeMetadata && typeMetadata.some(isDirectiveMetadata);
19300 }
19301 resolve(type, throwIfNotFound = true) {
19302 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
19303 if (typeMetadata) {
19304 const metadata = findLast(typeMetadata, isDirectiveMetadata);
19305 if (metadata) {
19306 const propertyMetadata = this._reflector.propMetadata(type);
19307 const guards = this._reflector.guards(type);
19308 return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
19309 }
19310 }
19311 if (throwIfNotFound) {
19312 throw new Error(`No Directive annotation found on ${stringify(type)}`);
19313 }
19314 return null;
19315 }
19316 _mergeWithPropertyMetadata(dm, propertyMetadata, guards, directiveType) {
19317 const inputs = [];
19318 const outputs = [];
19319 const host = {};
19320 const queries = {};
19321 Object.keys(propertyMetadata).forEach((propName) => {
19322 const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
19323 if (input) {
19324 if (input.bindingPropertyName) {
19325 inputs.push(`${propName}: ${input.bindingPropertyName}`);
19326 }
19327 else {
19328 inputs.push(propName);
19329 }
19330 }
19331 const output = findLast(propertyMetadata[propName], (a) => createOutput.isTypeOf(a));
19332 if (output) {
19333 if (output.bindingPropertyName) {
19334 outputs.push(`${propName}: ${output.bindingPropertyName}`);
19335 }
19336 else {
19337 outputs.push(propName);
19338 }
19339 }
19340 const hostBindings = propertyMetadata[propName].filter(a => createHostBinding.isTypeOf(a));
19341 hostBindings.forEach(hostBinding => {
19342 if (hostBinding.hostPropertyName) {
19343 const startWith = hostBinding.hostPropertyName[0];
19344 if (startWith === '(') {
19345 throw new Error(`@HostBinding can not bind to events. Use @HostListener instead.`);
19346 }
19347 else if (startWith === '[') {
19348 throw new Error(`@HostBinding parameter should be a property name, 'class.<name>', or 'attr.<name>'.`);
19349 }
19350 host[`[${hostBinding.hostPropertyName}]`] = propName;
19351 }
19352 else {
19353 host[`[${propName}]`] = propName;
19354 }
19355 });
19356 const hostListeners = propertyMetadata[propName].filter(a => createHostListener.isTypeOf(a));
19357 hostListeners.forEach(hostListener => {
19358 const args = hostListener.args || [];
19359 host[`(${hostListener.eventName})`] = `${propName}(${args.join(',')})`;
19360 });
19361 const query = findLast(propertyMetadata[propName], (a) => QUERY_METADATA_IDENTIFIERS.some(i => i.isTypeOf(a)));
19362 if (query) {
19363 queries[propName] = query;
19364 }
19365 });
19366 return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
19367 }
19368 _extractPublicName(def) {
19369 return splitAtColon(def, [null, def])[1].trim();
19370 }
19371 _dedupeBindings(bindings) {
19372 const names = new Set();
19373 const publicNames = new Set();
19374 const reversedResult = [];
19375 // go last to first to allow later entries to overwrite previous entries
19376 for (let i = bindings.length - 1; i >= 0; i--) {
19377 const binding = bindings[i];
19378 const name = this._extractPublicName(binding);
19379 publicNames.add(name);
19380 if (!names.has(name)) {
19381 names.add(name);
19382 reversedResult.push(binding);
19383 }
19384 }
19385 return reversedResult.reverse();
19386 }
19387 _merge(directive, inputs, outputs, host, queries, guards, directiveType) {
19388 const mergedInputs = this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
19389 const mergedOutputs = this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
19390 const mergedHost = directive.host ? Object.assign(Object.assign({}, directive.host), host) : host;
19391 const mergedQueries = directive.queries ? Object.assign(Object.assign({}, directive.queries), queries) : queries;
19392 if (createComponent.isTypeOf(directive)) {
19393 const comp = directive;
19394 return createComponent({
19395 selector: comp.selector,
19396 inputs: mergedInputs,
19397 outputs: mergedOutputs,
19398 host: mergedHost,
19399 exportAs: comp.exportAs,
19400 moduleId: comp.moduleId,
19401 queries: mergedQueries,
19402 changeDetection: comp.changeDetection,
19403 providers: comp.providers,
19404 viewProviders: comp.viewProviders,
19405 entryComponents: comp.entryComponents,
19406 template: comp.template,
19407 templateUrl: comp.templateUrl,
19408 styles: comp.styles,
19409 styleUrls: comp.styleUrls,
19410 encapsulation: comp.encapsulation,
19411 animations: comp.animations,
19412 interpolation: comp.interpolation,
19413 preserveWhitespaces: directive.preserveWhitespaces,
19414 });
19415 }
19416 else {
19417 return createDirective({
19418 selector: directive.selector,
19419 inputs: mergedInputs,
19420 outputs: mergedOutputs,
19421 host: mergedHost,
19422 exportAs: directive.exportAs,
19423 queries: mergedQueries,
19424 providers: directive.providers,
19425 guards
19426 });
19427 }
19428 }
19429 }
19430 function isDirectiveMetadata(type) {
19431 return createDirective.isTypeOf(type) || createComponent.isTypeOf(type);
19432 }
19433 function findLast(arr, condition) {
19434 for (let i = arr.length - 1; i >= 0; i--) {
19435 if (condition(arr[i])) {
19436 return arr[i];
19437 }
19438 }
19439 return null;
19440 }
19441
19442 /**
19443 * @license
19444 * Copyright Google LLC All Rights Reserved.
19445 *
19446 * Use of this source code is governed by an MIT-style license that can be
19447 * found in the LICENSE file at https://angular.io/license
19448 */
19449 var _VisitorMode;
19450 (function (_VisitorMode) {
19451 _VisitorMode[_VisitorMode["Extract"] = 0] = "Extract";
19452 _VisitorMode[_VisitorMode["Merge"] = 1] = "Merge";
19453 })(_VisitorMode || (_VisitorMode = {}));
19454
19455 /**
19456 * @license
19457 * Copyright Google LLC All Rights Reserved.
19458 *
19459 * Use of this source code is governed by an MIT-style license that can be
19460 * found in the LICENSE file at https://angular.io/license
19461 */
19462 const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
19463 const GENERATED_FILE = /\.ngfactory\.|\.ngsummary\./;
19464 const JIT_SUMMARY_FILE = /\.ngsummary\./;
19465 const JIT_SUMMARY_NAME = /NgSummary$/;
19466 function ngfactoryFilePath(filePath, forceSourceFile = false) {
19467 const urlWithSuffix = splitTypescriptSuffix(filePath, forceSourceFile);
19468 return `${urlWithSuffix[0]}.ngfactory${normalizeGenFileSuffix(urlWithSuffix[1])}`;
19469 }
19470 function stripGeneratedFileSuffix(filePath) {
19471 return filePath.replace(GENERATED_FILE, '.');
19472 }
19473 function isGeneratedFile(filePath) {
19474 return GENERATED_FILE.test(filePath);
19475 }
19476 function splitTypescriptSuffix(path, forceSourceFile = false) {
19477 if (path.endsWith('.d.ts')) {
19478 return [path.slice(0, -5), forceSourceFile ? '.ts' : '.d.ts'];
19479 }
19480 const lastDot = path.lastIndexOf('.');
19481 if (lastDot !== -1) {
19482 return [path.substring(0, lastDot), path.substring(lastDot)];
19483 }
19484 return [path, ''];
19485 }
19486 function normalizeGenFileSuffix(srcFileSuffix) {
19487 return srcFileSuffix === '.tsx' ? '.ts' : srcFileSuffix;
19488 }
19489 function summaryFileName(fileName) {
19490 const fileNameWithoutSuffix = fileName.replace(STRIP_SRC_FILE_SUFFIXES, '');
19491 return `${fileNameWithoutSuffix}.ngsummary.json`;
19492 }
19493 function summaryForJitFileName(fileName, forceSourceFile = false) {
19494 const urlWithSuffix = splitTypescriptSuffix(stripGeneratedFileSuffix(fileName), forceSourceFile);
19495 return `${urlWithSuffix[0]}.ngsummary${urlWithSuffix[1]}`;
19496 }
19497 function stripSummaryForJitFileSuffix(filePath) {
19498 return filePath.replace(JIT_SUMMARY_FILE, '.');
19499 }
19500 function summaryForJitName(symbolName) {
19501 return `${symbolName}NgSummary`;
19502 }
19503 function stripSummaryForJitNameSuffix(symbolName) {
19504 return symbolName.replace(JIT_SUMMARY_NAME, '');
19505 }
19506
19507 /**
19508 * @license
19509 * Copyright Google LLC All Rights Reserved.
19510 *
19511 * Use of this source code is governed by an MIT-style license that can be
19512 * found in the LICENSE file at https://angular.io/license
19513 */
19514 var LifecycleHooks;
19515 (function (LifecycleHooks) {
19516 LifecycleHooks[LifecycleHooks["OnInit"] = 0] = "OnInit";
19517 LifecycleHooks[LifecycleHooks["OnDestroy"] = 1] = "OnDestroy";
19518 LifecycleHooks[LifecycleHooks["DoCheck"] = 2] = "DoCheck";
19519 LifecycleHooks[LifecycleHooks["OnChanges"] = 3] = "OnChanges";
19520 LifecycleHooks[LifecycleHooks["AfterContentInit"] = 4] = "AfterContentInit";
19521 LifecycleHooks[LifecycleHooks["AfterContentChecked"] = 5] = "AfterContentChecked";
19522 LifecycleHooks[LifecycleHooks["AfterViewInit"] = 6] = "AfterViewInit";
19523 LifecycleHooks[LifecycleHooks["AfterViewChecked"] = 7] = "AfterViewChecked";
19524 })(LifecycleHooks || (LifecycleHooks = {}));
19525 const LIFECYCLE_HOOKS_VALUES = [
19526 LifecycleHooks.OnInit, LifecycleHooks.OnDestroy, LifecycleHooks.DoCheck, LifecycleHooks.OnChanges,
19527 LifecycleHooks.AfterContentInit, LifecycleHooks.AfterContentChecked, LifecycleHooks.AfterViewInit,
19528 LifecycleHooks.AfterViewChecked
19529 ];
19530 function hasLifecycleHook(reflector, hook, token) {
19531 return reflector.hasLifecycleHook(token, getHookName(hook));
19532 }
19533 function getAllLifecycleHooks(reflector, token) {
19534 return LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(reflector, hook, token));
19535 }
19536 function getHookName(hook) {
19537 switch (hook) {
19538 case LifecycleHooks.OnInit:
19539 return 'ngOnInit';
19540 case LifecycleHooks.OnDestroy:
19541 return 'ngOnDestroy';
19542 case LifecycleHooks.DoCheck:
19543 return 'ngDoCheck';
19544 case LifecycleHooks.OnChanges:
19545 return 'ngOnChanges';
19546 case LifecycleHooks.AfterContentInit:
19547 return 'ngAfterContentInit';
19548 case LifecycleHooks.AfterContentChecked:
19549 return 'ngAfterContentChecked';
19550 case LifecycleHooks.AfterViewInit:
19551 return 'ngAfterViewInit';
19552 case LifecycleHooks.AfterViewChecked:
19553 return 'ngAfterViewChecked';
19554 default:
19555 // This default case is not needed by TypeScript compiler, as the switch is exhaustive.
19556 // However Closure Compiler does not understand that and reports an error in typed mode.
19557 // The `throw new Error` below works around the problem, and the unexpected: never variable
19558 // makes sure tsc still checks this code is unreachable.
19559 const unexpected = hook;
19560 throw new Error(`unexpected ${unexpected}`);
19561 }
19562 }
19563
19564 /**
19565 * @license
19566 * Copyright Google LLC All Rights Reserved.
19567 *
19568 * Use of this source code is governed by an MIT-style license that can be
19569 * found in the LICENSE file at https://angular.io/license
19570 */
19571 const ERROR_COMPONENT_TYPE = 'ngComponentType';
19572 // Design notes:
19573 // - don't lazily create metadata:
19574 // For some metadata, we need to do async work sometimes,
19575 // so the user has to kick off this loading.
19576 // But we want to report errors even when the async work is
19577 // not required to check that the user would have been able
19578 // to wait correctly.
19579 class CompileMetadataResolver {
19580 constructor(_config, _htmlParser, _ngModuleResolver, _directiveResolver, _pipeResolver, _summaryResolver, _schemaRegistry, _directiveNormalizer, _console, _staticSymbolCache, _reflector, _errorCollector) {
19581 this._config = _config;
19582 this._htmlParser = _htmlParser;
19583 this._ngModuleResolver = _ngModuleResolver;
19584 this._directiveResolver = _directiveResolver;
19585 this._pipeResolver = _pipeResolver;
19586 this._summaryResolver = _summaryResolver;
19587 this._schemaRegistry = _schemaRegistry;
19588 this._directiveNormalizer = _directiveNormalizer;
19589 this._console = _console;
19590 this._staticSymbolCache = _staticSymbolCache;
19591 this._reflector = _reflector;
19592 this._errorCollector = _errorCollector;
19593 this._nonNormalizedDirectiveCache = new Map();
19594 this._directiveCache = new Map();
19595 this._summaryCache = new Map();
19596 this._pipeCache = new Map();
19597 this._ngModuleCache = new Map();
19598 this._ngModuleOfTypes = new Map();
19599 this._shallowModuleCache = new Map();
19600 }
19601 getReflector() {
19602 return this._reflector;
19603 }
19604 clearCacheFor(type) {
19605 const dirMeta = this._directiveCache.get(type);
19606 this._directiveCache.delete(type);
19607 this._nonNormalizedDirectiveCache.delete(type);
19608 this._summaryCache.delete(type);
19609 this._pipeCache.delete(type);
19610 this._ngModuleOfTypes.delete(type);
19611 // Clear all of the NgModule as they contain transitive information!
19612 this._ngModuleCache.clear();
19613 if (dirMeta) {
19614 this._directiveNormalizer.clearCacheFor(dirMeta);
19615 }
19616 }
19617 clearCache() {
19618 this._directiveCache.clear();
19619 this._nonNormalizedDirectiveCache.clear();
19620 this._summaryCache.clear();
19621 this._pipeCache.clear();
19622 this._ngModuleCache.clear();
19623 this._ngModuleOfTypes.clear();
19624 this._directiveNormalizer.clearCache();
19625 }
19626 _createProxyClass(baseType, name) {
19627 let delegate = null;
19628 const proxyClass = function () {
19629 if (!delegate) {
19630 throw new Error(`Illegal state: Class ${name} for type ${stringify(baseType)} is not compiled yet!`);
19631 }
19632 return delegate.apply(this, arguments);
19633 };
19634 proxyClass.setDelegate = (d) => {
19635 delegate = d;
19636 proxyClass.prototype = d.prototype;
19637 };
19638 // Make stringify work correctly
19639 proxyClass.overriddenName = name;
19640 return proxyClass;
19641 }
19642 getGeneratedClass(dirType, name) {
19643 if (dirType instanceof StaticSymbol) {
19644 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), name);
19645 }
19646 else {
19647 return this._createProxyClass(dirType, name);
19648 }
19649 }
19650 getComponentViewClass(dirType) {
19651 return this.getGeneratedClass(dirType, viewClassName(dirType, 0));
19652 }
19653 getHostComponentViewClass(dirType) {
19654 return this.getGeneratedClass(dirType, hostViewClassName(dirType));
19655 }
19656 getHostComponentType(dirType) {
19657 const name = `${identifierName({ reference: dirType })}_Host`;
19658 if (dirType instanceof StaticSymbol) {
19659 return this._staticSymbolCache.get(dirType.filePath, name);
19660 }
19661 return this._createProxyClass(dirType, name);
19662 }
19663 getRendererType(dirType) {
19664 if (dirType instanceof StaticSymbol) {
19665 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), rendererTypeName(dirType));
19666 }
19667 else {
19668 // returning an object as proxy,
19669 // that we fill later during runtime compilation.
19670 return {};
19671 }
19672 }
19673 getComponentFactory(selector, dirType, inputs, outputs) {
19674 if (dirType instanceof StaticSymbol) {
19675 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), componentFactoryName(dirType));
19676 }
19677 else {
19678 const hostView = this.getHostComponentViewClass(dirType);
19679 // Note: ngContentSelectors will be filled later once the template is
19680 // loaded.
19681 const createComponentFactory = this._reflector.resolveExternalReference(Identifiers.createComponentFactory);
19682 return createComponentFactory(selector, dirType, hostView, inputs, outputs, []);
19683 }
19684 }
19685 initComponentFactory(factory, ngContentSelectors) {
19686 if (!(factory instanceof StaticSymbol)) {
19687 factory.ngContentSelectors.push(...ngContentSelectors);
19688 }
19689 }
19690 _loadSummary(type, kind) {
19691 let typeSummary = this._summaryCache.get(type);
19692 if (!typeSummary) {
19693 const summary = this._summaryResolver.resolveSummary(type);
19694 typeSummary = summary ? summary.type : null;
19695 this._summaryCache.set(type, typeSummary || null);
19696 }
19697 return typeSummary && typeSummary.summaryKind === kind ? typeSummary : null;
19698 }
19699 getHostComponentMetadata(compMeta, hostViewType) {
19700 const hostType = this.getHostComponentType(compMeta.type.reference);
19701 if (!hostViewType) {
19702 hostViewType = this.getHostComponentViewClass(hostType);
19703 }
19704 // Note: ! is ok here as this method should only be called with normalized directive
19705 // metadata, which always fills in the selector.
19706 const template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
19707 const templateUrl = '';
19708 const htmlAst = this._htmlParser.parse(template, templateUrl);
19709 return CompileDirectiveMetadata.create({
19710 isHost: true,
19711 type: { reference: hostType, diDeps: [], lifecycleHooks: [] },
19712 template: new CompileTemplateMetadata({
19713 encapsulation: ViewEncapsulation.None,
19714 template,
19715 templateUrl,
19716 htmlAst,
19717 styles: [],
19718 styleUrls: [],
19719 ngContentSelectors: [],
19720 animations: [],
19721 isInline: true,
19722 externalStylesheets: [],
19723 interpolation: null,
19724 preserveWhitespaces: false,
19725 }),
19726 exportAs: null,
19727 changeDetection: ChangeDetectionStrategy.Default,
19728 inputs: [],
19729 outputs: [],
19730 host: {},
19731 isComponent: true,
19732 selector: '*',
19733 providers: [],
19734 viewProviders: [],
19735 queries: [],
19736 guards: {},
19737 viewQueries: [],
19738 componentViewType: hostViewType,
19739 rendererType: { id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {} },
19740 entryComponents: [],
19741 componentFactory: null
19742 });
19743 }
19744 loadDirectiveMetadata(ngModuleType, directiveType, isSync) {
19745 if (this._directiveCache.has(directiveType)) {
19746 return null;
19747 }
19748 directiveType = resolveForwardRef(directiveType);
19749 const { annotation, metadata } = this.getNonNormalizedDirectiveMetadata(directiveType);
19750 const createDirectiveMetadata = (templateMetadata) => {
19751 const normalizedDirMeta = new CompileDirectiveMetadata({
19752 isHost: false,
19753 type: metadata.type,
19754 isComponent: metadata.isComponent,
19755 selector: metadata.selector,
19756 exportAs: metadata.exportAs,
19757 changeDetection: metadata.changeDetection,
19758 inputs: metadata.inputs,
19759 outputs: metadata.outputs,
19760 hostListeners: metadata.hostListeners,
19761 hostProperties: metadata.hostProperties,
19762 hostAttributes: metadata.hostAttributes,
19763 providers: metadata.providers,
19764 viewProviders: metadata.viewProviders,
19765 queries: metadata.queries,
19766 guards: metadata.guards,
19767 viewQueries: metadata.viewQueries,
19768 entryComponents: metadata.entryComponents,
19769 componentViewType: metadata.componentViewType,
19770 rendererType: metadata.rendererType,
19771 componentFactory: metadata.componentFactory,
19772 template: templateMetadata
19773 });
19774 if (templateMetadata) {
19775 this.initComponentFactory(metadata.componentFactory, templateMetadata.ngContentSelectors);
19776 }
19777 this._directiveCache.set(directiveType, normalizedDirMeta);
19778 this._summaryCache.set(directiveType, normalizedDirMeta.toSummary());
19779 return null;
19780 };
19781 if (metadata.isComponent) {
19782 const template = metadata.template;
19783 const templateMeta = this._directiveNormalizer.normalizeTemplate({
19784 ngModuleType,
19785 componentType: directiveType,
19786 moduleUrl: this._reflector.componentModuleUrl(directiveType, annotation),
19787 encapsulation: template.encapsulation,
19788 template: template.template,
19789 templateUrl: template.templateUrl,
19790 styles: template.styles,
19791 styleUrls: template.styleUrls,
19792 animations: template.animations,
19793 interpolation: template.interpolation,
19794 preserveWhitespaces: template.preserveWhitespaces
19795 });
19796 if (isPromise(templateMeta) && isSync) {
19797 this._reportError(componentStillLoadingError(directiveType), directiveType);
19798 return null;
19799 }
19800 return SyncAsync.then(templateMeta, createDirectiveMetadata);
19801 }
19802 else {
19803 // directive
19804 createDirectiveMetadata(null);
19805 return null;
19806 }
19807 }
19808 getNonNormalizedDirectiveMetadata(directiveType) {
19809 directiveType = resolveForwardRef(directiveType);
19810 if (!directiveType) {
19811 return null;
19812 }
19813 let cacheEntry = this._nonNormalizedDirectiveCache.get(directiveType);
19814 if (cacheEntry) {
19815 return cacheEntry;
19816 }
19817 const dirMeta = this._directiveResolver.resolve(directiveType, false);
19818 if (!dirMeta) {
19819 return null;
19820 }
19821 let nonNormalizedTemplateMetadata = undefined;
19822 if (createComponent.isTypeOf(dirMeta)) {
19823 // component
19824 const compMeta = dirMeta;
19825 assertArrayOfStrings('styles', compMeta.styles);
19826 assertArrayOfStrings('styleUrls', compMeta.styleUrls);
19827 assertInterpolationSymbols('interpolation', compMeta.interpolation);
19828 const animations = compMeta.animations;
19829 nonNormalizedTemplateMetadata = new CompileTemplateMetadata({
19830 encapsulation: noUndefined(compMeta.encapsulation),
19831 template: noUndefined(compMeta.template),
19832 templateUrl: noUndefined(compMeta.templateUrl),
19833 htmlAst: null,
19834 styles: compMeta.styles || [],
19835 styleUrls: compMeta.styleUrls || [],
19836 animations: animations || [],
19837 interpolation: noUndefined(compMeta.interpolation),
19838 isInline: !!compMeta.template,
19839 externalStylesheets: [],
19840 ngContentSelectors: [],
19841 preserveWhitespaces: noUndefined(dirMeta.preserveWhitespaces),
19842 });
19843 }
19844 let changeDetectionStrategy = null;
19845 let viewProviders = [];
19846 let entryComponentMetadata = [];
19847 let selector = dirMeta.selector;
19848 if (createComponent.isTypeOf(dirMeta)) {
19849 // Component
19850 const compMeta = dirMeta;
19851 changeDetectionStrategy = compMeta.changeDetection;
19852 if (compMeta.viewProviders) {
19853 viewProviders = this._getProvidersMetadata(compMeta.viewProviders, entryComponentMetadata, `viewProviders for "${stringifyType(directiveType)}"`, [], directiveType);
19854 }
19855 if (compMeta.entryComponents) {
19856 entryComponentMetadata = flattenAndDedupeArray(compMeta.entryComponents)
19857 .map((type) => this._getEntryComponentMetadata(type))
19858 .concat(entryComponentMetadata);
19859 }
19860 if (!selector) {
19861 selector = this._schemaRegistry.getDefaultComponentElementName();
19862 }
19863 }
19864 else {
19865 // Directive
19866 if (!selector) {
19867 selector = null;
19868 }
19869 }
19870 let providers = [];
19871 if (dirMeta.providers != null) {
19872 providers = this._getProvidersMetadata(dirMeta.providers, entryComponentMetadata, `providers for "${stringifyType(directiveType)}"`, [], directiveType);
19873 }
19874 let queries = [];
19875 let viewQueries = [];
19876 if (dirMeta.queries != null) {
19877 queries = this._getQueriesMetadata(dirMeta.queries, false, directiveType);
19878 viewQueries = this._getQueriesMetadata(dirMeta.queries, true, directiveType);
19879 }
19880 const metadata = CompileDirectiveMetadata.create({
19881 isHost: false,
19882 selector: selector,
19883 exportAs: noUndefined(dirMeta.exportAs),
19884 isComponent: !!nonNormalizedTemplateMetadata,
19885 type: this._getTypeMetadata(directiveType),
19886 template: nonNormalizedTemplateMetadata,
19887 changeDetection: changeDetectionStrategy,
19888 inputs: dirMeta.inputs || [],
19889 outputs: dirMeta.outputs || [],
19890 host: dirMeta.host || {},
19891 providers: providers || [],
19892 viewProviders: viewProviders || [],
19893 queries: queries || [],
19894 guards: dirMeta.guards || {},
19895 viewQueries: viewQueries || [],
19896 entryComponents: entryComponentMetadata,
19897 componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
19898 null,
19899 rendererType: nonNormalizedTemplateMetadata ? this.getRendererType(directiveType) : null,
19900 componentFactory: null
19901 });
19902 if (nonNormalizedTemplateMetadata) {
19903 metadata.componentFactory =
19904 this.getComponentFactory(selector, directiveType, metadata.inputs, metadata.outputs);
19905 }
19906 cacheEntry = { metadata, annotation: dirMeta };
19907 this._nonNormalizedDirectiveCache.set(directiveType, cacheEntry);
19908 return cacheEntry;
19909 }
19910 /**
19911 * Gets the metadata for the given directive.
19912 * This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
19913 */
19914 getDirectiveMetadata(directiveType) {
19915 const dirMeta = this._directiveCache.get(directiveType);
19916 if (!dirMeta) {
19917 this._reportError(syntaxError(`Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${stringifyType(directiveType)}.`), directiveType);
19918 }
19919 return dirMeta;
19920 }
19921 getDirectiveSummary(dirType) {
19922 const dirSummary = this._loadSummary(dirType, CompileSummaryKind.Directive);
19923 if (!dirSummary) {
19924 this._reportError(syntaxError(`Illegal state: Could not load the summary for directive ${stringifyType(dirType)}.`), dirType);
19925 }
19926 return dirSummary;
19927 }
19928 isDirective(type) {
19929 return !!this._loadSummary(type, CompileSummaryKind.Directive) ||
19930 this._directiveResolver.isDirective(type);
19931 }
19932 isAbstractDirective(type) {
19933 const summary = this._loadSummary(type, CompileSummaryKind.Directive);
19934 if (summary && !summary.isComponent) {
19935 return !summary.selector;
19936 }
19937 const meta = this._directiveResolver.resolve(type, false);
19938 if (meta && !createComponent.isTypeOf(meta)) {
19939 return !meta.selector;
19940 }
19941 return false;
19942 }
19943 isPipe(type) {
19944 return !!this._loadSummary(type, CompileSummaryKind.Pipe) ||
19945 this._pipeResolver.isPipe(type);
19946 }
19947 isNgModule(type) {
19948 return !!this._loadSummary(type, CompileSummaryKind.NgModule) ||
19949 this._ngModuleResolver.isNgModule(type);
19950 }
19951 getNgModuleSummary(moduleType, alreadyCollecting = null) {
19952 let moduleSummary = this._loadSummary(moduleType, CompileSummaryKind.NgModule);
19953 if (!moduleSummary) {
19954 const moduleMeta = this.getNgModuleMetadata(moduleType, false, alreadyCollecting);
19955 moduleSummary = moduleMeta ? moduleMeta.toSummary() : null;
19956 if (moduleSummary) {
19957 this._summaryCache.set(moduleType, moduleSummary);
19958 }
19959 }
19960 return moduleSummary;
19961 }
19962 /**
19963 * Loads the declared directives and pipes of an NgModule.
19964 */
19965 loadNgModuleDirectiveAndPipeMetadata(moduleType, isSync, throwIfNotFound = true) {
19966 const ngModule = this.getNgModuleMetadata(moduleType, throwIfNotFound);
19967 const loading = [];
19968 if (ngModule) {
19969 ngModule.declaredDirectives.forEach((id) => {
19970 const promise = this.loadDirectiveMetadata(moduleType, id.reference, isSync);
19971 if (promise) {
19972 loading.push(promise);
19973 }
19974 });
19975 ngModule.declaredPipes.forEach((id) => this._loadPipeMetadata(id.reference));
19976 }
19977 return Promise.all(loading);
19978 }
19979 getShallowModuleMetadata(moduleType) {
19980 let compileMeta = this._shallowModuleCache.get(moduleType);
19981 if (compileMeta) {
19982 return compileMeta;
19983 }
19984 const ngModuleMeta = findLast(this._reflector.shallowAnnotations(moduleType), createNgModule.isTypeOf);
19985 compileMeta = {
19986 type: this._getTypeMetadata(moduleType),
19987 rawExports: ngModuleMeta.exports,
19988 rawImports: ngModuleMeta.imports,
19989 rawProviders: ngModuleMeta.providers,
19990 };
19991 this._shallowModuleCache.set(moduleType, compileMeta);
19992 return compileMeta;
19993 }
19994 getNgModuleMetadata(moduleType, throwIfNotFound = true, alreadyCollecting = null) {
19995 moduleType = resolveForwardRef(moduleType);
19996 let compileMeta = this._ngModuleCache.get(moduleType);
19997 if (compileMeta) {
19998 return compileMeta;
19999 }
20000 const meta = this._ngModuleResolver.resolve(moduleType, throwIfNotFound);
20001 if (!meta) {
20002 return null;
20003 }
20004 const declaredDirectives = [];
20005 const exportedNonModuleIdentifiers = [];
20006 const declaredPipes = [];
20007 const importedModules = [];
20008 const exportedModules = [];
20009 const providers = [];
20010 const entryComponents = [];
20011 const bootstrapComponents = [];
20012 const schemas = [];
20013 if (meta.imports) {
20014 flattenAndDedupeArray(meta.imports).forEach((importedType) => {
20015 let importedModuleType = undefined;
20016 if (isValidType(importedType)) {
20017 importedModuleType = importedType;
20018 }
20019 else if (importedType && importedType.ngModule) {
20020 const moduleWithProviders = importedType;
20021 importedModuleType = moduleWithProviders.ngModule;
20022 if (moduleWithProviders.providers) {
20023 providers.push(...this._getProvidersMetadata(moduleWithProviders.providers, entryComponents, `provider for the NgModule '${stringifyType(importedModuleType)}'`, [], importedType));
20024 }
20025 }
20026 if (importedModuleType) {
20027 if (this._checkSelfImport(moduleType, importedModuleType))
20028 return;
20029 if (!alreadyCollecting)
20030 alreadyCollecting = new Set();
20031 if (alreadyCollecting.has(importedModuleType)) {
20032 this._reportError(syntaxError(`${this._getTypeDescriptor(importedModuleType)} '${stringifyType(importedType)}' is imported recursively by the module '${stringifyType(moduleType)}'.`), moduleType);
20033 return;
20034 }
20035 alreadyCollecting.add(importedModuleType);
20036 const importedModuleSummary = this.getNgModuleSummary(importedModuleType, alreadyCollecting);
20037 alreadyCollecting.delete(importedModuleType);
20038 if (!importedModuleSummary) {
20039 this._reportError(syntaxError(`Unexpected ${this._getTypeDescriptor(importedType)} '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'. Please add a @NgModule annotation.`), moduleType);
20040 return;
20041 }
20042 importedModules.push(importedModuleSummary);
20043 }
20044 else {
20045 this._reportError(syntaxError(`Unexpected value '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'`), moduleType);
20046 return;
20047 }
20048 });
20049 }
20050 if (meta.exports) {
20051 flattenAndDedupeArray(meta.exports).forEach((exportedType) => {
20052 if (!isValidType(exportedType)) {
20053 this._reportError(syntaxError(`Unexpected value '${stringifyType(exportedType)}' exported by the module '${stringifyType(moduleType)}'`), moduleType);
20054 return;
20055 }
20056 if (!alreadyCollecting)
20057 alreadyCollecting = new Set();
20058 if (alreadyCollecting.has(exportedType)) {
20059 this._reportError(syntaxError(`${this._getTypeDescriptor(exportedType)} '${stringify(exportedType)}' is exported recursively by the module '${stringifyType(moduleType)}'`), moduleType);
20060 return;
20061 }
20062 alreadyCollecting.add(exportedType);
20063 const exportedModuleSummary = this.getNgModuleSummary(exportedType, alreadyCollecting);
20064 alreadyCollecting.delete(exportedType);
20065 if (exportedModuleSummary) {
20066 exportedModules.push(exportedModuleSummary);
20067 }
20068 else {
20069 exportedNonModuleIdentifiers.push(this._getIdentifierMetadata(exportedType));
20070 }
20071 });
20072 }
20073 // Note: This will be modified later, so we rely on
20074 // getting a new instance every time!
20075 const transitiveModule = this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
20076 if (meta.declarations) {
20077 flattenAndDedupeArray(meta.declarations).forEach((declaredType) => {
20078 if (!isValidType(declaredType)) {
20079 this._reportError(syntaxError(`Unexpected value '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'`), moduleType);
20080 return;
20081 }
20082 const declaredIdentifier = this._getIdentifierMetadata(declaredType);
20083 if (this.isDirective(declaredType)) {
20084 if (this.isAbstractDirective(declaredType)) {
20085 this._reportError(syntaxError(`Directive ${stringifyType(declaredType)} has no selector, please add it!`), declaredType);
20086 }
20087 transitiveModule.addDirective(declaredIdentifier);
20088 declaredDirectives.push(declaredIdentifier);
20089 this._addTypeToModule(declaredType, moduleType);
20090 }
20091 else if (this.isPipe(declaredType)) {
20092 transitiveModule.addPipe(declaredIdentifier);
20093 transitiveModule.pipes.push(declaredIdentifier);
20094 declaredPipes.push(declaredIdentifier);
20095 this._addTypeToModule(declaredType, moduleType);
20096 }
20097 else {
20098 this._reportError(syntaxError(`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`), moduleType);
20099 return;
20100 }
20101 });
20102 }
20103 const exportedDirectives = [];
20104 const exportedPipes = [];
20105 exportedNonModuleIdentifiers.forEach((exportedId) => {
20106 if (transitiveModule.directivesSet.has(exportedId.reference)) {
20107 exportedDirectives.push(exportedId);
20108 transitiveModule.addExportedDirective(exportedId);
20109 }
20110 else if (transitiveModule.pipesSet.has(exportedId.reference)) {
20111 exportedPipes.push(exportedId);
20112 transitiveModule.addExportedPipe(exportedId);
20113 }
20114 else {
20115 this._reportError(syntaxError(`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringifyType(exportedId.reference)} from ${stringifyType(moduleType)} as it was neither declared nor imported!`), moduleType);
20116 return;
20117 }
20118 });
20119 // The providers of the module have to go last
20120 // so that they overwrite any other provider we already added.
20121 if (meta.providers) {
20122 providers.push(...this._getProvidersMetadata(meta.providers, entryComponents, `provider for the NgModule '${stringifyType(moduleType)}'`, [], moduleType));
20123 }
20124 if (meta.entryComponents) {
20125 entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
20126 .map(type => this._getEntryComponentMetadata(type)));
20127 }
20128 if (meta.bootstrap) {
20129 flattenAndDedupeArray(meta.bootstrap).forEach(type => {
20130 if (!isValidType(type)) {
20131 this._reportError(syntaxError(`Unexpected value '${stringifyType(type)}' used in the bootstrap property of module '${stringifyType(moduleType)}'`), moduleType);
20132 return;
20133 }
20134 bootstrapComponents.push(this._getIdentifierMetadata(type));
20135 });
20136 }
20137 entryComponents.push(...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference)));
20138 if (meta.schemas) {
20139 schemas.push(...flattenAndDedupeArray(meta.schemas));
20140 }
20141 compileMeta = new CompileNgModuleMetadata({
20142 type: this._getTypeMetadata(moduleType),
20143 providers,
20144 entryComponents,
20145 bootstrapComponents,
20146 schemas,
20147 declaredDirectives,
20148 exportedDirectives,
20149 declaredPipes,
20150 exportedPipes,
20151 importedModules,
20152 exportedModules,
20153 transitiveModule,
20154 id: meta.id || null,
20155 });
20156 entryComponents.forEach((id) => transitiveModule.addEntryComponent(id));
20157 providers.forEach((provider) => transitiveModule.addProvider(provider, compileMeta.type));
20158 transitiveModule.addModule(compileMeta.type);
20159 this._ngModuleCache.set(moduleType, compileMeta);
20160 return compileMeta;
20161 }
20162 _checkSelfImport(moduleType, importedModuleType) {
20163 if (moduleType === importedModuleType) {
20164 this._reportError(syntaxError(`'${stringifyType(moduleType)}' module can't import itself`), moduleType);
20165 return true;
20166 }
20167 return false;
20168 }
20169 _getTypeDescriptor(type) {
20170 if (isValidType(type)) {
20171 if (this.isDirective(type)) {
20172 return 'directive';
20173 }
20174 if (this.isPipe(type)) {
20175 return 'pipe';
20176 }
20177 if (this.isNgModule(type)) {
20178 return 'module';
20179 }
20180 }
20181 if (type.provide) {
20182 return 'provider';
20183 }
20184 return 'value';
20185 }
20186 _addTypeToModule(type, moduleType) {
20187 const oldModule = this._ngModuleOfTypes.get(type);
20188 if (oldModule && oldModule !== moduleType) {
20189 this._reportError(syntaxError(`Type ${stringifyType(type)} is part of the declarations of 2 modules: ${stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` +
20190 `Please consider moving ${stringifyType(type)} to a higher module that imports ${stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` +
20191 `You can also create a new NgModule that exports and includes ${stringifyType(type)} then import that NgModule in ${stringifyType(oldModule)} and ${stringifyType(moduleType)}.`), moduleType);
20192 return;
20193 }
20194 this._ngModuleOfTypes.set(type, moduleType);
20195 }
20196 _getTransitiveNgModuleMetadata(importedModules, exportedModules) {
20197 // collect `providers` / `entryComponents` from all imported and all exported modules
20198 const result = new TransitiveCompileNgModuleMetadata();
20199 const modulesByToken = new Map();
20200 importedModules.concat(exportedModules).forEach((modSummary) => {
20201 modSummary.modules.forEach((mod) => result.addModule(mod));
20202 modSummary.entryComponents.forEach((comp) => result.addEntryComponent(comp));
20203 const addedTokens = new Set();
20204 modSummary.providers.forEach((entry) => {
20205 const tokenRef = tokenReference(entry.provider.token);
20206 let prevModules = modulesByToken.get(tokenRef);
20207 if (!prevModules) {
20208 prevModules = new Set();
20209 modulesByToken.set(tokenRef, prevModules);
20210 }
20211 const moduleRef = entry.module.reference;
20212 // Note: the providers of one module may still contain multiple providers
20213 // per token (e.g. for multi providers), and we need to preserve these.
20214 if (addedTokens.has(tokenRef) || !prevModules.has(moduleRef)) {
20215 prevModules.add(moduleRef);
20216 addedTokens.add(tokenRef);
20217 result.addProvider(entry.provider, entry.module);
20218 }
20219 });
20220 });
20221 exportedModules.forEach((modSummary) => {
20222 modSummary.exportedDirectives.forEach((id) => result.addExportedDirective(id));
20223 modSummary.exportedPipes.forEach((id) => result.addExportedPipe(id));
20224 });
20225 importedModules.forEach((modSummary) => {
20226 modSummary.exportedDirectives.forEach((id) => result.addDirective(id));
20227 modSummary.exportedPipes.forEach((id) => result.addPipe(id));
20228 });
20229 return result;
20230 }
20231 _getIdentifierMetadata(type) {
20232 type = resolveForwardRef(type);
20233 return { reference: type };
20234 }
20235 isInjectable(type) {
20236 const annotations = this._reflector.tryAnnotations(type);
20237 return annotations.some(ann => createInjectable.isTypeOf(ann));
20238 }
20239 getInjectableSummary(type) {
20240 return {
20241 summaryKind: CompileSummaryKind.Injectable,
20242 type: this._getTypeMetadata(type, null, false)
20243 };
20244 }
20245 getInjectableMetadata(type, dependencies = null, throwOnUnknownDeps = true) {
20246 const typeSummary = this._loadSummary(type, CompileSummaryKind.Injectable);
20247 const typeMetadata = typeSummary ?
20248 typeSummary.type :
20249 this._getTypeMetadata(type, dependencies, throwOnUnknownDeps);
20250 const annotations = this._reflector.annotations(type).filter(ann => createInjectable.isTypeOf(ann));
20251 if (annotations.length === 0) {
20252 return null;
20253 }
20254 const meta = annotations[annotations.length - 1];
20255 return {
20256 symbol: type,
20257 type: typeMetadata,
20258 providedIn: meta.providedIn,
20259 useValue: meta.useValue,
20260 useClass: meta.useClass,
20261 useExisting: meta.useExisting,
20262 useFactory: meta.useFactory,
20263 deps: meta.deps,
20264 };
20265 }
20266 _getTypeMetadata(type, dependencies = null, throwOnUnknownDeps = true) {
20267 const identifier = this._getIdentifierMetadata(type);
20268 return {
20269 reference: identifier.reference,
20270 diDeps: this._getDependenciesMetadata(identifier.reference, dependencies, throwOnUnknownDeps),
20271 lifecycleHooks: getAllLifecycleHooks(this._reflector, identifier.reference),
20272 };
20273 }
20274 _getFactoryMetadata(factory, dependencies = null) {
20275 factory = resolveForwardRef(factory);
20276 return { reference: factory, diDeps: this._getDependenciesMetadata(factory, dependencies) };
20277 }
20278 /**
20279 * Gets the metadata for the given pipe.
20280 * This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
20281 */
20282 getPipeMetadata(pipeType) {
20283 const pipeMeta = this._pipeCache.get(pipeType);
20284 if (!pipeMeta) {
20285 this._reportError(syntaxError(`Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${stringifyType(pipeType)}.`), pipeType);
20286 }
20287 return pipeMeta || null;
20288 }
20289 getPipeSummary(pipeType) {
20290 const pipeSummary = this._loadSummary(pipeType, CompileSummaryKind.Pipe);
20291 if (!pipeSummary) {
20292 this._reportError(syntaxError(`Illegal state: Could not load the summary for pipe ${stringifyType(pipeType)}.`), pipeType);
20293 }
20294 return pipeSummary;
20295 }
20296 getOrLoadPipeMetadata(pipeType) {
20297 let pipeMeta = this._pipeCache.get(pipeType);
20298 if (!pipeMeta) {
20299 pipeMeta = this._loadPipeMetadata(pipeType);
20300 }
20301 return pipeMeta;
20302 }
20303 _loadPipeMetadata(pipeType) {
20304 pipeType = resolveForwardRef(pipeType);
20305 const pipeAnnotation = this._pipeResolver.resolve(pipeType);
20306 const pipeMeta = new CompilePipeMetadata({
20307 type: this._getTypeMetadata(pipeType),
20308 name: pipeAnnotation.name,
20309 pure: !!pipeAnnotation.pure
20310 });
20311 this._pipeCache.set(pipeType, pipeMeta);
20312 this._summaryCache.set(pipeType, pipeMeta.toSummary());
20313 return pipeMeta;
20314 }
20315 _getDependenciesMetadata(typeOrFunc, dependencies, throwOnUnknownDeps = true) {
20316 let hasUnknownDeps = false;
20317 const params = dependencies || this._reflector.parameters(typeOrFunc) || [];
20318 const dependenciesMetadata = params.map((param) => {
20319 let isAttribute = false;
20320 let isHost = false;
20321 let isSelf = false;
20322 let isSkipSelf = false;
20323 let isOptional = false;
20324 let token = null;
20325 if (Array.isArray(param)) {
20326 param.forEach((paramEntry) => {
20327 if (createHost.isTypeOf(paramEntry)) {
20328 isHost = true;
20329 }
20330 else if (createSelf.isTypeOf(paramEntry)) {
20331 isSelf = true;
20332 }
20333 else if (createSkipSelf.isTypeOf(paramEntry)) {
20334 isSkipSelf = true;
20335 }
20336 else if (createOptional.isTypeOf(paramEntry)) {
20337 isOptional = true;
20338 }
20339 else if (createAttribute.isTypeOf(paramEntry)) {
20340 isAttribute = true;
20341 token = paramEntry.attributeName;
20342 }
20343 else if (createInject.isTypeOf(paramEntry)) {
20344 token = paramEntry.token;
20345 }
20346 else if (createInjectionToken.isTypeOf(paramEntry) ||
20347 paramEntry instanceof StaticSymbol) {
20348 token = paramEntry;
20349 }
20350 else if (isValidType(paramEntry) && token == null) {
20351 token = paramEntry;
20352 }
20353 });
20354 }
20355 else {
20356 token = param;
20357 }
20358 if (token == null) {
20359 hasUnknownDeps = true;
20360 return {};
20361 }
20362 return {
20363 isAttribute,
20364 isHost,
20365 isSelf,
20366 isSkipSelf,
20367 isOptional,
20368 token: this._getTokenMetadata(token)
20369 };
20370 });
20371 if (hasUnknownDeps) {
20372 const depsTokens = dependenciesMetadata.map((dep) => dep.token ? stringifyType(dep.token) : '?').join(', ');
20373 const message = `Can't resolve all parameters for ${stringifyType(typeOrFunc)}: (${depsTokens}).`;
20374 if (throwOnUnknownDeps || this._config.strictInjectionParameters) {
20375 this._reportError(syntaxError(message), typeOrFunc);
20376 }
20377 }
20378 return dependenciesMetadata;
20379 }
20380 _getTokenMetadata(token) {
20381 token = resolveForwardRef(token);
20382 let compileToken;
20383 if (typeof token === 'string') {
20384 compileToken = { value: token };
20385 }
20386 else {
20387 compileToken = { identifier: { reference: token } };
20388 }
20389 return compileToken;
20390 }
20391 _getProvidersMetadata(providers, targetEntryComponents, debugInfo, compileProviders = [], type) {
20392 providers.forEach((provider, providerIdx) => {
20393 if (Array.isArray(provider)) {
20394 this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
20395 }
20396 else {
20397 provider = resolveForwardRef(provider);
20398 let providerMeta = undefined;
20399 if (provider && typeof provider === 'object' && provider.hasOwnProperty('provide')) {
20400 this._validateProvider(provider);
20401 providerMeta = new ProviderMeta(provider.provide, provider);
20402 }
20403 else if (isValidType(provider)) {
20404 providerMeta = new ProviderMeta(provider, { useClass: provider });
20405 }
20406 else if (provider === void 0) {
20407 this._reportError(syntaxError(`Encountered undefined provider! Usually this means you have a circular dependencies. This might be caused by using 'barrel' index.ts files.`));
20408 return;
20409 }
20410 else {
20411 const providersInfo = providers
20412 .reduce((soFar, seenProvider, seenProviderIdx) => {
20413 if (seenProviderIdx < providerIdx) {
20414 soFar.push(`${stringifyType(seenProvider)}`);
20415 }
20416 else if (seenProviderIdx == providerIdx) {
20417 soFar.push(`?${stringifyType(seenProvider)}?`);
20418 }
20419 else if (seenProviderIdx == providerIdx + 1) {
20420 soFar.push('...');
20421 }
20422 return soFar;
20423 }, [])
20424 .join(', ');
20425 this._reportError(syntaxError(`Invalid ${debugInfo ?
20426 debugInfo :
20427 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`), type);
20428 return;
20429 }
20430 if (providerMeta.token ===
20431 this._reflector.resolveExternalReference(Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS)) {
20432 targetEntryComponents.push(...this._getEntryComponentsFromProvider(providerMeta, type));
20433 }
20434 else {
20435 compileProviders.push(this.getProviderMetadata(providerMeta));
20436 }
20437 }
20438 });
20439 return compileProviders;
20440 }
20441 _validateProvider(provider) {
20442 if (provider.hasOwnProperty('useClass') && provider.useClass == null) {
20443 this._reportError(syntaxError(`Invalid provider for ${stringifyType(provider.provide)}. useClass cannot be ${provider.useClass}.
20444 Usually it happens when:
20445 1. There's a circular dependency (might be caused by using index.ts (barrel) files).
20446 2. Class was used before it was declared. Use forwardRef in this case.`));
20447 }
20448 }
20449 _getEntryComponentsFromProvider(provider, type) {
20450 const components = [];
20451 const collectedIdentifiers = [];
20452 if (provider.useFactory || provider.useExisting || provider.useClass) {
20453 this._reportError(syntaxError(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!`), type);
20454 return [];
20455 }
20456 if (!provider.multi) {
20457 this._reportError(syntaxError(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!`), type);
20458 return [];
20459 }
20460 extractIdentifiers(provider.useValue, collectedIdentifiers);
20461 collectedIdentifiers.forEach((identifier) => {
20462 const entry = this._getEntryComponentMetadata(identifier.reference, false);
20463 if (entry) {
20464 components.push(entry);
20465 }
20466 });
20467 return components;
20468 }
20469 _getEntryComponentMetadata(dirType, throwIfNotFound = true) {
20470 const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
20471 if (dirMeta && dirMeta.metadata.isComponent) {
20472 return { componentType: dirType, componentFactory: dirMeta.metadata.componentFactory };
20473 }
20474 const dirSummary = this._loadSummary(dirType, CompileSummaryKind.Directive);
20475 if (dirSummary && dirSummary.isComponent) {
20476 return { componentType: dirType, componentFactory: dirSummary.componentFactory };
20477 }
20478 if (throwIfNotFound) {
20479 throw syntaxError(`${dirType.name} cannot be used as an entry component.`);
20480 }
20481 return null;
20482 }
20483 _getInjectableTypeMetadata(type, dependencies = null) {
20484 const typeSummary = this._loadSummary(type, CompileSummaryKind.Injectable);
20485 if (typeSummary) {
20486 return typeSummary.type;
20487 }
20488 return this._getTypeMetadata(type, dependencies);
20489 }
20490 getProviderMetadata(provider) {
20491 let compileDeps = undefined;
20492 let compileTypeMetadata = null;
20493 let compileFactoryMetadata = null;
20494 let token = this._getTokenMetadata(provider.token);
20495 if (provider.useClass) {
20496 compileTypeMetadata =
20497 this._getInjectableTypeMetadata(provider.useClass, provider.dependencies);
20498 compileDeps = compileTypeMetadata.diDeps;
20499 if (provider.token === provider.useClass) {
20500 // use the compileTypeMetadata as it contains information about lifecycleHooks...
20501 token = { identifier: compileTypeMetadata };
20502 }
20503 }
20504 else if (provider.useFactory) {
20505 compileFactoryMetadata = this._getFactoryMetadata(provider.useFactory, provider.dependencies);
20506 compileDeps = compileFactoryMetadata.diDeps;
20507 }
20508 return {
20509 token: token,
20510 useClass: compileTypeMetadata,
20511 useValue: provider.useValue,
20512 useFactory: compileFactoryMetadata,
20513 useExisting: provider.useExisting ? this._getTokenMetadata(provider.useExisting) : undefined,
20514 deps: compileDeps,
20515 multi: provider.multi
20516 };
20517 }
20518 _getQueriesMetadata(queries, isViewQuery, directiveType) {
20519 const res = [];
20520 Object.keys(queries).forEach((propertyName) => {
20521 const query = queries[propertyName];
20522 if (query.isViewQuery === isViewQuery) {
20523 res.push(this._getQueryMetadata(query, propertyName, directiveType));
20524 }
20525 });
20526 return res;
20527 }
20528 _queryVarBindings(selector) {
20529 return selector.split(/\s*,\s*/);
20530 }
20531 _getQueryMetadata(q, propertyName, typeOrFunc) {
20532 let selectors;
20533 if (typeof q.selector === 'string') {
20534 selectors =
20535 this._queryVarBindings(q.selector).map(varName => this._getTokenMetadata(varName));
20536 }
20537 else {
20538 if (!q.selector) {
20539 this._reportError(syntaxError(`Can't construct a query for the property "${propertyName}" of "${stringifyType(typeOrFunc)}" since the query selector wasn't defined.`), typeOrFunc);
20540 selectors = [];
20541 }
20542 else {
20543 selectors = [this._getTokenMetadata(q.selector)];
20544 }
20545 }
20546 return {
20547 selectors,
20548 first: q.first,
20549 descendants: q.descendants,
20550 emitDistinctChangesOnly: q.emitDistinctChangesOnly,
20551 propertyName,
20552 read: q.read ? this._getTokenMetadata(q.read) : null,
20553 static: q.static
20554 };
20555 }
20556 _reportError(error, type, otherType) {
20557 if (this._errorCollector) {
20558 this._errorCollector(error, type);
20559 if (otherType) {
20560 this._errorCollector(error, otherType);
20561 }
20562 }
20563 else {
20564 throw error;
20565 }
20566 }
20567 }
20568 function flattenArray(tree, out = []) {
20569 if (tree) {
20570 for (let i = 0; i < tree.length; i++) {
20571 const item = resolveForwardRef(tree[i]);
20572 if (Array.isArray(item)) {
20573 flattenArray(item, out);
20574 }
20575 else {
20576 out.push(item);
20577 }
20578 }
20579 }
20580 return out;
20581 }
20582 function dedupeArray(array) {
20583 if (array) {
20584 return Array.from(new Set(array));
20585 }
20586 return [];
20587 }
20588 function flattenAndDedupeArray(tree) {
20589 return dedupeArray(flattenArray(tree));
20590 }
20591 function isValidType(value) {
20592 return (value instanceof StaticSymbol) || (value instanceof Type);
20593 }
20594 function extractIdentifiers(value, targetIdentifiers) {
20595 visitValue(value, new _CompileValueConverter(), targetIdentifiers);
20596 }
20597 class _CompileValueConverter extends ValueTransformer {
20598 visitOther(value, targetIdentifiers) {
20599 targetIdentifiers.push({ reference: value });
20600 }
20601 }
20602 function stringifyType(type) {
20603 if (type instanceof StaticSymbol) {
20604 return `${type.name} in ${type.filePath}`;
20605 }
20606 else {
20607 return stringify(type);
20608 }
20609 }
20610 /**
20611 * Indicates that a component is still being loaded in a synchronous compile.
20612 */
20613 function componentStillLoadingError(compType) {
20614 const error = Error(`Can't compile synchronously as ${stringify(compType)} is still being loaded!`);
20615 error[ERROR_COMPONENT_TYPE] = compType;
20616 return error;
20617 }
20618
20619 /**
20620 * @license
20621 * Copyright Google LLC All Rights Reserved.
20622 *
20623 * Use of this source code is governed by an MIT-style license that can be
20624 * found in the LICENSE file at https://angular.io/license
20625 */
20626 const LOG_VAR = variable('_l');
20627
20628 /**
20629 * @license
20630 * Copyright Google LLC All Rights Reserved.
20631 *
20632 * Use of this source code is governed by an MIT-style license that can be
20633 * found in the LICENSE file at https://angular.io/license
20634 */
20635 /**
20636 * Resolves types to {@link NgModule}.
20637 */
20638 class NgModuleResolver {
20639 constructor(_reflector) {
20640 this._reflector = _reflector;
20641 }
20642 isNgModule(type) {
20643 return this._reflector.annotations(type).some(createNgModule.isTypeOf);
20644 }
20645 resolve(type, throwIfNotFound = true) {
20646 const ngModuleMeta = findLast(this._reflector.annotations(type), createNgModule.isTypeOf);
20647 if (ngModuleMeta) {
20648 return ngModuleMeta;
20649 }
20650 else {
20651 if (throwIfNotFound) {
20652 throw new Error(`No NgModule metadata found for '${stringify(type)}'.`);
20653 }
20654 return null;
20655 }
20656 }
20657 }
20658
20659 /**
20660 * @license
20661 * Copyright Google LLC All Rights Reserved.
20662 *
20663 * Use of this source code is governed by an MIT-style license that can be
20664 * found in the LICENSE file at https://angular.io/license
20665 */
20666 /**
20667 * Resolve a `Type` for {@link Pipe}.
20668 *
20669 * This interface can be overridden by the application developer to create custom behavior.
20670 *
20671 * See {@link Compiler}
20672 */
20673 class PipeResolver {
20674 constructor(_reflector) {
20675 this._reflector = _reflector;
20676 }
20677 isPipe(type) {
20678 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
20679 return typeMetadata && typeMetadata.some(createPipe.isTypeOf);
20680 }
20681 /**
20682 * Return {@link Pipe} for a given `Type`.
20683 */
20684 resolve(type, throwIfNotFound = true) {
20685 const metas = this._reflector.annotations(resolveForwardRef(type));
20686 if (metas) {
20687 const annotation = findLast(metas, createPipe.isTypeOf);
20688 if (annotation) {
20689 return annotation;
20690 }
20691 }
20692 if (throwIfNotFound) {
20693 throw new Error(`No Pipe decorator found on ${stringify(type)}`);
20694 }
20695 return null;
20696 }
20697 }
20698
20699 /**
20700 * @license
20701 * Copyright Google LLC All Rights Reserved.
20702 *
20703 * Use of this source code is governed by an MIT-style license that can be
20704 * found in the LICENSE file at https://angular.io/license
20705 */
20706 const LOG_VAR$1 = variable('_l');
20707 const VIEW_VAR = variable('_v');
20708 const CHECK_VAR = variable('_ck');
20709 const COMP_VAR = variable('_co');
20710 const EVENT_NAME_VAR = variable('en');
20711 const ALLOW_DEFAULT_VAR = variable(`ad`);
20712
20713 /**
20714 * @license
20715 * Copyright Google LLC All Rights Reserved.
20716 *
20717 * Use of this source code is governed by an MIT-style license that can be
20718 * found in the LICENSE file at https://angular.io/license
20719 */
20720 const TS = /^(?!.*\.d\.ts$).*\.ts$/;
20721 class ResolvedStaticSymbol {
20722 constructor(symbol, metadata) {
20723 this.symbol = symbol;
20724 this.metadata = metadata;
20725 }
20726 }
20727 const SUPPORTED_SCHEMA_VERSION = 4;
20728 /**
20729 * This class is responsible for loading metadata per symbol,
20730 * and normalizing references between symbols.
20731 *
20732 * Internally, it only uses symbols without members,
20733 * and deduces the values for symbols with members based
20734 * on these symbols.
20735 */
20736 class StaticSymbolResolver {
20737 constructor(host, staticSymbolCache, summaryResolver, errorRecorder) {
20738 this.host = host;
20739 this.staticSymbolCache = staticSymbolCache;
20740 this.summaryResolver = summaryResolver;
20741 this.errorRecorder = errorRecorder;
20742 this.metadataCache = new Map();
20743 // Note: this will only contain StaticSymbols without members!
20744 this.resolvedSymbols = new Map();
20745 // Note: this will only contain StaticSymbols without members!
20746 this.importAs = new Map();
20747 this.symbolResourcePaths = new Map();
20748 this.symbolFromFile = new Map();
20749 this.knownFileNameToModuleNames = new Map();
20750 }
20751 resolveSymbol(staticSymbol) {
20752 if (staticSymbol.members.length > 0) {
20753 return this._resolveSymbolMembers(staticSymbol);
20754 }
20755 // Note: always ask for a summary first,
20756 // as we might have read shallow metadata via a .d.ts file
20757 // for the symbol.
20758 const resultFromSummary = this._resolveSymbolFromSummary(staticSymbol);
20759 if (resultFromSummary) {
20760 return resultFromSummary;
20761 }
20762 const resultFromCache = this.resolvedSymbols.get(staticSymbol);
20763 if (resultFromCache) {
20764 return resultFromCache;
20765 }
20766 // Note: Some users use libraries that were not compiled with ngc, i.e. they don't
20767 // have summaries, only .d.ts files. So we always need to check both, the summary
20768 // and metadata.
20769 this._createSymbolsOf(staticSymbol.filePath);
20770 return this.resolvedSymbols.get(staticSymbol);
20771 }
20772 /**
20773 * getImportAs produces a symbol that can be used to import the given symbol.
20774 * The import might be different than the symbol if the symbol is exported from
20775 * a library with a summary; in which case we want to import the symbol from the
20776 * ngfactory re-export instead of directly to avoid introducing a direct dependency
20777 * on an otherwise indirect dependency.
20778 *
20779 * @param staticSymbol the symbol for which to generate a import symbol
20780 */
20781 getImportAs(staticSymbol, useSummaries = true) {
20782 if (staticSymbol.members.length) {
20783 const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
20784 const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
20785 return baseImportAs ?
20786 this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
20787 null;
20788 }
20789 const summarizedFileName = stripSummaryForJitFileSuffix(staticSymbol.filePath);
20790 if (summarizedFileName !== staticSymbol.filePath) {
20791 const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
20792 const baseSymbol = this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
20793 const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
20794 return baseImportAs ? this.getStaticSymbol(summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name), baseSymbol.members) :
20795 null;
20796 }
20797 let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
20798 if (!result) {
20799 result = this.importAs.get(staticSymbol);
20800 }
20801 return result;
20802 }
20803 /**
20804 * getResourcePath produces the path to the original location of the symbol and should
20805 * be used to determine the relative location of resource references recorded in
20806 * symbol metadata.
20807 */
20808 getResourcePath(staticSymbol) {
20809 return this.symbolResourcePaths.get(staticSymbol) || staticSymbol.filePath;
20810 }
20811 /**
20812 * getTypeArity returns the number of generic type parameters the given symbol
20813 * has. If the symbol is not a type the result is null.
20814 */
20815 getTypeArity(staticSymbol) {
20816 // If the file is a factory/ngsummary file, don't resolve the symbol as doing so would
20817 // cause the metadata for an factory/ngsummary file to be loaded which doesn't exist.
20818 // All references to generated classes must include the correct arity whenever
20819 // generating code.
20820 if (isGeneratedFile(staticSymbol.filePath)) {
20821 return null;
20822 }
20823 let resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(staticSymbol));
20824 while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
20825 resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(resolvedSymbol.metadata));
20826 }
20827 return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
20828 }
20829 getKnownModuleName(filePath) {
20830 return this.knownFileNameToModuleNames.get(filePath) || null;
20831 }
20832 recordImportAs(sourceSymbol, targetSymbol) {
20833 sourceSymbol.assertNoMembers();
20834 targetSymbol.assertNoMembers();
20835 this.importAs.set(sourceSymbol, targetSymbol);
20836 }
20837 recordModuleNameForFileName(fileName, moduleName) {
20838 this.knownFileNameToModuleNames.set(fileName, moduleName);
20839 }
20840 /**
20841 * Invalidate all information derived from the given file and return the
20842 * static symbols contained in the file.
20843 *
20844 * @param fileName the file to invalidate
20845 */
20846 invalidateFile(fileName) {
20847 this.metadataCache.delete(fileName);
20848 const symbols = this.symbolFromFile.get(fileName);
20849 if (!symbols) {
20850 return [];
20851 }
20852 this.symbolFromFile.delete(fileName);
20853 for (const symbol of symbols) {
20854 this.resolvedSymbols.delete(symbol);
20855 this.importAs.delete(symbol);
20856 this.symbolResourcePaths.delete(symbol);
20857 }
20858 return symbols;
20859 }
20860 /** @internal */
20861 ignoreErrorsFor(cb) {
20862 const recorder = this.errorRecorder;
20863 this.errorRecorder = () => { };
20864 try {
20865 return cb();
20866 }
20867 finally {
20868 this.errorRecorder = recorder;
20869 }
20870 }
20871 _resolveSymbolMembers(staticSymbol) {
20872 const members = staticSymbol.members;
20873 const baseResolvedSymbol = this.resolveSymbol(this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name));
20874 if (!baseResolvedSymbol) {
20875 return null;
20876 }
20877 let baseMetadata = unwrapResolvedMetadata(baseResolvedSymbol.metadata);
20878 if (baseMetadata instanceof StaticSymbol) {
20879 return new ResolvedStaticSymbol(staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
20880 }
20881 else if (baseMetadata && baseMetadata.__symbolic === 'class') {
20882 if (baseMetadata.statics && members.length === 1) {
20883 return new ResolvedStaticSymbol(staticSymbol, baseMetadata.statics[members[0]]);
20884 }
20885 }
20886 else {
20887 let value = baseMetadata;
20888 for (let i = 0; i < members.length && value; i++) {
20889 value = value[members[i]];
20890 }
20891 return new ResolvedStaticSymbol(staticSymbol, value);
20892 }
20893 return null;
20894 }
20895 _resolveSymbolFromSummary(staticSymbol) {
20896 const summary = this.summaryResolver.resolveSummary(staticSymbol);
20897 return summary ? new ResolvedStaticSymbol(staticSymbol, summary.metadata) : null;
20898 }
20899 /**
20900 * getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
20901 * All types passed to the StaticResolver should be pseudo-types returned by this method.
20902 *
20903 * @param declarationFile the absolute path of the file where the symbol is declared
20904 * @param name the name of the type.
20905 * @param members a symbol for a static member of the named type
20906 */
20907 getStaticSymbol(declarationFile, name, members) {
20908 return this.staticSymbolCache.get(declarationFile, name, members);
20909 }
20910 /**
20911 * hasDecorators checks a file's metadata for the presence of decorators without evaluating the
20912 * metadata.
20913 *
20914 * @param filePath the absolute path to examine for decorators.
20915 * @returns true if any class in the file has a decorator.
20916 */
20917 hasDecorators(filePath) {
20918 const metadata = this.getModuleMetadata(filePath);
20919 if (metadata['metadata']) {
20920 return Object.keys(metadata['metadata']).some((metadataKey) => {
20921 const entry = metadata['metadata'][metadataKey];
20922 return entry && entry.__symbolic === 'class' && entry.decorators;
20923 });
20924 }
20925 return false;
20926 }
20927 getSymbolsOf(filePath) {
20928 const summarySymbols = this.summaryResolver.getSymbolsOf(filePath);
20929 if (summarySymbols) {
20930 return summarySymbols;
20931 }
20932 // Note: Some users use libraries that were not compiled with ngc, i.e. they don't
20933 // have summaries, only .d.ts files, but `summaryResolver.isLibraryFile` returns true.
20934 this._createSymbolsOf(filePath);
20935 return this.symbolFromFile.get(filePath) || [];
20936 }
20937 _createSymbolsOf(filePath) {
20938 if (this.symbolFromFile.has(filePath)) {
20939 return;
20940 }
20941 const resolvedSymbols = [];
20942 const metadata = this.getModuleMetadata(filePath);
20943 if (metadata['importAs']) {
20944 // Index bundle indices should use the importAs module name defined
20945 // in the bundle.
20946 this.knownFileNameToModuleNames.set(filePath, metadata['importAs']);
20947 }
20948 // handle the symbols in one of the re-export location
20949 if (metadata['exports']) {
20950 for (const moduleExport of metadata['exports']) {
20951 // handle the symbols in the list of explicitly re-exported symbols.
20952 if (moduleExport.export) {
20953 moduleExport.export.forEach((exportSymbol) => {
20954 let symbolName;
20955 if (typeof exportSymbol === 'string') {
20956 symbolName = exportSymbol;
20957 }
20958 else {
20959 symbolName = exportSymbol.as;
20960 }
20961 symbolName = unescapeIdentifier(symbolName);
20962 let symName = symbolName;
20963 if (typeof exportSymbol !== 'string') {
20964 symName = unescapeIdentifier(exportSymbol.name);
20965 }
20966 const resolvedModule = this.resolveModule(moduleExport.from, filePath);
20967 if (resolvedModule) {
20968 const targetSymbol = this.getStaticSymbol(resolvedModule, symName);
20969 const sourceSymbol = this.getStaticSymbol(filePath, symbolName);
20970 resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
20971 }
20972 });
20973 }
20974 else {
20975 // Handle the symbols loaded by 'export *' directives.
20976 const resolvedModule = this.resolveModule(moduleExport.from, filePath);
20977 if (resolvedModule && resolvedModule !== filePath) {
20978 const nestedExports = this.getSymbolsOf(resolvedModule);
20979 nestedExports.forEach((targetSymbol) => {
20980 const sourceSymbol = this.getStaticSymbol(filePath, targetSymbol.name);
20981 resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
20982 });
20983 }
20984 }
20985 }
20986 }
20987 // handle the actual metadata. Has to be after the exports
20988 // as there might be collisions in the names, and we want the symbols
20989 // of the current module to win ofter reexports.
20990 if (metadata['metadata']) {
20991 // handle direct declarations of the symbol
20992 const topLevelSymbolNames = new Set(Object.keys(metadata['metadata']).map(unescapeIdentifier));
20993 const origins = metadata['origins'] || {};
20994 Object.keys(metadata['metadata']).forEach((metadataKey) => {
20995 const symbolMeta = metadata['metadata'][metadataKey];
20996 const name = unescapeIdentifier(metadataKey);
20997 const symbol = this.getStaticSymbol(filePath, name);
20998 const origin = origins.hasOwnProperty(metadataKey) && origins[metadataKey];
20999 if (origin) {
21000 // If the symbol is from a bundled index, use the declaration location of the
21001 // symbol so relative references (such as './my.html') will be calculated
21002 // correctly.
21003 const originFilePath = this.resolveModule(origin, filePath);
21004 if (!originFilePath) {
21005 this.reportError(new Error(`Couldn't resolve original symbol for ${origin} from ${this.host.getOutputName(filePath)}`));
21006 }
21007 else {
21008 this.symbolResourcePaths.set(symbol, originFilePath);
21009 }
21010 }
21011 resolvedSymbols.push(this.createResolvedSymbol(symbol, filePath, topLevelSymbolNames, symbolMeta));
21012 });
21013 }
21014 const uniqueSymbols = new Set();
21015 for (const resolvedSymbol of resolvedSymbols) {
21016 this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol);
21017 uniqueSymbols.add(resolvedSymbol.symbol);
21018 }
21019 this.symbolFromFile.set(filePath, Array.from(uniqueSymbols));
21020 }
21021 createResolvedSymbol(sourceSymbol, topLevelPath, topLevelSymbolNames, metadata) {
21022 // For classes that don't have Angular summaries / metadata,
21023 // we only keep their arity, but nothing else
21024 // (e.g. their constructor parameters).
21025 // We do this to prevent introducing deep imports
21026 // as we didn't generate .ngfactory.ts files with proper reexports.
21027 const isTsFile = TS.test(sourceSymbol.filePath);
21028 if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) && !isTsFile && metadata &&
21029 metadata['__symbolic'] === 'class') {
21030 const transformedMeta = { __symbolic: 'class', arity: metadata.arity };
21031 return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
21032 }
21033 let _originalFileMemo;
21034 const getOriginalName = () => {
21035 if (!_originalFileMemo) {
21036 // Guess what the original file name is from the reference. If it has a `.d.ts` extension
21037 // replace it with `.ts`. If it already has `.ts` just leave it in place. If it doesn't have
21038 // .ts or .d.ts, append `.ts'. Also, if it is in `node_modules`, trim the `node_module`
21039 // location as it is not important to finding the file.
21040 _originalFileMemo =
21041 this.host.getOutputName(topLevelPath.replace(/((\.ts)|(\.d\.ts)|)$/, '.ts')
21042 .replace(/^.*node_modules[/\\]/, ''));
21043 }
21044 return _originalFileMemo;
21045 };
21046 const self = this;
21047 class ReferenceTransformer extends ValueTransformer {
21048 visitStringMap(map, functionParams) {
21049 const symbolic = map['__symbolic'];
21050 if (symbolic === 'function') {
21051 const oldLen = functionParams.length;
21052 functionParams.push(...(map['parameters'] || []));
21053 const result = super.visitStringMap(map, functionParams);
21054 functionParams.length = oldLen;
21055 return result;
21056 }
21057 else if (symbolic === 'reference') {
21058 const module = map['module'];
21059 const name = map['name'] ? unescapeIdentifier(map['name']) : map['name'];
21060 if (!name) {
21061 return null;
21062 }
21063 let filePath;
21064 if (module) {
21065 filePath = self.resolveModule(module, sourceSymbol.filePath);
21066 if (!filePath) {
21067 return {
21068 __symbolic: 'error',
21069 message: `Could not resolve ${module} relative to ${self.host.getMetadataFor(sourceSymbol.filePath)}.`,
21070 line: map['line'],
21071 character: map['character'],
21072 fileName: getOriginalName()
21073 };
21074 }
21075 return {
21076 __symbolic: 'resolved',
21077 symbol: self.getStaticSymbol(filePath, name),
21078 line: map['line'],
21079 character: map['character'],
21080 fileName: getOriginalName()
21081 };
21082 }
21083 else if (functionParams.indexOf(name) >= 0) {
21084 // reference to a function parameter
21085 return { __symbolic: 'reference', name: name };
21086 }
21087 else {
21088 if (topLevelSymbolNames.has(name)) {
21089 return self.getStaticSymbol(topLevelPath, name);
21090 }
21091 }
21092 }
21093 else if (symbolic === 'error') {
21094 return Object.assign(Object.assign({}, map), { fileName: getOriginalName() });
21095 }
21096 else {
21097 return super.visitStringMap(map, functionParams);
21098 }
21099 }
21100 }
21101 const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
21102 let unwrappedTransformedMeta = unwrapResolvedMetadata(transformedMeta);
21103 if (unwrappedTransformedMeta instanceof StaticSymbol) {
21104 return this.createExport(sourceSymbol, unwrappedTransformedMeta);
21105 }
21106 return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
21107 }
21108 createExport(sourceSymbol, targetSymbol) {
21109 sourceSymbol.assertNoMembers();
21110 targetSymbol.assertNoMembers();
21111 if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) &&
21112 this.summaryResolver.isLibraryFile(targetSymbol.filePath)) {
21113 // This case is for an ng library importing symbols from a plain ts library
21114 // transitively.
21115 // Note: We rely on the fact that we discover symbols in the direction
21116 // from source files to library files
21117 this.importAs.set(targetSymbol, this.getImportAs(sourceSymbol) || sourceSymbol);
21118 }
21119 return new ResolvedStaticSymbol(sourceSymbol, targetSymbol);
21120 }
21121 reportError(error, context, path) {
21122 if (this.errorRecorder) {
21123 this.errorRecorder(error, (context && context.filePath) || path);
21124 }
21125 else {
21126 throw error;
21127 }
21128 }
21129 /**
21130 * @param module an absolute path to a module file.
21131 */
21132 getModuleMetadata(module) {
21133 let moduleMetadata = this.metadataCache.get(module);
21134 if (!moduleMetadata) {
21135 const moduleMetadatas = this.host.getMetadataFor(module);
21136 if (moduleMetadatas) {
21137 let maxVersion = -1;
21138 moduleMetadatas.forEach((md) => {
21139 if (md && md['version'] > maxVersion) {
21140 maxVersion = md['version'];
21141 moduleMetadata = md;
21142 }
21143 });
21144 }
21145 if (!moduleMetadata) {
21146 moduleMetadata =
21147 { __symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {} };
21148 }
21149 if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
21150 const errorMessage = moduleMetadata['version'] == 2 ?
21151 `Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` :
21152 `Metadata version mismatch for module ${this.host.getOutputName(module)}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
21153 this.reportError(new Error(errorMessage));
21154 }
21155 this.metadataCache.set(module, moduleMetadata);
21156 }
21157 return moduleMetadata;
21158 }
21159 getSymbolByModule(module, symbolName, containingFile) {
21160 const filePath = this.resolveModule(module, containingFile);
21161 if (!filePath) {
21162 this.reportError(new Error(`Could not resolve module ${module}${containingFile ? ' relative to ' + this.host.getOutputName(containingFile) : ''}`));
21163 return this.getStaticSymbol(`ERROR:${module}`, symbolName);
21164 }
21165 return this.getStaticSymbol(filePath, symbolName);
21166 }
21167 resolveModule(module, containingFile) {
21168 try {
21169 return this.host.moduleNameToFileName(module, containingFile);
21170 }
21171 catch (e) {
21172 console.error(`Could not resolve module '${module}' relative to file ${containingFile}`);
21173 this.reportError(e, undefined, containingFile);
21174 }
21175 return null;
21176 }
21177 }
21178 // Remove extra underscore from escaped identifier.
21179 // See https://github.com/Microsoft/TypeScript/blob/master/src/compiler/utilities.ts
21180 function unescapeIdentifier(identifier) {
21181 return identifier.startsWith('___') ? identifier.substr(1) : identifier;
21182 }
21183 function unwrapResolvedMetadata(metadata) {
21184 if (metadata && metadata.__symbolic === 'resolved') {
21185 return metadata.symbol;
21186 }
21187 return metadata;
21188 }
21189
21190 /**
21191 * @license
21192 * Copyright Google LLC All Rights Reserved.
21193 *
21194 * Use of this source code is governed by an MIT-style license that can be
21195 * found in the LICENSE file at https://angular.io/license
21196 */
21197 function deserializeSummaries(symbolCache, summaryResolver, libraryFileName, json) {
21198 const deserializer = new FromJsonDeserializer(symbolCache, summaryResolver);
21199 return deserializer.deserialize(libraryFileName, json);
21200 }
21201 class FromJsonDeserializer extends ValueTransformer {
21202 constructor(symbolCache, summaryResolver) {
21203 super();
21204 this.symbolCache = symbolCache;
21205 this.summaryResolver = summaryResolver;
21206 }
21207 deserialize(libraryFileName, json) {
21208 const data = JSON.parse(json);
21209 const allImportAs = [];
21210 this.symbols = data.symbols.map((serializedSymbol) => this.symbolCache.get(this.summaryResolver.fromSummaryFileName(serializedSymbol.filePath, libraryFileName), serializedSymbol.name));
21211 data.symbols.forEach((serializedSymbol, index) => {
21212 const symbol = this.symbols[index];
21213 const importAs = serializedSymbol.importAs;
21214 if (typeof importAs === 'number') {
21215 allImportAs.push({ symbol, importAs: this.symbols[importAs] });
21216 }
21217 else if (typeof importAs === 'string') {
21218 allImportAs.push({ symbol, importAs: this.symbolCache.get(ngfactoryFilePath(libraryFileName), importAs) });
21219 }
21220 });
21221 const summaries = visitValue(data.summaries, this, null);
21222 return { moduleName: data.moduleName, summaries, importAs: allImportAs };
21223 }
21224 visitStringMap(map, context) {
21225 if ('__symbol' in map) {
21226 const baseSymbol = this.symbols[map['__symbol']];
21227 const members = map['members'];
21228 return members.length ? this.symbolCache.get(baseSymbol.filePath, baseSymbol.name, members) :
21229 baseSymbol;
21230 }
21231 else {
21232 return super.visitStringMap(map, context);
21233 }
21234 }
21235 }
21236
21237 /**
21238 * @license
21239 * Copyright Google LLC All Rights Reserved.
21240 *
21241 * Use of this source code is governed by an MIT-style license that can be
21242 * found in the LICENSE file at https://angular.io/license
21243 */
21244 function analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver) {
21245 const files = _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver);
21246 return mergeAnalyzedFiles(files);
21247 }
21248 // Analyzes all of the program files,
21249 // including files that are not part of the program
21250 // but are referenced by an NgModule.
21251 function _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver) {
21252 const seenFiles = new Set();
21253 const files = [];
21254 const visitFile = (fileName) => {
21255 if (seenFiles.has(fileName) || !host.isSourceFile(fileName)) {
21256 return false;
21257 }
21258 seenFiles.add(fileName);
21259 const analyzedFile = analyzeFile(host, staticSymbolResolver, metadataResolver, fileName);
21260 files.push(analyzedFile);
21261 analyzedFile.ngModules.forEach(ngModule => {
21262 ngModule.transitiveModule.modules.forEach(modMeta => visitFile(modMeta.reference.filePath));
21263 });
21264 };
21265 fileNames.forEach((fileName) => visitFile(fileName));
21266 return files;
21267 }
21268 function analyzeFile(host, staticSymbolResolver, metadataResolver, fileName) {
21269 const abstractDirectives = [];
21270 const directives = [];
21271 const pipes = [];
21272 const injectables = [];
21273 const ngModules = [];
21274 const hasDecorators = staticSymbolResolver.hasDecorators(fileName);
21275 let exportsNonSourceFiles = false;
21276 const isDeclarationFile = fileName.endsWith('.d.ts');
21277 // Don't analyze .d.ts files that have no decorators as a shortcut
21278 // to speed up the analysis. This prevents us from
21279 // resolving the references in these files.
21280 // Note: exportsNonSourceFiles is only needed when compiling with summaries,
21281 // which is not the case when .d.ts files are treated as input files.
21282 if (!isDeclarationFile || hasDecorators) {
21283 staticSymbolResolver.getSymbolsOf(fileName).forEach((symbol) => {
21284 const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
21285 const symbolMeta = resolvedSymbol.metadata;
21286 if (!symbolMeta || symbolMeta.__symbolic === 'error') {
21287 return;
21288 }
21289 let isNgSymbol = false;
21290 if (symbolMeta.__symbolic === 'class') {
21291 if (metadataResolver.isDirective(symbol)) {
21292 isNgSymbol = true;
21293 // This directive either has a selector or doesn't. Selector-less directives get tracked
21294 // in abstractDirectives, not directives. The compiler doesn't deal with selector-less
21295 // directives at all, really, other than to persist their metadata. This is done so that
21296 // apps will have an easier time migrating to Ivy, which requires the selector-less
21297 // annotations to be applied.
21298 if (!metadataResolver.isAbstractDirective(symbol)) {
21299 // The directive is an ordinary directive.
21300 directives.push(symbol);
21301 }
21302 else {
21303 // The directive has no selector and is an "abstract" directive, so track it
21304 // accordingly.
21305 abstractDirectives.push(symbol);
21306 }
21307 }
21308 else if (metadataResolver.isPipe(symbol)) {
21309 isNgSymbol = true;
21310 pipes.push(symbol);
21311 }
21312 else if (metadataResolver.isNgModule(symbol)) {
21313 const ngModule = metadataResolver.getNgModuleMetadata(symbol, false);
21314 if (ngModule) {
21315 isNgSymbol = true;
21316 ngModules.push(ngModule);
21317 }
21318 }
21319 else if (metadataResolver.isInjectable(symbol)) {
21320 isNgSymbol = true;
21321 const injectable = metadataResolver.getInjectableMetadata(symbol, null, false);
21322 if (injectable) {
21323 injectables.push(injectable);
21324 }
21325 }
21326 }
21327 if (!isNgSymbol) {
21328 exportsNonSourceFiles =
21329 exportsNonSourceFiles || isValueExportingNonSourceFile(host, symbolMeta);
21330 }
21331 });
21332 }
21333 return {
21334 fileName,
21335 directives,
21336 abstractDirectives,
21337 pipes,
21338 ngModules,
21339 injectables,
21340 exportsNonSourceFiles,
21341 };
21342 }
21343 function isValueExportingNonSourceFile(host, metadata) {
21344 let exportsNonSourceFiles = false;
21345 class Visitor {
21346 visitArray(arr, context) {
21347 arr.forEach(v => visitValue(v, this, context));
21348 }
21349 visitStringMap(map, context) {
21350 Object.keys(map).forEach((key) => visitValue(map[key], this, context));
21351 }
21352 visitPrimitive(value, context) { }
21353 visitOther(value, context) {
21354 if (value instanceof StaticSymbol && !host.isSourceFile(value.filePath)) {
21355 exportsNonSourceFiles = true;
21356 }
21357 }
21358 }
21359 visitValue(metadata, new Visitor(), null);
21360 return exportsNonSourceFiles;
21361 }
21362 function mergeAnalyzedFiles(analyzedFiles) {
21363 const allNgModules = [];
21364 const ngModuleByPipeOrDirective = new Map();
21365 const allPipesAndDirectives = new Set();
21366 analyzedFiles.forEach(af => {
21367 af.ngModules.forEach(ngModule => {
21368 allNgModules.push(ngModule);
21369 ngModule.declaredDirectives.forEach(d => ngModuleByPipeOrDirective.set(d.reference, ngModule));
21370 ngModule.declaredPipes.forEach(p => ngModuleByPipeOrDirective.set(p.reference, ngModule));
21371 });
21372 af.directives.forEach(d => allPipesAndDirectives.add(d));
21373 af.pipes.forEach(p => allPipesAndDirectives.add(p));
21374 });
21375 const symbolsMissingModule = [];
21376 allPipesAndDirectives.forEach(ref => {
21377 if (!ngModuleByPipeOrDirective.has(ref)) {
21378 symbolsMissingModule.push(ref);
21379 }
21380 });
21381 return {
21382 ngModules: allNgModules,
21383 ngModuleByPipeOrDirective,
21384 symbolsMissingModule,
21385 files: analyzedFiles
21386 };
21387 }
21388
21389 /**
21390 * @license
21391 * Copyright Google LLC All Rights Reserved.
21392 *
21393 * Use of this source code is governed by an MIT-style license that can be
21394 * found in the LICENSE file at https://angular.io/license
21395 */
21396 const FORMATTED_MESSAGE = 'ngFormattedMessage';
21397 function indentStr(level) {
21398 if (level <= 0)
21399 return '';
21400 if (level < 6)
21401 return ['', ' ', ' ', ' ', ' ', ' '][level];
21402 const half = indentStr(Math.floor(level / 2));
21403 return half + half + (level % 2 === 1 ? ' ' : '');
21404 }
21405 function formatChain(chain, indent = 0) {
21406 if (!chain)
21407 return '';
21408 const position = chain.position ?
21409 `${chain.position.fileName}(${chain.position.line + 1},${chain.position.column + 1})` :
21410 '';
21411 const prefix = position && indent === 0 ? `${position}: ` : '';
21412 const postfix = position && indent !== 0 ? ` at ${position}` : '';
21413 let message = `${prefix}${chain.message}${postfix}`;
21414 if (chain.next) {
21415 for (const kid of chain.next) {
21416 message += '\n' + formatChain(kid, indent + 2);
21417 }
21418 }
21419 return `${indentStr(indent)}${message}`;
21420 }
21421 function formattedError(chain) {
21422 const message = formatChain(chain) + '.';
21423 const error = syntaxError(message);
21424 error[FORMATTED_MESSAGE] = true;
21425 error.chain = chain;
21426 error.position = chain.position;
21427 return error;
21428 }
21429 function isFormattedError(error) {
21430 return !!error[FORMATTED_MESSAGE];
21431 }
21432
21433 /**
21434 * @license
21435 * Copyright Google LLC All Rights Reserved.
21436 *
21437 * Use of this source code is governed by an MIT-style license that can be
21438 * found in the LICENSE file at https://angular.io/license
21439 */
21440 const ANGULAR_CORE = '@angular/core';
21441 const ANGULAR_ROUTER = '@angular/router';
21442 const HIDDEN_KEY = /^\$.*\$$/;
21443 const IGNORE = {
21444 __symbolic: 'ignore'
21445 };
21446 const USE_VALUE$1 = 'useValue';
21447 const PROVIDE = 'provide';
21448 const REFERENCE_SET = new Set([USE_VALUE$1, 'useFactory', 'data', 'id', 'loadChildren']);
21449 const TYPEGUARD_POSTFIX = 'TypeGuard';
21450 const USE_IF = 'UseIf';
21451 function shouldIgnore(value) {
21452 return value && value.__symbolic == 'ignore';
21453 }
21454 /**
21455 * A static reflector implements enough of the Reflector API that is necessary to compile
21456 * templates statically.
21457 */
21458 class StaticReflector {
21459 constructor(summaryResolver, symbolResolver, knownMetadataClasses = [], knownMetadataFunctions = [], errorRecorder) {
21460 this.summaryResolver = summaryResolver;
21461 this.symbolResolver = symbolResolver;
21462 this.errorRecorder = errorRecorder;
21463 this.annotationCache = new Map();
21464 this.shallowAnnotationCache = new Map();
21465 this.propertyCache = new Map();
21466 this.parameterCache = new Map();
21467 this.methodCache = new Map();
21468 this.staticCache = new Map();
21469 this.conversionMap = new Map();
21470 this.resolvedExternalReferences = new Map();
21471 this.annotationForParentClassWithSummaryKind = new Map();
21472 this.initializeConversionMap();
21473 knownMetadataClasses.forEach((kc) => this._registerDecoratorOrConstructor(this.getStaticSymbol(kc.filePath, kc.name), kc.ctor));
21474 knownMetadataFunctions.forEach((kf) => this._registerFunction(this.getStaticSymbol(kf.filePath, kf.name), kf.fn));
21475 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Directive, [createDirective, createComponent]);
21476 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Pipe, [createPipe]);
21477 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.NgModule, [createNgModule]);
21478 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Injectable, [createInjectable, createPipe, createDirective, createComponent, createNgModule]);
21479 }
21480 componentModuleUrl(typeOrFunc) {
21481 const staticSymbol = this.findSymbolDeclaration(typeOrFunc);
21482 return this.symbolResolver.getResourcePath(staticSymbol);
21483 }
21484 /**
21485 * Invalidate the specified `symbols` on program change.
21486 * @param symbols
21487 */
21488 invalidateSymbols(symbols) {
21489 for (const symbol of symbols) {
21490 this.annotationCache.delete(symbol);
21491 this.shallowAnnotationCache.delete(symbol);
21492 this.propertyCache.delete(symbol);
21493 this.parameterCache.delete(symbol);
21494 this.methodCache.delete(symbol);
21495 this.staticCache.delete(symbol);
21496 this.conversionMap.delete(symbol);
21497 }
21498 }
21499 resolveExternalReference(ref, containingFile) {
21500 let key = undefined;
21501 if (!containingFile) {
21502 key = `${ref.moduleName}:${ref.name}`;
21503 const declarationSymbol = this.resolvedExternalReferences.get(key);
21504 if (declarationSymbol)
21505 return declarationSymbol;
21506 }
21507 const refSymbol = this.symbolResolver.getSymbolByModule(ref.moduleName, ref.name, containingFile);
21508 const declarationSymbol = this.findSymbolDeclaration(refSymbol);
21509 if (!containingFile) {
21510 this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName);
21511 this.symbolResolver.recordImportAs(declarationSymbol, refSymbol);
21512 }
21513 if (key) {
21514 this.resolvedExternalReferences.set(key, declarationSymbol);
21515 }
21516 return declarationSymbol;
21517 }
21518 findDeclaration(moduleUrl, name, containingFile) {
21519 return this.findSymbolDeclaration(this.symbolResolver.getSymbolByModule(moduleUrl, name, containingFile));
21520 }
21521 tryFindDeclaration(moduleUrl, name, containingFile) {
21522 return this.symbolResolver.ignoreErrorsFor(() => this.findDeclaration(moduleUrl, name, containingFile));
21523 }
21524 findSymbolDeclaration(symbol) {
21525 const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
21526 if (resolvedSymbol) {
21527 let resolvedMetadata = resolvedSymbol.metadata;
21528 if (resolvedMetadata && resolvedMetadata.__symbolic === 'resolved') {
21529 resolvedMetadata = resolvedMetadata.symbol;
21530 }
21531 if (resolvedMetadata instanceof StaticSymbol) {
21532 return this.findSymbolDeclaration(resolvedSymbol.metadata);
21533 }
21534 }
21535 return symbol;
21536 }
21537 tryAnnotations(type) {
21538 const originalRecorder = this.errorRecorder;
21539 this.errorRecorder = (error, fileName) => { };
21540 try {
21541 return this.annotations(type);
21542 }
21543 finally {
21544 this.errorRecorder = originalRecorder;
21545 }
21546 }
21547 annotations(type) {
21548 return this._annotations(type, (type, decorators) => this.simplify(type, decorators), this.annotationCache);
21549 }
21550 shallowAnnotations(type) {
21551 return this._annotations(type, (type, decorators) => this.simplify(type, decorators, true), this.shallowAnnotationCache);
21552 }
21553 _annotations(type, simplify, annotationCache) {
21554 let annotations = annotationCache.get(type);
21555 if (!annotations) {
21556 annotations = [];
21557 const classMetadata = this.getTypeMetadata(type);
21558 const parentType = this.findParentType(type, classMetadata);
21559 if (parentType) {
21560 const parentAnnotations = this.annotations(parentType);
21561 annotations.push(...parentAnnotations);
21562 }
21563 let ownAnnotations = [];
21564 if (classMetadata['decorators']) {
21565 ownAnnotations = simplify(type, classMetadata['decorators']);
21566 if (ownAnnotations) {
21567 annotations.push(...ownAnnotations);
21568 }
21569 }
21570 if (parentType && !this.summaryResolver.isLibraryFile(type.filePath) &&
21571 this.summaryResolver.isLibraryFile(parentType.filePath)) {
21572 const summary = this.summaryResolver.resolveSummary(parentType);
21573 if (summary && summary.type) {
21574 const requiredAnnotationTypes = this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind);
21575 const typeHasRequiredAnnotation = requiredAnnotationTypes.some((requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
21576 if (!typeHasRequiredAnnotation) {
21577 this.reportError(formatMetadataError(metadataError(`Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind]} in another compilation unit without duplicating the decorator`,
21578 /* summary */ undefined, `Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName)
21579 .join(' or ')} decorator to the class`), type), type);
21580 }
21581 }
21582 }
21583 annotationCache.set(type, annotations.filter(ann => !!ann));
21584 }
21585 return annotations;
21586 }
21587 propMetadata(type) {
21588 let propMetadata = this.propertyCache.get(type);
21589 if (!propMetadata) {
21590 const classMetadata = this.getTypeMetadata(type);
21591 propMetadata = {};
21592 const parentType = this.findParentType(type, classMetadata);
21593 if (parentType) {
21594 const parentPropMetadata = this.propMetadata(parentType);
21595 Object.keys(parentPropMetadata).forEach((parentProp) => {
21596 propMetadata[parentProp] = parentPropMetadata[parentProp];
21597 });
21598 }
21599 const members = classMetadata['members'] || {};
21600 Object.keys(members).forEach((propName) => {
21601 const propData = members[propName];
21602 const prop = propData
21603 .find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method');
21604 const decorators = [];
21605 // hasOwnProperty() is used here to make sure we do not look up methods
21606 // on `Object.prototype`.
21607 if (propMetadata === null || propMetadata === void 0 ? void 0 : propMetadata.hasOwnProperty(propName)) {
21608 decorators.push(...propMetadata[propName]);
21609 }
21610 propMetadata[propName] = decorators;
21611 if (prop && prop['decorators']) {
21612 decorators.push(...this.simplify(type, prop['decorators']));
21613 }
21614 });
21615 this.propertyCache.set(type, propMetadata);
21616 }
21617 return propMetadata;
21618 }
21619 parameters(type) {
21620 if (!(type instanceof StaticSymbol)) {
21621 this.reportError(new Error(`parameters received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
21622 return [];
21623 }
21624 try {
21625 let parameters = this.parameterCache.get(type);
21626 if (!parameters) {
21627 const classMetadata = this.getTypeMetadata(type);
21628 const parentType = this.findParentType(type, classMetadata);
21629 const members = classMetadata ? classMetadata['members'] : null;
21630 const ctorData = members ? members['__ctor__'] : null;
21631 if (ctorData) {
21632 const ctor = ctorData.find(a => a['__symbolic'] == 'constructor');
21633 const rawParameterTypes = ctor['parameters'] || [];
21634 const parameterDecorators = this.simplify(type, ctor['parameterDecorators'] || []);
21635 parameters = [];
21636 rawParameterTypes.forEach((rawParamType, index) => {
21637 const nestedResult = [];
21638 const paramType = this.trySimplify(type, rawParamType);
21639 if (paramType)
21640 nestedResult.push(paramType);
21641 const decorators = parameterDecorators ? parameterDecorators[index] : null;
21642 if (decorators) {
21643 nestedResult.push(...decorators);
21644 }
21645 parameters.push(nestedResult);
21646 });
21647 }
21648 else if (parentType) {
21649 parameters = this.parameters(parentType);
21650 }
21651 if (!parameters) {
21652 parameters = [];
21653 }
21654 this.parameterCache.set(type, parameters);
21655 }
21656 return parameters;
21657 }
21658 catch (e) {
21659 console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
21660 throw e;
21661 }
21662 }
21663 _methodNames(type) {
21664 let methodNames = this.methodCache.get(type);
21665 if (!methodNames) {
21666 const classMetadata = this.getTypeMetadata(type);
21667 methodNames = {};
21668 const parentType = this.findParentType(type, classMetadata);
21669 if (parentType) {
21670 const parentMethodNames = this._methodNames(parentType);
21671 Object.keys(parentMethodNames).forEach((parentProp) => {
21672 methodNames[parentProp] = parentMethodNames[parentProp];
21673 });
21674 }
21675 const members = classMetadata['members'] || {};
21676 Object.keys(members).forEach((propName) => {
21677 const propData = members[propName];
21678 const isMethod = propData.some(a => a['__symbolic'] == 'method');
21679 methodNames[propName] = methodNames[propName] || isMethod;
21680 });
21681 this.methodCache.set(type, methodNames);
21682 }
21683 return methodNames;
21684 }
21685 _staticMembers(type) {
21686 let staticMembers = this.staticCache.get(type);
21687 if (!staticMembers) {
21688 const classMetadata = this.getTypeMetadata(type);
21689 const staticMemberData = classMetadata['statics'] || {};
21690 staticMembers = Object.keys(staticMemberData);
21691 this.staticCache.set(type, staticMembers);
21692 }
21693 return staticMembers;
21694 }
21695 findParentType(type, classMetadata) {
21696 const parentType = this.trySimplify(type, classMetadata['extends']);
21697 if (parentType instanceof StaticSymbol) {
21698 return parentType;
21699 }
21700 }
21701 hasLifecycleHook(type, lcProperty) {
21702 if (!(type instanceof StaticSymbol)) {
21703 this.reportError(new Error(`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
21704 }
21705 try {
21706 return !!this._methodNames(type)[lcProperty];
21707 }
21708 catch (e) {
21709 console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
21710 throw e;
21711 }
21712 }
21713 guards(type) {
21714 if (!(type instanceof StaticSymbol)) {
21715 this.reportError(new Error(`guards received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
21716 return {};
21717 }
21718 const staticMembers = this._staticMembers(type);
21719 const result = {};
21720 for (let name of staticMembers) {
21721 if (name.endsWith(TYPEGUARD_POSTFIX)) {
21722 let property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
21723 let value;
21724 if (property.endsWith(USE_IF)) {
21725 property = name.substr(0, property.length - USE_IF.length);
21726 value = USE_IF;
21727 }
21728 else {
21729 value = this.getStaticSymbol(type.filePath, type.name, [name]);
21730 }
21731 result[property] = value;
21732 }
21733 }
21734 return result;
21735 }
21736 _registerDecoratorOrConstructor(type, ctor) {
21737 this.conversionMap.set(type, (context, args) => new ctor(...args));
21738 }
21739 _registerFunction(type, fn) {
21740 this.conversionMap.set(type, (context, args) => fn.apply(undefined, args));
21741 }
21742 initializeConversionMap() {
21743 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Injectable'), createInjectable);
21744 this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');
21745 this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');
21746 this.ROUTES = this.tryFindDeclaration(ANGULAR_ROUTER, 'ROUTES');
21747 this.ANALYZE_FOR_ENTRY_COMPONENTS =
21748 this.findDeclaration(ANGULAR_CORE, 'ANALYZE_FOR_ENTRY_COMPONENTS');
21749 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
21750 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
21751 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
21752 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Inject'), createInject);
21753 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
21754 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Attribute'), createAttribute);
21755 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChild'), createContentChild);
21756 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), createContentChildren);
21757 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChild'), createViewChild);
21758 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), createViewChildren);
21759 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), createInput);
21760 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Output'), createOutput);
21761 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), createPipe);
21762 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostBinding'), createHostBinding);
21763 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostListener'), createHostListener);
21764 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Directive'), createDirective);
21765 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Component'), createComponent);
21766 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'NgModule'), createNgModule);
21767 // Note: Some metadata classes can be used directly with Provider.deps.
21768 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
21769 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
21770 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
21771 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
21772 }
21773 /**
21774 * getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
21775 * All types passed to the StaticResolver should be pseudo-types returned by this method.
21776 *
21777 * @param declarationFile the absolute path of the file where the symbol is declared
21778 * @param name the name of the type.
21779 */
21780 getStaticSymbol(declarationFile, name, members) {
21781 return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
21782 }
21783 /**
21784 * Simplify but discard any errors
21785 */
21786 trySimplify(context, value) {
21787 const originalRecorder = this.errorRecorder;
21788 this.errorRecorder = (error, fileName) => { };
21789 const result = this.simplify(context, value);
21790 this.errorRecorder = originalRecorder;
21791 return result;
21792 }
21793 /** @internal */
21794 simplify(context, value, lazy = false) {
21795 const self = this;
21796 let scope = BindingScope$1.empty;
21797 const calling = new Map();
21798 function simplifyInContext(context, value, depth, references) {
21799 function resolveReferenceValue(staticSymbol) {
21800 const resolvedSymbol = self.symbolResolver.resolveSymbol(staticSymbol);
21801 return resolvedSymbol ? resolvedSymbol.metadata : null;
21802 }
21803 function simplifyEagerly(value) {
21804 return simplifyInContext(context, value, depth, 0);
21805 }
21806 function simplifyLazily(value) {
21807 return simplifyInContext(context, value, depth, references + 1);
21808 }
21809 function simplifyNested(nestedContext, value) {
21810 if (nestedContext === context) {
21811 // If the context hasn't changed let the exception propagate unmodified.
21812 return simplifyInContext(nestedContext, value, depth + 1, references);
21813 }
21814 try {
21815 return simplifyInContext(nestedContext, value, depth + 1, references);
21816 }
21817 catch (e) {
21818 if (isMetadataError(e)) {
21819 // Propagate the message text up but add a message to the chain that explains how we got
21820 // here.
21821 // e.chain implies e.symbol
21822 const summaryMsg = e.chain ? 'references \'' + e.symbol.name + '\'' : errorSummary(e);
21823 const summary = `'${nestedContext.name}' ${summaryMsg}`;
21824 const chain = { message: summary, position: e.position, next: e.chain };
21825 // TODO(chuckj): retrieve the position information indirectly from the collectors node
21826 // map if the metadata is from a .ts file.
21827 self.error({
21828 message: e.message,
21829 advise: e.advise,
21830 context: e.context,
21831 chain,
21832 symbol: nestedContext
21833 }, context);
21834 }
21835 else {
21836 // It is probably an internal error.
21837 throw e;
21838 }
21839 }
21840 }
21841 function simplifyCall(functionSymbol, targetFunction, args, targetExpression) {
21842 if (targetFunction && targetFunction['__symbolic'] == 'function') {
21843 if (calling.get(functionSymbol)) {
21844 self.error({
21845 message: 'Recursion is not supported',
21846 summary: `called '${functionSymbol.name}' recursively`,
21847 value: targetFunction
21848 }, functionSymbol);
21849 }
21850 try {
21851 const value = targetFunction['value'];
21852 if (value && (depth != 0 || value.__symbolic != 'error')) {
21853 const parameters = targetFunction['parameters'];
21854 const defaults = targetFunction.defaults;
21855 args = args.map(arg => simplifyNested(context, arg))
21856 .map(arg => shouldIgnore(arg) ? undefined : arg);
21857 if (defaults && defaults.length > args.length) {
21858 args.push(...defaults.slice(args.length).map((value) => simplify(value)));
21859 }
21860 calling.set(functionSymbol, true);
21861 const functionScope = BindingScope$1.build();
21862 for (let i = 0; i < parameters.length; i++) {
21863 functionScope.define(parameters[i], args[i]);
21864 }
21865 const oldScope = scope;
21866 let result;
21867 try {
21868 scope = functionScope.done();
21869 result = simplifyNested(functionSymbol, value);
21870 }
21871 finally {
21872 scope = oldScope;
21873 }
21874 return result;
21875 }
21876 }
21877 finally {
21878 calling.delete(functionSymbol);
21879 }
21880 }
21881 if (depth === 0) {
21882 // If depth is 0 we are evaluating the top level expression that is describing element
21883 // decorator. In this case, it is a decorator we don't understand, such as a custom
21884 // non-angular decorator, and we should just ignore it.
21885 return IGNORE;
21886 }
21887 let position = undefined;
21888 if (targetExpression && targetExpression.__symbolic == 'resolved') {
21889 const line = targetExpression.line;
21890 const character = targetExpression.character;
21891 const fileName = targetExpression.fileName;
21892 if (fileName != null && line != null && character != null) {
21893 position = { fileName, line, column: character };
21894 }
21895 }
21896 self.error({
21897 message: FUNCTION_CALL_NOT_SUPPORTED,
21898 context: functionSymbol,
21899 value: targetFunction,
21900 position
21901 }, context);
21902 }
21903 function simplify(expression) {
21904 if (isPrimitive(expression)) {
21905 return expression;
21906 }
21907 if (Array.isArray(expression)) {
21908 const result = [];
21909 for (const item of expression) {
21910 // Check for a spread expression
21911 if (item && item.__symbolic === 'spread') {
21912 // We call with references as 0 because we require the actual value and cannot
21913 // tolerate a reference here.
21914 const spreadArray = simplifyEagerly(item.expression);
21915 if (Array.isArray(spreadArray)) {
21916 for (const spreadItem of spreadArray) {
21917 result.push(spreadItem);
21918 }
21919 continue;
21920 }
21921 }
21922 const value = simplify(item);
21923 if (shouldIgnore(value)) {
21924 continue;
21925 }
21926 result.push(value);
21927 }
21928 return result;
21929 }
21930 if (expression instanceof StaticSymbol) {
21931 // Stop simplification at builtin symbols or if we are in a reference context and
21932 // the symbol doesn't have members.
21933 if (expression === self.injectionToken || self.conversionMap.has(expression) ||
21934 (references > 0 && !expression.members.length)) {
21935 return expression;
21936 }
21937 else {
21938 const staticSymbol = expression;
21939 const declarationValue = resolveReferenceValue(staticSymbol);
21940 if (declarationValue != null) {
21941 return simplifyNested(staticSymbol, declarationValue);
21942 }
21943 else {
21944 return staticSymbol;
21945 }
21946 }
21947 }
21948 if (expression) {
21949 if (expression['__symbolic']) {
21950 let staticSymbol;
21951 switch (expression['__symbolic']) {
21952 case 'binop':
21953 let left = simplify(expression['left']);
21954 if (shouldIgnore(left))
21955 return left;
21956 let right = simplify(expression['right']);
21957 if (shouldIgnore(right))
21958 return right;
21959 switch (expression['operator']) {
21960 case '&&':
21961 return left && right;
21962 case '||':
21963 return left || right;
21964 case '|':
21965 return left | right;
21966 case '^':
21967 return left ^ right;
21968 case '&':
21969 return left & right;
21970 case '==':
21971 return left == right;
21972 case '!=':
21973 return left != right;
21974 case '===':
21975 return left === right;
21976 case '!==':
21977 return left !== right;
21978 case '<':
21979 return left < right;
21980 case '>':
21981 return left > right;
21982 case '<=':
21983 return left <= right;
21984 case '>=':
21985 return left >= right;
21986 case '<<':
21987 return left << right;
21988 case '>>':
21989 return left >> right;
21990 case '+':
21991 return left + right;
21992 case '-':
21993 return left - right;
21994 case '*':
21995 return left * right;
21996 case '/':
21997 return left / right;
21998 case '%':
21999 return left % right;
22000 }
22001 return null;
22002 case 'if':
22003 let condition = simplify(expression['condition']);
22004 return condition ? simplify(expression['thenExpression']) :
22005 simplify(expression['elseExpression']);
22006 case 'pre':
22007 let operand = simplify(expression['operand']);
22008 if (shouldIgnore(operand))
22009 return operand;
22010 switch (expression['operator']) {
22011 case '+':
22012 return operand;
22013 case '-':
22014 return -operand;
22015 case '!':
22016 return !operand;
22017 case '~':
22018 return ~operand;
22019 }
22020 return null;
22021 case 'index':
22022 let indexTarget = simplifyEagerly(expression['expression']);
22023 let index = simplifyEagerly(expression['index']);
22024 if (indexTarget && isPrimitive(index))
22025 return indexTarget[index];
22026 return null;
22027 case 'select':
22028 const member = expression['member'];
22029 let selectContext = context;
22030 let selectTarget = simplify(expression['expression']);
22031 if (selectTarget instanceof StaticSymbol) {
22032 const members = selectTarget.members.concat(member);
22033 selectContext =
22034 self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
22035 const declarationValue = resolveReferenceValue(selectContext);
22036 if (declarationValue != null) {
22037 return simplifyNested(selectContext, declarationValue);
22038 }
22039 else {
22040 return selectContext;
22041 }
22042 }
22043 if (selectTarget && isPrimitive(member))
22044 return simplifyNested(selectContext, selectTarget[member]);
22045 return null;
22046 case 'reference':
22047 // Note: This only has to deal with variable references, as symbol references have
22048 // been converted into 'resolved'
22049 // in the StaticSymbolResolver.
22050 const name = expression['name'];
22051 const localValue = scope.resolve(name);
22052 if (localValue != BindingScope$1.missing) {
22053 return localValue;
22054 }
22055 break;
22056 case 'resolved':
22057 try {
22058 return simplify(expression.symbol);
22059 }
22060 catch (e) {
22061 // If an error is reported evaluating the symbol record the position of the
22062 // reference in the error so it can
22063 // be reported in the error message generated from the exception.
22064 if (isMetadataError(e) && expression.fileName != null &&
22065 expression.line != null && expression.character != null) {
22066 e.position = {
22067 fileName: expression.fileName,
22068 line: expression.line,
22069 column: expression.character
22070 };
22071 }
22072 throw e;
22073 }
22074 case 'class':
22075 return context;
22076 case 'function':
22077 return context;
22078 case 'new':
22079 case 'call':
22080 // Determine if the function is a built-in conversion
22081 staticSymbol = simplifyInContext(context, expression['expression'], depth + 1, /* references */ 0);
22082 if (staticSymbol instanceof StaticSymbol) {
22083 if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {
22084 // if somebody calls new InjectionToken, don't create an InjectionToken,
22085 // but rather return the symbol to which the InjectionToken is assigned to.
22086 // OpaqueToken is supported too as it is required by the language service to
22087 // support v4 and prior versions of Angular.
22088 return context;
22089 }
22090 const argExpressions = expression['arguments'] || [];
22091 let converter = self.conversionMap.get(staticSymbol);
22092 if (converter) {
22093 const args = argExpressions.map(arg => simplifyNested(context, arg))
22094 .map(arg => shouldIgnore(arg) ? undefined : arg);
22095 return converter(context, args);
22096 }
22097 else {
22098 // Determine if the function is one we can simplify.
22099 const targetFunction = resolveReferenceValue(staticSymbol);
22100 return simplifyCall(staticSymbol, targetFunction, argExpressions, expression['expression']);
22101 }
22102 }
22103 return IGNORE;
22104 case 'error':
22105 let message = expression.message;
22106 if (expression['line'] != null) {
22107 self.error({
22108 message,
22109 context: expression.context,
22110 value: expression,
22111 position: {
22112 fileName: expression['fileName'],
22113 line: expression['line'],
22114 column: expression['character']
22115 }
22116 }, context);
22117 }
22118 else {
22119 self.error({ message, context: expression.context }, context);
22120 }
22121 return IGNORE;
22122 case 'ignore':
22123 return expression;
22124 }
22125 return null;
22126 }
22127 return mapStringMap(expression, (value, name) => {
22128 if (REFERENCE_SET.has(name)) {
22129 if (name === USE_VALUE$1 && PROVIDE in expression) {
22130 // If this is a provider expression, check for special tokens that need the value
22131 // during analysis.
22132 const provide = simplify(expression.provide);
22133 if (provide === self.ROUTES || provide == self.ANALYZE_FOR_ENTRY_COMPONENTS) {
22134 return simplify(value);
22135 }
22136 }
22137 return simplifyLazily(value);
22138 }
22139 return simplify(value);
22140 });
22141 }
22142 return IGNORE;
22143 }
22144 return simplify(value);
22145 }
22146 let result;
22147 try {
22148 result = simplifyInContext(context, value, 0, lazy ? 1 : 0);
22149 }
22150 catch (e) {
22151 if (this.errorRecorder) {
22152 this.reportError(e, context);
22153 }
22154 else {
22155 throw formatMetadataError(e, context);
22156 }
22157 }
22158 if (shouldIgnore(result)) {
22159 return undefined;
22160 }
22161 return result;
22162 }
22163 getTypeMetadata(type) {
22164 const resolvedSymbol = this.symbolResolver.resolveSymbol(type);
22165 return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
22166 { __symbolic: 'class' };
22167 }
22168 reportError(error, context, path) {
22169 if (this.errorRecorder) {
22170 this.errorRecorder(formatMetadataError(error, context), (context && context.filePath) || path);
22171 }
22172 else {
22173 throw error;
22174 }
22175 }
22176 error({ message, summary, advise, position, context, value, symbol, chain }, reportingContext) {
22177 this.reportError(metadataError(message, summary, advise, position, symbol, context, chain), reportingContext);
22178 }
22179 }
22180 const METADATA_ERROR = 'ngMetadataError';
22181 function metadataError(message, summary, advise, position, symbol, context, chain) {
22182 const error = syntaxError(message);
22183 error[METADATA_ERROR] = true;
22184 if (advise)
22185 error.advise = advise;
22186 if (position)
22187 error.position = position;
22188 if (summary)
22189 error.summary = summary;
22190 if (context)
22191 error.context = context;
22192 if (chain)
22193 error.chain = chain;
22194 if (symbol)
22195 error.symbol = symbol;
22196 return error;
22197 }
22198 function isMetadataError(error) {
22199 return !!error[METADATA_ERROR];
22200 }
22201 const REFERENCE_TO_NONEXPORTED_CLASS = 'Reference to non-exported class';
22202 const VARIABLE_NOT_INITIALIZED = 'Variable not initialized';
22203 const DESTRUCTURE_NOT_SUPPORTED = 'Destructuring not supported';
22204 const COULD_NOT_RESOLVE_TYPE = 'Could not resolve type';
22205 const FUNCTION_CALL_NOT_SUPPORTED = 'Function call not supported';
22206 const REFERENCE_TO_LOCAL_SYMBOL = 'Reference to a local symbol';
22207 const LAMBDA_NOT_SUPPORTED = 'Lambda not supported';
22208 function expandedMessage(message, context) {
22209 switch (message) {
22210 case REFERENCE_TO_NONEXPORTED_CLASS:
22211 if (context && context.className) {
22212 return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`;
22213 }
22214 break;
22215 case VARIABLE_NOT_INITIALIZED:
22216 return 'Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler';
22217 case DESTRUCTURE_NOT_SUPPORTED:
22218 return 'Referencing an exported destructured variable or constant is not supported in decorators and this value is needed by the template compiler';
22219 case COULD_NOT_RESOLVE_TYPE:
22220 if (context && context.typeName) {
22221 return `Could not resolve type ${context.typeName}`;
22222 }
22223 break;
22224 case FUNCTION_CALL_NOT_SUPPORTED:
22225 if (context && context.name) {
22226 return `Function calls are not supported in decorators but '${context.name}' was called`;
22227 }
22228 return 'Function calls are not supported in decorators';
22229 case REFERENCE_TO_LOCAL_SYMBOL:
22230 if (context && context.name) {
22231 return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`;
22232 }
22233 break;
22234 case LAMBDA_NOT_SUPPORTED:
22235 return `Function expressions are not supported in decorators`;
22236 }
22237 return message;
22238 }
22239 function messageAdvise(message, context) {
22240 switch (message) {
22241 case REFERENCE_TO_NONEXPORTED_CLASS:
22242 if (context && context.className) {
22243 return `Consider exporting '${context.className}'`;
22244 }
22245 break;
22246 case DESTRUCTURE_NOT_SUPPORTED:
22247 return 'Consider simplifying to avoid destructuring';
22248 case REFERENCE_TO_LOCAL_SYMBOL:
22249 if (context && context.name) {
22250 return `Consider exporting '${context.name}'`;
22251 }
22252 break;
22253 case LAMBDA_NOT_SUPPORTED:
22254 return `Consider changing the function expression into an exported function`;
22255 }
22256 return undefined;
22257 }
22258 function errorSummary(error) {
22259 if (error.summary) {
22260 return error.summary;
22261 }
22262 switch (error.message) {
22263 case REFERENCE_TO_NONEXPORTED_CLASS:
22264 if (error.context && error.context.className) {
22265 return `references non-exported class ${error.context.className}`;
22266 }
22267 break;
22268 case VARIABLE_NOT_INITIALIZED:
22269 return 'is not initialized';
22270 case DESTRUCTURE_NOT_SUPPORTED:
22271 return 'is a destructured variable';
22272 case COULD_NOT_RESOLVE_TYPE:
22273 return 'could not be resolved';
22274 case FUNCTION_CALL_NOT_SUPPORTED:
22275 if (error.context && error.context.name) {
22276 return `calls '${error.context.name}'`;
22277 }
22278 return `calls a function`;
22279 case REFERENCE_TO_LOCAL_SYMBOL:
22280 if (error.context && error.context.name) {
22281 return `references local variable ${error.context.name}`;
22282 }
22283 return `references a local variable`;
22284 }
22285 return 'contains the error';
22286 }
22287 function mapStringMap(input, transform) {
22288 if (!input)
22289 return {};
22290 const result = {};
22291 Object.keys(input).forEach((key) => {
22292 const value = transform(input[key], key);
22293 if (!shouldIgnore(value)) {
22294 if (HIDDEN_KEY.test(key)) {
22295 Object.defineProperty(result, key, { enumerable: false, configurable: true, value: value });
22296 }
22297 else {
22298 result[key] = value;
22299 }
22300 }
22301 });
22302 return result;
22303 }
22304 function isPrimitive(o) {
22305 return o === null || (typeof o !== 'function' && typeof o !== 'object');
22306 }
22307 class BindingScope$1 {
22308 static build() {
22309 const current = new Map();
22310 return {
22311 define: function (name, value) {
22312 current.set(name, value);
22313 return this;
22314 },
22315 done: function () {
22316 return current.size > 0 ? new PopulatedScope(current) : BindingScope$1.empty;
22317 }
22318 };
22319 }
22320 }
22321 BindingScope$1.missing = {};
22322 BindingScope$1.empty = { resolve: name => BindingScope$1.missing };
22323 class PopulatedScope extends BindingScope$1 {
22324 constructor(bindings) {
22325 super();
22326 this.bindings = bindings;
22327 }
22328 resolve(name) {
22329 return this.bindings.has(name) ? this.bindings.get(name) : BindingScope$1.missing;
22330 }
22331 }
22332 function formatMetadataMessageChain(chain, advise) {
22333 const expanded = expandedMessage(chain.message, chain.context);
22334 const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : '';
22335 const message = `${expanded}${nesting}`;
22336 const position = chain.position;
22337 const next = chain.next ?
22338 formatMetadataMessageChain(chain.next, advise) :
22339 advise ? { message: advise } : undefined;
22340 return { message, position, next: next ? [next] : undefined };
22341 }
22342 function formatMetadataError(e, context) {
22343 if (isMetadataError(e)) {
22344 // Produce a formatted version of the and leaving enough information in the original error
22345 // to recover the formatting information to eventually produce a diagnostic error message.
22346 const position = e.position;
22347 const chain = {
22348 message: `Error during template compile of '${context.name}'`,
22349 position: position,
22350 next: { message: e.message, next: e.chain, context: e.context, symbol: e.symbol }
22351 };
22352 const advise = e.advise || messageAdvise(e.message, e.context);
22353 return formattedError(formatMetadataMessageChain(chain, advise));
22354 }
22355 return e;
22356 }
22357
22358 /**
22359 * @license
22360 * Copyright Google LLC All Rights Reserved.
22361 *
22362 * Use of this source code is governed by an MIT-style license that can be
22363 * found in the LICENSE file at https://angular.io/license
22364 */
22365 class AotSummaryResolver {
22366 constructor(host, staticSymbolCache) {
22367 this.host = host;
22368 this.staticSymbolCache = staticSymbolCache;
22369 // Note: this will only contain StaticSymbols without members!
22370 this.summaryCache = new Map();
22371 this.loadedFilePaths = new Map();
22372 // Note: this will only contain StaticSymbols without members!
22373 this.importAs = new Map();
22374 this.knownFileNameToModuleNames = new Map();
22375 }
22376 isLibraryFile(filePath) {
22377 // Note: We need to strip the .ngfactory. file path,
22378 // so this method also works for generated files
22379 // (for which host.isSourceFile will always return false).
22380 return !this.host.isSourceFile(stripGeneratedFileSuffix(filePath));
22381 }
22382 toSummaryFileName(filePath, referringSrcFileName) {
22383 return this.host.toSummaryFileName(filePath, referringSrcFileName);
22384 }
22385 fromSummaryFileName(fileName, referringLibFileName) {
22386 return this.host.fromSummaryFileName(fileName, referringLibFileName);
22387 }
22388 resolveSummary(staticSymbol) {
22389 const rootSymbol = staticSymbol.members.length ?
22390 this.staticSymbolCache.get(staticSymbol.filePath, staticSymbol.name) :
22391 staticSymbol;
22392 let summary = this.summaryCache.get(rootSymbol);
22393 if (!summary) {
22394 this._loadSummaryFile(staticSymbol.filePath);
22395 summary = this.summaryCache.get(staticSymbol);
22396 }
22397 return (rootSymbol === staticSymbol && summary) || null;
22398 }
22399 getSymbolsOf(filePath) {
22400 if (this._loadSummaryFile(filePath)) {
22401 return Array.from(this.summaryCache.keys()).filter((symbol) => symbol.filePath === filePath);
22402 }
22403 return null;
22404 }
22405 getImportAs(staticSymbol) {
22406 staticSymbol.assertNoMembers();
22407 return this.importAs.get(staticSymbol);
22408 }
22409 /**
22410 * Converts a file path to a module name that can be used as an `import`.
22411 */
22412 getKnownModuleName(importedFilePath) {
22413 return this.knownFileNameToModuleNames.get(importedFilePath) || null;
22414 }
22415 addSummary(summary) {
22416 this.summaryCache.set(summary.symbol, summary);
22417 }
22418 _loadSummaryFile(filePath) {
22419 let hasSummary = this.loadedFilePaths.get(filePath);
22420 if (hasSummary != null) {
22421 return hasSummary;
22422 }
22423 let json = null;
22424 if (this.isLibraryFile(filePath)) {
22425 const summaryFilePath = summaryFileName(filePath);
22426 try {
22427 json = this.host.loadSummary(summaryFilePath);
22428 }
22429 catch (e) {
22430 console.error(`Error loading summary file ${summaryFilePath}`);
22431 throw e;
22432 }
22433 }
22434 hasSummary = json != null;
22435 this.loadedFilePaths.set(filePath, hasSummary);
22436 if (json) {
22437 const { moduleName, summaries, importAs } = deserializeSummaries(this.staticSymbolCache, this, filePath, json);
22438 summaries.forEach((summary) => this.summaryCache.set(summary.symbol, summary));
22439 if (moduleName) {
22440 this.knownFileNameToModuleNames.set(filePath, moduleName);
22441 }
22442 importAs.forEach((importAs) => {
22443 this.importAs.set(importAs.symbol, importAs.importAs);
22444 });
22445 }
22446 return hasSummary;
22447 }
22448 }
22449
22450 class JitSummaryResolver {
22451 constructor() {
22452 this._summaries = new Map();
22453 }
22454 isLibraryFile() {
22455 return false;
22456 }
22457 toSummaryFileName(fileName) {
22458 return fileName;
22459 }
22460 fromSummaryFileName(fileName) {
22461 return fileName;
22462 }
22463 resolveSummary(reference) {
22464 return this._summaries.get(reference) || null;
22465 }
22466 getSymbolsOf() {
22467 return [];
22468 }
22469 getImportAs(reference) {
22470 return reference;
22471 }
22472 getKnownModuleName(fileName) {
22473 return null;
22474 }
22475 addSummary(summary) {
22476 this._summaries.set(summary.symbol, summary);
22477 }
22478 }
22479
22480 /**
22481 * @license
22482 * Copyright Google LLC All Rights Reserved.
22483 *
22484 * Use of this source code is governed by an MIT-style license that can be
22485 * found in the LICENSE file at https://angular.io/license
22486 */
22487 /**
22488 * The index of each URI component in the return value of goog.uri.utils.split.
22489 * @enum {number}
22490 */
22491 var _ComponentIndex;
22492 (function (_ComponentIndex) {
22493 _ComponentIndex[_ComponentIndex["Scheme"] = 1] = "Scheme";
22494 _ComponentIndex[_ComponentIndex["UserInfo"] = 2] = "UserInfo";
22495 _ComponentIndex[_ComponentIndex["Domain"] = 3] = "Domain";
22496 _ComponentIndex[_ComponentIndex["Port"] = 4] = "Port";
22497 _ComponentIndex[_ComponentIndex["Path"] = 5] = "Path";
22498 _ComponentIndex[_ComponentIndex["QueryData"] = 6] = "QueryData";
22499 _ComponentIndex[_ComponentIndex["Fragment"] = 7] = "Fragment";
22500 })(_ComponentIndex || (_ComponentIndex = {}));
22501
22502 /**
22503 * @license
22504 * Copyright Google LLC All Rights Reserved.
22505 *
22506 * Use of this source code is governed by an MIT-style license that can be
22507 * found in the LICENSE file at https://angular.io/license
22508 */
22509 // This file only reexports content of the `src` folder. Keep it that way.
22510 // This function call has a global side effects and publishes the compiler into global namespace for
22511 // the late binding of the Compiler to the @angular/core for jit compilation.
22512 publishFacade(_global);
22513
22514 /**
22515 * @license
22516 * Copyright Google LLC All Rights Reserved.
22517 *
22518 * Use of this source code is governed by an MIT-style license that can be
22519 * found in the LICENSE file at https://angular.io/license
22520 */
22521 /**
22522 * Matches an Angular attribute to a binding type. See `ATTR` for more details.
22523 *
22524 * This is adapted from packages/compiler/src/render3/r3_template_transform.ts
22525 * to allow empty binding names and match template attributes.
22526 */
22527 const BIND_NAME_REGEXP$2 = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@)|(\*))(.*))|\[\(([^\)]*)\)\]|\[([^\]]*)\]|\(([^\)]*)\))$/;
22528 /**
22529 * Represents possible Angular attribute bindings, as indices on a match of `BIND_NAME_REGEXP`.
22530 */
22531 var ATTR;
22532 (function (ATTR) {
22533 /** "bind-" */
22534 ATTR[ATTR["KW_BIND"] = 1] = "KW_BIND";
22535 /** "let-" */
22536 ATTR[ATTR["KW_LET"] = 2] = "KW_LET";
22537 /** "ref-/#" */
22538 ATTR[ATTR["KW_REF"] = 3] = "KW_REF";
22539 /** "on-" */
22540 ATTR[ATTR["KW_ON"] = 4] = "KW_ON";
22541 /** "bindon-" */
22542 ATTR[ATTR["KW_BINDON"] = 5] = "KW_BINDON";
22543 /** "@" */
22544 ATTR[ATTR["KW_AT"] = 6] = "KW_AT";
22545 /**
22546 * "*"
22547 * Microsyntax template starts with '*'. See https://angular.io/api/core/TemplateRef
22548 */
22549 ATTR[ATTR["KW_MICROSYNTAX"] = 7] = "KW_MICROSYNTAX";
22550 /** The identifier after "bind-", "let-", "ref-/#", "on-", "bindon-", "@", or "*" */
22551 ATTR[ATTR["IDENT_KW"] = 8] = "IDENT_KW";
22552 /** Identifier inside [()] */
22553 ATTR[ATTR["IDENT_BANANA_BOX"] = 9] = "IDENT_BANANA_BOX";
22554 /** Identifier inside [] */
22555 ATTR[ATTR["IDENT_PROPERTY"] = 10] = "IDENT_PROPERTY";
22556 /** Identifier inside () */
22557 ATTR[ATTR["IDENT_EVENT"] = 11] = "IDENT_EVENT";
22558 })(ATTR || (ATTR = {}));
22559 /**
22560 * Returns a descriptor for a given Angular attribute, or undefined if the attribute is
22561 * not an Angular attribute.
22562 */
22563 function getBindingDescriptor(attribute) {
22564 const bindParts = attribute.match(BIND_NAME_REGEXP$2);
22565 if (!bindParts)
22566 return;
22567 // The first match element is skipped because it matches the entire attribute text, including the
22568 // binding part.
22569 const kind = bindParts.findIndex((val, i) => i > 0 && val !== undefined);
22570 if (!(kind in ATTR)) {
22571 throw TypeError(`"${kind}" is not a valid Angular binding kind for "${attribute}"`);
22572 }
22573 return {
22574 kind,
22575 name: bindParts[ATTR.IDENT_KW],
22576 };
22577 }
22578
22579 /**
22580 * @license
22581 * Copyright Google LLC All Rights Reserved.
22582 *
22583 * Use of this source code is governed by an MIT-style license that can be
22584 * found in the LICENSE file at https://angular.io/license
22585 */
22586 const Diagnostic = {
22587 directive_not_in_module: {
22588 message: `%1 '%2' is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration.`,
22589 kind: 'Suggestion',
22590 },
22591 missing_template_and_templateurl: {
22592 message: `Component '%1' must have a template or templateUrl`,
22593 kind: 'Error',
22594 },
22595 both_template_and_templateurl: {
22596 message: `Component '%1' must not have both template and templateUrl`,
22597 kind: 'Error',
22598 },
22599 invalid_templateurl: {
22600 message: `URL does not point to a valid file`,
22601 kind: 'Error',
22602 },
22603 template_context_missing_member: {
22604 message: `The template context of '%1' does not define %2.\n` +
22605 `If the context type is a base type or 'any', consider refining it to a more specific type.`,
22606 kind: 'Suggestion',
22607 },
22608 callable_expression_expected_method_call: {
22609 message: 'Unexpected callable expression. Expected a method call',
22610 kind: 'Warning',
22611 },
22612 call_target_not_callable: {
22613 message: `Call target '%1' has non-callable type '%2'.`,
22614 kind: 'Error',
22615 },
22616 expression_might_be_null: {
22617 message: 'The expression might be null',
22618 kind: 'Error',
22619 },
22620 expected_a_number_type: {
22621 message: 'Expected a number type',
22622 kind: 'Error',
22623 },
22624 expected_a_string_or_number_type: {
22625 message: 'Expected operands to be a string or number type',
22626 kind: 'Error',
22627 },
22628 expected_operands_of_comparable_types_or_any: {
22629 message: 'Expected operands to be of comparable types or any',
22630 kind: 'Error',
22631 },
22632 unrecognized_operator: {
22633 message: 'Unrecognized operator %1',
22634 kind: 'Error',
22635 },
22636 unrecognized_primitive: {
22637 message: 'Unrecognized primitive %1',
22638 kind: 'Error',
22639 },
22640 no_pipe_found: {
22641 message: 'No pipe of name %1 found',
22642 kind: 'Error',
22643 },
22644 // TODO: Consider a better error message here.
22645 unable_to_resolve_compatible_call_signature: {
22646 message: 'Unable to resolve compatible call signature',
22647 kind: 'Error',
22648 },
22649 unable_to_resolve_signature: {
22650 message: 'Unable to resolve signature for call of %1',
22651 kind: 'Error',
22652 },
22653 could_not_resolve_type: {
22654 message: `Could not resolve the type of '%1'`,
22655 kind: 'Error',
22656 },
22657 identifier_not_callable: {
22658 message: `'%1' is not callable`,
22659 kind: 'Error',
22660 },
22661 identifier_possibly_undefined: {
22662 message: `'%1' is possibly undefined. Consider using the safe navigation operator (%2) or non-null assertion operator (%3).`,
22663 kind: 'Suggestion',
22664 },
22665 identifier_not_defined_in_app_context: {
22666 message: `Identifier '%1' is not defined. The component declaration, template variable declarations, and element references do not contain such a member`,
22667 kind: 'Error',
22668 },
22669 identifier_not_defined_on_receiver: {
22670 message: `Identifier '%1' is not defined. '%2' does not contain such a member`,
22671 kind: 'Error',
22672 },
22673 identifier_is_private: {
22674 message: `Identifier '%1' refers to a private member of %2`,
22675 kind: 'Warning',
22676 },
22677 };
22678 /**
22679 * Creates a language service diagnostic.
22680 * @param span location the diagnostic for
22681 * @param dm diagnostic message
22682 * @param formatArgs run-time arguments to format the diagnostic message with (see the messages in
22683 * the `Diagnostic` object for an example).
22684 * @returns a created diagnostic
22685 */
22686 function createDiagnostic(span, dm, ...formatArgs) {
22687 // Formats "%1 %2" with formatArgs ['a', 'b'] as "a b"
22688 const formattedMessage = dm.message.replace(/%(\d+)/g, (_, index) => formatArgs[+index - 1]);
22689 return {
22690 kind: ts.DiagnosticCategory[dm.kind],
22691 message: formattedMessage,
22692 span,
22693 };
22694 }
22695
22696 /**
22697 * @license
22698 * Copyright Google LLC All Rights Reserved.
22699 *
22700 * Use of this source code is governed by an MIT-style license that can be
22701 * found in the LICENSE file at https://angular.io/license
22702 */
22703 /**
22704 * An enumeration of basic types.
22705 *
22706 * @publicApi
22707 */
22708 var BuiltinType$1;
22709 (function (BuiltinType) {
22710 /**
22711 * The type is a type that can hold any other type.
22712 */
22713 BuiltinType[BuiltinType["Any"] = -1] = "Any";
22714 /** Unknown types are functionally identical to any. */
22715 BuiltinType[BuiltinType["Unknown"] = -1] = "Unknown";
22716 /**
22717 * The type of a string literal.
22718 */
22719 BuiltinType[BuiltinType["String"] = 1] = "String";
22720 /**
22721 * The type of a numeric literal.
22722 */
22723 BuiltinType[BuiltinType["Number"] = 2] = "Number";
22724 /**
22725 * The type of the `true` and `false` literals.
22726 */
22727 BuiltinType[BuiltinType["Boolean"] = 4] = "Boolean";
22728 /**
22729 * The type of the `undefined` literal.
22730 */
22731 BuiltinType[BuiltinType["Undefined"] = 8] = "Undefined";
22732 /**
22733 * the type of the `null` literal.
22734 */
22735 BuiltinType[BuiltinType["Null"] = 16] = "Null";
22736 /**
22737 * the type is an unbound type parameter.
22738 */
22739 BuiltinType[BuiltinType["Unbound"] = 32] = "Unbound";
22740 /**
22741 * Not a built-in type.
22742 */
22743 BuiltinType[BuiltinType["Other"] = 64] = "Other";
22744 BuiltinType[BuiltinType["Object"] = 128] = "Object";
22745 })(BuiltinType$1 || (BuiltinType$1 = {}));
22746
22747 /**
22748 * @license
22749 * Copyright Google LLC All Rights Reserved.
22750 *
22751 * Use of this source code is governed by an MIT-style license that can be
22752 * found in the LICENSE file at https://angular.io/license
22753 */
22754 function isParseSourceSpan(value) {
22755 return value && !!value.start;
22756 }
22757 function spanOf(span) {
22758 if (!span)
22759 return undefined;
22760 if (isParseSourceSpan(span)) {
22761 return { start: span.start.offset, end: span.end.offset };
22762 }
22763 else {
22764 if (span.endSourceSpan) {
22765 return { start: span.sourceSpan.start.offset, end: span.endSourceSpan.end.offset };
22766 }
22767 else if (span.children && span.children.length) {
22768 return {
22769 start: span.sourceSpan.start.offset,
22770 end: spanOf(span.children[span.children.length - 1]).end
22771 };
22772 }
22773 return { start: span.sourceSpan.start.offset, end: span.sourceSpan.end.offset };
22774 }
22775 }
22776 function inSpan(position, span, exclusive) {
22777 return span != null &&
22778 (exclusive ? position >= span.start && position < span.end :
22779 position >= span.start && position <= span.end);
22780 }
22781 function offsetSpan(span, amount) {
22782 return { start: span.start + amount, end: span.end + amount };
22783 }
22784 function isNarrower(spanA, spanB) {
22785 return spanA.start >= spanB.start && spanA.end <= spanB.end;
22786 }
22787 function isStructuralDirective(type) {
22788 var _a;
22789 for (const diDep of type.diDeps) {
22790 const diDepName = identifierName((_a = diDep.token) === null || _a === void 0 ? void 0 : _a.identifier);
22791 if (diDepName === Identifiers.TemplateRef.name ||
22792 diDepName === Identifiers.ViewContainerRef.name) {
22793 return true;
22794 }
22795 }
22796 return false;
22797 }
22798 function getSelectors(info) {
22799 const map = new Map();
22800 const results = [];
22801 for (const directive of info.directives) {
22802 const selectors = CssSelector.parse(directive.selector);
22803 for (const selector of selectors) {
22804 results.push(selector);
22805 map.set(selector, directive);
22806 }
22807 }
22808 return { selectors: results, map };
22809 }
22810 function diagnosticInfoFromTemplateInfo(info) {
22811 return {
22812 fileName: info.template.fileName,
22813 offset: info.template.span.start,
22814 query: info.template.query,
22815 members: info.template.members,
22816 htmlAst: info.htmlAst,
22817 templateAst: info.templateAst,
22818 source: info.template.source,
22819 };
22820 }
22821 function findTemplateAstAt(ast, position) {
22822 const path = [];
22823 const visitor = new class extends RecursiveTemplateAstVisitor {
22824 visit(ast) {
22825 let span = spanOf(ast);
22826 if (inSpan(position, span)) {
22827 const len = path.length;
22828 if (!len || isNarrower(span, spanOf(path[len - 1]))) {
22829 path.push(ast);
22830 }
22831 }
22832 else {
22833 // Returning a value here will result in the children being skipped.
22834 return true;
22835 }
22836 }
22837 visitEmbeddedTemplate(ast, context) {
22838 return this.visitChildren(context, visit => {
22839 // Ignore reference, variable and providers
22840 visit(ast.attrs);
22841 visit(ast.directives);
22842 visit(ast.children);
22843 });
22844 }
22845 visitElement(ast, context) {
22846 return this.visitChildren(context, visit => {
22847 // Ingnore providers
22848 visit(ast.attrs);
22849 visit(ast.inputs);
22850 visit(ast.outputs);
22851 visit(ast.references);
22852 visit(ast.directives);
22853 visit(ast.children);
22854 });
22855 }
22856 visitDirective(ast, context) {
22857 // Ignore the host properties of a directive
22858 const result = this.visitChildren(context, visit => {
22859 visit(ast.inputs);
22860 });
22861 // We never care about the diretive itself, just its inputs.
22862 if (path[path.length - 1] === ast) {
22863 path.pop();
22864 }
22865 return result;
22866 }
22867 };
22868 templateVisitAll(visitor, ast);
22869 return new AstPath(path, position);
22870 }
22871 /**
22872 * Find the tightest node at the specified `position` from the AST `nodes`, and
22873 * return the path to the node.
22874 * @param nodes HTML AST nodes
22875 * @param position
22876 */
22877 function getPathToNodeAtPosition(nodes, position) {
22878 const path = [];
22879 const visitor = new class extends RecursiveVisitor {
22880 visit(ast) {
22881 const span = spanOf(ast);
22882 if (inSpan(position, span)) {
22883 path.push(ast);
22884 }
22885 else {
22886 // Returning a truthy value here will skip all children and terminate
22887 // the visit.
22888 return true;
22889 }
22890 }
22891 };
22892 visitAll$1(visitor, nodes);
22893 return new AstPath(path, position);
22894 }
22895 /**
22896 * Inverts an object's key-value pairs.
22897 */
22898 function invertMap(obj) {
22899 const result = {};
22900 for (const name of Object.keys(obj)) {
22901 const v = obj[name];
22902 result[v] = name;
22903 }
22904 return result;
22905 }
22906 /**
22907 * Finds the directive member providing a template output binding, if one exists.
22908 * @param info aggregate template AST information
22909 * @param path narrowing
22910 */
22911 function findOutputBinding(binding, path, query) {
22912 const element = path.first(ElementAst);
22913 if (element) {
22914 for (const directive of element.directives) {
22915 const invertedOutputs = invertMap(directive.directive.outputs);
22916 const fieldName = invertedOutputs[binding.name];
22917 if (fieldName) {
22918 const classSymbol = query.getTypeSymbol(directive.directive.type.reference);
22919 if (classSymbol) {
22920 return classSymbol.members().get(fieldName);
22921 }
22922 }
22923 }
22924 }
22925 }
22926 /**
22927 * Returns an absolute path from the text in `node`. If the text is already
22928 * an absolute path, return it as is, otherwise join the path with the filename
22929 * of the source file.
22930 */
22931 function extractAbsoluteFilePath(node) {
22932 const url = node.text;
22933 return path.isAbsolute(url) ? url : path.join(path.dirname(node.getSourceFile().fileName), url);
22934 }
22935
22936 /**
22937 * @license
22938 * Copyright Google LLC All Rights Reserved.
22939 *
22940 * Use of this source code is governed by an MIT-style license that can be
22941 * found in the LICENSE file at https://angular.io/license
22942 */
22943 // AstType calculatetype of the ast given AST element.
22944 class AstType {
22945 constructor(scope, query, context, source) {
22946 this.scope = scope;
22947 this.query = query;
22948 this.context = context;
22949 this.source = source;
22950 this.diagnostics = [];
22951 }
22952 getType(ast) {
22953 return ast.visit(this);
22954 }
22955 getDiagnostics(ast) {
22956 const type = ast.visit(this);
22957 if (this.context.inEvent && type.callable) {
22958 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.callable_expression_expected_method_call));
22959 }
22960 return this.diagnostics;
22961 }
22962 visitUnary(ast) {
22963 // Visit the child to produce diagnostics.
22964 ast.expr.visit(this);
22965 // The unary plus and minus operator are always of type number.
22966 // https://github.com/Microsoft/TypeScript/blob/v1.8.10/doc/spec.md#4.18
22967 switch (ast.operator) {
22968 case '-':
22969 case '+':
22970 return this.query.getBuiltinType(BuiltinType$1.Number);
22971 }
22972 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unrecognized_operator, ast.operator));
22973 return this.anyType;
22974 }
22975 visitBinary(ast) {
22976 const getType = (ast, operation) => {
22977 const type = this.getType(ast);
22978 if (type.nullable) {
22979 switch (operation) {
22980 case '&&':
22981 case '||':
22982 case '==':
22983 case '!=':
22984 case '===':
22985 case '!==':
22986 // Nullable allowed.
22987 break;
22988 default:
22989 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.expression_might_be_null));
22990 break;
22991 }
22992 }
22993 return type;
22994 };
22995 const leftType = getType(ast.left, ast.operation);
22996 const rightType = getType(ast.right, ast.operation);
22997 const leftKind = this.query.getTypeKind(leftType);
22998 const rightKind = this.query.getTypeKind(rightType);
22999 // The following swtich implements operator typing similar to the
23000 // type production tables in the TypeScript specification.
23001 // https://github.com/Microsoft/TypeScript/blob/v1.8.10/doc/spec.md#4.19
23002 const operKind = leftKind << 8 | rightKind;
23003 switch (ast.operation) {
23004 case '*':
23005 case '/':
23006 case '%':
23007 case '-':
23008 case '<<':
23009 case '>>':
23010 case '>>>':
23011 case '&':
23012 case '^':
23013 case '|':
23014 switch (operKind) {
23015 case BuiltinType$1.Any << 8 | BuiltinType$1.Any:
23016 case BuiltinType$1.Number << 8 | BuiltinType$1.Any:
23017 case BuiltinType$1.Any << 8 | BuiltinType$1.Number:
23018 case BuiltinType$1.Number << 8 | BuiltinType$1.Number:
23019 return this.query.getBuiltinType(BuiltinType$1.Number);
23020 default:
23021 let errorAst = ast.left;
23022 switch (leftKind) {
23023 case BuiltinType$1.Any:
23024 case BuiltinType$1.Number:
23025 errorAst = ast.right;
23026 break;
23027 }
23028 this.diagnostics.push(createDiagnostic(errorAst.span, Diagnostic.expected_a_number_type));
23029 return this.anyType;
23030 }
23031 case '+':
23032 switch (operKind) {
23033 case BuiltinType$1.Any << 8 | BuiltinType$1.Any:
23034 case BuiltinType$1.Any << 8 | BuiltinType$1.Boolean:
23035 case BuiltinType$1.Any << 8 | BuiltinType$1.Number:
23036 case BuiltinType$1.Any << 8 | BuiltinType$1.Other:
23037 case BuiltinType$1.Boolean << 8 | BuiltinType$1.Any:
23038 case BuiltinType$1.Number << 8 | BuiltinType$1.Any:
23039 case BuiltinType$1.Other << 8 | BuiltinType$1.Any:
23040 return this.anyType;
23041 case BuiltinType$1.Any << 8 | BuiltinType$1.String:
23042 case BuiltinType$1.Boolean << 8 | BuiltinType$1.String:
23043 case BuiltinType$1.Number << 8 | BuiltinType$1.String:
23044 case BuiltinType$1.String << 8 | BuiltinType$1.Any:
23045 case BuiltinType$1.String << 8 | BuiltinType$1.Boolean:
23046 case BuiltinType$1.String << 8 | BuiltinType$1.Number:
23047 case BuiltinType$1.String << 8 | BuiltinType$1.String:
23048 case BuiltinType$1.String << 8 | BuiltinType$1.Other:
23049 case BuiltinType$1.Other << 8 | BuiltinType$1.String:
23050 return this.query.getBuiltinType(BuiltinType$1.String);
23051 case BuiltinType$1.Number << 8 | BuiltinType$1.Number:
23052 return this.query.getBuiltinType(BuiltinType$1.Number);
23053 case BuiltinType$1.Boolean << 8 | BuiltinType$1.Number:
23054 case BuiltinType$1.Other << 8 | BuiltinType$1.Number:
23055 this.diagnostics.push(createDiagnostic(ast.left.span, Diagnostic.expected_a_number_type));
23056 return this.anyType;
23057 case BuiltinType$1.Number << 8 | BuiltinType$1.Boolean:
23058 case BuiltinType$1.Number << 8 | BuiltinType$1.Other:
23059 this.diagnostics.push(createDiagnostic(ast.right.span, Diagnostic.expected_a_number_type));
23060 return this.anyType;
23061 default:
23062 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.expected_a_string_or_number_type));
23063 return this.anyType;
23064 }
23065 case '>':
23066 case '<':
23067 case '<=':
23068 case '>=':
23069 case '==':
23070 case '!=':
23071 case '===':
23072 case '!==':
23073 if (!(leftKind & rightKind) &&
23074 !((leftKind | rightKind) & (BuiltinType$1.Null | BuiltinType$1.Undefined))) {
23075 // Two values are comparable only if
23076 // - they have some type overlap, or
23077 // - at least one is not defined
23078 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.expected_operands_of_comparable_types_or_any));
23079 }
23080 return this.query.getBuiltinType(BuiltinType$1.Boolean);
23081 case '&&':
23082 return rightType;
23083 case '||':
23084 return this.query.getTypeUnion(leftType, rightType);
23085 }
23086 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unrecognized_operator, ast.operation));
23087 return this.anyType;
23088 }
23089 visitChain(ast) {
23090 // If we are producing diagnostics, visit the children
23091 for (const expr of ast.expressions) {
23092 expr.visit(this);
23093 }
23094 // The type of a chain is always undefined.
23095 return this.query.getBuiltinType(BuiltinType$1.Undefined);
23096 }
23097 visitConditional(ast) {
23098 // The type of a conditional is the union of the true and false conditions.
23099 ast.condition.visit(this);
23100 ast.trueExp.visit(this);
23101 ast.falseExp.visit(this);
23102 return this.query.getTypeUnion(this.getType(ast.trueExp), this.getType(ast.falseExp));
23103 }
23104 visitFunctionCall(ast) {
23105 // The type of a function call is the return type of the selected signature.
23106 // The signature is selected based on the types of the arguments. Angular doesn't
23107 // support contextual typing of arguments so this is simpler than TypeScript's
23108 // version.
23109 const args = ast.args.map(arg => this.getType(arg));
23110 const target = this.getType(ast.target);
23111 if (!target || !target.callable) {
23112 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.call_target_not_callable, this.sourceOf(ast.target), target.name));
23113 return this.anyType;
23114 }
23115 const signature = target.selectSignature(args);
23116 if (signature) {
23117 return signature.result;
23118 }
23119 // TODO: Consider a better error message here. See `typescript_symbols#selectSignature` for more
23120 // details.
23121 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unable_to_resolve_compatible_call_signature));
23122 return this.anyType;
23123 }
23124 visitImplicitReceiver(_ast) {
23125 const _this = this;
23126 // Return a pseudo-symbol for the implicit receiver.
23127 // The members of the implicit receiver are what is defined by the
23128 // scope passed into this class.
23129 return {
23130 name: '$implicit',
23131 kind: 'component',
23132 language: 'ng-template',
23133 type: undefined,
23134 container: undefined,
23135 callable: false,
23136 nullable: false,
23137 public: true,
23138 definition: undefined,
23139 documentation: [],
23140 members() {
23141 return _this.scope;
23142 },
23143 signatures() {
23144 return [];
23145 },
23146 selectSignature(_types) {
23147 return undefined;
23148 },
23149 indexed(_argument) {
23150 return undefined;
23151 },
23152 typeArguments() {
23153 return undefined;
23154 },
23155 };
23156 }
23157 visitThisReceiver(_ast) {
23158 return this.visitImplicitReceiver(_ast);
23159 }
23160 visitInterpolation(ast) {
23161 // If we are producing diagnostics, visit the children.
23162 for (const expr of ast.expressions) {
23163 expr.visit(this);
23164 }
23165 return this.undefinedType;
23166 }
23167 visitKeyedRead(ast) {
23168 const targetType = this.getType(ast.obj);
23169 const keyType = this.getType(ast.key);
23170 const result = targetType.indexed(keyType, ast.key instanceof LiteralPrimitive ? ast.key.value : undefined);
23171 return result || this.anyType;
23172 }
23173 visitKeyedWrite(ast) {
23174 // The write of a type is the type of the value being written.
23175 return this.getType(ast.value);
23176 }
23177 visitLiteralArray(ast) {
23178 // A type literal is an array type of the union of the elements
23179 return this.query.getArrayType(this.query.getTypeUnion(...ast.expressions.map(element => this.getType(element))));
23180 }
23181 visitLiteralMap(ast) {
23182 // If we are producing diagnostics, visit the children
23183 for (const value of ast.values) {
23184 value.visit(this);
23185 }
23186 // TODO: Return a composite type.
23187 return this.anyType;
23188 }
23189 visitLiteralPrimitive(ast) {
23190 // The type of a literal primitive depends on the value of the literal.
23191 switch (ast.value) {
23192 case true:
23193 case false:
23194 return this.query.getBuiltinType(BuiltinType$1.Boolean);
23195 case null:
23196 return this.query.getBuiltinType(BuiltinType$1.Null);
23197 case undefined:
23198 return this.query.getBuiltinType(BuiltinType$1.Undefined);
23199 default:
23200 switch (typeof ast.value) {
23201 case 'string':
23202 return this.query.getBuiltinType(BuiltinType$1.String);
23203 case 'number':
23204 return this.query.getBuiltinType(BuiltinType$1.Number);
23205 default:
23206 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unrecognized_primitive, typeof ast.value));
23207 return this.anyType;
23208 }
23209 }
23210 }
23211 visitMethodCall(ast) {
23212 return this.resolveMethodCall(this.getType(ast.receiver), ast);
23213 }
23214 visitPipe(ast) {
23215 // The type of a pipe node is the return type of the pipe's transform method. The table returned
23216 // by getPipes() is expected to contain symbols with the corresponding transform method type.
23217 const pipe = this.query.getPipes().get(ast.name);
23218 if (!pipe) {
23219 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.no_pipe_found, ast.name));
23220 return this.anyType;
23221 }
23222 const expType = this.getType(ast.exp);
23223 const signature = pipe.selectSignature([expType].concat(ast.args.map(arg => this.getType(arg))));
23224 if (!signature) {
23225 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unable_to_resolve_signature, ast.name));
23226 return this.anyType;
23227 }
23228 return signature.result;
23229 }
23230 visitPrefixNot(ast) {
23231 // If we are producing diagnostics, visit the children
23232 ast.expression.visit(this);
23233 // The type of a prefix ! is always boolean.
23234 return this.query.getBuiltinType(BuiltinType$1.Boolean);
23235 }
23236 visitNonNullAssert(ast) {
23237 const expressionType = this.getType(ast.expression);
23238 return this.query.getNonNullableType(expressionType);
23239 }
23240 visitPropertyRead(ast) {
23241 return this.resolvePropertyRead(this.getType(ast.receiver), ast);
23242 }
23243 visitPropertyWrite(ast) {
23244 // The type of a write is the type of the value being written.
23245 return this.getType(ast.value);
23246 }
23247 visitQuote(_ast) {
23248 // The type of a quoted expression is any.
23249 return this.query.getBuiltinType(BuiltinType$1.Any);
23250 }
23251 visitSafeMethodCall(ast) {
23252 return this.resolveMethodCall(this.query.getNonNullableType(this.getType(ast.receiver)), ast);
23253 }
23254 visitSafePropertyRead(ast) {
23255 return this.resolvePropertyRead(this.query.getNonNullableType(this.getType(ast.receiver)), ast);
23256 }
23257 /**
23258 * Gets the source of an expession AST.
23259 * The AST's sourceSpan is relative to the start of the template source code, which is contained
23260 * at this.source.
23261 */
23262 sourceOf(ast) {
23263 return this.source.substring(ast.sourceSpan.start, ast.sourceSpan.end);
23264 }
23265 get anyType() {
23266 let result = this._anyType;
23267 if (!result) {
23268 result = this._anyType = this.query.getBuiltinType(BuiltinType$1.Any);
23269 }
23270 return result;
23271 }
23272 get undefinedType() {
23273 let result = this._undefinedType;
23274 if (!result) {
23275 result = this._undefinedType = this.query.getBuiltinType(BuiltinType$1.Undefined);
23276 }
23277 return result;
23278 }
23279 resolveMethodCall(receiverType, ast) {
23280 if (this.isAny(receiverType)) {
23281 return this.anyType;
23282 }
23283 const methodType = this.resolvePropertyRead(receiverType, ast);
23284 if (!methodType) {
23285 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.could_not_resolve_type, ast.name));
23286 return this.anyType;
23287 }
23288 if (this.isAny(methodType)) {
23289 return this.anyType;
23290 }
23291 if (!methodType.callable) {
23292 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_not_callable, ast.name));
23293 return this.anyType;
23294 }
23295 const signature = methodType.selectSignature(ast.args.map(arg => this.getType(arg)));
23296 if (!signature) {
23297 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unable_to_resolve_signature, ast.name));
23298 return this.anyType;
23299 }
23300 return signature.result;
23301 }
23302 resolvePropertyRead(receiverType, ast) {
23303 if (this.isAny(receiverType)) {
23304 return this.anyType;
23305 }
23306 // The type of a property read is the seelcted member's type.
23307 const member = receiverType.members().get(ast.name);
23308 if (!member) {
23309 if (receiverType.name === '$implicit') {
23310 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_not_defined_in_app_context, ast.name));
23311 }
23312 else if (receiverType.nullable && ast.receiver instanceof PropertyRead) {
23313 const receiver = ast.receiver.name;
23314 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_possibly_undefined, receiver, `${receiver}?.${ast.name}`, `${receiver}!.${ast.name}`));
23315 }
23316 else {
23317 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_not_defined_on_receiver, ast.name, receiverType.name));
23318 }
23319 return this.anyType;
23320 }
23321 if (!member.public) {
23322 const container = receiverType.name === '$implicit' ? 'the component' : `'${receiverType.name}'`;
23323 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_is_private, ast.name, container));
23324 }
23325 return member.type;
23326 }
23327 isAny(symbol) {
23328 return !symbol || this.query.getTypeKind(symbol) === BuiltinType$1.Any ||
23329 (!!symbol.type && this.isAny(symbol.type));
23330 }
23331 }
23332 function refinedSpan(ast) {
23333 // nameSpan is an absolute span, but the spans returned by the expression visitor are expected to
23334 // be relative to the start of the expression.
23335 // TODO: migrate to only using absolute spans
23336 const absoluteOffset = ast.sourceSpan.start - ast.span.start;
23337 if (ast instanceof ASTWithName) {
23338 return offsetSpan(ast.nameSpan, -absoluteOffset);
23339 }
23340 return offsetSpan(ast.sourceSpan, -absoluteOffset);
23341 }
23342
23343 /**
23344 * @license
23345 * Copyright Google LLC All Rights Reserved.
23346 *
23347 * Use of this source code is governed by an MIT-style license that can be
23348 * found in the LICENSE file at https://angular.io/license
23349 */
23350 function getTemplateExpressionDiagnostics(info) {
23351 const visitor = new ExpressionDiagnosticsVisitor(info, (path) => getExpressionScope(info, path));
23352 templateVisitAll(visitor, info.templateAst);
23353 return visitor.diagnostics;
23354 }
23355 function getReferences(info) {
23356 const result = [];
23357 function processReferences(references) {
23358 for (const reference of references) {
23359 let type = undefined;
23360 if (reference.value) {
23361 type = info.query.getTypeSymbol(tokenReference(reference.value));
23362 }
23363 result.push({
23364 name: reference.name,
23365 kind: 'reference',
23366 type: type || info.query.getBuiltinType(BuiltinType$1.Any),
23367 get definition() {
23368 return getDefinitionOf(info, reference);
23369 }
23370 });
23371 }
23372 }
23373 const visitor = new class extends RecursiveTemplateAstVisitor {
23374 visitEmbeddedTemplate(ast, context) {
23375 super.visitEmbeddedTemplate(ast, context);
23376 processReferences(ast.references);
23377 }
23378 visitElement(ast, context) {
23379 super.visitElement(ast, context);
23380 processReferences(ast.references);
23381 }
23382 };
23383 templateVisitAll(visitor, info.templateAst);
23384 return result;
23385 }
23386 function getDefinitionOf(info, ast) {
23387 if (info.fileName) {
23388 const templateOffset = info.offset;
23389 return [{
23390 fileName: info.fileName,
23391 span: {
23392 start: ast.sourceSpan.start.offset + templateOffset,
23393 end: ast.sourceSpan.end.offset + templateOffset
23394 }
23395 }];
23396 }
23397 }
23398 /**
23399 * Resolve all variable declarations in a template by traversing the specified
23400 * `path`.
23401 * @param info
23402 * @param path template AST path
23403 */
23404 function getVarDeclarations(info, path) {
23405 const results = [];
23406 for (let current = path.head; current; current = path.childOf(current)) {
23407 if (!(current instanceof EmbeddedTemplateAst)) {
23408 continue;
23409 }
23410 for (const variable of current.variables) {
23411 let symbol = getVariableTypeFromDirectiveContext(variable.value, info.query, current);
23412 const kind = info.query.getTypeKind(symbol);
23413 if (kind === BuiltinType$1.Any || kind === BuiltinType$1.Unbound) {
23414 // For special cases such as ngFor and ngIf, the any type is not very useful.
23415 // We can do better by resolving the binding value.
23416 const symbolsInScope = info.query.mergeSymbolTable([
23417 info.members,
23418 // Since we are traversing the AST path from head to tail, any variables
23419 // that have been declared so far are also in scope.
23420 info.query.createSymbolTable(results),
23421 ]);
23422 symbol = refinedVariableType(variable.value, symbolsInScope, info, current);
23423 }
23424 results.push({
23425 name: variable.name,
23426 kind: 'variable',
23427 type: symbol,
23428 get definition() {
23429 return getDefinitionOf(info, variable);
23430 },
23431 });
23432 }
23433 }
23434 return results;
23435 }
23436 /**
23437 * Resolve the type for the variable in `templateElement` by finding the structural
23438 * directive which has the context member. Returns any when not found.
23439 * @param value variable value name
23440 * @param query type symbol query
23441 * @param templateElement
23442 */
23443 function getVariableTypeFromDirectiveContext(value, query, templateElement) {
23444 for (const { directive } of templateElement.directives) {
23445 const context = query.getTemplateContext(directive.type.reference);
23446 if (context) {
23447 const member = context.get(value);
23448 if (member && member.type) {
23449 return member.type;
23450 }
23451 }
23452 }
23453 return query.getBuiltinType(BuiltinType$1.Any);
23454 }
23455 /**
23456 * Resolve a more specific type for the variable in `templateElement` by inspecting
23457 * all variables that are in scope in the `mergedTable`. This function is a special
23458 * case for `ngFor` and `ngIf`. If resolution fails, return the `any` type.
23459 * @param value variable value name
23460 * @param mergedTable symbol table for all variables in scope
23461 * @param info available template information
23462 * @param templateElement
23463 */
23464 function refinedVariableType(value, mergedTable, info, templateElement) {
23465 if (value === '$implicit') {
23466 // Special case: ngFor directive
23467 const ngForDirective = templateElement.directives.find(d => {
23468 const name = identifierName(d.directive.type);
23469 return name == 'NgFor' || name == 'NgForOf';
23470 });
23471 if (ngForDirective) {
23472 const ngForOfBinding = ngForDirective.inputs.find(i => i.directiveName == 'ngForOf');
23473 if (ngForOfBinding) {
23474 // Check if there is a known type for the ngFor binding.
23475 const bindingType = new AstType(mergedTable, info.query, {}, info.source).getType(ngForOfBinding.value);
23476 if (bindingType) {
23477 const result = info.query.getElementType(bindingType);
23478 if (result) {
23479 return result;
23480 }
23481 }
23482 }
23483 }
23484 }
23485 if (value === 'ngIf' || value === '$implicit') {
23486 const ngIfDirective = templateElement.directives.find(d => identifierName(d.directive.type) === 'NgIf');
23487 if (ngIfDirective) {
23488 // Special case: ngIf directive. The NgIf structural directive owns a template context with
23489 // "$implicit" and "ngIf" members. These properties are typed as generics. Until the language
23490 // service uses an Ivy and TypecheckBlock backend, we cannot bind these values to a concrete
23491 // type without manual inference. To get the concrete type, look up the type of the "ngIf"
23492 // import on the NgIf directive bound to the template.
23493 //
23494 // See @angular/common/ng_if.ts for more information.
23495 const ngIfBinding = ngIfDirective.inputs.find(i => i.directiveName === 'ngIf');
23496 if (ngIfBinding) {
23497 // Check if there is a known type bound to the ngIf input.
23498 const bindingType = new AstType(mergedTable, info.query, {}, info.source).getType(ngIfBinding.value);
23499 if (bindingType) {
23500 return bindingType;
23501 }
23502 }
23503 }
23504 }
23505 // We can't do better, return any
23506 return info.query.getBuiltinType(BuiltinType$1.Any);
23507 }
23508 function getEventDeclaration(info, path) {
23509 const event = path.tail;
23510 if (!(event instanceof BoundEventAst)) {
23511 // No event available in this context.
23512 return;
23513 }
23514 const genericEvent = {
23515 name: '$event',
23516 kind: 'variable',
23517 type: info.query.getBuiltinType(BuiltinType$1.Any),
23518 };
23519 const outputSymbol = findOutputBinding(event, path, info.query);
23520 if (!outputSymbol) {
23521 // The `$event` variable doesn't belong to an output, so its type can't be refined.
23522 // TODO: type `$event` variables in bindings to DOM events.
23523 return genericEvent;
23524 }
23525 // The raw event type is wrapped in a generic, like EventEmitter<T> or Observable<T>.
23526 const ta = outputSymbol.typeArguments();
23527 if (!ta || ta.length !== 1)
23528 return genericEvent;
23529 const eventType = ta[0];
23530 return Object.assign(Object.assign({}, genericEvent), { type: eventType });
23531 }
23532 /**
23533 * Returns the symbols available in a particular scope of a template.
23534 * @param info parsed template information
23535 * @param path path of template nodes narrowing to the context the expression scope should be
23536 * derived for.
23537 */
23538 function getExpressionScope(info, path) {
23539 let result = info.members;
23540 const references = getReferences(info);
23541 const variables = getVarDeclarations(info, path);
23542 const event = getEventDeclaration(info, path);
23543 if (references.length || variables.length || event) {
23544 const referenceTable = info.query.createSymbolTable(references);
23545 const variableTable = info.query.createSymbolTable(variables);
23546 const eventsTable = info.query.createSymbolTable(event ? [event] : []);
23547 result = info.query.mergeSymbolTable([result, referenceTable, variableTable, eventsTable]);
23548 }
23549 return result;
23550 }
23551 class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor {
23552 constructor(info, getExpressionScope) {
23553 super();
23554 this.info = info;
23555 this.getExpressionScope = getExpressionScope;
23556 this.diagnostics = [];
23557 this.path = new AstPath([]);
23558 }
23559 visitDirective(ast, context) {
23560 // Override the default child visitor to ignore the host properties of a directive.
23561 if (ast.inputs && ast.inputs.length) {
23562 templateVisitAll(this, ast.inputs, context);
23563 }
23564 }
23565 visitBoundText(ast) {
23566 this.push(ast);
23567 this.diagnoseExpression(ast.value, ast.sourceSpan.start.offset, false);
23568 this.pop();
23569 }
23570 visitDirectiveProperty(ast) {
23571 this.push(ast);
23572 this.diagnoseExpression(ast.value, this.attributeValueLocation(ast), false);
23573 this.pop();
23574 }
23575 visitElementProperty(ast) {
23576 this.push(ast);
23577 this.diagnoseExpression(ast.value, this.attributeValueLocation(ast), false);
23578 this.pop();
23579 }
23580 visitEvent(ast) {
23581 this.push(ast);
23582 this.diagnoseExpression(ast.handler, this.attributeValueLocation(ast), true);
23583 this.pop();
23584 }
23585 visitVariable(ast) {
23586 const directive = this.directiveSummary;
23587 if (directive && ast.value) {
23588 const context = this.info.query.getTemplateContext(directive.type.reference);
23589 if (context && !context.has(ast.value)) {
23590 const missingMember = ast.value === '$implicit' ? 'an implicit value' : `a member called '${ast.value}'`;
23591 const span = this.absSpan(spanOf$1(ast.sourceSpan));
23592 this.diagnostics.push(createDiagnostic(span, Diagnostic.template_context_missing_member, directive.type.reference.name, missingMember));
23593 }
23594 }
23595 }
23596 visitElement(ast, context) {
23597 this.push(ast);
23598 super.visitElement(ast, context);
23599 this.pop();
23600 }
23601 visitEmbeddedTemplate(ast, context) {
23602 const previousDirectiveSummary = this.directiveSummary;
23603 this.push(ast);
23604 // Find directive that references this template
23605 this.directiveSummary =
23606 ast.directives.map(d => d.directive).find(d => hasTemplateReference(d.type));
23607 // Process children
23608 super.visitEmbeddedTemplate(ast, context);
23609 this.pop();
23610 this.directiveSummary = previousDirectiveSummary;
23611 }
23612 attributeValueLocation(ast) {
23613 const path = getPathToNodeAtPosition(this.info.htmlAst, ast.sourceSpan.start.offset);
23614 const last = path.tail;
23615 if (last instanceof Attribute && last.valueSpan) {
23616 return last.valueSpan.start.offset;
23617 }
23618 return ast.sourceSpan.start.offset;
23619 }
23620 diagnoseExpression(ast, offset, inEvent) {
23621 const scope = this.getExpressionScope(this.path, inEvent);
23622 const analyzer = new AstType(scope, this.info.query, { inEvent }, this.info.source);
23623 for (const diagnostic of analyzer.getDiagnostics(ast)) {
23624 diagnostic.span = this.absSpan(diagnostic.span, offset);
23625 this.diagnostics.push(diagnostic);
23626 }
23627 }
23628 push(ast) {
23629 this.path.push(ast);
23630 }
23631 pop() {
23632 this.path.pop();
23633 }
23634 absSpan(span, additionalOffset = 0) {
23635 return {
23636 start: span.start + this.info.offset + additionalOffset,
23637 end: span.end + this.info.offset + additionalOffset,
23638 };
23639 }
23640 }
23641 function hasTemplateReference(type) {
23642 if (type.diDeps) {
23643 for (let diDep of type.diDeps) {
23644 if (diDep.token && diDep.token.identifier &&
23645 identifierName(diDep.token.identifier) == 'TemplateRef')
23646 return true;
23647 }
23648 }
23649 return false;
23650 }
23651 function spanOf$1(sourceSpan) {
23652 return { start: sourceSpan.start.offset, end: sourceSpan.end.offset };
23653 }
23654
23655 /**
23656 * @license
23657 * Copyright Google LLC All Rights Reserved.
23658 *
23659 * Use of this source code is governed by an MIT-style license that can be
23660 * found in the LICENSE file at https://angular.io/license
23661 */
23662 /**
23663 * The type of Angular directive. Used for QuickInfo in template.
23664 */
23665 var DirectiveKind;
23666 (function (DirectiveKind) {
23667 DirectiveKind["COMPONENT"] = "component";
23668 DirectiveKind["DIRECTIVE"] = "directive";
23669 DirectiveKind["EVENT"] = "event";
23670 })(DirectiveKind || (DirectiveKind = {}));
23671 /**
23672 * ScriptElementKind for completion.
23673 */
23674 var CompletionKind;
23675 (function (CompletionKind) {
23676 CompletionKind["ANGULAR_ELEMENT"] = "angular element";
23677 CompletionKind["ATTRIBUTE"] = "attribute";
23678 CompletionKind["COMPONENT"] = "component";
23679 CompletionKind["ELEMENT"] = "element";
23680 CompletionKind["ENTITY"] = "entity";
23681 CompletionKind["HTML_ATTRIBUTE"] = "html attribute";
23682 CompletionKind["HTML_ELEMENT"] = "html element";
23683 CompletionKind["KEY"] = "key";
23684 CompletionKind["METHOD"] = "method";
23685 CompletionKind["PIPE"] = "pipe";
23686 CompletionKind["PROPERTY"] = "property";
23687 CompletionKind["REFERENCE"] = "reference";
23688 CompletionKind["TYPE"] = "type";
23689 CompletionKind["VARIABLE"] = "variable";
23690 })(CompletionKind || (CompletionKind = {}));
23691
23692 /**
23693 * @license
23694 * Copyright Google LLC All Rights Reserved.
23695 *
23696 * Use of this source code is governed by an MIT-style license that can be
23697 * found in the LICENSE file at https://angular.io/license
23698 */
23699 function findAstAt(ast, position, excludeEmpty = false) {
23700 const path = [];
23701 const visitor = new class extends RecursiveAstVisitor {
23702 visit(ast) {
23703 if ((!excludeEmpty || ast.sourceSpan.start < ast.sourceSpan.end) &&
23704 inSpan(position, ast.sourceSpan)) {
23705 const isNotNarrower = path.length && !isNarrower(ast.span, path[path.length - 1].span);
23706 if (!isNotNarrower) {
23707 path.push(ast);
23708 }
23709 ast.visit(this);
23710 }
23711 }
23712 };
23713 // We never care about the ASTWithSource node and its visit() method calls its ast's visit so
23714 // the visit() method above would never see it.
23715 if (ast instanceof ASTWithSource) {
23716 ast = ast.ast;
23717 }
23718 // `Interpolation` is useless here except the `expressions` of it.
23719 if (ast instanceof Interpolation) {
23720 ast = ast.expressions.filter((_ast) => inSpan(position, _ast.sourceSpan))[0];
23721 }
23722 if (ast) {
23723 visitor.visit(ast);
23724 }
23725 return new AstPath(path, position);
23726 }
23727 function getExpressionCompletions(scope, ast, position, templateInfo) {
23728 const path = findAstAt(ast, position);
23729 if (path.empty)
23730 return undefined;
23731 const tail = path.tail;
23732 let result = scope;
23733 function getType(ast) {
23734 return new AstType(scope, templateInfo.query, {}, templateInfo.source).getType(ast);
23735 }
23736 // If the completion request is in a not in a pipe or property access then the global scope
23737 // (that is the scope of the implicit receiver) is the right scope as the user is typing the
23738 // beginning of an expression.
23739 tail.visit({
23740 visitUnary(_ast) { },
23741 visitBinary(_ast) { },
23742 visitChain(_ast) { },
23743 visitConditional(_ast) { },
23744 visitFunctionCall(_ast) { },
23745 visitImplicitReceiver(_ast) { },
23746 visitThisReceiver(_ast) { },
23747 visitInterpolation(_ast) {
23748 result = undefined;
23749 },
23750 visitKeyedRead(_ast) { },
23751 visitKeyedWrite(_ast) { },
23752 visitLiteralArray(_ast) { },
23753 visitLiteralMap(_ast) { },
23754 visitLiteralPrimitive(ast) {
23755 // The type `LiteralPrimitive` include the `ERROR`, and it's wrapped as `string`.
23756 // packages/compiler/src/template_parser/binding_parser.ts#L308
23757 // So exclude the `ERROR` here.
23758 if (typeof ast.value === 'string' &&
23759 ast.value ===
23760 templateInfo.source.slice(ast.sourceSpan.start + 1, ast.sourceSpan.end - 1)) {
23761 result = undefined;
23762 }
23763 },
23764 visitMethodCall(_ast) { },
23765 visitPipe(ast) {
23766 if (position >= ast.exp.span.end &&
23767 (!ast.args || !ast.args.length || position < ast.args[0].span.start)) {
23768 // We are in a position a pipe name is expected.
23769 result = templateInfo.query.getPipes();
23770 }
23771 },
23772 visitPrefixNot(_ast) { },
23773 visitNonNullAssert(_ast) { },
23774 visitPropertyRead(ast) {
23775 const receiverType = getType(ast.receiver);
23776 result = receiverType ? receiverType.members() : scope;
23777 },
23778 visitPropertyWrite(ast) {
23779 const receiverType = getType(ast.receiver);
23780 result = receiverType ? receiverType.members() : scope;
23781 },
23782 visitQuote(_ast) {
23783 // For a quote, return the members of any (if there are any).
23784 result = templateInfo.query.getBuiltinType(BuiltinType$1.Any).members();
23785 },
23786 visitSafeMethodCall(ast) {
23787 const receiverType = getType(ast.receiver);
23788 result = receiverType ? receiverType.members() : scope;
23789 },
23790 visitSafePropertyRead(ast) {
23791 const receiverType = getType(ast.receiver);
23792 result = receiverType ? receiverType.members() : scope;
23793 },
23794 });
23795 return result && result.values();
23796 }
23797 /**
23798 * Retrieves the expression symbol at a particular position in a template.
23799 *
23800 * @param scope symbols in scope of the template
23801 * @param ast template AST
23802 * @param position absolute location in template to retrieve symbol at
23803 * @param query type symbol query for the template scope
23804 */
23805 function getExpressionSymbol(scope, ast, position, templateInfo) {
23806 const path = findAstAt(ast, position, /* excludeEmpty */ true);
23807 if (path.empty)
23808 return undefined;
23809 const tail = path.tail;
23810 function getType(ast) {
23811 return new AstType(scope, templateInfo.query, {}, templateInfo.source).getType(ast);
23812 }
23813 function spanFromName(ast) {
23814 // `nameSpan` is an absolute span, but the span expected by the result of this method is
23815 // relative to the start of the expression.
23816 // TODO(ayazhafiz): migrate to only using absolute spans
23817 const offset = ast.sourceSpan.start - ast.span.start;
23818 return {
23819 start: ast.nameSpan.start - offset,
23820 end: ast.nameSpan.end - offset,
23821 };
23822 }
23823 let symbol = undefined;
23824 let span = undefined;
23825 // If the completion request is in a not in a pipe or property access then the global scope
23826 // (that is the scope of the implicit receiver) is the right scope as the user is typing the
23827 // beginning of an expression.
23828 tail.visit({
23829 visitUnary(_ast) { },
23830 visitBinary(_ast) { },
23831 visitChain(_ast) { },
23832 visitConditional(_ast) { },
23833 visitFunctionCall(_ast) { },
23834 visitImplicitReceiver(_ast) { },
23835 visitThisReceiver(_ast) { },
23836 visitInterpolation(_ast) { },
23837 visitKeyedRead(_ast) { },
23838 visitKeyedWrite(_ast) { },
23839 visitLiteralArray(_ast) { },
23840 visitLiteralMap(_ast) { },
23841 visitLiteralPrimitive(_ast) { },
23842 visitMethodCall(ast) {
23843 const receiverType = getType(ast.receiver);
23844 symbol = receiverType && receiverType.members().get(ast.name);
23845 span = spanFromName(ast);
23846 },
23847 visitPipe(ast) {
23848 if (inSpan(position, ast.nameSpan, /* exclusive */ true)) {
23849 // We are in a position a pipe name is expected.
23850 const pipes = templateInfo.query.getPipes();
23851 symbol = pipes.get(ast.name);
23852 span = spanFromName(ast);
23853 }
23854 },
23855 visitPrefixNot(_ast) { },
23856 visitNonNullAssert(_ast) { },
23857 visitPropertyRead(ast) {
23858 const receiverType = getType(ast.receiver);
23859 symbol = receiverType && receiverType.members().get(ast.name);
23860 span = spanFromName(ast);
23861 },
23862 visitPropertyWrite(ast) {
23863 const receiverType = getType(ast.receiver);
23864 symbol = receiverType && receiverType.members().get(ast.name);
23865 span = spanFromName(ast);
23866 },
23867 visitQuote(_ast) { },
23868 visitSafeMethodCall(ast) {
23869 const receiverType = getType(ast.receiver);
23870 symbol = receiverType && receiverType.members().get(ast.name);
23871 span = spanFromName(ast);
23872 },
23873 visitSafePropertyRead(ast) {
23874 const receiverType = getType(ast.receiver);
23875 symbol = receiverType && receiverType.members().get(ast.name);
23876 span = spanFromName(ast);
23877 },
23878 });
23879 if (symbol && span) {
23880 return { symbol, span };
23881 }
23882 }
23883
23884 /**
23885 * @license
23886 * Copyright Google LLC All Rights Reserved.
23887 *
23888 * Use of this source code is governed by an MIT-style license that can be
23889 * found in the LICENSE file at https://angular.io/license
23890 */
23891 const values = [
23892 'ID',
23893 'CDATA',
23894 'NAME',
23895 ['ltr', 'rtl'],
23896 ['rect', 'circle', 'poly', 'default'],
23897 'NUMBER',
23898 ['nohref'],
23899 ['ismap'],
23900 ['declare'],
23901 ['DATA', 'REF', 'OBJECT'],
23902 ['GET', 'POST'],
23903 'IDREF',
23904 ['TEXT', 'PASSWORD', 'CHECKBOX', 'RADIO', 'SUBMIT', 'RESET', 'FILE', 'HIDDEN', 'IMAGE', 'BUTTON'],
23905 ['checked'],
23906 ['disabled'],
23907 ['readonly'],
23908 ['multiple'],
23909 ['selected'],
23910 ['button', 'submit', 'reset'],
23911 ['void', 'above', 'below', 'hsides', 'lhs', 'rhs', 'vsides', 'box', 'border'],
23912 ['none', 'groups', 'rows', 'cols', 'all'],
23913 ['left', 'center', 'right', 'justify', 'char'],
23914 ['top', 'middle', 'bottom', 'baseline'],
23915 'IDREFS',
23916 ['row', 'col', 'rowgroup', 'colgroup'],
23917 ['defer']
23918 ];
23919 const groups = [
23920 { id: 0 },
23921 {
23922 onclick: 1,
23923 ondblclick: 1,
23924 onmousedown: 1,
23925 onmouseup: 1,
23926 onmouseover: 1,
23927 onmousemove: 1,
23928 onmouseout: 1,
23929 onkeypress: 1,
23930 onkeydown: 1,
23931 onkeyup: 1
23932 },
23933 { lang: 2, dir: 3 },
23934 { onload: 1, onunload: 1 },
23935 { name: 1 },
23936 { href: 1 },
23937 { type: 1 },
23938 { alt: 1 },
23939 { tabindex: 5 },
23940 { media: 1 },
23941 { nohref: 6 },
23942 { usemap: 1 },
23943 { src: 1 },
23944 { onfocus: 1, onblur: 1 },
23945 { charset: 1 },
23946 { declare: 8, classid: 1, codebase: 1, data: 1, codetype: 1, archive: 1, standby: 1 },
23947 { title: 1 },
23948 { value: 1 },
23949 { cite: 1 },
23950 { datetime: 1 },
23951 { accept: 1 },
23952 { shape: 4, coords: 1 },
23953 { for: 11
23954 },
23955 { action: 1, method: 10, enctype: 1, onsubmit: 1, onreset: 1, 'accept-charset': 1 },
23956 { valuetype: 9 },
23957 { longdesc: 1 },
23958 { width: 1 },
23959 { disabled: 14 },
23960 { readonly: 15, onselect: 1 },
23961 { accesskey: 1 },
23962 { size: 5, multiple: 16 },
23963 { onchange: 1 },
23964 { label: 1 },
23965 { selected: 17 },
23966 { type: 12, checked: 13, size: 1, maxlength: 5 },
23967 { rows: 5, cols: 5 },
23968 { type: 18 },
23969 { height: 1 },
23970 { summary: 1, border: 1, frame: 19, rules: 20, cellspacing: 1, cellpadding: 1, datapagesize: 1 },
23971 { align: 21, char: 1, charoff: 1, valign: 22 },
23972 { span: 5 },
23973 { abbr: 1, axis: 1, headers: 23, scope: 24, rowspan: 5, colspan: 5 },
23974 { profile: 1 },
23975 { 'http-equiv': 2, name: 2, content: 1, scheme: 1 },
23976 { class: 1, style: 1 },
23977 { hreflang: 2, rel: 1, rev: 1 },
23978 { ismap: 7 },
23979 {
23980 defer: 25, event: 1, for: 1
23981 }
23982 ];
23983 const elements = {
23984 TT: [0, 1, 2, 16, 44],
23985 I: [0, 1, 2, 16, 44],
23986 B: [0, 1, 2, 16, 44],
23987 BIG: [0, 1, 2, 16, 44],
23988 SMALL: [0, 1, 2, 16, 44],
23989 EM: [0, 1, 2, 16, 44],
23990 STRONG: [0, 1, 2, 16, 44],
23991 DFN: [0, 1, 2, 16, 44],
23992 CODE: [0, 1, 2, 16, 44],
23993 SAMP: [0, 1, 2, 16, 44],
23994 KBD: [0, 1, 2, 16, 44],
23995 VAR: [0, 1, 2, 16, 44],
23996 CITE: [0, 1, 2, 16, 44],
23997 ABBR: [0, 1, 2, 16, 44],
23998 ACRONYM: [0, 1, 2, 16, 44],
23999 SUB: [0, 1, 2, 16, 44],
24000 SUP: [0, 1, 2, 16, 44],
24001 SPAN: [0, 1, 2, 16, 44],
24002 BDO: [0, 2, 16, 44],
24003 BR: [0, 16, 44],
24004 BODY: [0, 1, 2, 3, 16, 44],
24005 ADDRESS: [0, 1, 2, 16, 44],
24006 DIV: [0, 1, 2, 16, 44],
24007 A: [0, 1, 2, 4, 5, 6, 8, 13, 14, 16, 21, 29, 44, 45],
24008 MAP: [0, 1, 2, 4, 16, 44],
24009 AREA: [0, 1, 2, 5, 7, 8, 10, 13, 16, 21, 29, 44],
24010 LINK: [0, 1, 2, 5, 6, 9, 14, 16, 44, 45],
24011 IMG: [0, 1, 2, 4, 7, 11, 12, 16, 25, 26, 37, 44, 46],
24012 OBJECT: [0, 1, 2, 4, 6, 8, 11, 15, 16, 26, 37, 44],
24013 PARAM: [0, 4, 6, 17, 24],
24014 HR: [0, 1, 2, 16, 44],
24015 P: [0, 1, 2, 16, 44],
24016 H1: [0, 1, 2, 16, 44],
24017 H2: [0, 1, 2, 16, 44],
24018 H3: [0, 1, 2, 16, 44],
24019 H4: [0, 1, 2, 16, 44],
24020 H5: [0, 1, 2, 16, 44],
24021 H6: [0, 1, 2, 16, 44],
24022 PRE: [0, 1, 2, 16, 44],
24023 Q: [0, 1, 2, 16, 18, 44],
24024 BLOCKQUOTE: [0, 1, 2, 16, 18, 44],
24025 INS: [0, 1, 2, 16, 18, 19, 44],
24026 DEL: [0, 1, 2, 16, 18, 19, 44],
24027 DL: [0, 1, 2, 16, 44],
24028 DT: [0, 1, 2, 16, 44],
24029 DD: [0, 1, 2, 16, 44],
24030 OL: [0, 1, 2, 16, 44],
24031 UL: [0, 1, 2, 16, 44],
24032 LI: [0, 1, 2, 16, 44],
24033 FORM: [0, 1, 2, 4, 16, 20, 23, 44],
24034 LABEL: [0, 1, 2, 13, 16, 22, 29, 44],
24035 INPUT: [0, 1, 2, 4, 7, 8, 11, 12, 13, 16, 17, 20, 27, 28, 29, 31, 34, 44, 46],
24036 SELECT: [0, 1, 2, 4, 8, 13, 16, 27, 30, 31, 44],
24037 OPTGROUP: [0, 1, 2, 16, 27, 32, 44],
24038 OPTION: [0, 1, 2, 16, 17, 27, 32, 33, 44],
24039 TEXTAREA: [0, 1, 2, 4, 8, 13, 16, 27, 28, 29, 31, 35, 44],
24040 FIELDSET: [0, 1, 2, 16, 44],
24041 LEGEND: [0, 1, 2, 16, 29, 44],
24042 BUTTON: [0, 1, 2, 4, 8, 13, 16, 17, 27, 29, 36, 44],
24043 TABLE: [0, 1, 2, 16, 26, 38, 44],
24044 CAPTION: [0, 1, 2, 16, 44],
24045 COLGROUP: [0, 1, 2, 16, 26, 39, 40, 44],
24046 COL: [0, 1, 2, 16, 26, 39, 40, 44],
24047 THEAD: [0, 1, 2, 16, 39, 44],
24048 TBODY: [0, 1, 2, 16, 39, 44],
24049 TFOOT: [0, 1, 2, 16, 39, 44],
24050 TR: [0, 1, 2, 16, 39, 44],
24051 TH: [0, 1, 2, 16, 39, 41, 44],
24052 TD: [0, 1, 2, 16, 39, 41, 44],
24053 HEAD: [2, 42],
24054 TITLE: [2],
24055 BASE: [5],
24056 META: [2, 43],
24057 STYLE: [2, 6, 9, 16],
24058 SCRIPT: [6, 12, 14, 47],
24059 NOSCRIPT: [0, 1, 2, 16, 44],
24060 HTML: [2]
24061 };
24062 const defaultAttributes = [0, 1, 2, 4];
24063 function elementNames() {
24064 return Object.keys(elements).sort().map(v => v.toLowerCase());
24065 }
24066 function compose(indexes) {
24067 const result = {};
24068 if (indexes) {
24069 for (let index of indexes) {
24070 const group = groups[index];
24071 for (let name in group)
24072 if (group.hasOwnProperty(name))
24073 result[name] = values[group[name]];
24074 }
24075 }
24076 return result;
24077 }
24078 function attributeNames(element) {
24079 return Object.keys(compose(elements[element.toUpperCase()] || defaultAttributes)).sort();
24080 }
24081 // This section is describes the DOM property surface of a DOM element and is derivgulp formated
24082 // from
24083 // from the SCHEMA strings from the security context information. SCHEMA is copied here because
24084 // it would be an unnecessary risk to allow this array to be imported from the security context
24085 // schema registry.
24086 const SCHEMA$1 = [
24087 '[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop,slot' +
24088 /* added manually to avoid breaking changes */
24089 ',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored',
24090 '[HTMLElement]^[Element]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
24091 'abbr,address,article,aside,b,bdi,bdo,cite,code,dd,dfn,dt,em,figcaption,figure,footer,header,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,section,small,strong,sub,sup,u,var,wbr^[HTMLElement]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
24092 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume',
24093 ':svg:^[HTMLElement]|*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,%style,#tabIndex',
24094 ':svg:graphics^:svg:|',
24095 ':svg:animation^:svg:|*begin,*end,*repeat',
24096 ':svg:geometry^:svg:|',
24097 ':svg:componentTransferFunction^:svg:|',
24098 ':svg:gradient^:svg:|',
24099 ':svg:textContent^:svg:graphics|',
24100 ':svg:textPositioning^:svg:textContent|',
24101 'a^[HTMLElement]|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,referrerPolicy,rel,rev,search,shape,target,text,type,username',
24102 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username',
24103 'audio^media|',
24104 'br^[HTMLElement]|clear',
24105 'base^[HTMLElement]|href,target',
24106 'body^[HTMLElement]|aLink,background,bgColor,link,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink',
24107 'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
24108 'canvas^[HTMLElement]|#height,#width',
24109 'content^[HTMLElement]|select',
24110 'dl^[HTMLElement]|!compact',
24111 'datalist^[HTMLElement]|',
24112 'details^[HTMLElement]|!open',
24113 'dialog^[HTMLElement]|!open,returnValue',
24114 'dir^[HTMLElement]|!compact',
24115 'div^[HTMLElement]|align',
24116 'embed^[HTMLElement]|align,height,name,src,type,width',
24117 'fieldset^[HTMLElement]|!disabled,name',
24118 'font^[HTMLElement]|color,face,size',
24119 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
24120 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
24121 'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
24122 'hr^[HTMLElement]|align,color,!noShade,size,width',
24123 'head^[HTMLElement]|',
24124 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align',
24125 'html^[HTMLElement]|version',
24126 'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width',
24127 'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width',
24128 'input^[HTMLElement]|accept,align,alt,autocapitalize,autocomplete,!autofocus,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width',
24129 'li^[HTMLElement]|type,#value',
24130 'label^[HTMLElement]|htmlFor',
24131 'legend^[HTMLElement]|align',
24132 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type',
24133 'map^[HTMLElement]|name',
24134 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
24135 'menu^[HTMLElement]|!compact',
24136 'meta^[HTMLElement]|content,httpEquiv,name,scheme',
24137 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value',
24138 'ins,del^[HTMLElement]|cite,dateTime',
24139 'ol^[HTMLElement]|!compact,!reversed,#start,type',
24140 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
24141 'optgroup^[HTMLElement]|!disabled,label',
24142 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value',
24143 'output^[HTMLElement]|defaultValue,%htmlFor,name,value',
24144 'p^[HTMLElement]|align',
24145 'param^[HTMLElement]|name,type,value,valueType',
24146 'picture^[HTMLElement]|',
24147 'pre^[HTMLElement]|#width',
24148 'progress^[HTMLElement]|#max,#value',
24149 'q,blockquote,cite^[HTMLElement]|',
24150 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
24151 'select^[HTMLElement]|!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
24152 'shadow^[HTMLElement]|',
24153 'slot^[HTMLElement]|name',
24154 'source^[HTMLElement]|media,sizes,src,srcset,type',
24155 'span^[HTMLElement]|',
24156 'style^[HTMLElement]|!disabled,media,type',
24157 'caption^[HTMLElement]|align',
24158 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
24159 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width',
24160 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
24161 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign',
24162 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign',
24163 'template^[HTMLElement]|',
24164 'textarea^[HTMLElement]|autocapitalize,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
24165 'title^[HTMLElement]|text',
24166 'track^[HTMLElement]|!default,kind,label,src,srclang',
24167 'ul^[HTMLElement]|!compact,type',
24168 'unknown^[HTMLElement]|',
24169 'video^media|#height,poster,#width',
24170 ':svg:a^:svg:graphics|',
24171 ':svg:animate^:svg:animation|',
24172 ':svg:animateMotion^:svg:animation|',
24173 ':svg:animateTransform^:svg:animation|',
24174 ':svg:circle^:svg:geometry|',
24175 ':svg:clipPath^:svg:graphics|',
24176 ':svg:defs^:svg:graphics|',
24177 ':svg:desc^:svg:|',
24178 ':svg:discard^:svg:|',
24179 ':svg:ellipse^:svg:geometry|',
24180 ':svg:feBlend^:svg:|',
24181 ':svg:feColorMatrix^:svg:|',
24182 ':svg:feComponentTransfer^:svg:|',
24183 ':svg:feComposite^:svg:|',
24184 ':svg:feConvolveMatrix^:svg:|',
24185 ':svg:feDiffuseLighting^:svg:|',
24186 ':svg:feDisplacementMap^:svg:|',
24187 ':svg:feDistantLight^:svg:|',
24188 ':svg:feDropShadow^:svg:|',
24189 ':svg:feFlood^:svg:|',
24190 ':svg:feFuncA^:svg:componentTransferFunction|',
24191 ':svg:feFuncB^:svg:componentTransferFunction|',
24192 ':svg:feFuncG^:svg:componentTransferFunction|',
24193 ':svg:feFuncR^:svg:componentTransferFunction|',
24194 ':svg:feGaussianBlur^:svg:|',
24195 ':svg:feImage^:svg:|',
24196 ':svg:feMerge^:svg:|',
24197 ':svg:feMergeNode^:svg:|',
24198 ':svg:feMorphology^:svg:|',
24199 ':svg:feOffset^:svg:|',
24200 ':svg:fePointLight^:svg:|',
24201 ':svg:feSpecularLighting^:svg:|',
24202 ':svg:feSpotLight^:svg:|',
24203 ':svg:feTile^:svg:|',
24204 ':svg:feTurbulence^:svg:|',
24205 ':svg:filter^:svg:|',
24206 ':svg:foreignObject^:svg:graphics|',
24207 ':svg:g^:svg:graphics|',
24208 ':svg:image^:svg:graphics|',
24209 ':svg:line^:svg:geometry|',
24210 ':svg:linearGradient^:svg:gradient|',
24211 ':svg:mpath^:svg:|',
24212 ':svg:marker^:svg:|',
24213 ':svg:mask^:svg:|',
24214 ':svg:metadata^:svg:|',
24215 ':svg:path^:svg:geometry|',
24216 ':svg:pattern^:svg:|',
24217 ':svg:polygon^:svg:geometry|',
24218 ':svg:polyline^:svg:geometry|',
24219 ':svg:radialGradient^:svg:gradient|',
24220 ':svg:rect^:svg:geometry|',
24221 ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan',
24222 ':svg:script^:svg:|type',
24223 ':svg:set^:svg:animation|',
24224 ':svg:stop^:svg:|',
24225 ':svg:style^:svg:|!disabled,media,title,type',
24226 ':svg:switch^:svg:graphics|',
24227 ':svg:symbol^:svg:|',
24228 ':svg:tspan^:svg:textPositioning|',
24229 ':svg:text^:svg:textPositioning|',
24230 ':svg:textPath^:svg:textContent|',
24231 ':svg:title^:svg:|',
24232 ':svg:use^:svg:graphics|',
24233 ':svg:view^:svg:|#zoomAndPan',
24234 'data^[HTMLElement]|value',
24235 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name',
24236 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
24237 'summary^[HTMLElement]|',
24238 'time^[HTMLElement]|dateTime',
24239 ':svg:cursor^:svg:|',
24240 ];
24241 const EVENT = 'event';
24242 const BOOLEAN$1 = 'boolean';
24243 const NUMBER$1 = 'number';
24244 const STRING$1 = 'string';
24245 const OBJECT$1 = 'object';
24246 class SchemaInformation {
24247 constructor() {
24248 this.schema = {};
24249 SCHEMA$1.forEach(encodedType => {
24250 const parts = encodedType.split('|');
24251 const properties = parts[1].split(',');
24252 const typeParts = (parts[0] + '^').split('^');
24253 const typeName = typeParts[0];
24254 const type = {};
24255 typeName.split(',').forEach(tag => this.schema[tag.toLowerCase()] = type);
24256 const superName = typeParts[1];
24257 const superType = superName && this.schema[superName.toLowerCase()];
24258 if (superType) {
24259 for (const key in superType) {
24260 type[key] = superType[key];
24261 }
24262 }
24263 properties.forEach((property) => {
24264 if (property === '') ;
24265 else if (property.startsWith('*')) {
24266 type[property.substring(1)] = EVENT;
24267 }
24268 else if (property.startsWith('!')) {
24269 type[property.substring(1)] = BOOLEAN$1;
24270 }
24271 else if (property.startsWith('#')) {
24272 type[property.substring(1)] = NUMBER$1;
24273 }
24274 else if (property.startsWith('%')) {
24275 type[property.substring(1)] = OBJECT$1;
24276 }
24277 else {
24278 type[property] = STRING$1;
24279 }
24280 });
24281 });
24282 }
24283 allKnownElements() {
24284 return Object.keys(this.schema);
24285 }
24286 eventsOf(elementName) {
24287 const elementType = this.schema[elementName.toLowerCase()] || {};
24288 return Object.keys(elementType).filter(property => elementType[property] === EVENT);
24289 }
24290 propertiesOf(elementName) {
24291 const elementType = this.schema[elementName.toLowerCase()] || {};
24292 return Object.keys(elementType).filter(property => elementType[property] !== EVENT);
24293 }
24294 typeOf(elementName, property) {
24295 return (this.schema[elementName.toLowerCase()] || {})[property];
24296 }
24297 static get instance() {
24298 let result = SchemaInformation._instance;
24299 if (!result) {
24300 result = SchemaInformation._instance = new SchemaInformation();
24301 }
24302 return result;
24303 }
24304 }
24305 function eventNames(elementName) {
24306 return SchemaInformation.instance.eventsOf(elementName);
24307 }
24308 function propertyNames(elementName) {
24309 return SchemaInformation.instance.propertiesOf(elementName);
24310 }
24311
24312 /**
24313 * @license
24314 * Copyright Google LLC All Rights Reserved.
24315 *
24316 * Use of this source code is governed by an MIT-style license that can be
24317 * found in the LICENSE file at https://angular.io/license
24318 */
24319 const EMPTY_SYMBOL_TABLE = {
24320 size: 0,
24321 get: () => undefined,
24322 has: () => false,
24323 values: () => [],
24324 };
24325 /**
24326 * A factory function that returns a symbol table that contains all global symbols
24327 * available in an interpolation scope in a template.
24328 * This function creates the table the first time it is called, and return a cached
24329 * value for all subsequent calls.
24330 */
24331 const createGlobalSymbolTable = (function () {
24332 let GLOBAL_SYMBOL_TABLE;
24333 return function (query) {
24334 if (GLOBAL_SYMBOL_TABLE) {
24335 return GLOBAL_SYMBOL_TABLE;
24336 }
24337 GLOBAL_SYMBOL_TABLE = query.createSymbolTable([
24338 // The `$any()` method casts the type of an expression to `any`.
24339 // https://angular.io/guide/template-syntax#the-any-type-cast-function
24340 {
24341 name: '$any',
24342 kind: 'method',
24343 type: {
24344 name: '$any',
24345 kind: 'method',
24346 type: undefined,
24347 language: 'typescript',
24348 container: undefined,
24349 public: true,
24350 callable: true,
24351 definition: undefined,
24352 nullable: false,
24353 documentation: [{
24354 kind: 'text',
24355 text: 'function to cast an expression to the `any` type',
24356 }],
24357 members: () => EMPTY_SYMBOL_TABLE,
24358 signatures: () => [],
24359 selectSignature(args) {
24360 if (args.length !== 1) {
24361 return;
24362 }
24363 return {
24364 arguments: EMPTY_SYMBOL_TABLE,
24365 result: query.getBuiltinType(BuiltinType$1.Any),
24366 };
24367 },
24368 indexed: () => undefined,
24369 typeArguments: () => undefined,
24370 },
24371 },
24372 ]);
24373 return GLOBAL_SYMBOL_TABLE;
24374 };
24375 })();
24376
24377 /**
24378 * @license
24379 * Copyright Google LLC All Rights Reserved.
24380 *
24381 * Use of this source code is governed by an MIT-style license that can be
24382 * found in the LICENSE file at https://angular.io/license
24383 */
24384 // In TypeScript 2.1 these flags moved
24385 // These helpers work for both 2.0 and 2.1.
24386 const isPrivate = ts.ModifierFlags ?
24387 ((node) => !!(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Private)) :
24388 ((node) => !!(node.flags & ts.NodeFlags.Private));
24389 const isReferenceType = ts.ObjectFlags ?
24390 ((type) => !!(type.flags & ts.TypeFlags.Object &&
24391 type.objectFlags & ts.ObjectFlags.Reference)) :
24392 ((type) => !!(type.flags & ts.TypeFlags.Reference));
24393 function getSymbolQuery(program, checker, source, fetchPipes) {
24394 return new TypeScriptSymbolQuery(program, checker, source, fetchPipes);
24395 }
24396 function getClassMembersFromDeclaration(program, checker, source, declaration) {
24397 const type = checker.getTypeAtLocation(declaration);
24398 return new TypeWrapper(type, { node: source, program, checker }).members();
24399 }
24400 function getPipesTable(source, program, checker, pipes) {
24401 return new PipesTable(pipes, { program, checker, node: source });
24402 }
24403 class TypeScriptSymbolQuery {
24404 constructor(program, checker, source, fetchPipes) {
24405 this.program = program;
24406 this.checker = checker;
24407 this.source = source;
24408 this.fetchPipes = fetchPipes;
24409 this.typeCache = new Map();
24410 }
24411 getTypeKind(symbol) {
24412 const type = symbol instanceof TypeWrapper ? symbol.tsType : undefined;
24413 return typeKindOf(type);
24414 }
24415 getBuiltinType(kind) {
24416 let result = this.typeCache.get(kind);
24417 if (!result) {
24418 const type = getTsTypeFromBuiltinType(kind, {
24419 checker: this.checker,
24420 node: this.source,
24421 program: this.program,
24422 });
24423 result =
24424 new TypeWrapper(type, { program: this.program, checker: this.checker, node: this.source });
24425 this.typeCache.set(kind, result);
24426 }
24427 return result;
24428 }
24429 getTypeUnion(...types) {
24430 // No API exists so return any if the types are not all the same type.
24431 let result = undefined;
24432 if (types.length) {
24433 result = types[0];
24434 for (let i = 1; i < types.length; i++) {
24435 if (types[i] != result) {
24436 result = undefined;
24437 break;
24438 }
24439 }
24440 }
24441 return result || this.getBuiltinType(BuiltinType$1.Any);
24442 }
24443 getArrayType(_type) {
24444 return this.getBuiltinType(BuiltinType$1.Any);
24445 }
24446 getElementType(type) {
24447 if (type instanceof TypeWrapper) {
24448 const ty = type.tsType;
24449 const tyArgs = type.typeArguments();
24450 // TODO(ayazhafiz): Track https://github.com/microsoft/TypeScript/issues/37711 to expose
24451 // `isArrayLikeType` as a public method.
24452 if (!this.checker.isArrayLikeType(ty) || (tyArgs === null || tyArgs === void 0 ? void 0 : tyArgs.length) !== 1)
24453 return;
24454 return tyArgs[0];
24455 }
24456 }
24457 getNonNullableType(symbol) {
24458 if (symbol instanceof TypeWrapper && (typeof this.checker.getNonNullableType == 'function')) {
24459 const tsType = symbol.tsType;
24460 const nonNullableType = this.checker.getNonNullableType(tsType);
24461 if (nonNullableType != tsType) {
24462 return new TypeWrapper(nonNullableType, symbol.context);
24463 }
24464 else if (nonNullableType == tsType) {
24465 return symbol;
24466 }
24467 }
24468 return this.getBuiltinType(BuiltinType$1.Any);
24469 }
24470 getPipes() {
24471 let result = this.pipesCache;
24472 if (!result) {
24473 result = this.pipesCache = this.fetchPipes();
24474 }
24475 return result;
24476 }
24477 getTemplateContext(type) {
24478 const context = { node: this.source, program: this.program, checker: this.checker };
24479 const typeSymbol = findClassSymbolInContext(type, context);
24480 if (typeSymbol) {
24481 const contextType = this.getTemplateRefContextType(typeSymbol, context);
24482 if (contextType)
24483 return contextType.members();
24484 }
24485 }
24486 getTypeSymbol(type) {
24487 const context = { node: this.source, program: this.program, checker: this.checker };
24488 const typeSymbol = findClassSymbolInContext(type, context);
24489 return typeSymbol && new SymbolWrapper(typeSymbol, context);
24490 }
24491 createSymbolTable(symbols) {
24492 const result = new MapSymbolTable();
24493 result.addAll(symbols.map(s => new DeclaredSymbol(s)));
24494 return result;
24495 }
24496 mergeSymbolTable(symbolTables) {
24497 const result = new MapSymbolTable();
24498 for (const symbolTable of symbolTables) {
24499 result.addAll(symbolTable.values());
24500 }
24501 return result;
24502 }
24503 getSpanAt(line, column) {
24504 return spanAt(this.source, line, column);
24505 }
24506 getTemplateRefContextType(typeSymbol, context) {
24507 const type = this.checker.getTypeOfSymbolAtLocation(typeSymbol, this.source);
24508 const constructor = type.symbol && type.symbol.members &&
24509 getFromSymbolTable(type.symbol.members, '__constructor');
24510 if (constructor) {
24511 const constructorDeclaration = constructor.declarations[0];
24512 for (const parameter of constructorDeclaration.parameters) {
24513 const type = this.checker.getTypeAtLocation(parameter.type);
24514 if (type.symbol.name == 'TemplateRef' && isReferenceType(type)) {
24515 const typeWrapper = new TypeWrapper(type, context);
24516 const typeArguments = typeWrapper.typeArguments();
24517 if (typeArguments && typeArguments.length === 1) {
24518 return typeArguments[0];
24519 }
24520 }
24521 }
24522 }
24523 }
24524 }
24525 function typeCallable(type) {
24526 const signatures = type.getCallSignatures();
24527 return signatures && signatures.length != 0;
24528 }
24529 function signaturesOf(type, context) {
24530 return type.getCallSignatures().map(s => new SignatureWrapper(s, context));
24531 }
24532 function selectSignature(type, context, types) {
24533 // TODO: Do a better job of selecting the right signature. TypeScript does not currently support a
24534 // Type Relationship API (see https://github.com/angular/vscode-ng-language-service/issues/143).
24535 // Consider creating a TypeCheckBlock host in the language service that may also act as a
24536 // scratchpad for type comparisons.
24537 const signatures = type.getCallSignatures();
24538 const passedInTypes = types.map(type => {
24539 if (type instanceof TypeWrapper) {
24540 return type.tsType;
24541 }
24542 });
24543 // Try to select a matching signature in which all parameter types match.
24544 // Note that this is just a best-effort approach, because we're checking for
24545 // strict type equality rather than compatibility.
24546 // For example, if the signature contains a ReadonlyArray<number> and the
24547 // passed parameter type is an Array<number>, this will fail.
24548 function allParameterTypesMatch(signature) {
24549 const tc = context.checker;
24550 return signature.getParameters().every((parameter, i) => {
24551 const type = tc.getTypeOfSymbolAtLocation(parameter, parameter.valueDeclaration);
24552 return type === passedInTypes[i];
24553 });
24554 }
24555 const exactMatch = signatures.find(allParameterTypesMatch);
24556 if (exactMatch) {
24557 return new SignatureWrapper(exactMatch, context);
24558 }
24559 // If not, fallback to a naive selection
24560 return signatures.length ? new SignatureWrapper(signatures[0], context) : undefined;
24561 }
24562 class TypeWrapper {
24563 constructor(tsType, context) {
24564 this.tsType = tsType;
24565 this.context = context;
24566 this.kind = 'type';
24567 this.language = 'typescript';
24568 this.type = undefined;
24569 this.container = undefined;
24570 this.public = true;
24571 if (!tsType) {
24572 throw Error('Internal: null type');
24573 }
24574 }
24575 get name() {
24576 return this.context.checker.typeToString(this.tsType);
24577 }
24578 get callable() {
24579 return typeCallable(this.tsType);
24580 }
24581 get nullable() {
24582 return this.context.checker.getNonNullableType(this.tsType) != this.tsType;
24583 }
24584 get documentation() {
24585 const symbol = this.tsType.getSymbol();
24586 if (!symbol) {
24587 return [];
24588 }
24589 return symbol.getDocumentationComment(this.context.checker);
24590 }
24591 get definition() {
24592 const symbol = this.tsType.getSymbol();
24593 return symbol ? definitionFromTsSymbol(symbol) : undefined;
24594 }
24595 members() {
24596 // Should call getApparentProperties() instead of getProperties() because
24597 // the former includes properties on the base class whereas the latter does
24598 // not. This provides properties like .bind(), .call(), .apply(), etc for
24599 // functions.
24600 return new SymbolTableWrapper(this.tsType.getApparentProperties(), this.context, this.tsType);
24601 }
24602 signatures() {
24603 return signaturesOf(this.tsType, this.context);
24604 }
24605 selectSignature(types) {
24606 return selectSignature(this.tsType, this.context, types);
24607 }
24608 indexed(type, value) {
24609 if (!(type instanceof TypeWrapper))
24610 return;
24611 const typeKind = typeKindOf(type.tsType);
24612 switch (typeKind) {
24613 case BuiltinType$1.Number:
24614 const nType = this.tsType.getNumberIndexType();
24615 if (nType) {
24616 // get the right tuple type by value, like 'var t: [number, string];'
24617 if (nType.isUnion()) {
24618 // return undefined if array index out of bound.
24619 return nType.types[value] && new TypeWrapper(nType.types[value], this.context);
24620 }
24621 return new TypeWrapper(nType, this.context);
24622 }
24623 return undefined;
24624 case BuiltinType$1.String:
24625 const sType = this.tsType.getStringIndexType();
24626 return sType && new TypeWrapper(sType, this.context);
24627 }
24628 }
24629 typeArguments() {
24630 if (!isReferenceType(this.tsType))
24631 return;
24632 const typeReference = this.tsType;
24633 let typeArguments;
24634 typeArguments = this.context.checker.getTypeArguments(typeReference);
24635 if (!typeArguments)
24636 return undefined;
24637 return typeArguments.map(ta => new TypeWrapper(ta, this.context));
24638 }
24639 }
24640 // If stringIndexType a primitive type(e.g. 'string'), the Symbol is undefined;
24641 // and in AstType.resolvePropertyRead method, the Symbol.type should get the right type.
24642 class StringIndexTypeWrapper extends TypeWrapper {
24643 constructor() {
24644 super(...arguments);
24645 this.type = new TypeWrapper(this.tsType, this.context);
24646 }
24647 }
24648 class SymbolWrapper {
24649 constructor(symbol,
24650 /** TypeScript type context of the symbol. */
24651 context,
24652 /**
24653 * Type of the TypeScript symbol, if known. If not provided, the type of the symbol
24654 * will be determined dynamically; see `SymbolWrapper#tsType`.
24655 */
24656 _tsType) {
24657 this.context = context;
24658 this._tsType = _tsType;
24659 this.nullable = false;
24660 this.language = 'typescript';
24661 this.symbol = symbol && context && (symbol.flags & ts.SymbolFlags.Alias) ?
24662 context.checker.getAliasedSymbol(symbol) :
24663 symbol;
24664 }
24665 get name() {
24666 return this.symbol.name;
24667 }
24668 get kind() {
24669 return this.callable ? 'method' : 'property';
24670 }
24671 get type() {
24672 return new TypeWrapper(this.tsType, this.context);
24673 }
24674 get container() {
24675 return getContainerOf(this.symbol, this.context);
24676 }
24677 get public() {
24678 // Symbols that are not explicitly made private are public.
24679 return !isSymbolPrivate(this.symbol);
24680 }
24681 get callable() {
24682 return typeCallable(this.tsType);
24683 }
24684 get definition() {
24685 return definitionFromTsSymbol(this.symbol);
24686 }
24687 get documentation() {
24688 return this.symbol.getDocumentationComment(this.context.checker);
24689 }
24690 members() {
24691 if (!this._members) {
24692 if ((this.symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) != 0) {
24693 const declaredType = this.context.checker.getDeclaredTypeOfSymbol(this.symbol);
24694 const typeWrapper = new TypeWrapper(declaredType, this.context);
24695 this._members = typeWrapper.members();
24696 }
24697 else {
24698 this._members = new SymbolTableWrapper(this.symbol.members, this.context, this.tsType);
24699 }
24700 }
24701 return this._members;
24702 }
24703 signatures() {
24704 return signaturesOf(this.tsType, this.context);
24705 }
24706 selectSignature(types) {
24707 return selectSignature(this.tsType, this.context, types);
24708 }
24709 indexed(_argument) {
24710 return undefined;
24711 }
24712 typeArguments() {
24713 return this.type.typeArguments();
24714 }
24715 get tsType() {
24716 let type = this._tsType;
24717 if (!type) {
24718 type = this._tsType =
24719 this.context.checker.getTypeOfSymbolAtLocation(this.symbol, this.context.node);
24720 }
24721 return type;
24722 }
24723 }
24724 class DeclaredSymbol {
24725 constructor(declaration) {
24726 this.declaration = declaration;
24727 this.language = 'ng-template';
24728 this.nullable = false;
24729 this.public = true;
24730 }
24731 get name() {
24732 return this.declaration.name;
24733 }
24734 get kind() {
24735 return this.declaration.kind;
24736 }
24737 get container() {
24738 return undefined;
24739 }
24740 get type() {
24741 return this.declaration.type;
24742 }
24743 get callable() {
24744 return this.type.callable;
24745 }
24746 get definition() {
24747 return this.declaration.definition;
24748 }
24749 get documentation() {
24750 return this.declaration.type.documentation;
24751 }
24752 members() {
24753 return this.type.members();
24754 }
24755 signatures() {
24756 return this.type.signatures();
24757 }
24758 selectSignature(types) {
24759 return this.type.selectSignature(types);
24760 }
24761 typeArguments() {
24762 return this.type.typeArguments();
24763 }
24764 indexed(_argument) {
24765 return undefined;
24766 }
24767 }
24768 class SignatureWrapper {
24769 constructor(signature, context) {
24770 this.signature = signature;
24771 this.context = context;
24772 }
24773 get arguments() {
24774 return new SymbolTableWrapper(this.signature.getParameters(), this.context);
24775 }
24776 get result() {
24777 return new TypeWrapper(this.signature.getReturnType(), this.context);
24778 }
24779 }
24780 class SignatureResultOverride {
24781 constructor(signature, resultType) {
24782 this.signature = signature;
24783 this.resultType = resultType;
24784 }
24785 get arguments() {
24786 return this.signature.arguments;
24787 }
24788 get result() {
24789 return this.resultType;
24790 }
24791 }
24792 function toSymbolTableFactory(symbols) {
24793 // ∀ Typescript version >= 2.2, `SymbolTable` is implemented as an ES6 `Map`
24794 const result = new Map();
24795 for (const symbol of symbols) {
24796 result.set(symbol.name, symbol);
24797 }
24798 return result;
24799 }
24800 function toSymbols(symbolTable) {
24801 if (!symbolTable)
24802 return [];
24803 const table = symbolTable;
24804 if (typeof table.values === 'function') {
24805 return Array.from(table.values());
24806 }
24807 const result = [];
24808 const own = typeof table.hasOwnProperty === 'function' ?
24809 (name) => table.hasOwnProperty(name) :
24810 (name) => !!table[name];
24811 for (const name in table) {
24812 if (own(name)) {
24813 result.push(table[name]);
24814 }
24815 }
24816 return result;
24817 }
24818 class SymbolTableWrapper {
24819 /**
24820 * Creates a queryable table of symbols belonging to a TypeScript entity.
24821 * @param symbols symbols to query belonging to the entity
24822 * @param context program context
24823 * @param type original TypeScript type of entity owning the symbols, if known
24824 */
24825 constructor(symbols, context, type) {
24826 this.context = context;
24827 symbols = symbols || [];
24828 if (Array.isArray(symbols)) {
24829 this.symbols = symbols;
24830 this.symbolTable = toSymbolTableFactory(symbols);
24831 }
24832 else {
24833 this.symbols = toSymbols(symbols);
24834 this.symbolTable = symbols;
24835 }
24836 if (type) {
24837 this.stringIndexType = type.getStringIndexType();
24838 }
24839 }
24840 get size() {
24841 return this.symbols.length;
24842 }
24843 get(key) {
24844 const symbol = getFromSymbolTable(this.symbolTable, key);
24845 if (symbol) {
24846 return new SymbolWrapper(symbol, this.context);
24847 }
24848 if (this.stringIndexType) {
24849 // If the key does not exist as an explicit symbol on the type, it may be accessing a string
24850 // index signature using dot notation:
24851 //
24852 // const obj<T>: { [key: string]: T };
24853 // obj.stringIndex // equivalent to obj['stringIndex'];
24854 //
24855 // In this case, return the type indexed by an arbitrary string key.
24856 return new StringIndexTypeWrapper(this.stringIndexType, this.context);
24857 }
24858 return undefined;
24859 }
24860 has(key) {
24861 const table = this.symbolTable;
24862 return ((typeof table.has === 'function') ? table.has(key) : table[key] != null) ||
24863 this.stringIndexType !== undefined;
24864 }
24865 values() {
24866 return this.symbols.map(s => new SymbolWrapper(s, this.context));
24867 }
24868 }
24869 class MapSymbolTable {
24870 constructor() {
24871 this.map = new Map();
24872 this._values = [];
24873 }
24874 get size() {
24875 return this.map.size;
24876 }
24877 get(key) {
24878 return this.map.get(key);
24879 }
24880 add(symbol) {
24881 if (this.map.has(symbol.name)) {
24882 const previous = this.map.get(symbol.name);
24883 this._values[this._values.indexOf(previous)] = symbol;
24884 }
24885 this.map.set(symbol.name, symbol);
24886 this._values.push(symbol);
24887 }
24888 addAll(symbols) {
24889 for (const symbol of symbols) {
24890 this.add(symbol);
24891 }
24892 }
24893 has(key) {
24894 return this.map.has(key);
24895 }
24896 values() {
24897 // Switch to this.map.values once iterables are supported by the target language.
24898 return this._values;
24899 }
24900 }
24901 class PipesTable {
24902 constructor(pipes, context) {
24903 this.pipes = pipes;
24904 this.context = context;
24905 }
24906 get size() {
24907 return this.pipes.length;
24908 }
24909 get(key) {
24910 const pipe = this.pipes.find(pipe => pipe.name == key);
24911 if (pipe) {
24912 return new PipeSymbol(pipe, this.context);
24913 }
24914 }
24915 has(key) {
24916 return this.pipes.find(pipe => pipe.name == key) != null;
24917 }
24918 values() {
24919 return this.pipes.map(pipe => new PipeSymbol(pipe, this.context));
24920 }
24921 }
24922 // This matches .d.ts files that look like ".../<package-name>/<package-name>.d.ts",
24923 const INDEX_PATTERN = /[\\/]([^\\/]+)[\\/]\1\.d\.ts$/;
24924 class PipeSymbol {
24925 constructor(pipe, context) {
24926 this.pipe = pipe;
24927 this.context = context;
24928 this.kind = 'pipe';
24929 this.language = 'typescript';
24930 this.container = undefined;
24931 this.callable = true;
24932 this.nullable = false;
24933 this.public = true;
24934 }
24935 get name() {
24936 return this.pipe.name;
24937 }
24938 get type() {
24939 return new TypeWrapper(this.tsType, this.context);
24940 }
24941 get definition() {
24942 const symbol = this.tsType.getSymbol();
24943 return symbol ? definitionFromTsSymbol(symbol) : undefined;
24944 }
24945 get documentation() {
24946 const symbol = this.tsType.getSymbol();
24947 if (!symbol) {
24948 return [];
24949 }
24950 return symbol.getDocumentationComment(this.context.checker);
24951 }
24952 members() {
24953 return EmptyTable.instance;
24954 }
24955 signatures() {
24956 return signaturesOf(this.tsType, this.context);
24957 }
24958 selectSignature(types) {
24959 let signature = selectSignature(this.tsType, this.context, types);
24960 if (types.length > 0) {
24961 const parameterType = types[0];
24962 let resultType = undefined;
24963 switch (this.name) {
24964 case 'async':
24965 // Get type argument of 'Observable', 'Promise', or 'EventEmitter'.
24966 const tArgs = parameterType.typeArguments();
24967 if (tArgs && tArgs.length === 1) {
24968 resultType = tArgs[0];
24969 }
24970 break;
24971 case 'slice':
24972 resultType = parameterType;
24973 break;
24974 }
24975 if (resultType) {
24976 signature = new SignatureResultOverride(signature, resultType);
24977 }
24978 }
24979 return signature;
24980 }
24981 indexed(_argument) {
24982 return undefined;
24983 }
24984 typeArguments() {
24985 return this.type.typeArguments();
24986 }
24987 get tsType() {
24988 let type = this._tsType;
24989 if (!type) {
24990 const classSymbol = this.findClassSymbol(this.pipe.type.reference);
24991 if (classSymbol) {
24992 type = this._tsType = this.findTransformMethodType(classSymbol);
24993 }
24994 if (!type) {
24995 type = this._tsType = getTsTypeFromBuiltinType(BuiltinType$1.Any, this.context);
24996 }
24997 }
24998 return type;
24999 }
25000 findClassSymbol(type) {
25001 return findClassSymbolInContext(type, this.context);
25002 }
25003 findTransformMethodType(classSymbol) {
25004 const classType = this.context.checker.getDeclaredTypeOfSymbol(classSymbol);
25005 if (classType) {
25006 const transform = classType.getProperty('transform');
25007 if (transform) {
25008 return this.context.checker.getTypeOfSymbolAtLocation(transform, this.context.node);
25009 }
25010 }
25011 }
25012 }
25013 function findClassSymbolInContext(type, context) {
25014 let sourceFile = context.program.getSourceFile(type.filePath);
25015 if (!sourceFile) {
25016 // This handles a case where an <packageName>/index.d.ts and a <packageName>/<packageName>.d.ts
25017 // are in the same directory. If we are looking for <packageName>/<packageName> and didn't
25018 // find it, look for <packageName>/index.d.ts as the program might have found that instead.
25019 const p = type.filePath;
25020 const m = p.match(INDEX_PATTERN);
25021 if (m) {
25022 const indexVersion = path.join(path.dirname(p), 'index.d.ts');
25023 sourceFile = context.program.getSourceFile(indexVersion);
25024 }
25025 }
25026 if (sourceFile) {
25027 const moduleSymbol = sourceFile.module || sourceFile.symbol;
25028 const exports = context.checker.getExportsOfModule(moduleSymbol);
25029 return (exports || []).find(symbol => symbol.name == type.name);
25030 }
25031 }
25032 class EmptyTable {
25033 constructor() {
25034 this.size = 0;
25035 }
25036 get(_key) {
25037 return undefined;
25038 }
25039 has(_key) {
25040 return false;
25041 }
25042 values() {
25043 return [];
25044 }
25045 }
25046 EmptyTable.instance = new EmptyTable();
25047 function isSymbolPrivate(s) {
25048 return !!s.valueDeclaration && isPrivate(s.valueDeclaration);
25049 }
25050 function getTsTypeFromBuiltinType(builtinType, ctx) {
25051 let syntaxKind;
25052 switch (builtinType) {
25053 case BuiltinType$1.Any:
25054 syntaxKind = ts.SyntaxKind.AnyKeyword;
25055 break;
25056 case BuiltinType$1.Boolean:
25057 syntaxKind = ts.SyntaxKind.BooleanKeyword;
25058 break;
25059 case BuiltinType$1.Null:
25060 syntaxKind = ts.SyntaxKind.NullKeyword;
25061 break;
25062 case BuiltinType$1.Number:
25063 syntaxKind = ts.SyntaxKind.NumberKeyword;
25064 break;
25065 case BuiltinType$1.String:
25066 syntaxKind = ts.SyntaxKind.StringKeyword;
25067 break;
25068 case BuiltinType$1.Undefined:
25069 syntaxKind = ts.SyntaxKind.UndefinedKeyword;
25070 break;
25071 default:
25072 throw new Error(`Internal error, unhandled literal kind ${builtinType}:${BuiltinType$1[builtinType]}`);
25073 }
25074 const node = ts.createNode(syntaxKind);
25075 node.parent = ts.createEmptyStatement();
25076 return ctx.checker.getTypeAtLocation(node);
25077 }
25078 function spanAt(sourceFile, line, column) {
25079 if (line != null && column != null) {
25080 const position = ts.getPositionOfLineAndCharacter(sourceFile, line, column);
25081 const findChild = function findChild(node) {
25082 if (node.kind > ts.SyntaxKind.LastToken && node.pos <= position && node.end > position) {
25083 const betterNode = ts.forEachChild(node, findChild);
25084 return betterNode || node;
25085 }
25086 };
25087 const node = ts.forEachChild(sourceFile, findChild);
25088 if (node) {
25089 return { start: node.getStart(), end: node.getEnd() };
25090 }
25091 }
25092 }
25093 function definitionFromTsSymbol(symbol) {
25094 const declarations = symbol.declarations;
25095 if (declarations) {
25096 return declarations.map(declaration => {
25097 const sourceFile = declaration.getSourceFile();
25098 return {
25099 fileName: sourceFile.fileName,
25100 span: { start: declaration.getStart(), end: declaration.getEnd() }
25101 };
25102 });
25103 }
25104 }
25105 function parentDeclarationOf(node) {
25106 while (node) {
25107 switch (node.kind) {
25108 case ts.SyntaxKind.ClassDeclaration:
25109 case ts.SyntaxKind.InterfaceDeclaration:
25110 return node;
25111 case ts.SyntaxKind.SourceFile:
25112 return undefined;
25113 }
25114 node = node.parent;
25115 }
25116 }
25117 function getContainerOf(symbol, context) {
25118 if (symbol.getFlags() & ts.SymbolFlags.ClassMember && symbol.declarations) {
25119 for (const declaration of symbol.declarations) {
25120 const parent = parentDeclarationOf(declaration);
25121 if (parent) {
25122 const type = context.checker.getTypeAtLocation(parent);
25123 if (type) {
25124 return new TypeWrapper(type, context);
25125 }
25126 }
25127 }
25128 }
25129 }
25130 function typeKindOf(type) {
25131 if (type) {
25132 if (type.flags & ts.TypeFlags.Any) {
25133 return BuiltinType$1.Any;
25134 }
25135 else if (type.flags & (ts.TypeFlags.String | ts.TypeFlags.StringLike | ts.TypeFlags.StringLiteral)) {
25136 return BuiltinType$1.String;
25137 }
25138 else if (type.flags & (ts.TypeFlags.Number | ts.TypeFlags.NumberLike)) {
25139 return BuiltinType$1.Number;
25140 }
25141 else if (type.flags & ts.TypeFlags.Object) {
25142 return BuiltinType$1.Object;
25143 }
25144 else if (type.flags & (ts.TypeFlags.Undefined)) {
25145 return BuiltinType$1.Undefined;
25146 }
25147 else if (type.flags & (ts.TypeFlags.Null)) {
25148 return BuiltinType$1.Null;
25149 }
25150 else if (type.flags & ts.TypeFlags.Union) {
25151 const unionType = type;
25152 if (unionType.types.length === 0)
25153 return BuiltinType$1.Other;
25154 let ty = 0;
25155 for (const subType of unionType.types) {
25156 ty |= typeKindOf(subType);
25157 }
25158 return ty;
25159 }
25160 else if (type.flags & ts.TypeFlags.TypeParameter) {
25161 return BuiltinType$1.Unbound;
25162 }
25163 }
25164 return BuiltinType$1.Other;
25165 }
25166 function getFromSymbolTable(symbolTable, key) {
25167 const table = symbolTable;
25168 let symbol;
25169 if (typeof table.get === 'function') {
25170 // TS 2.2 uses a Map
25171 symbol = table.get(key);
25172 }
25173 else {
25174 // TS pre-2.2 uses an object
25175 symbol = table[key];
25176 }
25177 return symbol;
25178 }
25179
25180 /**
25181 * @license
25182 * Copyright Google LLC All Rights Reserved.
25183 *
25184 * Use of this source code is governed by an MIT-style license that can be
25185 * found in the LICENSE file at https://angular.io/license
25186 */
25187 /**
25188 * A base class to represent a template and which component class it is
25189 * associated with. A template source could answer basic questions about
25190 * top-level declarations of its class through the members() and query()
25191 * methods.
25192 */
25193 class BaseTemplate {
25194 constructor(host, classDeclNode, classSymbol) {
25195 this.host = host;
25196 this.classDeclNode = classDeclNode;
25197 this.classSymbol = classSymbol;
25198 this.program = host.program;
25199 }
25200 /**
25201 * Return the Angular StaticSymbol for the class that contains this template.
25202 */
25203 get type() {
25204 return this.classSymbol;
25205 }
25206 /**
25207 * Return a Map-like data structure that allows users to retrieve some or all
25208 * top-level declarations in the associated component class.
25209 */
25210 get members() {
25211 if (!this.membersTable) {
25212 const typeChecker = this.program.getTypeChecker();
25213 const sourceFile = this.classDeclNode.getSourceFile();
25214 this.membersTable = this.query.mergeSymbolTable([
25215 createGlobalSymbolTable(this.query),
25216 getClassMembersFromDeclaration(this.program, typeChecker, sourceFile, this.classDeclNode),
25217 ]);
25218 }
25219 return this.membersTable;
25220 }
25221 /**
25222 * Return an engine that provides more information about symbols in the
25223 * template.
25224 */
25225 get query() {
25226 if (!this.queryCache) {
25227 const program = this.program;
25228 const typeChecker = program.getTypeChecker();
25229 const sourceFile = this.classDeclNode.getSourceFile();
25230 this.queryCache = getSymbolQuery(program, typeChecker, sourceFile, () => {
25231 // Computing the ast is relatively expensive. Do it only when absolutely
25232 // necessary.
25233 // TODO: There is circular dependency here between TemplateSource and
25234 // TypeScriptHost. Consider refactoring the code to break this cycle.
25235 const ast = this.host.getTemplateAst(this);
25236 const pipes = (ast && ast.pipes) || [];
25237 return getPipesTable(sourceFile, program, typeChecker, pipes);
25238 });
25239 }
25240 return this.queryCache;
25241 }
25242 }
25243 /**
25244 * An InlineTemplate represents template defined in a TS file through the
25245 * `template` attribute in the decorator.
25246 */
25247 class InlineTemplate extends BaseTemplate {
25248 constructor(templateNode, classDeclNode, classSymbol, host) {
25249 super(host, classDeclNode, classSymbol);
25250 const sourceFile = templateNode.getSourceFile();
25251 if (sourceFile !== classDeclNode.getSourceFile()) {
25252 throw new Error(`Inline template and component class should belong to the same source file`);
25253 }
25254 this.fileName = sourceFile.fileName;
25255 // node.text returns the TS internal representation of the normalized text,
25256 // and all CR characters are stripped. node.getText() returns the raw text.
25257 this.source = templateNode.getText().slice(1, -1); // strip leading and trailing quotes
25258 this.span = {
25259 // TS string literal includes surrounding quotes in the start/end offsets.
25260 start: templateNode.getStart() + 1,
25261 end: templateNode.getEnd() - 1,
25262 };
25263 }
25264 }
25265 /**
25266 * An ExternalTemplate represents template defined in an external (most likely
25267 * HTML, but not necessarily) file through the `templateUrl` attribute in the
25268 * decorator.
25269 * Note that there is no ts.Node associated with the template because it's not
25270 * a TS file.
25271 */
25272 class ExternalTemplate extends BaseTemplate {
25273 constructor(source, fileName, classDeclNode, classSymbol, host) {
25274 super(host, classDeclNode, classSymbol);
25275 this.source = source;
25276 this.fileName = fileName;
25277 this.span = {
25278 start: 0,
25279 end: source.length,
25280 };
25281 }
25282 }
25283
25284 /**
25285 * @license
25286 * Copyright Google LLC All Rights Reserved.
25287 *
25288 * Use of this source code is governed by an MIT-style license that can be
25289 * found in the LICENSE file at https://angular.io/license
25290 */
25291 const HIDDEN_HTML_ELEMENTS = new Set(['html', 'script', 'noscript', 'base', 'body', 'title', 'head', 'link']);
25292 const HTML_ELEMENTS = elementNames().filter(name => !HIDDEN_HTML_ELEMENTS.has(name)).map(name => {
25293 return {
25294 name,
25295 kind: CompletionKind.HTML_ELEMENT,
25296 sortText: name,
25297 };
25298 });
25299 const ANGULAR_ELEMENTS = [
25300 {
25301 name: 'ng-container',
25302 kind: CompletionKind.ANGULAR_ELEMENT,
25303 sortText: 'ng-container',
25304 },
25305 {
25306 name: 'ng-content',
25307 kind: CompletionKind.ANGULAR_ELEMENT,
25308 sortText: 'ng-content',
25309 },
25310 {
25311 name: 'ng-template',
25312 kind: CompletionKind.ANGULAR_ELEMENT,
25313 sortText: 'ng-template',
25314 },
25315 ];
25316 function isIdentifierPart$1(code) {
25317 // Identifiers consist of alphanumeric characters, '_', or '$'.
25318 return isAsciiLetter(code) || isDigit(code) || code == $$ || code == $_;
25319 }
25320 /**
25321 * Gets the span of word in a template that surrounds `position`. If there is no word around
25322 * `position`, nothing is returned.
25323 */
25324 function getBoundedWordSpan(templateInfo, position, ast) {
25325 const { template } = templateInfo;
25326 const templateSrc = template.source;
25327 if (!templateSrc)
25328 return;
25329 if (ast instanceof Element$1) {
25330 // The HTML tag may include `-` (e.g. `app-root`),
25331 // so use the HtmlAst to get the span before ayazhafiz refactor the code.
25332 return {
25333 start: templateInfo.template.span.start + ast.startSourceSpan.start.offset + 1,
25334 length: ast.name.length
25335 };
25336 }
25337 // TODO(ayazhafiz): A solution based on word expansion will always be expensive compared to one
25338 // based on ASTs. Whatever penalty we incur is probably manageable for small-length (i.e. the
25339 // majority of) identifiers, but the current solution involes a number of branchings and we can't
25340 // control potentially very long identifiers. Consider moving to an AST-based solution once
25341 // existing difficulties with AST spans are more clearly resolved (see #31898 for discussion of
25342 // known problems, and #33091 for how they affect text replacement).
25343 //
25344 // `templatePosition` represents the right-bound location of a cursor in the template.
25345 // key.ent|ry
25346 // ^---- cursor, at position `r` is at.
25347 // A cursor is not itself a character in the template; it has a left (lower) and right (upper)
25348 // index bound that hugs the cursor itself.
25349 let templatePosition = position - template.span.start;
25350 // To perform word expansion, we want to determine the left and right indices that hug the cursor.
25351 // There are three cases here.
25352 let left, right;
25353 if (templatePosition === 0) {
25354 // 1. Case like
25355 // |rest of template
25356 // the cursor is at the start of the template, hugged only by the right side (0-index).
25357 left = right = 0;
25358 }
25359 else if (templatePosition === templateSrc.length) {
25360 // 2. Case like
25361 // rest of template|
25362 // the cursor is at the end of the template, hugged only by the left side (last-index).
25363 left = right = templateSrc.length - 1;
25364 }
25365 else {
25366 // 3. Case like
25367 // wo|rd
25368 // there is a clear left and right index.
25369 left = templatePosition - 1;
25370 right = templatePosition;
25371 }
25372 if (!isIdentifierPart$1(templateSrc.charCodeAt(left)) &&
25373 !isIdentifierPart$1(templateSrc.charCodeAt(right))) {
25374 // Case like
25375 // .|.
25376 // left ---^ ^--- right
25377 // There is no word here.
25378 return;
25379 }
25380 // Expand on the left and right side until a word boundary is hit. Back up one expansion on both
25381 // side to stay inside the word.
25382 while (left >= 0 && isIdentifierPart$1(templateSrc.charCodeAt(left)))
25383 --left;
25384 ++left;
25385 while (right < templateSrc.length && isIdentifierPart$1(templateSrc.charCodeAt(right)))
25386 ++right;
25387 --right;
25388 const absoluteStartPosition = position - (templatePosition - left);
25389 const length = right - left + 1;
25390 return { start: absoluteStartPosition, length };
25391 }
25392 function getTemplateCompletions(templateInfo, position) {
25393 const { htmlAst, template } = templateInfo;
25394 // Calculate the position relative to the start of the template. This is needed
25395 // because spans in HTML AST are relative. Inline template has non-zero start position.
25396 const templatePosition = position - template.span.start;
25397 const htmlPath = getPathToNodeAtPosition(htmlAst, templatePosition);
25398 const mostSpecific = htmlPath.tail;
25399 const visitor = new HtmlVisitor(templateInfo, htmlPath);
25400 const results = mostSpecific ?
25401 mostSpecific.visit(visitor, null /* context */) :
25402 elementCompletions(templateInfo);
25403 const replacementSpan = getBoundedWordSpan(templateInfo, position, mostSpecific);
25404 return results.map(entry => {
25405 return Object.assign(Object.assign({}, entry), { replacementSpan });
25406 });
25407 }
25408 class HtmlVisitor {
25409 constructor(templateInfo, htmlPath) {
25410 this.templateInfo = templateInfo;
25411 this.htmlPath = htmlPath;
25412 this.relativePosition = htmlPath.position;
25413 }
25414 // Note that every visitor method must explicitly specify return type because
25415 // Visitor returns `any` for all methods.
25416 visitElement(ast) {
25417 const startTagSpan = spanOf(ast.sourceSpan);
25418 const tagLen = ast.name.length;
25419 // + 1 for the opening angle bracket
25420 if (this.relativePosition <= startTagSpan.start + tagLen + 1) {
25421 // If we are in the tag then return the element completions.
25422 return elementCompletions(this.templateInfo);
25423 }
25424 if (this.relativePosition < startTagSpan.end) {
25425 // We are in the attribute section of the element (but not in an attribute).
25426 // Return the attribute completions.
25427 return attributeCompletionsForElement(this.templateInfo, ast.name);
25428 }
25429 return [];
25430 }
25431 visitAttribute(ast) {
25432 // An attribute consists of two parts, LHS="RHS".
25433 // Determine if completions are requested for LHS or RHS
25434 if (ast.valueSpan && inSpan(this.relativePosition, spanOf(ast.valueSpan))) {
25435 // RHS completion
25436 return attributeValueCompletions(this.templateInfo, this.htmlPath);
25437 }
25438 // LHS completion
25439 return attributeCompletions(this.templateInfo, this.htmlPath);
25440 }
25441 visitText() {
25442 var _a;
25443 const templatePath = findTemplateAstAt(this.templateInfo.templateAst, this.relativePosition);
25444 if (templatePath.tail instanceof BoundTextAst) {
25445 // If we know that this is an interpolation then do not try other scenarios.
25446 const visitor = new ExpressionVisitor(this.templateInfo, this.relativePosition, () => getExpressionScope(diagnosticInfoFromTemplateInfo(this.templateInfo), templatePath));
25447 (_a = templatePath.tail) === null || _a === void 0 ? void 0 : _a.visit(visitor, null);
25448 return visitor.results;
25449 }
25450 // TODO(kyliau): Not sure if this check is really needed since we don't have
25451 // any test cases for it.
25452 const element = this.htmlPath.first(Element$1);
25453 if (element &&
25454 getHtmlTagDefinition(element.name).getContentType() !== TagContentType.PARSABLE_DATA) {
25455 return [];
25456 }
25457 // This is to account for cases like <h1> <a> text | </h1> where the
25458 // closest element has no closing tag and thus is considered plain text.
25459 const results = voidElementAttributeCompletions(this.templateInfo, this.htmlPath);
25460 if (results.length) {
25461 return results;
25462 }
25463 return elementCompletions(this.templateInfo);
25464 }
25465 visitComment() {
25466 return [];
25467 }
25468 visitExpansion() {
25469 return [];
25470 }
25471 visitExpansionCase() {
25472 return [];
25473 }
25474 }
25475 function attributeCompletions(info, path) {
25476 const attr = path.tail;
25477 const elem = path.parentOf(attr);
25478 if (!(attr instanceof Attribute) || !(elem instanceof Element$1)) {
25479 return [];
25480 }
25481 // TODO: Consider parsing the attrinute name to a proper AST instead of
25482 // matching using regex. This is because the regexp would incorrectly identify
25483 // bind parts for cases like [()|]
25484 // ^ cursor is here
25485 const binding = getBindingDescriptor(attr.name);
25486 if (!binding) {
25487 // This is a normal HTML attribute, not an Angular attribute.
25488 return attributeCompletionsForElement(info, elem.name);
25489 }
25490 const results = [];
25491 const ngAttrs = angularAttributes(info, elem.name);
25492 switch (binding.kind) {
25493 case ATTR.KW_MICROSYNTAX:
25494 // template reference attribute: *attrName
25495 results.push(...ngAttrs.templateRefs);
25496 break;
25497 case ATTR.KW_BIND:
25498 case ATTR.IDENT_PROPERTY:
25499 // property binding via bind- or []
25500 results.push(...propertyNames(elem.name), ...ngAttrs.inputs);
25501 break;
25502 case ATTR.KW_ON:
25503 case ATTR.IDENT_EVENT:
25504 // event binding via on- or ()
25505 results.push(...eventNames(elem.name), ...ngAttrs.outputs);
25506 break;
25507 case ATTR.KW_BINDON:
25508 case ATTR.IDENT_BANANA_BOX:
25509 // banana-in-a-box binding via bindon- or [()]
25510 results.push(...ngAttrs.bananas);
25511 break;
25512 }
25513 return results.map(name => {
25514 return {
25515 name,
25516 kind: CompletionKind.ATTRIBUTE,
25517 sortText: name,
25518 };
25519 });
25520 }
25521 function attributeCompletionsForElement(info, elementName) {
25522 const results = [];
25523 if (info.template instanceof InlineTemplate) {
25524 // Provide HTML attributes completion only for inline templates
25525 for (const name of attributeNames(elementName)) {
25526 results.push({
25527 name,
25528 kind: CompletionKind.HTML_ATTRIBUTE,
25529 sortText: name,
25530 });
25531 }
25532 }
25533 // Add Angular attributes
25534 const ngAttrs = angularAttributes(info, elementName);
25535 for (const name of ngAttrs.others) {
25536 results.push({
25537 name,
25538 kind: CompletionKind.ATTRIBUTE,
25539 sortText: name,
25540 });
25541 }
25542 return results;
25543 }
25544 /**
25545 * Provide completions to the RHS of an attribute, which is of the form
25546 * LHS="RHS". The template path is computed from the specified `info` whereas
25547 * the context is determined from the specified `htmlPath`.
25548 * @param info Object that contains the template AST
25549 * @param htmlPath Path to the HTML node
25550 */
25551 function attributeValueCompletions(info, htmlPath) {
25552 // Find the corresponding Template AST path.
25553 const templatePath = findTemplateAstAt(info.templateAst, htmlPath.position);
25554 const visitor = new ExpressionVisitor(info, htmlPath.position, () => {
25555 const dinfo = diagnosticInfoFromTemplateInfo(info);
25556 return getExpressionScope(dinfo, templatePath);
25557 });
25558 if (templatePath.tail instanceof AttrAst ||
25559 templatePath.tail instanceof BoundElementPropertyAst ||
25560 templatePath.tail instanceof BoundEventAst) {
25561 templatePath.tail.visit(visitor, null);
25562 return visitor.results;
25563 }
25564 // In order to provide accurate attribute value completion, we need to know
25565 // what the LHS is, and construct the proper AST if it is missing.
25566 const htmlAttr = htmlPath.tail;
25567 const binding = getBindingDescriptor(htmlAttr.name);
25568 if (binding && binding.kind === ATTR.KW_REF) {
25569 let refAst;
25570 let elemAst;
25571 if (templatePath.tail instanceof ReferenceAst) {
25572 refAst = templatePath.tail;
25573 const parent = templatePath.parentOf(refAst);
25574 if (parent instanceof ElementAst) {
25575 elemAst = parent;
25576 }
25577 }
25578 else if (templatePath.tail instanceof ElementAst) {
25579 refAst = new ReferenceAst(htmlAttr.name, null, htmlAttr.value, htmlAttr.valueSpan);
25580 elemAst = templatePath.tail;
25581 }
25582 if (refAst && elemAst) {
25583 refAst.visit(visitor, elemAst);
25584 }
25585 }
25586 else {
25587 // HtmlAst contains the `Attribute` node, however the corresponding `AttrAst`
25588 // node is missing from the TemplateAst.
25589 const attrAst = new AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan);
25590 attrAst.visit(visitor, null);
25591 }
25592 return visitor.results;
25593 }
25594 function elementCompletions(info) {
25595 const results = [...ANGULAR_ELEMENTS];
25596 if (info.template instanceof InlineTemplate) {
25597 // Provide HTML elements completion only for inline templates
25598 results.push(...HTML_ELEMENTS);
25599 }
25600 // Collect the elements referenced by the selectors
25601 const components = new Set();
25602 for (const selector of getSelectors(info).selectors) {
25603 const name = selector.element;
25604 if (name && !components.has(name)) {
25605 components.add(name);
25606 results.push({
25607 name,
25608 kind: CompletionKind.COMPONENT,
25609 sortText: name,
25610 });
25611 }
25612 }
25613 return results;
25614 }
25615 // There is a special case of HTML where text that contains a unclosed tag is treated as
25616 // text. For exaple '<h1> Some <a text </h1>' produces a text nodes inside of the H1
25617 // element "Some <a text". We, however, want to treat this as if the user was requesting
25618 // the attributes of an "a" element, not requesting completion in the a text element. This
25619 // code checks for this case and returns element completions if it is detected or undefined
25620 // if it is not.
25621 function voidElementAttributeCompletions(info, path) {
25622 const tail = path.tail;
25623 if (tail instanceof Text$2) {
25624 const match = tail.value.match(/<(\w(\w|\d|-)*:)?(\w(\w|\d|-)*)\s/);
25625 // The position must be after the match, otherwise we are still in a place where elements
25626 // are expected (such as `<|a` or `<a|`; we only want attributes for `<a |` or after).
25627 if (match &&
25628 path.position >= (match.index || 0) + match[0].length + tail.sourceSpan.start.offset) {
25629 return attributeCompletionsForElement(info, match[3]);
25630 }
25631 }
25632 return [];
25633 }
25634 class ExpressionVisitor extends NullTemplateVisitor {
25635 constructor(info, position, getExpressionScope) {
25636 super();
25637 this.info = info;
25638 this.position = position;
25639 this.getExpressionScope = getExpressionScope;
25640 this.completions = new Map();
25641 }
25642 get results() {
25643 return Array.from(this.completions.values());
25644 }
25645 visitDirectiveProperty(ast) {
25646 this.processExpressionCompletions(ast.value);
25647 }
25648 visitElementProperty(ast) {
25649 this.processExpressionCompletions(ast.value);
25650 }
25651 visitEvent(ast) {
25652 this.processExpressionCompletions(ast.handler);
25653 }
25654 visitElement() {
25655 // no-op for now
25656 }
25657 visitAttr(ast) {
25658 const binding = getBindingDescriptor(ast.name);
25659 if (binding && binding.kind === ATTR.KW_MICROSYNTAX) {
25660 // This a template binding given by micro syntax expression.
25661 // First, verify the attribute consists of some binding we can give completions for.
25662 // The sourceSpan of AttrAst points to the RHS of the attribute
25663 const templateKey = binding.name;
25664 const templateValue = ast.sourceSpan.toString();
25665 const templateUrl = ast.sourceSpan.start.file.url;
25666 // TODO(kyliau): We are unable to determine the absolute offset of the key
25667 // but it is okay here, because we are only looking at the RHS of the attr
25668 const absKeyOffset = 0;
25669 const absValueOffset = ast.sourceSpan.start.offset;
25670 const { templateBindings } = this.info.expressionParser.parseTemplateBindings(templateKey, templateValue, templateUrl, absKeyOffset, absValueOffset);
25671 // Find the nearest template binding to the position.
25672 const lastBindingEnd = templateBindings.length > 0 &&
25673 templateBindings[templateBindings.length - 1].sourceSpan.end;
25674 const normalizedPositionToBinding = lastBindingEnd && this.position > lastBindingEnd ? lastBindingEnd : this.position;
25675 const templateBinding = templateBindings.find(b => inSpan(normalizedPositionToBinding, b.sourceSpan));
25676 if (!templateBinding) {
25677 return;
25678 }
25679 this.microSyntaxInAttributeValue(ast, templateBinding);
25680 }
25681 else {
25682 const expressionAst = this.info.expressionParser.parseBinding(ast.value, ast.sourceSpan.toString(), ast.sourceSpan.start.offset);
25683 this.processExpressionCompletions(expressionAst);
25684 }
25685 }
25686 visitReference(_ast, context) {
25687 context.directives.forEach(dir => {
25688 const { exportAs } = dir.directive;
25689 if (exportAs) {
25690 this.completions.set(exportAs, { name: exportAs, kind: CompletionKind.REFERENCE, sortText: exportAs });
25691 }
25692 });
25693 }
25694 visitBoundText(ast) {
25695 if (inSpan(this.position, ast.value.sourceSpan)) {
25696 const completions = getExpressionCompletions(this.getExpressionScope(), ast.value, this.position, this.info.template);
25697 if (completions) {
25698 this.addSymbolsToCompletions(completions);
25699 }
25700 }
25701 }
25702 processExpressionCompletions(value) {
25703 const symbols = getExpressionCompletions(this.getExpressionScope(), value, this.position, this.info.template);
25704 if (symbols) {
25705 this.addSymbolsToCompletions(symbols);
25706 }
25707 }
25708 addSymbolsToCompletions(symbols) {
25709 for (const s of symbols) {
25710 if (s.name.startsWith('__') || !s.public || this.completions.has(s.name)) {
25711 continue;
25712 }
25713 // The pipe method should not include parentheses.
25714 // e.g. {{ value_expression | slice : start [ : end ] }}
25715 const shouldInsertParentheses = s.callable && s.kind !== CompletionKind.PIPE;
25716 this.completions.set(s.name, {
25717 name: s.name,
25718 kind: s.kind,
25719 sortText: s.name,
25720 insertText: shouldInsertParentheses ? `${s.name}()` : s.name,
25721 });
25722 }
25723 }
25724 /**
25725 * This method handles the completions of attribute values for directives that
25726 * support the microsyntax format. Examples are *ngFor and *ngIf.
25727 * These directives allows declaration of "let" variables, adds context-specific
25728 * symbols like $implicit, index, count, among other behaviors.
25729 * For a complete description of such format, see
25730 * https://angular.io/guide/structural-directives#the-asterisk--prefix
25731 *
25732 * @param attr descriptor for attribute name and value pair
25733 * @param binding template binding for the expression in the attribute
25734 */
25735 microSyntaxInAttributeValue(attr, binding) {
25736 var _a;
25737 const key = attr.name.substring(1); // remove leading asterisk
25738 // Find the selector - eg ngFor, ngIf, etc
25739 const selectorInfo = getSelectors(this.info);
25740 const selector = selectorInfo.selectors.find(s => {
25741 // attributes are listed in (attribute, value) pairs
25742 for (let i = 0; i < s.attrs.length; i += 2) {
25743 if (s.attrs[i] === key) {
25744 return true;
25745 }
25746 }
25747 });
25748 if (!selector) {
25749 return;
25750 }
25751 const valueRelativePosition = this.position - attr.sourceSpan.start.offset;
25752 if (binding instanceof VariableBinding) {
25753 // TODO(kyliau): With expression sourceSpan we shouldn't have to search
25754 // the attribute value string anymore. Just check if position is in the
25755 // expression source span.
25756 const equalLocation = attr.value.indexOf('=');
25757 if (equalLocation > 0 && valueRelativePosition > equalLocation) {
25758 // We are after the '=' in a let clause. The valid values here are the members of the
25759 // template reference's type parameter.
25760 const directiveMetadata = selectorInfo.map.get(selector);
25761 if (directiveMetadata) {
25762 const contextTable = this.info.template.query.getTemplateContext(directiveMetadata.type.reference);
25763 if (contextTable) {
25764 // This adds symbols like $implicit, index, count, etc.
25765 this.addSymbolsToCompletions(contextTable.values());
25766 return;
25767 }
25768 }
25769 }
25770 }
25771 else if (binding instanceof ExpressionBinding) {
25772 if (inSpan(this.position, (_a = binding.value) === null || _a === void 0 ? void 0 : _a.ast.sourceSpan)) {
25773 this.processExpressionCompletions(binding.value.ast);
25774 return;
25775 }
25776 else if (!binding.value && this.position > binding.key.span.end) {
25777 // No expression is defined for the value of the key expression binding, but the cursor is
25778 // in a location where the expression would be defined. This can happen in a case like
25779 // let i of |
25780 // ^-- cursor
25781 // In this case, backfill the value to be an empty expression and retrieve completions.
25782 this.processExpressionCompletions(new EmptyExpr(new ParseSpan(valueRelativePosition, valueRelativePosition), new AbsoluteSourceSpan(this.position, this.position)));
25783 return;
25784 }
25785 }
25786 }
25787 }
25788 /**
25789 * Return all Angular-specific attributes for the element with `elementName`.
25790 * @param info
25791 * @param elementName
25792 */
25793 function angularAttributes(info, elementName) {
25794 const { selectors, map: selectorMap } = getSelectors(info);
25795 const templateRefs = new Set();
25796 const inputs = new Set();
25797 const outputs = new Set();
25798 const bananas = new Set();
25799 const others = new Set();
25800 for (const selector of selectors) {
25801 if (selector.element && selector.element !== elementName) {
25802 continue;
25803 }
25804 const summary = selectorMap.get(selector);
25805 const hasTemplateRef = isStructuralDirective(summary.type);
25806 // attributes are listed in (attribute, value) pairs
25807 for (let i = 0; i < selector.attrs.length; i += 2) {
25808 const attr = selector.attrs[i];
25809 if (hasTemplateRef) {
25810 templateRefs.add(attr);
25811 }
25812 else {
25813 others.add(attr);
25814 }
25815 }
25816 for (const input of Object.values(summary.inputs)) {
25817 inputs.add(input);
25818 }
25819 for (const output of Object.values(summary.outputs)) {
25820 outputs.add(output);
25821 }
25822 }
25823 for (const name of inputs) {
25824 // Add banana-in-a-box syntax
25825 // https://angular.io/guide/template-syntax#two-way-binding-
25826 if (outputs.has(`${name}Change`)) {
25827 bananas.add(name);
25828 }
25829 }
25830 return { templateRefs, inputs, outputs, bananas, others };
25831 }
25832
25833 /**
25834 * @license
25835 * Copyright Google LLC All Rights Reserved.
25836 *
25837 * Use of this source code is governed by an MIT-style license that can be
25838 * found in the LICENSE file at https://angular.io/license
25839 */
25840 /**
25841 * Traverses a template AST and locates symbol(s) at a specified position.
25842 * @param info template AST information set
25843 * @param position location to locate symbols at
25844 */
25845 function locateSymbols(info, position) {
25846 const templatePosition = position - info.template.span.start;
25847 // TODO: update `findTemplateAstAt` to use absolute positions.
25848 const path = findTemplateAstAt(info.templateAst, templatePosition);
25849 const attribute = findAttribute(info, position);
25850 if (!path.tail)
25851 return [];
25852 const narrowest = spanOf(path.tail);
25853 const toVisit = [];
25854 for (let node = path.tail; node && isNarrower(spanOf(node.sourceSpan), narrowest); node = path.parentOf(node)) {
25855 toVisit.push(node);
25856 }
25857 // For the structural directive, only care about the last template AST.
25858 if (attribute === null || attribute === void 0 ? void 0 : attribute.name.startsWith('*')) {
25859 toVisit.splice(0, toVisit.length - 1);
25860 }
25861 return toVisit.map(ast => locateSymbol(ast, path, info))
25862 .filter((sym) => sym !== undefined);
25863 }
25864 /**
25865 * Visits a template node and locates the symbol in that node at a path position.
25866 * @param ast template AST node to visit
25867 * @param path non-empty set of narrowing AST nodes at a position
25868 * @param info template AST information set
25869 */
25870 function locateSymbol(ast, path, info) {
25871 const templatePosition = path.position;
25872 const position = templatePosition + info.template.span.start;
25873 let symbol;
25874 let span;
25875 let staticSymbol;
25876 const attributeValueSymbol = (ast) => {
25877 const attribute = findAttribute(info, position);
25878 if (attribute) {
25879 if (inSpan(templatePosition, spanOf(attribute.valueSpan))) {
25880 let result;
25881 if (attribute.name.startsWith('*')) {
25882 result = getSymbolInMicrosyntax(info, path, attribute);
25883 }
25884 else {
25885 const dinfo = diagnosticInfoFromTemplateInfo(info);
25886 const scope = getExpressionScope(dinfo, path);
25887 result = getExpressionSymbol(scope, ast, templatePosition, info.template);
25888 }
25889 if (result) {
25890 symbol = result.symbol;
25891 span = offsetSpan(result.span, attribute.valueSpan.start.offset);
25892 }
25893 return true;
25894 }
25895 }
25896 return false;
25897 };
25898 ast.visit({
25899 visitNgContent(_ast) { },
25900 visitEmbeddedTemplate(_ast) { },
25901 visitElement(ast) {
25902 const component = ast.directives.find(d => d.directive.isComponent);
25903 if (component) {
25904 // Need to cast because 'reference' is typed as any
25905 staticSymbol = component.directive.type.reference;
25906 symbol = info.template.query.getTypeSymbol(staticSymbol);
25907 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.COMPONENT);
25908 span = spanOf(ast);
25909 }
25910 else {
25911 // Find a directive that matches the element name
25912 const directive = ast.directives.find(d => d.directive.selector != null && d.directive.selector.indexOf(ast.name) >= 0);
25913 if (directive) {
25914 // Need to cast because 'reference' is typed as any
25915 staticSymbol = directive.directive.type.reference;
25916 symbol = info.template.query.getTypeSymbol(staticSymbol);
25917 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE);
25918 span = spanOf(ast);
25919 }
25920 }
25921 },
25922 visitReference(ast) {
25923 symbol = ast.value && info.template.query.getTypeSymbol(tokenReference(ast.value));
25924 span = spanOf(ast);
25925 },
25926 visitVariable(_ast) { },
25927 visitEvent(ast) {
25928 if (!attributeValueSymbol(ast.handler)) {
25929 symbol = findOutputBinding(ast, path, info.template.query);
25930 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.EVENT);
25931 span = spanOf(ast);
25932 }
25933 },
25934 visitElementProperty(ast) {
25935 attributeValueSymbol(ast.value);
25936 },
25937 visitAttr(ast) {
25938 const element = path.first(ElementAst);
25939 if (!element)
25940 return;
25941 // Create a mapping of all directives applied to the element from their selectors.
25942 const matcher = new SelectorMatcher();
25943 for (const dir of element.directives) {
25944 if (!dir.directive.selector)
25945 continue;
25946 matcher.addSelectables(CssSelector.parse(dir.directive.selector), dir);
25947 }
25948 // See if this attribute matches the selector of any directive on the element.
25949 const attributeSelector = `[${ast.name}=${ast.value}]`;
25950 const parsedAttribute = CssSelector.parse(attributeSelector);
25951 if (!parsedAttribute.length)
25952 return;
25953 matcher.match(parsedAttribute[0], (_, { directive }) => {
25954 // Need to cast because 'reference' is typed as any
25955 staticSymbol = directive.type.reference;
25956 symbol = info.template.query.getTypeSymbol(staticSymbol);
25957 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE);
25958 span = spanOf(ast);
25959 });
25960 },
25961 visitBoundText(ast) {
25962 const expressionPosition = templatePosition - ast.sourceSpan.start.offset;
25963 if (inSpan(expressionPosition, ast.value.span)) {
25964 const dinfo = diagnosticInfoFromTemplateInfo(info);
25965 const scope = getExpressionScope(dinfo, path);
25966 const result = getExpressionSymbol(scope, ast.value, templatePosition, info.template);
25967 if (result) {
25968 symbol = result.symbol;
25969 span = offsetSpan(result.span, ast.sourceSpan.start.offset);
25970 }
25971 }
25972 },
25973 visitText(_ast) { },
25974 visitDirective(ast) {
25975 // Need to cast because 'reference' is typed as any
25976 staticSymbol = ast.directive.type.reference;
25977 symbol = info.template.query.getTypeSymbol(staticSymbol);
25978 span = spanOf(ast);
25979 },
25980 visitDirectiveProperty(ast) {
25981 if (!attributeValueSymbol(ast.value)) {
25982 const directive = findParentOfBinding(info.templateAst, ast, templatePosition);
25983 const attribute = findAttribute(info, position);
25984 if (directive && attribute) {
25985 if (attribute.name.startsWith('*')) {
25986 const compileTypeSummary = directive.directive;
25987 symbol = info.template.query.getTypeSymbol(compileTypeSummary.type.reference);
25988 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE);
25989 // Use 'attribute.sourceSpan' instead of the directive's,
25990 // because the span of the directive is the whole opening tag of an element.
25991 span = spanOf(attribute.sourceSpan);
25992 }
25993 else {
25994 symbol = findInputBinding(info, ast.templateName, directive);
25995 span = spanOf(ast);
25996 }
25997 }
25998 }
25999 }
26000 }, null);
26001 if (symbol && span) {
26002 const { start, end } = offsetSpan(span, info.template.span.start);
26003 return {
26004 symbol,
26005 span: tss.createTextSpanFromBounds(start, end),
26006 staticSymbol,
26007 };
26008 }
26009 }
26010 // Get the symbol in microsyntax at template position.
26011 function getSymbolInMicrosyntax(info, path, attribute) {
26012 var _a;
26013 if (!attribute.valueSpan) {
26014 return;
26015 }
26016 const absValueOffset = attribute.valueSpan.start.offset;
26017 let result;
26018 const { templateBindings } = info.expressionParser.parseTemplateBindings(attribute.name, attribute.value, attribute.sourceSpan.toString(), attribute.sourceSpan.start.offset, attribute.valueSpan.start.offset);
26019 // Find the symbol that contains the position.
26020 for (const tb of templateBindings) {
26021 if (tb instanceof VariableBinding) {
26022 // TODO(kyliau): if binding is variable we should still look for the value
26023 // of the key. For example, "let i=index" => "index" should point to
26024 // NgForOfContext.index
26025 continue;
26026 }
26027 if (inSpan(path.position, (_a = tb.value) === null || _a === void 0 ? void 0 : _a.ast.sourceSpan)) {
26028 const dinfo = diagnosticInfoFromTemplateInfo(info);
26029 const scope = getExpressionScope(dinfo, path);
26030 result = getExpressionSymbol(scope, tb.value, path.position, info.template);
26031 }
26032 else if (inSpan(path.position, tb.sourceSpan)) {
26033 const template = path.first(EmbeddedTemplateAst);
26034 if (template) {
26035 // One element can only have one template binding.
26036 const directiveAst = template.directives[0];
26037 if (directiveAst) {
26038 const symbol = findInputBinding(info, tb.key.source.substring(1), directiveAst);
26039 if (symbol) {
26040 result = {
26041 symbol,
26042 // the span here has to be relative to the start of the template
26043 // value so deduct the absolute offset.
26044 // TODO(kyliau): Use absolute source span throughout completions.
26045 span: offsetSpan(tb.key.span, -absValueOffset),
26046 };
26047 }
26048 }
26049 }
26050 }
26051 }
26052 return result;
26053 }
26054 function findAttribute(info, position) {
26055 const templatePosition = position - info.template.span.start;
26056 const path = getPathToNodeAtPosition(info.htmlAst, templatePosition);
26057 return path.first(Attribute);
26058 }
26059 // TODO: remove this function after the path includes 'DirectiveAst'.
26060 // Find the directive that corresponds to the specified 'binding'
26061 // at the specified 'position' in the 'ast'.
26062 function findParentOfBinding(ast, binding, position) {
26063 let res;
26064 const visitor = new class extends RecursiveTemplateAstVisitor {
26065 visit(ast) {
26066 const span = spanOf(ast);
26067 if (!inSpan(position, span)) {
26068 // Returning a value here will result in the children being skipped.
26069 return true;
26070 }
26071 }
26072 visitEmbeddedTemplate(ast, context) {
26073 return this.visitChildren(context, visit => {
26074 visit(ast.directives);
26075 visit(ast.children);
26076 });
26077 }
26078 visitElement(ast, context) {
26079 return this.visitChildren(context, visit => {
26080 visit(ast.directives);
26081 visit(ast.children);
26082 });
26083 }
26084 visitDirective(ast) {
26085 const result = this.visitChildren(ast, visit => {
26086 visit(ast.inputs);
26087 });
26088 return result;
26089 }
26090 visitDirectiveProperty(ast, context) {
26091 if (ast === binding) {
26092 res = context;
26093 }
26094 }
26095 };
26096 templateVisitAll(visitor, ast);
26097 return res;
26098 }
26099 // Find the symbol of input binding in 'directiveAst' by 'name'.
26100 function findInputBinding(info, name, directiveAst) {
26101 const invertedInput = invertMap(directiveAst.directive.inputs);
26102 const fieldName = invertedInput[name];
26103 if (fieldName) {
26104 const classSymbol = info.template.query.getTypeSymbol(directiveAst.directive.type.reference);
26105 if (classSymbol) {
26106 return classSymbol.members().get(fieldName);
26107 }
26108 }
26109 }
26110 /**
26111 * Wrap a symbol and change its kind to component.
26112 */
26113 class OverrideKindSymbol {
26114 constructor(sym, kindOverride) {
26115 this.sym = sym;
26116 this.kind = kindOverride;
26117 }
26118 get name() {
26119 return this.sym.name;
26120 }
26121 get language() {
26122 return this.sym.language;
26123 }
26124 get type() {
26125 return this.sym.type;
26126 }
26127 get container() {
26128 return this.sym.container;
26129 }
26130 get public() {
26131 return this.sym.public;
26132 }
26133 get callable() {
26134 return this.sym.callable;
26135 }
26136 get nullable() {
26137 return this.sym.nullable;
26138 }
26139 get definition() {
26140 return this.sym.definition;
26141 }
26142 get documentation() {
26143 return this.sym.documentation;
26144 }
26145 members() {
26146 return this.sym.members();
26147 }
26148 signatures() {
26149 return this.sym.signatures();
26150 }
26151 selectSignature(types) {
26152 return this.sym.selectSignature(types);
26153 }
26154 indexed(argument) {
26155 return this.sym.indexed(argument);
26156 }
26157 typeArguments() {
26158 return this.sym.typeArguments();
26159 }
26160 }
26161
26162 /**
26163 * @license
26164 * Copyright Google LLC All Rights Reserved.
26165 *
26166 * Use of this source code is governed by an MIT-style license that can be
26167 * found in the LICENSE file at https://angular.io/license
26168 */
26169 /**
26170 * Return metadata about `node` if it looks like an Angular directive class.
26171 * In this case, potential matches are `@NgModule`, `@Component`, `@Directive`,
26172 * `@Pipe`, etc.
26173 * These class declarations all share some common attributes, namely their
26174 * decorator takes exactly one parameter and the parameter must be an object
26175 * literal.
26176 *
26177 * For example,
26178 * v---------- `decoratorId`
26179 * @NgModule({ <
26180 * declarations: [], < classDecln-al
26181 * }) <
26182 * class AppModule {} <
26183 * ^----- `classId`
26184 *
26185 * @param node Potential node that represents an Angular directive.
26186 */
26187 function getDirectiveClassLike(node) {
26188 if (!tss.isClassDeclaration(node) || !node.name || !node.decorators) {
26189 return;
26190 }
26191 for (const d of node.decorators) {
26192 const expr = d.expression;
26193 if (!tss.isCallExpression(expr) || expr.arguments.length !== 1 ||
26194 !tss.isIdentifier(expr.expression)) {
26195 continue;
26196 }
26197 const arg = expr.arguments[0];
26198 if (tss.isObjectLiteralExpression(arg)) {
26199 return {
26200 decoratorId: expr.expression,
26201 classId: node.name,
26202 };
26203 }
26204 }
26205 }
26206 /**
26207 * Finds the value of a property assignment that is nested in a TypeScript node and is of a certain
26208 * type T.
26209 *
26210 * @param startNode node to start searching for nested property assignment from
26211 * @param propName property assignment name
26212 * @param predicate function to verify that a node is of type T.
26213 * @return node property assignment value of type T, or undefined if none is found
26214 */
26215 function findPropertyValueOfType(startNode, propName, predicate) {
26216 if (tss.isPropertyAssignment(startNode) && startNode.name.getText() === propName) {
26217 const { initializer } = startNode;
26218 if (predicate(initializer))
26219 return initializer;
26220 }
26221 return startNode.forEachChild(c => findPropertyValueOfType(c, propName, predicate));
26222 }
26223 /**
26224 * Return the node that most tightly encompass the specified `position`.
26225 * @param node
26226 * @param position
26227 */
26228 function findTightestNode(node, position) {
26229 if (node.getStart() <= position && position < node.getEnd()) {
26230 return node.forEachChild(c => findTightestNode(c, position)) || node;
26231 }
26232 }
26233 /**
26234 * Returns a property assignment from the assignment value if the property name
26235 * matches the specified `key`, or `undefined` if there is no match.
26236 */
26237 function getPropertyAssignmentFromValue(value, key) {
26238 const propAssignment = value.parent;
26239 if (!propAssignment || !tss.isPropertyAssignment(propAssignment) ||
26240 propAssignment.name.getText() !== key) {
26241 return;
26242 }
26243 return propAssignment;
26244 }
26245 /**
26246 * Given a decorator property assignment, return the ClassDeclaration node that corresponds to the
26247 * directive class the property applies to.
26248 * If the property assignment is not on a class decorator, no declaration is returned.
26249 *
26250 * For example,
26251 *
26252 * @Component({
26253 * template: '<div></div>'
26254 * ^^^^^^^^^^^^^^^^^^^^^^^---- property assignment
26255 * })
26256 * class AppComponent {}
26257 * ^---- class declaration node
26258 *
26259 * @param propAsgnNode property assignment
26260 */
26261 function getClassDeclFromDecoratorProp(propAsgnNode) {
26262 if (!propAsgnNode.parent || !tss.isObjectLiteralExpression(propAsgnNode.parent)) {
26263 return;
26264 }
26265 const objLitExprNode = propAsgnNode.parent;
26266 if (!objLitExprNode.parent || !tss.isCallExpression(objLitExprNode.parent)) {
26267 return;
26268 }
26269 const callExprNode = objLitExprNode.parent;
26270 if (!callExprNode.parent || !tss.isDecorator(callExprNode.parent)) {
26271 return;
26272 }
26273 const decorator = callExprNode.parent;
26274 if (!decorator.parent || !tss.isClassDeclaration(decorator.parent)) {
26275 return;
26276 }
26277 const classDeclNode = decorator.parent;
26278 return classDeclNode;
26279 }
26280
26281 /**
26282 * @license
26283 * Copyright Google LLC All Rights Reserved.
26284 *
26285 * Use of this source code is governed by an MIT-style license that can be
26286 * found in the LICENSE file at https://angular.io/license
26287 */
26288 /**
26289 * Convert Angular Span to TypeScript TextSpan. Angular Span has 'start' and
26290 * 'end' whereas TS TextSpan has 'start' and 'length'.
26291 * @param span Angular Span
26292 */
26293 function ngSpanToTsTextSpan(span) {
26294 return {
26295 start: span.start,
26296 length: span.end - span.start,
26297 };
26298 }
26299 /**
26300 * Attempts to get the definition of a file whose URL is specified in a property assignment in a
26301 * directive decorator.
26302 * Currently applies to `templateUrl` and `styleUrls` properties.
26303 */
26304 function getUrlFromProperty(urlNode, tsLsHost) {
26305 // Get the property assignment node corresponding to the `templateUrl` or `styleUrls` assignment.
26306 // These assignments are specified differently; `templateUrl` is a string, and `styleUrls` is
26307 // an array of strings:
26308 // {
26309 // templateUrl: './template.ng.html',
26310 // styleUrls: ['./style.css', './other-style.css']
26311 // }
26312 // `templateUrl`'s property assignment can be found from the string literal node;
26313 // `styleUrls`'s property assignment can be found from the array (parent) node.
26314 //
26315 // First search for `templateUrl`.
26316 let asgn = getPropertyAssignmentFromValue(urlNode, 'templateUrl');
26317 if (!asgn) {
26318 // `templateUrl` assignment not found; search for `styleUrls` array assignment.
26319 asgn = getPropertyAssignmentFromValue(urlNode.parent, 'styleUrls');
26320 if (!asgn) {
26321 // Nothing found, bail.
26322 return;
26323 }
26324 }
26325 // If the property assignment is not a property of a class decorator, don't generate definitions
26326 // for it.
26327 if (!getClassDeclFromDecoratorProp(asgn)) {
26328 return;
26329 }
26330 // Extract url path specified by the url node, which is relative to the TypeScript source file
26331 // the url node is defined in.
26332 const url = extractAbsoluteFilePath(urlNode);
26333 // If the file does not exist, bail. It is possible that the TypeScript language service host
26334 // does not have a `fileExists` method, in which case optimistically assume the file exists.
26335 if (tsLsHost.fileExists && !tsLsHost.fileExists(url))
26336 return;
26337 const templateDefinitions = [{
26338 kind: ts.ScriptElementKind.externalModuleName,
26339 name: url,
26340 containerKind: ts.ScriptElementKind.unknown,
26341 containerName: '',
26342 // Reading the template is expensive, so don't provide a preview.
26343 textSpan: { start: 0, length: 0 },
26344 fileName: url,
26345 }];
26346 return {
26347 definitions: templateDefinitions,
26348 textSpan: {
26349 // Exclude opening and closing quotes in the url span.
26350 start: urlNode.getStart() + 1,
26351 length: urlNode.getWidth() - 2,
26352 },
26353 };
26354 }
26355 /**
26356 * Traverse the template AST and look for the symbol located at `position`, then
26357 * return its definition and span of bound text.
26358 * @param info
26359 * @param position
26360 */
26361 function getDefinitionAndBoundSpan(info, position) {
26362 const symbols = locateSymbols(info, position);
26363 if (!symbols.length) {
26364 return;
26365 }
26366 const seen = new Set();
26367 const definitions = [];
26368 for (const symbolInfo of symbols) {
26369 const { symbol } = symbolInfo;
26370 // symbol.definition is really the locations of the symbol. There could be
26371 // more than one. No meaningful info could be provided without any location.
26372 const { kind, name, container, definition: locations } = symbol;
26373 if (!locations || !locations.length) {
26374 continue;
26375 }
26376 const containerKind = container ? container.kind : ts.ScriptElementKind.unknown;
26377 const containerName = container ? container.name : '';
26378 for (const { fileName, span } of locations) {
26379 const textSpan = ngSpanToTsTextSpan(span);
26380 // In cases like two-way bindings, a request for the definitions of an expression may return
26381 // two of the same definition:
26382 // [(ngModel)]="prop"
26383 // ^^^^ -- one definition for the property binding, one for the event binding
26384 // To prune duplicate definitions, tag definitions with unique location signatures and ignore
26385 // definitions whose locations have already been seen.
26386 const signature = `${textSpan.start}:${textSpan.length}@${fileName}`;
26387 if (seen.has(signature))
26388 continue;
26389 definitions.push({
26390 kind: kind,
26391 name,
26392 containerKind,
26393 containerName,
26394 textSpan: ngSpanToTsTextSpan(span),
26395 fileName: fileName,
26396 });
26397 seen.add(signature);
26398 }
26399 }
26400 return {
26401 definitions,
26402 textSpan: symbols[0].span,
26403 };
26404 }
26405 /**
26406 * Gets an Angular-specific definition in a TypeScript source file.
26407 */
26408 function getTsDefinitionAndBoundSpan(sf, position, tsLsHost) {
26409 const node = findTightestNode(sf, position);
26410 if (!node)
26411 return;
26412 switch (node.kind) {
26413 case ts.SyntaxKind.StringLiteral:
26414 case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
26415 // Attempt to extract definition of a URL in a property assignment.
26416 return getUrlFromProperty(node, tsLsHost);
26417 default:
26418 return undefined;
26419 }
26420 }
26421
26422 /**
26423 * @license
26424 * Copyright Google LLC All Rights Reserved.
26425 *
26426 * Use of this source code is governed by an MIT-style license that can be
26427 * found in the LICENSE file at https://angular.io/license
26428 */
26429 /**
26430 * Return diagnostic information for the parsed AST of the template.
26431 * @param ast contains HTML and template AST
26432 */
26433 function getTemplateDiagnostics(ast) {
26434 const { parseErrors, templateAst, htmlAst, template } = ast;
26435 if (parseErrors && parseErrors.length) {
26436 return parseErrors.map(e => {
26437 return {
26438 kind: ts.DiagnosticCategory.Error,
26439 span: offsetSpan(spanOf(e.span), template.span.start),
26440 message: e.msg,
26441 };
26442 });
26443 }
26444 return getTemplateExpressionDiagnostics({
26445 templateAst: templateAst,
26446 htmlAst: htmlAst,
26447 offset: template.span.start,
26448 query: template.query,
26449 members: template.members,
26450 source: ast.template.source,
26451 });
26452 }
26453 /**
26454 * Performs a variety diagnostics on directive declarations.
26455 *
26456 * @param declarations Angular directive declarations
26457 * @param modules NgModules in the project
26458 * @param host TypeScript service host used to perform TypeScript queries
26459 * @return diagnosed errors, if any
26460 */
26461 function getDeclarationDiagnostics(declarations, modules, host) {
26462 const directives = new Set();
26463 for (const ngModule of modules.ngModules) {
26464 for (const directive of ngModule.declaredDirectives) {
26465 directives.add(directive.reference);
26466 }
26467 }
26468 const results = [];
26469 for (const declaration of declarations) {
26470 const { errors, metadata, type, declarationSpan } = declaration;
26471 const sf = host.getSourceFile(type.filePath);
26472 if (!sf) {
26473 host.error(`directive ${type.name} exists but has no source file`);
26474 return [];
26475 }
26476 // TypeScript identifier of the directive declaration annotation (e.g. "Component" or
26477 // "Directive") on a directive class.
26478 const directiveIdentifier = findTightestNode(sf, declarationSpan.start);
26479 if (!directiveIdentifier) {
26480 host.error(`directive ${type.name} exists but has no identifier`);
26481 return [];
26482 }
26483 for (const error of errors) {
26484 results.push({
26485 kind: ts.DiagnosticCategory.Error,
26486 message: error.message,
26487 span: error.span,
26488 });
26489 }
26490 if (!modules.ngModuleByPipeOrDirective.has(declaration.type)) {
26491 results.push(createDiagnostic(declarationSpan, Diagnostic.directive_not_in_module, metadata.isComponent ? 'Component' : 'Directive', type.name));
26492 }
26493 if (metadata.isComponent) {
26494 const { template, templateUrl, styleUrls } = metadata.template;
26495 if (template === null && !templateUrl) {
26496 results.push(createDiagnostic(declarationSpan, Diagnostic.missing_template_and_templateurl, type.name));
26497 }
26498 else if (templateUrl) {
26499 if (template) {
26500 results.push(createDiagnostic(declarationSpan, Diagnostic.both_template_and_templateurl, type.name));
26501 }
26502 // Find templateUrl value from the directive call expression, which is the parent of the
26503 // directive identifier.
26504 //
26505 // TODO: We should create an enum of the various properties a directive can have to use
26506 // instead of string literals. We can then perform a mass migration of all literal usages.
26507 const templateUrlNode = findPropertyValueOfType(directiveIdentifier.parent, 'templateUrl', ts.isLiteralExpression);
26508 if (!templateUrlNode) {
26509 host.error(`templateUrl ${templateUrl} exists but its TypeScript node doesn't`);
26510 return [];
26511 }
26512 results.push(...validateUrls([templateUrlNode], host.tsLsHost));
26513 }
26514 if (styleUrls.length > 0) {
26515 // Find styleUrls value from the directive call expression, which is the parent of the
26516 // directive identifier.
26517 const styleUrlsNode = findPropertyValueOfType(directiveIdentifier.parent, 'styleUrls', ts.isArrayLiteralExpression);
26518 if (!styleUrlsNode) {
26519 host.error(`styleUrls property exists but its TypeScript node doesn't'`);
26520 return [];
26521 }
26522 results.push(...validateUrls(styleUrlsNode.elements, host.tsLsHost));
26523 }
26524 }
26525 }
26526 return results;
26527 }
26528 /**
26529 * Checks that URLs on a directive point to a valid file.
26530 * Note that this diagnostic check may require a filesystem hit, and thus may be slower than other
26531 * checks.
26532 *
26533 * @param urls urls to check for validity
26534 * @param tsLsHost TS LS host used for querying filesystem information
26535 * @return diagnosed url errors, if any
26536 */
26537 function validateUrls(urls, tsLsHost) {
26538 if (!tsLsHost.fileExists) {
26539 return [];
26540 }
26541 const allErrors = [];
26542 // TODO(ayazhafiz): most of this logic can be unified with the logic in
26543 // definitions.ts#getUrlFromProperty. Create a utility function to be used by both.
26544 for (let i = 0; i < urls.length; ++i) {
26545 const urlNode = urls[i];
26546 if (!ts.isStringLiteralLike(urlNode)) {
26547 // If a non-string value is assigned to a URL node (like `templateUrl`), a type error will be
26548 // picked up by the TS Language Server.
26549 continue;
26550 }
26551 const url = extractAbsoluteFilePath(urlNode);
26552 if (tsLsHost.fileExists(url))
26553 continue;
26554 // Exclude opening and closing quotes in the url span.
26555 const urlSpan = { start: urlNode.getStart() + 1, end: urlNode.end - 1 };
26556 allErrors.push(createDiagnostic(urlSpan, Diagnostic.invalid_templateurl));
26557 }
26558 return allErrors;
26559 }
26560 /**
26561 * Return a recursive data structure that chains diagnostic messages.
26562 * @param chain
26563 */
26564 function chainDiagnostics(chain) {
26565 return {
26566 messageText: chain.message,
26567 category: ts.DiagnosticCategory.Error,
26568 code: 0,
26569 next: chain.next ? chain.next.map(chainDiagnostics) : undefined
26570 };
26571 }
26572 /**
26573 * Convert ng.Diagnostic to ts.Diagnostic.
26574 * @param d diagnostic
26575 * @param file
26576 */
26577 function ngDiagnosticToTsDiagnostic(d, file) {
26578 return {
26579 file,
26580 start: d.span.start,
26581 length: d.span.end - d.span.start,
26582 messageText: typeof d.message === 'string' ? d.message : chainDiagnostics(d.message),
26583 category: d.kind,
26584 code: 0,
26585 source: 'ng',
26586 };
26587 }
26588
26589 /**
26590 * @license
26591 * Copyright Google LLC All Rights Reserved.
26592 *
26593 * Use of this source code is governed by an MIT-style license that can be
26594 * found in the LICENSE file at https://angular.io/license
26595 */
26596 /**
26597 * Traverse the template AST and look for the symbol located at `position`, then
26598 * return the corresponding quick info.
26599 * @param info template AST
26600 * @param position location of the symbol
26601 * @param analyzedModules all NgModules in the program.
26602 */
26603 function getTemplateHover(info, position, analyzedModules) {
26604 var _a, _b;
26605 const symbolInfo = locateSymbols(info, position)[0];
26606 if (!symbolInfo) {
26607 return;
26608 }
26609 const { symbol, span, staticSymbol } = symbolInfo;
26610 // The container is either the symbol's container (for example, 'AppComponent'
26611 // is the container of the symbol 'title' in its template) or the NgModule
26612 // that the directive belongs to (the container of AppComponent is AppModule).
26613 let containerName = (_a = symbol.container) === null || _a === void 0 ? void 0 : _a.name;
26614 if (!containerName && staticSymbol) {
26615 // If there is a static symbol then the target is a directive.
26616 const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol);
26617 containerName = ngModule === null || ngModule === void 0 ? void 0 : ngModule.type.reference.name;
26618 }
26619 return createQuickInfo(symbol.name, symbol.kind, span, containerName, (_b = symbol.type) === null || _b === void 0 ? void 0 : _b.name, symbol.documentation);
26620 }
26621 /**
26622 * Get quick info for Angular semantic entities in TypeScript files, like Directives.
26623 * @param position location of the symbol in the source file
26624 * @param declarations All Directive-like declarations in the source file.
26625 * @param analyzedModules all NgModules in the program.
26626 */
26627 function getTsHover(position, declarations, analyzedModules) {
26628 for (const { declarationSpan, metadata } of declarations) {
26629 if (inSpan(position, declarationSpan)) {
26630 const staticSymbol = metadata.type.reference;
26631 const directiveName = staticSymbol.name;
26632 const kind = metadata.isComponent ? 'component' : 'directive';
26633 const textSpan = ts.createTextSpanFromBounds(declarationSpan.start, declarationSpan.end);
26634 const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol);
26635 const moduleName = ngModule === null || ngModule === void 0 ? void 0 : ngModule.type.reference.name;
26636 return createQuickInfo(directiveName, kind, textSpan, moduleName, ts.ScriptElementKind.classElement);
26637 }
26638 }
26639 }
26640 // Reverse mappings of enum would generate strings
26641 const ALIAS_NAME = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.aliasName];
26642 const SYMBOL_INTERFACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.interfaceName];
26643 const SYMBOL_PUNC = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.punctuation];
26644 const SYMBOL_SPACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.space];
26645 const SYMBOL_TEXT = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.text];
26646 /**
26647 * Construct a QuickInfo object taking into account its container and type.
26648 * @param name Name of the QuickInfo target
26649 * @param kind component, directive, pipe, etc.
26650 * @param textSpan span of the target
26651 * @param containerName either the Symbol's container or the NgModule that contains the directive
26652 * @param type user-friendly name of the type
26653 * @param documentation docstring or comment
26654 */
26655 function createQuickInfo(name, kind, textSpan, containerName, type, documentation) {
26656 const containerDisplayParts = containerName ?
26657 [
26658 { text: containerName, kind: SYMBOL_INTERFACE },
26659 { text: '.', kind: SYMBOL_PUNC },
26660 ] :
26661 [];
26662 const typeDisplayParts = type ?
26663 [
26664 { text: ':', kind: SYMBOL_PUNC },
26665 { text: ' ', kind: SYMBOL_SPACE },
26666 { text: type, kind: SYMBOL_INTERFACE },
26667 ] :
26668 [];
26669 return {
26670 kind: kind,
26671 kindModifiers: ts.ScriptElementKindModifier.none,
26672 textSpan: textSpan,
26673 displayParts: [
26674 { text: '(', kind: SYMBOL_PUNC },
26675 { text: kind, kind: SYMBOL_TEXT },
26676 { text: ')', kind: SYMBOL_PUNC },
26677 { text: ' ', kind: SYMBOL_SPACE },
26678 ...containerDisplayParts,
26679 { text: name, kind: SYMBOL_INTERFACE },
26680 ...typeDisplayParts,
26681 ],
26682 documentation,
26683 };
26684 }
26685
26686 /**
26687 * @license
26688 * Copyright Google LLC All Rights Reserved.
26689 *
26690 * Use of this source code is governed by an MIT-style license that can be
26691 * found in the LICENSE file at https://angular.io/license
26692 */
26693 /**
26694 * Create an instance of an Angular `LanguageService`.
26695 *
26696 * @publicApi
26697 */
26698 function createLanguageService(host) {
26699 return new LanguageServiceImpl(host);
26700 }
26701 class LanguageServiceImpl {
26702 constructor(host) {
26703 this.host = host;
26704 }
26705 getSemanticDiagnostics(fileName) {
26706 const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26707 const ngDiagnostics = [];
26708 const templates = this.host.getTemplates(fileName);
26709 for (const template of templates) {
26710 const ast = this.host.getTemplateAst(template);
26711 if (ast) {
26712 ngDiagnostics.push(...getTemplateDiagnostics(ast));
26713 }
26714 }
26715 const declarations = this.host.getDeclarations(fileName);
26716 ngDiagnostics.push(...getDeclarationDiagnostics(declarations, analyzedModules, this.host));
26717 const sourceFile = fileName.endsWith('.ts') ? this.host.getSourceFile(fileName) : undefined;
26718 const tsDiagnostics = ngDiagnostics.map(d => ngDiagnosticToTsDiagnostic(d, sourceFile));
26719 return [...tss.sortAndDeduplicateDiagnostics(tsDiagnostics)];
26720 }
26721 getCompletionsAtPosition(fileName, position, _options) {
26722 this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26723 const ast = this.host.getTemplateAstAtPosition(fileName, position);
26724 if (!ast) {
26725 return;
26726 }
26727 const results = getTemplateCompletions(ast, position);
26728 if (!results || !results.length) {
26729 return;
26730 }
26731 return {
26732 isGlobalCompletion: false,
26733 isMemberCompletion: false,
26734 isNewIdentifierLocation: false,
26735 // Cast CompletionEntry.kind from ng.CompletionKind to ts.ScriptElementKind
26736 entries: results,
26737 };
26738 }
26739 getDefinitionAndBoundSpan(fileName, position) {
26740 this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26741 const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
26742 if (templateInfo) {
26743 return getDefinitionAndBoundSpan(templateInfo, position);
26744 }
26745 // Attempt to get Angular-specific definitions in a TypeScript file, like templates defined
26746 // in a `templateUrl` property.
26747 if (fileName.endsWith('.ts')) {
26748 const sf = this.host.getSourceFile(fileName);
26749 if (sf) {
26750 return getTsDefinitionAndBoundSpan(sf, position, this.host.tsLsHost);
26751 }
26752 }
26753 }
26754 getQuickInfoAtPosition(fileName, position) {
26755 const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26756 const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
26757 if (templateInfo) {
26758 return getTemplateHover(templateInfo, position, analyzedModules);
26759 }
26760 // Attempt to get Angular-specific hover information in a TypeScript file, the NgModule a
26761 // directive belongs to.
26762 const declarations = this.host.getDeclarations(fileName);
26763 return getTsHover(position, declarations, analyzedModules);
26764 }
26765 getReferencesAtPosition(fileName, position) {
26766 const defAndSpan = this.getDefinitionAndBoundSpan(fileName, position);
26767 if (!(defAndSpan === null || defAndSpan === void 0 ? void 0 : defAndSpan.definitions)) {
26768 return;
26769 }
26770 const { definitions } = defAndSpan;
26771 const tsDef = definitions.find(def => def.fileName.endsWith('.ts'));
26772 if (!tsDef) {
26773 return;
26774 }
26775 return this.host.tsLS.getReferencesAtPosition(tsDef.fileName, tsDef.textSpan.start);
26776 }
26777 }
26778
26779 /**
26780 * @license
26781 * Copyright Google LLC All Rights Reserved.
26782 *
26783 * Use of this source code is governed by an MIT-style license that can be
26784 * found in the LICENSE file at https://angular.io/license
26785 */
26786 function getClosureSafeProperty(objWithPropertyToExtract) {
26787 for (let key in objWithPropertyToExtract) {
26788 if (objWithPropertyToExtract[key] === getClosureSafeProperty) {
26789 return key;
26790 }
26791 }
26792 throw Error('Could not find renamed property on target object.');
26793 }
26794
26795 /**
26796 * @license
26797 * Copyright Google LLC All Rights Reserved.
26798 *
26799 * Use of this source code is governed by an MIT-style license that can be
26800 * found in the LICENSE file at https://angular.io/license
26801 */
26802 function stringify$1(token) {
26803 if (typeof token === 'string') {
26804 return token;
26805 }
26806 if (Array.isArray(token)) {
26807 return '[' + token.map(stringify$1).join(', ') + ']';
26808 }
26809 if (token == null) {
26810 return '' + token;
26811 }
26812 if (token.overriddenName) {
26813 return `${token.overriddenName}`;
26814 }
26815 if (token.name) {
26816 return `${token.name}`;
26817 }
26818 const res = token.toString();
26819 if (res == null) {
26820 return '' + res;
26821 }
26822 const newLineIndex = res.indexOf('\n');
26823 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
26824 }
26825 /**
26826 * Concatenates two strings with separator, allocating new strings only when necessary.
26827 *
26828 * @param before before string.
26829 * @param separator separator string.
26830 * @param after after string.
26831 * @returns concatenated string.
26832 */
26833 function concatStringsWithSpace(before, after) {
26834 return (before == null || before === '') ?
26835 (after === null ? '' : after) :
26836 ((after == null || after === '') ? before : before + ' ' + after);
26837 }
26838
26839 /**
26840 * @license
26841 * Copyright Google LLC All Rights Reserved.
26842 *
26843 * Use of this source code is governed by an MIT-style license that can be
26844 * found in the LICENSE file at https://angular.io/license
26845 */
26846 const __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty });
26847 /**
26848 * Allows to refer to references which are not yet defined.
26849 *
26850 * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
26851 * DI is declared, but not yet defined. It is also used when the `token` which we use when creating
26852 * a query is not yet defined.
26853 *
26854 * @usageNotes
26855 * ### Example
26856 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'}
26857 * @publicApi
26858 */
26859 function forwardRef(forwardRefFn) {
26860 forwardRefFn.__forward_ref__ = forwardRef;
26861 forwardRefFn.toString = function () {
26862 return stringify$1(this());
26863 };
26864 return forwardRefFn;
26865 }
26866 /**
26867 * Lazily retrieves the reference value from a forwardRef.
26868 *
26869 * Acts as the identity function when given a non-forward-ref value.
26870 *
26871 * @usageNotes
26872 * ### Example
26873 *
26874 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'}
26875 *
26876 * @see `forwardRef`
26877 * @publicApi
26878 */
26879 function resolveForwardRef$1(type) {
26880 return isForwardRef(type) ? type() : type;
26881 }
26882 /** Checks whether a function is wrapped by a `forwardRef`. */
26883 function isForwardRef(fn) {
26884 return typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
26885 fn.__forward_ref__ === forwardRef;
26886 }
26887
26888 /**
26889 * @license
26890 * Copyright Google LLC All Rights Reserved.
26891 *
26892 * Use of this source code is governed by an MIT-style license that can be
26893 * found in the LICENSE file at https://angular.io/license
26894 */
26895 function assertNumber(actual, msg) {
26896 if (!(typeof actual === 'number')) {
26897 throwError(msg, typeof actual, 'number', '===');
26898 }
26899 }
26900 function assertString(actual, msg) {
26901 if (!(typeof actual === 'string')) {
26902 throwError(msg, actual === null ? 'null' : typeof actual, 'string', '===');
26903 }
26904 }
26905 function assertFunction(actual, msg) {
26906 if (!(typeof actual === 'function')) {
26907 throwError(msg, actual === null ? 'null' : typeof actual, 'function', '===');
26908 }
26909 }
26910 function assertEqual(actual, expected, msg) {
26911 if (!(actual == expected)) {
26912 throwError(msg, actual, expected, '==');
26913 }
26914 }
26915 function assertNotEqual(actual, expected, msg) {
26916 if (!(actual != expected)) {
26917 throwError(msg, actual, expected, '!=');
26918 }
26919 }
26920 function assertSame(actual, expected, msg) {
26921 if (!(actual === expected)) {
26922 throwError(msg, actual, expected, '===');
26923 }
26924 }
26925 function assertNotSame(actual, expected, msg) {
26926 if (!(actual !== expected)) {
26927 throwError(msg, actual, expected, '!==');
26928 }
26929 }
26930 function assertLessThan(actual, expected, msg) {
26931 if (!(actual < expected)) {
26932 throwError(msg, actual, expected, '<');
26933 }
26934 }
26935 function assertGreaterThan(actual, expected, msg) {
26936 if (!(actual > expected)) {
26937 throwError(msg, actual, expected, '>');
26938 }
26939 }
26940 function assertGreaterThanOrEqual(actual, expected, msg) {
26941 if (!(actual >= expected)) {
26942 throwError(msg, actual, expected, '>=');
26943 }
26944 }
26945 function assertDefined(actual, msg) {
26946 if (actual == null) {
26947 throwError(msg, actual, null, '!=');
26948 }
26949 }
26950 function throwError(msg, actual, expected, comparison) {
26951 throw new Error(`ASSERTION ERROR: ${msg}` +
26952 (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
26953 }
26954 function assertDomNode(node) {
26955 // If we're in a worker, `Node` will not be defined.
26956 if (!(typeof Node !== 'undefined' && node instanceof Node) &&
26957 !(typeof node === 'object' && node != null &&
26958 node.constructor.name === 'WebWorkerRenderNode')) {
26959 throwError(`The provided value must be an instance of a DOM Node but got ${stringify$1(node)}`);
26960 }
26961 }
26962 function assertIndexInRange(arr, index) {
26963 assertDefined(arr, 'Array must be defined.');
26964 const maxLen = arr.length;
26965 if (index < 0 || index >= maxLen) {
26966 throwError(`Index expected to be less than ${maxLen} but got ${index}`);
26967 }
26968 }
26969
26970 /**
26971 * @license
26972 * Copyright Google LLC All Rights Reserved.
26973 *
26974 * Use of this source code is governed by an MIT-style license that can be
26975 * found in the LICENSE file at https://angular.io/license
26976 */
26977 /**
26978 * Construct an `InjectableDef` which defines how a token will be constructed by the DI system, and
26979 * in which injectors (if any) it will be available.
26980 *
26981 * This should be assigned to a static `ɵprov` field on a type, which will then be an
26982 * `InjectableType`.
26983 *
26984 * Options:
26985 * * `providedIn` determines which injectors will include the injectable, by either associating it
26986 * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
26987 * provided in the `'root'` injector, which will be the application-level injector in most apps.
26988 * * `factory` gives the zero argument function which will create an instance of the injectable.
26989 * The factory can call `inject` to access the `Injector` and request injection of dependencies.
26990 *
26991 * @codeGenApi
26992 * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
26993 */
26994 function ɵɵdefineInjectable(opts) {
26995 return {
26996 token: opts.token,
26997 providedIn: opts.providedIn || null,
26998 factory: opts.factory,
26999 value: undefined,
27000 };
27001 }
27002 /**
27003 * Construct an `InjectorDef` which configures an injector.
27004 *
27005 * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
27006 * `InjectorType`.
27007 *
27008 * Options:
27009 *
27010 * * `factory`: an `InjectorType` is an instantiable type, so a zero argument `factory` function to
27011 * create the type must be provided. If that factory function needs to inject arguments, it can
27012 * use the `inject` function.
27013 * * `providers`: an optional array of providers to add to the injector. Each provider must
27014 * either have a factory or point to a type which has a `ɵprov` static property (the
27015 * type must be an `InjectableType`).
27016 * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
27017 * whose providers will also be added to the injector. Locally provided types will override
27018 * providers from imports.
27019 *
27020 * @codeGenApi
27021 */
27022 function ɵɵdefineInjector(options) {
27023 return {
27024 factory: options.factory,
27025 providers: options.providers || [],
27026 imports: options.imports || [],
27027 };
27028 }
27029 /**
27030 * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
27031 * inherited value.
27032 *
27033 * @param type A type which may have its own (non-inherited) `ɵprov`.
27034 */
27035 function getInjectableDef(type) {
27036 return getOwnDefinition(type, NG_PROV_DEF) || getOwnDefinition(type, NG_INJECTABLE_DEF);
27037 }
27038 /**
27039 * Return definition only if it is defined directly on `type` and is not inherited from a base
27040 * class of `type`.
27041 */
27042 function getOwnDefinition(type, field) {
27043 return type.hasOwnProperty(field) ? type[field] : null;
27044 }
27045 const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty });
27046 const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty });
27047 // We need to keep these around so we can read off old defs if new defs are unavailable
27048 const NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty });
27049 const NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty });
27050
27051 /**
27052 * @license
27053 * Copyright Google LLC All Rights Reserved.
27054 *
27055 * Use of this source code is governed by an MIT-style license that can be
27056 * found in the LICENSE file at https://angular.io/license
27057 */
27058 /**
27059 * Injection flags for DI.
27060 *
27061 * @publicApi
27062 */
27063 var InjectFlags;
27064 (function (InjectFlags) {
27065 // TODO(alxhub): make this 'const' (and remove `InternalInjectFlags` enum) when ngc no longer
27066 // writes exports of it into ngfactory files.
27067 /** Check self and check parent injector if needed */
27068 InjectFlags[InjectFlags["Default"] = 0] = "Default";
27069 /**
27070 * Specifies that an injector should retrieve a dependency from any injector until reaching the
27071 * host element of the current component. (Only used with Element Injector)
27072 */
27073 InjectFlags[InjectFlags["Host"] = 1] = "Host";
27074 /** Don't ascend to ancestors of the node requesting injection. */
27075 InjectFlags[InjectFlags["Self"] = 2] = "Self";
27076 /** Skip the node that is requesting injection. */
27077 InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf";
27078 /** Inject `defaultValue` instead if token not found. */
27079 InjectFlags[InjectFlags["Optional"] = 8] = "Optional";
27080 })(InjectFlags || (InjectFlags = {}));
27081
27082 /**
27083 * @license
27084 * Copyright Google LLC All Rights Reserved.
27085 *
27086 * Use of this source code is governed by an MIT-style license that can be
27087 * found in the LICENSE file at https://angular.io/license
27088 */
27089 /**
27090 * Current implementation of inject.
27091 *
27092 * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
27093 * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
27094 * way for two reasons:
27095 * 1. `Injector` should not depend on ivy logic.
27096 * 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
27097 */
27098 let _injectImplementation;
27099 function getInjectImplementation() {
27100 return _injectImplementation;
27101 }
27102 /**
27103 * Sets the current inject implementation.
27104 */
27105 function setInjectImplementation(impl) {
27106 const previous = _injectImplementation;
27107 _injectImplementation = impl;
27108 return previous;
27109 }
27110 /**
27111 * Injects `root` tokens in limp mode.
27112 *
27113 * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
27114 * `"root"`. This is known as the limp mode injection. In such case the value is stored in the
27115 * `InjectableDef`.
27116 */
27117 function injectRootLimpMode(token, notFoundValue, flags) {
27118 const injectableDef = getInjectableDef(token);
27119 if (injectableDef && injectableDef.providedIn == 'root') {
27120 return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
27121 injectableDef.value;
27122 }
27123 if (flags & InjectFlags.Optional)
27124 return null;
27125 if (notFoundValue !== undefined)
27126 return notFoundValue;
27127 throw new Error(`Injector: NOT_FOUND [${stringify$1(token)}]`);
27128 }
27129
27130 /**
27131 * @license
27132 * Copyright Google LLC All Rights Reserved.
27133 *
27134 * Use of this source code is governed by an MIT-style license that can be
27135 * found in the LICENSE file at https://angular.io/license
27136 */
27137 /**
27138 * Convince closure compiler that the wrapped function has no side-effects.
27139 *
27140 * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to
27141 * allow us to execute a function but have closure compiler mark the call as no-side-effects.
27142 * It is important that the return value for the `noSideEffects` function be assigned
27143 * to something which is retained otherwise the call to `noSideEffects` will be removed by closure
27144 * compiler.
27145 */
27146 function noSideEffects(fn) {
27147 return { toString: fn }.toString();
27148 }
27149
27150 /**
27151 * @license
27152 * Copyright Google LLC All Rights Reserved.
27153 *
27154 * Use of this source code is governed by an MIT-style license that can be
27155 * found in the LICENSE file at https://angular.io/license
27156 */
27157 /**
27158 * The strategy that the default change detector uses to detect changes.
27159 * When set, takes effect the next time change detection is triggered.
27160 *
27161 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
27162 *
27163 * @publicApi
27164 */
27165 var ChangeDetectionStrategy$1;
27166 (function (ChangeDetectionStrategy) {
27167 /**
27168 * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated
27169 * until reactivated by setting the strategy to `Default` (`CheckAlways`).
27170 * Change detection can still be explicitly invoked.
27171 * This strategy applies to all child directives and cannot be overridden.
27172 */
27173 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
27174 /**
27175 * Use the default `CheckAlways` strategy, in which change detection is automatic until
27176 * explicitly deactivated.
27177 */
27178 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
27179 })(ChangeDetectionStrategy$1 || (ChangeDetectionStrategy$1 = {}));
27180 /**
27181 * Defines the possible states of the default change detector.
27182 * @see `ChangeDetectorRef`
27183 */
27184 var ChangeDetectorStatus;
27185 (function (ChangeDetectorStatus) {
27186 /**
27187 * A state in which, after calling `detectChanges()`, the change detector
27188 * state becomes `Checked`, and must be explicitly invoked or reactivated.
27189 */
27190 ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce";
27191 /**
27192 * A state in which change detection is skipped until the change detector mode
27193 * becomes `CheckOnce`.
27194 */
27195 ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked";
27196 /**
27197 * A state in which change detection continues automatically until explicitly
27198 * deactivated.
27199 */
27200 ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways";
27201 /**
27202 * A state in which a change detector sub tree is not a part of the main tree and
27203 * should be skipped.
27204 */
27205 ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached";
27206 /**
27207 * Indicates that the change detector encountered an error checking a binding
27208 * or calling a directive lifecycle method and is now in an inconsistent state. Change
27209 * detectors in this state do not detect changes.
27210 */
27211 ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored";
27212 /**
27213 * Indicates that the change detector has been destroyed.
27214 */
27215 ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed";
27216 })(ChangeDetectorStatus || (ChangeDetectorStatus = {}));
27217
27218 /**
27219 * @license
27220 * Copyright Google LLC All Rights Reserved.
27221 *
27222 * Use of this source code is governed by an MIT-style license that can be
27223 * found in the LICENSE file at https://angular.io/license
27224 */
27225 /**
27226 * Defines template and style encapsulation options available for Component's {@link Component}.
27227 *
27228 * See {@link Component#encapsulation encapsulation}.
27229 *
27230 * @usageNotes
27231 * ### Example
27232 *
27233 * {@example core/ts/metadata/encapsulation.ts region='longform'}
27234 *
27235 * @publicApi
27236 */
27237 var ViewEncapsulation$1;
27238 (function (ViewEncapsulation) {
27239 /**
27240 * Emulate `Native` scoping of styles by adding an attribute containing surrogate id to the Host
27241 * Element and pre-processing the style rules provided via {@link Component#styles styles} or
27242 * {@link Component#styleUrls styleUrls}, and adding the new Host Element attribute to all
27243 * selectors.
27244 *
27245 * This is the default option.
27246 */
27247 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
27248 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
27249 /**
27250 * Don't provide any template or style encapsulation.
27251 */
27252 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
27253 /**
27254 * Use Shadow DOM to encapsulate styles.
27255 *
27256 * For the DOM this means using modern [Shadow
27257 * DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) and
27258 * creating a ShadowRoot for Component's Host Element.
27259 */
27260 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
27261 })(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
27262
27263 /**
27264 * @license
27265 * Copyright Google LLC All Rights Reserved.
27266 *
27267 * Use of this source code is governed by an MIT-style license that can be
27268 * found in the LICENSE file at https://angular.io/license
27269 */
27270 const __globalThis = typeof globalThis !== 'undefined' && globalThis;
27271 const __window$1 = typeof window !== 'undefined' && window;
27272 const __self$1 = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
27273 self instanceof WorkerGlobalScope && self;
27274 const __global$1 = typeof global !== 'undefined' && global;
27275 // Always use __globalThis if available, which is the spec-defined global variable across all
27276 // environments, then fallback to __global first, because in Node tests both __global and
27277 // __window may be defined and _global should be __global in that case.
27278 const _global$1 = __globalThis || __global$1 || __window$1 || __self$1;
27279
27280 /**
27281 * @license
27282 * Copyright Google LLC All Rights Reserved.
27283 *
27284 * Use of this source code is governed by an MIT-style license that can be
27285 * found in the LICENSE file at https://angular.io/license
27286 */
27287 function ngDevModeResetPerfCounters() {
27288 const locationString = typeof location !== 'undefined' ? location.toString() : '';
27289 const newCounters = {
27290 namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1,
27291 firstCreatePass: 0,
27292 tNode: 0,
27293 tView: 0,
27294 rendererCreateTextNode: 0,
27295 rendererSetText: 0,
27296 rendererCreateElement: 0,
27297 rendererAddEventListener: 0,
27298 rendererSetAttribute: 0,
27299 rendererRemoveAttribute: 0,
27300 rendererSetProperty: 0,
27301 rendererSetClassName: 0,
27302 rendererAddClass: 0,
27303 rendererRemoveClass: 0,
27304 rendererSetStyle: 0,
27305 rendererRemoveStyle: 0,
27306 rendererDestroy: 0,
27307 rendererDestroyNode: 0,
27308 rendererMoveNode: 0,
27309 rendererRemoveNode: 0,
27310 rendererAppendChild: 0,
27311 rendererInsertBefore: 0,
27312 rendererCreateComment: 0,
27313 };
27314 // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
27315 const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
27316 _global$1['ngDevMode'] = allowNgDevModeTrue && newCounters;
27317 return newCounters;
27318 }
27319 /**
27320 * This function checks to see if the `ngDevMode` has been set. If yes,
27321 * then we honor it, otherwise we default to dev mode with additional checks.
27322 *
27323 * The idea is that unless we are doing production build where we explicitly
27324 * set `ngDevMode == false` we should be helping the developer by providing
27325 * as much early warning and errors as possible.
27326 *
27327 * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions
27328 * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode
27329 * is defined for the entire instruction set.
27330 *
27331 * When checking `ngDevMode` on toplevel, always init it before referencing it
27332 * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can
27333 * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595.
27334 *
27335 * Details on possible values for `ngDevMode` can be found on its docstring.
27336 *
27337 * NOTE:
27338 * - changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`.
27339 */
27340 function initNgDevMode() {
27341 // The below checks are to ensure that calling `initNgDevMode` multiple times does not
27342 // reset the counters.
27343 // If the `ngDevMode` is not an object, then it means we have not created the perf counters
27344 // yet.
27345 if (typeof ngDevMode === 'undefined' || ngDevMode) {
27346 if (typeof ngDevMode !== 'object') {
27347 ngDevModeResetPerfCounters();
27348 }
27349 return typeof ngDevMode !== 'undefined' && !!ngDevMode;
27350 }
27351 return false;
27352 }
27353
27354 /**
27355 * @license
27356 * Copyright Google LLC All Rights Reserved.
27357 *
27358 * Use of this source code is governed by an MIT-style license that can be
27359 * found in the LICENSE file at https://angular.io/license
27360 */
27361 /**
27362 * This file contains reuseable "empty" symbols that can be used as default return values
27363 * in different parts of the rendering code. Because the same symbols are returned, this
27364 * allows for identity checks against these values to be consistently used by the framework
27365 * code.
27366 */
27367 const EMPTY_OBJ = {};
27368 const EMPTY_ARRAY = [];
27369 // freezing the values prevents any code from accidentally inserting new values in
27370 if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
27371 // These property accesses can be ignored because ngDevMode will be set to false
27372 // when optimizing code and the whole if statement will be dropped.
27373 // tslint:disable-next-line:no-toplevel-property-access
27374 Object.freeze(EMPTY_OBJ);
27375 // tslint:disable-next-line:no-toplevel-property-access
27376 Object.freeze(EMPTY_ARRAY);
27377 }
27378
27379 /**
27380 * @license
27381 * Copyright Google LLC All Rights Reserved.
27382 *
27383 * Use of this source code is governed by an MIT-style license that can be
27384 * found in the LICENSE file at https://angular.io/license
27385 */
27386 const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty });
27387 const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty });
27388 const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty });
27389 const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty });
27390 const NG_LOC_ID_DEF = getClosureSafeProperty({ ɵloc: getClosureSafeProperty });
27391 const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty });
27392 /**
27393 * If a directive is diPublic, bloomAdd sets a property on the type with this constant as
27394 * the key and the directive's unique ID as the value. This allows us to map directives to their
27395 * bloom filter bit for DI.
27396 */
27397 // TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified.
27398 const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty });
27399
27400 /**
27401 * @license
27402 * Copyright Google LLC All Rights Reserved.
27403 *
27404 * Use of this source code is governed by an MIT-style license that can be
27405 * found in the LICENSE file at https://angular.io/license
27406 */
27407 /**
27408 * The following getter methods retrieve the definition from the type. Currently the retrieval
27409 * honors inheritance, but in the future we may change the rule to require that definitions are
27410 * explicit. This would require some sort of migration strategy.
27411 */
27412 function getComponentDef(type) {
27413 return type[NG_COMP_DEF] || null;
27414 }
27415
27416 /**
27417 * @license
27418 * Copyright Google LLC All Rights Reserved.
27419 *
27420 * Use of this source code is governed by an MIT-style license that can be
27421 * found in the LICENSE file at https://angular.io/license
27422 */
27423 // Below are constants for LView indices to help us look up LView members
27424 // without having to remember the specific indices.
27425 // Uglify will inline these when minifying so there shouldn't be a cost.
27426 const HOST = 0;
27427 const TVIEW = 1;
27428 const FLAGS = 2;
27429 const PARENT = 3;
27430 const NEXT = 4;
27431 const TRANSPLANTED_VIEWS_TO_REFRESH = 5;
27432 const T_HOST = 6;
27433 const CLEANUP = 7;
27434 const CONTEXT = 8;
27435 const INJECTOR = 9;
27436 const RENDERER_FACTORY = 10;
27437 const RENDERER = 11;
27438 const SANITIZER = 12;
27439 const CHILD_HEAD = 13;
27440 const CHILD_TAIL = 14;
27441 // FIXME(misko): Investigate if the three declarations aren't all same thing.
27442 const DECLARATION_VIEW = 15;
27443 const DECLARATION_COMPONENT_VIEW = 16;
27444 const DECLARATION_LCONTAINER = 17;
27445 const PREORDER_HOOK_FLAGS = 18;
27446 const QUERIES = 19;
27447 /**
27448 * Size of LView's header. Necessary to adjust for it when setting slots.
27449 *
27450 * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
27451 * instruction index into `LView` index. All other indexes should be in the `LView` index space and
27452 * there should be no need to refer to `HEADER_OFFSET` anywhere else.
27453 */
27454 const HEADER_OFFSET = 20;
27455 /**
27456 * Converts `TViewType` into human readable text.
27457 * Make sure this matches with `TViewType`
27458 */
27459 const TViewTypeAsString = [
27460 'Root',
27461 'Component',
27462 'Embedded',
27463 ];
27464
27465 /**
27466 * @license
27467 * Copyright Google LLC All Rights Reserved.
27468 *
27469 * Use of this source code is governed by an MIT-style license that can be
27470 * found in the LICENSE file at https://angular.io/license
27471 */
27472 /**
27473 * Special location which allows easy identification of type. If we have an array which was
27474 * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
27475 * `LContainer`.
27476 */
27477 const TYPE = 1;
27478 /**
27479 * Below are constants for LContainer indices to help us look up LContainer members
27480 * without having to remember the specific indices.
27481 * Uglify will inline these when minifying so there shouldn't be a cost.
27482 */
27483 /**
27484 * Flag to signify that this `LContainer` may have transplanted views which need to be change
27485 * detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
27486 *
27487 * This flag, once set, is never unset for the `LContainer`. This means that when unset we can skip
27488 * a lot of work in `refreshEmbeddedViews`. But when set we still need to verify
27489 * that the `MOVED_VIEWS` are transplanted and on-push.
27490 */
27491 const HAS_TRANSPLANTED_VIEWS = 2;
27492 // PARENT, NEXT, TRANSPLANTED_VIEWS_TO_REFRESH are indices 3, 4, and 5
27493 // As we already have these constants in LView, we don't need to re-create them.
27494 // T_HOST is index 6
27495 // We already have this constants in LView, we don't need to re-create it.
27496 const NATIVE = 7;
27497 const VIEW_REFS = 8;
27498 const MOVED_VIEWS = 9;
27499 /**
27500 * Size of LContainer's header. Represents the index after which all views in the
27501 * container will be inserted. We need to keep a record of current views so we know
27502 * which views are already in the DOM (and don't need to be re-added) and so we can
27503 * remove views from the DOM when they are no longer required.
27504 */
27505 const CONTAINER_HEADER_OFFSET = 10;
27506
27507 /**
27508 * @license
27509 * Copyright Google LLC All Rights Reserved.
27510 *
27511 * Use of this source code is governed by an MIT-style license that can be
27512 * found in the LICENSE file at https://angular.io/license
27513 */
27514 /**
27515 * True if `value` is `LView`.
27516 * @param value wrapped value of `RNode`, `LView`, `LContainer`
27517 */
27518 function isLView(value) {
27519 return Array.isArray(value) && typeof value[TYPE] === 'object';
27520 }
27521 /**
27522 * True if `value` is `LContainer`.
27523 * @param value wrapped value of `RNode`, `LView`, `LContainer`
27524 */
27525 function isLContainer(value) {
27526 return Array.isArray(value) && value[TYPE] === true;
27527 }
27528 function isComponentHost(tNode) {
27529 return (tNode.flags & 2 /* isComponentHost */) === 2 /* isComponentHost */;
27530 }
27531 function isComponentDef(def) {
27532 return def.template !== null;
27533 }
27534 function isRootView(target) {
27535 return (target[FLAGS] & 512 /* IsRoot */) !== 0;
27536 }
27537
27538 /**
27539 * @license
27540 * Copyright Google LLC All Rights Reserved.
27541 *
27542 * Use of this source code is governed by an MIT-style license that can be
27543 * found in the LICENSE file at https://angular.io/license
27544 */
27545 // [Assert functions do not constraint type when they are guarded by a truthy
27546 // expression.](https://github.com/microsoft/TypeScript/issues/37295)
27547 function assertTNodeForLView(tNode, lView) {
27548 assertTNodeForTView(tNode, lView[TVIEW]);
27549 }
27550 function assertTNodeForTView(tNode, tView) {
27551 assertTNode(tNode);
27552 tNode.hasOwnProperty('tView_') &&
27553 assertEqual(tNode.tView_, tView, 'This TNode does not belong to this TView.');
27554 }
27555 function assertTNode(tNode) {
27556 assertDefined(tNode, 'TNode must be defined');
27557 if (!(tNode && typeof tNode === 'object' && tNode.hasOwnProperty('directiveStylingLast'))) {
27558 throwError('Not of type TNode, got: ' + tNode);
27559 }
27560 }
27561 function assertComponentType(actual, msg = 'Type passed in is not ComponentType, it does not have \'ɵcmp\' property.') {
27562 if (!getComponentDef(actual)) {
27563 throwError(msg);
27564 }
27565 }
27566 function assertLContainer(value) {
27567 assertDefined(value, 'LContainer must be defined');
27568 assertEqual(isLContainer(value), true, 'Expecting LContainer');
27569 }
27570 function assertLViewOrUndefined(value) {
27571 value && assertEqual(isLView(value), true, 'Expecting LView or undefined or null');
27572 }
27573 function assertLView(value) {
27574 assertDefined(value, 'LView must be defined');
27575 assertEqual(isLView(value), true, 'Expecting LView');
27576 }
27577 function assertFirstCreatePass(tView, errMessage) {
27578 assertEqual(tView.firstCreatePass, true, errMessage || 'Should only be called in first create pass.');
27579 }
27580 function assertFirstUpdatePass(tView, errMessage) {
27581 assertEqual(tView.firstUpdatePass, true, errMessage || 'Should only be called in first update pass.');
27582 }
27583 /**
27584 * This is a basic sanity check that an object is probably a directive def. DirectiveDef is
27585 * an interface, so we can't do a direct instanceof check.
27586 */
27587 function assertDirectiveDef(obj) {
27588 if (obj.type === undefined || obj.selectors == undefined || obj.inputs === undefined) {
27589 throwError(`Expected a DirectiveDef/ComponentDef and this object does not seem to have the expected shape.`);
27590 }
27591 }
27592 function assertIndexInDeclRange(lView, index) {
27593 const tView = lView[1];
27594 assertBetween(HEADER_OFFSET, tView.bindingStartIndex, index);
27595 }
27596 function assertIndexInExpandoRange(lView, index) {
27597 const tView = lView[1];
27598 assertBetween(tView.expandoStartIndex, lView.length, index);
27599 }
27600 function assertBetween(lower, upper, index) {
27601 if (!(lower <= index && index < upper)) {
27602 throwError(`Index out of range (expecting ${lower} <= ${index} < ${upper})`);
27603 }
27604 }
27605 function assertProjectionSlots(lView, errMessage) {
27606 assertDefined(lView[DECLARATION_COMPONENT_VIEW], 'Component views should exist.');
27607 assertDefined(lView[DECLARATION_COMPONENT_VIEW][T_HOST].projection, errMessage ||
27608 'Components with projection nodes (<ng-content>) must have projection slots defined.');
27609 }
27610 function assertParentView(lView, errMessage) {
27611 assertDefined(lView, errMessage || 'Component views should always have a parent view (component\'s host view)');
27612 }
27613 /**
27614 * This is a basic sanity check that the `injectorIndex` seems to point to what looks like a
27615 * NodeInjector data structure.
27616 *
27617 * @param lView `LView` which should be checked.
27618 * @param injectorIndex index into the `LView` where the `NodeInjector` is expected.
27619 */
27620 function assertNodeInjector(lView, injectorIndex) {
27621 assertIndexInExpandoRange(lView, injectorIndex);
27622 assertIndexInExpandoRange(lView, injectorIndex + 8 /* PARENT */);
27623 assertNumber(lView[injectorIndex + 0], 'injectorIndex should point to a bloom filter');
27624 assertNumber(lView[injectorIndex + 1], 'injectorIndex should point to a bloom filter');
27625 assertNumber(lView[injectorIndex + 2], 'injectorIndex should point to a bloom filter');
27626 assertNumber(lView[injectorIndex + 3], 'injectorIndex should point to a bloom filter');
27627 assertNumber(lView[injectorIndex + 4], 'injectorIndex should point to a bloom filter');
27628 assertNumber(lView[injectorIndex + 5], 'injectorIndex should point to a bloom filter');
27629 assertNumber(lView[injectorIndex + 6], 'injectorIndex should point to a bloom filter');
27630 assertNumber(lView[injectorIndex + 7], 'injectorIndex should point to a bloom filter');
27631 assertNumber(lView[injectorIndex + 8 /* PARENT */], 'injectorIndex should point to parent injector');
27632 }
27633
27634 /**
27635 * @license
27636 * Copyright Google LLC All Rights Reserved.
27637 *
27638 * Use of this source code is governed by an MIT-style license that can be
27639 * found in the LICENSE file at https://angular.io/license
27640 */
27641 function getFactoryDef(type, throwNotFound) {
27642 const hasFactoryDef = type.hasOwnProperty(NG_FACTORY_DEF);
27643 if (!hasFactoryDef && throwNotFound === true && ngDevMode) {
27644 throw new Error(`Type ${stringify$1(type)} does not have 'ɵfac' property.`);
27645 }
27646 return hasFactoryDef ? type[NG_FACTORY_DEF] : null;
27647 }
27648
27649 /**
27650 * @license
27651 * Copyright Google LLC All Rights Reserved.
27652 *
27653 * Use of this source code is governed by an MIT-style license that can be
27654 * found in the LICENSE file at https://angular.io/license
27655 */
27656 // Base URL for the error details page.
27657 // Keep this value in sync with a similar const in
27658 // `packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts`.
27659 const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors';
27660 class RuntimeError extends Error {
27661 constructor(code, message) {
27662 super(formatRuntimeError(code, message));
27663 this.code = code;
27664 }
27665 }
27666 // Contains a set of error messages that have details guides at angular.io.
27667 // Full list of available error guides can be found at https://angular.io/errors
27668 /* tslint:disable:no-toplevel-property-access */
27669 const RUNTIME_ERRORS_WITH_GUIDES = new Set([
27670 "100" /* EXPRESSION_CHANGED_AFTER_CHECKED */,
27671 "200" /* CYCLIC_DI_DEPENDENCY */,
27672 "201" /* PROVIDER_NOT_FOUND */,
27673 "300" /* MULTIPLE_COMPONENTS_MATCH */,
27674 "301" /* EXPORT_NOT_FOUND */,
27675 "302" /* PIPE_NOT_FOUND */,
27676 ]);
27677 /* tslint:enable:no-toplevel-property-access */
27678 /** Called to format a runtime error */
27679 function formatRuntimeError(code, message) {
27680 const fullCode = code ? `NG0${code}: ` : '';
27681 let errorMessage = `${fullCode}${message}`;
27682 // Some runtime errors are still thrown without `ngDevMode` (for example
27683 // `throwProviderNotFoundError`), so we add `ngDevMode` check here to avoid pulling
27684 // `RUNTIME_ERRORS_WITH_GUIDES` symbol into prod bundles.
27685 // TODO: revisit all instances where `RuntimeError` is thrown and see if `ngDevMode` can be added
27686 // there instead to tree-shake more devmode-only code (and eventually remove `ngDevMode` check
27687 // from this code).
27688 if (ngDevMode && RUNTIME_ERRORS_WITH_GUIDES.has(code)) {
27689 errorMessage = `${errorMessage}. Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/NG0${code}`;
27690 }
27691 return errorMessage;
27692 }
27693
27694 /**
27695 * @license
27696 * Copyright Google LLC All Rights Reserved.
27697 *
27698 * Use of this source code is governed by an MIT-style license that can be
27699 * found in the LICENSE file at https://angular.io/license
27700 */
27701 /**
27702 * Used for stringify render output in Ivy.
27703 * Important! This function is very performance-sensitive and we should
27704 * be extra careful not to introduce megamorphic reads in it.
27705 * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations.
27706 */
27707 function renderStringify(value) {
27708 if (typeof value === 'string')
27709 return value;
27710 if (value == null)
27711 return '';
27712 // Use `String` so that it invokes the `toString` method of the value. Note that this
27713 // appears to be faster than calling `value.toString` (see `render_stringify` benchmark).
27714 return String(value);
27715 }
27716 /**
27717 * Used to stringify a value so that it can be displayed in an error message.
27718 * Important! This function contains a megamorphic read and should only be
27719 * used for error messages.
27720 */
27721 function stringifyForError(value) {
27722 if (typeof value === 'function')
27723 return value.name || value.toString();
27724 if (typeof value === 'object' && value != null && typeof value.type === 'function') {
27725 return value.type.name || value.type.toString();
27726 }
27727 return renderStringify(value);
27728 }
27729
27730 /** Called when directives inject each other (creating a circular dependency) */
27731 function throwCyclicDependencyError(token, path) {
27732 const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
27733 throw new RuntimeError("200" /* CYCLIC_DI_DEPENDENCY */, `Circular dependency in DI detected for ${token}${depPath}`);
27734 }
27735 /** Throws an error when a token is not found in DI. */
27736 function throwProviderNotFoundError(token, injectorName) {
27737 const injectorDetails = injectorName ? ` in ${injectorName}` : '';
27738 throw new RuntimeError("201" /* PROVIDER_NOT_FOUND */, `No provider for ${stringifyForError(token)} found${injectorDetails}`);
27739 }
27740
27741 /**
27742 * @license
27743 * Copyright Google LLC All Rights Reserved.
27744 *
27745 * Use of this source code is governed by an MIT-style license that can be
27746 * found in the LICENSE file at https://angular.io/license
27747 */
27748 /**
27749 * Represents a basic change from a previous to a new value for a single
27750 * property on a directive instance. Passed as a value in a
27751 * {@link SimpleChanges} object to the `ngOnChanges` hook.
27752 *
27753 * @see `OnChanges`
27754 *
27755 * @publicApi
27756 */
27757 class SimpleChange {
27758 constructor(previousValue, currentValue, firstChange) {
27759 this.previousValue = previousValue;
27760 this.currentValue = currentValue;
27761 this.firstChange = firstChange;
27762 }
27763 /**
27764 * Check whether the new value is the first value assigned.
27765 */
27766 isFirstChange() {
27767 return this.firstChange;
27768 }
27769 }
27770
27771 /**
27772 * @license
27773 * Copyright Google LLC All Rights Reserved.
27774 *
27775 * Use of this source code is governed by an MIT-style license that can be
27776 * found in the LICENSE file at https://angular.io/license
27777 */
27778 function NgOnChangesFeatureImpl(definition) {
27779 if (definition.type.prototype.ngOnChanges) {
27780 definition.setInput = ngOnChangesSetInput;
27781 }
27782 return rememberChangeHistoryAndInvokeOnChangesHook;
27783 }
27784 /**
27785 * This is a synthetic lifecycle hook which gets inserted into `TView.preOrderHooks` to simulate
27786 * `ngOnChanges`.
27787 *
27788 * The hook reads the `NgSimpleChangesStore` data from the component instance and if changes are
27789 * found it invokes `ngOnChanges` on the component instance.
27790 *
27791 * @param this Component instance. Because this function gets inserted into `TView.preOrderHooks`,
27792 * it is guaranteed to be called with component instance.
27793 */
27794 function rememberChangeHistoryAndInvokeOnChangesHook() {
27795 const simpleChangesStore = getSimpleChangesStore(this);
27796 const current = simpleChangesStore === null || simpleChangesStore === void 0 ? void 0 : simpleChangesStore.current;
27797 if (current) {
27798 const previous = simpleChangesStore.previous;
27799 if (previous === EMPTY_OBJ) {
27800 simpleChangesStore.previous = current;
27801 }
27802 else {
27803 // New changes are copied to the previous store, so that we don't lose history for inputs
27804 // which were not changed this time
27805 for (let key in current) {
27806 previous[key] = current[key];
27807 }
27808 }
27809 simpleChangesStore.current = null;
27810 this.ngOnChanges(current);
27811 }
27812 }
27813 function ngOnChangesSetInput(instance, value, publicName, privateName) {
27814 const simpleChangesStore = getSimpleChangesStore(instance) ||
27815 setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
27816 const current = simpleChangesStore.current || (simpleChangesStore.current = {});
27817 const previous = simpleChangesStore.previous;
27818 const declaredName = this.declaredInputs[publicName];
27819 const previousChange = previous[declaredName];
27820 current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
27821 instance[privateName] = value;
27822 }
27823 const SIMPLE_CHANGES_STORE = '__ngSimpleChanges__';
27824 function getSimpleChangesStore(instance) {
27825 return instance[SIMPLE_CHANGES_STORE] || null;
27826 }
27827 function setSimpleChangesStore(instance, store) {
27828 return instance[SIMPLE_CHANGES_STORE] = store;
27829 }
27830
27831 /**
27832 * @license
27833 * Copyright Google LLC All Rights Reserved.
27834 *
27835 * Use of this source code is governed by an MIT-style license that can be
27836 * found in the LICENSE file at https://angular.io/license
27837 */
27838 const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
27839 const MATH_ML_NAMESPACE = 'http://www.w3.org/1998/MathML/';
27840
27841 /**
27842 * @license
27843 * Copyright Google LLC All Rights Reserved.
27844 *
27845 * Use of this source code is governed by an MIT-style license that can be
27846 * found in the LICENSE file at https://angular.io/license
27847 */
27848 /**
27849 * This property will be monkey-patched on elements, components and directives
27850 */
27851 const MONKEY_PATCH_KEY_NAME = '__ngContext__';
27852
27853 /**
27854 * @license
27855 * Copyright Google LLC All Rights Reserved.
27856 *
27857 * Use of this source code is governed by an MIT-style license that can be
27858 * found in the LICENSE file at https://angular.io/license
27859 */
27860 /**
27861 * Access the object that represents the `document` for this platform.
27862 *
27863 * Ivy calls this whenever it needs to access the `document` object.
27864 * For example to create the renderer or to do sanitization.
27865 */
27866 function getDocument() {
27867 if (typeof document !== 'undefined') {
27868 return document;
27869 }
27870 // No "document" can be found. This should only happen if we are running ivy outside Angular and
27871 // the current platform is not a browser. Since this is not a supported scenario at the moment
27872 // this should not happen in Angular apps.
27873 // Once we support running ivy outside of Angular we will need to publish `setDocument()` as a
27874 // public API. Meanwhile we just return `undefined` and let the application fail.
27875 return undefined;
27876 }
27877
27878 /**
27879 * @license
27880 * Copyright Google LLC All Rights Reserved.
27881 *
27882 * Use of this source code is governed by an MIT-style license that can be
27883 * found in the LICENSE file at https://angular.io/license
27884 */
27885 // TODO: cleanup once the code is merged in angular/angular
27886 var RendererStyleFlags3;
27887 (function (RendererStyleFlags3) {
27888 RendererStyleFlags3[RendererStyleFlags3["Important"] = 1] = "Important";
27889 RendererStyleFlags3[RendererStyleFlags3["DashCase"] = 2] = "DashCase";
27890 })(RendererStyleFlags3 || (RendererStyleFlags3 = {}));
27891 /** Returns whether the `renderer` is a `ProceduralRenderer3` */
27892 function isProceduralRenderer(renderer) {
27893 return !!(renderer.listen);
27894 }
27895 const ɵ0 = (hostElement, rendererType) => {
27896 return getDocument();
27897 };
27898 const domRendererFactory3 = {
27899 createRenderer: ɵ0
27900 };
27901
27902 /**
27903 * @license
27904 * Copyright Google LLC All Rights Reserved.
27905 *
27906 * Use of this source code is governed by an MIT-style license that can be
27907 * found in the LICENSE file at https://angular.io/license
27908 */
27909 /**
27910 * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
27911 * in same location in `LView`. This is because we don't want to pre-allocate space for it
27912 * because the storage is sparse. This file contains utilities for dealing with such data types.
27913 *
27914 * How do we know what is stored at a given location in `LView`.
27915 * - `Array.isArray(value) === false` => `RNode` (The normal storage value)
27916 * - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value.
27917 * - `typeof value[TYPE] === 'object'` => `LView`
27918 * - This happens when we have a component at a given location
27919 * - `typeof value[TYPE] === true` => `LContainer`
27920 * - This happens when we have `LContainer` binding at a given location.
27921 *
27922 *
27923 * NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.
27924 */
27925 /**
27926 * Returns `RNode`.
27927 * @param value wrapped value of `RNode`, `LView`, `LContainer`
27928 */
27929 function unwrapRNode(value) {
27930 while (Array.isArray(value)) {
27931 value = value[HOST];
27932 }
27933 return value;
27934 }
27935 /**
27936 * Retrieve an `RNode` for a given `TNode` and `LView`.
27937 *
27938 * This function guarantees in dev mode to retrieve a non-null `RNode`.
27939 *
27940 * @param tNode
27941 * @param lView
27942 */
27943 function getNativeByTNode(tNode, lView) {
27944 ngDevMode && assertTNodeForLView(tNode, lView);
27945 ngDevMode && assertIndexInRange(lView, tNode.index);
27946 const node = unwrapRNode(lView[tNode.index]);
27947 ngDevMode && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
27948 return node;
27949 }
27950 // fixme(misko): The return Type should be `TNode|null`
27951 function getTNode(tView, index) {
27952 ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
27953 ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode');
27954 const tNode = tView.data[index];
27955 ngDevMode && tNode !== null && assertTNode(tNode);
27956 return tNode;
27957 }
27958 function getComponentLViewByIndex(nodeIndex, hostView) {
27959 // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
27960 ngDevMode && assertIndexInRange(hostView, nodeIndex);
27961 const slotValue = hostView[nodeIndex];
27962 const lView = isLView(slotValue) ? slotValue : slotValue[HOST];
27963 return lView;
27964 }
27965 /**
27966 * Returns the monkey-patch value data present on the target (which could be
27967 * a component, directive or a DOM node).
27968 */
27969 function readPatchedData(target) {
27970 ngDevMode && assertDefined(target, 'Target expected');
27971 return target[MONKEY_PATCH_KEY_NAME] || null;
27972 }
27973 function readPatchedLView(target) {
27974 const value = readPatchedData(target);
27975 if (value) {
27976 return Array.isArray(value) ? value : value.lView;
27977 }
27978 return null;
27979 }
27980 /** Checks whether a given view is in creation mode */
27981 function isCreationMode(view) {
27982 return (view[FLAGS] & 4 /* CreationMode */) === 4 /* CreationMode */;
27983 }
27984 /**
27985 * Returns a boolean for whether the view is attached to the change detection tree.
27986 *
27987 * Note: This determines whether a view should be checked, not whether it's inserted
27988 * into a container. For that, you'll want `viewAttachedToContainer` below.
27989 */
27990 function viewAttachedToChangeDetector(view) {
27991 return (view[FLAGS] & 128 /* Attached */) === 128 /* Attached */;
27992 }
27993 /**
27994 * Resets the pre-order hook flags of the view.
27995 * @param lView the LView on which the flags are reset
27996 */
27997 function resetPreOrderHookFlags(lView) {
27998 lView[PREORDER_HOOK_FLAGS] = 0;
27999 }
28000 /**
28001 * Updates the `TRANSPLANTED_VIEWS_TO_REFRESH` counter on the `LContainer` as well as the parents
28002 * whose
28003 * 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
28004 * or
28005 * 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
28006 */
28007 function updateTransplantedViewCount(lContainer, amount) {
28008 lContainer[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
28009 let viewOrContainer = lContainer;
28010 let parent = lContainer[PARENT];
28011 while (parent !== null &&
28012 ((amount === 1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 1) ||
28013 (amount === -1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 0))) {
28014 parent[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
28015 viewOrContainer = parent;
28016 parent = parent[PARENT];
28017 }
28018 }
28019
28020 /**
28021 * @license
28022 * Copyright Google LLC All Rights Reserved.
28023 *
28024 * Use of this source code is governed by an MIT-style license that can be
28025 * found in the LICENSE file at https://angular.io/license
28026 */
28027 const instructionState = {
28028 lFrame: createLFrame(null),
28029 bindingsEnabled: true,
28030 isInCheckNoChangesMode: false,
28031 };
28032 /**
28033 * Return the current `LView`.
28034 */
28035 function getLView() {
28036 return instructionState.lFrame.lView;
28037 }
28038 /**
28039 * Return the current `TView`.
28040 */
28041 function getTView() {
28042 return instructionState.lFrame.tView;
28043 }
28044 function getCurrentTNode() {
28045 let currentTNode = getCurrentTNodePlaceholderOk();
28046 while (currentTNode !== null && currentTNode.type === 64 /* Placeholder */) {
28047 currentTNode = currentTNode.parent;
28048 }
28049 return currentTNode;
28050 }
28051 function getCurrentTNodePlaceholderOk() {
28052 return instructionState.lFrame.currentTNode;
28053 }
28054 function getCurrentParentTNode() {
28055 const lFrame = instructionState.lFrame;
28056 const currentTNode = lFrame.currentTNode;
28057 return lFrame.isParent ? currentTNode : currentTNode.parent;
28058 }
28059 function setCurrentTNode(tNode, isParent) {
28060 ngDevMode && tNode && assertTNodeForTView(tNode, instructionState.lFrame.tView);
28061 const lFrame = instructionState.lFrame;
28062 lFrame.currentTNode = tNode;
28063 lFrame.isParent = isParent;
28064 }
28065 function isCurrentTNodeParent() {
28066 return instructionState.lFrame.isParent;
28067 }
28068 function isInCheckNoChangesMode() {
28069 // TODO(misko): remove this from the LView since it is ngDevMode=true mode only.
28070 return instructionState.isInCheckNoChangesMode;
28071 }
28072 function setIsInCheckNoChangesMode(mode) {
28073 instructionState.isInCheckNoChangesMode = mode;
28074 }
28075 function setBindingIndex(value) {
28076 return instructionState.lFrame.bindingIndex = value;
28077 }
28078 function isInI18nBlock() {
28079 return instructionState.lFrame.inI18n;
28080 }
28081 /**
28082 * Set a new binding root index so that host template functions can execute.
28083 *
28084 * Bindings inside the host template are 0 index. But because we don't know ahead of time
28085 * how many host bindings we have we can't pre-compute them. For this reason they are all
28086 * 0 index and we just shift the root so that they match next available location in the LView.
28087 *
28088 * @param bindingRootIndex Root index for `hostBindings`
28089 * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive
28090 * whose `hostBindings` are being processed.
28091 */
28092 function setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex) {
28093 const lFrame = instructionState.lFrame;
28094 lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex;
28095 setCurrentDirectiveIndex(currentDirectiveIndex);
28096 }
28097 /**
28098 * Sets an index of a directive whose `hostBindings` are being processed.
28099 *
28100 * @param currentDirectiveIndex `TData` index where current directive instance can be found.
28101 */
28102 function setCurrentDirectiveIndex(currentDirectiveIndex) {
28103 instructionState.lFrame.currentDirectiveIndex = currentDirectiveIndex;
28104 }
28105 function setCurrentQueryIndex(value) {
28106 instructionState.lFrame.currentQueryIndex = value;
28107 }
28108 /**
28109 * Returns a `TNode` of the location where the current `LView` is declared at.
28110 *
28111 * @param lView an `LView` that we want to find parent `TNode` for.
28112 */
28113 function getDeclarationTNode(lView) {
28114 const tView = lView[TVIEW];
28115 // Return the declaration parent for embedded views
28116 if (tView.type === 2 /* Embedded */) {
28117 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
28118 return tView.declTNode;
28119 }
28120 // Components don't have `TView.declTNode` because each instance of component could be
28121 // inserted in different location, hence `TView.declTNode` is meaningless.
28122 // Falling back to `T_HOST` in case we cross component boundary.
28123 if (tView.type === 1 /* Component */) {
28124 return lView[T_HOST];
28125 }
28126 // Remaining TNode type is `TViewType.Root` which doesn't have a parent TNode.
28127 return null;
28128 }
28129 /**
28130 * This is a light weight version of the `enterView` which is needed by the DI system.
28131 *
28132 * @param lView `LView` location of the DI context.
28133 * @param tNode `TNode` for DI context
28134 * @param flags DI context flags. if `SkipSelf` flag is set than we walk up the declaration
28135 * tree from `tNode` until we find parent declared `TElementNode`.
28136 * @returns `true` if we have successfully entered DI associated with `tNode` (or with declared
28137 * `TNode` if `flags` has `SkipSelf`). Failing to enter DI implies that no associated
28138 * `NodeInjector` can be found and we should instead use `ModuleInjector`.
28139 * - If `true` than this call must be fallowed by `leaveDI`
28140 * - If `false` than this call failed and we should NOT call `leaveDI`
28141 */
28142 function enterDI(lView, tNode, flags) {
28143 ngDevMode && assertLViewOrUndefined(lView);
28144 if (flags & InjectFlags.SkipSelf) {
28145 ngDevMode && assertTNodeForTView(tNode, lView[TVIEW]);
28146 let parentTNode = tNode;
28147 let parentLView = lView;
28148 while (true) {
28149 ngDevMode && assertDefined(parentTNode, 'Parent TNode should be defined');
28150 parentTNode = parentTNode.parent;
28151 if (parentTNode === null && !(flags & InjectFlags.Host)) {
28152 parentTNode = getDeclarationTNode(parentLView);
28153 if (parentTNode === null)
28154 break;
28155 // In this case, a parent exists and is definitely an element. So it will definitely
28156 // have an existing lView as the declaration view, which is why we can assume it's defined.
28157 ngDevMode && assertDefined(parentLView, 'Parent LView should be defined');
28158 parentLView = parentLView[DECLARATION_VIEW];
28159 // In Ivy there are Comment nodes that correspond to ngIf and NgFor embedded directives
28160 // We want to skip those and look only at Elements and ElementContainers to ensure
28161 // we're looking at true parent nodes, and not content or other types.
28162 if (parentTNode.type & (2 /* Element */ | 8 /* ElementContainer */)) {
28163 break;
28164 }
28165 }
28166 else {
28167 break;
28168 }
28169 }
28170 if (parentTNode === null) {
28171 // If we failed to find a parent TNode this means that we should use module injector.
28172 return false;
28173 }
28174 else {
28175 tNode = parentTNode;
28176 lView = parentLView;
28177 }
28178 }
28179 ngDevMode && assertTNodeForLView(tNode, lView);
28180 const lFrame = instructionState.lFrame = allocLFrame();
28181 lFrame.currentTNode = tNode;
28182 lFrame.lView = lView;
28183 return true;
28184 }
28185 /**
28186 * Swap the current lView with a new lView.
28187 *
28188 * For performance reasons we store the lView in the top level of the module.
28189 * This way we minimize the number of properties to read. Whenever a new view
28190 * is entered we have to store the lView for later, and when the view is
28191 * exited the state has to be restored
28192 *
28193 * @param newView New lView to become active
28194 * @returns the previously active lView;
28195 */
28196 function enterView(newView) {
28197 ngDevMode && assertNotEqual(newView[0], newView[1], '????');
28198 ngDevMode && assertLViewOrUndefined(newView);
28199 const newLFrame = allocLFrame();
28200 if (ngDevMode) {
28201 assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
28202 assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
28203 assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
28204 assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
28205 assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
28206 assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
28207 assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
28208 assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
28209 assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
28210 }
28211 const tView = newView[TVIEW];
28212 instructionState.lFrame = newLFrame;
28213 ngDevMode && tView.firstChild && assertTNodeForTView(tView.firstChild, tView);
28214 newLFrame.currentTNode = tView.firstChild;
28215 newLFrame.lView = newView;
28216 newLFrame.tView = tView;
28217 newLFrame.contextLView = newView;
28218 newLFrame.bindingIndex = tView.bindingStartIndex;
28219 newLFrame.inI18n = false;
28220 }
28221 /**
28222 * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure.
28223 */
28224 function allocLFrame() {
28225 const currentLFrame = instructionState.lFrame;
28226 const childLFrame = currentLFrame === null ? null : currentLFrame.child;
28227 const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame;
28228 return newLFrame;
28229 }
28230 function createLFrame(parent) {
28231 const lFrame = {
28232 currentTNode: null,
28233 isParent: true,
28234 lView: null,
28235 tView: null,
28236 selectedIndex: -1,
28237 contextLView: null,
28238 elementDepthCount: 0,
28239 currentNamespace: null,
28240 currentDirectiveIndex: -1,
28241 bindingRootIndex: -1,
28242 bindingIndex: -1,
28243 currentQueryIndex: 0,
28244 parent: parent,
28245 child: null,
28246 inI18n: false,
28247 };
28248 parent !== null && (parent.child = lFrame); // link the new LFrame for reuse.
28249 return lFrame;
28250 }
28251 /**
28252 * A lightweight version of leave which is used with DI.
28253 *
28254 * This function only resets `currentTNode` and `LView` as those are the only properties
28255 * used with DI (`enterDI()`).
28256 *
28257 * NOTE: This function is reexported as `leaveDI`. However `leaveDI` has return type of `void` where
28258 * as `leaveViewLight` has `LFrame`. This is so that `leaveViewLight` can be used in `leaveView`.
28259 */
28260 function leaveViewLight() {
28261 const oldLFrame = instructionState.lFrame;
28262 instructionState.lFrame = oldLFrame.parent;
28263 oldLFrame.currentTNode = null;
28264 oldLFrame.lView = null;
28265 return oldLFrame;
28266 }
28267 /**
28268 * This is a lightweight version of the `leaveView` which is needed by the DI system.
28269 *
28270 * NOTE: this function is an alias so that we can change the type of the function to have `void`
28271 * return type.
28272 */
28273 const leaveDI = leaveViewLight;
28274 /**
28275 * Leave the current `LView`
28276 *
28277 * This pops the `LFrame` with the associated `LView` from the stack.
28278 *
28279 * IMPORTANT: We must zero out the `LFrame` values here otherwise they will be retained. This is
28280 * because for performance reasons we don't release `LFrame` but rather keep it for next use.
28281 */
28282 function leaveView() {
28283 const oldLFrame = leaveViewLight();
28284 oldLFrame.isParent = true;
28285 oldLFrame.tView = null;
28286 oldLFrame.selectedIndex = -1;
28287 oldLFrame.contextLView = null;
28288 oldLFrame.elementDepthCount = 0;
28289 oldLFrame.currentDirectiveIndex = -1;
28290 oldLFrame.currentNamespace = null;
28291 oldLFrame.bindingRootIndex = -1;
28292 oldLFrame.bindingIndex = -1;
28293 oldLFrame.currentQueryIndex = 0;
28294 }
28295 /**
28296 * Gets the currently selected element index.
28297 *
28298 * Used with {@link property} instruction (and more in the future) to identify the index in the
28299 * current `LView` to act on.
28300 */
28301 function getSelectedIndex() {
28302 return instructionState.lFrame.selectedIndex;
28303 }
28304 /**
28305 * Sets the most recent index passed to {@link select}
28306 *
28307 * Used with {@link property} instruction (and more in the future) to identify the index in the
28308 * current `LView` to act on.
28309 *
28310 * (Note that if an "exit function" was set earlier (via `setElementExitFn()`) then that will be
28311 * run if and when the provided `index` value is different from the current selected index value.)
28312 */
28313 function setSelectedIndex(index) {
28314 ngDevMode && index !== -1 &&
28315 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
28316 ngDevMode &&
28317 assertLessThan(index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView');
28318 instructionState.lFrame.selectedIndex = index;
28319 }
28320
28321 /**
28322 * @license
28323 * Copyright Google LLC All Rights Reserved.
28324 *
28325 * Use of this source code is governed by an MIT-style license that can be
28326 * found in the LICENSE file at https://angular.io/license
28327 */
28328 /**
28329 * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`.
28330 *
28331 * Must be run *only* on the first template pass.
28332 *
28333 * Sets up the pre-order hooks on the provided `tView`,
28334 * see {@link HookData} for details about the data structure.
28335 *
28336 * @param directiveIndex The index of the directive in LView
28337 * @param directiveDef The definition containing the hooks to setup in tView
28338 * @param tView The current TView
28339 */
28340 function registerPreOrderHooks(directiveIndex, directiveDef, tView) {
28341 ngDevMode && assertFirstCreatePass(tView);
28342 const { ngOnChanges, ngOnInit, ngDoCheck } = directiveDef.type.prototype;
28343 if (ngOnChanges) {
28344 const wrappedOnChanges = NgOnChangesFeatureImpl(directiveDef);
28345 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, wrappedOnChanges);
28346 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = []))
28347 .push(directiveIndex, wrappedOnChanges);
28348 }
28349 if (ngOnInit) {
28350 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(0 - directiveIndex, ngOnInit);
28351 }
28352 if (ngDoCheck) {
28353 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, ngDoCheck);
28354 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, ngDoCheck);
28355 }
28356 }
28357 /**
28358 *
28359 * Loops through the directives on the provided `tNode` and queues hooks to be
28360 * run that are not initialization hooks.
28361 *
28362 * Should be executed during `elementEnd()` and similar to
28363 * preserve hook execution order. Content, view, and destroy hooks for projected
28364 * components and directives must be called *before* their hosts.
28365 *
28366 * Sets up the content, view, and destroy hooks on the provided `tView`,
28367 * see {@link HookData} for details about the data structure.
28368 *
28369 * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up
28370 * separately at `elementStart`.
28371 *
28372 * @param tView The current TView
28373 * @param tNode The TNode whose directives are to be searched for hooks to queue
28374 */
28375 function registerPostOrderHooks(tView, tNode) {
28376 ngDevMode && assertFirstCreatePass(tView);
28377 // It's necessary to loop through the directives at elementEnd() (rather than processing in
28378 // directiveCreate) so we can preserve the current hook order. Content, view, and destroy
28379 // hooks for projected components and directives must be called *before* their hosts.
28380 for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) {
28381 const directiveDef = tView.data[i];
28382 ngDevMode && assertDefined(directiveDef, 'Expecting DirectiveDef');
28383 const lifecycleHooks = directiveDef.type.prototype;
28384 const { ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked, ngOnDestroy } = lifecycleHooks;
28385 if (ngAfterContentInit) {
28386 (tView.contentHooks || (tView.contentHooks = [])).push(-i, ngAfterContentInit);
28387 }
28388 if (ngAfterContentChecked) {
28389 (tView.contentHooks || (tView.contentHooks = [])).push(i, ngAfterContentChecked);
28390 (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, ngAfterContentChecked);
28391 }
28392 if (ngAfterViewInit) {
28393 (tView.viewHooks || (tView.viewHooks = [])).push(-i, ngAfterViewInit);
28394 }
28395 if (ngAfterViewChecked) {
28396 (tView.viewHooks || (tView.viewHooks = [])).push(i, ngAfterViewChecked);
28397 (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, ngAfterViewChecked);
28398 }
28399 if (ngOnDestroy != null) {
28400 (tView.destroyHooks || (tView.destroyHooks = [])).push(i, ngOnDestroy);
28401 }
28402 }
28403 }
28404 /**
28405 * Executing hooks requires complex logic as we need to deal with 2 constraints.
28406 *
28407 * 1. Init hooks (ngOnInit, ngAfterContentInit, ngAfterViewInit) must all be executed once and only
28408 * once, across many change detection cycles. This must be true even if some hooks throw, or if
28409 * some recursively trigger a change detection cycle.
28410 * To solve that, it is required to track the state of the execution of these init hooks.
28411 * This is done by storing and maintaining flags in the view: the {@link InitPhaseState},
28412 * and the index within that phase. They can be seen as a cursor in the following structure:
28413 * [[onInit1, onInit2], [afterContentInit1], [afterViewInit1, afterViewInit2, afterViewInit3]]
28414 * They are are stored as flags in LView[FLAGS].
28415 *
28416 * 2. Pre-order hooks can be executed in batches, because of the select instruction.
28417 * To be able to pause and resume their execution, we also need some state about the hook's array
28418 * that is being processed:
28419 * - the index of the next hook to be executed
28420 * - the number of init hooks already found in the processed part of the array
28421 * They are are stored as flags in LView[PREORDER_HOOK_FLAGS].
28422 */
28423 /**
28424 * Executes pre-order check hooks ( OnChanges, DoChanges) given a view where all the init hooks were
28425 * executed once. This is a light version of executeInitAndCheckPreOrderHooks where we can skip read
28426 * / write of the init-hooks related flags.
28427 * @param lView The LView where hooks are defined
28428 * @param hooks Hooks to be run
28429 * @param nodeIndex 3 cases depending on the value:
28430 * - undefined: all hooks from the array should be executed (post-order case)
28431 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
28432 * flushing the remaining hooks)
28433 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
28434 * case, when executing select(number))
28435 */
28436 function executeCheckHooks(lView, hooks, nodeIndex) {
28437 callHooks(lView, hooks, 3 /* InitPhaseCompleted */, nodeIndex);
28438 }
28439 /**
28440 * Executes post-order init and check hooks (one of AfterContentInit, AfterContentChecked,
28441 * AfterViewInit, AfterViewChecked) given a view where there are pending init hooks to be executed.
28442 * @param lView The LView where hooks are defined
28443 * @param hooks Hooks to be run
28444 * @param initPhase A phase for which hooks should be run
28445 * @param nodeIndex 3 cases depending on the value:
28446 * - undefined: all hooks from the array should be executed (post-order case)
28447 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
28448 * flushing the remaining hooks)
28449 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
28450 * case, when executing select(number))
28451 */
28452 function executeInitAndCheckHooks(lView, hooks, initPhase, nodeIndex) {
28453 ngDevMode &&
28454 assertNotEqual(initPhase, 3 /* InitPhaseCompleted */, 'Init pre-order hooks should not be called more than once');
28455 if ((lView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhase) {
28456 callHooks(lView, hooks, initPhase, nodeIndex);
28457 }
28458 }
28459 function incrementInitPhaseFlags(lView, initPhase) {
28460 ngDevMode &&
28461 assertNotEqual(initPhase, 3 /* InitPhaseCompleted */, 'Init hooks phase should not be incremented after all init hooks have been run.');
28462 let flags = lView[FLAGS];
28463 if ((flags & 3 /* InitPhaseStateMask */) === initPhase) {
28464 flags &= 2047 /* IndexWithinInitPhaseReset */;
28465 flags += 1 /* InitPhaseStateIncrementer */;
28466 lView[FLAGS] = flags;
28467 }
28468 }
28469 /**
28470 * Calls lifecycle hooks with their contexts, skipping init hooks if it's not
28471 * the first LView pass
28472 *
28473 * @param currentView The current view
28474 * @param arr The array in which the hooks are found
28475 * @param initPhaseState the current state of the init phase
28476 * @param currentNodeIndex 3 cases depending on the value:
28477 * - undefined: all hooks from the array should be executed (post-order case)
28478 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
28479 * flushing the remaining hooks)
28480 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
28481 * case, when executing select(number))
28482 */
28483 function callHooks(currentView, arr, initPhase, currentNodeIndex) {
28484 ngDevMode &&
28485 assertEqual(isInCheckNoChangesMode(), false, 'Hooks should never be run when in check no changes mode.');
28486 const startIndex = currentNodeIndex !== undefined ?
28487 (currentView[PREORDER_HOOK_FLAGS] & 65535 /* IndexOfTheNextPreOrderHookMaskMask */) :
28488 0;
28489 const nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1;
28490 const max = arr.length - 1; // Stop the loop at length - 1, because we look for the hook at i + 1
28491 let lastNodeIndexFound = 0;
28492 for (let i = startIndex; i < max; i++) {
28493 const hook = arr[i + 1];
28494 if (typeof hook === 'number') {
28495 lastNodeIndexFound = arr[i];
28496 if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) {
28497 break;
28498 }
28499 }
28500 else {
28501 const isInitHook = arr[i] < 0;
28502 if (isInitHook)
28503 currentView[PREORDER_HOOK_FLAGS] += 65536 /* NumberOfInitHooksCalledIncrementer */;
28504 if (lastNodeIndexFound < nodeIndexLimit || nodeIndexLimit == -1) {
28505 callHook(currentView, initPhase, arr, i);
28506 currentView[PREORDER_HOOK_FLAGS] =
28507 (currentView[PREORDER_HOOK_FLAGS] & 4294901760 /* NumberOfInitHooksCalledMask */) + i +
28508 2;
28509 }
28510 i++;
28511 }
28512 }
28513 }
28514 /**
28515 * Execute one hook against the current `LView`.
28516 *
28517 * @param currentView The current view
28518 * @param initPhaseState the current state of the init phase
28519 * @param arr The array in which the hooks are found
28520 * @param i The current index within the hook data array
28521 */
28522 function callHook(currentView, initPhase, arr, i) {
28523 const isInitHook = arr[i] < 0;
28524 const hook = arr[i + 1];
28525 const directiveIndex = isInitHook ? -arr[i] : arr[i];
28526 const directive = currentView[directiveIndex];
28527 if (isInitHook) {
28528 const indexWithintInitPhase = currentView[FLAGS] >> 11 /* IndexWithinInitPhaseShift */;
28529 // The init phase state must be always checked here as it may have been recursively updated.
28530 if (indexWithintInitPhase <
28531 (currentView[PREORDER_HOOK_FLAGS] >> 16 /* NumberOfInitHooksCalledShift */) &&
28532 (currentView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhase) {
28533 currentView[FLAGS] += 2048 /* IndexWithinInitPhaseIncrementer */;
28534 hook.call(directive);
28535 }
28536 }
28537 else {
28538 hook.call(directive);
28539 }
28540 }
28541
28542 /**
28543 * @license
28544 * Copyright Google LLC All Rights Reserved.
28545 *
28546 * Use of this source code is governed by an MIT-style license that can be
28547 * found in the LICENSE file at https://angular.io/license
28548 */
28549 const NO_PARENT_INJECTOR = -1;
28550 /**
28551 * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in
28552 * `TView.data`. This allows us to store information about the current node's tokens (which
28553 * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
28554 * shared, so they live in `LView`).
28555 *
28556 * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter
28557 * determines whether a directive is available on the associated node or not. This prevents us
28558 * from searching the directives array at this level unless it's probable the directive is in it.
28559 *
28560 * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
28561 *
28562 * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed
28563 * using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
28564 * will differ based on where it is flattened into the main array, so it's not possible to know
28565 * the indices ahead of time and save their types here. The interfaces are still included here
28566 * for documentation purposes.
28567 *
28568 * export interface LInjector extends Array<any> {
28569 *
28570 * // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
28571 * [0]: number;
28572 *
28573 * // Cumulative bloom for directive IDs 32-63
28574 * [1]: number;
28575 *
28576 * // Cumulative bloom for directive IDs 64-95
28577 * [2]: number;
28578 *
28579 * // Cumulative bloom for directive IDs 96-127
28580 * [3]: number;
28581 *
28582 * // Cumulative bloom for directive IDs 128-159
28583 * [4]: number;
28584 *
28585 * // Cumulative bloom for directive IDs 160 - 191
28586 * [5]: number;
28587 *
28588 * // Cumulative bloom for directive IDs 192 - 223
28589 * [6]: number;
28590 *
28591 * // Cumulative bloom for directive IDs 224 - 255
28592 * [7]: number;
28593 *
28594 * // We need to store a reference to the injector's parent so DI can keep looking up
28595 * // the injector tree until it finds the dependency it's looking for.
28596 * [PARENT_INJECTOR]: number;
28597 * }
28598 *
28599 * export interface TInjector extends Array<any> {
28600 *
28601 * // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
28602 * [0]: number;
28603 *
28604 * // Shared node bloom for directive IDs 32-63
28605 * [1]: number;
28606 *
28607 * // Shared node bloom for directive IDs 64-95
28608 * [2]: number;
28609 *
28610 * // Shared node bloom for directive IDs 96-127
28611 * [3]: number;
28612 *
28613 * // Shared node bloom for directive IDs 128-159
28614 * [4]: number;
28615 *
28616 * // Shared node bloom for directive IDs 160 - 191
28617 * [5]: number;
28618 *
28619 * // Shared node bloom for directive IDs 192 - 223
28620 * [6]: number;
28621 *
28622 * // Shared node bloom for directive IDs 224 - 255
28623 * [7]: number;
28624 *
28625 * // Necessary to find directive indices for a particular node.
28626 * [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
28627 * }
28628 */
28629 /**
28630 * Factory for creating instances of injectors in the NodeInjector.
28631 *
28632 * This factory is complicated by the fact that it can resolve `multi` factories as well.
28633 *
28634 * NOTE: Some of the fields are optional which means that this class has two hidden classes.
28635 * - One without `multi` support (most common)
28636 * - One with `multi` values, (rare).
28637 *
28638 * Since VMs can cache up to 4 inline hidden classes this is OK.
28639 *
28640 * - Single factory: Only `resolving` and `factory` is defined.
28641 * - `providers` factory: `componentProviders` is a number and `index = -1`.
28642 * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`.
28643 */
28644 class NodeInjectorFactory {
28645 constructor(
28646 /**
28647 * Factory to invoke in order to create a new instance.
28648 */
28649 factory,
28650 /**
28651 * Set to `true` if the token is declared in `viewProviders` (or if it is component).
28652 */
28653 isViewProvider, injectImplementation) {
28654 this.factory = factory;
28655 /**
28656 * Marker set to true during factory invocation to see if we get into recursive loop.
28657 * Recursive loop causes an error to be displayed.
28658 */
28659 this.resolving = false;
28660 ngDevMode && assertDefined(factory, 'Factory not specified');
28661 ngDevMode && assertEqual(typeof factory, 'function', 'Expected factory function.');
28662 this.canSeeViewProviders = isViewProvider;
28663 this.injectImpl = injectImplementation;
28664 }
28665 }
28666 function isFactory(obj) {
28667 return obj instanceof NodeInjectorFactory;
28668 }
28669
28670 /**
28671 * Converts `TNodeType` into human readable text.
28672 * Make sure this matches with `TNodeType`
28673 */
28674 function toTNodeTypeAsString(tNodeType) {
28675 let text = '';
28676 (tNodeType & 1 /* Text */) && (text += '|Text');
28677 (tNodeType & 2 /* Element */) && (text += '|Element');
28678 (tNodeType & 4 /* Container */) && (text += '|Container');
28679 (tNodeType & 8 /* ElementContainer */) && (text += '|ElementContainer');
28680 (tNodeType & 16 /* Projection */) && (text += '|Projection');
28681 (tNodeType & 32 /* Icu */) && (text += '|IcuContainer');
28682 (tNodeType & 64 /* Placeholder */) && (text += '|Placeholder');
28683 return text.length > 0 ? text.substring(1) : text;
28684 }
28685
28686 /**
28687 * @license
28688 * Copyright Google LLC All Rights Reserved.
28689 *
28690 * Use of this source code is governed by an MIT-style license that can be
28691 * found in the LICENSE file at https://angular.io/license
28692 */
28693 function assertTNodeType(tNode, expectedTypes, message) {
28694 assertDefined(tNode, 'should be called with a TNode');
28695 if ((tNode.type & expectedTypes) === 0) {
28696 throwError(message ||
28697 `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
28698 }
28699 }
28700 function assertPureTNodeType(type) {
28701 if (!(type === 2 /* Element */ || //
28702 type === 1 /* Text */ || //
28703 type === 4 /* Container */ || //
28704 type === 8 /* ElementContainer */ || //
28705 type === 32 /* Icu */ || //
28706 type === 16 /* Projection */ || //
28707 type === 64 /* Placeholder */)) {
28708 throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
28709 }
28710 }
28711
28712 /**
28713 * Assigns all attribute values to the provided element via the inferred renderer.
28714 *
28715 * This function accepts two forms of attribute entries:
28716 *
28717 * default: (key, value):
28718 * attrs = [key1, value1, key2, value2]
28719 *
28720 * namespaced: (NAMESPACE_MARKER, uri, name, value)
28721 * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
28722 *
28723 * The `attrs` array can contain a mix of both the default and namespaced entries.
28724 * The "default" values are set without a marker, but if the function comes across
28725 * a marker value then it will attempt to set a namespaced value. If the marker is
28726 * not of a namespaced value then the function will quit and return the index value
28727 * where it stopped during the iteration of the attrs array.
28728 *
28729 * See [AttributeMarker] to understand what the namespace marker value is.
28730 *
28731 * Note that this instruction does not support assigning style and class values to
28732 * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
28733 * are applied to an element.
28734 * @param renderer The renderer to be used
28735 * @param native The element that the attributes will be assigned to
28736 * @param attrs The attribute array of values that will be assigned to the element
28737 * @returns the index value that was last accessed in the attributes array
28738 */
28739 function setUpAttributes(renderer, native, attrs) {
28740 const isProc = isProceduralRenderer(renderer);
28741 let i = 0;
28742 while (i < attrs.length) {
28743 const value = attrs[i];
28744 if (typeof value === 'number') {
28745 // only namespaces are supported. Other value types (such as style/class
28746 // entries) are not supported in this function.
28747 if (value !== 0 /* NamespaceURI */) {
28748 break;
28749 }
28750 // we just landed on the marker value ... therefore
28751 // we should skip to the next entry
28752 i++;
28753 const namespaceURI = attrs[i++];
28754 const attrName = attrs[i++];
28755 const attrVal = attrs[i++];
28756 ngDevMode && ngDevMode.rendererSetAttribute++;
28757 isProc ?
28758 renderer.setAttribute(native, attrName, attrVal, namespaceURI) :
28759 native.setAttributeNS(namespaceURI, attrName, attrVal);
28760 }
28761 else {
28762 // attrName is string;
28763 const attrName = value;
28764 const attrVal = attrs[++i];
28765 // Standard attributes
28766 ngDevMode && ngDevMode.rendererSetAttribute++;
28767 if (isAnimationProp(attrName)) {
28768 if (isProc) {
28769 renderer.setProperty(native, attrName, attrVal);
28770 }
28771 }
28772 else {
28773 isProc ?
28774 renderer.setAttribute(native, attrName, attrVal) :
28775 native.setAttribute(attrName, attrVal);
28776 }
28777 i++;
28778 }
28779 }
28780 // another piece of code may iterate over the same attributes array. Therefore
28781 // it may be helpful to return the exact spot where the attributes array exited
28782 // whether by running into an unsupported marker or if all the static values were
28783 // iterated over.
28784 return i;
28785 }
28786 function isAnimationProp(name) {
28787 // Perf note: accessing charCodeAt to check for the first character of a string is faster as
28788 // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
28789 // charCodeAt doesn't allocate memory to return a substring.
28790 return name.charCodeAt(0) === 64 /* AT_SIGN */;
28791 }
28792
28793 /**
28794 * @license
28795 * Copyright Google LLC All Rights Reserved.
28796 *
28797 * Use of this source code is governed by an MIT-style license that can be
28798 * found in the LICENSE file at https://angular.io/license
28799 */
28800 /// Parent Injector Utils ///////////////////////////////////////////////////////////////
28801 function hasParentInjector(parentLocation) {
28802 return parentLocation !== NO_PARENT_INJECTOR;
28803 }
28804 function getParentInjectorIndex(parentLocation) {
28805 ngDevMode && assertNumber(parentLocation, 'Number expected');
28806 ngDevMode && assertNotEqual(parentLocation, -1, 'Not a valid state.');
28807 const parentInjectorIndex = parentLocation & 32767 /* InjectorIndexMask */;
28808 ngDevMode &&
28809 assertGreaterThan(parentInjectorIndex, HEADER_OFFSET, 'Parent injector must be pointing past HEADER_OFFSET.');
28810 return parentLocation & 32767 /* InjectorIndexMask */;
28811 }
28812 function getParentInjectorViewOffset(parentLocation) {
28813 return parentLocation >> 16 /* ViewOffsetShift */;
28814 }
28815 /**
28816 * Unwraps a parent injector location number to find the view offset from the current injector,
28817 * then walks up the declaration view tree until the view is found that contains the parent
28818 * injector.
28819 *
28820 * @param location The location of the parent injector, which contains the view offset
28821 * @param startView The LView instance from which to start walking up the view tree
28822 * @returns The LView instance that contains the parent injector
28823 */
28824 function getParentInjectorView(location, startView) {
28825 let viewOffset = getParentInjectorViewOffset(location);
28826 let parentView = startView;
28827 // For most cases, the parent injector can be found on the host node (e.g. for component
28828 // or container), but we must keep the loop here to support the rarer case of deeply nested
28829 // <ng-template> tags or inline views, where the parent injector might live many views
28830 // above the child injector.
28831 while (viewOffset > 0) {
28832 parentView = parentView[DECLARATION_VIEW];
28833 viewOffset--;
28834 }
28835 return parentView;
28836 }
28837
28838 /**
28839 * @license
28840 * Copyright Google LLC All Rights Reserved.
28841 *
28842 * Use of this source code is governed by an MIT-style license that can be
28843 * found in the LICENSE file at https://angular.io/license
28844 */
28845 /**
28846 * Defines if the call to `inject` should include `viewProviders` in its resolution.
28847 *
28848 * This is set to true when we try to instantiate a component. This value is reset in
28849 * `getNodeInjectable` to a value which matches the declaration location of the token about to be
28850 * instantiated. This is done so that if we are injecting a token which was declared outside of
28851 * `viewProviders` we don't accidentally pull `viewProviders` in.
28852 *
28853 * Example:
28854 *
28855 * ```
28856 * @Injectable()
28857 * class MyService {
28858 * constructor(public value: String) {}
28859 * }
28860 *
28861 * @Component({
28862 * providers: [
28863 * MyService,
28864 * {provide: String, value: 'providers' }
28865 * ]
28866 * viewProviders: [
28867 * {provide: String, value: 'viewProviders'}
28868 * ]
28869 * })
28870 * class MyComponent {
28871 * constructor(myService: MyService, value: String) {
28872 * // We expect that Component can see into `viewProviders`.
28873 * expect(value).toEqual('viewProviders');
28874 * // `MyService` was not declared in `viewProviders` hence it can't see it.
28875 * expect(myService.value).toEqual('providers');
28876 * }
28877 * }
28878 *
28879 * ```
28880 */
28881 let includeViewProviders = true;
28882 function setIncludeViewProviders(v) {
28883 const oldValue = includeViewProviders;
28884 includeViewProviders = v;
28885 return oldValue;
28886 }
28887 /**
28888 * The number of slots in each bloom filter (used by DI). The larger this number, the fewer
28889 * directives that will share slots, and thus, the fewer false positives when checking for
28890 * the existence of a directive.
28891 */
28892 const BLOOM_SIZE = 256;
28893 const BLOOM_MASK = BLOOM_SIZE - 1;
28894 /**
28895 * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits,
28896 * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash
28897 * number.
28898 */
28899 const BLOOM_BUCKET_BITS = 5;
28900 /** Counter used to generate unique IDs for directives. */
28901 let nextNgElementId = 0;
28902 /**
28903 * Registers this directive as present in its node's injector by flipping the directive's
28904 * corresponding bit in the injector's bloom filter.
28905 *
28906 * @param injectorIndex The index of the node injector where this token should be registered
28907 * @param tView The TView for the injector's bloom filters
28908 * @param type The directive token to register
28909 */
28910 function bloomAdd(injectorIndex, tView, type) {
28911 ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
28912 let id;
28913 if (typeof type === 'string') {
28914 id = type.charCodeAt(0) || 0;
28915 }
28916 else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
28917 id = type[NG_ELEMENT_ID];
28918 }
28919 // Set a unique ID on the directive type, so if something tries to inject the directive,
28920 // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
28921 if (id == null) {
28922 id = type[NG_ELEMENT_ID] = nextNgElementId++;
28923 }
28924 // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
28925 // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
28926 const bloomHash = id & BLOOM_MASK;
28927 // Create a mask that targets the specific bit associated with the directive.
28928 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
28929 // to bit positions 0 - 31 in a 32 bit integer.
28930 const mask = 1 << bloomHash;
28931 // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`.
28932 // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask
28933 // should be written to.
28934 tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask;
28935 }
28936 /**
28937 * Creates (or gets an existing) injector for a given element or container.
28938 *
28939 * @param tNode for which an injector should be retrieved / created.
28940 * @param lView View where the node is stored
28941 * @returns Node injector
28942 */
28943 function getOrCreateNodeInjectorForNode(tNode, lView) {
28944 const existingInjectorIndex = getInjectorIndex(tNode, lView);
28945 if (existingInjectorIndex !== -1) {
28946 return existingInjectorIndex;
28947 }
28948 const tView = lView[TVIEW];
28949 if (tView.firstCreatePass) {
28950 tNode.injectorIndex = lView.length;
28951 insertBloom(tView.data, tNode); // foundation for node bloom
28952 insertBloom(lView, null); // foundation for cumulative bloom
28953 insertBloom(tView.blueprint, null);
28954 }
28955 const parentLoc = getParentInjectorLocation(tNode, lView);
28956 const injectorIndex = tNode.injectorIndex;
28957 // If a parent injector can't be found, its location is set to -1.
28958 // In that case, we don't need to set up a cumulative bloom
28959 if (hasParentInjector(parentLoc)) {
28960 const parentIndex = getParentInjectorIndex(parentLoc);
28961 const parentLView = getParentInjectorView(parentLoc, lView);
28962 const parentData = parentLView[TVIEW].data;
28963 // Creates a cumulative bloom filter that merges the parent's bloom filter
28964 // and its own cumulative bloom (which contains tokens for all ancestors)
28965 for (let i = 0; i < 8 /* BLOOM_SIZE */; i++) {
28966 lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
28967 }
28968 }
28969 lView[injectorIndex + 8 /* PARENT */] = parentLoc;
28970 return injectorIndex;
28971 }
28972 function insertBloom(arr, footer) {
28973 arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
28974 }
28975 function getInjectorIndex(tNode, lView) {
28976 if (tNode.injectorIndex === -1 ||
28977 // If the injector index is the same as its parent's injector index, then the index has been
28978 // copied down from the parent node. No injector has been created yet on this node.
28979 (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
28980 // After the first template pass, the injector index might exist but the parent values
28981 // might not have been calculated yet for this instance
28982 lView[tNode.injectorIndex + 8 /* PARENT */] === null) {
28983 return -1;
28984 }
28985 else {
28986 ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
28987 return tNode.injectorIndex;
28988 }
28989 }
28990 /**
28991 * Finds the index of the parent injector, with a view offset if applicable. Used to set the
28992 * parent injector initially.
28993 *
28994 * @returns Returns a number that is the combination of the number of LViews that we have to go up
28995 * to find the LView containing the parent inject AND the index of the injector within that LView.
28996 */
28997 function getParentInjectorLocation(tNode, lView) {
28998 if (tNode.parent && tNode.parent.injectorIndex !== -1) {
28999 // If we have a parent `TNode` and there is an injector associated with it we are done, because
29000 // the parent injector is within the current `LView`.
29001 return tNode.parent.injectorIndex; // ViewOffset is 0
29002 }
29003 // When parent injector location is computed it may be outside of the current view. (ie it could
29004 // be pointing to a declared parent location). This variable stores number of declaration parents
29005 // we need to walk up in order to find the parent injector location.
29006 let declarationViewOffset = 0;
29007 let parentTNode = null;
29008 let lViewCursor = lView;
29009 // The parent injector is not in the current `LView`. We will have to walk the declared parent
29010 // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
29011 // `NodeInjector`.
29012 while (lViewCursor !== null) {
29013 // First determine the `parentTNode` location. The parent pointer differs based on `TView.type`.
29014 const tView = lViewCursor[TVIEW];
29015 const tViewType = tView.type;
29016 if (tViewType === 2 /* Embedded */) {
29017 ngDevMode &&
29018 assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
29019 parentTNode = tView.declTNode;
29020 }
29021 else if (tViewType === 1 /* Component */) {
29022 // Components don't have `TView.declTNode` because each instance of component could be
29023 // inserted in different location, hence `TView.declTNode` is meaningless.
29024 parentTNode = lViewCursor[T_HOST];
29025 }
29026 else {
29027 ngDevMode && assertEqual(tView.type, 0 /* Root */, 'Root type expected');
29028 parentTNode = null;
29029 }
29030 if (parentTNode === null) {
29031 // If we have no parent, than we are done.
29032 return NO_PARENT_INJECTOR;
29033 }
29034 ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]);
29035 // Every iteration of the loop requires that we go to the declared parent.
29036 declarationViewOffset++;
29037 lViewCursor = lViewCursor[DECLARATION_VIEW];
29038 if (parentTNode.injectorIndex !== -1) {
29039 // We found a NodeInjector which points to something.
29040 return (parentTNode.injectorIndex |
29041 (declarationViewOffset << 16 /* ViewOffsetShift */));
29042 }
29043 }
29044 return NO_PARENT_INJECTOR;
29045 }
29046 /**
29047 * Makes a type or an injection token public to the DI system by adding it to an
29048 * injector's bloom filter.
29049 *
29050 * @param di The node injector in which a directive will be added
29051 * @param token The type or the injection token to be made public
29052 */
29053 function diPublicInInjector(injectorIndex, tView, token) {
29054 bloomAdd(injectorIndex, tView, token);
29055 }
29056 function notFoundValueOrThrow(notFoundValue, token, flags) {
29057 if (flags & InjectFlags.Optional) {
29058 return notFoundValue;
29059 }
29060 else {
29061 throwProviderNotFoundError(token, 'NodeInjector');
29062 }
29063 }
29064 /**
29065 * Returns the value associated to the given token from the ModuleInjector or throws exception
29066 *
29067 * @param lView The `LView` that contains the `tNode`
29068 * @param token The token to look for
29069 * @param flags Injection flags
29070 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
29071 * @returns the value from the injector or throws an exception
29072 */
29073 function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) {
29074 if (flags & InjectFlags.Optional && notFoundValue === undefined) {
29075 // This must be set or the NullInjector will throw for optional deps
29076 notFoundValue = null;
29077 }
29078 if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
29079 const moduleInjector = lView[INJECTOR];
29080 // switch to `injectInjectorOnly` implementation for module injector, since module injector
29081 // should not have access to Component/Directive DI scope (that may happen through
29082 // `directiveInject` implementation)
29083 const previousInjectImplementation = setInjectImplementation(undefined);
29084 try {
29085 if (moduleInjector) {
29086 return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
29087 }
29088 else {
29089 return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
29090 }
29091 }
29092 finally {
29093 setInjectImplementation(previousInjectImplementation);
29094 }
29095 }
29096 return notFoundValueOrThrow(notFoundValue, token, flags);
29097 }
29098 /**
29099 * Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
29100 *
29101 * Look for the injector providing the token by walking up the node injector tree and then
29102 * the module injector tree.
29103 *
29104 * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom
29105 * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`)
29106 *
29107 * @param tNode The Node where the search for the injector should start
29108 * @param lView The `LView` that contains the `tNode`
29109 * @param token The token to look for
29110 * @param flags Injection flags
29111 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
29112 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
29113 */
29114 function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) {
29115 if (tNode !== null) {
29116 const bloomHash = bloomHashBitOrFactory(token);
29117 // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
29118 // so just call the factory function to create it.
29119 if (typeof bloomHash === 'function') {
29120 if (!enterDI(lView, tNode, flags)) {
29121 // Failed to enter DI, try module injector instead. If a token is injected with the @Host
29122 // flag, the module injector is not searched for that token in Ivy.
29123 return (flags & InjectFlags.Host) ?
29124 notFoundValueOrThrow(notFoundValue, token, flags) :
29125 lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
29126 }
29127 try {
29128 const value = bloomHash();
29129 if (value == null && !(flags & InjectFlags.Optional)) {
29130 throwProviderNotFoundError(token);
29131 }
29132 else {
29133 return value;
29134 }
29135 }
29136 finally {
29137 leaveDI();
29138 }
29139 }
29140 else if (typeof bloomHash === 'number') {
29141 // A reference to the previous injector TView that was found while climbing the element
29142 // injector tree. This is used to know if viewProviders can be accessed on the current
29143 // injector.
29144 let previousTView = null;
29145 let injectorIndex = getInjectorIndex(tNode, lView);
29146 let parentLocation = NO_PARENT_INJECTOR;
29147 let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
29148 // If we should skip this injector, or if there is no injector on this node, start by
29149 // searching the parent injector.
29150 if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
29151 parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
29152 lView[injectorIndex + 8 /* PARENT */];
29153 if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
29154 injectorIndex = -1;
29155 }
29156 else {
29157 previousTView = lView[TVIEW];
29158 injectorIndex = getParentInjectorIndex(parentLocation);
29159 lView = getParentInjectorView(parentLocation, lView);
29160 }
29161 }
29162 // Traverse up the injector tree until we find a potential match or until we know there
29163 // *isn't* a match.
29164 while (injectorIndex !== -1) {
29165 ngDevMode && assertNodeInjector(lView, injectorIndex);
29166 // Check the current injector. If it matches, see if it contains token.
29167 const tView = lView[TVIEW];
29168 ngDevMode &&
29169 assertTNodeForLView(tView.data[injectorIndex + 8 /* TNODE */], lView);
29170 if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
29171 // At this point, we have an injector which *may* contain the token, so we step through
29172 // the providers and directives associated with the injector's corresponding node to get
29173 // the instance.
29174 const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode);
29175 if (instance !== NOT_FOUND) {
29176 return instance;
29177 }
29178 }
29179 parentLocation = lView[injectorIndex + 8 /* PARENT */];
29180 if (parentLocation !== NO_PARENT_INJECTOR &&
29181 shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* TNODE */] === hostTElementNode) &&
29182 bloomHasToken(bloomHash, injectorIndex, lView)) {
29183 // The def wasn't found anywhere on this node, so it was a false positive.
29184 // Traverse up the tree and continue searching.
29185 previousTView = tView;
29186 injectorIndex = getParentInjectorIndex(parentLocation);
29187 lView = getParentInjectorView(parentLocation, lView);
29188 }
29189 else {
29190 // If we should not search parent OR If the ancestor bloom filter value does not have the
29191 // bit corresponding to the directive we can give up on traversing up to find the specific
29192 // injector.
29193 injectorIndex = -1;
29194 }
29195 }
29196 }
29197 }
29198 return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
29199 }
29200 const NOT_FOUND = {};
29201 function createNodeInjector() {
29202 return new NodeInjector(getCurrentTNode(), getLView());
29203 }
29204 function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) {
29205 const currentTView = lView[TVIEW];
29206 const tNode = currentTView.data[injectorIndex + 8 /* TNODE */];
29207 // First, we need to determine if view providers can be accessed by the starting element.
29208 // There are two possibilities
29209 const canAccessViewProviders = previousTView == null ?
29210 // 1) This is the first invocation `previousTView == null` which means that we are at the
29211 // `TNode` of where injector is starting to look. In such a case the only time we are allowed
29212 // to look into the ViewProviders is if:
29213 // - we are on a component
29214 // - AND the injector set `includeViewProviders` to true (implying that the token can see
29215 // ViewProviders because it is the Component or a Service which itself was declared in
29216 // ViewProviders)
29217 (isComponentHost(tNode) && includeViewProviders) :
29218 // 2) `previousTView != null` which means that we are now walking across the parent nodes.
29219 // In such a case we are only allowed to look into the ViewProviders if:
29220 // - We just crossed from child View to Parent View `previousTView != currentTView`
29221 // - AND the parent TNode is an Element.
29222 // This means that we just came from the Component's View and therefore are allowed to see
29223 // into the ViewProviders.
29224 (previousTView != currentTView && ((tNode.type & 3 /* AnyRNode */) !== 0));
29225 // This special case happens when there is a @host on the inject and when we are searching
29226 // on the host element node.
29227 const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode;
29228 const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase);
29229 if (injectableIdx !== null) {
29230 return getNodeInjectable(lView, currentTView, injectableIdx, tNode);
29231 }
29232 else {
29233 return NOT_FOUND;
29234 }
29235 }
29236 /**
29237 * Searches for the given token among the node's directives and providers.
29238 *
29239 * @param tNode TNode on which directives are present.
29240 * @param tView The tView we are currently processing
29241 * @param token Provider token or type of a directive to look for.
29242 * @param canAccessViewProviders Whether view providers should be considered.
29243 * @param isHostSpecialCase Whether the host special case applies.
29244 * @returns Index of a found directive or provider, or null when none found.
29245 */
29246 function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) {
29247 const nodeProviderIndexes = tNode.providerIndexes;
29248 const tInjectables = tView.data;
29249 const injectablesStart = nodeProviderIndexes & 1048575 /* ProvidersStartIndexMask */;
29250 const directivesStart = tNode.directiveStart;
29251 const directiveEnd = tNode.directiveEnd;
29252 const cptViewProvidersCount = nodeProviderIndexes >> 20 /* CptViewProvidersCountShift */;
29253 const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount;
29254 // When the host special case applies, only the viewProviders and the component are visible
29255 const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd;
29256 for (let i = startingIndex; i < endIndex; i++) {
29257 const providerTokenOrDef = tInjectables[i];
29258 if (i < directivesStart && token === providerTokenOrDef ||
29259 i >= directivesStart && providerTokenOrDef.type === token) {
29260 return i;
29261 }
29262 }
29263 if (isHostSpecialCase) {
29264 const dirDef = tInjectables[directivesStart];
29265 if (dirDef && isComponentDef(dirDef) && dirDef.type === token) {
29266 return directivesStart;
29267 }
29268 }
29269 return null;
29270 }
29271 /**
29272 * Retrieve or instantiate the injectable from the `LView` at particular `index`.
29273 *
29274 * This function checks to see if the value has already been instantiated and if so returns the
29275 * cached `injectable`. Otherwise if it detects that the value is still a factory it
29276 * instantiates the `injectable` and caches the value.
29277 */
29278 function getNodeInjectable(lView, tView, index, tNode) {
29279 let value = lView[index];
29280 const tData = tView.data;
29281 if (isFactory(value)) {
29282 const factory = value;
29283 if (factory.resolving) {
29284 throwCyclicDependencyError(stringifyForError(tData[index]));
29285 }
29286 const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
29287 factory.resolving = true;
29288 const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
29289 const success = enterDI(lView, tNode, InjectFlags.Default);
29290 ngDevMode &&
29291 assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.');
29292 try {
29293 value = lView[index] = factory.factory(undefined, tData, lView, tNode);
29294 // This code path is hit for both directives and providers.
29295 // For perf reasons, we want to avoid searching for hooks on providers.
29296 // It does no harm to try (the hooks just won't exist), but the extra
29297 // checks are unnecessary and this is a hot path. So we check to see
29298 // if the index of the dependency is in the directive range for this
29299 // tNode. If it's not, we know it's a provider and skip hook registration.
29300 if (tView.firstCreatePass && index >= tNode.directiveStart) {
29301 ngDevMode && assertDirectiveDef(tData[index]);
29302 registerPreOrderHooks(index, tData[index], tView);
29303 }
29304 }
29305 finally {
29306 previousInjectImplementation !== null &&
29307 setInjectImplementation(previousInjectImplementation);
29308 setIncludeViewProviders(previousIncludeViewProviders);
29309 factory.resolving = false;
29310 leaveDI();
29311 }
29312 }
29313 return value;
29314 }
29315 /**
29316 * Returns the bit in an injector's bloom filter that should be used to determine whether or not
29317 * the directive might be provided by the injector.
29318 *
29319 * When a directive is public, it is added to the bloom filter and given a unique ID that can be
29320 * retrieved on the Type. When the directive isn't public or the token is not a directive `null`
29321 * is returned as the node injector can not possibly provide that token.
29322 *
29323 * @param token the injection token
29324 * @returns the matching bit to check in the bloom filter or `null` if the token is not known.
29325 * When the returned value is negative then it represents special values such as `Injector`.
29326 */
29327 function bloomHashBitOrFactory(token) {
29328 ngDevMode && assertDefined(token, 'token must be defined');
29329 if (typeof token === 'string') {
29330 return token.charCodeAt(0) || 0;
29331 }
29332 const tokenId =
29333 // First check with `hasOwnProperty` so we don't get an inherited ID.
29334 token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined;
29335 // Negative token IDs are used for special objects such as `Injector`
29336 if (typeof tokenId === 'number') {
29337 if (tokenId >= 0) {
29338 return tokenId & BLOOM_MASK;
29339 }
29340 else {
29341 ngDevMode &&
29342 assertEqual(tokenId, -1 /* Injector */, 'Expecting to get Special Injector Id');
29343 return createNodeInjector;
29344 }
29345 }
29346 else {
29347 return tokenId;
29348 }
29349 }
29350 function bloomHasToken(bloomHash, injectorIndex, injectorView) {
29351 // Create a mask that targets the specific bit associated with the directive we're looking for.
29352 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
29353 // to bit positions 0 - 31 in a 32 bit integer.
29354 const mask = 1 << bloomHash;
29355 // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of
29356 // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset
29357 // that should be used.
29358 const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)];
29359 // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
29360 // this injector is a potential match.
29361 return !!(value & mask);
29362 }
29363 /** Returns true if flags prevent parent injector from being searched for tokens */
29364 function shouldSearchParent(flags, isFirstHostTNode) {
29365 return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode);
29366 }
29367 class NodeInjector {
29368 constructor(_tNode, _lView) {
29369 this._tNode = _tNode;
29370 this._lView = _lView;
29371 }
29372 get(token, notFoundValue) {
29373 return getOrCreateInjectable(this._tNode, this._lView, token, undefined, notFoundValue);
29374 }
29375 }
29376
29377 /**
29378 * @license
29379 * Copyright Google LLC All Rights Reserved.
29380 *
29381 * Use of this source code is governed by an MIT-style license that can be
29382 * found in the LICENSE file at https://angular.io/license
29383 */
29384 const ANNOTATIONS = '__annotations__';
29385 const PARAMETERS = '__parameters__';
29386 const PROP_METADATA = '__prop__metadata__';
29387 /**
29388 * @suppress {globalThis}
29389 */
29390 function makeDecorator(name, props, parentClass, additionalProcessing, typeFn) {
29391 return noSideEffects(() => {
29392 const metaCtor = makeMetadataCtor(props);
29393 function DecoratorFactory(...args) {
29394 if (this instanceof DecoratorFactory) {
29395 metaCtor.call(this, ...args);
29396 return this;
29397 }
29398 const annotationInstance = new DecoratorFactory(...args);
29399 return function TypeDecorator(cls) {
29400 if (typeFn)
29401 typeFn(cls, ...args);
29402 // Use of Object.defineProperty is important since it creates non-enumerable property which
29403 // prevents the property is copied during subclassing.
29404 const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
29405 cls[ANNOTATIONS] :
29406 Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
29407 annotations.push(annotationInstance);
29408 if (additionalProcessing)
29409 additionalProcessing(cls);
29410 return cls;
29411 };
29412 }
29413 if (parentClass) {
29414 DecoratorFactory.prototype = Object.create(parentClass.prototype);
29415 }
29416 DecoratorFactory.prototype.ngMetadataName = name;
29417 DecoratorFactory.annotationCls = DecoratorFactory;
29418 return DecoratorFactory;
29419 });
29420 }
29421 function makeMetadataCtor(props) {
29422 return function ctor(...args) {
29423 if (props) {
29424 const values = props(...args);
29425 for (const propName in values) {
29426 this[propName] = values[propName];
29427 }
29428 }
29429 };
29430 }
29431 function makeParamDecorator(name, props, parentClass) {
29432 return noSideEffects(() => {
29433 const metaCtor = makeMetadataCtor(props);
29434 function ParamDecoratorFactory(...args) {
29435 if (this instanceof ParamDecoratorFactory) {
29436 metaCtor.apply(this, args);
29437 return this;
29438 }
29439 const annotationInstance = new ParamDecoratorFactory(...args);
29440 ParamDecorator.annotation = annotationInstance;
29441 return ParamDecorator;
29442 function ParamDecorator(cls, unusedKey, index) {
29443 // Use of Object.defineProperty is important since it creates non-enumerable property which
29444 // prevents the property is copied during subclassing.
29445 const parameters = cls.hasOwnProperty(PARAMETERS) ?
29446 cls[PARAMETERS] :
29447 Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS];
29448 // there might be gaps if some in between parameters do not have annotations.
29449 // we pad with nulls.
29450 while (parameters.length <= index) {
29451 parameters.push(null);
29452 }
29453 (parameters[index] = parameters[index] || []).push(annotationInstance);
29454 return cls;
29455 }
29456 }
29457 if (parentClass) {
29458 ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
29459 }
29460 ParamDecoratorFactory.prototype.ngMetadataName = name;
29461 ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
29462 return ParamDecoratorFactory;
29463 });
29464 }
29465 function makePropDecorator(name, props, parentClass, additionalProcessing) {
29466 return noSideEffects(() => {
29467 const metaCtor = makeMetadataCtor(props);
29468 function PropDecoratorFactory(...args) {
29469 if (this instanceof PropDecoratorFactory) {
29470 metaCtor.apply(this, args);
29471 return this;
29472 }
29473 const decoratorInstance = new PropDecoratorFactory(...args);
29474 function PropDecorator(target, name) {
29475 const constructor = target.constructor;
29476 // Use of Object.defineProperty is important because it creates a non-enumerable property
29477 // which prevents the property from being copied during subclassing.
29478 const meta = constructor.hasOwnProperty(PROP_METADATA) ?
29479 constructor[PROP_METADATA] :
29480 Object.defineProperty(constructor, PROP_METADATA, { value: {} })[PROP_METADATA];
29481 meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
29482 meta[name].unshift(decoratorInstance);
29483 if (additionalProcessing)
29484 additionalProcessing(target, name, ...args);
29485 }
29486 return PropDecorator;
29487 }
29488 if (parentClass) {
29489 PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
29490 }
29491 PropDecoratorFactory.prototype.ngMetadataName = name;
29492 PropDecoratorFactory.annotationCls = PropDecoratorFactory;
29493 return PropDecoratorFactory;
29494 });
29495 }
29496
29497 /**
29498 * @license
29499 * Copyright Google LLC All Rights Reserved.
29500 *
29501 * Use of this source code is governed by an MIT-style license that can be
29502 * found in the LICENSE file at https://angular.io/license
29503 */
29504 function CREATE_ATTRIBUTE_DECORATOR__PRE_R3__() {
29505 return makeParamDecorator('Attribute', (attributeName) => ({ attributeName }));
29506 }
29507 const CREATE_ATTRIBUTE_DECORATOR_IMPL = CREATE_ATTRIBUTE_DECORATOR__PRE_R3__;
29508 /**
29509 * Attribute decorator and metadata.
29510 *
29511 * @Annotation
29512 * @publicApi
29513 */
29514 const Attribute$1 = CREATE_ATTRIBUTE_DECORATOR_IMPL();
29515
29516 /**
29517 * @license
29518 * Copyright Google LLC All Rights Reserved.
29519 *
29520 * Use of this source code is governed by an MIT-style license that can be
29521 * found in the LICENSE file at https://angular.io/license
29522 */
29523 /**
29524 * Creates a token that can be used in a DI Provider.
29525 *
29526 * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
29527 * runtime representation) such as when injecting an interface, callable type, array or
29528 * parameterized type.
29529 *
29530 * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
29531 * the `Injector`. This provides additional level of type safety.
29532 *
29533 * ```
29534 * interface MyInterface {...}
29535 * var myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
29536 * // myInterface is inferred to be MyInterface.
29537 * ```
29538 *
29539 * When creating an `InjectionToken`, you can optionally specify a factory function which returns
29540 * (possibly by creating) a default value of the parameterized type `T`. This sets up the
29541 * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
29542 * application's root injector. If the factory function, which takes zero arguments, needs to inject
29543 * dependencies, it can do so using the `inject` function. See below for an example.
29544 *
29545 * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
29546 * overrides the above behavior and marks the token as belonging to a particular `@NgModule`. As
29547 * mentioned above, `'root'` is the default value for `providedIn`.
29548 *
29549 * @usageNotes
29550 * ### Basic Example
29551 *
29552 * ### Plain InjectionToken
29553 *
29554 * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
29555 *
29556 * ### Tree-shakable InjectionToken
29557 *
29558 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
29559 *
29560 *
29561 * @publicApi
29562 */
29563 class InjectionToken {
29564 constructor(_desc, options) {
29565 this._desc = _desc;
29566 /** @internal */
29567 this.ngMetadataName = 'InjectionToken';
29568 this.ɵprov = undefined;
29569 if (typeof options == 'number') {
29570 (typeof ngDevMode === 'undefined' || ngDevMode) &&
29571 assertLessThan(options, 0, 'Only negative numbers are supported here');
29572 // This is a special hack to assign __NG_ELEMENT_ID__ to this instance.
29573 // See `InjectorMarkers`
29574 this.__NG_ELEMENT_ID__ = options;
29575 }
29576 else if (options !== undefined) {
29577 this.ɵprov = ɵɵdefineInjectable({
29578 token: this,
29579 providedIn: options.providedIn || 'root',
29580 factory: options.factory,
29581 });
29582 }
29583 }
29584 toString() {
29585 return `InjectionToken ${this._desc}`;
29586 }
29587 }
29588
29589 /**
29590 * @license
29591 * Copyright Google LLC All Rights Reserved.
29592 *
29593 * Use of this source code is governed by an MIT-style license that can be
29594 * found in the LICENSE file at https://angular.io/license
29595 */
29596 /**
29597 * A DI token that you can use to create a virtual [provider](guide/glossary#provider)
29598 * that will populate the `entryComponents` field of components and NgModules
29599 * based on its `useValue` property value.
29600 * All components that are referenced in the `useValue` value (either directly
29601 * or in a nested array or map) are added to the `entryComponents` property.
29602 *
29603 * @usageNotes
29604 *
29605 * The following example shows how the router can populate the `entryComponents`
29606 * field of an NgModule based on a router configuration that refers
29607 * to components.
29608 *
29609 * ```typescript
29610 * // helper function inside the router
29611 * function provideRoutes(routes) {
29612 * return [
29613 * {provide: ROUTES, useValue: routes},
29614 * {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: routes, multi: true}
29615 * ];
29616 * }
29617 *
29618 * // user code
29619 * let routes = [
29620 * {path: '/root', component: RootComp},
29621 * {path: '/teams', component: TeamsComp}
29622 * ];
29623 *
29624 * @NgModule({
29625 * providers: [provideRoutes(routes)]
29626 * })
29627 * class ModuleWithRoutes {}
29628 * ```
29629 *
29630 * @publicApi
29631 * @deprecated Since 9.0.0. With Ivy, this property is no longer necessary.
29632 */
29633 const ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForEntryComponents');
29634 // Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
29635 // explicitly set. This value will be changed to `true` in v12.
29636 // TODO(misko): switch the default in v12 to `true`. See: packages/compiler/src/core.ts
29637 const emitDistinctChangesOnlyDefaultValue$1 = false;
29638 /**
29639 * Base class for query metadata.
29640 *
29641 * @see `ContentChildren`.
29642 * @see `ContentChild`.
29643 * @see `ViewChildren`.
29644 * @see `ViewChild`.
29645 *
29646 * @publicApi
29647 */
29648 class Query {
29649 }
29650 const ɵ0$1 = (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue$1 }, data));
29651 /**
29652 * ContentChildren decorator and metadata.
29653 *
29654 *
29655 * @Annotation
29656 * @publicApi
29657 */
29658 const ContentChildren = makePropDecorator('ContentChildren', ɵ0$1, Query);
29659 const ɵ1 = (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data));
29660 /**
29661 * ContentChild decorator and metadata.
29662 *
29663 *
29664 * @Annotation
29665 *
29666 * @publicApi
29667 */
29668 const ContentChild = makePropDecorator('ContentChild', ɵ1, Query);
29669 const ɵ2 = (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue$1 }, data));
29670 /**
29671 * ViewChildren decorator and metadata.
29672 *
29673 * @Annotation
29674 * @publicApi
29675 */
29676 const ViewChildren = makePropDecorator('ViewChildren', ɵ2, Query);
29677 const ɵ3 = (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data));
29678 /**
29679 * ViewChild decorator and metadata.
29680 *
29681 * @Annotation
29682 * @publicApi
29683 */
29684 const ViewChild = makePropDecorator('ViewChild', ɵ3, Query);
29685
29686 /**
29687 * @license
29688 * Copyright Google LLC All Rights Reserved.
29689 *
29690 * Use of this source code is governed by an MIT-style license that can be
29691 * found in the LICENSE file at https://angular.io/license
29692 */
29693 var R3ResolvedDependencyType$1;
29694 (function (R3ResolvedDependencyType) {
29695 R3ResolvedDependencyType[R3ResolvedDependencyType["Token"] = 0] = "Token";
29696 R3ResolvedDependencyType[R3ResolvedDependencyType["Attribute"] = 1] = "Attribute";
29697 R3ResolvedDependencyType[R3ResolvedDependencyType["ChangeDetectorRef"] = 2] = "ChangeDetectorRef";
29698 R3ResolvedDependencyType[R3ResolvedDependencyType["Invalid"] = 3] = "Invalid";
29699 })(R3ResolvedDependencyType$1 || (R3ResolvedDependencyType$1 = {}));
29700 var R3FactoryTarget$1;
29701 (function (R3FactoryTarget) {
29702 R3FactoryTarget[R3FactoryTarget["Directive"] = 0] = "Directive";
29703 R3FactoryTarget[R3FactoryTarget["Component"] = 1] = "Component";
29704 R3FactoryTarget[R3FactoryTarget["Injectable"] = 2] = "Injectable";
29705 R3FactoryTarget[R3FactoryTarget["Pipe"] = 3] = "Pipe";
29706 R3FactoryTarget[R3FactoryTarget["NgModule"] = 4] = "NgModule";
29707 })(R3FactoryTarget$1 || (R3FactoryTarget$1 = {}));
29708 var ViewEncapsulation$2;
29709 (function (ViewEncapsulation) {
29710 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
29711 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
29712 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
29713 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
29714 })(ViewEncapsulation$2 || (ViewEncapsulation$2 = {}));
29715
29716 /**
29717 * @license
29718 * Copyright Google LLC All Rights Reserved.
29719 *
29720 * Use of this source code is governed by an MIT-style license that can be
29721 * found in the LICENSE file at https://angular.io/license
29722 */
29723 /**
29724 * @description
29725 *
29726 * Represents a type that a Component or other object is instances of.
29727 *
29728 * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is represented by
29729 * the `MyCustomComponent` constructor function.
29730 *
29731 * @publicApi
29732 */
29733 const Type$2 = Function;
29734 function isType(v) {
29735 return typeof v === 'function';
29736 }
29737
29738 /**
29739 * @license
29740 * Copyright Google LLC All Rights Reserved.
29741 *
29742 * Use of this source code is governed by an MIT-style license that can be
29743 * found in the LICENSE file at https://angular.io/license
29744 */
29745 function removeFromArray(arr, index) {
29746 // perf: array.pop is faster than array.splice!
29747 if (index >= arr.length - 1) {
29748 return arr.pop();
29749 }
29750 else {
29751 return arr.splice(index, 1)[0];
29752 }
29753 }
29754 function newArray$1(size, value) {
29755 const list = [];
29756 for (let i = 0; i < size; i++) {
29757 list.push(value);
29758 }
29759 return list;
29760 }
29761
29762 /**
29763 * @license
29764 * Copyright Google LLC All Rights Reserved.
29765 *
29766 * Use of this source code is governed by an MIT-style license that can be
29767 * found in the LICENSE file at https://angular.io/license
29768 */
29769 /*
29770 * #########################
29771 * Attention: These Regular expressions have to hold even if the code is minified!
29772 * ##########################
29773 */
29774 /**
29775 * Regular expression that detects pass-through constructors for ES5 output. This Regex
29776 * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
29777 * it intends to capture the pattern where existing constructors have been downleveled from
29778 * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
29779 *
29780 * ```
29781 * function MyClass() {
29782 * var _this = _super.apply(this, arguments) || this;
29783 * ```
29784 *
29785 * ```
29786 * function MyClass() {
29787 * var _this = _super.apply(this, __spread(arguments)) || this;
29788 * ```
29789 *
29790 * More details can be found in: https://github.com/angular/angular/issues/38453.
29791 */
29792 const ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|[^()]+\(arguments\))\)/;
29793 /** Regular expression that detects ES2015 classes which extend from other classes. */
29794 const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
29795 /**
29796 * Regular expression that detects ES2015 classes which extend from other classes and
29797 * have an explicit constructor defined.
29798 */
29799 const ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
29800 /**
29801 * Regular expression that detects ES2015 classes which extend from other classes
29802 * and inherit a constructor.
29803 */
29804 const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/;
29805 /**
29806 * Determine whether a stringified type is a class which delegates its constructor
29807 * to its parent.
29808 *
29809 * This is not trivial since compiled code can actually contain a constructor function
29810 * even if the original source code did not. For instance, when the child class contains
29811 * an initialized instance property.
29812 */
29813 function isDelegateCtor(typeStr) {
29814 return ES5_DELEGATE_CTOR.test(typeStr) ||
29815 ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
29816 (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
29817 }
29818 class ReflectionCapabilities {
29819 constructor(reflect) {
29820 this._reflect = reflect || _global$1['Reflect'];
29821 }
29822 isReflectionEnabled() {
29823 return true;
29824 }
29825 factory(t) {
29826 return (...args) => new t(...args);
29827 }
29828 /** @internal */
29829 _zipTypesAndAnnotations(paramTypes, paramAnnotations) {
29830 let result;
29831 if (typeof paramTypes === 'undefined') {
29832 result = newArray$1(paramAnnotations.length);
29833 }
29834 else {
29835 result = newArray$1(paramTypes.length);
29836 }
29837 for (let i = 0; i < result.length; i++) {
29838 // TS outputs Object for parameters without types, while Traceur omits
29839 // the annotations. For now we preserve the Traceur behavior to aid
29840 // migration, but this can be revisited.
29841 if (typeof paramTypes === 'undefined') {
29842 result[i] = [];
29843 }
29844 else if (paramTypes[i] && paramTypes[i] != Object) {
29845 result[i] = [paramTypes[i]];
29846 }
29847 else {
29848 result[i] = [];
29849 }
29850 if (paramAnnotations && paramAnnotations[i] != null) {
29851 result[i] = result[i].concat(paramAnnotations[i]);
29852 }
29853 }
29854 return result;
29855 }
29856 _ownParameters(type, parentCtor) {
29857 const typeStr = type.toString();
29858 // If we have no decorators, we only have function.length as metadata.
29859 // In that case, to detect whether a child class declared an own constructor or not,
29860 // we need to look inside of that constructor to check whether it is
29861 // just calling the parent.
29862 // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
29863 // that sets 'design:paramtypes' to []
29864 // if a class inherits from another class but has no ctor declared itself.
29865 if (isDelegateCtor(typeStr)) {
29866 return null;
29867 }
29868 // Prefer the direct API.
29869 if (type.parameters && type.parameters !== parentCtor.parameters) {
29870 return type.parameters;
29871 }
29872 // API of tsickle for lowering decorators to properties on the class.
29873 const tsickleCtorParams = type.ctorParameters;
29874 if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
29875 // Newer tsickle uses a function closure
29876 // Retain the non-function case for compatibility with older tsickle
29877 const ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
29878 const paramTypes = ctorParameters.map((ctorParam) => ctorParam && ctorParam.type);
29879 const paramAnnotations = ctorParameters.map((ctorParam) => ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
29880 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
29881 }
29882 // API for metadata created by invoking the decorators.
29883 const paramAnnotations = type.hasOwnProperty(PARAMETERS) && type[PARAMETERS];
29884 const paramTypes = this._reflect && this._reflect.getOwnMetadata &&
29885 this._reflect.getOwnMetadata('design:paramtypes', type);
29886 if (paramTypes || paramAnnotations) {
29887 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
29888 }
29889 // If a class has no decorators, at least create metadata
29890 // based on function.length.
29891 // Note: We know that this is a real constructor as we checked
29892 // the content of the constructor above.
29893 return newArray$1(type.length);
29894 }
29895 parameters(type) {
29896 // Note: only report metadata if we have at least one class decorator
29897 // to stay in sync with the static reflector.
29898 if (!isType(type)) {
29899 return [];
29900 }
29901 const parentCtor = getParentCtor(type);
29902 let parameters = this._ownParameters(type, parentCtor);
29903 if (!parameters && parentCtor !== Object) {
29904 parameters = this.parameters(parentCtor);
29905 }
29906 return parameters || [];
29907 }
29908 _ownAnnotations(typeOrFunc, parentCtor) {
29909 // Prefer the direct API.
29910 if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
29911 let annotations = typeOrFunc.annotations;
29912 if (typeof annotations === 'function' && annotations.annotations) {
29913 annotations = annotations.annotations;
29914 }
29915 return annotations;
29916 }
29917 // API of tsickle for lowering decorators to properties on the class.
29918 if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) {
29919 return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators);
29920 }
29921 // API for metadata created by invoking the decorators.
29922 if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
29923 return typeOrFunc[ANNOTATIONS];
29924 }
29925 return null;
29926 }
29927 annotations(typeOrFunc) {
29928 if (!isType(typeOrFunc)) {
29929 return [];
29930 }
29931 const parentCtor = getParentCtor(typeOrFunc);
29932 const ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
29933 const parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
29934 return parentAnnotations.concat(ownAnnotations);
29935 }
29936 _ownPropMetadata(typeOrFunc, parentCtor) {
29937 // Prefer the direct API.
29938 if (typeOrFunc.propMetadata &&
29939 typeOrFunc.propMetadata !== parentCtor.propMetadata) {
29940 let propMetadata = typeOrFunc.propMetadata;
29941 if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
29942 propMetadata = propMetadata.propMetadata;
29943 }
29944 return propMetadata;
29945 }
29946 // API of tsickle for lowering decorators to properties on the class.
29947 if (typeOrFunc.propDecorators &&
29948 typeOrFunc.propDecorators !== parentCtor.propDecorators) {
29949 const propDecorators = typeOrFunc.propDecorators;
29950 const propMetadata = {};
29951 Object.keys(propDecorators).forEach(prop => {
29952 propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
29953 });
29954 return propMetadata;
29955 }
29956 // API for metadata created by invoking the decorators.
29957 if (typeOrFunc.hasOwnProperty(PROP_METADATA)) {
29958 return typeOrFunc[PROP_METADATA];
29959 }
29960 return null;
29961 }
29962 propMetadata(typeOrFunc) {
29963 if (!isType(typeOrFunc)) {
29964 return {};
29965 }
29966 const parentCtor = getParentCtor(typeOrFunc);
29967 const propMetadata = {};
29968 if (parentCtor !== Object) {
29969 const parentPropMetadata = this.propMetadata(parentCtor);
29970 Object.keys(parentPropMetadata).forEach((propName) => {
29971 propMetadata[propName] = parentPropMetadata[propName];
29972 });
29973 }
29974 const ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
29975 if (ownPropMetadata) {
29976 Object.keys(ownPropMetadata).forEach((propName) => {
29977 const decorators = [];
29978 if (propMetadata.hasOwnProperty(propName)) {
29979 decorators.push(...propMetadata[propName]);
29980 }
29981 decorators.push(...ownPropMetadata[propName]);
29982 propMetadata[propName] = decorators;
29983 });
29984 }
29985 return propMetadata;
29986 }
29987 ownPropMetadata(typeOrFunc) {
29988 if (!isType(typeOrFunc)) {
29989 return {};
29990 }
29991 return this._ownPropMetadata(typeOrFunc, getParentCtor(typeOrFunc)) || {};
29992 }
29993 hasLifecycleHook(type, lcProperty) {
29994 return type instanceof Type$2 && lcProperty in type.prototype;
29995 }
29996 guards(type) {
29997 return {};
29998 }
29999 getter(name) {
30000 return new Function('o', 'return o.' + name + ';');
30001 }
30002 setter(name) {
30003 return new Function('o', 'v', 'return o.' + name + ' = v;');
30004 }
30005 method(name) {
30006 const functionBody = `if (!o.${name}) throw new Error('"${name}" is undefined');
30007 return o.${name}.apply(o, args);`;
30008 return new Function('o', 'args', functionBody);
30009 }
30010 // There is not a concept of import uri in Js, but this is useful in developing Dart applications.
30011 importUri(type) {
30012 // StaticSymbol
30013 if (typeof type === 'object' && type['filePath']) {
30014 return type['filePath'];
30015 }
30016 // Runtime type
30017 return `./${stringify$1(type)}`;
30018 }
30019 resourceUri(type) {
30020 return `./${stringify$1(type)}`;
30021 }
30022 resolveIdentifier(name, moduleUrl, members, runtime) {
30023 return runtime;
30024 }
30025 resolveEnum(enumIdentifier, name) {
30026 return enumIdentifier[name];
30027 }
30028 }
30029 function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
30030 if (!decoratorInvocations) {
30031 return [];
30032 }
30033 return decoratorInvocations.map(decoratorInvocation => {
30034 const decoratorType = decoratorInvocation.type;
30035 const annotationCls = decoratorType.annotationCls;
30036 const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
30037 return new annotationCls(...annotationArgs);
30038 });
30039 }
30040 function getParentCtor(ctor) {
30041 const parentProto = ctor.prototype ? Object.getPrototypeOf(ctor.prototype) : null;
30042 const parentCtor = parentProto ? parentProto.constructor : null;
30043 // Note: We always use `Object` as the null value
30044 // to simplify checking later on.
30045 return parentCtor || Object;
30046 }
30047
30048 /**
30049 * @license
30050 * Copyright Google LLC All Rights Reserved.
30051 *
30052 * Use of this source code is governed by an MIT-style license that can be
30053 * found in the LICENSE file at https://angular.io/license
30054 */
30055 const _THROW_IF_NOT_FOUND = {};
30056 const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
30057 /*
30058 * Name of a property (that we patch onto DI decorator), which is used as an annotation of which
30059 * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators
30060 * in the code, thus making them tree-shakable.
30061 */
30062 const DI_DECORATOR_FLAG = '__NG_DI_FLAG__';
30063 const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath';
30064 const NG_TOKEN_PATH = 'ngTokenPath';
30065 const NEW_LINE = /\n/gm;
30066 const NO_NEW_LINE = 'ɵ';
30067 const SOURCE = '__source';
30068 const ɵ0$2 = getClosureSafeProperty;
30069 const USE_VALUE$2 = getClosureSafeProperty({ provide: String, useValue: ɵ0$2 });
30070 /**
30071 * Current injector value used by `inject`.
30072 * - `undefined`: it is an error to call `inject`
30073 * - `null`: `inject` can be called but there is no injector (limp-mode).
30074 * - Injector instance: Use the injector for resolution.
30075 */
30076 let _currentInjector = undefined;
30077 function setCurrentInjector(injector) {
30078 const former = _currentInjector;
30079 _currentInjector = injector;
30080 return former;
30081 }
30082 function injectInjectorOnly(token, flags = InjectFlags.Default) {
30083 if (_currentInjector === undefined) {
30084 throw new Error(`inject() must be called from an injection context`);
30085 }
30086 else if (_currentInjector === null) {
30087 return injectRootLimpMode(token, undefined, flags);
30088 }
30089 else {
30090 return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
30091 }
30092 }
30093 function ɵɵinject(token, flags = InjectFlags.Default) {
30094 return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef$1(token), flags);
30095 }
30096 function injectArgs(types) {
30097 const args = [];
30098 for (let i = 0; i < types.length; i++) {
30099 const arg = resolveForwardRef$1(types[i]);
30100 if (Array.isArray(arg)) {
30101 if (arg.length === 0) {
30102 throw new Error('Arguments array must have arguments.');
30103 }
30104 let type = undefined;
30105 let flags = InjectFlags.Default;
30106 for (let j = 0; j < arg.length; j++) {
30107 const meta = arg[j];
30108 const flag = getInjectFlag(meta);
30109 if (typeof flag === 'number') {
30110 // Special case when we handle @Inject decorator.
30111 if (flag === -1 /* Inject */) {
30112 type = meta.token;
30113 }
30114 else {
30115 flags |= flag;
30116 }
30117 }
30118 else {
30119 type = meta;
30120 }
30121 }
30122 args.push(ɵɵinject(type, flags));
30123 }
30124 else {
30125 args.push(ɵɵinject(arg));
30126 }
30127 }
30128 return args;
30129 }
30130 /**
30131 * Attaches a given InjectFlag to a given decorator using monkey-patching.
30132 * Since DI decorators can be used in providers `deps` array (when provider is configured using
30133 * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we
30134 * attach the flag to make it available both as a static property and as a field on decorator
30135 * instance.
30136 *
30137 * @param decorator Provided DI decorator.
30138 * @param flag InjectFlag that should be applied.
30139 */
30140 function attachInjectFlag(decorator, flag) {
30141 decorator[DI_DECORATOR_FLAG] = flag;
30142 decorator.prototype[DI_DECORATOR_FLAG] = flag;
30143 return decorator;
30144 }
30145 /**
30146 * Reads monkey-patched property that contains InjectFlag attached to a decorator.
30147 *
30148 * @param token Token that may contain monkey-patched DI flags property.
30149 */
30150 function getInjectFlag(token) {
30151 return token[DI_DECORATOR_FLAG];
30152 }
30153 function catchInjectorError(e, token, injectorErrorName, source) {
30154 const tokenPath = e[NG_TEMP_TOKEN_PATH];
30155 if (token[SOURCE]) {
30156 tokenPath.unshift(token[SOURCE]);
30157 }
30158 e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source);
30159 e[NG_TOKEN_PATH] = tokenPath;
30160 e[NG_TEMP_TOKEN_PATH] = null;
30161 throw e;
30162 }
30163 function formatError(text, obj, injectorErrorName, source = null) {
30164 text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text;
30165 let context = stringify$1(obj);
30166 if (Array.isArray(obj)) {
30167 context = obj.map(stringify$1).join(' -> ');
30168 }
30169 else if (typeof obj === 'object') {
30170 let parts = [];
30171 for (let key in obj) {
30172 if (obj.hasOwnProperty(key)) {
30173 let value = obj[key];
30174 parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify$1(value)));
30175 }
30176 }
30177 context = `{${parts.join(', ')}}`;
30178 }
30179 return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
30180 }
30181
30182 /**
30183 * @license
30184 * Copyright Google LLC All Rights Reserved.
30185 *
30186 * Use of this source code is governed by an MIT-style license that can be
30187 * found in the LICENSE file at https://angular.io/license
30188 */
30189 const ɵ0$3 = (token) => ({ token });
30190 /**
30191 * Inject decorator and metadata.
30192 *
30193 * @Annotation
30194 * @publicApi
30195 */
30196 const Inject = attachInjectFlag(
30197 // Disable tslint because `DecoratorFlags` is a const enum which gets inlined.
30198 // tslint:disable-next-line: no-toplevel-property-access
30199 makeParamDecorator('Inject', ɵ0$3), -1 /* Inject */);
30200 /**
30201 * Optional decorator and metadata.
30202 *
30203 * @Annotation
30204 * @publicApi
30205 */
30206 const Optional =
30207 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30208 // tslint:disable-next-line: no-toplevel-property-access
30209 attachInjectFlag(makeParamDecorator('Optional'), 8 /* Optional */);
30210 /**
30211 * Self decorator and metadata.
30212 *
30213 * @Annotation
30214 * @publicApi
30215 */
30216 const Self =
30217 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30218 // tslint:disable-next-line: no-toplevel-property-access
30219 attachInjectFlag(makeParamDecorator('Self'), 2 /* Self */);
30220 /**
30221 * `SkipSelf` decorator and metadata.
30222 *
30223 * @Annotation
30224 * @publicApi
30225 */
30226 const SkipSelf =
30227 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30228 // tslint:disable-next-line: no-toplevel-property-access
30229 attachInjectFlag(makeParamDecorator('SkipSelf'), 4 /* SkipSelf */);
30230 /**
30231 * Host decorator and metadata.
30232 *
30233 * @Annotation
30234 * @publicApi
30235 */
30236 const Host =
30237 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30238 // tslint:disable-next-line: no-toplevel-property-access
30239 attachInjectFlag(makeParamDecorator('Host'), 1 /* Host */);
30240
30241 /**
30242 * @license
30243 * Copyright Google LLC All Rights Reserved.
30244 *
30245 * Use of this source code is governed by an MIT-style license that can be
30246 * found in the LICENSE file at https://angular.io/license
30247 */
30248 /**
30249 * The Trusted Types policy, or null if Trusted Types are not
30250 * enabled/supported, or undefined if the policy has not been created yet.
30251 */
30252 let policy$1;
30253 /**
30254 * Returns the Trusted Types policy, or null if Trusted Types are not
30255 * enabled/supported. The first call to this function will create the policy.
30256 */
30257 function getPolicy$1() {
30258 if (policy$1 === undefined) {
30259 policy$1 = null;
30260 if (_global$1.trustedTypes) {
30261 try {
30262 policy$1 = _global$1.trustedTypes.createPolicy('angular', {
30263 createHTML: (s) => s,
30264 createScript: (s) => s,
30265 createScriptURL: (s) => s,
30266 });
30267 }
30268 catch (_a) {
30269 // trustedTypes.createPolicy throws if called with a name that is
30270 // already registered, even in report-only mode. Until the API changes,
30271 // catch the error not to break the applications functionally. In such
30272 // cases, the code will fall back to using strings.
30273 }
30274 }
30275 }
30276 return policy$1;
30277 }
30278 /**
30279 * Unsafely promote a string to a TrustedScript, falling back to strings when
30280 * Trusted Types are not available.
30281 * @security In particular, it must be assured that the provided string will
30282 * never cause an XSS vulnerability if used in a context that will be
30283 * interpreted and executed as a script by a browser, e.g. when calling eval.
30284 */
30285 function trustedScriptFromString$1(script) {
30286 var _a;
30287 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
30288 }
30289 /**
30290 * Unsafely call the Function constructor with the given string arguments. It
30291 * is only available in development mode, and should be stripped out of
30292 * production code.
30293 * @security This is a security-sensitive function; any use of this function
30294 * must go through security review. In particular, it must be assured that it
30295 * is only called from development code, as use in production code can lead to
30296 * XSS vulnerabilities.
30297 */
30298 function newTrustedFunctionForDev(...args) {
30299 if (typeof ngDevMode === 'undefined') {
30300 throw new Error('newTrustedFunctionForDev should never be called in production');
30301 }
30302 if (!_global$1.trustedTypes) {
30303 // In environments that don't support Trusted Types, fall back to the most
30304 // straightforward implementation:
30305 return new Function(...args);
30306 }
30307 // Chrome currently does not support passing TrustedScript to the Function
30308 // constructor. The following implements the workaround proposed on the page
30309 // below, where the Chromium bug is also referenced:
30310 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
30311 const fnArgs = args.slice(0, -1).join(',');
30312 const fnBody = args.pop().toString();
30313 const body = `(function anonymous(${fnArgs}
30314) { ${fnBody}
30315})`;
30316 // Using eval directly confuses the compiler and prevents this module from
30317 // being stripped out of JS binaries even if not used. The global['eval']
30318 // indirection fixes that.
30319 const fn = _global$1['eval'](trustedScriptFromString$1(body));
30320 // To completely mimic the behavior of calling "new Function", two more
30321 // things need to happen:
30322 // 1. Stringifying the resulting function should return its source code
30323 fn.toString = () => body;
30324 // 2. When calling the resulting function, `this` should refer to `global`
30325 return fn.bind(_global$1);
30326 // When Trusted Types support in Function constructors is widely available,
30327 // the implementation of this function can be simplified to:
30328 // return new Function(...args.map(a => trustedScriptFromString(a)));
30329 }
30330
30331 /**
30332 * @license
30333 * Copyright Google LLC All Rights Reserved.
30334 *
30335 * Use of this source code is governed by an MIT-style license that can be
30336 * found in the LICENSE file at https://angular.io/license
30337 */
30338 function tagSet(tags) {
30339 const res = {};
30340 for (const t of tags.split(','))
30341 res[t] = true;
30342 return res;
30343 }
30344 function merge(...sets) {
30345 const res = {};
30346 for (const s of sets) {
30347 for (const v in s) {
30348 if (s.hasOwnProperty(v))
30349 res[v] = true;
30350 }
30351 }
30352 return res;
30353 }
30354 // Good source of info about elements and attributes
30355 // https://html.spec.whatwg.org/#semantics
30356 // https://simon.html5.org/html-elements
30357 // Safe Void Elements - HTML5
30358 // https://html.spec.whatwg.org/#void-elements
30359 const VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr');
30360 // Elements that you can, intentionally, leave open (and which close themselves)
30361 // https://html.spec.whatwg.org/#optional-tags
30362 const OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr');
30363 const OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt');
30364 const OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS);
30365 // Safe Block Elements - HTML5
30366 const BLOCK_ELEMENTS = merge(OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet('address,article,' +
30367 'aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
30368 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul'));
30369 // Inline Elements - HTML5
30370 const INLINE_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet('a,abbr,acronym,audio,b,' +
30371 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' +
30372 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video'));
30373 const VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS);
30374 // Attributes that have href and hence need to be sanitized
30375 const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
30376 // Attributes that have special href set hence need to be sanitized
30377 const SRCSET_ATTRS = tagSet('srcset');
30378 const HTML_ATTRS = tagSet('abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' +
30379 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' +
30380 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' +
30381 'scope,scrolling,shape,size,sizes,span,srclang,start,summary,tabindex,target,title,translate,type,usemap,' +
30382 'valign,value,vspace,width');
30383 // Accessibility attributes as per WAI-ARIA 1.1 (W3C Working Draft 14 December 2018)
30384 const ARIA_ATTRS = tagSet('aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,' +
30385 'aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,' +
30386 'aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,' +
30387 'aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,' +
30388 'aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,' +
30389 'aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,' +
30390 'aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext');
30391 // NB: This currently consciously doesn't support SVG. SVG sanitization has had several security
30392 // issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via
30393 // innerHTML is required, SVG attributes should be added here.
30394 // NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those
30395 // can be sanitized, but they increase security surface area without a legitimate use case, so they
30396 // are left out here.
30397 const VALID_ATTRS = merge(URI_ATTRS, SRCSET_ATTRS, HTML_ATTRS, ARIA_ATTRS);
30398 // Elements whose content should not be traversed/preserved, if the elements themselves are invalid.
30399 //
30400 // Typically, `<invalid>Some content</invalid>` would traverse (and in this case preserve)
30401 // `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we
30402 // don't want to preserve the content, if the elements themselves are going to be removed.
30403 const SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template');
30404
30405 /**
30406 * @license
30407 * Copyright Google LLC All Rights Reserved.
30408 *
30409 * Use of this source code is governed by an MIT-style license that can be
30410 * found in the LICENSE file at https://angular.io/license
30411 */
30412 /**
30413 * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
30414 * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
30415 * handled.
30416 *
30417 * See DomSanitizer for more details on security in Angular applications.
30418 *
30419 * @publicApi
30420 */
30421 var SecurityContext$1;
30422 (function (SecurityContext) {
30423 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
30424 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
30425 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
30426 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
30427 SecurityContext[SecurityContext["URL"] = 4] = "URL";
30428 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
30429 })(SecurityContext$1 || (SecurityContext$1 = {}));
30430
30431 /**
30432 * @license
30433 * Copyright Google LLC All Rights Reserved.
30434 *
30435 * Use of this source code is governed by an MIT-style license that can be
30436 * found in the LICENSE file at https://angular.io/license
30437 */
30438 const ERROR_DEBUG_CONTEXT = 'ngDebugContext';
30439 const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
30440 const ERROR_LOGGER = 'ngErrorLogger';
30441 function wrappedError(message, originalError) {
30442 const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
30443 const error = Error(msg);
30444 error[ERROR_ORIGINAL_ERROR] = originalError;
30445 return error;
30446 }
30447
30448 /**
30449 * @license
30450 * Copyright Google LLC All Rights Reserved.
30451 *
30452 * Use of this source code is governed by an MIT-style license that can be
30453 * found in the LICENSE file at https://angular.io/license
30454 */
30455 function getDebugContext(error) {
30456 return error[ERROR_DEBUG_CONTEXT];
30457 }
30458 function getOriginalError(error) {
30459 return error[ERROR_ORIGINAL_ERROR];
30460 }
30461 function getErrorLogger(error) {
30462 return error[ERROR_LOGGER] || defaultErrorLogger;
30463 }
30464 function defaultErrorLogger(console, ...values) {
30465 console.error(...values);
30466 }
30467
30468 /**
30469 * @license
30470 * Copyright Google LLC All Rights Reserved.
30471 *
30472 * Use of this source code is governed by an MIT-style license that can be
30473 * found in the LICENSE file at https://angular.io/license
30474 */
30475 /**
30476 * Provides a hook for centralized exception handling.
30477 *
30478 * The default implementation of `ErrorHandler` prints error messages to the `console`. To
30479 * intercept error handling, write a custom exception handler that replaces this default as
30480 * appropriate for your app.
30481 *
30482 * @usageNotes
30483 * ### Example
30484 *
30485 * ```
30486 * class MyErrorHandler implements ErrorHandler {
30487 * handleError(error) {
30488 * // do something with the exception
30489 * }
30490 * }
30491 *
30492 * @NgModule({
30493 * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
30494 * })
30495 * class MyModule {}
30496 * ```
30497 *
30498 * @publicApi
30499 */
30500 class ErrorHandler {
30501 constructor() {
30502 /**
30503 * @internal
30504 */
30505 this._console = console;
30506 }
30507 handleError(error) {
30508 const originalError = this._findOriginalError(error);
30509 const context = this._findContext(error);
30510 // Note: Browser consoles show the place from where console.error was called.
30511 // We can use this to give users additional information about the error.
30512 const errorLogger = getErrorLogger(error);
30513 errorLogger(this._console, `ERROR`, error);
30514 if (originalError) {
30515 errorLogger(this._console, `ORIGINAL ERROR`, originalError);
30516 }
30517 if (context) {
30518 errorLogger(this._console, 'ERROR CONTEXT', context);
30519 }
30520 }
30521 /** @internal */
30522 _findContext(error) {
30523 if (error) {
30524 return getDebugContext(error) ? getDebugContext(error) :
30525 this._findContext(getOriginalError(error));
30526 }
30527 return null;
30528 }
30529 /** @internal */
30530 _findOriginalError(error) {
30531 let e = getOriginalError(error);
30532 while (e && getOriginalError(e)) {
30533 e = getOriginalError(e);
30534 }
30535 return e;
30536 }
30537 }
30538
30539 /**
30540 * @license
30541 * Copyright Google LLC All Rights Reserved.
30542 *
30543 * Use of this source code is governed by an MIT-style license that can be
30544 * found in the LICENSE file at https://angular.io/license
30545 */
30546 /**
30547 * THIS FILE CONTAINS CODE WHICH SHOULD BE TREE SHAKEN AND NEVER CALLED FROM PRODUCTION CODE!!!
30548 */
30549 /**
30550 * Creates an `Array` construction with a given name. This is useful when
30551 * looking for memory consumption to see what time of array it is.
30552 *
30553 *
30554 * @param name Name to give to the constructor
30555 * @returns A subclass of `Array` if possible. This can only be done in
30556 * environments which support `class` construct.
30557 */
30558 function createNamedArrayType(name) {
30559 // This should never be called in prod mode, so let's verify that is the case.
30560 if (ngDevMode) {
30561 try {
30562 // If this function were compromised the following could lead to arbitrary
30563 // script execution. We bless it with Trusted Types anyway since this
30564 // function is stripped out of production binaries.
30565 return (newTrustedFunctionForDev('Array', `return class ${name} extends Array{}`))(Array);
30566 }
30567 catch (e) {
30568 // If it does not work just give up and fall back to regular Array.
30569 return Array;
30570 }
30571 }
30572 else {
30573 throw new Error('Looks like we are in \'prod mode\', but we are creating a named Array type, which is wrong! Check your code');
30574 }
30575 }
30576
30577 /**
30578 * @license
30579 * Copyright Google LLC All Rights Reserved.
30580 *
30581 * Use of this source code is governed by an MIT-style license that can be
30582 * found in the LICENSE file at https://angular.io/license
30583 */
30584 /**
30585 * Assigns the given data to the given target (which could be a component,
30586 * directive or DOM node instance) using monkey-patching.
30587 */
30588 function attachPatchData(target, data) {
30589 target[MONKEY_PATCH_KEY_NAME] = data;
30590 }
30591
30592 /**
30593 * @license
30594 * Copyright Google LLC All Rights Reserved.
30595 *
30596 * Use of this source code is governed by an MIT-style license that can be
30597 * found in the LICENSE file at https://angular.io/license
30598 */
30599 const ɵ0$4 = () => (typeof requestAnimationFrame !== 'undefined' &&
30600 requestAnimationFrame || // browser only
30601 setTimeout // everything else
30602 )
30603 .bind(_global$1);
30604 const defaultScheduler = (ɵ0$4)();
30605
30606 /**
30607 * @license
30608 * Copyright Google LLC All Rights Reserved.
30609 *
30610 * Use of this source code is governed by an MIT-style license that can be
30611 * found in the LICENSE file at https://angular.io/license
30612 */
30613 /**
30614 * Flags for renderer-specific style modifiers.
30615 * @publicApi
30616 */
30617 var RendererStyleFlags2;
30618 (function (RendererStyleFlags2) {
30619 // TODO(misko): This needs to be refactored into a separate file so that it can be imported from
30620 // `node_manipulation.ts` Currently doing the import cause resolution order to change and fails
30621 // the tests. The work around is to have hard coded value in `node_manipulation.ts` for now.
30622 /**
30623 * Marks a style as important.
30624 */
30625 RendererStyleFlags2[RendererStyleFlags2["Important"] = 1] = "Important";
30626 /**
30627 * Marks a style as using dash case naming (this-is-dash-case).
30628 */
30629 RendererStyleFlags2[RendererStyleFlags2["DashCase"] = 2] = "DashCase";
30630 })(RendererStyleFlags2 || (RendererStyleFlags2 = {}));
30631
30632 /**
30633 * @license
30634 * Copyright Google LLC All Rights Reserved.
30635 *
30636 * Use of this source code is governed by an MIT-style license that can be
30637 * found in the LICENSE file at https://angular.io/license
30638 */
30639 let _icuContainerIterate;
30640 /**
30641 * Iterator which provides ability to visit all of the `TIcuContainerNode` root `RNode`s.
30642 */
30643 function icuContainerIterate(tIcuContainerNode, lView) {
30644 return _icuContainerIterate();
30645 }
30646
30647 /**
30648 * @license
30649 * Copyright Google LLC All Rights Reserved.
30650 *
30651 * Use of this source code is governed by an MIT-style license that can be
30652 * found in the LICENSE file at https://angular.io/license
30653 */
30654 /**
30655 * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of
30656 * that LContainer, which is an LView
30657 * @param lView the lView whose parent to get
30658 */
30659 function getLViewParent(lView) {
30660 ngDevMode && assertLView(lView);
30661 const parent = lView[PARENT];
30662 return isLContainer(parent) ? parent[PARENT] : parent;
30663 }
30664 /**
30665 * Gets the first `LContainer` in the LView or `null` if none exists.
30666 */
30667 function getFirstLContainer(lView) {
30668 return getNearestLContainer(lView[CHILD_HEAD]);
30669 }
30670 /**
30671 * Gets the next `LContainer` that is a sibling of the given container.
30672 */
30673 function getNextLContainer(container) {
30674 return getNearestLContainer(container[NEXT]);
30675 }
30676 function getNearestLContainer(viewOrContainer) {
30677 while (viewOrContainer !== null && !isLContainer(viewOrContainer)) {
30678 viewOrContainer = viewOrContainer[NEXT];
30679 }
30680 return viewOrContainer;
30681 }
30682
30683 /**
30684 * @license
30685 * Copyright Google LLC All Rights Reserved.
30686 *
30687 * Use of this source code is governed by an MIT-style license that can be
30688 * found in the LICENSE file at https://angular.io/license
30689 */
30690 /**
30691 * NOTE: for performance reasons, the possible actions are inlined within the function instead of
30692 * being passed as an argument.
30693 */
30694 function applyToElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
30695 // If this slot was allocated for a text node dynamically created by i18n, the text node itself
30696 // won't be created until i18nApply() in the update block, so this node should be skipped.
30697 // For more info, see "ICU expressions should work inside an ngTemplateOutlet inside an ngFor"
30698 // in `i18n_spec.ts`.
30699 if (lNodeToHandle != null) {
30700 let lContainer;
30701 let isComponent = false;
30702 // We are expecting an RNode, but in the case of a component or LContainer the `RNode` is
30703 // wrapped in an array which needs to be unwrapped. We need to know if it is a component and if
30704 // it has LContainer so that we can process all of those cases appropriately.
30705 if (isLContainer(lNodeToHandle)) {
30706 lContainer = lNodeToHandle;
30707 }
30708 else if (isLView(lNodeToHandle)) {
30709 isComponent = true;
30710 ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView');
30711 lNodeToHandle = lNodeToHandle[HOST];
30712 }
30713 const rNode = unwrapRNode(lNodeToHandle);
30714 ngDevMode && !isProceduralRenderer(renderer) && assertDomNode(rNode);
30715 if (action === 0 /* Create */ && parent !== null) {
30716 if (beforeNode == null) {
30717 nativeAppendChild(renderer, parent, rNode);
30718 }
30719 else {
30720 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
30721 }
30722 }
30723 else if (action === 1 /* Insert */ && parent !== null) {
30724 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
30725 }
30726 else if (action === 2 /* Detach */) {
30727 nativeRemoveNode(renderer, rNode, isComponent);
30728 }
30729 else if (action === 3 /* Destroy */) {
30730 ngDevMode && ngDevMode.rendererDestroyNode++;
30731 renderer.destroyNode(rNode);
30732 }
30733 if (lContainer != null) {
30734 applyContainer(renderer, action, lContainer, parent, beforeNode);
30735 }
30736 }
30737 }
30738 /**
30739 * Creates a native element from a tag name, using a renderer.
30740 * @param renderer A renderer to use
30741 * @param name the tag name
30742 * @param namespace Optional namespace for element.
30743 * @returns the element created
30744 */
30745 function createElementNode(renderer, name, namespace) {
30746 ngDevMode && ngDevMode.rendererCreateElement++;
30747 if (isProceduralRenderer(renderer)) {
30748 return renderer.createElement(name, namespace);
30749 }
30750 else {
30751 return namespace === null ? renderer.createElement(name) :
30752 renderer.createElementNS(namespace, name);
30753 }
30754 }
30755 /**
30756 * Removes all DOM elements associated with a view.
30757 *
30758 * Because some root nodes of the view may be containers, we sometimes need
30759 * to propagate deeply into the nested containers to remove all elements in the
30760 * views beneath it.
30761 *
30762 * @param tView The `TView' of the `LView` from which elements should be added or removed
30763 * @param lView The view from which elements should be added or removed
30764 */
30765 function removeViewFromContainer(tView, lView) {
30766 const renderer = lView[RENDERER];
30767 applyView(tView, lView, renderer, 2 /* Detach */, null, null);
30768 lView[HOST] = null;
30769 lView[T_HOST] = null;
30770 }
30771 /**
30772 * Detach a `LView` from the DOM by detaching its nodes.
30773 *
30774 * @param tView The `TView' of the `LView` to be detached
30775 * @param lView the `LView` to be detached.
30776 */
30777 function renderDetachView(tView, lView) {
30778 applyView(tView, lView, lView[RENDERER], 2 /* Detach */, null, null);
30779 }
30780 /**
30781 * Traverses down and up the tree of views and containers to remove listeners and
30782 * call onDestroy callbacks.
30783 *
30784 * Notes:
30785 * - Because it's used for onDestroy calls, it needs to be bottom-up.
30786 * - Must process containers instead of their views to avoid splicing
30787 * when views are destroyed and re-added.
30788 * - Using a while loop because it's faster than recursion
30789 * - Destroy only called on movement to sibling or movement to parent (laterally or up)
30790 *
30791 * @param rootView The view to destroy
30792 */
30793 function destroyViewTree(rootView) {
30794 // If the view has no children, we can clean it up and return early.
30795 let lViewOrLContainer = rootView[CHILD_HEAD];
30796 if (!lViewOrLContainer) {
30797 return cleanUpView(rootView[TVIEW], rootView);
30798 }
30799 while (lViewOrLContainer) {
30800 let next = null;
30801 if (isLView(lViewOrLContainer)) {
30802 // If LView, traverse down to child.
30803 next = lViewOrLContainer[CHILD_HEAD];
30804 }
30805 else {
30806 ngDevMode && assertLContainer(lViewOrLContainer);
30807 // If container, traverse down to its first LView.
30808 const firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET];
30809 if (firstView)
30810 next = firstView;
30811 }
30812 if (!next) {
30813 // Only clean up view when moving to the side or up, as destroy hooks
30814 // should be called in order from the bottom up.
30815 while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) {
30816 if (isLView(lViewOrLContainer)) {
30817 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
30818 }
30819 lViewOrLContainer = lViewOrLContainer[PARENT];
30820 }
30821 if (lViewOrLContainer === null)
30822 lViewOrLContainer = rootView;
30823 if (isLView(lViewOrLContainer)) {
30824 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
30825 }
30826 next = lViewOrLContainer && lViewOrLContainer[NEXT];
30827 }
30828 lViewOrLContainer = next;
30829 }
30830 }
30831 function detachMovedView(declarationContainer, lView) {
30832 ngDevMode && assertLContainer(declarationContainer);
30833 ngDevMode &&
30834 assertDefined(declarationContainer[MOVED_VIEWS], 'A projected view should belong to a non-empty projected views collection');
30835 const movedViews = declarationContainer[MOVED_VIEWS];
30836 const declarationViewIndex = movedViews.indexOf(lView);
30837 const insertionLContainer = lView[PARENT];
30838 ngDevMode && assertLContainer(insertionLContainer);
30839 // If the view was marked for refresh but then detached before it was checked (where the flag
30840 // would be cleared and the counter decremented), we need to decrement the view counter here
30841 // instead.
30842 if (lView[FLAGS] & 1024 /* RefreshTransplantedView */) {
30843 lView[FLAGS] &= ~1024 /* RefreshTransplantedView */;
30844 updateTransplantedViewCount(insertionLContainer, -1);
30845 }
30846 movedViews.splice(declarationViewIndex, 1);
30847 }
30848 /**
30849 * Detaches a view from a container.
30850 *
30851 * This method removes the view from the container's array of active views. It also
30852 * removes the view's elements from the DOM.
30853 *
30854 * @param lContainer The container from which to detach a view
30855 * @param removeIndex The index of the view to detach
30856 * @returns Detached LView instance.
30857 */
30858 function detachView(lContainer, removeIndex) {
30859 if (lContainer.length <= CONTAINER_HEADER_OFFSET)
30860 return;
30861 const indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
30862 const viewToDetach = lContainer[indexInContainer];
30863 if (viewToDetach) {
30864 const declarationLContainer = viewToDetach[DECLARATION_LCONTAINER];
30865 if (declarationLContainer !== null && declarationLContainer !== lContainer) {
30866 detachMovedView(declarationLContainer, viewToDetach);
30867 }
30868 if (removeIndex > 0) {
30869 lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT];
30870 }
30871 const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
30872 removeViewFromContainer(viewToDetach[TVIEW], viewToDetach);
30873 // notify query that a view has been removed
30874 const lQueries = removedLView[QUERIES];
30875 if (lQueries !== null) {
30876 lQueries.detachView(removedLView[TVIEW]);
30877 }
30878 viewToDetach[PARENT] = null;
30879 viewToDetach[NEXT] = null;
30880 // Unsets the attached flag
30881 viewToDetach[FLAGS] &= ~128 /* Attached */;
30882 }
30883 return viewToDetach;
30884 }
30885 /**
30886 * A standalone function which destroys an LView,
30887 * conducting clean up (e.g. removing listeners, calling onDestroys).
30888 *
30889 * @param tView The `TView' of the `LView` to be destroyed
30890 * @param lView The view to be destroyed.
30891 */
30892 function destroyLView(tView, lView) {
30893 if (!(lView[FLAGS] & 256 /* Destroyed */)) {
30894 const renderer = lView[RENDERER];
30895 if (isProceduralRenderer(renderer) && renderer.destroyNode) {
30896 applyView(tView, lView, renderer, 3 /* Destroy */, null, null);
30897 }
30898 destroyViewTree(lView);
30899 }
30900 }
30901 /**
30902 * Calls onDestroys hooks for all directives and pipes in a given view and then removes all
30903 * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks
30904 * can be propagated to @Output listeners.
30905 *
30906 * @param tView `TView` for the `LView` to clean up.
30907 * @param lView The LView to clean up
30908 */
30909 function cleanUpView(tView, lView) {
30910 if (!(lView[FLAGS] & 256 /* Destroyed */)) {
30911 // Usually the Attached flag is removed when the view is detached from its parent, however
30912 // if it's a root view, the flag won't be unset hence why we're also removing on destroy.
30913 lView[FLAGS] &= ~128 /* Attached */;
30914 // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
30915 // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
30916 // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
30917 // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
30918 // really more of an "afterDestroy" hook if you think about it.
30919 lView[FLAGS] |= 256 /* Destroyed */;
30920 executeOnDestroys(tView, lView);
30921 processCleanups(tView, lView);
30922 // For component views only, the local renderer is destroyed at clean up time.
30923 if (lView[TVIEW].type === 1 /* Component */ && isProceduralRenderer(lView[RENDERER])) {
30924 ngDevMode && ngDevMode.rendererDestroy++;
30925 lView[RENDERER].destroy();
30926 }
30927 const declarationContainer = lView[DECLARATION_LCONTAINER];
30928 // we are dealing with an embedded view that is still inserted into a container
30929 if (declarationContainer !== null && isLContainer(lView[PARENT])) {
30930 // and this is a projected view
30931 if (declarationContainer !== lView[PARENT]) {
30932 detachMovedView(declarationContainer, lView);
30933 }
30934 // For embedded views still attached to a container: remove query result from this view.
30935 const lQueries = lView[QUERIES];
30936 if (lQueries !== null) {
30937 lQueries.detachView(tView);
30938 }
30939 }
30940 }
30941 }
30942 /** Removes listeners and unsubscribes from output subscriptions */
30943 function processCleanups(tView, lView) {
30944 const tCleanup = tView.cleanup;
30945 const lCleanup = lView[CLEANUP];
30946 // `LCleanup` contains both share information with `TCleanup` as well as instance specific
30947 // information appended at the end. We need to know where the end of the `TCleanup` information
30948 // is, and we track this with `lastLCleanupIndex`.
30949 let lastLCleanupIndex = -1;
30950 if (tCleanup !== null) {
30951 for (let i = 0; i < tCleanup.length - 1; i += 2) {
30952 if (typeof tCleanup[i] === 'string') {
30953 // This is a native DOM listener
30954 const idxOrTargetGetter = tCleanup[i + 1];
30955 const target = typeof idxOrTargetGetter === 'function' ?
30956 idxOrTargetGetter(lView) :
30957 unwrapRNode(lView[idxOrTargetGetter]);
30958 const listener = lCleanup[lastLCleanupIndex = tCleanup[i + 2]];
30959 const useCaptureOrSubIdx = tCleanup[i + 3];
30960 if (typeof useCaptureOrSubIdx === 'boolean') {
30961 // native DOM listener registered with Renderer3
30962 target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx);
30963 }
30964 else {
30965 if (useCaptureOrSubIdx >= 0) {
30966 // unregister
30967 lCleanup[lastLCleanupIndex = useCaptureOrSubIdx]();
30968 }
30969 else {
30970 // Subscription
30971 lCleanup[lastLCleanupIndex = -useCaptureOrSubIdx].unsubscribe();
30972 }
30973 }
30974 i += 2;
30975 }
30976 else {
30977 // This is a cleanup function that is grouped with the index of its context
30978 const context = lCleanup[lastLCleanupIndex = tCleanup[i + 1]];
30979 tCleanup[i].call(context);
30980 }
30981 }
30982 }
30983 if (lCleanup !== null) {
30984 for (let i = lastLCleanupIndex + 1; i < lCleanup.length; i++) {
30985 const instanceCleanupFn = lCleanup[i];
30986 ngDevMode && assertFunction(instanceCleanupFn, 'Expecting instance cleanup function.');
30987 instanceCleanupFn();
30988 }
30989 lView[CLEANUP] = null;
30990 }
30991 }
30992 /** Calls onDestroy hooks for this view */
30993 function executeOnDestroys(tView, lView) {
30994 let destroyHooks;
30995 if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
30996 for (let i = 0; i < destroyHooks.length; i += 2) {
30997 const context = lView[destroyHooks[i]];
30998 // Only call the destroy hook if the context has been requested.
30999 if (!(context instanceof NodeInjectorFactory)) {
31000 const toCall = destroyHooks[i + 1];
31001 if (Array.isArray(toCall)) {
31002 for (let j = 0; j < toCall.length; j += 2) {
31003 toCall[j + 1].call(context[toCall[j]]);
31004 }
31005 }
31006 else {
31007 toCall.call(context);
31008 }
31009 }
31010 }
31011 }
31012 }
31013 /**
31014 * Inserts a native node before another native node for a given parent using {@link Renderer3}.
31015 * This is a utility function that can be used when native nodes were determined - it abstracts an
31016 * actual renderer being used.
31017 */
31018 function nativeInsertBefore(renderer, parent, child, beforeNode, isMove) {
31019 ngDevMode && ngDevMode.rendererInsertBefore++;
31020 if (isProceduralRenderer(renderer)) {
31021 renderer.insertBefore(parent, child, beforeNode, isMove);
31022 }
31023 else {
31024 parent.insertBefore(child, beforeNode, isMove);
31025 }
31026 }
31027 function nativeAppendChild(renderer, parent, child) {
31028 ngDevMode && ngDevMode.rendererAppendChild++;
31029 ngDevMode && assertDefined(parent, 'parent node must be defined');
31030 if (isProceduralRenderer(renderer)) {
31031 renderer.appendChild(parent, child);
31032 }
31033 else {
31034 parent.appendChild(child);
31035 }
31036 }
31037 /** Removes a node from the DOM given its native parent. */
31038 function nativeRemoveChild(renderer, parent, child, isHostElement) {
31039 if (isProceduralRenderer(renderer)) {
31040 renderer.removeChild(parent, child, isHostElement);
31041 }
31042 else {
31043 parent.removeChild(child);
31044 }
31045 }
31046 /**
31047 * Returns a native parent of a given native node.
31048 */
31049 function nativeParentNode(renderer, node) {
31050 return (isProceduralRenderer(renderer) ? renderer.parentNode(node) : node.parentNode);
31051 }
31052 function getProjectionNodes(lView, tNode) {
31053 if (tNode !== null) {
31054 const componentView = lView[DECLARATION_COMPONENT_VIEW];
31055 const componentHost = componentView[T_HOST];
31056 const slotIdx = tNode.projection;
31057 ngDevMode && assertProjectionSlots(lView);
31058 return componentHost.projection[slotIdx];
31059 }
31060 return null;
31061 }
31062 /**
31063 * Removes a native node itself using a given renderer. To remove the node we are looking up its
31064 * parent from the native tree as not all platforms / browsers support the equivalent of
31065 * node.remove().
31066 *
31067 * @param renderer A renderer to be used
31068 * @param rNode The native node that should be removed
31069 * @param isHostElement A flag indicating if a node to be removed is a host of a component.
31070 */
31071 function nativeRemoveNode(renderer, rNode, isHostElement) {
31072 ngDevMode && ngDevMode.rendererRemoveNode++;
31073 const nativeParent = nativeParentNode(renderer, rNode);
31074 if (nativeParent) {
31075 nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
31076 }
31077 }
31078 /**
31079 * Performs the operation of `action` on the node. Typically this involves inserting or removing
31080 * nodes on the LView or projection boundary.
31081 */
31082 function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode, isProjection) {
31083 while (tNode != null) {
31084 ngDevMode && assertTNodeForLView(tNode, lView);
31085 ngDevMode &&
31086 assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */ | 16 /* Projection */ | 32 /* Icu */);
31087 const rawSlotValue = lView[tNode.index];
31088 const tNodeType = tNode.type;
31089 if (isProjection) {
31090 if (action === 0 /* Create */) {
31091 rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
31092 tNode.flags |= 4 /* isProjected */;
31093 }
31094 }
31095 if ((tNode.flags & 64 /* isDetached */) !== 64 /* isDetached */) {
31096 if (tNodeType & 8 /* ElementContainer */) {
31097 applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
31098 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
31099 }
31100 else if (tNodeType & 32 /* Icu */) {
31101 const nextRNode = icuContainerIterate();
31102 let rNode;
31103 while (rNode = nextRNode()) {
31104 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
31105 }
31106 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
31107 }
31108 else if (tNodeType & 16 /* Projection */) {
31109 applyProjectionRecursive(renderer, action, lView, tNode, parentRElement, beforeNode);
31110 }
31111 else {
31112 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */ | 4 /* Container */);
31113 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
31114 }
31115 }
31116 tNode = isProjection ? tNode.projectionNext : tNode.next;
31117 }
31118 }
31119 function applyView(tView, lView, renderer, action, parentRElement, beforeNode) {
31120 applyNodes(renderer, action, tView.firstChild, lView, parentRElement, beforeNode, false);
31121 }
31122 /**
31123 * `applyProjectionRecursive` performs operation on the projection specified by `action` (insert,
31124 * detach, destroy)
31125 *
31126 * Inserting a projection requires us to locate the projected nodes from the parent component. The
31127 * complication is that those nodes themselves could be re-projected from their parent component.
31128 *
31129 * @param renderer Render to use
31130 * @param action action to perform (insert, detach, destroy)
31131 * @param lView The LView which needs to be inserted, detached, destroyed.
31132 * @param tProjectionNode node to project
31133 * @param parentRElement parent DOM element for insertion/removal.
31134 * @param beforeNode Before which node the insertions should happen.
31135 */
31136 function applyProjectionRecursive(renderer, action, lView, tProjectionNode, parentRElement, beforeNode) {
31137 const componentLView = lView[DECLARATION_COMPONENT_VIEW];
31138 const componentNode = componentLView[T_HOST];
31139 ngDevMode &&
31140 assertEqual(typeof tProjectionNode.projection, 'number', 'expecting projection index');
31141 const nodeToProjectOrRNodes = componentNode.projection[tProjectionNode.projection];
31142 if (Array.isArray(nodeToProjectOrRNodes)) {
31143 // This should not exist, it is a bit of a hack. When we bootstrap a top level node and we
31144 // need to support passing projectable nodes, so we cheat and put them in the TNode
31145 // of the Host TView. (Yes we put instance info at the T Level). We can get away with it
31146 // because we know that that TView is not shared and therefore it will not be a problem.
31147 // This should be refactored and cleaned up.
31148 for (let i = 0; i < nodeToProjectOrRNodes.length; i++) {
31149 const rNode = nodeToProjectOrRNodes[i];
31150 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
31151 }
31152 }
31153 else {
31154 let nodeToProject = nodeToProjectOrRNodes;
31155 const projectedComponentLView = componentLView[PARENT];
31156 applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
31157 }
31158 }
31159 /**
31160 * `applyContainer` performs an operation on the container and its views as specified by
31161 * `action` (insert, detach, destroy)
31162 *
31163 * Inserting a Container is complicated by the fact that the container may have Views which
31164 * themselves have containers or projections.
31165 *
31166 * @param renderer Renderer to use
31167 * @param action action to perform (insert, detach, destroy)
31168 * @param lContainer The LContainer which needs to be inserted, detached, destroyed.
31169 * @param parentRElement parent DOM element for insertion/removal.
31170 * @param beforeNode Before which node the insertions should happen.
31171 */
31172 function applyContainer(renderer, action, lContainer, parentRElement, beforeNode) {
31173 ngDevMode && assertLContainer(lContainer);
31174 const anchor = lContainer[NATIVE]; // LContainer has its own before node.
31175 const native = unwrapRNode(lContainer);
31176 // An LContainer can be created dynamically on any node by injecting ViewContainerRef.
31177 // Asking for a ViewContainerRef on an element will result in a creation of a separate anchor
31178 // node (comment in the DOM) that will be different from the LContainer's host node. In this
31179 // particular case we need to execute action on 2 nodes:
31180 // - container's host node (this is done in the executeActionOnElementOrContainer)
31181 // - container's host node (this is done here)
31182 if (anchor !== native) {
31183 // This is very strange to me (Misko). I would expect that the native is same as anchor. I
31184 // don't see a reason why they should be different, but they are.
31185 //
31186 // If they are we need to process the second anchor as well.
31187 applyToElementOrContainer(action, renderer, parentRElement, anchor, beforeNode);
31188 }
31189 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
31190 const lView = lContainer[i];
31191 applyView(lView[TVIEW], lView, renderer, action, parentRElement, anchor);
31192 }
31193 }
31194 /**
31195 * Write `cssText` to `RElement`.
31196 *
31197 * This function does direct write without any reconciliation. Used for writing initial values, so
31198 * that static styling values do not pull in the style parser.
31199 *
31200 * @param renderer Renderer to use
31201 * @param element The element which needs to be updated.
31202 * @param newValue The new class list to write.
31203 */
31204 function writeDirectStyle(renderer, element, newValue) {
31205 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
31206 if (isProceduralRenderer(renderer)) {
31207 renderer.setAttribute(element, 'style', newValue);
31208 }
31209 else {
31210 element.style.cssText = newValue;
31211 }
31212 ngDevMode && ngDevMode.rendererSetStyle++;
31213 }
31214 /**
31215 * Write `className` to `RElement`.
31216 *
31217 * This function does direct write without any reconciliation. Used for writing initial values, so
31218 * that static styling values do not pull in the style parser.
31219 *
31220 * @param renderer Renderer to use
31221 * @param element The element which needs to be updated.
31222 * @param newValue The new class list to write.
31223 */
31224 function writeDirectClass(renderer, element, newValue) {
31225 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
31226 if (isProceduralRenderer(renderer)) {
31227 if (newValue === '') {
31228 // There are tests in `google3` which expect `element.getAttribute('class')` to be `null`.
31229 renderer.removeAttribute(element, 'class');
31230 }
31231 else {
31232 renderer.setAttribute(element, 'class', newValue);
31233 }
31234 }
31235 else {
31236 element.className = newValue;
31237 }
31238 ngDevMode && ngDevMode.rendererSetClassName++;
31239 }
31240
31241 /**
31242 * @license
31243 * Copyright Google LLC All Rights Reserved.
31244 *
31245 * Use of this source code is governed by an MIT-style license that can be
31246 * found in the LICENSE file at https://angular.io/license
31247 */
31248 function isPositive(mode) {
31249 return (mode & 1 /* NOT */) === 0;
31250 }
31251 function maybeWrapInNotSelector(isNegativeMode, chunk) {
31252 return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
31253 }
31254 function stringifyCSSSelector(selector) {
31255 let result = selector[0];
31256 let i = 1;
31257 let mode = 2 /* ATTRIBUTE */;
31258 let currentChunk = '';
31259 let isNegativeMode = false;
31260 while (i < selector.length) {
31261 let valueOrMarker = selector[i];
31262 if (typeof valueOrMarker === 'string') {
31263 if (mode & 2 /* ATTRIBUTE */) {
31264 const attrValue = selector[++i];
31265 currentChunk +=
31266 '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
31267 }
31268 else if (mode & 8 /* CLASS */) {
31269 currentChunk += '.' + valueOrMarker;
31270 }
31271 else if (mode & 4 /* ELEMENT */) {
31272 currentChunk += ' ' + valueOrMarker;
31273 }
31274 }
31275 else {
31276 //
31277 // Append current chunk to the final result in case we come across SelectorFlag, which
31278 // indicates that the previous section of a selector is over. We need to accumulate content
31279 // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
31280 // ```
31281 // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
31282 // ```
31283 // should be transformed to `.classA :not(.classB .classC)`.
31284 //
31285 // Note: for negative selector part, we accumulate content between flags until we find the
31286 // next negative flag. This is needed to support a case where `:not()` rule contains more than
31287 // one chunk, e.g. the following selector:
31288 // ```
31289 // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
31290 // ```
31291 // should be stringified to `:not(p.foo) :not(.bar)`
31292 //
31293 if (currentChunk !== '' && !isPositive(valueOrMarker)) {
31294 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
31295 currentChunk = '';
31296 }
31297 mode = valueOrMarker;
31298 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
31299 // mode is maintained for remaining chunks of a selector.
31300 isNegativeMode = isNegativeMode || !isPositive(mode);
31301 }
31302 i++;
31303 }
31304 if (currentChunk !== '') {
31305 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
31306 }
31307 return result;
31308 }
31309 /**
31310 * Generates string representation of CSS selector in parsed form.
31311 *
31312 * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
31313 * additional parsing at runtime (for example, for directive matching). However in some cases (for
31314 * example, while bootstrapping a component), a string version of the selector is required to query
31315 * for the host element on the page. This function takes the parsed form of a selector and returns
31316 * its string representation.
31317 *
31318 * @param selectorList selector in parsed form
31319 * @returns string representation of a given selector
31320 */
31321 function stringifyCSSSelectorList(selectorList) {
31322 return selectorList.map(stringifyCSSSelector).join(',');
31323 }
31324 /**
31325 * Extracts attributes and classes information from a given CSS selector.
31326 *
31327 * This function is used while creating a component dynamically. In this case, the host element
31328 * (that is created dynamically) should contain attributes and classes specified in component's CSS
31329 * selector.
31330 *
31331 * @param selector CSS selector in parsed form (in a form of array)
31332 * @returns object with `attrs` and `classes` fields that contain extracted information
31333 */
31334 function extractAttrsAndClassesFromSelector(selector) {
31335 const attrs = [];
31336 const classes = [];
31337 let i = 1;
31338 let mode = 2 /* ATTRIBUTE */;
31339 while (i < selector.length) {
31340 let valueOrMarker = selector[i];
31341 if (typeof valueOrMarker === 'string') {
31342 if (mode === 2 /* ATTRIBUTE */) {
31343 if (valueOrMarker !== '') {
31344 attrs.push(valueOrMarker, selector[++i]);
31345 }
31346 }
31347 else if (mode === 8 /* CLASS */) {
31348 classes.push(valueOrMarker);
31349 }
31350 }
31351 else {
31352 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
31353 // mode is maintained for remaining chunks of a selector. Since attributes and classes are
31354 // extracted only for "positive" part of the selector, we can stop here.
31355 if (!isPositive(mode))
31356 break;
31357 mode = valueOrMarker;
31358 }
31359 i++;
31360 }
31361 return { attrs, classes };
31362 }
31363
31364 /**
31365 * @license
31366 * Copyright Google LLC All Rights Reserved.
31367 *
31368 * Use of this source code is governed by an MIT-style license that can be
31369 * found in the LICENSE file at https://angular.io/license
31370 */
31371 /** A special value which designates that a value has not changed. */
31372 const NO_CHANGE = (typeof ngDevMode === 'undefined' || ngDevMode) ? { __brand__: 'NO_CHANGE' } : {};
31373
31374 /**
31375 * @license
31376 * Copyright Google LLC All Rights Reserved.
31377 *
31378 * Use of this source code is governed by an MIT-style license that can be
31379 * found in the LICENSE file at https://angular.io/license
31380 */
31381 function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
31382 ngDevMode && assertIndexInDeclRange(lView, index);
31383 // Flush the initial hooks for elements in the view that have been added up to this point.
31384 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
31385 if (!checkNoChangesMode) {
31386 const hooksInitPhaseCompleted = (lView[FLAGS] & 3 /* InitPhaseStateMask */) === 3 /* InitPhaseCompleted */;
31387 if (hooksInitPhaseCompleted) {
31388 const preOrderCheckHooks = tView.preOrderCheckHooks;
31389 if (preOrderCheckHooks !== null) {
31390 executeCheckHooks(lView, preOrderCheckHooks, index);
31391 }
31392 }
31393 else {
31394 const preOrderHooks = tView.preOrderHooks;
31395 if (preOrderHooks !== null) {
31396 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* OnInitHooksToBeRun */, index);
31397 }
31398 }
31399 }
31400 // We must set the selected index *after* running the hooks, because hooks may have side-effects
31401 // that cause other template functions to run, thus updating the selected index, which is global
31402 // state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index
31403 // will be altered by the time we leave the `ɵɵadvance` instruction.
31404 setSelectedIndex(index);
31405 }
31406
31407 /**
31408 * @license
31409 * Copyright Google LLC All Rights Reserved.
31410 *
31411 * Use of this source code is governed by an MIT-style license that can be
31412 * found in the LICENSE file at https://angular.io/license
31413 */
31414 function getTStylingRangePrev(tStylingRange) {
31415 ngDevMode && assertNumber(tStylingRange, 'expected number');
31416 return (tStylingRange >> 17 /* PREV_SHIFT */) & 32767 /* UNSIGNED_MASK */;
31417 }
31418 function getTStylingRangePrevDuplicate(tStylingRange) {
31419 ngDevMode && assertNumber(tStylingRange, 'expected number');
31420 return (tStylingRange & 2 /* PREV_DUPLICATE */) ==
31421 2 /* PREV_DUPLICATE */;
31422 }
31423 function getTStylingRangeNext(tStylingRange) {
31424 ngDevMode && assertNumber(tStylingRange, 'expected number');
31425 return (tStylingRange & 131068 /* NEXT_MASK */) >> 2 /* NEXT_SHIFT */;
31426 }
31427 function getTStylingRangeNextDuplicate(tStylingRange) {
31428 ngDevMode && assertNumber(tStylingRange, 'expected number');
31429 return (tStylingRange & 1 /* NEXT_DUPLICATE */) ===
31430 1 /* NEXT_DUPLICATE */;
31431 }
31432
31433 /**
31434 * @license
31435 * Copyright Google LLC All Rights Reserved.
31436 *
31437 * Use of this source code is governed by an MIT-style license that can be
31438 * found in the LICENSE file at https://angular.io/license
31439 */
31440 /**
31441 * Patch a `debug` property on top of the existing object.
31442 *
31443 * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
31444 *
31445 * @param obj Object to patch
31446 * @param debug Value to patch
31447 */
31448 function attachDebugObject(obj, debug) {
31449 if (ngDevMode) {
31450 Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
31451 }
31452 else {
31453 throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
31454 }
31455 }
31456
31457 /**
31458 * @license
31459 * Copyright Google LLC All Rights Reserved.
31460 *
31461 * Use of this source code is governed by an MIT-style license that can be
31462 * found in the LICENSE file at https://angular.io/license
31463 */
31464 const NG_DEV_MODE = ((typeof ngDevMode === 'undefined' || !!ngDevMode) && initNgDevMode());
31465 /*
31466 * This file contains conditionally attached classes which provide human readable (debug) level
31467 * information for `LView`, `LContainer` and other internal data structures. These data structures
31468 * are stored internally as array which makes it very difficult during debugging to reason about the
31469 * current state of the system.
31470 *
31471 * Patching the array with extra property does change the array's hidden class' but it does not
31472 * change the cost of access, therefore this patching should not have significant if any impact in
31473 * `ngDevMode` mode. (see: https://jsperf.com/array-vs-monkey-patch-array)
31474 *
31475 * So instead of seeing:
31476 * ```
31477 * Array(30) [Object, 659, null, …]
31478 * ```
31479 *
31480 * You get to see:
31481 * ```
31482 * LViewDebug {
31483 * views: [...],
31484 * flags: {attached: true, ...}
31485 * nodes: [
31486 * {html: '<div id="123">', ..., nodes: [
31487 * {html: '<span>', ..., nodes: null}
31488 * ]}
31489 * ]
31490 * }
31491 * ```
31492 */
31493 let LVIEW_COMPONENT_CACHE;
31494 let LVIEW_EMBEDDED_CACHE;
31495 let LVIEW_ROOT;
31496 /**
31497 * This function clones a blueprint and creates LView.
31498 *
31499 * Simple slice will keep the same type, and we need it to be LView
31500 */
31501 function cloneToLViewFromTViewBlueprint(tView) {
31502 const debugTView = tView;
31503 const lView = getLViewToClone(debugTView.type, tView.template && tView.template.name);
31504 return lView.concat(tView.blueprint);
31505 }
31506 function getLViewToClone(type, name) {
31507 switch (type) {
31508 case 0 /* Root */:
31509 if (LVIEW_ROOT === undefined)
31510 LVIEW_ROOT = new (createNamedArrayType('LRootView'))();
31511 return LVIEW_ROOT;
31512 case 1 /* Component */:
31513 if (LVIEW_COMPONENT_CACHE === undefined)
31514 LVIEW_COMPONENT_CACHE = new Map();
31515 let componentArray = LVIEW_COMPONENT_CACHE.get(name);
31516 if (componentArray === undefined) {
31517 componentArray = new (createNamedArrayType('LComponentView' + nameSuffix(name)))();
31518 LVIEW_COMPONENT_CACHE.set(name, componentArray);
31519 }
31520 return componentArray;
31521 case 2 /* Embedded */:
31522 if (LVIEW_EMBEDDED_CACHE === undefined)
31523 LVIEW_EMBEDDED_CACHE = new Map();
31524 let embeddedArray = LVIEW_EMBEDDED_CACHE.get(name);
31525 if (embeddedArray === undefined) {
31526 embeddedArray = new (createNamedArrayType('LEmbeddedView' + nameSuffix(name)))();
31527 LVIEW_EMBEDDED_CACHE.set(name, embeddedArray);
31528 }
31529 return embeddedArray;
31530 }
31531 throw new Error('unreachable code');
31532 }
31533 function nameSuffix(text) {
31534 if (text == null)
31535 return '';
31536 const index = text.lastIndexOf('_Template');
31537 return '_' + (index === -1 ? text : text.substr(0, index));
31538 }
31539 /**
31540 * This class is a debug version of Object literal so that we can have constructor name show up
31541 * in
31542 * debug tools in ngDevMode.
31543 */
31544 const TViewConstructor = class TView {
31545 constructor(type, blueprint, template, queries, viewQuery, declTNode, data, bindingStartIndex, expandoStartIndex, hostBindingOpCodes, firstCreatePass, firstUpdatePass, staticViewQueries, staticContentQueries, preOrderHooks, preOrderCheckHooks, contentHooks, contentCheckHooks, viewHooks, viewCheckHooks, destroyHooks, cleanup, contentQueries, components, directiveRegistry, pipeRegistry, firstChild, schemas, consts, incompleteFirstPass, _decls, _vars) {
31546 this.type = type;
31547 this.blueprint = blueprint;
31548 this.template = template;
31549 this.queries = queries;
31550 this.viewQuery = viewQuery;
31551 this.declTNode = declTNode;
31552 this.data = data;
31553 this.bindingStartIndex = bindingStartIndex;
31554 this.expandoStartIndex = expandoStartIndex;
31555 this.hostBindingOpCodes = hostBindingOpCodes;
31556 this.firstCreatePass = firstCreatePass;
31557 this.firstUpdatePass = firstUpdatePass;
31558 this.staticViewQueries = staticViewQueries;
31559 this.staticContentQueries = staticContentQueries;
31560 this.preOrderHooks = preOrderHooks;
31561 this.preOrderCheckHooks = preOrderCheckHooks;
31562 this.contentHooks = contentHooks;
31563 this.contentCheckHooks = contentCheckHooks;
31564 this.viewHooks = viewHooks;
31565 this.viewCheckHooks = viewCheckHooks;
31566 this.destroyHooks = destroyHooks;
31567 this.cleanup = cleanup;
31568 this.contentQueries = contentQueries;
31569 this.components = components;
31570 this.directiveRegistry = directiveRegistry;
31571 this.pipeRegistry = pipeRegistry;
31572 this.firstChild = firstChild;
31573 this.schemas = schemas;
31574 this.consts = consts;
31575 this.incompleteFirstPass = incompleteFirstPass;
31576 this._decls = _decls;
31577 this._vars = _vars;
31578 }
31579 get template_() {
31580 const buf = [];
31581 processTNodeChildren(this.firstChild, buf);
31582 return buf.join('');
31583 }
31584 get type_() {
31585 return TViewTypeAsString[this.type] || `TViewType.?${this.type}?`;
31586 }
31587 };
31588 class TNode {
31589 constructor(tView_, //
31590 type, //
31591 index, //
31592 insertBeforeIndex, //
31593 injectorIndex, //
31594 directiveStart, //
31595 directiveEnd, //
31596 directiveStylingLast, //
31597 propertyBindings, //
31598 flags, //
31599 providerIndexes, //
31600 value, //
31601 attrs, //
31602 mergedAttrs, //
31603 localNames, //
31604 initialInputs, //
31605 inputs, //
31606 outputs, //
31607 tViews, //
31608 next, //
31609 projectionNext, //
31610 child, //
31611 parent, //
31612 projection, //
31613 styles, //
31614 stylesWithoutHost, //
31615 residualStyles, //
31616 classes, //
31617 classesWithoutHost, //
31618 residualClasses, //
31619 classBindings, //
31620 styleBindings) {
31621 this.tView_ = tView_;
31622 this.type = type;
31623 this.index = index;
31624 this.insertBeforeIndex = insertBeforeIndex;
31625 this.injectorIndex = injectorIndex;
31626 this.directiveStart = directiveStart;
31627 this.directiveEnd = directiveEnd;
31628 this.directiveStylingLast = directiveStylingLast;
31629 this.propertyBindings = propertyBindings;
31630 this.flags = flags;
31631 this.providerIndexes = providerIndexes;
31632 this.value = value;
31633 this.attrs = attrs;
31634 this.mergedAttrs = mergedAttrs;
31635 this.localNames = localNames;
31636 this.initialInputs = initialInputs;
31637 this.inputs = inputs;
31638 this.outputs = outputs;
31639 this.tViews = tViews;
31640 this.next = next;
31641 this.projectionNext = projectionNext;
31642 this.child = child;
31643 this.parent = parent;
31644 this.projection = projection;
31645 this.styles = styles;
31646 this.stylesWithoutHost = stylesWithoutHost;
31647 this.residualStyles = residualStyles;
31648 this.classes = classes;
31649 this.classesWithoutHost = classesWithoutHost;
31650 this.residualClasses = residualClasses;
31651 this.classBindings = classBindings;
31652 this.styleBindings = styleBindings;
31653 }
31654 /**
31655 * Return a human debug version of the set of `NodeInjector`s which will be consulted when
31656 * resolving tokens from this `TNode`.
31657 *
31658 * When debugging applications, it is often difficult to determine which `NodeInjector`s will be
31659 * consulted. This method shows a list of `DebugNode`s representing the `TNode`s which will be
31660 * consulted in order when resolving a token starting at this `TNode`.
31661 *
31662 * The original data is stored in `LView` and `TView` with a lot of offset indexes, and so it is
31663 * difficult to reason about.
31664 *
31665 * @param lView The `LView` instance for this `TNode`.
31666 */
31667 debugNodeInjectorPath(lView) {
31668 const path = [];
31669 let injectorIndex = getInjectorIndex(this, lView);
31670 if (injectorIndex === -1) {
31671 // Looks like the current `TNode` does not have `NodeInjector` associated with it => look for
31672 // parent NodeInjector.
31673 const parentLocation = getParentInjectorLocation(this, lView);
31674 if (parentLocation !== NO_PARENT_INJECTOR) {
31675 // We found a parent, so start searching from the parent location.
31676 injectorIndex = getParentInjectorIndex(parentLocation);
31677 lView = getParentInjectorView(parentLocation, lView);
31678 }
31679 }
31680 while (injectorIndex !== -1) {
31681 ngDevMode && assertNodeInjector(lView, injectorIndex);
31682 const tNode = lView[TVIEW].data[injectorIndex + 8 /* TNODE */];
31683 path.push(buildDebugNode(tNode, lView));
31684 const parentLocation = lView[injectorIndex + 8 /* PARENT */];
31685 if (parentLocation === NO_PARENT_INJECTOR) {
31686 injectorIndex = -1;
31687 }
31688 else {
31689 injectorIndex = getParentInjectorIndex(parentLocation);
31690 lView = getParentInjectorView(parentLocation, lView);
31691 }
31692 }
31693 return path;
31694 }
31695 get type_() {
31696 return toTNodeTypeAsString(this.type) || `TNodeType.?${this.type}?`;
31697 }
31698 get flags_() {
31699 const flags = [];
31700 if (this.flags & 16 /* hasClassInput */)
31701 flags.push('TNodeFlags.hasClassInput');
31702 if (this.flags & 8 /* hasContentQuery */)
31703 flags.push('TNodeFlags.hasContentQuery');
31704 if (this.flags & 32 /* hasStyleInput */)
31705 flags.push('TNodeFlags.hasStyleInput');
31706 if (this.flags & 128 /* hasHostBindings */)
31707 flags.push('TNodeFlags.hasHostBindings');
31708 if (this.flags & 2 /* isComponentHost */)
31709 flags.push('TNodeFlags.isComponentHost');
31710 if (this.flags & 1 /* isDirectiveHost */)
31711 flags.push('TNodeFlags.isDirectiveHost');
31712 if (this.flags & 64 /* isDetached */)
31713 flags.push('TNodeFlags.isDetached');
31714 if (this.flags & 4 /* isProjected */)
31715 flags.push('TNodeFlags.isProjected');
31716 return flags.join('|');
31717 }
31718 get template_() {
31719 if (this.type & 1 /* Text */)
31720 return this.value;
31721 const buf = [];
31722 const tagName = typeof this.value === 'string' && this.value || this.type_;
31723 buf.push('<', tagName);
31724 if (this.flags) {
31725 buf.push(' ', this.flags_);
31726 }
31727 if (this.attrs) {
31728 for (let i = 0; i < this.attrs.length;) {
31729 const attrName = this.attrs[i++];
31730 if (typeof attrName == 'number') {
31731 break;
31732 }
31733 const attrValue = this.attrs[i++];
31734 buf.push(' ', attrName, '="', attrValue, '"');
31735 }
31736 }
31737 buf.push('>');
31738 processTNodeChildren(this.child, buf);
31739 buf.push('</', tagName, '>');
31740 return buf.join('');
31741 }
31742 get styleBindings_() {
31743 return toDebugStyleBinding(this, false);
31744 }
31745 get classBindings_() {
31746 return toDebugStyleBinding(this, true);
31747 }
31748 get providerIndexStart_() {
31749 return this.providerIndexes & 1048575 /* ProvidersStartIndexMask */;
31750 }
31751 get providerIndexEnd_() {
31752 return this.providerIndexStart_ +
31753 (this.providerIndexes >>> 20 /* CptViewProvidersCountShift */);
31754 }
31755 }
31756 const TNodeDebug = TNode;
31757 function toDebugStyleBinding(tNode, isClassBased) {
31758 const tData = tNode.tView_.data;
31759 const bindings = [];
31760 const range = isClassBased ? tNode.classBindings : tNode.styleBindings;
31761 const prev = getTStylingRangePrev(range);
31762 const next = getTStylingRangeNext(range);
31763 let isTemplate = next !== 0;
31764 let cursor = isTemplate ? next : prev;
31765 while (cursor !== 0) {
31766 const itemKey = tData[cursor];
31767 const itemRange = tData[cursor + 1];
31768 bindings.unshift({
31769 key: itemKey,
31770 index: cursor,
31771 isTemplate: isTemplate,
31772 prevDuplicate: getTStylingRangePrevDuplicate(itemRange),
31773 nextDuplicate: getTStylingRangeNextDuplicate(itemRange),
31774 nextIndex: getTStylingRangeNext(itemRange),
31775 prevIndex: getTStylingRangePrev(itemRange),
31776 });
31777 if (cursor === prev)
31778 isTemplate = false;
31779 cursor = getTStylingRangePrev(itemRange);
31780 }
31781 bindings.push((isClassBased ? tNode.residualClasses : tNode.residualStyles) || null);
31782 return bindings;
31783 }
31784 function processTNodeChildren(tNode, buf) {
31785 while (tNode) {
31786 buf.push(tNode.template_);
31787 tNode = tNode.next;
31788 }
31789 }
31790 const TViewData = NG_DEV_MODE && createNamedArrayType('TViewData') || null;
31791 let TVIEWDATA_EMPTY; // can't initialize here or it will not be tree shaken, because
31792 // `LView` constructor could have side-effects.
31793 /**
31794 * This function clones a blueprint and creates TData.
31795 *
31796 * Simple slice will keep the same type, and we need it to be TData
31797 */
31798 function cloneToTViewData(list) {
31799 if (TVIEWDATA_EMPTY === undefined)
31800 TVIEWDATA_EMPTY = new TViewData();
31801 return TVIEWDATA_EMPTY.concat(list);
31802 }
31803 const LViewBlueprint = NG_DEV_MODE && createNamedArrayType('LViewBlueprint') || null;
31804 const MatchesArray = NG_DEV_MODE && createNamedArrayType('MatchesArray') || null;
31805 const TViewComponents = NG_DEV_MODE && createNamedArrayType('TViewComponents') || null;
31806 const TNodeLocalNames = NG_DEV_MODE && createNamedArrayType('TNodeLocalNames') || null;
31807 const TNodeInitialInputs = NG_DEV_MODE && createNamedArrayType('TNodeInitialInputs') || null;
31808 const TNodeInitialData = NG_DEV_MODE && createNamedArrayType('TNodeInitialData') || null;
31809 const LCleanup = NG_DEV_MODE && createNamedArrayType('LCleanup') || null;
31810 const TCleanup = NG_DEV_MODE && createNamedArrayType('TCleanup') || null;
31811 function attachLViewDebug(lView) {
31812 attachDebugObject(lView, new LViewDebug(lView));
31813 }
31814 function toDebug(obj) {
31815 if (obj) {
31816 const debug = obj.debug;
31817 assertDefined(debug, 'Object does not have a debug representation.');
31818 return debug;
31819 }
31820 else {
31821 return obj;
31822 }
31823 }
31824 /**
31825 * Use this method to unwrap a native element in `LView` and convert it into HTML for easier
31826 * reading.
31827 *
31828 * @param value possibly wrapped native DOM node.
31829 * @param includeChildren If `true` then the serialized HTML form will include child elements
31830 * (same
31831 * as `outerHTML`). If `false` then the serialized HTML form will only contain the element
31832 * itself
31833 * (will not serialize child elements).
31834 */
31835 function toHtml(value, includeChildren = false) {
31836 const node = unwrapRNode(value);
31837 if (node) {
31838 switch (node.nodeType) {
31839 case Node.TEXT_NODE:
31840 return node.textContent;
31841 case Node.COMMENT_NODE:
31842 return `<!--${node.textContent}-->`;
31843 case Node.ELEMENT_NODE:
31844 const outerHTML = node.outerHTML;
31845 if (includeChildren) {
31846 return outerHTML;
31847 }
31848 else {
31849 const innerHTML = '>' + node.innerHTML + '<';
31850 return (outerHTML.split(innerHTML)[0]) + '>';
31851 }
31852 }
31853 }
31854 return null;
31855 }
31856 class LViewDebug {
31857 constructor(_raw_lView) {
31858 this._raw_lView = _raw_lView;
31859 }
31860 /**
31861 * Flags associated with the `LView` unpacked into a more readable state.
31862 */
31863 get flags() {
31864 const flags = this._raw_lView[FLAGS];
31865 return {
31866 __raw__flags__: flags,
31867 initPhaseState: flags & 3 /* InitPhaseStateMask */,
31868 creationMode: !!(flags & 4 /* CreationMode */),
31869 firstViewPass: !!(flags & 8 /* FirstLViewPass */),
31870 checkAlways: !!(flags & 16 /* CheckAlways */),
31871 dirty: !!(flags & 64 /* Dirty */),
31872 attached: !!(flags & 128 /* Attached */),
31873 destroyed: !!(flags & 256 /* Destroyed */),
31874 isRoot: !!(flags & 512 /* IsRoot */),
31875 indexWithinInitPhase: flags >> 11 /* IndexWithinInitPhaseShift */,
31876 };
31877 }
31878 get parent() {
31879 return toDebug(this._raw_lView[PARENT]);
31880 }
31881 get hostHTML() {
31882 return toHtml(this._raw_lView[HOST], true);
31883 }
31884 get html() {
31885 return (this.nodes || []).map(mapToHTML).join('');
31886 }
31887 get context() {
31888 return this._raw_lView[CONTEXT];
31889 }
31890 /**
31891 * The tree of nodes associated with the current `LView`. The nodes have been normalized into
31892 * a tree structure with relevant details pulled out for readability.
31893 */
31894 get nodes() {
31895 const lView = this._raw_lView;
31896 const tNode = lView[TVIEW].firstChild;
31897 return toDebugNodes(tNode, lView);
31898 }
31899 get template() {
31900 return this.tView.template_;
31901 }
31902 get tView() {
31903 return this._raw_lView[TVIEW];
31904 }
31905 get cleanup() {
31906 return this._raw_lView[CLEANUP];
31907 }
31908 get injector() {
31909 return this._raw_lView[INJECTOR];
31910 }
31911 get rendererFactory() {
31912 return this._raw_lView[RENDERER_FACTORY];
31913 }
31914 get renderer() {
31915 return this._raw_lView[RENDERER];
31916 }
31917 get sanitizer() {
31918 return this._raw_lView[SANITIZER];
31919 }
31920 get childHead() {
31921 return toDebug(this._raw_lView[CHILD_HEAD]);
31922 }
31923 get next() {
31924 return toDebug(this._raw_lView[NEXT]);
31925 }
31926 get childTail() {
31927 return toDebug(this._raw_lView[CHILD_TAIL]);
31928 }
31929 get declarationView() {
31930 return toDebug(this._raw_lView[DECLARATION_VIEW]);
31931 }
31932 get queries() {
31933 return this._raw_lView[QUERIES];
31934 }
31935 get tHost() {
31936 return this._raw_lView[T_HOST];
31937 }
31938 get decls() {
31939 return toLViewRange(this.tView, this._raw_lView, HEADER_OFFSET, this.tView.bindingStartIndex);
31940 }
31941 get vars() {
31942 return toLViewRange(this.tView, this._raw_lView, this.tView.bindingStartIndex, this.tView.expandoStartIndex);
31943 }
31944 get expando() {
31945 return toLViewRange(this.tView, this._raw_lView, this.tView.expandoStartIndex, this._raw_lView.length);
31946 }
31947 /**
31948 * Normalized view of child views (and containers) attached at this location.
31949 */
31950 get childViews() {
31951 const childViews = [];
31952 let child = this.childHead;
31953 while (child) {
31954 childViews.push(child);
31955 child = child.next;
31956 }
31957 return childViews;
31958 }
31959 }
31960 function mapToHTML(node) {
31961 if (node.type === 'ElementContainer') {
31962 return (node.children || []).map(mapToHTML).join('');
31963 }
31964 else if (node.type === 'IcuContainer') {
31965 throw new Error('Not implemented');
31966 }
31967 else {
31968 return toHtml(node.native, true) || '';
31969 }
31970 }
31971 function toLViewRange(tView, lView, start, end) {
31972 let content = [];
31973 for (let index = start; index < end; index++) {
31974 content.push({ index: index, t: tView.data[index], l: lView[index] });
31975 }
31976 return { start: start, end: end, length: end - start, content: content };
31977 }
31978 /**
31979 * Turns a flat list of nodes into a tree by walking the associated `TNode` tree.
31980 *
31981 * @param tNode
31982 * @param lView
31983 */
31984 function toDebugNodes(tNode, lView) {
31985 if (tNode) {
31986 const debugNodes = [];
31987 let tNodeCursor = tNode;
31988 while (tNodeCursor) {
31989 debugNodes.push(buildDebugNode(tNodeCursor, lView));
31990 tNodeCursor = tNodeCursor.next;
31991 }
31992 return debugNodes;
31993 }
31994 else {
31995 return [];
31996 }
31997 }
31998 function buildDebugNode(tNode, lView) {
31999 const rawValue = lView[tNode.index];
32000 const native = unwrapRNode(rawValue);
32001 const factories = [];
32002 const instances = [];
32003 const tView = lView[TVIEW];
32004 for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
32005 const def = tView.data[i];
32006 factories.push(def.type);
32007 instances.push(lView[i]);
32008 }
32009 return {
32010 html: toHtml(native),
32011 type: toTNodeTypeAsString(tNode.type),
32012 tNode,
32013 native: native,
32014 children: toDebugNodes(tNode.child, lView),
32015 factories,
32016 instances,
32017 injector: buildNodeInjectorDebug(tNode, tView, lView),
32018 get injectorResolutionPath() {
32019 return tNode.debugNodeInjectorPath(lView);
32020 },
32021 };
32022 }
32023 function buildNodeInjectorDebug(tNode, tView, lView) {
32024 const viewProviders = [];
32025 for (let i = tNode.providerIndexStart_; i < tNode.providerIndexEnd_; i++) {
32026 viewProviders.push(tView.data[i]);
32027 }
32028 const providers = [];
32029 for (let i = tNode.providerIndexEnd_; i < tNode.directiveEnd; i++) {
32030 providers.push(tView.data[i]);
32031 }
32032 const nodeInjectorDebug = {
32033 bloom: toBloom(lView, tNode.injectorIndex),
32034 cumulativeBloom: toBloom(tView.data, tNode.injectorIndex),
32035 providers,
32036 viewProviders,
32037 parentInjectorIndex: lView[tNode.providerIndexStart_ - 1],
32038 };
32039 return nodeInjectorDebug;
32040 }
32041 /**
32042 * Convert a number at `idx` location in `array` into binary representation.
32043 *
32044 * @param array
32045 * @param idx
32046 */
32047 function binary(array, idx) {
32048 const value = array[idx];
32049 // If not a number we print 8 `?` to retain alignment but let user know that it was called on
32050 // wrong type.
32051 if (typeof value !== 'number')
32052 return '????????';
32053 // We prefix 0s so that we have constant length number
32054 const text = '00000000' + value.toString(2);
32055 return text.substring(text.length - 8);
32056 }
32057 /**
32058 * Convert a bloom filter at location `idx` in `array` into binary representation.
32059 *
32060 * @param array
32061 * @param idx
32062 */
32063 function toBloom(array, idx) {
32064 if (idx < 0) {
32065 return 'NO_NODE_INJECTOR';
32066 }
32067 return `${binary(array, idx + 7)}_${binary(array, idx + 6)}_${binary(array, idx + 5)}_${binary(array, idx + 4)}_${binary(array, idx + 3)}_${binary(array, idx + 2)}_${binary(array, idx + 1)}_${binary(array, idx + 0)}`;
32068 }
32069
32070 const ɵ0$5 = () => Promise.resolve(null);
32071 /**
32072 * A permanent marker promise which signifies that the current CD tree is
32073 * clean.
32074 */
32075 const _CLEAN_PROMISE = (ɵ0$5)();
32076 /**
32077 * Invoke `HostBindingsFunction`s for view.
32078 *
32079 * This methods executes `TView.hostBindingOpCodes`. It is used to execute the
32080 * `HostBindingsFunction`s associated with the current `LView`.
32081 *
32082 * @param tView Current `TView`.
32083 * @param lView Current `LView`.
32084 */
32085 function processHostBindingOpCodes(tView, lView) {
32086 const hostBindingOpCodes = tView.hostBindingOpCodes;
32087 if (hostBindingOpCodes === null)
32088 return;
32089 try {
32090 for (let i = 0; i < hostBindingOpCodes.length; i++) {
32091 const opCode = hostBindingOpCodes[i];
32092 if (opCode < 0) {
32093 // Negative numbers are element indexes.
32094 setSelectedIndex(~opCode);
32095 }
32096 else {
32097 // Positive numbers are NumberTuple which store bindingRootIndex and directiveIndex.
32098 const directiveIdx = opCode;
32099 const bindingRootIndx = hostBindingOpCodes[++i];
32100 const hostBindingFn = hostBindingOpCodes[++i];
32101 setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
32102 const context = lView[directiveIdx];
32103 hostBindingFn(2 /* Update */, context);
32104 }
32105 }
32106 }
32107 finally {
32108 setSelectedIndex(-1);
32109 }
32110 }
32111 /** Refreshes all content queries declared by directives in a given view */
32112 function refreshContentQueries(tView, lView) {
32113 const contentQueries = tView.contentQueries;
32114 if (contentQueries !== null) {
32115 for (let i = 0; i < contentQueries.length; i += 2) {
32116 const queryStartIdx = contentQueries[i];
32117 const directiveDefIdx = contentQueries[i + 1];
32118 if (directiveDefIdx !== -1) {
32119 const directiveDef = tView.data[directiveDefIdx];
32120 ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
32121 ngDevMode &&
32122 assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
32123 setCurrentQueryIndex(queryStartIdx);
32124 directiveDef.contentQueries(2 /* Update */, lView[directiveDefIdx], directiveDefIdx);
32125 }
32126 }
32127 }
32128 }
32129 /** Refreshes child components in the current view (update mode). */
32130 function refreshChildComponents(hostLView, components) {
32131 for (let i = 0; i < components.length; i++) {
32132 refreshComponent(hostLView, components[i]);
32133 }
32134 }
32135 /** Renders child components in the current view (creation mode). */
32136 function renderChildComponents(hostLView, components) {
32137 for (let i = 0; i < components.length; i++) {
32138 renderComponent(hostLView, components[i]);
32139 }
32140 }
32141 function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector) {
32142 const lView = ngDevMode ? cloneToLViewFromTViewBlueprint(tView) : tView.blueprint.slice();
32143 lView[HOST] = host;
32144 lView[FLAGS] = flags | 4 /* CreationMode */ | 128 /* Attached */ | 8 /* FirstLViewPass */;
32145 resetPreOrderHookFlags(lView);
32146 ngDevMode && tView.declTNode && parentLView && assertTNodeForLView(tView.declTNode, parentLView);
32147 lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
32148 lView[CONTEXT] = context;
32149 lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]);
32150 ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required');
32151 lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]);
32152 ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required');
32153 lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null;
32154 lView[INJECTOR] = injector || parentLView && parentLView[INJECTOR] || null;
32155 lView[T_HOST] = tHostNode;
32156 ngDevMode &&
32157 assertEqual(tView.type == 2 /* Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
32158 lView[DECLARATION_COMPONENT_VIEW] =
32159 tView.type == 2 /* Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
32160 ngDevMode && attachLViewDebug(lView);
32161 return lView;
32162 }
32163 function getOrCreateTNode(tView, index, type, name, attrs) {
32164 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
32165 // `view_engine_compatibility` for additional context.
32166 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
32167 // Keep this function short, so that the VM will inline it.
32168 ngDevMode && assertPureTNodeType(type);
32169 let tNode = tView.data[index];
32170 if (tNode === null) {
32171 tNode = createTNodeAtIndex(tView, index, type, name, attrs);
32172 if (isInI18nBlock()) {
32173 // If we are in i18n block then all elements should be pre declared through `Placeholder`
32174 // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
32175 // If the `TNode` was not pre-declared than it means it was not mentioned which means it was
32176 // removed, so we mark it as detached.
32177 tNode.flags |= 64 /* isDetached */;
32178 }
32179 }
32180 else if (tNode.type & 64 /* Placeholder */) {
32181 tNode.type = type;
32182 tNode.value = name;
32183 tNode.attrs = attrs;
32184 const parent = getCurrentParentTNode();
32185 tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex;
32186 ngDevMode && assertTNodeForTView(tNode, tView);
32187 ngDevMode && assertEqual(index, tNode.index, 'Expecting same index');
32188 }
32189 setCurrentTNode(tNode, true);
32190 return tNode;
32191 }
32192 function createTNodeAtIndex(tView, index, type, name, attrs) {
32193 const currentTNode = getCurrentTNodePlaceholderOk();
32194 const isParent = isCurrentTNodeParent();
32195 const parent = isParent ? currentTNode : currentTNode && currentTNode.parent;
32196 // Parents cannot cross component boundaries because components will be used in multiple places.
32197 const tNode = tView.data[index] =
32198 createTNode(tView, parent, type, index, name, attrs);
32199 // Assign a pointer to the first child node of a given view. The first node is not always the one
32200 // at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
32201 // the index 1 or more, so we can't just check node index.
32202 if (tView.firstChild === null) {
32203 tView.firstChild = tNode;
32204 }
32205 if (currentTNode !== null) {
32206 if (isParent) {
32207 // FIXME(misko): This logic looks unnecessarily complicated. Could we simplify?
32208 if (currentTNode.child == null && tNode.parent !== null) {
32209 // We are in the same view, which means we are adding content node to the parent view.
32210 currentTNode.child = tNode;
32211 }
32212 }
32213 else {
32214 if (currentTNode.next === null) {
32215 // In the case of i18n the `currentTNode` may already be linked, in which case we don't want
32216 // to break the links which i18n created.
32217 currentTNode.next = tNode;
32218 }
32219 }
32220 }
32221 return tNode;
32222 }
32223 /**
32224 * When elements are created dynamically after a view blueprint is created (e.g. through
32225 * i18nApply()), we need to adjust the blueprint for future
32226 * template passes.
32227 *
32228 * @param tView `TView` associated with `LView`
32229 * @param lView The `LView` containing the blueprint to adjust
32230 * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
32231 * @param initialValue Initial value to store in blueprint
32232 */
32233 function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
32234 if (numSlotsToAlloc === 0)
32235 return -1;
32236 if (ngDevMode) {
32237 assertFirstCreatePass(tView);
32238 assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
32239 assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
32240 assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
32241 assertFirstUpdatePass(tView);
32242 }
32243 const allocIdx = lView.length;
32244 for (let i = 0; i < numSlotsToAlloc; i++) {
32245 lView.push(initialValue);
32246 tView.blueprint.push(initialValue);
32247 tView.data.push(null);
32248 }
32249 return allocIdx;
32250 }
32251 //////////////////////////
32252 //// Render
32253 //////////////////////////
32254 /**
32255 * Processes a view in the creation mode. This includes a number of steps in a specific order:
32256 * - creating view query functions (if any);
32257 * - executing a template function in the creation mode;
32258 * - updating static queries (if any);
32259 * - creating child components defined in a given view.
32260 */
32261 function renderView(tView, lView, context) {
32262 ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
32263 enterView(lView);
32264 try {
32265 const viewQuery = tView.viewQuery;
32266 if (viewQuery !== null) {
32267 executeViewQueryFn(1 /* Create */, viewQuery, context);
32268 }
32269 // Execute a template associated with this view, if it exists. A template function might not be
32270 // defined for the root component views.
32271 const templateFn = tView.template;
32272 if (templateFn !== null) {
32273 executeTemplate(tView, lView, templateFn, 1 /* Create */, context);
32274 }
32275 // This needs to be set before children are processed to support recursive components.
32276 // This must be set to false immediately after the first creation run because in an
32277 // ngFor loop, all the views will be created together before update mode runs and turns
32278 // off firstCreatePass. If we don't set it here, instances will perform directive
32279 // matching, etc again and again.
32280 if (tView.firstCreatePass) {
32281 tView.firstCreatePass = false;
32282 }
32283 // We resolve content queries specifically marked as `static` in creation mode. Dynamic
32284 // content queries are resolved during change detection (i.e. update mode), after embedded
32285 // views are refreshed (see block above).
32286 if (tView.staticContentQueries) {
32287 refreshContentQueries(tView, lView);
32288 }
32289 // We must materialize query results before child components are processed
32290 // in case a child component has projected a container. The LContainer needs
32291 // to exist so the embedded views are properly attached by the container.
32292 if (tView.staticViewQueries) {
32293 executeViewQueryFn(2 /* Update */, tView.viewQuery, context);
32294 }
32295 // Render child component views.
32296 const components = tView.components;
32297 if (components !== null) {
32298 renderChildComponents(lView, components);
32299 }
32300 }
32301 catch (error) {
32302 // If we didn't manage to get past the first template pass due to
32303 // an error, mark the view as corrupted so we can try to recover.
32304 if (tView.firstCreatePass) {
32305 tView.incompleteFirstPass = true;
32306 }
32307 throw error;
32308 }
32309 finally {
32310 lView[FLAGS] &= ~4 /* CreationMode */;
32311 leaveView();
32312 }
32313 }
32314 /**
32315 * Processes a view in update mode. This includes a number of steps in a specific order:
32316 * - executing a template function in update mode;
32317 * - executing hooks;
32318 * - refreshing queries;
32319 * - setting host bindings;
32320 * - refreshing child (embedded and component) views.
32321 */
32322 function refreshView(tView, lView, templateFn, context) {
32323 ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
32324 const flags = lView[FLAGS];
32325 if ((flags & 256 /* Destroyed */) === 256 /* Destroyed */)
32326 return;
32327 enterView(lView);
32328 // Check no changes mode is a dev only mode used to verify that bindings have not changed
32329 // since they were assigned. We do not want to execute lifecycle hooks in that mode.
32330 const isInCheckNoChangesPass = isInCheckNoChangesMode();
32331 try {
32332 resetPreOrderHookFlags(lView);
32333 setBindingIndex(tView.bindingStartIndex);
32334 if (templateFn !== null) {
32335 executeTemplate(tView, lView, templateFn, 2 /* Update */, context);
32336 }
32337 const hooksInitPhaseCompleted = (flags & 3 /* InitPhaseStateMask */) === 3 /* InitPhaseCompleted */;
32338 // execute pre-order hooks (OnInit, OnChanges, DoCheck)
32339 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
32340 if (!isInCheckNoChangesPass) {
32341 if (hooksInitPhaseCompleted) {
32342 const preOrderCheckHooks = tView.preOrderCheckHooks;
32343 if (preOrderCheckHooks !== null) {
32344 executeCheckHooks(lView, preOrderCheckHooks, null);
32345 }
32346 }
32347 else {
32348 const preOrderHooks = tView.preOrderHooks;
32349 if (preOrderHooks !== null) {
32350 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* OnInitHooksToBeRun */, null);
32351 }
32352 incrementInitPhaseFlags(lView, 0 /* OnInitHooksToBeRun */);
32353 }
32354 }
32355 // First mark transplanted views that are declared in this lView as needing a refresh at their
32356 // insertion points. This is needed to avoid the situation where the template is defined in this
32357 // `LView` but its declaration appears after the insertion component.
32358 markTransplantedViewsForRefresh(lView);
32359 refreshEmbeddedViews(lView);
32360 // Content query results must be refreshed before content hooks are called.
32361 if (tView.contentQueries !== null) {
32362 refreshContentQueries(tView, lView);
32363 }
32364 // execute content hooks (AfterContentInit, AfterContentChecked)
32365 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
32366 if (!isInCheckNoChangesPass) {
32367 if (hooksInitPhaseCompleted) {
32368 const contentCheckHooks = tView.contentCheckHooks;
32369 if (contentCheckHooks !== null) {
32370 executeCheckHooks(lView, contentCheckHooks);
32371 }
32372 }
32373 else {
32374 const contentHooks = tView.contentHooks;
32375 if (contentHooks !== null) {
32376 executeInitAndCheckHooks(lView, contentHooks, 1 /* AfterContentInitHooksToBeRun */);
32377 }
32378 incrementInitPhaseFlags(lView, 1 /* AfterContentInitHooksToBeRun */);
32379 }
32380 }
32381 processHostBindingOpCodes(tView, lView);
32382 // Refresh child component views.
32383 const components = tView.components;
32384 if (components !== null) {
32385 refreshChildComponents(lView, components);
32386 }
32387 // View queries must execute after refreshing child components because a template in this view
32388 // could be inserted in a child component. If the view query executes before child component
32389 // refresh, the template might not yet be inserted.
32390 const viewQuery = tView.viewQuery;
32391 if (viewQuery !== null) {
32392 executeViewQueryFn(2 /* Update */, viewQuery, context);
32393 }
32394 // execute view hooks (AfterViewInit, AfterViewChecked)
32395 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
32396 if (!isInCheckNoChangesPass) {
32397 if (hooksInitPhaseCompleted) {
32398 const viewCheckHooks = tView.viewCheckHooks;
32399 if (viewCheckHooks !== null) {
32400 executeCheckHooks(lView, viewCheckHooks);
32401 }
32402 }
32403 else {
32404 const viewHooks = tView.viewHooks;
32405 if (viewHooks !== null) {
32406 executeInitAndCheckHooks(lView, viewHooks, 2 /* AfterViewInitHooksToBeRun */);
32407 }
32408 incrementInitPhaseFlags(lView, 2 /* AfterViewInitHooksToBeRun */);
32409 }
32410 }
32411 if (tView.firstUpdatePass === true) {
32412 // We need to make sure that we only flip the flag on successful `refreshView` only
32413 // Don't do this in `finally` block.
32414 // If we did this in `finally` block then an exception could block the execution of styling
32415 // instructions which in turn would be unable to insert themselves into the styling linked
32416 // list. The result of this would be that if the exception would not be throw on subsequent CD
32417 // the styling would be unable to process it data and reflect to the DOM.
32418 tView.firstUpdatePass = false;
32419 }
32420 // Do not reset the dirty state when running in check no changes mode. We don't want components
32421 // to behave differently depending on whether check no changes is enabled or not. For example:
32422 // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
32423 // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
32424 // no changes cycle, the component would be not be dirty for the next update pass. This would
32425 // be different in production mode where the component dirty state is not reset.
32426 if (!isInCheckNoChangesPass) {
32427 lView[FLAGS] &= ~(64 /* Dirty */ | 8 /* FirstLViewPass */);
32428 }
32429 if (lView[FLAGS] & 1024 /* RefreshTransplantedView */) {
32430 lView[FLAGS] &= ~1024 /* RefreshTransplantedView */;
32431 updateTransplantedViewCount(lView[PARENT], -1);
32432 }
32433 }
32434 finally {
32435 leaveView();
32436 }
32437 }
32438 function renderComponentOrTemplate(tView, lView, templateFn, context) {
32439 const rendererFactory = lView[RENDERER_FACTORY];
32440 const normalExecutionPath = !isInCheckNoChangesMode();
32441 const creationModeIsActive = isCreationMode(lView);
32442 try {
32443 if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) {
32444 rendererFactory.begin();
32445 }
32446 if (creationModeIsActive) {
32447 renderView(tView, lView, context);
32448 }
32449 refreshView(tView, lView, templateFn, context);
32450 }
32451 finally {
32452 if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) {
32453 rendererFactory.end();
32454 }
32455 }
32456 }
32457 function executeTemplate(tView, lView, templateFn, rf, context) {
32458 const prevSelectedIndex = getSelectedIndex();
32459 try {
32460 setSelectedIndex(-1);
32461 if (rf & 2 /* Update */ && lView.length > HEADER_OFFSET) {
32462 // When we're updating, inherently select 0 so we don't
32463 // have to generate that instruction for most update blocks.
32464 selectIndexInternal(tView, lView, HEADER_OFFSET, isInCheckNoChangesMode());
32465 }
32466 templateFn(rf, context);
32467 }
32468 finally {
32469 setSelectedIndex(prevSelectedIndex);
32470 }
32471 }
32472 /**
32473 * Gets TView from a template function or creates a new TView
32474 * if it doesn't already exist.
32475 *
32476 * @param def ComponentDef
32477 * @returns TView
32478 */
32479 function getOrCreateTComponentView(def) {
32480 const tView = def.tView;
32481 // Create a TView if there isn't one, or recreate it if the first create pass didn't
32482 // complete successfully since we can't know for sure whether it's in a usable shape.
32483 if (tView === null || tView.incompleteFirstPass) {
32484 // Declaration node here is null since this function is called when we dynamically create a
32485 // component and hence there is no declaration.
32486 const declTNode = null;
32487 return def.tView = createTView(1 /* Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
32488 }
32489 return tView;
32490 }
32491 /**
32492 * Creates a TView instance
32493 *
32494 * @param type Type of `TView`.
32495 * @param declTNode Declaration location of this `TView`.
32496 * @param templateFn Template function
32497 * @param decls The number of nodes, local refs, and pipes in this template
32498 * @param directives Registry of directives for this view
32499 * @param pipes Registry of pipes for this view
32500 * @param viewQuery View queries for this view
32501 * @param schemas Schemas for this view
32502 * @param consts Constants for this view
32503 */
32504 function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
32505 ngDevMode && ngDevMode.tView++;
32506 const bindingStartIndex = HEADER_OFFSET + decls;
32507 // This length does not yet contain host bindings from child directives because at this point,
32508 // we don't know which directives are active on this template. As soon as a directive is matched
32509 // that has a host binding, we will update the blueprint with that def's hostVars count.
32510 const initialViewLength = bindingStartIndex + vars;
32511 const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
32512 const consts = typeof constsOrFactory === 'function' ? constsOrFactory() : constsOrFactory;
32513 const tView = blueprint[TVIEW] = ngDevMode ?
32514 new TViewConstructor(type, // type: TViewType,
32515 blueprint, // blueprint: LView,
32516 templateFn, // template: ComponentTemplate<{}>|null,
32517 null, // queries: TQueries|null
32518 viewQuery, // viewQuery: ViewQueriesFunction<{}>|null,
32519 declTNode, // declTNode: TNode|null,
32520 cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData,
32521 bindingStartIndex, // bindingStartIndex: number,
32522 initialViewLength, // expandoStartIndex: number,
32523 null, // hostBindingOpCodes: HostBindingOpCodes,
32524 true, // firstCreatePass: boolean,
32525 true, // firstUpdatePass: boolean,
32526 false, // staticViewQueries: boolean,
32527 false, // staticContentQueries: boolean,
32528 null, // preOrderHooks: HookData|null,
32529 null, // preOrderCheckHooks: HookData|null,
32530 null, // contentHooks: HookData|null,
32531 null, // contentCheckHooks: HookData|null,
32532 null, // viewHooks: HookData|null,
32533 null, // viewCheckHooks: HookData|null,
32534 null, // destroyHooks: DestroyHookData|null,
32535 null, // cleanup: any[]|null,
32536 null, // contentQueries: number[]|null,
32537 null, // components: number[]|null,
32538 typeof directives === 'function' ? //
32539 directives() : //
32540 directives, // directiveRegistry: DirectiveDefList|null,
32541 typeof pipes === 'function' ? pipes() : pipes, // pipeRegistry: PipeDefList|null,
32542 null, // firstChild: TNode|null,
32543 schemas, // schemas: SchemaMetadata[]|null,
32544 consts, // consts: TConstants|null
32545 false, // incompleteFirstPass: boolean
32546 decls, // ngDevMode only: decls
32547 vars) :
32548 {
32549 type: type,
32550 blueprint: blueprint,
32551 template: templateFn,
32552 queries: null,
32553 viewQuery: viewQuery,
32554 declTNode: declTNode,
32555 data: blueprint.slice().fill(null, bindingStartIndex),
32556 bindingStartIndex: bindingStartIndex,
32557 expandoStartIndex: initialViewLength,
32558 hostBindingOpCodes: null,
32559 firstCreatePass: true,
32560 firstUpdatePass: true,
32561 staticViewQueries: false,
32562 staticContentQueries: false,
32563 preOrderHooks: null,
32564 preOrderCheckHooks: null,
32565 contentHooks: null,
32566 contentCheckHooks: null,
32567 viewHooks: null,
32568 viewCheckHooks: null,
32569 destroyHooks: null,
32570 cleanup: null,
32571 contentQueries: null,
32572 components: null,
32573 directiveRegistry: typeof directives === 'function' ? directives() : directives,
32574 pipeRegistry: typeof pipes === 'function' ? pipes() : pipes,
32575 firstChild: null,
32576 schemas: schemas,
32577 consts: consts,
32578 incompleteFirstPass: false
32579 };
32580 if (ngDevMode) {
32581 // For performance reasons it is important that the tView retains the same shape during runtime.
32582 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
32583 // prevent class transitions.
32584 Object.seal(tView);
32585 }
32586 return tView;
32587 }
32588 function createViewBlueprint(bindingStartIndex, initialViewLength) {
32589 const blueprint = ngDevMode ? new LViewBlueprint() : [];
32590 for (let i = 0; i < initialViewLength; i++) {
32591 blueprint.push(i < bindingStartIndex ? null : NO_CHANGE);
32592 }
32593 return blueprint;
32594 }
32595 function createError(text, token) {
32596 return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
32597 }
32598 function assertHostNodeExists(rElement, elementOrSelector) {
32599 if (!rElement) {
32600 if (typeof elementOrSelector === 'string') {
32601 throw createError('Host node with selector not found:', elementOrSelector);
32602 }
32603 else {
32604 throw createError('Host node is required:', elementOrSelector);
32605 }
32606 }
32607 }
32608 /**
32609 * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
32610 *
32611 * @param rendererFactory Factory function to create renderer instance.
32612 * @param elementOrSelector Render element or CSS selector to locate the element.
32613 * @param encapsulation View Encapsulation defined for component that requests host element.
32614 */
32615 function locateHostElement(renderer, elementOrSelector, encapsulation) {
32616 if (isProceduralRenderer(renderer)) {
32617 // When using native Shadow DOM, do not clear host element to allow native slot projection
32618 const preserveContent = encapsulation === ViewEncapsulation$1.ShadowDom;
32619 return renderer.selectRootElement(elementOrSelector, preserveContent);
32620 }
32621 let rElement = typeof elementOrSelector === 'string' ?
32622 renderer.querySelector(elementOrSelector) :
32623 elementOrSelector;
32624 ngDevMode && assertHostNodeExists(rElement, elementOrSelector);
32625 // Always clear host element's content when Renderer3 is in use. For procedural renderer case we
32626 // make it depend on whether ShadowDom encapsulation is used (in which case the content should be
32627 // preserved to allow native slot projection). ShadowDom encapsulation requires procedural
32628 // renderer, and procedural renderer case is handled above.
32629 rElement.textContent = '';
32630 return rElement;
32631 }
32632 /**
32633 * Saves context for this cleanup function in LView.cleanupInstances.
32634 *
32635 * On the first template pass, saves in TView:
32636 * - Cleanup function
32637 * - Index of context we just saved in LView.cleanupInstances
32638 *
32639 * This function can also be used to store instance specific cleanup fns. In that case the `context`
32640 * is `null` and the function is store in `LView` (rather than it `TView`).
32641 */
32642 function storeCleanupWithContext(tView, lView, context, cleanupFn) {
32643 const lCleanup = getOrCreateLViewCleanup(lView);
32644 if (context === null) {
32645 // If context is null that this is instance specific callback. These callbacks can only be
32646 // inserted after template shared instances. For this reason in ngDevMode we freeze the TView.
32647 if (ngDevMode) {
32648 Object.freeze(getOrCreateTViewCleanup(tView));
32649 }
32650 lCleanup.push(cleanupFn);
32651 }
32652 else {
32653 lCleanup.push(context);
32654 if (tView.firstCreatePass) {
32655 getOrCreateTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1);
32656 }
32657 }
32658 }
32659 function createTNode(tView, tParent, type, index, value, attrs) {
32660 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
32661 // `view_engine_compatibility` for additional context.
32662 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
32663 ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\'');
32664 ngDevMode && ngDevMode.tNode++;
32665 ngDevMode && tParent && assertTNodeForTView(tParent, tView);
32666 let injectorIndex = tParent ? tParent.injectorIndex : -1;
32667 const tNode = ngDevMode ?
32668 new TNodeDebug(tView, // tView_: TView
32669 type, // type: TNodeType
32670 index, // index: number
32671 null, // insertBeforeIndex: null|-1|number|number[]
32672 injectorIndex, // injectorIndex: number
32673 -1, // directiveStart: number
32674 -1, // directiveEnd: number
32675 -1, // directiveStylingLast: number
32676 null, // propertyBindings: number[]|null
32677 0, // flags: TNodeFlags
32678 0, // providerIndexes: TNodeProviderIndexes
32679 value, // value: string|null
32680 attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
32681 null, // mergedAttrs
32682 null, // localNames: (string|number)[]|null
32683 undefined, // initialInputs: (string[]|null)[]|null|undefined
32684 null, // inputs: PropertyAliases|null
32685 null, // outputs: PropertyAliases|null
32686 null, // tViews: ITView|ITView[]|null
32687 null, // next: ITNode|null
32688 null, // projectionNext: ITNode|null
32689 null, // child: ITNode|null
32690 tParent, // parent: TElementNode|TContainerNode|null
32691 null, // projection: number|(ITNode|RNode[])[]|null
32692 null, // styles: string|null
32693 null, // stylesWithoutHost: string|null
32694 undefined, // residualStyles: string|null
32695 null, // classes: string|null
32696 null, // classesWithoutHost: string|null
32697 undefined, // residualClasses: string|null
32698 0, // classBindings: TStylingRange;
32699 0) :
32700 {
32701 type,
32702 index,
32703 insertBeforeIndex: null,
32704 injectorIndex,
32705 directiveStart: -1,
32706 directiveEnd: -1,
32707 directiveStylingLast: -1,
32708 propertyBindings: null,
32709 flags: 0,
32710 providerIndexes: 0,
32711 value: value,
32712 attrs: attrs,
32713 mergedAttrs: null,
32714 localNames: null,
32715 initialInputs: undefined,
32716 inputs: null,
32717 outputs: null,
32718 tViews: null,
32719 next: null,
32720 projectionNext: null,
32721 child: null,
32722 parent: tParent,
32723 projection: null,
32724 styles: null,
32725 stylesWithoutHost: null,
32726 residualStyles: undefined,
32727 classes: null,
32728 classesWithoutHost: null,
32729 residualClasses: undefined,
32730 classBindings: 0,
32731 styleBindings: 0,
32732 };
32733 if (ngDevMode) {
32734 // For performance reasons it is important that the tNode retains the same shape during runtime.
32735 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
32736 // prevent class transitions.
32737 Object.seal(tNode);
32738 }
32739 return tNode;
32740 }
32741 /**
32742 * Instantiate a root component.
32743 */
32744 function instantiateRootComponent(tView, lView, def) {
32745 const rootTNode = getCurrentTNode();
32746 if (tView.firstCreatePass) {
32747 if (def.providersResolver)
32748 def.providersResolver(def);
32749 const directiveIndex = allocExpando(tView, lView, 1, null);
32750 ngDevMode &&
32751 assertEqual(directiveIndex, rootTNode.directiveStart, 'Because this is a root component the allocated expando should match the TNode component.');
32752 configureViewWithDirective(tView, rootTNode, lView, directiveIndex, def);
32753 }
32754 const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart, rootTNode);
32755 attachPatchData(directive, lView);
32756 const native = getNativeByTNode(rootTNode, lView);
32757 if (native) {
32758 attachPatchData(native, lView);
32759 }
32760 return directive;
32761 }
32762 /**
32763 * Add `hostBindings` to the `TView.hostBindingOpCodes`.
32764 *
32765 * @param tView `TView` to which the `hostBindings` should be added.
32766 * @param tNode `TNode` the element which contains the directive
32767 * @param lView `LView` current `LView`
32768 * @param directiveIdx Directive index in view.
32769 * @param directiveVarsIdx Where will the directive's vars be stored
32770 * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
32771 */
32772 function registerHostBindingOpCodes(tView, tNode, lView, directiveIdx, directiveVarsIdx, def) {
32773 ngDevMode && assertFirstCreatePass(tView);
32774 const hostBindings = def.hostBindings;
32775 if (hostBindings) {
32776 let hostBindingOpCodes = tView.hostBindingOpCodes;
32777 if (hostBindingOpCodes === null) {
32778 hostBindingOpCodes = tView.hostBindingOpCodes = [];
32779 }
32780 const elementIndx = ~tNode.index;
32781 if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
32782 // Conditionally add select element so that we are more efficient in execution.
32783 // NOTE: this is strictly not necessary and it trades code size for runtime perf.
32784 // (We could just always add it.)
32785 hostBindingOpCodes.push(elementIndx);
32786 }
32787 hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
32788 }
32789 }
32790 /**
32791 * Returns the last selected element index in the `HostBindingOpCodes`
32792 *
32793 * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
32794 * if it changes. This method returns the last index (or '0' if not found.)
32795 *
32796 * Selected element index are only the ones which are negative.
32797 */
32798 function lastSelectedElementIdx(hostBindingOpCodes) {
32799 let i = hostBindingOpCodes.length;
32800 while (i > 0) {
32801 const value = hostBindingOpCodes[--i];
32802 if (typeof value === 'number' && value < 0) {
32803 return value;
32804 }
32805 }
32806 return 0;
32807 }
32808 /**
32809 * Invoke the host bindings in creation mode.
32810 *
32811 * @param def `DirectiveDef` which may contain the `hostBindings` function.
32812 * @param directive Instance of directive.
32813 */
32814 function invokeHostBindingsInCreationMode(def, directive) {
32815 if (def.hostBindings !== null) {
32816 def.hostBindings(1 /* Create */, directive);
32817 }
32818 }
32819 /**
32820 * Marks a given TNode as a component's host. This consists of:
32821 * - setting appropriate TNode flags;
32822 * - storing index of component's host element so it will be queued for view refresh during CD.
32823 */
32824 function markAsComponentHost(tView, hostTNode) {
32825 ngDevMode && assertFirstCreatePass(tView);
32826 hostTNode.flags |= 2 /* isComponentHost */;
32827 (tView.components || (tView.components = ngDevMode ? new TViewComponents() : []))
32828 .push(hostTNode.index);
32829 }
32830 /**
32831 * Initializes the flags on the current node, setting all indices to the initial index,
32832 * the directive count to 0, and adding the isComponent flag.
32833 * @param index the initial index
32834 */
32835 function initTNodeFlags(tNode, index, numberOfDirectives) {
32836 ngDevMode &&
32837 assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
32838 tNode.flags |= 1 /* isDirectiveHost */;
32839 // When the first directive is created on a node, save the index
32840 tNode.directiveStart = index;
32841 tNode.directiveEnd = index + numberOfDirectives;
32842 tNode.providerIndexes = index;
32843 }
32844 /**
32845 * Setup directive for instantiation.
32846 *
32847 * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
32848 * as `LView`. `TView` gets the `DirectiveDef`.
32849 *
32850 * @param tView `TView`
32851 * @param tNode `TNode`
32852 * @param lView `LView`
32853 * @param directiveIndex Index where the directive will be stored in the Expando.
32854 * @param def `DirectiveDef`
32855 */
32856 function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
32857 ngDevMode &&
32858 assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
32859 tView.data[directiveIndex] = def;
32860 const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
32861 const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null);
32862 tView.blueprint[directiveIndex] = nodeInjectorFactory;
32863 lView[directiveIndex] = nodeInjectorFactory;
32864 registerHostBindingOpCodes(tView, tNode, lView, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
32865 }
32866 //////////////////////////
32867 //// ViewContainer & View
32868 //////////////////////////
32869 // Not sure why I need to do `any` here but TS complains later.
32870 const LContainerArray = ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) &&
32871 createNamedArrayType('LContainer');
32872 /**
32873 * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
32874 * them by executing an associated template function.
32875 */
32876 function refreshEmbeddedViews(lView) {
32877 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
32878 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
32879 const embeddedLView = lContainer[i];
32880 const embeddedTView = embeddedLView[TVIEW];
32881 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
32882 if (viewAttachedToChangeDetector(embeddedLView)) {
32883 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
32884 }
32885 }
32886 }
32887 }
32888 /**
32889 * Mark transplanted views as needing to be refreshed at their insertion points.
32890 *
32891 * @param lView The `LView` that may have transplanted views.
32892 */
32893 function markTransplantedViewsForRefresh(lView) {
32894 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
32895 if (!lContainer[HAS_TRANSPLANTED_VIEWS])
32896 continue;
32897 const movedViews = lContainer[MOVED_VIEWS];
32898 ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
32899 for (let i = 0; i < movedViews.length; i++) {
32900 const movedLView = movedViews[i];
32901 const insertionLContainer = movedLView[PARENT];
32902 ngDevMode && assertLContainer(insertionLContainer);
32903 // We don't want to increment the counter if the moved LView was already marked for
32904 // refresh.
32905 if ((movedLView[FLAGS] & 1024 /* RefreshTransplantedView */) === 0) {
32906 updateTransplantedViewCount(insertionLContainer, 1);
32907 }
32908 // Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
32909 // those that aren't (declaration component === insertion component). In the latter case,
32910 // it's fine to add the flag, as we will clear it immediately in
32911 // `refreshEmbeddedViews` for the view currently being refreshed.
32912 movedLView[FLAGS] |= 1024 /* RefreshTransplantedView */;
32913 }
32914 }
32915 }
32916 /////////////
32917 /**
32918 * Refreshes components by entering the component view and processing its bindings, queries, etc.
32919 *
32920 * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
32921 */
32922 function refreshComponent(hostLView, componentHostIdx) {
32923 ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
32924 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
32925 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
32926 if (viewAttachedToChangeDetector(componentView)) {
32927 const tView = componentView[TVIEW];
32928 if (componentView[FLAGS] & (16 /* CheckAlways */ | 64 /* Dirty */)) {
32929 refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
32930 }
32931 else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
32932 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
32933 refreshContainsDirtyView(componentView);
32934 }
32935 }
32936 }
32937 /**
32938 * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
32939 * children or descendants of the given lView.
32940 *
32941 * @param lView The lView which contains descendant transplanted views that need to be refreshed.
32942 */
32943 function refreshContainsDirtyView(lView) {
32944 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
32945 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
32946 const embeddedLView = lContainer[i];
32947 if (embeddedLView[FLAGS] & 1024 /* RefreshTransplantedView */) {
32948 const embeddedTView = embeddedLView[TVIEW];
32949 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
32950 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
32951 }
32952 else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
32953 refreshContainsDirtyView(embeddedLView);
32954 }
32955 }
32956 }
32957 const tView = lView[TVIEW];
32958 // Refresh child component views.
32959 const components = tView.components;
32960 if (components !== null) {
32961 for (let i = 0; i < components.length; i++) {
32962 const componentView = getComponentLViewByIndex(components[i], lView);
32963 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
32964 if (viewAttachedToChangeDetector(componentView) &&
32965 componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
32966 refreshContainsDirtyView(componentView);
32967 }
32968 }
32969 }
32970 }
32971 function renderComponent(hostLView, componentHostIdx) {
32972 ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
32973 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
32974 const componentTView = componentView[TVIEW];
32975 syncViewWithBlueprint(componentTView, componentView);
32976 renderView(componentTView, componentView, componentView[CONTEXT]);
32977 }
32978 /**
32979 * Syncs an LView instance with its blueprint if they have gotten out of sync.
32980 *
32981 * Typically, blueprints and their view instances should always be in sync, so the loop here
32982 * will be skipped. However, consider this case of two components side-by-side:
32983 *
32984 * App template:
32985 * ```
32986 * <comp></comp>
32987 * <comp></comp>
32988 * ```
32989 *
32990 * The following will happen:
32991 * 1. App template begins processing.
32992 * 2. First <comp> is matched as a component and its LView is created.
32993 * 3. Second <comp> is matched as a component and its LView is created.
32994 * 4. App template completes processing, so it's time to check child templates.
32995 * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
32996 * 6. Second <comp> template is checked. Its blueprint has been updated by the first
32997 * <comp> template, but its LView was created before this update, so it is out of sync.
32998 *
32999 * Note that embedded views inside ngFor loops will never be out of sync because these views
33000 * are processed as soon as they are created.
33001 *
33002 * @param tView The `TView` that contains the blueprint for syncing
33003 * @param lView The view to sync
33004 */
33005 function syncViewWithBlueprint(tView, lView) {
33006 for (let i = lView.length; i < tView.blueprint.length; i++) {
33007 lView.push(tView.blueprint[i]);
33008 }
33009 }
33010 /**
33011 * Adds LView or LContainer to the end of the current view tree.
33012 *
33013 * This structure will be used to traverse through nested views to remove listeners
33014 * and call onDestroy callbacks.
33015 *
33016 * @param lView The view where LView or LContainer should be added
33017 * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header
33018 * @param lViewOrLContainer The LView or LContainer to add to the view tree
33019 * @returns The state passed in
33020 */
33021 function addToViewTree(lView, lViewOrLContainer) {
33022 // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
33023 // to the end of the queue, which means if the developer retrieves the LContainers from RNodes out
33024 // of order, the change detection will run out of order, as the act of retrieving the the
33025 // LContainer from the RNode is what adds it to the queue.
33026 if (lView[CHILD_HEAD]) {
33027 lView[CHILD_TAIL][NEXT] = lViewOrLContainer;
33028 }
33029 else {
33030 lView[CHILD_HEAD] = lViewOrLContainer;
33031 }
33032 lView[CHILD_TAIL] = lViewOrLContainer;
33033 return lViewOrLContainer;
33034 }
33035 ///////////////////////////////
33036 //// Change detection
33037 ///////////////////////////////
33038 /**
33039 * Marks current view and all ancestors dirty.
33040 *
33041 * Returns the root view because it is found as a byproduct of marking the view tree
33042 * dirty, and can be used by methods that consume markViewDirty() to easily schedule
33043 * change detection. Otherwise, such methods would need to traverse up the view tree
33044 * an additional time to get the root view and schedule a tick on it.
33045 *
33046 * @param lView The starting LView to mark dirty
33047 * @returns the root LView
33048 */
33049 function markViewDirty(lView) {
33050 while (lView) {
33051 lView[FLAGS] |= 64 /* Dirty */;
33052 const parent = getLViewParent(lView);
33053 // Stop traversing up as soon as you find a root view that wasn't attached to any container
33054 if (isRootView(lView) && !parent) {
33055 return lView;
33056 }
33057 // continue otherwise
33058 lView = parent;
33059 }
33060 return null;
33061 }
33062 function tickRootContext(rootContext) {
33063 for (let i = 0; i < rootContext.components.length; i++) {
33064 const rootComponent = rootContext.components[i];
33065 const lView = readPatchedLView(rootComponent);
33066 const tView = lView[TVIEW];
33067 renderComponentOrTemplate(tView, lView, tView.template, rootComponent);
33068 }
33069 }
33070 function detectChangesInternal(tView, lView, context) {
33071 const rendererFactory = lView[RENDERER_FACTORY];
33072 if (rendererFactory.begin)
33073 rendererFactory.begin();
33074 try {
33075 refreshView(tView, lView, tView.template, context);
33076 }
33077 catch (error) {
33078 handleError(lView, error);
33079 throw error;
33080 }
33081 finally {
33082 if (rendererFactory.end)
33083 rendererFactory.end();
33084 }
33085 }
33086 /**
33087 * Synchronously perform change detection on a root view and its components.
33088 *
33089 * @param lView The view which the change detection should be performed on.
33090 */
33091 function detectChangesInRootView(lView) {
33092 tickRootContext(lView[CONTEXT]);
33093 }
33094 function checkNoChangesInternal(tView, view, context) {
33095 setIsInCheckNoChangesMode(true);
33096 try {
33097 detectChangesInternal(tView, view, context);
33098 }
33099 finally {
33100 setIsInCheckNoChangesMode(false);
33101 }
33102 }
33103 /**
33104 * Checks the change detector on a root view and its components, and throws if any changes are
33105 * detected.
33106 *
33107 * This is used in development mode to verify that running change detection doesn't
33108 * introduce other changes.
33109 *
33110 * @param lView The view which the change detection should be checked on.
33111 */
33112 function checkNoChangesInRootView(lView) {
33113 setIsInCheckNoChangesMode(true);
33114 try {
33115 detectChangesInRootView(lView);
33116 }
33117 finally {
33118 setIsInCheckNoChangesMode(false);
33119 }
33120 }
33121 function executeViewQueryFn(flags, viewQueryFn, component) {
33122 ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
33123 setCurrentQueryIndex(0);
33124 viewQueryFn(flags, component);
33125 }
33126 const CLEAN_PROMISE = _CLEAN_PROMISE;
33127 function getOrCreateLViewCleanup(view) {
33128 // top level variables should not be exported for performance reasons (PERF_NOTES.md)
33129 return view[CLEANUP] || (view[CLEANUP] = ngDevMode ? new LCleanup() : []);
33130 }
33131 function getOrCreateTViewCleanup(tView) {
33132 return tView.cleanup || (tView.cleanup = ngDevMode ? new TCleanup() : []);
33133 }
33134 /** Handles an error thrown in an LView. */
33135 function handleError(lView, error) {
33136 const injector = lView[INJECTOR];
33137 const errorHandler = injector ? injector.get(ErrorHandler, null) : null;
33138 errorHandler && errorHandler.handleError(error);
33139 }
33140
33141 /**
33142 * @license
33143 * Copyright Google LLC All Rights Reserved.
33144 *
33145 * Use of this source code is governed by an MIT-style license that can be
33146 * found in the LICENSE file at https://angular.io/license
33147 */
33148 /**
33149 * Compute the static styling (class/style) from `TAttributes`.
33150 *
33151 * This function should be called during `firstCreatePass` only.
33152 *
33153 * @param tNode The `TNode` into which the styling information should be loaded.
33154 * @param attrs `TAttributes` containing the styling information.
33155 * @param writeToHost Where should the resulting static styles be written?
33156 * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
33157 * - `true` Write to `TNode.styles` / `TNode.classes`
33158 */
33159 function computeStaticStyling(tNode, attrs, writeToHost) {
33160 ngDevMode &&
33161 assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
33162 let styles = writeToHost ? tNode.styles : null;
33163 let classes = writeToHost ? tNode.classes : null;
33164 let mode = 0;
33165 if (attrs !== null) {
33166 for (let i = 0; i < attrs.length; i++) {
33167 const value = attrs[i];
33168 if (typeof value === 'number') {
33169 mode = value;
33170 }
33171 else if (mode == 1 /* Classes */) {
33172 classes = concatStringsWithSpace(classes, value);
33173 }
33174 else if (mode == 2 /* Styles */) {
33175 const style = value;
33176 const styleValue = attrs[++i];
33177 styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
33178 }
33179 }
33180 }
33181 writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
33182 writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
33183 }
33184
33185 /**
33186 * @license
33187 * Copyright Google LLC All Rights Reserved.
33188 *
33189 * Use of this source code is governed by an MIT-style license that can be
33190 * found in the LICENSE file at https://angular.io/license
33191 */
33192 /**
33193 * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors.
33194 *
33195 * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a
33196 * project.
33197 *
33198 * @publicApi
33199 */
33200 const INJECTOR$1 = new InjectionToken('INJECTOR',
33201 // Dissable tslint because this is const enum which gets inlined not top level prop access.
33202 // tslint:disable-next-line: no-toplevel-property-access
33203 -1 /* Injector */);
33204
33205 /**
33206 * @license
33207 * Copyright Google LLC All Rights Reserved.
33208 *
33209 * Use of this source code is governed by an MIT-style license that can be
33210 * found in the LICENSE file at https://angular.io/license
33211 */
33212 class NullInjector {
33213 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
33214 if (notFoundValue === THROW_IF_NOT_FOUND) {
33215 const error = new Error(`NullInjectorError: No provider for ${stringify$1(token)}!`);
33216 error.name = 'NullInjectorError';
33217 throw error;
33218 }
33219 return notFoundValue;
33220 }
33221 }
33222
33223 /**
33224 * @license
33225 * Copyright Google LLC All Rights Reserved.
33226 *
33227 * Use of this source code is governed by an MIT-style license that can be
33228 * found in the LICENSE file at https://angular.io/license
33229 */
33230 /**
33231 * An internal token whose presence in an injector indicates that the injector should treat itself
33232 * as a root scoped injector when processing requests for unknown tokens which may indicate
33233 * they are provided in the root scope.
33234 */
33235 const INJECTOR_SCOPE = new InjectionToken('Set Injector scope.');
33236
33237 /**
33238 * @license
33239 * Copyright Google LLC All Rights Reserved.
33240 *
33241 * Use of this source code is governed by an MIT-style license that can be
33242 * found in the LICENSE file at https://angular.io/license
33243 */
33244 function INJECTOR_IMPL__PRE_R3__(providers, parent, name) {
33245 return new StaticInjector(providers, parent, name);
33246 }
33247 const INJECTOR_IMPL = INJECTOR_IMPL__PRE_R3__;
33248 /**
33249 * Concrete injectors implement this interface. Injectors are configured
33250 * with [providers](guide/glossary#provider) that associate
33251 * dependencies of various types with [injection tokens](guide/glossary#di-token).
33252 *
33253 * @see ["DI Providers"](guide/dependency-injection-providers).
33254 * @see `StaticProvider`
33255 *
33256 * @usageNotes
33257 *
33258 * The following example creates a service injector instance.
33259 *
33260 * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
33261 *
33262 * ### Usage example
33263 *
33264 * {@example core/di/ts/injector_spec.ts region='Injector'}
33265 *
33266 * `Injector` returns itself when given `Injector` as a token:
33267 *
33268 * {@example core/di/ts/injector_spec.ts region='injectInjector'}
33269 *
33270 * @publicApi
33271 */
33272 class Injector {
33273 static create(options, parent) {
33274 if (Array.isArray(options)) {
33275 return INJECTOR_IMPL(options, parent, '');
33276 }
33277 else {
33278 return INJECTOR_IMPL(options.providers, options.parent, options.name || '');
33279 }
33280 }
33281 }
33282 Injector.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
33283 Injector.NULL = new NullInjector();
33284 /** @nocollapse */
33285 Injector.ɵprov = ɵɵdefineInjectable({
33286 token: Injector,
33287 providedIn: 'any',
33288 factory: () => ɵɵinject(INJECTOR$1),
33289 });
33290 /**
33291 * @internal
33292 * @nocollapse
33293 */
33294 Injector.__NG_ELEMENT_ID__ = -1 /* Injector */;
33295 const IDENT = function (value) {
33296 return value;
33297 };
33298 const EMPTY = [];
33299 const CIRCULAR = IDENT;
33300 const MULTI_PROVIDER_FN = function () {
33301 return Array.prototype.slice.call(arguments);
33302 };
33303 const NO_NEW_LINE$1 = 'ɵ';
33304 class StaticInjector {
33305 constructor(providers, parent = Injector.NULL, source = null) {
33306 this.parent = parent;
33307 this.source = source;
33308 const records = this._records = new Map();
33309 records.set(Injector, { token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false });
33310 records.set(INJECTOR$1, { token: INJECTOR$1, fn: IDENT, deps: EMPTY, value: this, useNew: false });
33311 this.scope = recursivelyProcessProviders(records, providers);
33312 }
33313 get(token, notFoundValue, flags = InjectFlags.Default) {
33314 const records = this._records;
33315 let record = records.get(token);
33316 if (record === undefined) {
33317 // This means we have never seen this record, see if it is tree shakable provider.
33318 const injectableDef = getInjectableDef(token);
33319 if (injectableDef) {
33320 const providedIn = injectableDef && injectableDef.providedIn;
33321 if (providedIn === 'any' || providedIn != null && providedIn === this.scope) {
33322 records.set(token, record = resolveProvider({ provide: token, useFactory: injectableDef.factory, deps: EMPTY }));
33323 }
33324 }
33325 if (record === undefined) {
33326 // Set record to null to make sure that we don't go through expensive lookup above again.
33327 records.set(token, null);
33328 }
33329 }
33330 let lastInjector = setCurrentInjector(this);
33331 try {
33332 return tryResolveToken(token, record, records, this.parent, notFoundValue, flags);
33333 }
33334 catch (e) {
33335 return catchInjectorError(e, token, 'StaticInjectorError', this.source);
33336 }
33337 finally {
33338 setCurrentInjector(lastInjector);
33339 }
33340 }
33341 toString() {
33342 const tokens = [], records = this._records;
33343 records.forEach((v, token) => tokens.push(stringify$1(token)));
33344 return `StaticInjector[${tokens.join(', ')}]`;
33345 }
33346 }
33347 function resolveProvider(provider) {
33348 const deps = computeDeps(provider);
33349 let fn = IDENT;
33350 let value = EMPTY;
33351 let useNew = false;
33352 let provide = resolveForwardRef$1(provider.provide);
33353 if (USE_VALUE$2 in provider) {
33354 // We need to use USE_VALUE in provider since provider.useValue could be defined as undefined.
33355 value = provider.useValue;
33356 }
33357 else if (provider.useFactory) {
33358 fn = provider.useFactory;
33359 }
33360 else if (provider.useExisting) ;
33361 else if (provider.useClass) {
33362 useNew = true;
33363 fn = resolveForwardRef$1(provider.useClass);
33364 }
33365 else if (typeof provide == 'function') {
33366 useNew = true;
33367 fn = provide;
33368 }
33369 else {
33370 throw staticError('StaticProvider does not have [useValue|useFactory|useExisting|useClass] or [provide] is not newable', provider);
33371 }
33372 return { deps, fn, useNew, value };
33373 }
33374 function multiProviderMixError(token) {
33375 return staticError('Cannot mix multi providers and regular providers', token);
33376 }
33377 function recursivelyProcessProviders(records, provider) {
33378 let scope = null;
33379 if (provider) {
33380 provider = resolveForwardRef$1(provider);
33381 if (Array.isArray(provider)) {
33382 // if we have an array recurse into the array
33383 for (let i = 0; i < provider.length; i++) {
33384 scope = recursivelyProcessProviders(records, provider[i]) || scope;
33385 }
33386 }
33387 else if (typeof provider === 'function') {
33388 // Functions were supported in ReflectiveInjector, but are not here. For safety give useful
33389 // error messages
33390 throw staticError('Function/Class not supported', provider);
33391 }
33392 else if (provider && typeof provider === 'object' && provider.provide) {
33393 // At this point we have what looks like a provider: {provide: ?, ....}
33394 let token = resolveForwardRef$1(provider.provide);
33395 const resolvedProvider = resolveProvider(provider);
33396 if (provider.multi === true) {
33397 // This is a multi provider.
33398 let multiProvider = records.get(token);
33399 if (multiProvider) {
33400 if (multiProvider.fn !== MULTI_PROVIDER_FN) {
33401 throw multiProviderMixError(token);
33402 }
33403 }
33404 else {
33405 // Create a placeholder factory which will look up the constituents of the multi provider.
33406 records.set(token, multiProvider = {
33407 token: provider.provide,
33408 deps: [],
33409 useNew: false,
33410 fn: MULTI_PROVIDER_FN,
33411 value: EMPTY
33412 });
33413 }
33414 // Treat the provider as the token.
33415 token = provider;
33416 multiProvider.deps.push({ token, options: 6 /* Default */ });
33417 }
33418 const record = records.get(token);
33419 if (record && record.fn == MULTI_PROVIDER_FN) {
33420 throw multiProviderMixError(token);
33421 }
33422 if (token === INJECTOR_SCOPE) {
33423 scope = resolvedProvider.value;
33424 }
33425 records.set(token, resolvedProvider);
33426 }
33427 else {
33428 throw staticError('Unexpected provider', provider);
33429 }
33430 }
33431 return scope;
33432 }
33433 function tryResolveToken(token, record, records, parent, notFoundValue, flags) {
33434 try {
33435 return resolveToken(token, record, records, parent, notFoundValue, flags);
33436 }
33437 catch (e) {
33438 // ensure that 'e' is of type Error.
33439 if (!(e instanceof Error)) {
33440 e = new Error(e);
33441 }
33442 const path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || [];
33443 path.unshift(token);
33444 if (record && record.value == CIRCULAR) {
33445 // Reset the Circular flag.
33446 record.value = EMPTY;
33447 }
33448 throw e;
33449 }
33450 }
33451 function resolveToken(token, record, records, parent, notFoundValue, flags) {
33452 let value;
33453 if (record && !(flags & InjectFlags.SkipSelf)) {
33454 // If we don't have a record, this implies that we don't own the provider hence don't know how
33455 // to resolve it.
33456 value = record.value;
33457 if (value == CIRCULAR) {
33458 throw Error(NO_NEW_LINE$1 + 'Circular dependency');
33459 }
33460 else if (value === EMPTY) {
33461 record.value = CIRCULAR;
33462 let obj = undefined;
33463 let useNew = record.useNew;
33464 let fn = record.fn;
33465 let depRecords = record.deps;
33466 let deps = EMPTY;
33467 if (depRecords.length) {
33468 deps = [];
33469 for (let i = 0; i < depRecords.length; i++) {
33470 const depRecord = depRecords[i];
33471 const options = depRecord.options;
33472 const childRecord = options & 2 /* CheckSelf */ ? records.get(depRecord.token) : undefined;
33473 deps.push(tryResolveToken(
33474 // Current Token to resolve
33475 depRecord.token,
33476 // A record which describes how to resolve the token.
33477 // If undefined, this means we don't have such a record
33478 childRecord,
33479 // Other records we know about.
33480 records,
33481 // If we don't know how to resolve dependency and we should not check parent for it,
33482 // than pass in Null injector.
33483 !childRecord && !(options & 4 /* CheckParent */) ? Injector.NULL : parent, options & 1 /* Optional */ ? null : Injector.THROW_IF_NOT_FOUND, InjectFlags.Default));
33484 }
33485 }
33486 record.value = value = useNew ? new fn(...deps) : fn.apply(obj, deps);
33487 }
33488 }
33489 else if (!(flags & InjectFlags.Self)) {
33490 value = parent.get(token, notFoundValue, InjectFlags.Default);
33491 }
33492 else if (!(flags & InjectFlags.Optional)) {
33493 value = Injector.NULL.get(token, notFoundValue);
33494 }
33495 else {
33496 value = Injector.NULL.get(token, typeof notFoundValue !== 'undefined' ? notFoundValue : null);
33497 }
33498 return value;
33499 }
33500 function computeDeps(provider) {
33501 let deps = EMPTY;
33502 const providerDeps = provider.deps;
33503 if (providerDeps && providerDeps.length) {
33504 deps = [];
33505 for (let i = 0; i < providerDeps.length; i++) {
33506 let options = 6 /* Default */;
33507 let token = resolveForwardRef$1(providerDeps[i]);
33508 if (Array.isArray(token)) {
33509 for (let j = 0, annotations = token; j < annotations.length; j++) {
33510 const annotation = annotations[j];
33511 if (annotation instanceof Optional || annotation == Optional) {
33512 options = options | 1 /* Optional */;
33513 }
33514 else if (annotation instanceof SkipSelf || annotation == SkipSelf) {
33515 options = options & ~2 /* CheckSelf */;
33516 }
33517 else if (annotation instanceof Self || annotation == Self) {
33518 options = options & ~4 /* CheckParent */;
33519 }
33520 else if (annotation instanceof Inject) {
33521 token = annotation.token;
33522 }
33523 else {
33524 token = resolveForwardRef$1(annotation);
33525 }
33526 }
33527 }
33528 deps.push({ token, options });
33529 }
33530 }
33531 else if (provider.useExisting) {
33532 const token = resolveForwardRef$1(provider.useExisting);
33533 deps = [{ token, options: 6 /* Default */ }];
33534 }
33535 else if (!providerDeps && !(USE_VALUE$2 in provider)) {
33536 // useValue & useExisting are the only ones which are exempt from deps all others need it.
33537 throw staticError('\'deps\' required', provider);
33538 }
33539 return deps;
33540 }
33541 function staticError(text, obj) {
33542 return new Error(formatError(text, obj, 'StaticInjectorError'));
33543 }
33544
33545 /**
33546 * @license
33547 * Copyright Google LLC All Rights Reserved.
33548 *
33549 * Use of this source code is governed by an MIT-style license that can be
33550 * found in the LICENSE file at https://angular.io/license
33551 */
33552 /**
33553 * Creates the root component view and the root component node.
33554 *
33555 * @param rNode Render host element.
33556 * @param def ComponentDef
33557 * @param rootView The parent view where the host node is stored
33558 * @param rendererFactory Factory to be used for creating child renderers.
33559 * @param hostRenderer The current renderer
33560 * @param sanitizer The sanitizer, if provided
33561 *
33562 * @returns Component view created
33563 */
33564 function createRootComponentView(rNode, def, rootView, rendererFactory, hostRenderer, sanitizer) {
33565 const tView = rootView[TVIEW];
33566 const index = HEADER_OFFSET;
33567 ngDevMode && assertIndexInRange(rootView, index);
33568 rootView[index] = rNode;
33569 // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
33570 // the same time we want to communicate the debug `TNode` that this is a special `TNode`
33571 // representing a host element.
33572 const tNode = getOrCreateTNode(tView, index, 2 /* Element */, '#host', null);
33573 const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
33574 if (mergedAttrs !== null) {
33575 computeStaticStyling(tNode, mergedAttrs, true);
33576 if (rNode !== null) {
33577 setUpAttributes(hostRenderer, rNode, mergedAttrs);
33578 if (tNode.classes !== null) {
33579 writeDirectClass(hostRenderer, rNode, tNode.classes);
33580 }
33581 if (tNode.styles !== null) {
33582 writeDirectStyle(hostRenderer, rNode, tNode.styles);
33583 }
33584 }
33585 }
33586 const viewRenderer = rendererFactory.createRenderer(rNode, def);
33587 const componentView = createLView(rootView, getOrCreateTComponentView(def), null, def.onPush ? 64 /* Dirty */ : 16 /* CheckAlways */, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null);
33588 if (tView.firstCreatePass) {
33589 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, def.type);
33590 markAsComponentHost(tView, tNode);
33591 initTNodeFlags(tNode, rootView.length, 1);
33592 }
33593 addToViewTree(rootView, componentView);
33594 // Store component view at node index, with node as the HOST
33595 return rootView[index] = componentView;
33596 }
33597 /**
33598 * Creates a root component and sets it up with features and host bindings. Shared by
33599 * renderComponent() and ViewContainerRef.createComponent().
33600 */
33601 function createRootComponent(componentView, componentDef, rootLView, rootContext, hostFeatures) {
33602 const tView = rootLView[TVIEW];
33603 // Create directive instance with factory() and store at next index in viewData
33604 const component = instantiateRootComponent(tView, rootLView, componentDef);
33605 rootContext.components.push(component);
33606 componentView[CONTEXT] = component;
33607 hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
33608 // We want to generate an empty QueryList for root content queries for backwards
33609 // compatibility with ViewEngine.
33610 if (componentDef.contentQueries) {
33611 const tNode = getCurrentTNode();
33612 ngDevMode && assertDefined(tNode, 'TNode expected');
33613 componentDef.contentQueries(1 /* Create */, component, tNode.directiveStart);
33614 }
33615 const rootTNode = getCurrentTNode();
33616 ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
33617 if (tView.firstCreatePass &&
33618 (componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) {
33619 setSelectedIndex(rootTNode.index);
33620 const rootTView = rootLView[TVIEW];
33621 registerHostBindingOpCodes(rootTView, rootTNode, rootLView, rootTNode.directiveStart, rootTNode.directiveEnd, componentDef);
33622 invokeHostBindingsInCreationMode(componentDef, component);
33623 }
33624 return component;
33625 }
33626 function createRootContext(scheduler, playerHandler) {
33627 return {
33628 components: [],
33629 scheduler: scheduler || defaultScheduler,
33630 clean: CLEAN_PROMISE,
33631 playerHandler: playerHandler || null,
33632 flags: 0 /* Empty */
33633 };
33634 }
33635 /**
33636 * Used to enable lifecycle hooks on the root component.
33637 *
33638 * Include this feature when calling `renderComponent` if the root component
33639 * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't
33640 * be called properly.
33641 *
33642 * Example:
33643 *
33644 * ```
33645 * renderComponent(AppComponent, {hostFeatures: [LifecycleHooksFeature]});
33646 * ```
33647 */
33648 function LifecycleHooksFeature(component, def) {
33649 const lView = readPatchedLView(component);
33650 ngDevMode && assertDefined(lView, 'LView is required');
33651 const tView = lView[TVIEW];
33652 const tNode = getCurrentTNode();
33653 ngDevMode && assertDefined(tNode, 'TNode is required');
33654 registerPostOrderHooks(tView, tNode);
33655 }
33656
33657 /**
33658 * @license
33659 * Copyright Google LLC All Rights Reserved.
33660 *
33661 * Use of this source code is governed by an MIT-style license that can be
33662 * found in the LICENSE file at https://angular.io/license
33663 */
33664 let _symbolIterator = null;
33665 function getSymbolIterator() {
33666 if (!_symbolIterator) {
33667 const Symbol = _global$1['Symbol'];
33668 if (Symbol && Symbol.iterator) {
33669 _symbolIterator = Symbol.iterator;
33670 }
33671 else {
33672 // es6-shim specific logic
33673 const keys = Object.getOwnPropertyNames(Map.prototype);
33674 for (let i = 0; i < keys.length; ++i) {
33675 const key = keys[i];
33676 if (key !== 'entries' && key !== 'size' &&
33677 Map.prototype[key] === Map.prototype['entries']) {
33678 _symbolIterator = key;
33679 }
33680 }
33681 }
33682 }
33683 return _symbolIterator;
33684 }
33685
33686 /**
33687 * @license
33688 * Copyright Google LLC All Rights Reserved.
33689 *
33690 * Use of this source code is governed by an MIT-style license that can be
33691 * found in the LICENSE file at https://angular.io/license
33692 */
33693 function isListLikeIterable(obj) {
33694 if (!isJsObject(obj))
33695 return false;
33696 return Array.isArray(obj) ||
33697 (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
33698 getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop
33699 }
33700 function iterateListLike(obj, fn) {
33701 if (Array.isArray(obj)) {
33702 for (let i = 0; i < obj.length; i++) {
33703 fn(obj[i]);
33704 }
33705 }
33706 else {
33707 const iterator = obj[getSymbolIterator()]();
33708 let item;
33709 while (!((item = iterator.next()).done)) {
33710 fn(item.value);
33711 }
33712 }
33713 }
33714 function isJsObject(o) {
33715 return o !== null && (typeof o === 'function' || typeof o === 'object');
33716 }
33717
33718 /**
33719 * @license
33720 * Copyright Google LLC All Rights Reserved.
33721 *
33722 * Use of this source code is governed by an MIT-style license that can be
33723 * found in the LICENSE file at https://angular.io/license
33724 */
33725 const ɵ0$6 = getClosureSafeProperty;
33726 const USE_VALUE$3 = getClosureSafeProperty({ provide: String, useValue: ɵ0$6 });
33727
33728 /**
33729 * @license
33730 * Copyright Google LLC All Rights Reserved.
33731 *
33732 * Use of this source code is governed by an MIT-style license that can be
33733 * found in the LICENSE file at https://angular.io/license
33734 */
33735 const ɵ0$7 = getClosureSafeProperty;
33736 const USE_VALUE$4 = getClosureSafeProperty({ provide: String, useValue: ɵ0$7 });
33737 const EMPTY_ARRAY$1 = [];
33738 function convertInjectableProviderToFactory(type, provider) {
33739 if (!provider) {
33740 const reflectionCapabilities = new ReflectionCapabilities();
33741 const deps = reflectionCapabilities.parameters(type);
33742 // TODO - convert to flags.
33743 return () => new type(...injectArgs(deps));
33744 }
33745 if (USE_VALUE$4 in provider) {
33746 const valueProvider = provider;
33747 return () => valueProvider.useValue;
33748 }
33749 else if (provider.useExisting) {
33750 const existingProvider = provider;
33751 return () => ɵɵinject(resolveForwardRef$1(existingProvider.useExisting));
33752 }
33753 else if (provider.useFactory) {
33754 const factoryProvider = provider;
33755 return () => factoryProvider.useFactory(...injectArgs(factoryProvider.deps || EMPTY_ARRAY$1));
33756 }
33757 else if (provider.useClass) {
33758 const classProvider = provider;
33759 let deps = provider.deps;
33760 if (!deps) {
33761 const reflectionCapabilities = new ReflectionCapabilities();
33762 deps = reflectionCapabilities.parameters(type);
33763 }
33764 return () => new (resolveForwardRef$1(classProvider.useClass))(...injectArgs(deps));
33765 }
33766 else {
33767 let deps = provider.deps;
33768 if (!deps) {
33769 const reflectionCapabilities = new ReflectionCapabilities();
33770 deps = reflectionCapabilities.parameters(type);
33771 }
33772 return () => new type(...injectArgs(deps));
33773 }
33774 }
33775
33776 /**
33777 * @license
33778 * Copyright Google LLC All Rights Reserved.
33779 *
33780 * Use of this source code is governed by an MIT-style license that can be
33781 * found in the LICENSE file at https://angular.io/license
33782 */
33783 const ɵ0$8 = (type, meta) => SWITCH_COMPILE_INJECTABLE(type, meta);
33784 /**
33785 * Injectable decorator and metadata.
33786 *
33787 * @Annotation
33788 * @publicApi
33789 */
33790 const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, ɵ0$8);
33791 /**
33792 * Supports @Injectable() in JIT mode for Render2.
33793 */
33794 function render2CompileInjectable(injectableType, options) {
33795 if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) {
33796 injectableType.ɵprov = ɵɵdefineInjectable({
33797 token: injectableType,
33798 providedIn: options.providedIn,
33799 factory: convertInjectableProviderToFactory(injectableType, options),
33800 });
33801 }
33802 }
33803 const SWITCH_COMPILE_INJECTABLE__PRE_R3__ = render2CompileInjectable;
33804 const SWITCH_COMPILE_INJECTABLE = SWITCH_COMPILE_INJECTABLE__PRE_R3__;
33805
33806 /**
33807 * @license
33808 * Copyright Google LLC All Rights Reserved.
33809 *
33810 * Use of this source code is governed by an MIT-style license that can be
33811 * found in the LICENSE file at https://angular.io/license
33812 */
33813 function findFirstClosedCycle(keys) {
33814 const res = [];
33815 for (let i = 0; i < keys.length; ++i) {
33816 if (res.indexOf(keys[i]) > -1) {
33817 res.push(keys[i]);
33818 return res;
33819 }
33820 res.push(keys[i]);
33821 }
33822 return res;
33823 }
33824 function constructResolvingPath(keys) {
33825 if (keys.length > 1) {
33826 const reversed = findFirstClosedCycle(keys.slice().reverse());
33827 const tokenStrs = reversed.map(k => stringify$1(k.token));
33828 return ' (' + tokenStrs.join(' -> ') + ')';
33829 }
33830 return '';
33831 }
33832 function injectionError(injector, key, constructResolvingMessage, originalError) {
33833 const keys = [key];
33834 const errMsg = constructResolvingMessage(keys);
33835 const error = (originalError ? wrappedError(errMsg, originalError) : Error(errMsg));
33836 error.addKey = addKey;
33837 error.keys = keys;
33838 error.injectors = [injector];
33839 error.constructResolvingMessage = constructResolvingMessage;
33840 error[ERROR_ORIGINAL_ERROR] = originalError;
33841 return error;
33842 }
33843 function addKey(injector, key) {
33844 this.injectors.push(injector);
33845 this.keys.push(key);
33846 // Note: This updated message won't be reflected in the `.stack` property
33847 this.message = this.constructResolvingMessage(this.keys);
33848 }
33849 /**
33850 * Thrown when trying to retrieve a dependency by key from {@link Injector}, but the
33851 * {@link Injector} does not have a {@link Provider} for the given key.
33852 *
33853 * @usageNotes
33854 * ### Example
33855 *
33856 * ```typescript
33857 * class A {
33858 * constructor(b:B) {}
33859 * }
33860 *
33861 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
33862 * ```
33863 */
33864 function noProviderError(injector, key) {
33865 return injectionError(injector, key, function (keys) {
33866 const first = stringify$1(keys[0].token);
33867 return `No provider for ${first}!${constructResolvingPath(keys)}`;
33868 });
33869 }
33870 /**
33871 * Thrown when dependencies form a cycle.
33872 *
33873 * @usageNotes
33874 * ### Example
33875 *
33876 * ```typescript
33877 * var injector = Injector.resolveAndCreate([
33878 * {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]},
33879 * {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]}
33880 * ]);
33881 *
33882 * expect(() => injector.get("one")).toThrowError();
33883 * ```
33884 *
33885 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
33886 */
33887 function cyclicDependencyError(injector, key) {
33888 return injectionError(injector, key, function (keys) {
33889 return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
33890 });
33891 }
33892 /**
33893 * Thrown when a constructing type returns with an Error.
33894 *
33895 * The `InstantiationError` class contains the original error plus the dependency graph which caused
33896 * this object to be instantiated.
33897 *
33898 * @usageNotes
33899 * ### Example
33900 *
33901 * ```typescript
33902 * class A {
33903 * constructor() {
33904 * throw new Error('message');
33905 * }
33906 * }
33907 *
33908 * var injector = Injector.resolveAndCreate([A]);
33909
33910 * try {
33911 * injector.get(A);
33912 * } catch (e) {
33913 * expect(e instanceof InstantiationError).toBe(true);
33914 * expect(e.originalException.message).toEqual("message");
33915 * expect(e.originalStack).toBeDefined();
33916 * }
33917 * ```
33918 */
33919 function instantiationError(injector, originalException, originalStack, key) {
33920 return injectionError(injector, key, function (keys) {
33921 const first = stringify$1(keys[0].token);
33922 return `${originalException.message}: Error during instantiation of ${first}!${constructResolvingPath(keys)}.`;
33923 }, originalException);
33924 }
33925 /**
33926 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
33927 * creation.
33928 *
33929 * @usageNotes
33930 * ### Example
33931 *
33932 * ```typescript
33933 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
33934 * ```
33935 */
33936 function invalidProviderError(provider) {
33937 return Error(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
33938 }
33939 /**
33940 * Thrown when the class has no annotation information.
33941 *
33942 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
33943 * need to be injected into the constructor.
33944 *
33945 * @usageNotes
33946 * ### Example
33947 *
33948 * ```typescript
33949 * class A {
33950 * constructor(b) {}
33951 * }
33952 *
33953 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
33954 * ```
33955 *
33956 * This error is also thrown when the class not marked with {@link Injectable} has parameter types.
33957 *
33958 * ```typescript
33959 * class B {}
33960 *
33961 * class A {
33962 * constructor(b:B) {} // no information about the parameter types of A is available at runtime.
33963 * }
33964 *
33965 * expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
33966 * ```
33967 *
33968 */
33969 function noAnnotationError(typeOrFunc, params) {
33970 const signature = [];
33971 for (let i = 0, ii = params.length; i < ii; i++) {
33972 const parameter = params[i];
33973 if (!parameter || parameter.length == 0) {
33974 signature.push('?');
33975 }
33976 else {
33977 signature.push(parameter.map(stringify$1).join(' '));
33978 }
33979 }
33980 return Error('Cannot resolve all parameters for \'' + stringify$1(typeOrFunc) + '\'(' +
33981 signature.join(', ') + '). ' +
33982 'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
33983 stringify$1(typeOrFunc) + '\' is decorated with Injectable.');
33984 }
33985 /**
33986 * Thrown when getting an object by index.
33987 *
33988 * @usageNotes
33989 * ### Example
33990 *
33991 * ```typescript
33992 * class A {}
33993 *
33994 * var injector = Injector.resolveAndCreate([A]);
33995 *
33996 * expect(() => injector.getAt(100)).toThrowError();
33997 * ```
33998 *
33999 */
34000 function outOfBoundsError(index) {
34001 return Error(`Index ${index} is out-of-bounds.`);
34002 }
34003 // TODO: add a working example after alpha38 is released
34004 /**
34005 * Thrown when a multi provider and a regular provider are bound to the same token.
34006 *
34007 * @usageNotes
34008 * ### Example
34009 *
34010 * ```typescript
34011 * expect(() => Injector.resolveAndCreate([
34012 * { provide: "Strings", useValue: "string1", multi: true},
34013 * { provide: "Strings", useValue: "string2", multi: false}
34014 * ])).toThrowError();
34015 * ```
34016 */
34017 function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) {
34018 return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
34019 }
34020
34021 /**
34022 * @license
34023 * Copyright Google LLC All Rights Reserved.
34024 *
34025 * Use of this source code is governed by an MIT-style license that can be
34026 * found in the LICENSE file at https://angular.io/license
34027 */
34028 /**
34029 * A unique object used for retrieving items from the {@link ReflectiveInjector}.
34030 *
34031 * Keys have:
34032 * - a system-wide unique `id`.
34033 * - a `token`.
34034 *
34035 * `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
34036 * the
34037 * injector to store created objects in a more efficient way.
34038 *
34039 * `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
34040 * resolving
34041 * providers.
34042 *
34043 * @deprecated No replacement
34044 * @publicApi
34045 */
34046 class ReflectiveKey {
34047 /**
34048 * Private
34049 */
34050 constructor(token, id) {
34051 this.token = token;
34052 this.id = id;
34053 if (!token) {
34054 throw new Error('Token must be defined!');
34055 }
34056 this.displayName = stringify$1(this.token);
34057 }
34058 /**
34059 * Retrieves a `Key` for a token.
34060 */
34061 static get(token) {
34062 return _globalKeyRegistry.get(resolveForwardRef$1(token));
34063 }
34064 /**
34065 * @returns the number of keys registered in the system.
34066 */
34067 static get numberOfKeys() {
34068 return _globalKeyRegistry.numberOfKeys;
34069 }
34070 }
34071 class KeyRegistry {
34072 constructor() {
34073 this._allKeys = new Map();
34074 }
34075 get(token) {
34076 if (token instanceof ReflectiveKey)
34077 return token;
34078 if (this._allKeys.has(token)) {
34079 return this._allKeys.get(token);
34080 }
34081 const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
34082 this._allKeys.set(token, newKey);
34083 return newKey;
34084 }
34085 get numberOfKeys() {
34086 return this._allKeys.size;
34087 }
34088 }
34089 const _globalKeyRegistry = new KeyRegistry();
34090
34091 /**
34092 * @license
34093 * Copyright Google LLC All Rights Reserved.
34094 *
34095 * Use of this source code is governed by an MIT-style license that can be
34096 * found in the LICENSE file at https://angular.io/license
34097 */
34098 /**
34099 * Provides access to reflection data about symbols. Used internally by Angular
34100 * to power dependency injection and compilation.
34101 */
34102 class Reflector {
34103 constructor(reflectionCapabilities) {
34104 this.reflectionCapabilities = reflectionCapabilities;
34105 }
34106 updateCapabilities(caps) {
34107 this.reflectionCapabilities = caps;
34108 }
34109 factory(type) {
34110 return this.reflectionCapabilities.factory(type);
34111 }
34112 parameters(typeOrFunc) {
34113 return this.reflectionCapabilities.parameters(typeOrFunc);
34114 }
34115 annotations(typeOrFunc) {
34116 return this.reflectionCapabilities.annotations(typeOrFunc);
34117 }
34118 propMetadata(typeOrFunc) {
34119 return this.reflectionCapabilities.propMetadata(typeOrFunc);
34120 }
34121 hasLifecycleHook(type, lcProperty) {
34122 return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
34123 }
34124 getter(name) {
34125 return this.reflectionCapabilities.getter(name);
34126 }
34127 setter(name) {
34128 return this.reflectionCapabilities.setter(name);
34129 }
34130 method(name) {
34131 return this.reflectionCapabilities.method(name);
34132 }
34133 importUri(type) {
34134 return this.reflectionCapabilities.importUri(type);
34135 }
34136 resourceUri(type) {
34137 return this.reflectionCapabilities.resourceUri(type);
34138 }
34139 resolveIdentifier(name, moduleUrl, members, runtime) {
34140 return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime);
34141 }
34142 resolveEnum(identifier, name) {
34143 return this.reflectionCapabilities.resolveEnum(identifier, name);
34144 }
34145 }
34146
34147 /**
34148 * @license
34149 * Copyright Google LLC All Rights Reserved.
34150 *
34151 * Use of this source code is governed by an MIT-style license that can be
34152 * found in the LICENSE file at https://angular.io/license
34153 */
34154 /**
34155 * The {@link Reflector} used internally in Angular to access metadata
34156 * about symbols.
34157 */
34158 const reflector = new Reflector(new ReflectionCapabilities());
34159
34160 /**
34161 * @license
34162 * Copyright Google LLC All Rights Reserved.
34163 *
34164 * Use of this source code is governed by an MIT-style license that can be
34165 * found in the LICENSE file at https://angular.io/license
34166 */
34167 /**
34168 * `Dependency` is used by the framework to extend DI.
34169 * This is internal to Angular and should not be used directly.
34170 */
34171 class ReflectiveDependency {
34172 constructor(key, optional, visibility) {
34173 this.key = key;
34174 this.optional = optional;
34175 this.visibility = visibility;
34176 }
34177 static fromKey(key) {
34178 return new ReflectiveDependency(key, false, null);
34179 }
34180 }
34181 const _EMPTY_LIST = [];
34182 class ResolvedReflectiveProvider_ {
34183 constructor(key, resolvedFactories, multiProvider) {
34184 this.key = key;
34185 this.resolvedFactories = resolvedFactories;
34186 this.multiProvider = multiProvider;
34187 this.resolvedFactory = this.resolvedFactories[0];
34188 }
34189 }
34190 /**
34191 * An internal resolved representation of a factory function created by resolving `Provider`.
34192 * @publicApi
34193 */
34194 class ResolvedReflectiveFactory {
34195 constructor(
34196 /**
34197 * Factory function which can return an instance of an object represented by a key.
34198 */
34199 factory,
34200 /**
34201 * Arguments (dependencies) to the `factory` function.
34202 */
34203 dependencies) {
34204 this.factory = factory;
34205 this.dependencies = dependencies;
34206 }
34207 }
34208 /**
34209 * Resolve a single provider.
34210 */
34211 function resolveReflectiveFactory(provider) {
34212 let factoryFn;
34213 let resolvedDeps;
34214 if (provider.useClass) {
34215 const useClass = resolveForwardRef$1(provider.useClass);
34216 factoryFn = reflector.factory(useClass);
34217 resolvedDeps = _dependenciesFor(useClass);
34218 }
34219 else if (provider.useExisting) {
34220 factoryFn = (aliasInstance) => aliasInstance;
34221 resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
34222 }
34223 else if (provider.useFactory) {
34224 factoryFn = provider.useFactory;
34225 resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
34226 }
34227 else {
34228 factoryFn = () => provider.useValue;
34229 resolvedDeps = _EMPTY_LIST;
34230 }
34231 return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
34232 }
34233 /**
34234 * Converts the `Provider` into `ResolvedProvider`.
34235 *
34236 * `Injector` internally only uses `ResolvedProvider`, `Provider` contains convenience provider
34237 * syntax.
34238 */
34239 function resolveReflectiveProvider(provider) {
34240 return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false);
34241 }
34242 /**
34243 * Resolve a list of Providers.
34244 */
34245 function resolveReflectiveProviders(providers) {
34246 const normalized = _normalizeProviders(providers, []);
34247 const resolved = normalized.map(resolveReflectiveProvider);
34248 const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
34249 return Array.from(resolvedProviderMap.values());
34250 }
34251 /**
34252 * Merges a list of ResolvedProviders into a list where each key is contained exactly once and
34253 * multi providers have been merged.
34254 */
34255 function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) {
34256 for (let i = 0; i < providers.length; i++) {
34257 const provider = providers[i];
34258 const existing = normalizedProvidersMap.get(provider.key.id);
34259 if (existing) {
34260 if (provider.multiProvider !== existing.multiProvider) {
34261 throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
34262 }
34263 if (provider.multiProvider) {
34264 for (let j = 0; j < provider.resolvedFactories.length; j++) {
34265 existing.resolvedFactories.push(provider.resolvedFactories[j]);
34266 }
34267 }
34268 else {
34269 normalizedProvidersMap.set(provider.key.id, provider);
34270 }
34271 }
34272 else {
34273 let resolvedProvider;
34274 if (provider.multiProvider) {
34275 resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider);
34276 }
34277 else {
34278 resolvedProvider = provider;
34279 }
34280 normalizedProvidersMap.set(provider.key.id, resolvedProvider);
34281 }
34282 }
34283 return normalizedProvidersMap;
34284 }
34285 function _normalizeProviders(providers, res) {
34286 providers.forEach(b => {
34287 if (b instanceof Type$2) {
34288 res.push({ provide: b, useClass: b });
34289 }
34290 else if (b && typeof b == 'object' && b.provide !== undefined) {
34291 res.push(b);
34292 }
34293 else if (Array.isArray(b)) {
34294 _normalizeProviders(b, res);
34295 }
34296 else {
34297 throw invalidProviderError(b);
34298 }
34299 });
34300 return res;
34301 }
34302 function constructDependencies(typeOrFunc, dependencies) {
34303 if (!dependencies) {
34304 return _dependenciesFor(typeOrFunc);
34305 }
34306 else {
34307 const params = dependencies.map(t => [t]);
34308 return dependencies.map(t => _extractToken(typeOrFunc, t, params));
34309 }
34310 }
34311 function _dependenciesFor(typeOrFunc) {
34312 const params = reflector.parameters(typeOrFunc);
34313 if (!params)
34314 return [];
34315 if (params.some(p => p == null)) {
34316 throw noAnnotationError(typeOrFunc, params);
34317 }
34318 return params.map(p => _extractToken(typeOrFunc, p, params));
34319 }
34320 function _extractToken(typeOrFunc, metadata, params) {
34321 let token = null;
34322 let optional = false;
34323 if (!Array.isArray(metadata)) {
34324 if (metadata instanceof Inject) {
34325 return _createDependency(metadata.token, optional, null);
34326 }
34327 else {
34328 return _createDependency(metadata, optional, null);
34329 }
34330 }
34331 let visibility = null;
34332 for (let i = 0; i < metadata.length; ++i) {
34333 const paramMetadata = metadata[i];
34334 if (paramMetadata instanceof Type$2) {
34335 token = paramMetadata;
34336 }
34337 else if (paramMetadata instanceof Inject) {
34338 token = paramMetadata.token;
34339 }
34340 else if (paramMetadata instanceof Optional) {
34341 optional = true;
34342 }
34343 else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
34344 visibility = paramMetadata;
34345 }
34346 else if (paramMetadata instanceof InjectionToken) {
34347 token = paramMetadata;
34348 }
34349 }
34350 token = resolveForwardRef$1(token);
34351 if (token != null) {
34352 return _createDependency(token, optional, visibility);
34353 }
34354 else {
34355 throw noAnnotationError(typeOrFunc, params);
34356 }
34357 }
34358 function _createDependency(token, optional, visibility) {
34359 return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
34360 }
34361
34362 /**
34363 * @license
34364 * Copyright Google LLC All Rights Reserved.
34365 *
34366 * Use of this source code is governed by an MIT-style license that can be
34367 * found in the LICENSE file at https://angular.io/license
34368 */
34369 // Threshold for the dynamic version
34370 const UNDEFINED = {};
34371 /**
34372 * A ReflectiveDependency injection container used for instantiating objects and resolving
34373 * dependencies.
34374 *
34375 * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
34376 * constructor dependencies.
34377 *
34378 * In typical use, application code asks for the dependencies in the constructor and they are
34379 * resolved by the `Injector`.
34380 *
34381 * @usageNotes
34382 * ### Example
34383 *
34384 * The following example creates an `Injector` configured to create `Engine` and `Car`.
34385 *
34386 * ```typescript
34387 * @Injectable()
34388 * class Engine {
34389 * }
34390 *
34391 * @Injectable()
34392 * class Car {
34393 * constructor(public engine:Engine) {}
34394 * }
34395 *
34396 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
34397 * var car = injector.get(Car);
34398 * expect(car instanceof Car).toBe(true);
34399 * expect(car.engine instanceof Engine).toBe(true);
34400 * ```
34401 *
34402 * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
34403 * resolve all of the object's dependencies automatically.
34404 *
34405 * @deprecated from v5 - slow and brings in a lot of code, Use `Injector.create` instead.
34406 * @publicApi
34407 */
34408 class ReflectiveInjector {
34409 /**
34410 * Turns an array of provider definitions into an array of resolved providers.
34411 *
34412 * A resolution is a process of flattening multiple nested arrays and converting individual
34413 * providers into an array of `ResolvedReflectiveProvider`s.
34414 *
34415 * @usageNotes
34416 * ### Example
34417 *
34418 * ```typescript
34419 * @Injectable()
34420 * class Engine {
34421 * }
34422 *
34423 * @Injectable()
34424 * class Car {
34425 * constructor(public engine:Engine) {}
34426 * }
34427 *
34428 * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
34429 *
34430 * expect(providers.length).toEqual(2);
34431 *
34432 * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
34433 * expect(providers[0].key.displayName).toBe("Car");
34434 * expect(providers[0].dependencies.length).toEqual(1);
34435 * expect(providers[0].factory).toBeDefined();
34436 *
34437 * expect(providers[1].key.displayName).toBe("Engine");
34438 * });
34439 * ```
34440 *
34441 */
34442 static resolve(providers) {
34443 return resolveReflectiveProviders(providers);
34444 }
34445 /**
34446 * Resolves an array of providers and creates an injector from those providers.
34447 *
34448 * The passed-in providers can be an array of `Type`, `Provider`,
34449 * or a recursive array of more providers.
34450 *
34451 * @usageNotes
34452 * ### Example
34453 *
34454 * ```typescript
34455 * @Injectable()
34456 * class Engine {
34457 * }
34458 *
34459 * @Injectable()
34460 * class Car {
34461 * constructor(public engine:Engine) {}
34462 * }
34463 *
34464 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
34465 * expect(injector.get(Car) instanceof Car).toBe(true);
34466 * ```
34467 */
34468 static resolveAndCreate(providers, parent) {
34469 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
34470 return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
34471 }
34472 /**
34473 * Creates an injector from previously resolved providers.
34474 *
34475 * This API is the recommended way to construct injectors in performance-sensitive parts.
34476 *
34477 * @usageNotes
34478 * ### Example
34479 *
34480 * ```typescript
34481 * @Injectable()
34482 * class Engine {
34483 * }
34484 *
34485 * @Injectable()
34486 * class Car {
34487 * constructor(public engine:Engine) {}
34488 * }
34489 *
34490 * var providers = ReflectiveInjector.resolve([Car, Engine]);
34491 * var injector = ReflectiveInjector.fromResolvedProviders(providers);
34492 * expect(injector.get(Car) instanceof Car).toBe(true);
34493 * ```
34494 */
34495 static fromResolvedProviders(providers, parent) {
34496 return new ReflectiveInjector_(providers, parent);
34497 }
34498 }
34499 class ReflectiveInjector_ {
34500 /**
34501 * Private
34502 */
34503 constructor(_providers, _parent) {
34504 /** @internal */
34505 this._constructionCounter = 0;
34506 this._providers = _providers;
34507 this.parent = _parent || null;
34508 const len = _providers.length;
34509 this.keyIds = [];
34510 this.objs = [];
34511 for (let i = 0; i < len; i++) {
34512 this.keyIds[i] = _providers[i].key.id;
34513 this.objs[i] = UNDEFINED;
34514 }
34515 }
34516 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
34517 return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
34518 }
34519 resolveAndCreateChild(providers) {
34520 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
34521 return this.createChildFromResolved(ResolvedReflectiveProviders);
34522 }
34523 createChildFromResolved(providers) {
34524 const inj = new ReflectiveInjector_(providers);
34525 inj.parent = this;
34526 return inj;
34527 }
34528 resolveAndInstantiate(provider) {
34529 return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
34530 }
34531 instantiateResolved(provider) {
34532 return this._instantiateProvider(provider);
34533 }
34534 getProviderAtIndex(index) {
34535 if (index < 0 || index >= this._providers.length) {
34536 throw outOfBoundsError(index);
34537 }
34538 return this._providers[index];
34539 }
34540 /** @internal */
34541 _new(provider) {
34542 if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
34543 throw cyclicDependencyError(this, provider.key);
34544 }
34545 return this._instantiateProvider(provider);
34546 }
34547 _getMaxNumberOfObjects() {
34548 return this.objs.length;
34549 }
34550 _instantiateProvider(provider) {
34551 if (provider.multiProvider) {
34552 const res = [];
34553 for (let i = 0; i < provider.resolvedFactories.length; ++i) {
34554 res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
34555 }
34556 return res;
34557 }
34558 else {
34559 return this._instantiate(provider, provider.resolvedFactories[0]);
34560 }
34561 }
34562 _instantiate(provider, ResolvedReflectiveFactory) {
34563 const factory = ResolvedReflectiveFactory.factory;
34564 let deps;
34565 try {
34566 deps =
34567 ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
34568 }
34569 catch (e) {
34570 if (e.addKey) {
34571 e.addKey(this, provider.key);
34572 }
34573 throw e;
34574 }
34575 let obj;
34576 try {
34577 obj = factory(...deps);
34578 }
34579 catch (e) {
34580 throw instantiationError(this, e, e.stack, provider.key);
34581 }
34582 return obj;
34583 }
34584 _getByReflectiveDependency(dep) {
34585 return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
34586 }
34587 _getByKey(key, visibility, notFoundValue) {
34588 if (key === ReflectiveInjector_.INJECTOR_KEY) {
34589 return this;
34590 }
34591 if (visibility instanceof Self) {
34592 return this._getByKeySelf(key, notFoundValue);
34593 }
34594 else {
34595 return this._getByKeyDefault(key, notFoundValue, visibility);
34596 }
34597 }
34598 _getObjByKeyId(keyId) {
34599 for (let i = 0; i < this.keyIds.length; i++) {
34600 if (this.keyIds[i] === keyId) {
34601 if (this.objs[i] === UNDEFINED) {
34602 this.objs[i] = this._new(this._providers[i]);
34603 }
34604 return this.objs[i];
34605 }
34606 }
34607 return UNDEFINED;
34608 }
34609 /** @internal */
34610 _throwOrNull(key, notFoundValue) {
34611 if (notFoundValue !== THROW_IF_NOT_FOUND) {
34612 return notFoundValue;
34613 }
34614 else {
34615 throw noProviderError(this, key);
34616 }
34617 }
34618 /** @internal */
34619 _getByKeySelf(key, notFoundValue) {
34620 const obj = this._getObjByKeyId(key.id);
34621 return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
34622 }
34623 /** @internal */
34624 _getByKeyDefault(key, notFoundValue, visibility) {
34625 let inj;
34626 if (visibility instanceof SkipSelf) {
34627 inj = this.parent;
34628 }
34629 else {
34630 inj = this;
34631 }
34632 while (inj instanceof ReflectiveInjector_) {
34633 const inj_ = inj;
34634 const obj = inj_._getObjByKeyId(key.id);
34635 if (obj !== UNDEFINED)
34636 return obj;
34637 inj = inj_.parent;
34638 }
34639 if (inj !== null) {
34640 return inj.get(key.token, notFoundValue);
34641 }
34642 else {
34643 return this._throwOrNull(key, notFoundValue);
34644 }
34645 }
34646 get displayName() {
34647 const providers = _mapProviders(this, (b) => ' "' + b.key.displayName + '" ')
34648 .join(', ');
34649 return `ReflectiveInjector(providers: [${providers}])`;
34650 }
34651 toString() {
34652 return this.displayName;
34653 }
34654 }
34655 ReflectiveInjector_.INJECTOR_KEY = ReflectiveKey.get(Injector);
34656 function _mapProviders(injector, fn) {
34657 const res = [];
34658 for (let i = 0; i < injector._providers.length; ++i) {
34659 res[i] = fn(injector.getProviderAtIndex(i));
34660 }
34661 return res;
34662 }
34663
34664 /**
34665 * @license
34666 * Copyright Google LLC All Rights Reserved.
34667 *
34668 * Use of this source code is governed by an MIT-style license that can be
34669 * found in the LICENSE file at https://angular.io/license
34670 */
34671 /**
34672 * Determine if the argument is shaped like a Promise
34673 */
34674 function isPromise$1(obj) {
34675 // allow any Promise/A+ compliant thenable.
34676 // It's up to the caller to ensure that obj.then conforms to the spec
34677 return !!obj && typeof obj.then === 'function';
34678 }
34679
34680 /**
34681 * @license
34682 * Copyright Google LLC All Rights Reserved.
34683 *
34684 * Use of this source code is governed by an MIT-style license that can be
34685 * found in the LICENSE file at https://angular.io/license
34686 */
34687 /**
34688 * This file contains reuseable "empty" symbols that can be used as default return values
34689 * in different parts of the rendering code. Because the same symbols are returned, this
34690 * allows for identity checks against these values to be consistently used by the framework
34691 * code.
34692 */
34693 const EMPTY_OBJ$1 = {};
34694 const EMPTY_ARRAY$2 = [];
34695 // freezing the values prevents any code from accidentally inserting new values in
34696 if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
34697 // These property accesses can be ignored because ngDevMode will be set to false
34698 // when optimizing code and the whole if statement will be dropped.
34699 // tslint:disable-next-line:no-toplevel-property-access
34700 Object.freeze(EMPTY_OBJ$1);
34701 // tslint:disable-next-line:no-toplevel-property-access
34702 Object.freeze(EMPTY_ARRAY$2);
34703 }
34704
34705 /**
34706 * @license
34707 * Copyright Google LLC All Rights Reserved.
34708 *
34709 * Use of this source code is governed by an MIT-style license that can be
34710 * found in the LICENSE file at https://angular.io/license
34711 */
34712 /**
34713 * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
34714 */
34715 if (typeof ngI18nClosureMode === 'undefined') {
34716 // These property accesses can be ignored because ngI18nClosureMode will be set to false
34717 // when optimizing code and the whole if statement will be dropped.
34718 // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
34719 // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
34720 (function () {
34721 // tslint:disable-next-line:no-toplevel-property-access
34722 _global$1['ngI18nClosureMode'] =
34723 // TODO(FW-1250): validate that this actually, you know, works.
34724 // tslint:disable-next-line:no-toplevel-property-access
34725 typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
34726 })();
34727 }
34728
34729 /**
34730 * @license
34731 * Copyright Google LLC All Rights Reserved.
34732 *
34733 * Use of this source code is governed by an MIT-style license that can be
34734 * found in the LICENSE file at https://angular.io/license
34735 */
34736 /**
34737 * Index of each type of locale data from the locale data array
34738 */
34739 var LocaleDataIndex;
34740 (function (LocaleDataIndex) {
34741 LocaleDataIndex[LocaleDataIndex["LocaleId"] = 0] = "LocaleId";
34742 LocaleDataIndex[LocaleDataIndex["DayPeriodsFormat"] = 1] = "DayPeriodsFormat";
34743 LocaleDataIndex[LocaleDataIndex["DayPeriodsStandalone"] = 2] = "DayPeriodsStandalone";
34744 LocaleDataIndex[LocaleDataIndex["DaysFormat"] = 3] = "DaysFormat";
34745 LocaleDataIndex[LocaleDataIndex["DaysStandalone"] = 4] = "DaysStandalone";
34746 LocaleDataIndex[LocaleDataIndex["MonthsFormat"] = 5] = "MonthsFormat";
34747 LocaleDataIndex[LocaleDataIndex["MonthsStandalone"] = 6] = "MonthsStandalone";
34748 LocaleDataIndex[LocaleDataIndex["Eras"] = 7] = "Eras";
34749 LocaleDataIndex[LocaleDataIndex["FirstDayOfWeek"] = 8] = "FirstDayOfWeek";
34750 LocaleDataIndex[LocaleDataIndex["WeekendRange"] = 9] = "WeekendRange";
34751 LocaleDataIndex[LocaleDataIndex["DateFormat"] = 10] = "DateFormat";
34752 LocaleDataIndex[LocaleDataIndex["TimeFormat"] = 11] = "TimeFormat";
34753 LocaleDataIndex[LocaleDataIndex["DateTimeFormat"] = 12] = "DateTimeFormat";
34754 LocaleDataIndex[LocaleDataIndex["NumberSymbols"] = 13] = "NumberSymbols";
34755 LocaleDataIndex[LocaleDataIndex["NumberFormats"] = 14] = "NumberFormats";
34756 LocaleDataIndex[LocaleDataIndex["CurrencyCode"] = 15] = "CurrencyCode";
34757 LocaleDataIndex[LocaleDataIndex["CurrencySymbol"] = 16] = "CurrencySymbol";
34758 LocaleDataIndex[LocaleDataIndex["CurrencyName"] = 17] = "CurrencyName";
34759 LocaleDataIndex[LocaleDataIndex["Currencies"] = 18] = "Currencies";
34760 LocaleDataIndex[LocaleDataIndex["Directionality"] = 19] = "Directionality";
34761 LocaleDataIndex[LocaleDataIndex["PluralCase"] = 20] = "PluralCase";
34762 LocaleDataIndex[LocaleDataIndex["ExtraData"] = 21] = "ExtraData";
34763 })(LocaleDataIndex || (LocaleDataIndex = {}));
34764
34765 /**
34766 * @license
34767 * Copyright Google LLC All Rights Reserved.
34768 *
34769 * Use of this source code is governed by an MIT-style license that can be
34770 * found in the LICENSE file at https://angular.io/license
34771 */
34772 /**
34773 * The locale id that the application is using by default (for translations and ICU expressions).
34774 */
34775 const DEFAULT_LOCALE_ID = 'en-US';
34776 /**
34777 * USD currency code that the application uses by default for CurrencyPipe when no
34778 * DEFAULT_CURRENCY_CODE is provided.
34779 */
34780 const USD_CURRENCY_CODE = 'USD';
34781
34782 /**
34783 * @license
34784 * Copyright Google LLC All Rights Reserved.
34785 *
34786 * Use of this source code is governed by an MIT-style license that can be
34787 * found in the LICENSE file at https://angular.io/license
34788 */
34789 /**
34790 * See `I18nCreateOpCodes`
34791 */
34792 var I18nCreateOpCode;
34793 (function (I18nCreateOpCode) {
34794 /**
34795 * Number of bits to shift index so that it can be combined with the `APPEND_EAGERLY` and
34796 * `COMMENT`.
34797 */
34798 I18nCreateOpCode[I18nCreateOpCode["SHIFT"] = 2] = "SHIFT";
34799 /**
34800 * Should the node be appended to parent imedditatly after creation.
34801 */
34802 I18nCreateOpCode[I18nCreateOpCode["APPEND_EAGERLY"] = 1] = "APPEND_EAGERLY";
34803 /**
34804 * If set the node should be comment (rather than a text) node.
34805 */
34806 I18nCreateOpCode[I18nCreateOpCode["COMMENT"] = 2] = "COMMENT";
34807 })(I18nCreateOpCode || (I18nCreateOpCode = {}));
34808
34809 /**
34810 * @license
34811 * Copyright Google LLC All Rights Reserved.
34812 *
34813 * Use of this source code is governed by an MIT-style license that can be
34814 * found in the LICENSE file at https://angular.io/license
34815 */
34816 /**
34817 * The locale id that the application is currently using (for translations and ICU expressions).
34818 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
34819 * but is now defined as a global value.
34820 */
34821 let LOCALE_ID = DEFAULT_LOCALE_ID;
34822 /**
34823 * Sets the locale id that will be used for translations and ICU expressions.
34824 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
34825 * but is now defined as a global value.
34826 *
34827 * @param localeId
34828 */
34829 function setLocaleId(localeId) {
34830 assertDefined(localeId, `Expected localeId to be defined`);
34831 if (typeof localeId === 'string') {
34832 LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
34833 }
34834 }
34835
34836 /**
34837 * @license
34838 * Copyright Google LLC All Rights Reserved.
34839 *
34840 * Use of this source code is governed by an MIT-style license that can be
34841 * found in the LICENSE file at https://angular.io/license
34842 */
34843 /**
34844 * Represents a component created by a `ComponentFactory`.
34845 * Provides access to the component instance and related objects,
34846 * and provides the means of destroying the instance.
34847 *
34848 * @publicApi
34849 */
34850 class ComponentRef {
34851 }
34852 /**
34853 * Base class for a factory that can create a component dynamically.
34854 * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
34855 * Use the resulting `ComponentFactory.create()` method to create a component of that type.
34856 *
34857 * @see [Dynamic Components](guide/dynamic-component-loader)
34858 *
34859 * @publicApi
34860 */
34861 class ComponentFactory {
34862 }
34863
34864 /**
34865 * @license
34866 * Copyright Google LLC All Rights Reserved.
34867 *
34868 * Use of this source code is governed by an MIT-style license that can be
34869 * found in the LICENSE file at https://angular.io/license
34870 */
34871 function noComponentFactoryError(component) {
34872 const error = Error(`No component factory found for ${stringify$1(component)}. Did you add it to @NgModule.entryComponents?`);
34873 error[ERROR_COMPONENT] = component;
34874 return error;
34875 }
34876 const ERROR_COMPONENT = 'ngComponent';
34877 class _NullComponentFactoryResolver {
34878 resolveComponentFactory(component) {
34879 throw noComponentFactoryError(component);
34880 }
34881 }
34882 /**
34883 * A simple registry that maps `Components` to generated `ComponentFactory` classes
34884 * that can be used to create instances of components.
34885 * Use to obtain the factory for a given component type,
34886 * then use the factory's `create()` method to create a component of that type.
34887 *
34888 * @see [Dynamic Components](guide/dynamic-component-loader)
34889 * @publicApi
34890 */
34891 class ComponentFactoryResolver {
34892 }
34893 ComponentFactoryResolver.NULL = new _NullComponentFactoryResolver();
34894 class ComponentFactoryBoundToModule extends ComponentFactory {
34895 constructor(factory, ngModule) {
34896 super();
34897 this.factory = factory;
34898 this.ngModule = ngModule;
34899 this.selector = factory.selector;
34900 this.componentType = factory.componentType;
34901 this.ngContentSelectors = factory.ngContentSelectors;
34902 this.inputs = factory.inputs;
34903 this.outputs = factory.outputs;
34904 }
34905 create(injector, projectableNodes, rootSelectorOrNode, ngModule) {
34906 return this.factory.create(injector, projectableNodes, rootSelectorOrNode, ngModule || this.ngModule);
34907 }
34908 }
34909
34910 /**
34911 * @license
34912 * Copyright Google LLC All Rights Reserved.
34913 *
34914 * Use of this source code is governed by an MIT-style license that can be
34915 * found in the LICENSE file at https://angular.io/license
34916 */
34917 function noop(...args) {
34918 // Do nothing.
34919 }
34920
34921 /**
34922 * @license
34923 * Copyright Google LLC All Rights Reserved.
34924 *
34925 * Use of this source code is governed by an MIT-style license that can be
34926 * found in the LICENSE file at https://angular.io/license
34927 */
34928 /**
34929 * Creates an ElementRef given a node.
34930 *
34931 * @param tNode The node for which you'd like an ElementRef
34932 * @param lView The view to which the node belongs
34933 * @returns The ElementRef instance to use
34934 */
34935 function createElementRef(tNode, lView) {
34936 return new ElementRef(getNativeByTNode(tNode, lView));
34937 }
34938 const SWITCH_ELEMENT_REF_FACTORY__PRE_R3__ = noop;
34939 const SWITCH_ELEMENT_REF_FACTORY = SWITCH_ELEMENT_REF_FACTORY__PRE_R3__;
34940 /**
34941 * A wrapper around a native element inside of a View.
34942 *
34943 * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
34944 * element.
34945 *
34946 * @security Permitting direct access to the DOM can make your application more vulnerable to
34947 * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
34948 * [Security Guide](https://g.co/ng/security).
34949 *
34950 * @publicApi
34951 */
34952 // Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
34953 // i.e. users have to ask for what they need. With that, we can build better analysis tools
34954 // and could do better codegen in the future.
34955 class ElementRef {
34956 constructor(nativeElement) {
34957 this.nativeElement = nativeElement;
34958 }
34959 }
34960 /**
34961 * @internal
34962 * @nocollapse
34963 */
34964 ElementRef.__NG_ELEMENT_ID__ = SWITCH_ELEMENT_REF_FACTORY;
34965
34966 /**
34967 * @license
34968 * Copyright Google LLC All Rights Reserved.
34969 *
34970 * Use of this source code is governed by an MIT-style license that can be
34971 * found in the LICENSE file at https://angular.io/license
34972 */
34973 const Renderer2Interceptor = new InjectionToken('Renderer2Interceptor');
34974 /**
34975 * Creates and initializes a custom renderer that implements the `Renderer2` base class.
34976 *
34977 * @publicApi
34978 */
34979 class RendererFactory2 {
34980 }
34981 /**
34982 * Extend this base class to implement custom rendering. By default, Angular
34983 * renders a template into DOM. You can use custom rendering to intercept
34984 * rendering calls, or to render to something other than DOM.
34985 *
34986 * Create your custom renderer using `RendererFactory2`.
34987 *
34988 * Use a custom renderer to bypass Angular's templating and
34989 * make custom UI changes that can't be expressed declaratively.
34990 * For example if you need to set a property or an attribute whose name is
34991 * not statically known, use the `setProperty()` or
34992 * `setAttribute()` method.
34993 *
34994 * @publicApi
34995 */
34996 class Renderer2 {
34997 }
34998 /**
34999 * @internal
35000 * @nocollapse
35001 */
35002 Renderer2.__NG_ELEMENT_ID__ = () => SWITCH_RENDERER2_FACTORY();
35003 const SWITCH_RENDERER2_FACTORY__PRE_R3__ = noop;
35004 const SWITCH_RENDERER2_FACTORY = SWITCH_RENDERER2_FACTORY__PRE_R3__;
35005
35006 /**
35007 * @license
35008 * Copyright Google LLC All Rights Reserved.
35009 *
35010 * Use of this source code is governed by an MIT-style license that can be
35011 * found in the LICENSE file at https://angular.io/license
35012 */
35013 /**
35014 * Sanitizer is used by the views to sanitize potentially dangerous values.
35015 *
35016 * @publicApi
35017 */
35018 class Sanitizer {
35019 }
35020 /** @nocollapse */
35021 Sanitizer.ɵprov = ɵɵdefineInjectable({
35022 token: Sanitizer,
35023 providedIn: 'root',
35024 factory: () => null,
35025 });
35026
35027 /**
35028 * @license
35029 * Copyright Google LLC All Rights Reserved.
35030 *
35031 * Use of this source code is governed by an MIT-style license that can be
35032 * found in the LICENSE file at https://angular.io/license
35033 */
35034 /**
35035 * @description Represents the version of Angular
35036 *
35037 * @publicApi
35038 */
35039 class Version$1 {
35040 constructor(full) {
35041 this.full = full;
35042 this.major = full.split('.')[0];
35043 this.minor = full.split('.')[1];
35044 this.patch = full.split('.').slice(2).join('.');
35045 }
35046 }
35047 /**
35048 * @publicApi
35049 */
35050 const VERSION$2 = new Version$1('11.2.0');
35051
35052 /**
35053 * @license
35054 * Copyright Google LLC All Rights Reserved.
35055 *
35056 * Use of this source code is governed by an MIT-style license that can be
35057 * found in the LICENSE file at https://angular.io/license
35058 */
35059 class DefaultIterableDifferFactory {
35060 constructor() { }
35061 supports(obj) {
35062 return isListLikeIterable(obj);
35063 }
35064 create(trackByFn) {
35065 return new DefaultIterableDiffer(trackByFn);
35066 }
35067 }
35068 const trackByIdentity = (index, item) => item;
35069 /**
35070 * @deprecated v4.0.0 - Should not be part of public API.
35071 * @publicApi
35072 */
35073 class DefaultIterableDiffer {
35074 constructor(trackByFn) {
35075 this.length = 0;
35076 // Keeps track of the used records at any point in time (during & across `_check()` calls)
35077 this._linkedRecords = null;
35078 // Keeps track of the removed records at any point in time during `_check()` calls.
35079 this._unlinkedRecords = null;
35080 this._previousItHead = null;
35081 this._itHead = null;
35082 this._itTail = null;
35083 this._additionsHead = null;
35084 this._additionsTail = null;
35085 this._movesHead = null;
35086 this._movesTail = null;
35087 this._removalsHead = null;
35088 this._removalsTail = null;
35089 // Keeps track of records where custom track by is the same, but item identity has changed
35090 this._identityChangesHead = null;
35091 this._identityChangesTail = null;
35092 this._trackByFn = trackByFn || trackByIdentity;
35093 }
35094 forEachItem(fn) {
35095 let record;
35096 for (record = this._itHead; record !== null; record = record._next) {
35097 fn(record);
35098 }
35099 }
35100 forEachOperation(fn) {
35101 let nextIt = this._itHead;
35102 let nextRemove = this._removalsHead;
35103 let addRemoveOffset = 0;
35104 let moveOffsets = null;
35105 while (nextIt || nextRemove) {
35106 // Figure out which is the next record to process
35107 // Order: remove, add, move
35108 const record = !nextRemove ||
35109 nextIt &&
35110 nextIt.currentIndex <
35111 getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
35112 nextIt :
35113 nextRemove;
35114 const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets);
35115 const currentIndex = record.currentIndex;
35116 // consume the item, and adjust the addRemoveOffset and update moveDistance if necessary
35117 if (record === nextRemove) {
35118 addRemoveOffset--;
35119 nextRemove = nextRemove._nextRemoved;
35120 }
35121 else {
35122 nextIt = nextIt._next;
35123 if (record.previousIndex == null) {
35124 addRemoveOffset++;
35125 }
35126 else {
35127 // INVARIANT: currentIndex < previousIndex
35128 if (!moveOffsets)
35129 moveOffsets = [];
35130 const localMovePreviousIndex = adjPreviousIndex - addRemoveOffset;
35131 const localCurrentIndex = currentIndex - addRemoveOffset;
35132 if (localMovePreviousIndex != localCurrentIndex) {
35133 for (let i = 0; i < localMovePreviousIndex; i++) {
35134 const offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0);
35135 const index = offset + i;
35136 if (localCurrentIndex <= index && index < localMovePreviousIndex) {
35137 moveOffsets[i] = offset + 1;
35138 }
35139 }
35140 const previousIndex = record.previousIndex;
35141 moveOffsets[previousIndex] = localCurrentIndex - localMovePreviousIndex;
35142 }
35143 }
35144 }
35145 if (adjPreviousIndex !== currentIndex) {
35146 fn(record, adjPreviousIndex, currentIndex);
35147 }
35148 }
35149 }
35150 forEachPreviousItem(fn) {
35151 let record;
35152 for (record = this._previousItHead; record !== null; record = record._nextPrevious) {
35153 fn(record);
35154 }
35155 }
35156 forEachAddedItem(fn) {
35157 let record;
35158 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
35159 fn(record);
35160 }
35161 }
35162 forEachMovedItem(fn) {
35163 let record;
35164 for (record = this._movesHead; record !== null; record = record._nextMoved) {
35165 fn(record);
35166 }
35167 }
35168 forEachRemovedItem(fn) {
35169 let record;
35170 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
35171 fn(record);
35172 }
35173 }
35174 forEachIdentityChange(fn) {
35175 let record;
35176 for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) {
35177 fn(record);
35178 }
35179 }
35180 diff(collection) {
35181 if (collection == null)
35182 collection = [];
35183 if (!isListLikeIterable(collection)) {
35184 throw new Error(`Error trying to diff '${stringify$1(collection)}'. Only arrays and iterables are allowed`);
35185 }
35186 if (this.check(collection)) {
35187 return this;
35188 }
35189 else {
35190 return null;
35191 }
35192 }
35193 onDestroy() { }
35194 check(collection) {
35195 this._reset();
35196 let record = this._itHead;
35197 let mayBeDirty = false;
35198 let index;
35199 let item;
35200 let itemTrackBy;
35201 if (Array.isArray(collection)) {
35202 this.length = collection.length;
35203 for (let index = 0; index < this.length; index++) {
35204 item = collection[index];
35205 itemTrackBy = this._trackByFn(index, item);
35206 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
35207 record = this._mismatch(record, item, itemTrackBy, index);
35208 mayBeDirty = true;
35209 }
35210 else {
35211 if (mayBeDirty) {
35212 // TODO(misko): can we limit this to duplicates only?
35213 record = this._verifyReinsertion(record, item, itemTrackBy, index);
35214 }
35215 if (!Object.is(record.item, item))
35216 this._addIdentityChange(record, item);
35217 }
35218 record = record._next;
35219 }
35220 }
35221 else {
35222 index = 0;
35223 iterateListLike(collection, (item) => {
35224 itemTrackBy = this._trackByFn(index, item);
35225 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
35226 record = this._mismatch(record, item, itemTrackBy, index);
35227 mayBeDirty = true;
35228 }
35229 else {
35230 if (mayBeDirty) {
35231 // TODO(misko): can we limit this to duplicates only?
35232 record = this._verifyReinsertion(record, item, itemTrackBy, index);
35233 }
35234 if (!Object.is(record.item, item))
35235 this._addIdentityChange(record, item);
35236 }
35237 record = record._next;
35238 index++;
35239 });
35240 this.length = index;
35241 }
35242 this._truncate(record);
35243 this.collection = collection;
35244 return this.isDirty;
35245 }
35246 /* CollectionChanges is considered dirty if it has any additions, moves, removals, or identity
35247 * changes.
35248 */
35249 get isDirty() {
35250 return this._additionsHead !== null || this._movesHead !== null ||
35251 this._removalsHead !== null || this._identityChangesHead !== null;
35252 }
35253 /**
35254 * Reset the state of the change objects to show no changes. This means set previousKey to
35255 * currentKey, and clear all of the queues (additions, moves, removals).
35256 * Set the previousIndexes of moved and added items to their currentIndexes
35257 * Reset the list of additions, moves and removals
35258 *
35259 * @internal
35260 */
35261 _reset() {
35262 if (this.isDirty) {
35263 let record;
35264 for (record = this._previousItHead = this._itHead; record !== null; record = record._next) {
35265 record._nextPrevious = record._next;
35266 }
35267 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
35268 record.previousIndex = record.currentIndex;
35269 }
35270 this._additionsHead = this._additionsTail = null;
35271 for (record = this._movesHead; record !== null; record = record._nextMoved) {
35272 record.previousIndex = record.currentIndex;
35273 }
35274 this._movesHead = this._movesTail = null;
35275 this._removalsHead = this._removalsTail = null;
35276 this._identityChangesHead = this._identityChangesTail = null;
35277 // TODO(vicb): when assert gets supported
35278 // assert(!this.isDirty);
35279 }
35280 }
35281 /**
35282 * This is the core function which handles differences between collections.
35283 *
35284 * - `record` is the record which we saw at this position last time. If null then it is a new
35285 * item.
35286 * - `item` is the current item in the collection
35287 * - `index` is the position of the item in the collection
35288 *
35289 * @internal
35290 */
35291 _mismatch(record, item, itemTrackBy, index) {
35292 // The previous record after which we will append the current one.
35293 let previousRecord;
35294 if (record === null) {
35295 previousRecord = this._itTail;
35296 }
35297 else {
35298 previousRecord = record._prev;
35299 // Remove the record from the collection since we know it does not match the item.
35300 this._remove(record);
35301 }
35302 // See if we have evicted the item, which used to be at some anterior position of _itHead list.
35303 record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
35304 if (record !== null) {
35305 // It is an item which we have evicted earlier: reinsert it back into the list.
35306 // But first we need to check if identity changed, so we can update in view if necessary.
35307 if (!Object.is(record.item, item))
35308 this._addIdentityChange(record, item);
35309 this._reinsertAfter(record, previousRecord, index);
35310 }
35311 else {
35312 // Attempt to see if the item is at some posterior position of _itHead list.
35313 record = this._linkedRecords === null ? null : this._linkedRecords.get(itemTrackBy, index);
35314 if (record !== null) {
35315 // We have the item in _itHead at/after `index` position. We need to move it forward in the
35316 // collection.
35317 // But first we need to check if identity changed, so we can update in view if necessary.
35318 if (!Object.is(record.item, item))
35319 this._addIdentityChange(record, item);
35320 this._moveAfter(record, previousRecord, index);
35321 }
35322 else {
35323 // It is a new item: add it.
35324 record =
35325 this._addAfter(new IterableChangeRecord_(item, itemTrackBy), previousRecord, index);
35326 }
35327 }
35328 return record;
35329 }
35330 /**
35331 * This check is only needed if an array contains duplicates. (Short circuit of nothing dirty)
35332 *
35333 * Use case: `[a, a]` => `[b, a, a]`
35334 *
35335 * If we did not have this check then the insertion of `b` would:
35336 * 1) evict first `a`
35337 * 2) insert `b` at `0` index.
35338 * 3) leave `a` at index `1` as is. <-- this is wrong!
35339 * 3) reinsert `a` at index 2. <-- this is wrong!
35340 *
35341 * The correct behavior is:
35342 * 1) evict first `a`
35343 * 2) insert `b` at `0` index.
35344 * 3) reinsert `a` at index 1.
35345 * 3) move `a` at from `1` to `2`.
35346 *
35347 *
35348 * Double check that we have not evicted a duplicate item. We need to check if the item type may
35349 * have already been removed:
35350 * The insertion of b will evict the first 'a'. If we don't reinsert it now it will be reinserted
35351 * at the end. Which will show up as the two 'a's switching position. This is incorrect, since a
35352 * better way to think of it is as insert of 'b' rather then switch 'a' with 'b' and then add 'a'
35353 * at the end.
35354 *
35355 * @internal
35356 */
35357 _verifyReinsertion(record, item, itemTrackBy, index) {
35358 let reinsertRecord = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
35359 if (reinsertRecord !== null) {
35360 record = this._reinsertAfter(reinsertRecord, record._prev, index);
35361 }
35362 else if (record.currentIndex != index) {
35363 record.currentIndex = index;
35364 this._addToMoves(record, index);
35365 }
35366 return record;
35367 }
35368 /**
35369 * Get rid of any excess {@link IterableChangeRecord_}s from the previous collection
35370 *
35371 * - `record` The first excess {@link IterableChangeRecord_}.
35372 *
35373 * @internal
35374 */
35375 _truncate(record) {
35376 // Anything after that needs to be removed;
35377 while (record !== null) {
35378 const nextRecord = record._next;
35379 this._addToRemovals(this._unlink(record));
35380 record = nextRecord;
35381 }
35382 if (this._unlinkedRecords !== null) {
35383 this._unlinkedRecords.clear();
35384 }
35385 if (this._additionsTail !== null) {
35386 this._additionsTail._nextAdded = null;
35387 }
35388 if (this._movesTail !== null) {
35389 this._movesTail._nextMoved = null;
35390 }
35391 if (this._itTail !== null) {
35392 this._itTail._next = null;
35393 }
35394 if (this._removalsTail !== null) {
35395 this._removalsTail._nextRemoved = null;
35396 }
35397 if (this._identityChangesTail !== null) {
35398 this._identityChangesTail._nextIdentityChange = null;
35399 }
35400 }
35401 /** @internal */
35402 _reinsertAfter(record, prevRecord, index) {
35403 if (this._unlinkedRecords !== null) {
35404 this._unlinkedRecords.remove(record);
35405 }
35406 const prev = record._prevRemoved;
35407 const next = record._nextRemoved;
35408 if (prev === null) {
35409 this._removalsHead = next;
35410 }
35411 else {
35412 prev._nextRemoved = next;
35413 }
35414 if (next === null) {
35415 this._removalsTail = prev;
35416 }
35417 else {
35418 next._prevRemoved = prev;
35419 }
35420 this._insertAfter(record, prevRecord, index);
35421 this._addToMoves(record, index);
35422 return record;
35423 }
35424 /** @internal */
35425 _moveAfter(record, prevRecord, index) {
35426 this._unlink(record);
35427 this._insertAfter(record, prevRecord, index);
35428 this._addToMoves(record, index);
35429 return record;
35430 }
35431 /** @internal */
35432 _addAfter(record, prevRecord, index) {
35433 this._insertAfter(record, prevRecord, index);
35434 if (this._additionsTail === null) {
35435 // TODO(vicb):
35436 // assert(this._additionsHead === null);
35437 this._additionsTail = this._additionsHead = record;
35438 }
35439 else {
35440 // TODO(vicb):
35441 // assert(_additionsTail._nextAdded === null);
35442 // assert(record._nextAdded === null);
35443 this._additionsTail = this._additionsTail._nextAdded = record;
35444 }
35445 return record;
35446 }
35447 /** @internal */
35448 _insertAfter(record, prevRecord, index) {
35449 // TODO(vicb):
35450 // assert(record != prevRecord);
35451 // assert(record._next === null);
35452 // assert(record._prev === null);
35453 const next = prevRecord === null ? this._itHead : prevRecord._next;
35454 // TODO(vicb):
35455 // assert(next != record);
35456 // assert(prevRecord != record);
35457 record._next = next;
35458 record._prev = prevRecord;
35459 if (next === null) {
35460 this._itTail = record;
35461 }
35462 else {
35463 next._prev = record;
35464 }
35465 if (prevRecord === null) {
35466 this._itHead = record;
35467 }
35468 else {
35469 prevRecord._next = record;
35470 }
35471 if (this._linkedRecords === null) {
35472 this._linkedRecords = new _DuplicateMap();
35473 }
35474 this._linkedRecords.put(record);
35475 record.currentIndex = index;
35476 return record;
35477 }
35478 /** @internal */
35479 _remove(record) {
35480 return this._addToRemovals(this._unlink(record));
35481 }
35482 /** @internal */
35483 _unlink(record) {
35484 if (this._linkedRecords !== null) {
35485 this._linkedRecords.remove(record);
35486 }
35487 const prev = record._prev;
35488 const next = record._next;
35489 // TODO(vicb):
35490 // assert((record._prev = null) === null);
35491 // assert((record._next = null) === null);
35492 if (prev === null) {
35493 this._itHead = next;
35494 }
35495 else {
35496 prev._next = next;
35497 }
35498 if (next === null) {
35499 this._itTail = prev;
35500 }
35501 else {
35502 next._prev = prev;
35503 }
35504 return record;
35505 }
35506 /** @internal */
35507 _addToMoves(record, toIndex) {
35508 // TODO(vicb):
35509 // assert(record._nextMoved === null);
35510 if (record.previousIndex === toIndex) {
35511 return record;
35512 }
35513 if (this._movesTail === null) {
35514 // TODO(vicb):
35515 // assert(_movesHead === null);
35516 this._movesTail = this._movesHead = record;
35517 }
35518 else {
35519 // TODO(vicb):
35520 // assert(_movesTail._nextMoved === null);
35521 this._movesTail = this._movesTail._nextMoved = record;
35522 }
35523 return record;
35524 }
35525 _addToRemovals(record) {
35526 if (this._unlinkedRecords === null) {
35527 this._unlinkedRecords = new _DuplicateMap();
35528 }
35529 this._unlinkedRecords.put(record);
35530 record.currentIndex = null;
35531 record._nextRemoved = null;
35532 if (this._removalsTail === null) {
35533 // TODO(vicb):
35534 // assert(_removalsHead === null);
35535 this._removalsTail = this._removalsHead = record;
35536 record._prevRemoved = null;
35537 }
35538 else {
35539 // TODO(vicb):
35540 // assert(_removalsTail._nextRemoved === null);
35541 // assert(record._nextRemoved === null);
35542 record._prevRemoved = this._removalsTail;
35543 this._removalsTail = this._removalsTail._nextRemoved = record;
35544 }
35545 return record;
35546 }
35547 /** @internal */
35548 _addIdentityChange(record, item) {
35549 record.item = item;
35550 if (this._identityChangesTail === null) {
35551 this._identityChangesTail = this._identityChangesHead = record;
35552 }
35553 else {
35554 this._identityChangesTail = this._identityChangesTail._nextIdentityChange = record;
35555 }
35556 return record;
35557 }
35558 }
35559 class IterableChangeRecord_ {
35560 constructor(item, trackById) {
35561 this.item = item;
35562 this.trackById = trackById;
35563 this.currentIndex = null;
35564 this.previousIndex = null;
35565 /** @internal */
35566 this._nextPrevious = null;
35567 /** @internal */
35568 this._prev = null;
35569 /** @internal */
35570 this._next = null;
35571 /** @internal */
35572 this._prevDup = null;
35573 /** @internal */
35574 this._nextDup = null;
35575 /** @internal */
35576 this._prevRemoved = null;
35577 /** @internal */
35578 this._nextRemoved = null;
35579 /** @internal */
35580 this._nextAdded = null;
35581 /** @internal */
35582 this._nextMoved = null;
35583 /** @internal */
35584 this._nextIdentityChange = null;
35585 }
35586 }
35587 // A linked list of IterableChangeRecords with the same IterableChangeRecord_.item
35588 class _DuplicateItemRecordList {
35589 constructor() {
35590 /** @internal */
35591 this._head = null;
35592 /** @internal */
35593 this._tail = null;
35594 }
35595 /**
35596 * Append the record to the list of duplicates.
35597 *
35598 * Note: by design all records in the list of duplicates hold the same value in record.item.
35599 */
35600 add(record) {
35601 if (this._head === null) {
35602 this._head = this._tail = record;
35603 record._nextDup = null;
35604 record._prevDup = null;
35605 }
35606 else {
35607 // TODO(vicb):
35608 // assert(record.item == _head.item ||
35609 // record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN);
35610 this._tail._nextDup = record;
35611 record._prevDup = this._tail;
35612 record._nextDup = null;
35613 this._tail = record;
35614 }
35615 }
35616 // Returns a IterableChangeRecord_ having IterableChangeRecord_.trackById == trackById and
35617 // IterableChangeRecord_.currentIndex >= atOrAfterIndex
35618 get(trackById, atOrAfterIndex) {
35619 let record;
35620 for (record = this._head; record !== null; record = record._nextDup) {
35621 if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex) &&
35622 Object.is(record.trackById, trackById)) {
35623 return record;
35624 }
35625 }
35626 return null;
35627 }
35628 /**
35629 * Remove one {@link IterableChangeRecord_} from the list of duplicates.
35630 *
35631 * Returns whether the list of duplicates is empty.
35632 */
35633 remove(record) {
35634 // TODO(vicb):
35635 // assert(() {
35636 // // verify that the record being removed is in the list.
35637 // for (IterableChangeRecord_ cursor = _head; cursor != null; cursor = cursor._nextDup) {
35638 // if (identical(cursor, record)) return true;
35639 // }
35640 // return false;
35641 //});
35642 const prev = record._prevDup;
35643 const next = record._nextDup;
35644 if (prev === null) {
35645 this._head = next;
35646 }
35647 else {
35648 prev._nextDup = next;
35649 }
35650 if (next === null) {
35651 this._tail = prev;
35652 }
35653 else {
35654 next._prevDup = prev;
35655 }
35656 return this._head === null;
35657 }
35658 }
35659 class _DuplicateMap {
35660 constructor() {
35661 this.map = new Map();
35662 }
35663 put(record) {
35664 const key = record.trackById;
35665 let duplicates = this.map.get(key);
35666 if (!duplicates) {
35667 duplicates = new _DuplicateItemRecordList();
35668 this.map.set(key, duplicates);
35669 }
35670 duplicates.add(record);
35671 }
35672 /**
35673 * Retrieve the `value` using key. Because the IterableChangeRecord_ value may be one which we
35674 * have already iterated over, we use the `atOrAfterIndex` to pretend it is not there.
35675 *
35676 * Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we
35677 * have any more `a`s needs to return the second `a`.
35678 */
35679 get(trackById, atOrAfterIndex) {
35680 const key = trackById;
35681 const recordList = this.map.get(key);
35682 return recordList ? recordList.get(trackById, atOrAfterIndex) : null;
35683 }
35684 /**
35685 * Removes a {@link IterableChangeRecord_} from the list of duplicates.
35686 *
35687 * The list of duplicates also is removed from the map if it gets empty.
35688 */
35689 remove(record) {
35690 const key = record.trackById;
35691 const recordList = this.map.get(key);
35692 // Remove the list of duplicates when it gets empty
35693 if (recordList.remove(record)) {
35694 this.map.delete(key);
35695 }
35696 return record;
35697 }
35698 get isEmpty() {
35699 return this.map.size === 0;
35700 }
35701 clear() {
35702 this.map.clear();
35703 }
35704 }
35705 function getPreviousIndex(item, addRemoveOffset, moveOffsets) {
35706 const previousIndex = item.previousIndex;
35707 if (previousIndex === null)
35708 return previousIndex;
35709 let moveOffset = 0;
35710 if (moveOffsets && previousIndex < moveOffsets.length) {
35711 moveOffset = moveOffsets[previousIndex];
35712 }
35713 return previousIndex + addRemoveOffset + moveOffset;
35714 }
35715
35716 /**
35717 * @license
35718 * Copyright Google LLC All Rights Reserved.
35719 *
35720 * Use of this source code is governed by an MIT-style license that can be
35721 * found in the LICENSE file at https://angular.io/license
35722 */
35723 class DefaultKeyValueDifferFactory {
35724 constructor() { }
35725 supports(obj) {
35726 return obj instanceof Map || isJsObject(obj);
35727 }
35728 create() {
35729 return new DefaultKeyValueDiffer();
35730 }
35731 }
35732 class DefaultKeyValueDiffer {
35733 constructor() {
35734 this._records = new Map();
35735 this._mapHead = null;
35736 // _appendAfter is used in the check loop
35737 this._appendAfter = null;
35738 this._previousMapHead = null;
35739 this._changesHead = null;
35740 this._changesTail = null;
35741 this._additionsHead = null;
35742 this._additionsTail = null;
35743 this._removalsHead = null;
35744 this._removalsTail = null;
35745 }
35746 get isDirty() {
35747 return this._additionsHead !== null || this._changesHead !== null ||
35748 this._removalsHead !== null;
35749 }
35750 forEachItem(fn) {
35751 let record;
35752 for (record = this._mapHead; record !== null; record = record._next) {
35753 fn(record);
35754 }
35755 }
35756 forEachPreviousItem(fn) {
35757 let record;
35758 for (record = this._previousMapHead; record !== null; record = record._nextPrevious) {
35759 fn(record);
35760 }
35761 }
35762 forEachChangedItem(fn) {
35763 let record;
35764 for (record = this._changesHead; record !== null; record = record._nextChanged) {
35765 fn(record);
35766 }
35767 }
35768 forEachAddedItem(fn) {
35769 let record;
35770 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
35771 fn(record);
35772 }
35773 }
35774 forEachRemovedItem(fn) {
35775 let record;
35776 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
35777 fn(record);
35778 }
35779 }
35780 diff(map) {
35781 if (!map) {
35782 map = new Map();
35783 }
35784 else if (!(map instanceof Map || isJsObject(map))) {
35785 throw new Error(`Error trying to diff '${stringify$1(map)}'. Only maps and objects are allowed`);
35786 }
35787 return this.check(map) ? this : null;
35788 }
35789 onDestroy() { }
35790 /**
35791 * Check the current state of the map vs the previous.
35792 * The algorithm is optimised for when the keys do no change.
35793 */
35794 check(map) {
35795 this._reset();
35796 let insertBefore = this._mapHead;
35797 this._appendAfter = null;
35798 this._forEach(map, (value, key) => {
35799 if (insertBefore && insertBefore.key === key) {
35800 this._maybeAddToChanges(insertBefore, value);
35801 this._appendAfter = insertBefore;
35802 insertBefore = insertBefore._next;
35803 }
35804 else {
35805 const record = this._getOrCreateRecordForKey(key, value);
35806 insertBefore = this._insertBeforeOrAppend(insertBefore, record);
35807 }
35808 });
35809 // Items remaining at the end of the list have been deleted
35810 if (insertBefore) {
35811 if (insertBefore._prev) {
35812 insertBefore._prev._next = null;
35813 }
35814 this._removalsHead = insertBefore;
35815 for (let record = insertBefore; record !== null; record = record._nextRemoved) {
35816 if (record === this._mapHead) {
35817 this._mapHead = null;
35818 }
35819 this._records.delete(record.key);
35820 record._nextRemoved = record._next;
35821 record.previousValue = record.currentValue;
35822 record.currentValue = null;
35823 record._prev = null;
35824 record._next = null;
35825 }
35826 }
35827 // Make sure tails have no next records from previous runs
35828 if (this._changesTail)
35829 this._changesTail._nextChanged = null;
35830 if (this._additionsTail)
35831 this._additionsTail._nextAdded = null;
35832 return this.isDirty;
35833 }
35834 /**
35835 * Inserts a record before `before` or append at the end of the list when `before` is null.
35836 *
35837 * Notes:
35838 * - This method appends at `this._appendAfter`,
35839 * - This method updates `this._appendAfter`,
35840 * - The return value is the new value for the insertion pointer.
35841 */
35842 _insertBeforeOrAppend(before, record) {
35843 if (before) {
35844 const prev = before._prev;
35845 record._next = before;
35846 record._prev = prev;
35847 before._prev = record;
35848 if (prev) {
35849 prev._next = record;
35850 }
35851 if (before === this._mapHead) {
35852 this._mapHead = record;
35853 }
35854 this._appendAfter = before;
35855 return before;
35856 }
35857 if (this._appendAfter) {
35858 this._appendAfter._next = record;
35859 record._prev = this._appendAfter;
35860 }
35861 else {
35862 this._mapHead = record;
35863 }
35864 this._appendAfter = record;
35865 return null;
35866 }
35867 _getOrCreateRecordForKey(key, value) {
35868 if (this._records.has(key)) {
35869 const record = this._records.get(key);
35870 this._maybeAddToChanges(record, value);
35871 const prev = record._prev;
35872 const next = record._next;
35873 if (prev) {
35874 prev._next = next;
35875 }
35876 if (next) {
35877 next._prev = prev;
35878 }
35879 record._next = null;
35880 record._prev = null;
35881 return record;
35882 }
35883 const record = new KeyValueChangeRecord_(key);
35884 this._records.set(key, record);
35885 record.currentValue = value;
35886 this._addToAdditions(record);
35887 return record;
35888 }
35889 /** @internal */
35890 _reset() {
35891 if (this.isDirty) {
35892 let record;
35893 // let `_previousMapHead` contain the state of the map before the changes
35894 this._previousMapHead = this._mapHead;
35895 for (record = this._previousMapHead; record !== null; record = record._next) {
35896 record._nextPrevious = record._next;
35897 }
35898 // Update `record.previousValue` with the value of the item before the changes
35899 // We need to update all changed items (that's those which have been added and changed)
35900 for (record = this._changesHead; record !== null; record = record._nextChanged) {
35901 record.previousValue = record.currentValue;
35902 }
35903 for (record = this._additionsHead; record != null; record = record._nextAdded) {
35904 record.previousValue = record.currentValue;
35905 }
35906 this._changesHead = this._changesTail = null;
35907 this._additionsHead = this._additionsTail = null;
35908 this._removalsHead = null;
35909 }
35910 }
35911 // Add the record or a given key to the list of changes only when the value has actually changed
35912 _maybeAddToChanges(record, newValue) {
35913 if (!Object.is(newValue, record.currentValue)) {
35914 record.previousValue = record.currentValue;
35915 record.currentValue = newValue;
35916 this._addToChanges(record);
35917 }
35918 }
35919 _addToAdditions(record) {
35920 if (this._additionsHead === null) {
35921 this._additionsHead = this._additionsTail = record;
35922 }
35923 else {
35924 this._additionsTail._nextAdded = record;
35925 this._additionsTail = record;
35926 }
35927 }
35928 _addToChanges(record) {
35929 if (this._changesHead === null) {
35930 this._changesHead = this._changesTail = record;
35931 }
35932 else {
35933 this._changesTail._nextChanged = record;
35934 this._changesTail = record;
35935 }
35936 }
35937 /** @internal */
35938 _forEach(obj, fn) {
35939 if (obj instanceof Map) {
35940 obj.forEach(fn);
35941 }
35942 else {
35943 Object.keys(obj).forEach(k => fn(obj[k], k));
35944 }
35945 }
35946 }
35947 class KeyValueChangeRecord_ {
35948 constructor(key) {
35949 this.key = key;
35950 this.previousValue = null;
35951 this.currentValue = null;
35952 /** @internal */
35953 this._nextPrevious = null;
35954 /** @internal */
35955 this._next = null;
35956 /** @internal */
35957 this._prev = null;
35958 /** @internal */
35959 this._nextAdded = null;
35960 /** @internal */
35961 this._nextRemoved = null;
35962 /** @internal */
35963 this._nextChanged = null;
35964 }
35965 }
35966
35967 /**
35968 * @license
35969 * Copyright Google LLC All Rights Reserved.
35970 *
35971 * Use of this source code is governed by an MIT-style license that can be
35972 * found in the LICENSE file at https://angular.io/license
35973 */
35974 function defaultIterableDiffersFactory() {
35975 return new IterableDiffers([new DefaultIterableDifferFactory()]);
35976 }
35977 /**
35978 * A repository of different iterable diffing strategies used by NgFor, NgClass, and others.
35979 *
35980 * @publicApi
35981 */
35982 class IterableDiffers {
35983 constructor(factories) {
35984 this.factories = factories;
35985 }
35986 static create(factories, parent) {
35987 if (parent != null) {
35988 const copied = parent.factories.slice();
35989 factories = factories.concat(copied);
35990 }
35991 return new IterableDiffers(factories);
35992 }
35993 /**
35994 * Takes an array of {@link IterableDifferFactory} and returns a provider used to extend the
35995 * inherited {@link IterableDiffers} instance with the provided factories and return a new
35996 * {@link IterableDiffers} instance.
35997 *
35998 * @usageNotes
35999 * ### Example
36000 *
36001 * The following example shows how to extend an existing list of factories,
36002 * which will only be applied to the injector for this component and its children.
36003 * This step is all that's required to make a new {@link IterableDiffer} available.
36004 *
36005 * ```
36006 * @Component({
36007 * viewProviders: [
36008 * IterableDiffers.extend([new ImmutableListDiffer()])
36009 * ]
36010 * })
36011 * ```
36012 */
36013 static extend(factories) {
36014 return {
36015 provide: IterableDiffers,
36016 useFactory: (parent) => {
36017 // if parent is null, it means that we are in the root injector and we have just overridden
36018 // the default injection mechanism for IterableDiffers, in such a case just assume
36019 // `defaultIterableDiffersFactory`.
36020 return IterableDiffers.create(factories, parent || defaultIterableDiffersFactory());
36021 },
36022 // Dependency technically isn't optional, but we can provide a better error message this way.
36023 deps: [[IterableDiffers, new SkipSelf(), new Optional()]]
36024 };
36025 }
36026 find(iterable) {
36027 const factory = this.factories.find(f => f.supports(iterable));
36028 if (factory != null) {
36029 return factory;
36030 }
36031 else {
36032 throw new Error(`Cannot find a differ supporting object '${iterable}' of type '${getTypeNameForDebugging(iterable)}'`);
36033 }
36034 }
36035 }
36036 /** @nocollapse */
36037 IterableDiffers.ɵprov = ɵɵdefineInjectable({ token: IterableDiffers, providedIn: 'root', factory: defaultIterableDiffersFactory });
36038 function getTypeNameForDebugging(type) {
36039 return type['name'] || typeof type;
36040 }
36041
36042 /**
36043 * @license
36044 * Copyright Google LLC All Rights Reserved.
36045 *
36046 * Use of this source code is governed by an MIT-style license that can be
36047 * found in the LICENSE file at https://angular.io/license
36048 */
36049 function defaultKeyValueDiffersFactory() {
36050 return new KeyValueDiffers([new DefaultKeyValueDifferFactory()]);
36051 }
36052 /**
36053 * A repository of different Map diffing strategies used by NgClass, NgStyle, and others.
36054 *
36055 * @publicApi
36056 */
36057 class KeyValueDiffers {
36058 constructor(factories) {
36059 this.factories = factories;
36060 }
36061 static create(factories, parent) {
36062 if (parent) {
36063 const copied = parent.factories.slice();
36064 factories = factories.concat(copied);
36065 }
36066 return new KeyValueDiffers(factories);
36067 }
36068 /**
36069 * Takes an array of {@link KeyValueDifferFactory} and returns a provider used to extend the
36070 * inherited {@link KeyValueDiffers} instance with the provided factories and return a new
36071 * {@link KeyValueDiffers} instance.
36072 *
36073 * @usageNotes
36074 * ### Example
36075 *
36076 * The following example shows how to extend an existing list of factories,
36077 * which will only be applied to the injector for this component and its children.
36078 * This step is all that's required to make a new {@link KeyValueDiffer} available.
36079 *
36080 * ```
36081 * @Component({
36082 * viewProviders: [
36083 * KeyValueDiffers.extend([new ImmutableMapDiffer()])
36084 * ]
36085 * })
36086 * ```
36087 */
36088 static extend(factories) {
36089 return {
36090 provide: KeyValueDiffers,
36091 useFactory: (parent) => {
36092 // if parent is null, it means that we are in the root injector and we have just overridden
36093 // the default injection mechanism for KeyValueDiffers, in such a case just assume
36094 // `defaultKeyValueDiffersFactory`.
36095 return KeyValueDiffers.create(factories, parent || defaultKeyValueDiffersFactory());
36096 },
36097 // Dependency technically isn't optional, but we can provide a better error message this way.
36098 deps: [[KeyValueDiffers, new SkipSelf(), new Optional()]]
36099 };
36100 }
36101 find(kv) {
36102 const factory = this.factories.find(f => f.supports(kv));
36103 if (factory) {
36104 return factory;
36105 }
36106 throw new Error(`Cannot find a differ supporting object '${kv}'`);
36107 }
36108 }
36109 /** @nocollapse */
36110 KeyValueDiffers.ɵprov = ɵɵdefineInjectable({ token: KeyValueDiffers, providedIn: 'root', factory: defaultKeyValueDiffersFactory });
36111
36112 /**
36113 * @license
36114 * Copyright Google LLC All Rights Reserved.
36115 *
36116 * Use of this source code is governed by an MIT-style license that can be
36117 * found in the LICENSE file at https://angular.io/license
36118 */
36119 function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
36120 while (tNode !== null) {
36121 ngDevMode &&
36122 assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */ | 16 /* Projection */ | 32 /* Icu */);
36123 const lNode = lView[tNode.index];
36124 if (lNode !== null) {
36125 result.push(unwrapRNode(lNode));
36126 }
36127 // A given lNode can represent either a native node or a LContainer (when it is a host of a
36128 // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
36129 // from the views in this container.
36130 if (isLContainer(lNode)) {
36131 for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
36132 const lViewInAContainer = lNode[i];
36133 const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
36134 if (lViewFirstChildTNode !== null) {
36135 collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
36136 }
36137 }
36138 }
36139 const tNodeType = tNode.type;
36140 if (tNodeType & 8 /* ElementContainer */) {
36141 collectNativeNodes(tView, lView, tNode.child, result);
36142 }
36143 else if (tNodeType & 32 /* Icu */) {
36144 const nextRNode = icuContainerIterate();
36145 let rNode;
36146 while (rNode = nextRNode()) {
36147 result.push(rNode);
36148 }
36149 }
36150 else if (tNodeType & 16 /* Projection */) {
36151 const nodesInSlot = getProjectionNodes(lView, tNode);
36152 if (Array.isArray(nodesInSlot)) {
36153 result.push(...nodesInSlot);
36154 }
36155 else {
36156 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
36157 ngDevMode && assertParentView(parentView);
36158 collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
36159 }
36160 }
36161 tNode = isProjection ? tNode.projectionNext : tNode.next;
36162 }
36163 return result;
36164 }
36165
36166 /**
36167 * @license
36168 * Copyright Google LLC All Rights Reserved.
36169 *
36170 * Use of this source code is governed by an MIT-style license that can be
36171 * found in the LICENSE file at https://angular.io/license
36172 */
36173 class ViewRef {
36174 constructor(
36175 /**
36176 * This represents `LView` associated with the component when ViewRef is a ChangeDetectorRef.
36177 *
36178 * When ViewRef is created for a dynamic component, this also represents the `LView` for the
36179 * component.
36180 *
36181 * For a "regular" ViewRef created for an embedded view, this is the `LView` for the embedded
36182 * view.
36183 *
36184 * @internal
36185 */
36186 _lView,
36187 /**
36188 * This represents the `LView` associated with the point where `ChangeDetectorRef` was
36189 * requested.
36190 *
36191 * This may be different from `_lView` if the `_cdRefInjectingView` is an embedded view.
36192 */
36193 _cdRefInjectingView) {
36194 this._lView = _lView;
36195 this._cdRefInjectingView = _cdRefInjectingView;
36196 this._appRef = null;
36197 this._attachedToViewContainer = false;
36198 }
36199 get rootNodes() {
36200 const lView = this._lView;
36201 const tView = lView[TVIEW];
36202 return collectNativeNodes(tView, lView, tView.firstChild, []);
36203 }
36204 get context() {
36205 return this._lView[CONTEXT];
36206 }
36207 get destroyed() {
36208 return (this._lView[FLAGS] & 256 /* Destroyed */) === 256 /* Destroyed */;
36209 }
36210 destroy() {
36211 if (this._appRef) {
36212 this._appRef.detachView(this);
36213 }
36214 else if (this._attachedToViewContainer) {
36215 const parent = this._lView[PARENT];
36216 if (isLContainer(parent)) {
36217 const viewRefs = parent[VIEW_REFS];
36218 const index = viewRefs ? viewRefs.indexOf(this) : -1;
36219 if (index > -1) {
36220 ngDevMode &&
36221 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.');
36222 detachView(parent, index);
36223 removeFromArray(viewRefs, index);
36224 }
36225 }
36226 this._attachedToViewContainer = false;
36227 }
36228 destroyLView(this._lView[TVIEW], this._lView);
36229 }
36230 onDestroy(callback) {
36231 storeCleanupWithContext(this._lView[TVIEW], this._lView, null, callback);
36232 }
36233 /**
36234 * Marks a view and all of its ancestors dirty.
36235 *
36236 * It also triggers change detection by calling `scheduleTick` internally, which coalesces
36237 * multiple `markForCheck` calls to into one change detection run.
36238 *
36239 * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is
36240 * checked when it needs to be re-rendered but the two normal triggers haven't marked it
36241 * dirty (i.e. inputs haven't changed and events haven't fired in the view).
36242 *
36243 * <!-- TODO: Add a link to a chapter on OnPush components -->
36244 *
36245 * @usageNotes
36246 * ### Example
36247 *
36248 * ```typescript
36249 * @Component({
36250 * selector: 'my-app',
36251 * template: `Number of ticks: {{numberOfTicks}}`
36252 * changeDetection: ChangeDetectionStrategy.OnPush,
36253 * })
36254 * class AppComponent {
36255 * numberOfTicks = 0;
36256 *
36257 * constructor(private ref: ChangeDetectorRef) {
36258 * setInterval(() => {
36259 * this.numberOfTicks++;
36260 * // the following is required, otherwise the view will not be updated
36261 * this.ref.markForCheck();
36262 * }, 1000);
36263 * }
36264 * }
36265 * ```
36266 */
36267 markForCheck() {
36268 markViewDirty(this._cdRefInjectingView || this._lView);
36269 }
36270 /**
36271 * Detaches the view from the change detection tree.
36272 *
36273 * Detached views will not be checked during change detection runs until they are
36274 * re-attached, even if they are dirty. `detach` can be used in combination with
36275 * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change
36276 * detection checks.
36277 *
36278 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
36279 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
36280 *
36281 * @usageNotes
36282 * ### Example
36283 *
36284 * The following example defines a component with a large list of readonly data.
36285 * Imagine the data changes constantly, many times per second. For performance reasons,
36286 * we want to check and update the list every five seconds. We can do that by detaching
36287 * the component's change detector and doing a local check every five seconds.
36288 *
36289 * ```typescript
36290 * class DataProvider {
36291 * // in a real application the returned data will be different every time
36292 * get data() {
36293 * return [1,2,3,4,5];
36294 * }
36295 * }
36296 *
36297 * @Component({
36298 * selector: 'giant-list',
36299 * template: `
36300 * <li *ngFor="let d of dataProvider.data">Data {{d}}</li>
36301 * `,
36302 * })
36303 * class GiantList {
36304 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {
36305 * ref.detach();
36306 * setInterval(() => {
36307 * this.ref.detectChanges();
36308 * }, 5000);
36309 * }
36310 * }
36311 *
36312 * @Component({
36313 * selector: 'app',
36314 * providers: [DataProvider],
36315 * template: `
36316 * <giant-list><giant-list>
36317 * `,
36318 * })
36319 * class App {
36320 * }
36321 * ```
36322 */
36323 detach() {
36324 this._lView[FLAGS] &= ~128 /* Attached */;
36325 }
36326 /**
36327 * Re-attaches a view to the change detection tree.
36328 *
36329 * This can be used to re-attach views that were previously detached from the tree
36330 * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default.
36331 *
36332 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
36333 *
36334 * @usageNotes
36335 * ### Example
36336 *
36337 * The following example creates a component displaying `live` data. The component will detach
36338 * its change detector from the main change detector tree when the component's live property
36339 * is set to false.
36340 *
36341 * ```typescript
36342 * class DataProvider {
36343 * data = 1;
36344 *
36345 * constructor() {
36346 * setInterval(() => {
36347 * this.data = this.data * 2;
36348 * }, 500);
36349 * }
36350 * }
36351 *
36352 * @Component({
36353 * selector: 'live-data',
36354 * inputs: ['live'],
36355 * template: 'Data: {{dataProvider.data}}'
36356 * })
36357 * class LiveData {
36358 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {}
36359 *
36360 * set live(value) {
36361 * if (value) {
36362 * this.ref.reattach();
36363 * } else {
36364 * this.ref.detach();
36365 * }
36366 * }
36367 * }
36368 *
36369 * @Component({
36370 * selector: 'my-app',
36371 * providers: [DataProvider],
36372 * template: `
36373 * Live Update: <input type="checkbox" [(ngModel)]="live">
36374 * <live-data [live]="live"><live-data>
36375 * `,
36376 * })
36377 * class AppComponent {
36378 * live = true;
36379 * }
36380 * ```
36381 */
36382 reattach() {
36383 this._lView[FLAGS] |= 128 /* Attached */;
36384 }
36385 /**
36386 * Checks the view and its children.
36387 *
36388 * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement
36389 * local change detection checks.
36390 *
36391 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
36392 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
36393 *
36394 * @usageNotes
36395 * ### Example
36396 *
36397 * The following example defines a component with a large list of readonly data.
36398 * Imagine, the data changes constantly, many times per second. For performance reasons,
36399 * we want to check and update the list every five seconds.
36400 *
36401 * We can do that by detaching the component's change detector and doing a local change detection
36402 * check every five seconds.
36403 *
36404 * See {@link ChangeDetectorRef#detach detach} for more information.
36405 */
36406 detectChanges() {
36407 detectChangesInternal(this._lView[TVIEW], this._lView, this.context);
36408 }
36409 /**
36410 * Checks the change detector and its children, and throws if any changes are detected.
36411 *
36412 * This is used in development mode to verify that running change detection doesn't
36413 * introduce other changes.
36414 */
36415 checkNoChanges() {
36416 checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
36417 }
36418 attachToViewContainerRef() {
36419 if (this._appRef) {
36420 throw new Error('This view is already attached directly to the ApplicationRef!');
36421 }
36422 this._attachedToViewContainer = true;
36423 }
36424 detachFromAppRef() {
36425 this._appRef = null;
36426 renderDetachView(this._lView[TVIEW], this._lView);
36427 }
36428 attachToAppRef(appRef) {
36429 if (this._attachedToViewContainer) {
36430 throw new Error('This view is already attached to a ViewContainer!');
36431 }
36432 this._appRef = appRef;
36433 }
36434 }
36435 /** @internal */
36436 class RootViewRef extends ViewRef {
36437 constructor(_view) {
36438 super(_view);
36439 this._view = _view;
36440 }
36441 detectChanges() {
36442 detectChangesInRootView(this._view);
36443 }
36444 checkNoChanges() {
36445 checkNoChangesInRootView(this._view);
36446 }
36447 get context() {
36448 return null;
36449 }
36450 }
36451
36452 /**
36453 * @license
36454 * Copyright Google LLC All Rights Reserved.
36455 *
36456 * Use of this source code is governed by an MIT-style license that can be
36457 * found in the LICENSE file at https://angular.io/license
36458 */
36459 const SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__ = noop;
36460 const SWITCH_CHANGE_DETECTOR_REF_FACTORY = SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__;
36461 /**
36462 * Base class that provides change detection functionality.
36463 * A change-detection tree collects all views that are to be checked for changes.
36464 * Use the methods to add and remove views from the tree, initiate change-detection,
36465 * and explicitly mark views as _dirty_, meaning that they have changed and need to be re-rendered.
36466 *
36467 * @see [Using change detection hooks](guide/lifecycle-hooks#using-change-detection-hooks)
36468 * @see [Defining custom change detection](guide/lifecycle-hooks#defining-custom-change-detection)
36469 *
36470 * @usageNotes
36471 *
36472 * The following examples demonstrate how to modify default change-detection behavior
36473 * to perform explicit detection when needed.
36474 *
36475 * ### Use `markForCheck()` with `CheckOnce` strategy
36476 *
36477 * The following example sets the `OnPush` change-detection strategy for a component
36478 * (`CheckOnce`, rather than the default `CheckAlways`), then forces a second check
36479 * after an interval. See [live demo](https://plnkr.co/edit/GC512b?p=preview).
36480 *
36481 * <code-example path="core/ts/change_detect/change-detection.ts"
36482 * region="mark-for-check"></code-example>
36483 *
36484 * ### Detach change detector to limit how often check occurs
36485 *
36486 * The following example defines a component with a large list of read-only data
36487 * that is expected to change constantly, many times per second.
36488 * To improve performance, we want to check and update the list
36489 * less often than the changes actually occur. To do that, we detach
36490 * the component's change detector and perform an explicit local check every five seconds.
36491 *
36492 * <code-example path="core/ts/change_detect/change-detection.ts" region="detach"></code-example>
36493 *
36494 *
36495 * ### Reattaching a detached component
36496 *
36497 * The following example creates a component displaying live data.
36498 * The component detaches its change detector from the main change detector tree
36499 * when the `live` property is set to false, and reattaches it when the property
36500 * becomes true.
36501 *
36502 * <code-example path="core/ts/change_detect/change-detection.ts" region="reattach"></code-example>
36503 *
36504 * @publicApi
36505 */
36506 class ChangeDetectorRef {
36507 }
36508 /**
36509 * @internal
36510 * @nocollapse
36511 */
36512 ChangeDetectorRef.__NG_ELEMENT_ID__ = SWITCH_CHANGE_DETECTOR_REF_FACTORY;
36513 /**
36514 * This marker is need so that the JIT compiler can correctly identify this class as special.
36515 *
36516 * @internal
36517 * @nocollapse
36518 */
36519 ChangeDetectorRef.__ChangeDetectorRef__ = true;
36520
36521 /**
36522 * @license
36523 * Copyright Google LLC All Rights Reserved.
36524 *
36525 * Use of this source code is governed by an MIT-style license that can be
36526 * found in the LICENSE file at https://angular.io/license
36527 */
36528 /**
36529 * Structural diffing for `Object`s and `Map`s.
36530 */
36531 const keyValDiff = [new DefaultKeyValueDifferFactory()];
36532 /**
36533 * Structural diffing for `Iterable` types such as `Array`s.
36534 */
36535 const iterableDiff = [new DefaultIterableDifferFactory()];
36536 const defaultIterableDiffers = new IterableDiffers(iterableDiff);
36537 const defaultKeyValueDiffers = new KeyValueDiffers(keyValDiff);
36538
36539 /**
36540 * @license
36541 * Copyright Google LLC All Rights Reserved.
36542 *
36543 * Use of this source code is governed by an MIT-style license that can be
36544 * found in the LICENSE file at https://angular.io/license
36545 */
36546 const SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__ = noop;
36547 const SWITCH_TEMPLATE_REF_FACTORY = SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__;
36548 /**
36549 * Represents an embedded template that can be used to instantiate embedded views.
36550 * To instantiate embedded views based on a template, use the `ViewContainerRef`
36551 * method `createEmbeddedView()`.
36552 *
36553 * Access a `TemplateRef` instance by placing a directive on an `<ng-template>`
36554 * element (or directive prefixed with `*`). The `TemplateRef` for the embedded view
36555 * is injected into the constructor of the directive,
36556 * using the `TemplateRef` token.
36557 *
36558 * You can also use a `Query` to find a `TemplateRef` associated with
36559 * a component or a directive.
36560 *
36561 * @see `ViewContainerRef`
36562 * @see [Navigate the Component Tree with DI](guide/dependency-injection-navtree)
36563 *
36564 * @publicApi
36565 */
36566 class TemplateRef {
36567 }
36568 /**
36569 * @internal
36570 * @nocollapse
36571 */
36572 TemplateRef.__NG_ELEMENT_ID__ = SWITCH_TEMPLATE_REF_FACTORY;
36573
36574 /**
36575 * @license
36576 * Copyright Google LLC All Rights Reserved.
36577 *
36578 * Use of this source code is governed by an MIT-style license that can be
36579 * found in the LICENSE file at https://angular.io/license
36580 */
36581 /**
36582 * Represents an instance of an `NgModule` created by an `NgModuleFactory`.
36583 * Provides access to the `NgModule` instance and related objects.
36584 *
36585 * @publicApi
36586 */
36587 class NgModuleRef {
36588 }
36589
36590 /**
36591 * @license
36592 * Copyright Google LLC All Rights Reserved.
36593 *
36594 * Use of this source code is governed by an MIT-style license that can be
36595 * found in the LICENSE file at https://angular.io/license
36596 */
36597 const SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__ = noop;
36598 const SWITCH_VIEW_CONTAINER_REF_FACTORY = SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__;
36599 /**
36600 * Represents a container where one or more views can be attached to a component.
36601 *
36602 * Can contain *host views* (created by instantiating a
36603 * component with the `createComponent()` method), and *embedded views*
36604 * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
36605 *
36606 * A view container instance can contain other view containers,
36607 * creating a [view hierarchy](guide/glossary#view-tree).
36608 *
36609 * @see `ComponentRef`
36610 * @see `EmbeddedViewRef`
36611 *
36612 * @publicApi
36613 */
36614 class ViewContainerRef {
36615 }
36616 /**
36617 * @internal
36618 * @nocollapse
36619 */
36620 ViewContainerRef.__NG_ELEMENT_ID__ = SWITCH_VIEW_CONTAINER_REF_FACTORY;
36621
36622 /**
36623 * @license
36624 * Copyright Google LLC All Rights Reserved.
36625 *
36626 * Use of this source code is governed by an MIT-style license that can be
36627 * found in the LICENSE file at https://angular.io/license
36628 */
36629 const _tokenKeyCache = new Map();
36630 function tokenKey(token) {
36631 let key = _tokenKeyCache.get(token);
36632 if (!key) {
36633 key = stringify$1(token) + '_' + _tokenKeyCache.size;
36634 _tokenKeyCache.set(token, key);
36635 }
36636 return key;
36637 }
36638
36639 /**
36640 * @license
36641 * Copyright Google LLC All Rights Reserved.
36642 *
36643 * Use of this source code is governed by an MIT-style license that can be
36644 * found in the LICENSE file at https://angular.io/license
36645 */
36646 const InjectorRefTokenKey = tokenKey(Injector);
36647 const INJECTORRefTokenKey = tokenKey(INJECTOR$1);
36648 const NgModuleRefTokenKey = tokenKey(NgModuleRef);
36649
36650 /**
36651 * @license
36652 * Copyright Google LLC All Rights Reserved.
36653 *
36654 * Use of this source code is governed by an MIT-style license that can be
36655 * found in the LICENSE file at https://angular.io/license
36656 */
36657 const Renderer2TokenKey = tokenKey(Renderer2);
36658 const ElementRefTokenKey = tokenKey(ElementRef);
36659 const ViewContainerRefTokenKey = tokenKey(ViewContainerRef);
36660 const TemplateRefTokenKey = tokenKey(TemplateRef);
36661 const ChangeDetectorRefTokenKey = tokenKey(ChangeDetectorRef);
36662 const InjectorRefTokenKey$1 = tokenKey(Injector);
36663 const INJECTORRefTokenKey$1 = tokenKey(INJECTOR$1);
36664 // This default value is when checking the hierarchy for a token.
36665 //
36666 // It means both:
36667 // - the token is not provided by the current injector,
36668 // - only the element injectors should be checked (ie do not check module injectors
36669 //
36670 // mod1
36671 // /
36672 // el1 mod2
36673 // \ /
36674 // el2
36675 //
36676 // When requesting el2.injector.get(token), we should check in the following order and return the
36677 // first found value:
36678 // - el2.injector.get(token, default)
36679 // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
36680 // - mod2.injector.get(token, default)
36681 const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
36682
36683 /**
36684 * @license
36685 * Copyright Google LLC All Rights Reserved.
36686 *
36687 * Use of this source code is governed by an MIT-style license that can be
36688 * found in the LICENSE file at https://angular.io/license
36689 */
36690 class ComponentFactoryResolver$1 extends ComponentFactoryResolver {
36691 /**
36692 * @param ngModule The NgModuleRef to which all resolved factories are bound.
36693 */
36694 constructor(ngModule) {
36695 super();
36696 this.ngModule = ngModule;
36697 }
36698 resolveComponentFactory(component) {
36699 ngDevMode && assertComponentType(component);
36700 const componentDef = getComponentDef(component);
36701 return new ComponentFactory$1(componentDef, this.ngModule);
36702 }
36703 }
36704 function toRefArray(map) {
36705 const array = [];
36706 for (let nonMinified in map) {
36707 if (map.hasOwnProperty(nonMinified)) {
36708 const minified = map[nonMinified];
36709 array.push({ propName: minified, templateName: nonMinified });
36710 }
36711 }
36712 return array;
36713 }
36714 function getNamespace(elementName) {
36715 const name = elementName.toLowerCase();
36716 return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null);
36717 }
36718 /**
36719 * A change detection scheduler token for {@link RootContext}. This token is the default value used
36720 * for the default `RootContext` found in the {@link ROOT_CONTEXT} token.
36721 */
36722 const SCHEDULER = new InjectionToken('SCHEDULER_TOKEN', {
36723 providedIn: 'root',
36724 factory: () => defaultScheduler,
36725 });
36726 function createChainedInjector(rootViewInjector, moduleInjector) {
36727 return {
36728 get: (token, notFoundValue, flags) => {
36729 const value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
36730 if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
36731 notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
36732 // Return the value from the root element injector when
36733 // - it provides it
36734 // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
36735 // - the module injector should not be checked
36736 // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
36737 return value;
36738 }
36739 return moduleInjector.get(token, notFoundValue, flags);
36740 }
36741 };
36742 }
36743 /**
36744 * Render3 implementation of {@link viewEngine_ComponentFactory}.
36745 */
36746 class ComponentFactory$1 extends ComponentFactory {
36747 /**
36748 * @param componentDef The component definition.
36749 * @param ngModule The NgModuleRef to which the factory is bound.
36750 */
36751 constructor(componentDef, ngModule) {
36752 super();
36753 this.componentDef = componentDef;
36754 this.ngModule = ngModule;
36755 this.componentType = componentDef.type;
36756 this.selector = stringifyCSSSelectorList(componentDef.selectors);
36757 this.ngContentSelectors =
36758 componentDef.ngContentSelectors ? componentDef.ngContentSelectors : [];
36759 this.isBoundToModule = !!ngModule;
36760 }
36761 get inputs() {
36762 return toRefArray(this.componentDef.inputs);
36763 }
36764 get outputs() {
36765 return toRefArray(this.componentDef.outputs);
36766 }
36767 create(injector, projectableNodes, rootSelectorOrNode, ngModule) {
36768 ngModule = ngModule || this.ngModule;
36769 const rootViewInjector = ngModule ? createChainedInjector(injector, ngModule.injector) : injector;
36770 const rendererFactory = rootViewInjector.get(RendererFactory2, domRendererFactory3);
36771 const sanitizer = rootViewInjector.get(Sanitizer, null);
36772 const hostRenderer = rendererFactory.createRenderer(null, this.componentDef);
36773 // Determine a tag name used for creating host elements when this component is created
36774 // dynamically. Default to 'div' if this component did not specify any tag name in its selector.
36775 const elementName = this.componentDef.selectors[0][0] || 'div';
36776 const hostRNode = rootSelectorOrNode ?
36777 locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) :
36778 createElementNode(rendererFactory.createRenderer(null, this.componentDef), elementName, getNamespace(elementName));
36779 const rootFlags = this.componentDef.onPush ? 64 /* Dirty */ | 512 /* IsRoot */ :
36780 16 /* CheckAlways */ | 512 /* IsRoot */;
36781 const rootContext = createRootContext();
36782 // Create the root view. Uses empty TView and ContentTemplate.
36783 const rootTView = createTView(0 /* Root */, null, null, 1, 0, null, null, null, null, null);
36784 const rootLView = createLView(null, rootTView, rootContext, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector);
36785 // rootView is the parent when bootstrapping
36786 // TODO(misko): it looks like we are entering view here but we don't really need to as
36787 // `renderView` does that. However as the code is written it is needed because
36788 // `createRootComponentView` and `createRootComponent` both read global state. Fixing those
36789 // issues would allow us to drop this.
36790 enterView(rootLView);
36791 let component;
36792 let tElementNode;
36793 try {
36794 const componentView = createRootComponentView(hostRNode, this.componentDef, rootLView, rendererFactory, hostRenderer);
36795 if (hostRNode) {
36796 if (rootSelectorOrNode) {
36797 setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION$2.full]);
36798 }
36799 else {
36800 // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
36801 // is not defined), also apply attributes and classes extracted from component selector.
36802 // Extract attributes and classes from the first selector only to match VE behavior.
36803 const { attrs, classes } = extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
36804 if (attrs) {
36805 setUpAttributes(hostRenderer, hostRNode, attrs);
36806 }
36807 if (classes && classes.length > 0) {
36808 writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
36809 }
36810 }
36811 }
36812 tElementNode = getTNode(rootTView, HEADER_OFFSET);
36813 if (projectableNodes !== undefined) {
36814 const projection = tElementNode.projection = [];
36815 for (let i = 0; i < this.ngContentSelectors.length; i++) {
36816 const nodesforSlot = projectableNodes[i];
36817 // Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
36818 // case). Here we do normalize passed data structure to be an array of arrays to avoid
36819 // complex checks down the line.
36820 // We also normalize the length of the passed in projectable nodes (to match the number of
36821 // <ng-container> slots defined by a component).
36822 projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
36823 }
36824 }
36825 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
36826 // executed here?
36827 // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
36828 component = createRootComponent(componentView, this.componentDef, rootLView, rootContext, [LifecycleHooksFeature]);
36829 renderView(rootTView, rootLView, null);
36830 }
36831 finally {
36832 leaveView();
36833 }
36834 return new ComponentRef$1(this.componentType, component, createElementRef(tElementNode, rootLView), rootLView, tElementNode);
36835 }
36836 }
36837 const componentFactoryResolver = new ComponentFactoryResolver$1();
36838 /**
36839 * Represents an instance of a Component created via a {@link ComponentFactory}.
36840 *
36841 * `ComponentRef` provides access to the Component Instance as well other objects related to this
36842 * Component Instance and allows you to destroy the Component Instance via the {@link #destroy}
36843 * method.
36844 *
36845 */
36846 class ComponentRef$1 extends ComponentRef {
36847 constructor(componentType, instance, location, _rootLView, _tNode) {
36848 super();
36849 this.location = location;
36850 this._rootLView = _rootLView;
36851 this._tNode = _tNode;
36852 this.instance = instance;
36853 this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView);
36854 this.componentType = componentType;
36855 }
36856 get injector() {
36857 return new NodeInjector(this._tNode, this._rootLView);
36858 }
36859 destroy() {
36860 this.hostView.destroy();
36861 }
36862 onDestroy(callback) {
36863 this.hostView.onDestroy(callback);
36864 }
36865 }
36866
36867 /*! *****************************************************************************
36868 Copyright (c) Microsoft Corporation. All rights reserved.
36869 Licensed under the Apache License, Version 2.0 (the "License"); you may not use
36870 this file except in compliance with the License. You may obtain a copy of the
36871 License at http://www.apache.org/licenses/LICENSE-2.0
36872
36873 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
36874 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
36875 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
36876 MERCHANTABLITY OR NON-INFRINGEMENT.
36877
36878 See the Apache Version 2.0 License for specific language governing permissions
36879 and limitations under the License.
36880 ***************************************************************************** */
36881 /* global Reflect, Promise */
36882
36883 var extendStatics = function(d, b) {
36884 extendStatics = Object.setPrototypeOf ||
36885 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
36886 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
36887 return extendStatics(d, b);
36888 };
36889
36890 function __extends(d, b) {
36891 extendStatics(d, b);
36892 function __() { this.constructor = d; }
36893 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
36894 }
36895
36896 /** PURE_IMPORTS_START PURE_IMPORTS_END */
36897 function isFunction(x) {
36898 return typeof x === 'function';
36899 }
36900
36901 /** PURE_IMPORTS_START PURE_IMPORTS_END */
36902 var _enable_super_gross_mode_that_will_cause_bad_things = false;
36903 var config = {
36904 Promise: undefined,
36905 set useDeprecatedSynchronousErrorHandling(value) {
36906 if (value) {
36907 var error = /*@__PURE__*/ new Error();
36908 /*@__PURE__*/ console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n' + error.stack);
36909 }
36910 _enable_super_gross_mode_that_will_cause_bad_things = value;
36911 },
36912 get useDeprecatedSynchronousErrorHandling() {
36913 return _enable_super_gross_mode_that_will_cause_bad_things;
36914 },
36915 };
36916
36917 /** PURE_IMPORTS_START PURE_IMPORTS_END */
36918 function hostReportError(err) {
36919 setTimeout(function () { throw err; }, 0);
36920 }
36921
36922 /** PURE_IMPORTS_START _config,_util_hostReportError PURE_IMPORTS_END */
36923 var empty = {
36924 closed: true,
36925 next: function (value) { },
36926 error: function (err) {
36927 if (config.useDeprecatedSynchronousErrorHandling) {
36928 throw err;
36929 }
36930 else {
36931 hostReportError(err);
36932 }
36933 },
36934 complete: function () { }
36935 };
36936
36937 /** PURE_IMPORTS_START PURE_IMPORTS_END */
36938 var isArray = /*@__PURE__*/ (function () { return Array.isArray || (function (x) { return x && typeof x.length === 'number'; }); })();
36939
36940 /** PURE_IMPORTS_START PURE_IMPORTS_END */
36941 function isObject(x) {
36942 return x !== null && typeof x === 'object';
36943 }
36944
36945 /** PURE_IMPORTS_START PURE_IMPORTS_END */
36946 var UnsubscriptionErrorImpl = /*@__PURE__*/ (function () {
36947 function UnsubscriptionErrorImpl(errors) {
36948 Error.call(this);
36949 this.message = errors ?
36950 errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { return i + 1 + ") " + err.toString(); }).join('\n ') : '';
36951 this.name = 'UnsubscriptionError';
36952 this.errors = errors;
36953 return this;
36954 }
36955 UnsubscriptionErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
36956 return UnsubscriptionErrorImpl;
36957 })();
36958 var UnsubscriptionError = UnsubscriptionErrorImpl;
36959
36960 /** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_UnsubscriptionError PURE_IMPORTS_END */
36961 var Subscription = /*@__PURE__*/ (function () {
36962 function Subscription(unsubscribe) {
36963 this.closed = false;
36964 this._parentOrParents = null;
36965 this._subscriptions = null;
36966 if (unsubscribe) {
36967 this._unsubscribe = unsubscribe;
36968 }
36969 }
36970 Subscription.prototype.unsubscribe = function () {
36971 var errors;
36972 if (this.closed) {
36973 return;
36974 }
36975 var _a = this, _parentOrParents = _a._parentOrParents, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions;
36976 this.closed = true;
36977 this._parentOrParents = null;
36978 this._subscriptions = null;
36979 if (_parentOrParents instanceof Subscription) {
36980 _parentOrParents.remove(this);
36981 }
36982 else if (_parentOrParents !== null) {
36983 for (var index = 0; index < _parentOrParents.length; ++index) {
36984 var parent_1 = _parentOrParents[index];
36985 parent_1.remove(this);
36986 }
36987 }
36988 if (isFunction(_unsubscribe)) {
36989 try {
36990 _unsubscribe.call(this);
36991 }
36992 catch (e) {
36993 errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e];
36994 }
36995 }
36996 if (isArray(_subscriptions)) {
36997 var index = -1;
36998 var len = _subscriptions.length;
36999 while (++index < len) {
37000 var sub = _subscriptions[index];
37001 if (isObject(sub)) {
37002 try {
37003 sub.unsubscribe();
37004 }
37005 catch (e) {
37006 errors = errors || [];
37007 if (e instanceof UnsubscriptionError) {
37008 errors = errors.concat(flattenUnsubscriptionErrors(e.errors));
37009 }
37010 else {
37011 errors.push(e);
37012 }
37013 }
37014 }
37015 }
37016 }
37017 if (errors) {
37018 throw new UnsubscriptionError(errors);
37019 }
37020 };
37021 Subscription.prototype.add = function (teardown) {
37022 var subscription = teardown;
37023 if (!teardown) {
37024 return Subscription.EMPTY;
37025 }
37026 switch (typeof teardown) {
37027 case 'function':
37028 subscription = new Subscription(teardown);
37029 case 'object':
37030 if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') {
37031 return subscription;
37032 }
37033 else if (this.closed) {
37034 subscription.unsubscribe();
37035 return subscription;
37036 }
37037 else if (!(subscription instanceof Subscription)) {
37038 var tmp = subscription;
37039 subscription = new Subscription();
37040 subscription._subscriptions = [tmp];
37041 }
37042 break;
37043 default: {
37044 throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');
37045 }
37046 }
37047 var _parentOrParents = subscription._parentOrParents;
37048 if (_parentOrParents === null) {
37049 subscription._parentOrParents = this;
37050 }
37051 else if (_parentOrParents instanceof Subscription) {
37052 if (_parentOrParents === this) {
37053 return subscription;
37054 }
37055 subscription._parentOrParents = [_parentOrParents, this];
37056 }
37057 else if (_parentOrParents.indexOf(this) === -1) {
37058 _parentOrParents.push(this);
37059 }
37060 else {
37061 return subscription;
37062 }
37063 var subscriptions = this._subscriptions;
37064 if (subscriptions === null) {
37065 this._subscriptions = [subscription];
37066 }
37067 else {
37068 subscriptions.push(subscription);
37069 }
37070 return subscription;
37071 };
37072 Subscription.prototype.remove = function (subscription) {
37073 var subscriptions = this._subscriptions;
37074 if (subscriptions) {
37075 var subscriptionIndex = subscriptions.indexOf(subscription);
37076 if (subscriptionIndex !== -1) {
37077 subscriptions.splice(subscriptionIndex, 1);
37078 }
37079 }
37080 };
37081 Subscription.EMPTY = (function (empty) {
37082 empty.closed = true;
37083 return empty;
37084 }(new Subscription()));
37085 return Subscription;
37086 }());
37087 function flattenUnsubscriptionErrors(errors) {
37088 return errors.reduce(function (errs, err) { return errs.concat((err instanceof UnsubscriptionError) ? err.errors : err); }, []);
37089 }
37090
37091 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37092 var rxSubscriber = /*@__PURE__*/ (function () {
37093 return typeof Symbol === 'function'
37094 ? /*@__PURE__*/ Symbol('rxSubscriber')
37095 : '@@rxSubscriber_' + /*@__PURE__*/ Math.random();
37096 })();
37097
37098 /** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */
37099 var Subscriber = /*@__PURE__*/ (function (_super) {
37100 __extends(Subscriber, _super);
37101 function Subscriber(destinationOrNext, error, complete) {
37102 var _this = _super.call(this) || this;
37103 _this.syncErrorValue = null;
37104 _this.syncErrorThrown = false;
37105 _this.syncErrorThrowable = false;
37106 _this.isStopped = false;
37107 switch (arguments.length) {
37108 case 0:
37109 _this.destination = empty;
37110 break;
37111 case 1:
37112 if (!destinationOrNext) {
37113 _this.destination = empty;
37114 break;
37115 }
37116 if (typeof destinationOrNext === 'object') {
37117 if (destinationOrNext instanceof Subscriber) {
37118 _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable;
37119 _this.destination = destinationOrNext;
37120 destinationOrNext.add(_this);
37121 }
37122 else {
37123 _this.syncErrorThrowable = true;
37124 _this.destination = new SafeSubscriber(_this, destinationOrNext);
37125 }
37126 break;
37127 }
37128 default:
37129 _this.syncErrorThrowable = true;
37130 _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete);
37131 break;
37132 }
37133 return _this;
37134 }
37135 Subscriber.prototype[rxSubscriber] = function () { return this; };
37136 Subscriber.create = function (next, error, complete) {
37137 var subscriber = new Subscriber(next, error, complete);
37138 subscriber.syncErrorThrowable = false;
37139 return subscriber;
37140 };
37141 Subscriber.prototype.next = function (value) {
37142 if (!this.isStopped) {
37143 this._next(value);
37144 }
37145 };
37146 Subscriber.prototype.error = function (err) {
37147 if (!this.isStopped) {
37148 this.isStopped = true;
37149 this._error(err);
37150 }
37151 };
37152 Subscriber.prototype.complete = function () {
37153 if (!this.isStopped) {
37154 this.isStopped = true;
37155 this._complete();
37156 }
37157 };
37158 Subscriber.prototype.unsubscribe = function () {
37159 if (this.closed) {
37160 return;
37161 }
37162 this.isStopped = true;
37163 _super.prototype.unsubscribe.call(this);
37164 };
37165 Subscriber.prototype._next = function (value) {
37166 this.destination.next(value);
37167 };
37168 Subscriber.prototype._error = function (err) {
37169 this.destination.error(err);
37170 this.unsubscribe();
37171 };
37172 Subscriber.prototype._complete = function () {
37173 this.destination.complete();
37174 this.unsubscribe();
37175 };
37176 Subscriber.prototype._unsubscribeAndRecycle = function () {
37177 var _parentOrParents = this._parentOrParents;
37178 this._parentOrParents = null;
37179 this.unsubscribe();
37180 this.closed = false;
37181 this.isStopped = false;
37182 this._parentOrParents = _parentOrParents;
37183 return this;
37184 };
37185 return Subscriber;
37186 }(Subscription));
37187 var SafeSubscriber = /*@__PURE__*/ (function (_super) {
37188 __extends(SafeSubscriber, _super);
37189 function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) {
37190 var _this = _super.call(this) || this;
37191 _this._parentSubscriber = _parentSubscriber;
37192 var next;
37193 var context = _this;
37194 if (isFunction(observerOrNext)) {
37195 next = observerOrNext;
37196 }
37197 else if (observerOrNext) {
37198 next = observerOrNext.next;
37199 error = observerOrNext.error;
37200 complete = observerOrNext.complete;
37201 if (observerOrNext !== empty) {
37202 context = Object.create(observerOrNext);
37203 if (isFunction(context.unsubscribe)) {
37204 _this.add(context.unsubscribe.bind(context));
37205 }
37206 context.unsubscribe = _this.unsubscribe.bind(_this);
37207 }
37208 }
37209 _this._context = context;
37210 _this._next = next;
37211 _this._error = error;
37212 _this._complete = complete;
37213 return _this;
37214 }
37215 SafeSubscriber.prototype.next = function (value) {
37216 if (!this.isStopped && this._next) {
37217 var _parentSubscriber = this._parentSubscriber;
37218 if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
37219 this.__tryOrUnsub(this._next, value);
37220 }
37221 else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
37222 this.unsubscribe();
37223 }
37224 }
37225 };
37226 SafeSubscriber.prototype.error = function (err) {
37227 if (!this.isStopped) {
37228 var _parentSubscriber = this._parentSubscriber;
37229 var useDeprecatedSynchronousErrorHandling = config.useDeprecatedSynchronousErrorHandling;
37230 if (this._error) {
37231 if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
37232 this.__tryOrUnsub(this._error, err);
37233 this.unsubscribe();
37234 }
37235 else {
37236 this.__tryOrSetError(_parentSubscriber, this._error, err);
37237 this.unsubscribe();
37238 }
37239 }
37240 else if (!_parentSubscriber.syncErrorThrowable) {
37241 this.unsubscribe();
37242 if (useDeprecatedSynchronousErrorHandling) {
37243 throw err;
37244 }
37245 hostReportError(err);
37246 }
37247 else {
37248 if (useDeprecatedSynchronousErrorHandling) {
37249 _parentSubscriber.syncErrorValue = err;
37250 _parentSubscriber.syncErrorThrown = true;
37251 }
37252 else {
37253 hostReportError(err);
37254 }
37255 this.unsubscribe();
37256 }
37257 }
37258 };
37259 SafeSubscriber.prototype.complete = function () {
37260 var _this = this;
37261 if (!this.isStopped) {
37262 var _parentSubscriber = this._parentSubscriber;
37263 if (this._complete) {
37264 var wrappedComplete = function () { return _this._complete.call(_this._context); };
37265 if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
37266 this.__tryOrUnsub(wrappedComplete);
37267 this.unsubscribe();
37268 }
37269 else {
37270 this.__tryOrSetError(_parentSubscriber, wrappedComplete);
37271 this.unsubscribe();
37272 }
37273 }
37274 else {
37275 this.unsubscribe();
37276 }
37277 }
37278 };
37279 SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) {
37280 try {
37281 fn.call(this._context, value);
37282 }
37283 catch (err) {
37284 this.unsubscribe();
37285 if (config.useDeprecatedSynchronousErrorHandling) {
37286 throw err;
37287 }
37288 else {
37289 hostReportError(err);
37290 }
37291 }
37292 };
37293 SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) {
37294 if (!config.useDeprecatedSynchronousErrorHandling) {
37295 throw new Error('bad call');
37296 }
37297 try {
37298 fn.call(this._context, value);
37299 }
37300 catch (err) {
37301 if (config.useDeprecatedSynchronousErrorHandling) {
37302 parent.syncErrorValue = err;
37303 parent.syncErrorThrown = true;
37304 return true;
37305 }
37306 else {
37307 hostReportError(err);
37308 return true;
37309 }
37310 }
37311 return false;
37312 };
37313 SafeSubscriber.prototype._unsubscribe = function () {
37314 var _parentSubscriber = this._parentSubscriber;
37315 this._context = null;
37316 this._parentSubscriber = null;
37317 _parentSubscriber.unsubscribe();
37318 };
37319 return SafeSubscriber;
37320 }(Subscriber));
37321
37322 /** PURE_IMPORTS_START _Subscriber PURE_IMPORTS_END */
37323 function canReportError(observer) {
37324 while (observer) {
37325 var _a = observer, closed_1 = _a.closed, destination = _a.destination, isStopped = _a.isStopped;
37326 if (closed_1 || isStopped) {
37327 return false;
37328 }
37329 else if (destination && destination instanceof Subscriber) {
37330 observer = destination;
37331 }
37332 else {
37333 observer = null;
37334 }
37335 }
37336 return true;
37337 }
37338
37339 /** PURE_IMPORTS_START _Subscriber,_symbol_rxSubscriber,_Observer PURE_IMPORTS_END */
37340 function toSubscriber(nextOrObserver, error, complete) {
37341 if (nextOrObserver) {
37342 if (nextOrObserver instanceof Subscriber) {
37343 return nextOrObserver;
37344 }
37345 if (nextOrObserver[rxSubscriber]) {
37346 return nextOrObserver[rxSubscriber]();
37347 }
37348 }
37349 if (!nextOrObserver && !error && !complete) {
37350 return new Subscriber(empty);
37351 }
37352 return new Subscriber(nextOrObserver, error, complete);
37353 }
37354
37355 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37356 var observable = /*@__PURE__*/ (function () { return typeof Symbol === 'function' && Symbol.observable || '@@observable'; })();
37357
37358 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37359 function noop$1() { }
37360
37361 /** PURE_IMPORTS_START _noop PURE_IMPORTS_END */
37362 function pipeFromArray(fns) {
37363 if (!fns) {
37364 return noop$1;
37365 }
37366 if (fns.length === 1) {
37367 return fns[0];
37368 }
37369 return function piped(input) {
37370 return fns.reduce(function (prev, fn) { return fn(prev); }, input);
37371 };
37372 }
37373
37374 /** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */
37375 var Observable = /*@__PURE__*/ (function () {
37376 function Observable(subscribe) {
37377 this._isScalar = false;
37378 if (subscribe) {
37379 this._subscribe = subscribe;
37380 }
37381 }
37382 Observable.prototype.lift = function (operator) {
37383 var observable = new Observable();
37384 observable.source = this;
37385 observable.operator = operator;
37386 return observable;
37387 };
37388 Observable.prototype.subscribe = function (observerOrNext, error, complete) {
37389 var operator = this.operator;
37390 var sink = toSubscriber(observerOrNext, error, complete);
37391 if (operator) {
37392 sink.add(operator.call(sink, this.source));
37393 }
37394 else {
37395 sink.add(this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ?
37396 this._subscribe(sink) :
37397 this._trySubscribe(sink));
37398 }
37399 if (config.useDeprecatedSynchronousErrorHandling) {
37400 if (sink.syncErrorThrowable) {
37401 sink.syncErrorThrowable = false;
37402 if (sink.syncErrorThrown) {
37403 throw sink.syncErrorValue;
37404 }
37405 }
37406 }
37407 return sink;
37408 };
37409 Observable.prototype._trySubscribe = function (sink) {
37410 try {
37411 return this._subscribe(sink);
37412 }
37413 catch (err) {
37414 if (config.useDeprecatedSynchronousErrorHandling) {
37415 sink.syncErrorThrown = true;
37416 sink.syncErrorValue = err;
37417 }
37418 if (canReportError(sink)) {
37419 sink.error(err);
37420 }
37421 else {
37422 console.warn(err);
37423 }
37424 }
37425 };
37426 Observable.prototype.forEach = function (next, promiseCtor) {
37427 var _this = this;
37428 promiseCtor = getPromiseCtor(promiseCtor);
37429 return new promiseCtor(function (resolve, reject) {
37430 var subscription;
37431 subscription = _this.subscribe(function (value) {
37432 try {
37433 next(value);
37434 }
37435 catch (err) {
37436 reject(err);
37437 if (subscription) {
37438 subscription.unsubscribe();
37439 }
37440 }
37441 }, reject, resolve);
37442 });
37443 };
37444 Observable.prototype._subscribe = function (subscriber) {
37445 var source = this.source;
37446 return source && source.subscribe(subscriber);
37447 };
37448 Observable.prototype[observable] = function () {
37449 return this;
37450 };
37451 Observable.prototype.pipe = function () {
37452 var operations = [];
37453 for (var _i = 0; _i < arguments.length; _i++) {
37454 operations[_i] = arguments[_i];
37455 }
37456 if (operations.length === 0) {
37457 return this;
37458 }
37459 return pipeFromArray(operations)(this);
37460 };
37461 Observable.prototype.toPromise = function (promiseCtor) {
37462 var _this = this;
37463 promiseCtor = getPromiseCtor(promiseCtor);
37464 return new promiseCtor(function (resolve, reject) {
37465 var value;
37466 _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); });
37467 });
37468 };
37469 Observable.create = function (subscribe) {
37470 return new Observable(subscribe);
37471 };
37472 return Observable;
37473 }());
37474 function getPromiseCtor(promiseCtor) {
37475 if (!promiseCtor) {
37476 promiseCtor = Promise;
37477 }
37478 if (!promiseCtor) {
37479 throw new Error('no Promise impl found');
37480 }
37481 return promiseCtor;
37482 }
37483
37484 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37485 var ObjectUnsubscribedErrorImpl = /*@__PURE__*/ (function () {
37486 function ObjectUnsubscribedErrorImpl() {
37487 Error.call(this);
37488 this.message = 'object unsubscribed';
37489 this.name = 'ObjectUnsubscribedError';
37490 return this;
37491 }
37492 ObjectUnsubscribedErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
37493 return ObjectUnsubscribedErrorImpl;
37494 })();
37495 var ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl;
37496
37497 /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */
37498 var SubjectSubscription = /*@__PURE__*/ (function (_super) {
37499 __extends(SubjectSubscription, _super);
37500 function SubjectSubscription(subject, subscriber) {
37501 var _this = _super.call(this) || this;
37502 _this.subject = subject;
37503 _this.subscriber = subscriber;
37504 _this.closed = false;
37505 return _this;
37506 }
37507 SubjectSubscription.prototype.unsubscribe = function () {
37508 if (this.closed) {
37509 return;
37510 }
37511 this.closed = true;
37512 var subject = this.subject;
37513 var observers = subject.observers;
37514 this.subject = null;
37515 if (!observers || observers.length === 0 || subject.isStopped || subject.closed) {
37516 return;
37517 }
37518 var subscriberIndex = observers.indexOf(this.subscriber);
37519 if (subscriberIndex !== -1) {
37520 observers.splice(subscriberIndex, 1);
37521 }
37522 };
37523 return SubjectSubscription;
37524 }(Subscription));
37525
37526 /** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */
37527 var SubjectSubscriber = /*@__PURE__*/ (function (_super) {
37528 __extends(SubjectSubscriber, _super);
37529 function SubjectSubscriber(destination) {
37530 var _this = _super.call(this, destination) || this;
37531 _this.destination = destination;
37532 return _this;
37533 }
37534 return SubjectSubscriber;
37535 }(Subscriber));
37536 var Subject = /*@__PURE__*/ (function (_super) {
37537 __extends(Subject, _super);
37538 function Subject() {
37539 var _this = _super.call(this) || this;
37540 _this.observers = [];
37541 _this.closed = false;
37542 _this.isStopped = false;
37543 _this.hasError = false;
37544 _this.thrownError = null;
37545 return _this;
37546 }
37547 Subject.prototype[rxSubscriber] = function () {
37548 return new SubjectSubscriber(this);
37549 };
37550 Subject.prototype.lift = function (operator) {
37551 var subject = new AnonymousSubject(this, this);
37552 subject.operator = operator;
37553 return subject;
37554 };
37555 Subject.prototype.next = function (value) {
37556 if (this.closed) {
37557 throw new ObjectUnsubscribedError();
37558 }
37559 if (!this.isStopped) {
37560 var observers = this.observers;
37561 var len = observers.length;
37562 var copy = observers.slice();
37563 for (var i = 0; i < len; i++) {
37564 copy[i].next(value);
37565 }
37566 }
37567 };
37568 Subject.prototype.error = function (err) {
37569 if (this.closed) {
37570 throw new ObjectUnsubscribedError();
37571 }
37572 this.hasError = true;
37573 this.thrownError = err;
37574 this.isStopped = true;
37575 var observers = this.observers;
37576 var len = observers.length;
37577 var copy = observers.slice();
37578 for (var i = 0; i < len; i++) {
37579 copy[i].error(err);
37580 }
37581 this.observers.length = 0;
37582 };
37583 Subject.prototype.complete = function () {
37584 if (this.closed) {
37585 throw new ObjectUnsubscribedError();
37586 }
37587 this.isStopped = true;
37588 var observers = this.observers;
37589 var len = observers.length;
37590 var copy = observers.slice();
37591 for (var i = 0; i < len; i++) {
37592 copy[i].complete();
37593 }
37594 this.observers.length = 0;
37595 };
37596 Subject.prototype.unsubscribe = function () {
37597 this.isStopped = true;
37598 this.closed = true;
37599 this.observers = null;
37600 };
37601 Subject.prototype._trySubscribe = function (subscriber) {
37602 if (this.closed) {
37603 throw new ObjectUnsubscribedError();
37604 }
37605 else {
37606 return _super.prototype._trySubscribe.call(this, subscriber);
37607 }
37608 };
37609 Subject.prototype._subscribe = function (subscriber) {
37610 if (this.closed) {
37611 throw new ObjectUnsubscribedError();
37612 }
37613 else if (this.hasError) {
37614 subscriber.error(this.thrownError);
37615 return Subscription.EMPTY;
37616 }
37617 else if (this.isStopped) {
37618 subscriber.complete();
37619 return Subscription.EMPTY;
37620 }
37621 else {
37622 this.observers.push(subscriber);
37623 return new SubjectSubscription(this, subscriber);
37624 }
37625 };
37626 Subject.prototype.asObservable = function () {
37627 var observable = new Observable();
37628 observable.source = this;
37629 return observable;
37630 };
37631 Subject.create = function (destination, source) {
37632 return new AnonymousSubject(destination, source);
37633 };
37634 return Subject;
37635 }(Observable));
37636 var AnonymousSubject = /*@__PURE__*/ (function (_super) {
37637 __extends(AnonymousSubject, _super);
37638 function AnonymousSubject(destination, source) {
37639 var _this = _super.call(this) || this;
37640 _this.destination = destination;
37641 _this.source = source;
37642 return _this;
37643 }
37644 AnonymousSubject.prototype.next = function (value) {
37645 var destination = this.destination;
37646 if (destination && destination.next) {
37647 destination.next(value);
37648 }
37649 };
37650 AnonymousSubject.prototype.error = function (err) {
37651 var destination = this.destination;
37652 if (destination && destination.error) {
37653 this.destination.error(err);
37654 }
37655 };
37656 AnonymousSubject.prototype.complete = function () {
37657 var destination = this.destination;
37658 if (destination && destination.complete) {
37659 this.destination.complete();
37660 }
37661 };
37662 AnonymousSubject.prototype._subscribe = function (subscriber) {
37663 var source = this.source;
37664 if (source) {
37665 return this.source.subscribe(subscriber);
37666 }
37667 else {
37668 return Subscription.EMPTY;
37669 }
37670 };
37671 return AnonymousSubject;
37672 }(Subject));
37673
37674 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
37675 function refCount() {
37676 return function refCountOperatorFunction(source) {
37677 return source.lift(new RefCountOperator(source));
37678 };
37679 }
37680 var RefCountOperator = /*@__PURE__*/ (function () {
37681 function RefCountOperator(connectable) {
37682 this.connectable = connectable;
37683 }
37684 RefCountOperator.prototype.call = function (subscriber, source) {
37685 var connectable = this.connectable;
37686 connectable._refCount++;
37687 var refCounter = new RefCountSubscriber(subscriber, connectable);
37688 var subscription = source.subscribe(refCounter);
37689 if (!refCounter.closed) {
37690 refCounter.connection = connectable.connect();
37691 }
37692 return subscription;
37693 };
37694 return RefCountOperator;
37695 }());
37696 var RefCountSubscriber = /*@__PURE__*/ (function (_super) {
37697 __extends(RefCountSubscriber, _super);
37698 function RefCountSubscriber(destination, connectable) {
37699 var _this = _super.call(this, destination) || this;
37700 _this.connectable = connectable;
37701 return _this;
37702 }
37703 RefCountSubscriber.prototype._unsubscribe = function () {
37704 var connectable = this.connectable;
37705 if (!connectable) {
37706 this.connection = null;
37707 return;
37708 }
37709 this.connectable = null;
37710 var refCount = connectable._refCount;
37711 if (refCount <= 0) {
37712 this.connection = null;
37713 return;
37714 }
37715 connectable._refCount = refCount - 1;
37716 if (refCount > 1) {
37717 this.connection = null;
37718 return;
37719 }
37720 var connection = this.connection;
37721 var sharedConnection = connectable._connection;
37722 this.connection = null;
37723 if (sharedConnection && (!connection || sharedConnection === connection)) {
37724 sharedConnection.unsubscribe();
37725 }
37726 };
37727 return RefCountSubscriber;
37728 }(Subscriber));
37729
37730 /** PURE_IMPORTS_START tslib,_Subject,_Observable,_Subscriber,_Subscription,_operators_refCount PURE_IMPORTS_END */
37731 var ConnectableObservable = /*@__PURE__*/ (function (_super) {
37732 __extends(ConnectableObservable, _super);
37733 function ConnectableObservable(source, subjectFactory) {
37734 var _this = _super.call(this) || this;
37735 _this.source = source;
37736 _this.subjectFactory = subjectFactory;
37737 _this._refCount = 0;
37738 _this._isComplete = false;
37739 return _this;
37740 }
37741 ConnectableObservable.prototype._subscribe = function (subscriber) {
37742 return this.getSubject().subscribe(subscriber);
37743 };
37744 ConnectableObservable.prototype.getSubject = function () {
37745 var subject = this._subject;
37746 if (!subject || subject.isStopped) {
37747 this._subject = this.subjectFactory();
37748 }
37749 return this._subject;
37750 };
37751 ConnectableObservable.prototype.connect = function () {
37752 var connection = this._connection;
37753 if (!connection) {
37754 this._isComplete = false;
37755 connection = this._connection = new Subscription();
37756 connection.add(this.source
37757 .subscribe(new ConnectableSubscriber(this.getSubject(), this)));
37758 if (connection.closed) {
37759 this._connection = null;
37760 connection = Subscription.EMPTY;
37761 }
37762 }
37763 return connection;
37764 };
37765 ConnectableObservable.prototype.refCount = function () {
37766 return refCount()(this);
37767 };
37768 return ConnectableObservable;
37769 }(Observable));
37770 var connectableObservableDescriptor = /*@__PURE__*/ (function () {
37771 var connectableProto = ConnectableObservable.prototype;
37772 return {
37773 operator: { value: null },
37774 _refCount: { value: 0, writable: true },
37775 _subject: { value: null, writable: true },
37776 _connection: { value: null, writable: true },
37777 _subscribe: { value: connectableProto._subscribe },
37778 _isComplete: { value: connectableProto._isComplete, writable: true },
37779 getSubject: { value: connectableProto.getSubject },
37780 connect: { value: connectableProto.connect },
37781 refCount: { value: connectableProto.refCount }
37782 };
37783 })();
37784 var ConnectableSubscriber = /*@__PURE__*/ (function (_super) {
37785 __extends(ConnectableSubscriber, _super);
37786 function ConnectableSubscriber(destination, connectable) {
37787 var _this = _super.call(this, destination) || this;
37788 _this.connectable = connectable;
37789 return _this;
37790 }
37791 ConnectableSubscriber.prototype._error = function (err) {
37792 this._unsubscribe();
37793 _super.prototype._error.call(this, err);
37794 };
37795 ConnectableSubscriber.prototype._complete = function () {
37796 this.connectable._isComplete = true;
37797 this._unsubscribe();
37798 _super.prototype._complete.call(this);
37799 };
37800 ConnectableSubscriber.prototype._unsubscribe = function () {
37801 var connectable = this.connectable;
37802 if (connectable) {
37803 this.connectable = null;
37804 var connection = connectable._connection;
37805 connectable._refCount = 0;
37806 connectable._subject = null;
37807 connectable._connection = null;
37808 if (connection) {
37809 connection.unsubscribe();
37810 }
37811 }
37812 };
37813 return ConnectableSubscriber;
37814 }(SubjectSubscriber));
37815
37816 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37817 function isScheduler(value) {
37818 return value && typeof value.schedule === 'function';
37819 }
37820
37821 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37822 var subscribeToArray = function (array) {
37823 return function (subscriber) {
37824 for (var i = 0, len = array.length; i < len && !subscriber.closed; i++) {
37825 subscriber.next(array[i]);
37826 }
37827 subscriber.complete();
37828 };
37829 };
37830
37831 /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */
37832 function scheduleArray(input, scheduler) {
37833 return new Observable(function (subscriber) {
37834 var sub = new Subscription();
37835 var i = 0;
37836 sub.add(scheduler.schedule(function () {
37837 if (i === input.length) {
37838 subscriber.complete();
37839 return;
37840 }
37841 subscriber.next(input[i++]);
37842 if (!subscriber.closed) {
37843 sub.add(this.schedule());
37844 }
37845 }));
37846 return sub;
37847 });
37848 }
37849
37850 /** PURE_IMPORTS_START _Observable,_util_subscribeToArray,_scheduled_scheduleArray PURE_IMPORTS_END */
37851 function fromArray(input, scheduler) {
37852 if (!scheduler) {
37853 return new Observable(subscribeToArray(input));
37854 }
37855 else {
37856 return scheduleArray(input, scheduler);
37857 }
37858 }
37859
37860 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37861 function identity(x) {
37862 return x;
37863 }
37864
37865 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
37866 function map(project, thisArg) {
37867 return function mapOperation(source) {
37868 if (typeof project !== 'function') {
37869 throw new TypeError('argument is not a function. Are you looking for `mapTo()`?');
37870 }
37871 return source.lift(new MapOperator(project, thisArg));
37872 };
37873 }
37874 var MapOperator = /*@__PURE__*/ (function () {
37875 function MapOperator(project, thisArg) {
37876 this.project = project;
37877 this.thisArg = thisArg;
37878 }
37879 MapOperator.prototype.call = function (subscriber, source) {
37880 return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg));
37881 };
37882 return MapOperator;
37883 }());
37884 var MapSubscriber = /*@__PURE__*/ (function (_super) {
37885 __extends(MapSubscriber, _super);
37886 function MapSubscriber(destination, project, thisArg) {
37887 var _this = _super.call(this, destination) || this;
37888 _this.project = project;
37889 _this.count = 0;
37890 _this.thisArg = thisArg || _this;
37891 return _this;
37892 }
37893 MapSubscriber.prototype._next = function (value) {
37894 var result;
37895 try {
37896 result = this.project.call(this.thisArg, value, this.count++);
37897 }
37898 catch (err) {
37899 this.destination.error(err);
37900 return;
37901 }
37902 this.destination.next(result);
37903 };
37904 return MapSubscriber;
37905 }(Subscriber));
37906
37907 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
37908 var OuterSubscriber = /*@__PURE__*/ (function (_super) {
37909 __extends(OuterSubscriber, _super);
37910 function OuterSubscriber() {
37911 return _super !== null && _super.apply(this, arguments) || this;
37912 }
37913 OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) {
37914 this.destination.next(innerValue);
37915 };
37916 OuterSubscriber.prototype.notifyError = function (error, innerSub) {
37917 this.destination.error(error);
37918 };
37919 OuterSubscriber.prototype.notifyComplete = function (innerSub) {
37920 this.destination.complete();
37921 };
37922 return OuterSubscriber;
37923 }(Subscriber));
37924
37925 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
37926 var InnerSubscriber = /*@__PURE__*/ (function (_super) {
37927 __extends(InnerSubscriber, _super);
37928 function InnerSubscriber(parent, outerValue, outerIndex) {
37929 var _this = _super.call(this) || this;
37930 _this.parent = parent;
37931 _this.outerValue = outerValue;
37932 _this.outerIndex = outerIndex;
37933 _this.index = 0;
37934 return _this;
37935 }
37936 InnerSubscriber.prototype._next = function (value) {
37937 this.parent.notifyNext(this.outerValue, value, this.outerIndex, this.index++, this);
37938 };
37939 InnerSubscriber.prototype._error = function (error) {
37940 this.parent.notifyError(error, this);
37941 this.unsubscribe();
37942 };
37943 InnerSubscriber.prototype._complete = function () {
37944 this.parent.notifyComplete(this);
37945 this.unsubscribe();
37946 };
37947 return InnerSubscriber;
37948 }(Subscriber));
37949
37950 /** PURE_IMPORTS_START _hostReportError PURE_IMPORTS_END */
37951 var subscribeToPromise = function (promise) {
37952 return function (subscriber) {
37953 promise.then(function (value) {
37954 if (!subscriber.closed) {
37955 subscriber.next(value);
37956 subscriber.complete();
37957 }
37958 }, function (err) { return subscriber.error(err); })
37959 .then(null, hostReportError);
37960 return subscriber;
37961 };
37962 };
37963
37964 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37965 function getSymbolIterator$1() {
37966 if (typeof Symbol !== 'function' || !Symbol.iterator) {
37967 return '@@iterator';
37968 }
37969 return Symbol.iterator;
37970 }
37971 var iterator = /*@__PURE__*/ getSymbolIterator$1();
37972
37973 /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */
37974 var subscribeToIterable = function (iterable) {
37975 return function (subscriber) {
37976 var iterator$1 = iterable[iterator]();
37977 do {
37978 var item = iterator$1.next();
37979 if (item.done) {
37980 subscriber.complete();
37981 break;
37982 }
37983 subscriber.next(item.value);
37984 if (subscriber.closed) {
37985 break;
37986 }
37987 } while (true);
37988 if (typeof iterator$1.return === 'function') {
37989 subscriber.add(function () {
37990 if (iterator$1.return) {
37991 iterator$1.return();
37992 }
37993 });
37994 }
37995 return subscriber;
37996 };
37997 };
37998
37999 /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */
38000 var subscribeToObservable = function (obj) {
38001 return function (subscriber) {
38002 var obs = obj[observable]();
38003 if (typeof obs.subscribe !== 'function') {
38004 throw new TypeError('Provided object does not correctly implement Symbol.observable');
38005 }
38006 else {
38007 return obs.subscribe(subscriber);
38008 }
38009 };
38010 };
38011
38012 /** PURE_IMPORTS_START PURE_IMPORTS_END */
38013 var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; });
38014
38015 /** PURE_IMPORTS_START PURE_IMPORTS_END */
38016 function isPromise$2(value) {
38017 return !!value && typeof value.subscribe !== 'function' && typeof value.then === 'function';
38018 }
38019
38020 /** PURE_IMPORTS_START _subscribeToArray,_subscribeToPromise,_subscribeToIterable,_subscribeToObservable,_isArrayLike,_isPromise,_isObject,_symbol_iterator,_symbol_observable PURE_IMPORTS_END */
38021 var subscribeTo = function (result) {
38022 if (!!result && typeof result[observable] === 'function') {
38023 return subscribeToObservable(result);
38024 }
38025 else if (isArrayLike(result)) {
38026 return subscribeToArray(result);
38027 }
38028 else if (isPromise$2(result)) {
38029 return subscribeToPromise(result);
38030 }
38031 else if (!!result && typeof result[iterator] === 'function') {
38032 return subscribeToIterable(result);
38033 }
38034 else {
38035 var value = isObject(result) ? 'an invalid object' : "'" + result + "'";
38036 var msg = "You provided " + value + " where a stream was expected."
38037 + ' You can provide an Observable, Promise, Array, or Iterable.';
38038 throw new TypeError(msg);
38039 }
38040 };
38041
38042 /** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo,_Observable PURE_IMPORTS_END */
38043 function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, innerSubscriber) {
38044 if (innerSubscriber === void 0) {
38045 innerSubscriber = new InnerSubscriber(outerSubscriber, outerValue, outerIndex);
38046 }
38047 if (innerSubscriber.closed) {
38048 return undefined;
38049 }
38050 if (result instanceof Observable) {
38051 return result.subscribe(innerSubscriber);
38052 }
38053 return subscribeTo(result)(innerSubscriber);
38054 }
38055
38056 /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_observable PURE_IMPORTS_END */
38057 function scheduleObservable(input, scheduler) {
38058 return new Observable(function (subscriber) {
38059 var sub = new Subscription();
38060 sub.add(scheduler.schedule(function () {
38061 var observable$1 = input[observable]();
38062 sub.add(observable$1.subscribe({
38063 next: function (value) { sub.add(scheduler.schedule(function () { return subscriber.next(value); })); },
38064 error: function (err) { sub.add(scheduler.schedule(function () { return subscriber.error(err); })); },
38065 complete: function () { sub.add(scheduler.schedule(function () { return subscriber.complete(); })); },
38066 }));
38067 }));
38068 return sub;
38069 });
38070 }
38071
38072 /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */
38073 function schedulePromise(input, scheduler) {
38074 return new Observable(function (subscriber) {
38075 var sub = new Subscription();
38076 sub.add(scheduler.schedule(function () {
38077 return input.then(function (value) {
38078 sub.add(scheduler.schedule(function () {
38079 subscriber.next(value);
38080 sub.add(scheduler.schedule(function () { return subscriber.complete(); }));
38081 }));
38082 }, function (err) {
38083 sub.add(scheduler.schedule(function () { return subscriber.error(err); }));
38084 });
38085 }));
38086 return sub;
38087 });
38088 }
38089
38090 /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_iterator PURE_IMPORTS_END */
38091 function scheduleIterable(input, scheduler) {
38092 if (!input) {
38093 throw new Error('Iterable cannot be null');
38094 }
38095 return new Observable(function (subscriber) {
38096 var sub = new Subscription();
38097 var iterator$1;
38098 sub.add(function () {
38099 if (iterator$1 && typeof iterator$1.return === 'function') {
38100 iterator$1.return();
38101 }
38102 });
38103 sub.add(scheduler.schedule(function () {
38104 iterator$1 = input[iterator]();
38105 sub.add(scheduler.schedule(function () {
38106 if (subscriber.closed) {
38107 return;
38108 }
38109 var value;
38110 var done;
38111 try {
38112 var result = iterator$1.next();
38113 value = result.value;
38114 done = result.done;
38115 }
38116 catch (err) {
38117 subscriber.error(err);
38118 return;
38119 }
38120 if (done) {
38121 subscriber.complete();
38122 }
38123 else {
38124 subscriber.next(value);
38125 this.schedule();
38126 }
38127 }));
38128 }));
38129 return sub;
38130 });
38131 }
38132
38133 /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */
38134 function isInteropObservable(input) {
38135 return input && typeof input[observable] === 'function';
38136 }
38137
38138 /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */
38139 function isIterable(input) {
38140 return input && typeof input[iterator] === 'function';
38141 }
38142
38143 /** PURE_IMPORTS_START _scheduleObservable,_schedulePromise,_scheduleArray,_scheduleIterable,_util_isInteropObservable,_util_isPromise,_util_isArrayLike,_util_isIterable PURE_IMPORTS_END */
38144 function scheduled(input, scheduler) {
38145 if (input != null) {
38146 if (isInteropObservable(input)) {
38147 return scheduleObservable(input, scheduler);
38148 }
38149 else if (isPromise$2(input)) {
38150 return schedulePromise(input, scheduler);
38151 }
38152 else if (isArrayLike(input)) {
38153 return scheduleArray(input, scheduler);
38154 }
38155 else if (isIterable(input) || typeof input === 'string') {
38156 return scheduleIterable(input, scheduler);
38157 }
38158 }
38159 throw new TypeError((input !== null && typeof input || input) + ' is not observable');
38160 }
38161
38162 /** PURE_IMPORTS_START _Observable,_util_subscribeTo,_scheduled_scheduled PURE_IMPORTS_END */
38163 function from(input, scheduler) {
38164 if (!scheduler) {
38165 if (input instanceof Observable) {
38166 return input;
38167 }
38168 return new Observable(subscribeTo(input));
38169 }
38170 else {
38171 return scheduled(input, scheduler);
38172 }
38173 }
38174
38175 /** PURE_IMPORTS_START tslib,_util_subscribeToResult,_OuterSubscriber,_InnerSubscriber,_map,_observable_from PURE_IMPORTS_END */
38176 function mergeMap(project, resultSelector, concurrent) {
38177 if (concurrent === void 0) {
38178 concurrent = Number.POSITIVE_INFINITY;
38179 }
38180 if (typeof resultSelector === 'function') {
38181 return function (source) { return source.pipe(mergeMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); }, concurrent)); };
38182 }
38183 else if (typeof resultSelector === 'number') {
38184 concurrent = resultSelector;
38185 }
38186 return function (source) { return source.lift(new MergeMapOperator(project, concurrent)); };
38187 }
38188 var MergeMapOperator = /*@__PURE__*/ (function () {
38189 function MergeMapOperator(project, concurrent) {
38190 if (concurrent === void 0) {
38191 concurrent = Number.POSITIVE_INFINITY;
38192 }
38193 this.project = project;
38194 this.concurrent = concurrent;
38195 }
38196 MergeMapOperator.prototype.call = function (observer, source) {
38197 return source.subscribe(new MergeMapSubscriber(observer, this.project, this.concurrent));
38198 };
38199 return MergeMapOperator;
38200 }());
38201 var MergeMapSubscriber = /*@__PURE__*/ (function (_super) {
38202 __extends(MergeMapSubscriber, _super);
38203 function MergeMapSubscriber(destination, project, concurrent) {
38204 if (concurrent === void 0) {
38205 concurrent = Number.POSITIVE_INFINITY;
38206 }
38207 var _this = _super.call(this, destination) || this;
38208 _this.project = project;
38209 _this.concurrent = concurrent;
38210 _this.hasCompleted = false;
38211 _this.buffer = [];
38212 _this.active = 0;
38213 _this.index = 0;
38214 return _this;
38215 }
38216 MergeMapSubscriber.prototype._next = function (value) {
38217 if (this.active < this.concurrent) {
38218 this._tryNext(value);
38219 }
38220 else {
38221 this.buffer.push(value);
38222 }
38223 };
38224 MergeMapSubscriber.prototype._tryNext = function (value) {
38225 var result;
38226 var index = this.index++;
38227 try {
38228 result = this.project(value, index);
38229 }
38230 catch (err) {
38231 this.destination.error(err);
38232 return;
38233 }
38234 this.active++;
38235 this._innerSub(result, value, index);
38236 };
38237 MergeMapSubscriber.prototype._innerSub = function (ish, value, index) {
38238 var innerSubscriber = new InnerSubscriber(this, value, index);
38239 var destination = this.destination;
38240 destination.add(innerSubscriber);
38241 var innerSubscription = subscribeToResult(this, ish, undefined, undefined, innerSubscriber);
38242 if (innerSubscription !== innerSubscriber) {
38243 destination.add(innerSubscription);
38244 }
38245 };
38246 MergeMapSubscriber.prototype._complete = function () {
38247 this.hasCompleted = true;
38248 if (this.active === 0 && this.buffer.length === 0) {
38249 this.destination.complete();
38250 }
38251 this.unsubscribe();
38252 };
38253 MergeMapSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) {
38254 this.destination.next(innerValue);
38255 };
38256 MergeMapSubscriber.prototype.notifyComplete = function (innerSub) {
38257 var buffer = this.buffer;
38258 this.remove(innerSub);
38259 this.active--;
38260 if (buffer.length > 0) {
38261 this._next(buffer.shift());
38262 }
38263 else if (this.active === 0 && this.hasCompleted) {
38264 this.destination.complete();
38265 }
38266 };
38267 return MergeMapSubscriber;
38268 }(OuterSubscriber));
38269
38270 /** PURE_IMPORTS_START _mergeMap,_util_identity PURE_IMPORTS_END */
38271 function mergeAll(concurrent) {
38272 if (concurrent === void 0) {
38273 concurrent = Number.POSITIVE_INFINITY;
38274 }
38275 return mergeMap(identity, concurrent);
38276 }
38277
38278 /** PURE_IMPORTS_START _Observable,_util_isScheduler,_operators_mergeAll,_fromArray PURE_IMPORTS_END */
38279 function merge$1() {
38280 var observables = [];
38281 for (var _i = 0; _i < arguments.length; _i++) {
38282 observables[_i] = arguments[_i];
38283 }
38284 var concurrent = Number.POSITIVE_INFINITY;
38285 var scheduler = null;
38286 var last = observables[observables.length - 1];
38287 if (isScheduler(last)) {
38288 scheduler = observables.pop();
38289 if (observables.length > 1 && typeof observables[observables.length - 1] === 'number') {
38290 concurrent = observables.pop();
38291 }
38292 }
38293 else if (typeof last === 'number') {
38294 concurrent = observables.pop();
38295 }
38296 if (scheduler === null && observables.length === 1 && observables[0] instanceof Observable) {
38297 return observables[0];
38298 }
38299 return mergeAll(concurrent)(fromArray(observables, scheduler));
38300 }
38301
38302 /**
38303 * @license
38304 * Copyright Google LLC All Rights Reserved.
38305 *
38306 * Use of this source code is governed by an MIT-style license that can be
38307 * found in the LICENSE file at https://angular.io/license
38308 */
38309 class EventEmitter_ extends Subject {
38310 constructor(isAsync = false) {
38311 super();
38312 this.__isAsync = isAsync;
38313 }
38314 emit(value) {
38315 super.next(value);
38316 }
38317 subscribe(observerOrNext, error, complete) {
38318 let schedulerFn;
38319 let errorFn = (err) => null;
38320 let completeFn = () => null;
38321 if (observerOrNext && typeof observerOrNext === 'object') {
38322 schedulerFn = this.__isAsync ? (value) => {
38323 setTimeout(() => observerOrNext.next(value));
38324 } : (value) => {
38325 observerOrNext.next(value);
38326 };
38327 if (observerOrNext.error) {
38328 errorFn = this.__isAsync ? (err) => {
38329 setTimeout(() => observerOrNext.error(err));
38330 } : (err) => {
38331 observerOrNext.error(err);
38332 };
38333 }
38334 if (observerOrNext.complete) {
38335 completeFn = this.__isAsync ? () => {
38336 setTimeout(() => observerOrNext.complete());
38337 } : () => {
38338 observerOrNext.complete();
38339 };
38340 }
38341 }
38342 else {
38343 schedulerFn = this.__isAsync ? (value) => {
38344 setTimeout(() => observerOrNext(value));
38345 } : (value) => {
38346 observerOrNext(value);
38347 };
38348 if (error) {
38349 errorFn = this.__isAsync ? (err) => {
38350 setTimeout(() => error(err));
38351 } : (err) => {
38352 error(err);
38353 };
38354 }
38355 if (complete) {
38356 completeFn = this.__isAsync ? () => {
38357 setTimeout(() => complete());
38358 } : () => {
38359 complete();
38360 };
38361 }
38362 }
38363 const sink = super.subscribe(schedulerFn, errorFn, completeFn);
38364 if (observerOrNext instanceof Subscription) {
38365 observerOrNext.add(sink);
38366 }
38367 return sink;
38368 }
38369 }
38370 /**
38371 * @publicApi
38372 */
38373 const EventEmitter = EventEmitter_;
38374
38375 /**
38376 * @license
38377 * Copyright Google LLC All Rights Reserved.
38378 *
38379 * Use of this source code is governed by an MIT-style license that can be
38380 * found in the LICENSE file at https://angular.io/license
38381 */
38382 const ɵ0$9 = (dir = {}) => dir, ɵ1$1 = (type, meta) => SWITCH_COMPILE_DIRECTIVE(type, meta);
38383 /**
38384 * Type of the Directive metadata.
38385 *
38386 * @publicApi
38387 */
38388 const Directive = makeDecorator('Directive', ɵ0$9, undefined, undefined, ɵ1$1);
38389 const ɵ2$1 = (c = {}) => (Object.assign({ changeDetection: ChangeDetectionStrategy$1.Default }, c)), ɵ3$1 = (type, meta) => SWITCH_COMPILE_COMPONENT(type, meta);
38390 /**
38391 * Component decorator and metadata.
38392 *
38393 * @Annotation
38394 * @publicApi
38395 */
38396 const Component = makeDecorator('Component', ɵ2$1, Directive, undefined, ɵ3$1);
38397 const ɵ4 = (p) => (Object.assign({ pure: true }, p)), ɵ5 = (type, meta) => SWITCH_COMPILE_PIPE(type, meta);
38398 /**
38399 * @Annotation
38400 * @publicApi
38401 */
38402 const Pipe = makeDecorator('Pipe', ɵ4, undefined, undefined, ɵ5);
38403 const ɵ6 = (bindingPropertyName) => ({ bindingPropertyName });
38404 /**
38405 * @Annotation
38406 * @publicApi
38407 */
38408 const Input = makePropDecorator('Input', ɵ6);
38409 const ɵ7 = (bindingPropertyName) => ({ bindingPropertyName });
38410 /**
38411 * @Annotation
38412 * @publicApi
38413 */
38414 const Output = makePropDecorator('Output', ɵ7);
38415 const ɵ8 = (hostPropertyName) => ({ hostPropertyName });
38416 /**
38417 * @Annotation
38418 * @publicApi
38419 */
38420 const HostBinding = makePropDecorator('HostBinding', ɵ8);
38421 const ɵ9 = (eventName, args) => ({ eventName, args });
38422 /**
38423 * Decorator that binds a DOM event to a host listener and supplies configuration metadata.
38424 * Angular invokes the supplied handler method when the host element emits the specified event,
38425 * and updates the bound element with the result.
38426 *
38427 * If the handler method returns false, applies `preventDefault` on the bound element.
38428 *
38429 * @usageNotes
38430 *
38431 * The following example declares a directive
38432 * that attaches a click listener to a button and counts clicks.
38433 *
38434 * ```ts
38435 * @Directive({selector: 'button[counting]'})
38436 * class CountClicks {
38437 * numberOfClicks = 0;
38438 *
38439 * @HostListener('click', ['$event.target'])
38440 * onClick(btn) {
38441 * console.log('button', btn, 'number of clicks:', this.numberOfClicks++);
38442 * }
38443 * }
38444 *
38445 * @Component({
38446 * selector: 'app',
38447 * template: '<button counting>Increment</button>',
38448 * })
38449 * class App {}
38450 *
38451 * ```
38452 *
38453 * The following example registers another DOM event handler that listens for key-press events.
38454 * ``` ts
38455 * import { HostListener, Component } from "@angular/core";
38456 *
38457 * @Component({
38458 * selector: 'app',
38459 * template: `<h1>Hello, you have pressed keys {{counter}} number of times!</h1> Press any key to
38460 * increment the counter.
38461 * <button (click)="resetCounter()">Reset Counter</button>`
38462 * })
38463 * class AppComponent {
38464 * counter = 0;
38465 * @HostListener('window:keydown', ['$event'])
38466 * handleKeyDown(event: KeyboardEvent) {
38467 * this.counter++;
38468 * }
38469 * resetCounter() {
38470 * this.counter = 0;
38471 * }
38472 * }
38473 * ```
38474 *
38475 * @Annotation
38476 * @publicApi
38477 */
38478 const HostListener = makePropDecorator('HostListener', ɵ9);
38479 const SWITCH_COMPILE_COMPONENT__PRE_R3__ = noop;
38480 const SWITCH_COMPILE_DIRECTIVE__PRE_R3__ = noop;
38481 const SWITCH_COMPILE_PIPE__PRE_R3__ = noop;
38482 const SWITCH_COMPILE_COMPONENT = SWITCH_COMPILE_COMPONENT__PRE_R3__;
38483 const SWITCH_COMPILE_DIRECTIVE = SWITCH_COMPILE_DIRECTIVE__PRE_R3__;
38484 const SWITCH_COMPILE_PIPE = SWITCH_COMPILE_PIPE__PRE_R3__;
38485
38486 /**
38487 * @license
38488 * Copyright Google LLC All Rights Reserved.
38489 *
38490 * Use of this source code is governed by an MIT-style license that can be
38491 * found in the LICENSE file at https://angular.io/license
38492 */
38493 const ɵ0$a = (ngModule) => ngModule, ɵ1$2 =
38494 /**
38495 * Decorator that marks the following class as an NgModule, and supplies
38496 * configuration metadata for it.
38497 *
38498 * * The `declarations` and `entryComponents` options configure the compiler
38499 * with information about what belongs to the NgModule.
38500 * * The `providers` options configures the NgModule's injector to provide
38501 * dependencies the NgModule members.
38502 * * The `imports` and `exports` options bring in members from other modules, and make
38503 * this module's members available to others.
38504 */
38505 (type, meta) => SWITCH_COMPILE_NGMODULE(type, meta);
38506 /**
38507 * @Annotation
38508 * @publicApi
38509 */
38510 const NgModule = makeDecorator('NgModule', ɵ0$a, undefined, undefined, ɵ1$2);
38511 function preR3NgModuleCompile(moduleType, metadata) {
38512 let imports = (metadata && metadata.imports) || [];
38513 if (metadata && metadata.exports) {
38514 imports = [...imports, metadata.exports];
38515 }
38516 moduleType.ɵinj = ɵɵdefineInjector({
38517 factory: convertInjectableProviderToFactory(moduleType, { useClass: moduleType }),
38518 providers: metadata && metadata.providers,
38519 imports: imports,
38520 });
38521 }
38522 const SWITCH_COMPILE_NGMODULE__PRE_R3__ = preR3NgModuleCompile;
38523 const SWITCH_COMPILE_NGMODULE = SWITCH_COMPILE_NGMODULE__PRE_R3__;
38524
38525 /** PURE_IMPORTS_START _observable_ConnectableObservable PURE_IMPORTS_END */
38526 function multicast(subjectOrSubjectFactory, selector) {
38527 return function multicastOperatorFunction(source) {
38528 var subjectFactory;
38529 if (typeof subjectOrSubjectFactory === 'function') {
38530 subjectFactory = subjectOrSubjectFactory;
38531 }
38532 else {
38533 subjectFactory = function subjectFactory() {
38534 return subjectOrSubjectFactory;
38535 };
38536 }
38537 if (typeof selector === 'function') {
38538 return source.lift(new MulticastOperator(subjectFactory, selector));
38539 }
38540 var connectable = Object.create(source, connectableObservableDescriptor);
38541 connectable.source = source;
38542 connectable.subjectFactory = subjectFactory;
38543 return connectable;
38544 };
38545 }
38546 var MulticastOperator = /*@__PURE__*/ (function () {
38547 function MulticastOperator(subjectFactory, selector) {
38548 this.subjectFactory = subjectFactory;
38549 this.selector = selector;
38550 }
38551 MulticastOperator.prototype.call = function (subscriber, source) {
38552 var selector = this.selector;
38553 var subject = this.subjectFactory();
38554 var subscription = selector(subject).subscribe(subscriber);
38555 subscription.add(source.subscribe(subject));
38556 return subscription;
38557 };
38558 return MulticastOperator;
38559 }());
38560
38561 /** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */
38562 function shareSubjectFactory() {
38563 return new Subject();
38564 }
38565 function share() {
38566 return function (source) { return refCount()(multicast(shareSubjectFactory)(source)); };
38567 }
38568
38569 /**
38570 * @license
38571 * Copyright Google LLC All Rights Reserved.
38572 *
38573 * Use of this source code is governed by an MIT-style license that can be
38574 * found in the LICENSE file at https://angular.io/license
38575 */
38576 /**
38577 * A [DI token](guide/glossary#di-token "DI token definition") that you can use to provide
38578 * one or more initialization functions.
38579 *
38580 * The provided functions are injected at application startup and executed during
38581 * app initialization. If any of these functions returns a Promise, initialization
38582 * does not complete until the Promise is resolved.
38583 *
38584 * You can, for example, create a factory function that loads language data
38585 * or an external configuration, and provide that function to the `APP_INITIALIZER` token.
38586 * The function is executed during the application bootstrap process,
38587 * and the needed data is available on startup.
38588 *
38589 * @see `ApplicationInitStatus`
38590 *
38591 * @publicApi
38592 */
38593 const APP_INITIALIZER = new InjectionToken('Application Initializer');
38594 /**
38595 * A class that reflects the state of running {@link APP_INITIALIZER} functions.
38596 *
38597 * @publicApi
38598 */
38599 class ApplicationInitStatus {
38600 constructor(appInits) {
38601 this.appInits = appInits;
38602 this.resolve = noop;
38603 this.reject = noop;
38604 this.initialized = false;
38605 this.done = false;
38606 this.donePromise = new Promise((res, rej) => {
38607 this.resolve = res;
38608 this.reject = rej;
38609 });
38610 }
38611 /** @internal */
38612 runInitializers() {
38613 if (this.initialized) {
38614 return;
38615 }
38616 const asyncInitPromises = [];
38617 const complete = () => {
38618 this.done = true;
38619 this.resolve();
38620 };
38621 if (this.appInits) {
38622 for (let i = 0; i < this.appInits.length; i++) {
38623 const initResult = this.appInits[i]();
38624 if (isPromise$1(initResult)) {
38625 asyncInitPromises.push(initResult);
38626 }
38627 }
38628 }
38629 Promise.all(asyncInitPromises)
38630 .then(() => {
38631 complete();
38632 })
38633 .catch(e => {
38634 this.reject(e);
38635 });
38636 if (asyncInitPromises.length === 0) {
38637 complete();
38638 }
38639 this.initialized = true;
38640 }
38641 }
38642 ApplicationInitStatus.decorators = [
38643 { type: Injectable }
38644 ];
38645 ApplicationInitStatus.ctorParameters = () => [
38646 { type: Array, decorators: [{ type: Inject, args: [APP_INITIALIZER,] }, { type: Optional }] }
38647 ];
38648
38649 /**
38650 * @license
38651 * Copyright Google LLC All Rights Reserved.
38652 *
38653 * Use of this source code is governed by an MIT-style license that can be
38654 * found in the LICENSE file at https://angular.io/license
38655 */
38656 /**
38657 * A [DI token](guide/glossary#di-token "DI token definition") representing a unique string ID, used
38658 * primarily for prefixing application attributes and CSS styles when
38659 * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used.
38660 *
38661 * BY default, the value is randomly generated and assigned to the application by Angular.
38662 * To provide a custom ID value, use a DI provider <!-- TODO: provider --> to configure
38663 * the root {@link Injector} that uses this token.
38664 *
38665 * @publicApi
38666 */
38667 const APP_ID = new InjectionToken('AppId');
38668 function _appIdRandomProviderFactory() {
38669 return `${_randomChar()}${_randomChar()}${_randomChar()}`;
38670 }
38671 /**
38672 * Providers that generate a random `APP_ID_TOKEN`.
38673 * @publicApi
38674 */
38675 const APP_ID_RANDOM_PROVIDER = {
38676 provide: APP_ID,
38677 useFactory: _appIdRandomProviderFactory,
38678 deps: [],
38679 };
38680 function _randomChar() {
38681 return String.fromCharCode(97 + Math.floor(Math.random() * 25));
38682 }
38683 /**
38684 * A function that is executed when a platform is initialized.
38685 * @publicApi
38686 */
38687 const PLATFORM_INITIALIZER = new InjectionToken('Platform Initializer');
38688 /**
38689 * A token that indicates an opaque platform ID.
38690 * @publicApi
38691 */
38692 const PLATFORM_ID = new InjectionToken('Platform ID');
38693 /**
38694 * A [DI token](guide/glossary#di-token "DI token definition") that provides a set of callbacks to
38695 * be called for every component that is bootstrapped.
38696 *
38697 * Each callback must take a `ComponentRef` instance and return nothing.
38698 *
38699 * `(componentRef: ComponentRef) => void`
38700 *
38701 * @publicApi
38702 */
38703 const APP_BOOTSTRAP_LISTENER = new InjectionToken('appBootstrapListener');
38704 /**
38705 * A [DI token](guide/glossary#di-token "DI token definition") that indicates the root directory of
38706 * the application
38707 * @publicApi
38708 */
38709 const PACKAGE_ROOT_URL = new InjectionToken('Application Packages Root URL');
38710
38711 /**
38712 * @license
38713 * Copyright Google LLC All Rights Reserved.
38714 *
38715 * Use of this source code is governed by an MIT-style license that can be
38716 * found in the LICENSE file at https://angular.io/license
38717 */
38718 class Console {
38719 log(message) {
38720 // tslint:disable-next-line:no-console
38721 console.log(message);
38722 }
38723 // Note: for reporting errors use `DOM.logError()` as it is platform specific
38724 warn(message) {
38725 // tslint:disable-next-line:no-console
38726 console.warn(message);
38727 }
38728 }
38729 Console.decorators = [
38730 { type: Injectable }
38731 ];
38732
38733 /**
38734 * @license
38735 * Copyright Google LLC All Rights Reserved.
38736 *
38737 * Use of this source code is governed by an MIT-style license that can be
38738 * found in the LICENSE file at https://angular.io/license
38739 */
38740 /**
38741 * Provide this token to set the locale of your application.
38742 * It is used for i18n extraction, by i18n pipes (DatePipe, I18nPluralPipe, CurrencyPipe,
38743 * DecimalPipe and PercentPipe) and by ICU expressions.
38744 *
38745 * See the [i18n guide](guide/i18n#setting-up-locale) for more information.
38746 *
38747 * @usageNotes
38748 * ### Example
38749 *
38750 * ```typescript
38751 * import { LOCALE_ID } from '@angular/core';
38752 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38753 * import { AppModule } from './app/app.module';
38754 *
38755 * platformBrowserDynamic().bootstrapModule(AppModule, {
38756 * providers: [{provide: LOCALE_ID, useValue: 'en-US' }]
38757 * });
38758 * ```
38759 *
38760 * @publicApi
38761 */
38762 const LOCALE_ID$1 = new InjectionToken('LocaleId');
38763 /**
38764 * Provide this token to set the default currency code your application uses for
38765 * CurrencyPipe when there is no currency code passed into it. This is only used by
38766 * CurrencyPipe and has no relation to locale currency. Defaults to USD if not configured.
38767 *
38768 * See the [i18n guide](guide/i18n#setting-up-locale) for more information.
38769 *
38770 * <div class="alert is-helpful">
38771 *
38772 * **Deprecation notice:**
38773 *
38774 * The default currency code is currently always `USD` but this is deprecated from v9.
38775 *
38776 * **In v10 the default currency code will be taken from the current locale.**
38777 *
38778 * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in
38779 * your application `NgModule`:
38780 *
38781 * ```ts
38782 * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
38783 * ```
38784 *
38785 * </div>
38786 *
38787 * @usageNotes
38788 * ### Example
38789 *
38790 * ```typescript
38791 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38792 * import { AppModule } from './app/app.module';
38793 *
38794 * platformBrowserDynamic().bootstrapModule(AppModule, {
38795 * providers: [{provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' }]
38796 * });
38797 * ```
38798 *
38799 * @publicApi
38800 */
38801 const DEFAULT_CURRENCY_CODE = new InjectionToken('DefaultCurrencyCode');
38802 /**
38803 * Use this token at bootstrap to provide the content of your translation file (`xtb`,
38804 * `xlf` or `xlf2`) when you want to translate your application in another language.
38805 *
38806 * See the [i18n guide](guide/i18n#merge) for more information.
38807 *
38808 * @usageNotes
38809 * ### Example
38810 *
38811 * ```typescript
38812 * import { TRANSLATIONS } from '@angular/core';
38813 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38814 * import { AppModule } from './app/app.module';
38815 *
38816 * // content of your translation file
38817 * const translations = '....';
38818 *
38819 * platformBrowserDynamic().bootstrapModule(AppModule, {
38820 * providers: [{provide: TRANSLATIONS, useValue: translations }]
38821 * });
38822 * ```
38823 *
38824 * @publicApi
38825 */
38826 const TRANSLATIONS = new InjectionToken('Translations');
38827 /**
38828 * Provide this token at bootstrap to set the format of your {@link TRANSLATIONS}: `xtb`,
38829 * `xlf` or `xlf2`.
38830 *
38831 * See the [i18n guide](guide/i18n#merge) for more information.
38832 *
38833 * @usageNotes
38834 * ### Example
38835 *
38836 * ```typescript
38837 * import { TRANSLATIONS_FORMAT } from '@angular/core';
38838 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38839 * import { AppModule } from './app/app.module';
38840 *
38841 * platformBrowserDynamic().bootstrapModule(AppModule, {
38842 * providers: [{provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }]
38843 * });
38844 * ```
38845 *
38846 * @publicApi
38847 */
38848 const TRANSLATIONS_FORMAT = new InjectionToken('TranslationsFormat');
38849 /**
38850 * Use this enum at bootstrap as an option of `bootstrapModule` to define the strategy
38851 * that the compiler should use in case of missing translations:
38852 * - Error: throw if you have missing translations.
38853 * - Warning (default): show a warning in the console and/or shell.
38854 * - Ignore: do nothing.
38855 *
38856 * See the [i18n guide](guide/i18n#missing-translation) for more information.
38857 *
38858 * @usageNotes
38859 * ### Example
38860 * ```typescript
38861 * import { MissingTranslationStrategy } from '@angular/core';
38862 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38863 * import { AppModule } from './app/app.module';
38864 *
38865 * platformBrowserDynamic().bootstrapModule(AppModule, {
38866 * missingTranslation: MissingTranslationStrategy.Error
38867 * });
38868 * ```
38869 *
38870 * @publicApi
38871 */
38872 var MissingTranslationStrategy$1;
38873 (function (MissingTranslationStrategy) {
38874 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
38875 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
38876 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
38877 })(MissingTranslationStrategy$1 || (MissingTranslationStrategy$1 = {}));
38878
38879 /**
38880 * @license
38881 * Copyright Google LLC All Rights Reserved.
38882 *
38883 * Use of this source code is governed by an MIT-style license that can be
38884 * found in the LICENSE file at https://angular.io/license
38885 */
38886 const SWITCH_IVY_ENABLED__PRE_R3__ = false;
38887 const ivyEnabled = SWITCH_IVY_ENABLED__PRE_R3__;
38888
38889 /**
38890 * @license
38891 * Copyright Google LLC All Rights Reserved.
38892 *
38893 * Use of this source code is governed by an MIT-style license that can be
38894 * found in the LICENSE file at https://angular.io/license
38895 */
38896 function _throwError() {
38897 throw new Error(`Runtime compiler is not loaded`);
38898 }
38899 const Compiler_compileModuleSync__PRE_R3__ = _throwError;
38900 const Compiler_compileModuleSync = Compiler_compileModuleSync__PRE_R3__;
38901 const Compiler_compileModuleAsync__PRE_R3__ = _throwError;
38902 const Compiler_compileModuleAsync = Compiler_compileModuleAsync__PRE_R3__;
38903 const Compiler_compileModuleAndAllComponentsSync__PRE_R3__ = _throwError;
38904 const Compiler_compileModuleAndAllComponentsSync = Compiler_compileModuleAndAllComponentsSync__PRE_R3__;
38905 const Compiler_compileModuleAndAllComponentsAsync__PRE_R3__ = _throwError;
38906 const Compiler_compileModuleAndAllComponentsAsync = Compiler_compileModuleAndAllComponentsAsync__PRE_R3__;
38907 /**
38908 * Low-level service for running the angular compiler during runtime
38909 * to create {@link ComponentFactory}s, which
38910 * can later be used to create and render a Component instance.
38911 *
38912 * Each `@NgModule` provides an own `Compiler` to its injector,
38913 * that will use the directives/pipes of the ng module for compilation
38914 * of components.
38915 *
38916 * @publicApi
38917 */
38918 class Compiler {
38919 constructor() {
38920 /**
38921 * Compiles the given NgModule and all of its components. All templates of the components listed
38922 * in `entryComponents` have to be inlined.
38923 */
38924 this.compileModuleSync = Compiler_compileModuleSync;
38925 /**
38926 * Compiles the given NgModule and all of its components
38927 */
38928 this.compileModuleAsync = Compiler_compileModuleAsync;
38929 /**
38930 * Same as {@link #compileModuleSync} but also creates ComponentFactories for all components.
38931 */
38932 this.compileModuleAndAllComponentsSync = Compiler_compileModuleAndAllComponentsSync;
38933 /**
38934 * Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components.
38935 */
38936 this.compileModuleAndAllComponentsAsync = Compiler_compileModuleAndAllComponentsAsync;
38937 }
38938 /**
38939 * Clears all caches.
38940 */
38941 clearCache() { }
38942 /**
38943 * Clears the cache for the given component/ngModule.
38944 */
38945 clearCacheFor(type) { }
38946 /**
38947 * Returns the id for a given NgModule, if one is defined and known to the compiler.
38948 */
38949 getModuleId(moduleType) {
38950 return undefined;
38951 }
38952 }
38953 Compiler.decorators = [
38954 { type: Injectable }
38955 ];
38956 /**
38957 * Token to provide CompilerOptions in the platform injector.
38958 *
38959 * @publicApi
38960 */
38961 const COMPILER_OPTIONS = new InjectionToken('compilerOptions');
38962 /**
38963 * A factory for creating a Compiler
38964 *
38965 * @publicApi
38966 */
38967 class CompilerFactory {
38968 }
38969
38970 /**
38971 * @license
38972 * Copyright Google LLC All Rights Reserved.
38973 *
38974 * Use of this source code is governed by an MIT-style license that can be
38975 * found in the LICENSE file at https://angular.io/license
38976 */
38977 const promise = (() => Promise.resolve(0))();
38978 function scheduleMicroTask(fn) {
38979 if (typeof Zone === 'undefined') {
38980 // use promise to schedule microTask instead of use Zone
38981 promise.then(() => {
38982 fn && fn.apply(null, null);
38983 });
38984 }
38985 else {
38986 Zone.current.scheduleMicroTask('scheduleMicrotask', fn);
38987 }
38988 }
38989
38990 /**
38991 * @license
38992 * Copyright Google LLC All Rights Reserved.
38993 *
38994 * Use of this source code is governed by an MIT-style license that can be
38995 * found in the LICENSE file at https://angular.io/license
38996 */
38997 function getNativeRequestAnimationFrame() {
38998 let nativeRequestAnimationFrame = _global$1['requestAnimationFrame'];
38999 let nativeCancelAnimationFrame = _global$1['cancelAnimationFrame'];
39000 if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
39001 // use unpatched version of requestAnimationFrame(native delegate) if possible
39002 // to avoid another Change detection
39003 const unpatchedRequestAnimationFrame = nativeRequestAnimationFrame[Zone.__symbol__('OriginalDelegate')];
39004 if (unpatchedRequestAnimationFrame) {
39005 nativeRequestAnimationFrame = unpatchedRequestAnimationFrame;
39006 }
39007 const unpatchedCancelAnimationFrame = nativeCancelAnimationFrame[Zone.__symbol__('OriginalDelegate')];
39008 if (unpatchedCancelAnimationFrame) {
39009 nativeCancelAnimationFrame = unpatchedCancelAnimationFrame;
39010 }
39011 }
39012 return { nativeRequestAnimationFrame, nativeCancelAnimationFrame };
39013 }
39014
39015 /**
39016 * @license
39017 * Copyright Google LLC All Rights Reserved.
39018 *
39019 * Use of this source code is governed by an MIT-style license that can be
39020 * found in the LICENSE file at https://angular.io/license
39021 */
39022 /**
39023 * An injectable service for executing work inside or outside of the Angular zone.
39024 *
39025 * The most common use of this service is to optimize performance when starting a work consisting of
39026 * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
39027 * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
39028 * can reenter the Angular zone via {@link #run}.
39029 *
39030 * <!-- TODO: add/fix links to:
39031 * - docs explaining zones and the use of zones in Angular and change-detection
39032 * - link to runOutsideAngular/run (throughout this file!)
39033 * -->
39034 *
39035 * @usageNotes
39036 * ### Example
39037 *
39038 * ```
39039 * import {Component, NgZone} from '@angular/core';
39040 * import {NgIf} from '@angular/common';
39041 *
39042 * @Component({
39043 * selector: 'ng-zone-demo',
39044 * template: `
39045 * <h2>Demo: NgZone</h2>
39046 *
39047 * <p>Progress: {{progress}}%</p>
39048 * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
39049 *
39050 * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
39051 * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
39052 * `,
39053 * })
39054 * export class NgZoneDemo {
39055 * progress: number = 0;
39056 * label: string;
39057 *
39058 * constructor(private _ngZone: NgZone) {}
39059 *
39060 * // Loop inside the Angular zone
39061 * // so the UI DOES refresh after each setTimeout cycle
39062 * processWithinAngularZone() {
39063 * this.label = 'inside';
39064 * this.progress = 0;
39065 * this._increaseProgress(() => console.log('Inside Done!'));
39066 * }
39067 *
39068 * // Loop outside of the Angular zone
39069 * // so the UI DOES NOT refresh after each setTimeout cycle
39070 * processOutsideOfAngularZone() {
39071 * this.label = 'outside';
39072 * this.progress = 0;
39073 * this._ngZone.runOutsideAngular(() => {
39074 * this._increaseProgress(() => {
39075 * // reenter the Angular zone and display done
39076 * this._ngZone.run(() => { console.log('Outside Done!'); });
39077 * });
39078 * });
39079 * }
39080 *
39081 * _increaseProgress(doneCallback: () => void) {
39082 * this.progress += 1;
39083 * console.log(`Current progress: ${this.progress}%`);
39084 *
39085 * if (this.progress < 100) {
39086 * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
39087 * } else {
39088 * doneCallback();
39089 * }
39090 * }
39091 * }
39092 * ```
39093 *
39094 * @publicApi
39095 */
39096 class NgZone {
39097 constructor({ enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false }) {
39098 this.hasPendingMacrotasks = false;
39099 this.hasPendingMicrotasks = false;
39100 /**
39101 * Whether there are no outstanding microtasks or macrotasks.
39102 */
39103 this.isStable = true;
39104 /**
39105 * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
39106 */
39107 this.onUnstable = new EventEmitter(false);
39108 /**
39109 * Notifies when there is no more microtasks enqueued in the current VM Turn.
39110 * This is a hint for Angular to do change detection, which may enqueue more microtasks.
39111 * For this reason this event can fire multiple times per VM Turn.
39112 */
39113 this.onMicrotaskEmpty = new EventEmitter(false);
39114 /**
39115 * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
39116 * implies we are about to relinquish VM turn.
39117 * This event gets called just once.
39118 */
39119 this.onStable = new EventEmitter(false);
39120 /**
39121 * Notifies that an error has been delivered.
39122 */
39123 this.onError = new EventEmitter(false);
39124 if (typeof Zone == 'undefined') {
39125 throw new Error(`In this configuration Angular requires Zone.js`);
39126 }
39127 Zone.assertZonePatched();
39128 const self = this;
39129 self._nesting = 0;
39130 self._outer = self._inner = Zone.current;
39131 if (Zone['TaskTrackingZoneSpec']) {
39132 self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']);
39133 }
39134 if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
39135 self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
39136 }
39137 // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
39138 // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
39139 self.shouldCoalesceEventChangeDetection =
39140 !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
39141 self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
39142 self.lastRequestAnimationFrameId = -1;
39143 self.nativeRequestAnimationFrame = getNativeRequestAnimationFrame().nativeRequestAnimationFrame;
39144 forkInnerZoneWithAngularBehavior(self);
39145 }
39146 static isInAngularZone() {
39147 return Zone.current.get('isAngularZone') === true;
39148 }
39149 static assertInAngularZone() {
39150 if (!NgZone.isInAngularZone()) {
39151 throw new Error('Expected to be in Angular Zone, but it is not!');
39152 }
39153 }
39154 static assertNotInAngularZone() {
39155 if (NgZone.isInAngularZone()) {
39156 throw new Error('Expected to not be in Angular Zone, but it is!');
39157 }
39158 }
39159 /**
39160 * Executes the `fn` function synchronously within the Angular zone and returns value returned by
39161 * the function.
39162 *
39163 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
39164 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
39165 *
39166 * Any future tasks or microtasks scheduled from within this function will continue executing from
39167 * within the Angular zone.
39168 *
39169 * If a synchronous error happens it will be rethrown and not reported via `onError`.
39170 */
39171 run(fn, applyThis, applyArgs) {
39172 return this._inner.run(fn, applyThis, applyArgs);
39173 }
39174 /**
39175 * Executes the `fn` function synchronously within the Angular zone as a task and returns value
39176 * returned by the function.
39177 *
39178 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
39179 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
39180 *
39181 * Any future tasks or microtasks scheduled from within this function will continue executing from
39182 * within the Angular zone.
39183 *
39184 * If a synchronous error happens it will be rethrown and not reported via `onError`.
39185 */
39186 runTask(fn, applyThis, applyArgs, name) {
39187 const zone = this._inner;
39188 const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
39189 try {
39190 return zone.runTask(task, applyThis, applyArgs);
39191 }
39192 finally {
39193 zone.cancelTask(task);
39194 }
39195 }
39196 /**
39197 * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
39198 * rethrown.
39199 */
39200 runGuarded(fn, applyThis, applyArgs) {
39201 return this._inner.runGuarded(fn, applyThis, applyArgs);
39202 }
39203 /**
39204 * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
39205 * the function.
39206 *
39207 * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
39208 * work that
39209 * doesn't trigger Angular change-detection or is subject to Angular's error handling.
39210 *
39211 * Any future tasks or microtasks scheduled from within this function will continue executing from
39212 * outside of the Angular zone.
39213 *
39214 * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
39215 */
39216 runOutsideAngular(fn) {
39217 return this._outer.run(fn);
39218 }
39219 }
39220 const EMPTY_PAYLOAD = {};
39221 function checkStable(zone) {
39222 if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
39223 try {
39224 zone._nesting++;
39225 zone.onMicrotaskEmpty.emit(null);
39226 }
39227 finally {
39228 zone._nesting--;
39229 if (!zone.hasPendingMicrotasks) {
39230 try {
39231 zone.runOutsideAngular(() => zone.onStable.emit(null));
39232 }
39233 finally {
39234 zone.isStable = true;
39235 }
39236 }
39237 }
39238 }
39239 }
39240 function delayChangeDetectionForEvents(zone) {
39241 if (zone.lastRequestAnimationFrameId !== -1) {
39242 return;
39243 }
39244 zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(_global$1, () => {
39245 // This is a work around for https://github.com/angular/angular/issues/36839.
39246 // The core issue is that when event coalescing is enabled it is possible for microtasks
39247 // to get flushed too early (As is the case with `Promise.then`) between the
39248 // coalescing eventTasks.
39249 //
39250 // To workaround this we schedule a "fake" eventTask before we process the
39251 // coalescing eventTasks. The benefit of this is that the "fake" container eventTask
39252 // will prevent the microtasks queue from getting drained in between the coalescing
39253 // eventTask execution.
39254 if (!zone.fakeTopEventTask) {
39255 zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
39256 zone.lastRequestAnimationFrameId = -1;
39257 updateMicroTaskStatus(zone);
39258 checkStable(zone);
39259 }, undefined, () => { }, () => { });
39260 }
39261 zone.fakeTopEventTask.invoke();
39262 });
39263 updateMicroTaskStatus(zone);
39264 }
39265 function forkInnerZoneWithAngularBehavior(zone) {
39266 const delayChangeDetectionForEventsDelegate = () => {
39267 delayChangeDetectionForEvents(zone);
39268 };
39269 zone._inner = zone._inner.fork({
39270 name: 'angular',
39271 properties: { 'isAngularZone': true },
39272 onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
39273 try {
39274 onEnter(zone);
39275 return delegate.invokeTask(target, task, applyThis, applyArgs);
39276 }
39277 finally {
39278 if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
39279 zone.shouldCoalesceRunChangeDetection) {
39280 delayChangeDetectionForEventsDelegate();
39281 }
39282 onLeave(zone);
39283 }
39284 },
39285 onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
39286 try {
39287 onEnter(zone);
39288 return delegate.invoke(target, callback, applyThis, applyArgs, source);
39289 }
39290 finally {
39291 if (zone.shouldCoalesceRunChangeDetection) {
39292 delayChangeDetectionForEventsDelegate();
39293 }
39294 onLeave(zone);
39295 }
39296 },
39297 onHasTask: (delegate, current, target, hasTaskState) => {
39298 delegate.hasTask(target, hasTaskState);
39299 if (current === target) {
39300 // We are only interested in hasTask events which originate from our zone
39301 // (A child hasTask event is not interesting to us)
39302 if (hasTaskState.change == 'microTask') {
39303 zone._hasPendingMicrotasks = hasTaskState.microTask;
39304 updateMicroTaskStatus(zone);
39305 checkStable(zone);
39306 }
39307 else if (hasTaskState.change == 'macroTask') {
39308 zone.hasPendingMacrotasks = hasTaskState.macroTask;
39309 }
39310 }
39311 },
39312 onHandleError: (delegate, current, target, error) => {
39313 delegate.handleError(target, error);
39314 zone.runOutsideAngular(() => zone.onError.emit(error));
39315 return false;
39316 }
39317 });
39318 }
39319 function updateMicroTaskStatus(zone) {
39320 if (zone._hasPendingMicrotasks ||
39321 ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
39322 zone.lastRequestAnimationFrameId !== -1)) {
39323 zone.hasPendingMicrotasks = true;
39324 }
39325 else {
39326 zone.hasPendingMicrotasks = false;
39327 }
39328 }
39329 function onEnter(zone) {
39330 zone._nesting++;
39331 if (zone.isStable) {
39332 zone.isStable = false;
39333 zone.onUnstable.emit(null);
39334 }
39335 }
39336 function onLeave(zone) {
39337 zone._nesting--;
39338 checkStable(zone);
39339 }
39340 /**
39341 * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
39342 * to framework to perform rendering.
39343 */
39344 class NoopNgZone {
39345 constructor() {
39346 this.hasPendingMicrotasks = false;
39347 this.hasPendingMacrotasks = false;
39348 this.isStable = true;
39349 this.onUnstable = new EventEmitter();
39350 this.onMicrotaskEmpty = new EventEmitter();
39351 this.onStable = new EventEmitter();
39352 this.onError = new EventEmitter();
39353 }
39354 run(fn, applyThis, applyArgs) {
39355 return fn.apply(applyThis, applyArgs);
39356 }
39357 runGuarded(fn, applyThis, applyArgs) {
39358 return fn.apply(applyThis, applyArgs);
39359 }
39360 runOutsideAngular(fn) {
39361 return fn();
39362 }
39363 runTask(fn, applyThis, applyArgs, name) {
39364 return fn.apply(applyThis, applyArgs);
39365 }
39366 }
39367
39368 /**
39369 * @license
39370 * Copyright Google LLC All Rights Reserved.
39371 *
39372 * Use of this source code is governed by an MIT-style license that can be
39373 * found in the LICENSE file at https://angular.io/license
39374 */
39375 /**
39376 * The Testability service provides testing hooks that can be accessed from
39377 * the browser and by services such as Protractor. Each bootstrapped Angular
39378 * application on the page will have an instance of Testability.
39379 * @publicApi
39380 */
39381 class Testability {
39382 constructor(_ngZone) {
39383 this._ngZone = _ngZone;
39384 this._pendingCount = 0;
39385 this._isZoneStable = true;
39386 /**
39387 * Whether any work was done since the last 'whenStable' callback. This is
39388 * useful to detect if this could have potentially destabilized another
39389 * component while it is stabilizing.
39390 * @internal
39391 */
39392 this._didWork = false;
39393 this._callbacks = [];
39394 this.taskTrackingZone = null;
39395 this._watchAngularEvents();
39396 _ngZone.run(() => {
39397 this.taskTrackingZone =
39398 typeof Zone == 'undefined' ? null : Zone.current.get('TaskTrackingZone');
39399 });
39400 }
39401 _watchAngularEvents() {
39402 this._ngZone.onUnstable.subscribe({
39403 next: () => {
39404 this._didWork = true;
39405 this._isZoneStable = false;
39406 }
39407 });
39408 this._ngZone.runOutsideAngular(() => {
39409 this._ngZone.onStable.subscribe({
39410 next: () => {
39411 NgZone.assertNotInAngularZone();
39412 scheduleMicroTask(() => {
39413 this._isZoneStable = true;
39414 this._runCallbacksIfReady();
39415 });
39416 }
39417 });
39418 });
39419 }
39420 /**
39421 * Increases the number of pending request
39422 * @deprecated pending requests are now tracked with zones.
39423 */
39424 increasePendingRequestCount() {
39425 this._pendingCount += 1;
39426 this._didWork = true;
39427 return this._pendingCount;
39428 }
39429 /**
39430 * Decreases the number of pending request
39431 * @deprecated pending requests are now tracked with zones
39432 */
39433 decreasePendingRequestCount() {
39434 this._pendingCount -= 1;
39435 if (this._pendingCount < 0) {
39436 throw new Error('pending async requests below zero');
39437 }
39438 this._runCallbacksIfReady();
39439 return this._pendingCount;
39440 }
39441 /**
39442 * Whether an associated application is stable
39443 */
39444 isStable() {
39445 return this._isZoneStable && this._pendingCount === 0 && !this._ngZone.hasPendingMacrotasks;
39446 }
39447 _runCallbacksIfReady() {
39448 if (this.isStable()) {
39449 // Schedules the call backs in a new frame so that it is always async.
39450 scheduleMicroTask(() => {
39451 while (this._callbacks.length !== 0) {
39452 let cb = this._callbacks.pop();
39453 clearTimeout(cb.timeoutId);
39454 cb.doneCb(this._didWork);
39455 }
39456 this._didWork = false;
39457 });
39458 }
39459 else {
39460 // Still not stable, send updates.
39461 let pending = this.getPendingTasks();
39462 this._callbacks = this._callbacks.filter((cb) => {
39463 if (cb.updateCb && cb.updateCb(pending)) {
39464 clearTimeout(cb.timeoutId);
39465 return false;
39466 }
39467 return true;
39468 });
39469 this._didWork = true;
39470 }
39471 }
39472 getPendingTasks() {
39473 if (!this.taskTrackingZone) {
39474 return [];
39475 }
39476 // Copy the tasks data so that we don't leak tasks.
39477 return this.taskTrackingZone.macroTasks.map((t) => {
39478 return {
39479 source: t.source,
39480 // From TaskTrackingZone:
39481 // https://github.com/angular/zone.js/blob/master/lib/zone-spec/task-tracking.ts#L40
39482 creationLocation: t.creationLocation,
39483 data: t.data
39484 };
39485 });
39486 }
39487 addCallback(cb, timeout, updateCb) {
39488 let timeoutId = -1;
39489 if (timeout && timeout > 0) {
39490 timeoutId = setTimeout(() => {
39491 this._callbacks = this._callbacks.filter((cb) => cb.timeoutId !== timeoutId);
39492 cb(this._didWork, this.getPendingTasks());
39493 }, timeout);
39494 }
39495 this._callbacks.push({ doneCb: cb, timeoutId: timeoutId, updateCb: updateCb });
39496 }
39497 /**
39498 * Wait for the application to be stable with a timeout. If the timeout is reached before that
39499 * happens, the callback receives a list of the macro tasks that were pending, otherwise null.
39500 *
39501 * @param doneCb The callback to invoke when Angular is stable or the timeout expires
39502 * whichever comes first.
39503 * @param timeout Optional. The maximum time to wait for Angular to become stable. If not
39504 * specified, whenStable() will wait forever.
39505 * @param updateCb Optional. If specified, this callback will be invoked whenever the set of
39506 * pending macrotasks changes. If this callback returns true doneCb will not be invoked
39507 * and no further updates will be issued.
39508 */
39509 whenStable(doneCb, timeout, updateCb) {
39510 if (updateCb && !this.taskTrackingZone) {
39511 throw new Error('Task tracking zone is required when passing an update callback to ' +
39512 'whenStable(). Is "zone.js/dist/task-tracking.js" loaded?');
39513 }
39514 // These arguments are 'Function' above to keep the public API simple.
39515 this.addCallback(doneCb, timeout, updateCb);
39516 this._runCallbacksIfReady();
39517 }
39518 /**
39519 * Get the number of pending requests
39520 * @deprecated pending requests are now tracked with zones
39521 */
39522 getPendingRequestCount() {
39523 return this._pendingCount;
39524 }
39525 /**
39526 * Find providers by name
39527 * @param using The root element to search from
39528 * @param provider The name of binding variable
39529 * @param exactMatch Whether using exactMatch
39530 */
39531 findProviders(using, provider, exactMatch) {
39532 // TODO(juliemr): implement.
39533 return [];
39534 }
39535 }
39536 Testability.decorators = [
39537 { type: Injectable }
39538 ];
39539 Testability.ctorParameters = () => [
39540 { type: NgZone }
39541 ];
39542 /**
39543 * A global registry of {@link Testability} instances for specific elements.
39544 * @publicApi
39545 */
39546 class TestabilityRegistry {
39547 constructor() {
39548 /** @internal */
39549 this._applications = new Map();
39550 _testabilityGetter.addToWindow(this);
39551 }
39552 /**
39553 * Registers an application with a testability hook so that it can be tracked
39554 * @param token token of application, root element
39555 * @param testability Testability hook
39556 */
39557 registerApplication(token, testability) {
39558 this._applications.set(token, testability);
39559 }
39560 /**
39561 * Unregisters an application.
39562 * @param token token of application, root element
39563 */
39564 unregisterApplication(token) {
39565 this._applications.delete(token);
39566 }
39567 /**
39568 * Unregisters all applications
39569 */
39570 unregisterAllApplications() {
39571 this._applications.clear();
39572 }
39573 /**
39574 * Get a testability hook associated with the application
39575 * @param elem root element
39576 */
39577 getTestability(elem) {
39578 return this._applications.get(elem) || null;
39579 }
39580 /**
39581 * Get all registered testabilities
39582 */
39583 getAllTestabilities() {
39584 return Array.from(this._applications.values());
39585 }
39586 /**
39587 * Get all registered applications(root elements)
39588 */
39589 getAllRootElements() {
39590 return Array.from(this._applications.keys());
39591 }
39592 /**
39593 * Find testability of a node in the Tree
39594 * @param elem node
39595 * @param findInAncestors whether finding testability in ancestors if testability was not found in
39596 * current node
39597 */
39598 findTestabilityInTree(elem, findInAncestors = true) {
39599 return _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors);
39600 }
39601 }
39602 TestabilityRegistry.decorators = [
39603 { type: Injectable }
39604 ];
39605 TestabilityRegistry.ctorParameters = () => [];
39606 class _NoopGetTestability {
39607 addToWindow(registry) { }
39608 findTestabilityInTree(registry, elem, findInAncestors) {
39609 return null;
39610 }
39611 }
39612 let _testabilityGetter = new _NoopGetTestability();
39613
39614 /**
39615 * @license
39616 * Copyright Google LLC All Rights Reserved.
39617 *
39618 * Use of this source code is governed by an MIT-style license that can be
39619 * found in the LICENSE file at https://angular.io/license
39620 */
39621 /**
39622 * This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
39623 *
39624 * For more information on how to run and debug tests with either Ivy or View Engine (legacy),
39625 * please see [BAZEL.md](./docs/BAZEL.md).
39626 */
39627 let _devMode = true;
39628 /**
39629 * Returns whether Angular is in development mode. After called once,
39630 * the value is locked and won't change any more.
39631 *
39632 * By default, this is true, unless a user calls `enableProdMode` before calling this.
39633 *
39634 * @publicApi
39635 */
39636 function isDevMode() {
39637 return _devMode;
39638 }
39639
39640 /**
39641 * @license
39642 * Copyright Google LLC All Rights Reserved.
39643 *
39644 * Use of this source code is governed by an MIT-style license that can be
39645 * found in the LICENSE file at https://angular.io/license
39646 */
39647 let _platform;
39648 let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
39649 function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {
39650 const compilerFactory = injector.get(CompilerFactory);
39651 const compiler = compilerFactory.createCompiler([options]);
39652 return compiler.compileModuleAsync(moduleType);
39653 }
39654 let isBoundToModule = isBoundToModule__PRE_R3__;
39655 function isBoundToModule__PRE_R3__(cf) {
39656 return cf instanceof ComponentFactoryBoundToModule;
39657 }
39658 const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken');
39659 /**
39660 * Creates a platform.
39661 * Platforms must be created on launch using this function.
39662 *
39663 * @publicApi
39664 */
39665 function createPlatform(injector) {
39666 if (_platform && !_platform.destroyed &&
39667 !_platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
39668 throw new Error('There can be only one platform. Destroy the previous one to create a new one.');
39669 }
39670 _platform = injector.get(PlatformRef);
39671 const inits = injector.get(PLATFORM_INITIALIZER, null);
39672 if (inits)
39673 inits.forEach((init) => init());
39674 return _platform;
39675 }
39676 /**
39677 * Creates a factory for a platform. Can be used to provide or override `Providers` specific to
39678 * your application's runtime needs, such as `PLATFORM_INITIALIZER` and `PLATFORM_ID`.
39679 * @param parentPlatformFactory Another platform factory to modify. Allows you to compose factories
39680 * to build up configurations that might be required by different libraries or parts of the
39681 * application.
39682 * @param name Identifies the new platform factory.
39683 * @param providers A set of dependency providers for platforms created with the new factory.
39684 *
39685 * @publicApi
39686 */
39687 function createPlatformFactory(parentPlatformFactory, name, providers = []) {
39688 const desc = `Platform: ${name}`;
39689 const marker = new InjectionToken(desc);
39690 return (extraProviders = []) => {
39691 let platform = getPlatform();
39692 if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
39693 if (parentPlatformFactory) {
39694 parentPlatformFactory(providers.concat(extraProviders).concat({ provide: marker, useValue: true }));
39695 }
39696 else {
39697 const injectedProviders = providers.concat(extraProviders).concat({ provide: marker, useValue: true }, {
39698 provide: INJECTOR_SCOPE,
39699 useValue: 'platform'
39700 });
39701 createPlatform(Injector.create({ providers: injectedProviders, name: desc }));
39702 }
39703 }
39704 return assertPlatform(marker);
39705 };
39706 }
39707 /**
39708 * Checks that there is currently a platform that contains the given token as a provider.
39709 *
39710 * @publicApi
39711 */
39712 function assertPlatform(requiredToken) {
39713 const platform = getPlatform();
39714 if (!platform) {
39715 throw new Error('No platform exists!');
39716 }
39717 if (!platform.injector.get(requiredToken, null)) {
39718 throw new Error('A platform with a different configuration has been created. Please destroy it first.');
39719 }
39720 return platform;
39721 }
39722 /**
39723 * Returns the current platform.
39724 *
39725 * @publicApi
39726 */
39727 function getPlatform() {
39728 return _platform && !_platform.destroyed ? _platform : null;
39729 }
39730 /**
39731 * The Angular platform is the entry point for Angular on a web page.
39732 * Each page has exactly one platform. Services (such as reflection) which are common
39733 * to every Angular application running on the page are bound in its scope.
39734 * A page's platform is initialized implicitly when a platform is created using a platform
39735 * factory such as `PlatformBrowser`, or explicitly by calling the `createPlatform()` function.
39736 *
39737 * @publicApi
39738 */
39739 class PlatformRef {
39740 /** @internal */
39741 constructor(_injector) {
39742 this._injector = _injector;
39743 this._modules = [];
39744 this._destroyListeners = [];
39745 this._destroyed = false;
39746 }
39747 /**
39748 * Creates an instance of an `@NgModule` for the given platform for offline compilation.
39749 *
39750 * @usageNotes
39751 *
39752 * The following example creates the NgModule for a browser platform.
39753 *
39754 * ```typescript
39755 * my_module.ts:
39756 *
39757 * @NgModule({
39758 * imports: [BrowserModule]
39759 * })
39760 * class MyModule {}
39761 *
39762 * main.ts:
39763 * import {MyModuleNgFactory} from './my_module.ngfactory';
39764 * import {platformBrowser} from '@angular/platform-browser';
39765 *
39766 * let moduleRef = platformBrowser().bootstrapModuleFactory(MyModuleNgFactory);
39767 * ```
39768 */
39769 bootstrapModuleFactory(moduleFactory, options) {
39770 // Note: We need to create the NgZone _before_ we instantiate the module,
39771 // as instantiating the module creates some providers eagerly.
39772 // So we create a mini parent injector that just contains the new NgZone and
39773 // pass that as parent to the NgModuleFactory.
39774 const ngZoneOption = options ? options.ngZone : undefined;
39775 const ngZoneEventCoalescing = (options && options.ngZoneEventCoalescing) || false;
39776 const ngZoneRunCoalescing = (options && options.ngZoneRunCoalescing) || false;
39777 const ngZone = getNgZone(ngZoneOption, { ngZoneEventCoalescing, ngZoneRunCoalescing });
39778 const providers = [{ provide: NgZone, useValue: ngZone }];
39779 // Note: Create ngZoneInjector within ngZone.run so that all of the instantiated services are
39780 // created within the Angular zone
39781 // Do not try to replace ngZone.run with ApplicationRef#run because ApplicationRef would then be
39782 // created outside of the Angular zone.
39783 return ngZone.run(() => {
39784 const ngZoneInjector = Injector.create({ providers: providers, parent: this.injector, name: moduleFactory.moduleType.name });
39785 const moduleRef = moduleFactory.create(ngZoneInjector);
39786 const exceptionHandler = moduleRef.injector.get(ErrorHandler, null);
39787 if (!exceptionHandler) {
39788 throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
39789 }
39790 ngZone.runOutsideAngular(() => {
39791 const subscription = ngZone.onError.subscribe({
39792 next: (error) => {
39793 exceptionHandler.handleError(error);
39794 }
39795 });
39796 moduleRef.onDestroy(() => {
39797 remove(this._modules, moduleRef);
39798 subscription.unsubscribe();
39799 });
39800 });
39801 return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
39802 const initStatus = moduleRef.injector.get(ApplicationInitStatus);
39803 initStatus.runInitializers();
39804 return initStatus.donePromise.then(() => {
39805 if (ivyEnabled) {
39806 // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy
39807 const localeId = moduleRef.injector.get(LOCALE_ID$1, DEFAULT_LOCALE_ID);
39808 setLocaleId(localeId || DEFAULT_LOCALE_ID);
39809 }
39810 this._moduleDoBootstrap(moduleRef);
39811 return moduleRef;
39812 });
39813 });
39814 });
39815 }
39816 /**
39817 * Creates an instance of an `@NgModule` for a given platform using the given runtime compiler.
39818 *
39819 * @usageNotes
39820 * ### Simple Example
39821 *
39822 * ```typescript
39823 * @NgModule({
39824 * imports: [BrowserModule]
39825 * })
39826 * class MyModule {}
39827 *
39828 * let moduleRef = platformBrowser().bootstrapModule(MyModule);
39829 * ```
39830 *
39831 */
39832 bootstrapModule(moduleType, compilerOptions = []) {
39833 const options = optionsReducer({}, compilerOptions);
39834 return compileNgModuleFactory(this.injector, options, moduleType)
39835 .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
39836 }
39837 _moduleDoBootstrap(moduleRef) {
39838 const appRef = moduleRef.injector.get(ApplicationRef);
39839 if (moduleRef._bootstrapComponents.length > 0) {
39840 moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
39841 }
39842 else if (moduleRef.instance.ngDoBootstrap) {
39843 moduleRef.instance.ngDoBootstrap(appRef);
39844 }
39845 else {
39846 throw new Error(`The module ${stringify$1(moduleRef.instance
39847 .constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
39848 `Please define one of these.`);
39849 }
39850 this._modules.push(moduleRef);
39851 }
39852 /**
39853 * Registers a listener to be called when the platform is destroyed.
39854 */
39855 onDestroy(callback) {
39856 this._destroyListeners.push(callback);
39857 }
39858 /**
39859 * Retrieves the platform {@link Injector}, which is the parent injector for
39860 * every Angular application on the page and provides singleton providers.
39861 */
39862 get injector() {
39863 return this._injector;
39864 }
39865 /**
39866 * Destroys the current Angular platform and all Angular applications on the page.
39867 * Destroys all modules and listeners registered with the platform.
39868 */
39869 destroy() {
39870 if (this._destroyed) {
39871 throw new Error('The platform has already been destroyed!');
39872 }
39873 this._modules.slice().forEach(module => module.destroy());
39874 this._destroyListeners.forEach(listener => listener());
39875 this._destroyed = true;
39876 }
39877 get destroyed() {
39878 return this._destroyed;
39879 }
39880 }
39881 PlatformRef.decorators = [
39882 { type: Injectable }
39883 ];
39884 PlatformRef.ctorParameters = () => [
39885 { type: Injector }
39886 ];
39887 function getNgZone(ngZoneOption, extra) {
39888 let ngZone;
39889 if (ngZoneOption === 'noop') {
39890 ngZone = new NoopNgZone();
39891 }
39892 else {
39893 ngZone = (ngZoneOption === 'zone.js' ? undefined : ngZoneOption) || new NgZone({
39894 enableLongStackTrace: isDevMode(),
39895 shouldCoalesceEventChangeDetection: !!(extra === null || extra === void 0 ? void 0 : extra.ngZoneEventCoalescing),
39896 shouldCoalesceRunChangeDetection: !!(extra === null || extra === void 0 ? void 0 : extra.ngZoneRunCoalescing)
39897 });
39898 }
39899 return ngZone;
39900 }
39901 function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
39902 try {
39903 const result = callback();
39904 if (isPromise$1(result)) {
39905 return result.catch((e) => {
39906 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
39907 // rethrow as the exception handler might not do it
39908 throw e;
39909 });
39910 }
39911 return result;
39912 }
39913 catch (e) {
39914 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
39915 // rethrow as the exception handler might not do it
39916 throw e;
39917 }
39918 }
39919 function optionsReducer(dst, objs) {
39920 if (Array.isArray(objs)) {
39921 dst = objs.reduce(optionsReducer, dst);
39922 }
39923 else {
39924 dst = Object.assign(Object.assign({}, dst), objs);
39925 }
39926 return dst;
39927 }
39928 /**
39929 * A reference to an Angular application running on a page.
39930 *
39931 * @usageNotes
39932 *
39933 * {@a is-stable-examples}
39934 * ### isStable examples and caveats
39935 *
39936 * Note two important points about `isStable`, demonstrated in the examples below:
39937 * - the application will never be stable if you start any kind
39938 * of recurrent asynchronous task when the application starts
39939 * (for example for a polling process, started with a `setInterval`, a `setTimeout`
39940 * or using RxJS operators like `interval`);
39941 * - the `isStable` Observable runs outside of the Angular zone.
39942 *
39943 * Let's imagine that you start a recurrent task
39944 * (here incrementing a counter, using RxJS `interval`),
39945 * and at the same time subscribe to `isStable`.
39946 *
39947 * ```
39948 * constructor(appRef: ApplicationRef) {
39949 * appRef.isStable.pipe(
39950 * filter(stable => stable)
39951 * ).subscribe(() => console.log('App is stable now');
39952 * interval(1000).subscribe(counter => console.log(counter));
39953 * }
39954 * ```
39955 * In this example, `isStable` will never emit `true`,
39956 * and the trace "App is stable now" will never get logged.
39957 *
39958 * If you want to execute something when the app is stable,
39959 * you have to wait for the application to be stable
39960 * before starting your polling process.
39961 *
39962 * ```
39963 * constructor(appRef: ApplicationRef) {
39964 * appRef.isStable.pipe(
39965 * first(stable => stable),
39966 * tap(stable => console.log('App is stable now')),
39967 * switchMap(() => interval(1000))
39968 * ).subscribe(counter => console.log(counter));
39969 * }
39970 * ```
39971 * In this example, the trace "App is stable now" will be logged
39972 * and then the counter starts incrementing every second.
39973 *
39974 * Note also that this Observable runs outside of the Angular zone,
39975 * which means that the code in the subscription
39976 * to this Observable will not trigger the change detection.
39977 *
39978 * Let's imagine that instead of logging the counter value,
39979 * you update a field of your component
39980 * and display it in its template.
39981 *
39982 * ```
39983 * constructor(appRef: ApplicationRef) {
39984 * appRef.isStable.pipe(
39985 * first(stable => stable),
39986 * switchMap(() => interval(1000))
39987 * ).subscribe(counter => this.value = counter);
39988 * }
39989 * ```
39990 * As the `isStable` Observable runs outside the zone,
39991 * the `value` field will be updated properly,
39992 * but the template will not be refreshed!
39993 *
39994 * You'll have to manually trigger the change detection to update the template.
39995 *
39996 * ```
39997 * constructor(appRef: ApplicationRef, cd: ChangeDetectorRef) {
39998 * appRef.isStable.pipe(
39999 * first(stable => stable),
40000 * switchMap(() => interval(1000))
40001 * ).subscribe(counter => {
40002 * this.value = counter;
40003 * cd.detectChanges();
40004 * });
40005 * }
40006 * ```
40007 *
40008 * Or make the subscription callback run inside the zone.
40009 *
40010 * ```
40011 * constructor(appRef: ApplicationRef, zone: NgZone) {
40012 * appRef.isStable.pipe(
40013 * first(stable => stable),
40014 * switchMap(() => interval(1000))
40015 * ).subscribe(counter => zone.run(() => this.value = counter));
40016 * }
40017 * ```
40018 *
40019 * @publicApi
40020 */
40021 class ApplicationRef {
40022 /** @internal */
40023 constructor(_zone, _console, _injector, _exceptionHandler, _componentFactoryResolver, _initStatus) {
40024 this._zone = _zone;
40025 this._console = _console;
40026 this._injector = _injector;
40027 this._exceptionHandler = _exceptionHandler;
40028 this._componentFactoryResolver = _componentFactoryResolver;
40029 this._initStatus = _initStatus;
40030 /** @internal */
40031 this._bootstrapListeners = [];
40032 this._views = [];
40033 this._runningTick = false;
40034 this._stable = true;
40035 /**
40036 * Get a list of component types registered to this application.
40037 * This list is populated even before the component is created.
40038 */
40039 this.componentTypes = [];
40040 /**
40041 * Get a list of components registered to this application.
40042 */
40043 this.components = [];
40044 this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({
40045 next: () => {
40046 this._zone.run(() => {
40047 this.tick();
40048 });
40049 }
40050 });
40051 const isCurrentlyStable = new Observable((observer) => {
40052 this._stable = this._zone.isStable && !this._zone.hasPendingMacrotasks &&
40053 !this._zone.hasPendingMicrotasks;
40054 this._zone.runOutsideAngular(() => {
40055 observer.next(this._stable);
40056 observer.complete();
40057 });
40058 });
40059 const isStable = new Observable((observer) => {
40060 // Create the subscription to onStable outside the Angular Zone so that
40061 // the callback is run outside the Angular Zone.
40062 let stableSub;
40063 this._zone.runOutsideAngular(() => {
40064 stableSub = this._zone.onStable.subscribe(() => {
40065 NgZone.assertNotInAngularZone();
40066 // Check whether there are no pending macro/micro tasks in the next tick
40067 // to allow for NgZone to update the state.
40068 scheduleMicroTask(() => {
40069 if (!this._stable && !this._zone.hasPendingMacrotasks &&
40070 !this._zone.hasPendingMicrotasks) {
40071 this._stable = true;
40072 observer.next(true);
40073 }
40074 });
40075 });
40076 });
40077 const unstableSub = this._zone.onUnstable.subscribe(() => {
40078 NgZone.assertInAngularZone();
40079 if (this._stable) {
40080 this._stable = false;
40081 this._zone.runOutsideAngular(() => {
40082 observer.next(false);
40083 });
40084 }
40085 });
40086 return () => {
40087 stableSub.unsubscribe();
40088 unstableSub.unsubscribe();
40089 };
40090 });
40091 this.isStable =
40092 merge$1(isCurrentlyStable, isStable.pipe(share()));
40093 }
40094 /**
40095 * Bootstrap a new component at the root level of the application.
40096 *
40097 * @usageNotes
40098 * ### Bootstrap process
40099 *
40100 * When bootstrapping a new root component into an application, Angular mounts the
40101 * specified application component onto DOM elements identified by the componentType's
40102 * selector and kicks off automatic change detection to finish initializing the component.
40103 *
40104 * Optionally, a component can be mounted onto a DOM element that does not match the
40105 * componentType's selector.
40106 *
40107 * ### Example
40108 * {@example core/ts/platform/platform.ts region='longform'}
40109 */
40110 bootstrap(componentOrFactory, rootSelectorOrNode) {
40111 if (!this._initStatus.done) {
40112 throw new Error('Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
40113 }
40114 let componentFactory;
40115 if (componentOrFactory instanceof ComponentFactory) {
40116 componentFactory = componentOrFactory;
40117 }
40118 else {
40119 componentFactory =
40120 this._componentFactoryResolver.resolveComponentFactory(componentOrFactory);
40121 }
40122 this.componentTypes.push(componentFactory.componentType);
40123 // Create a factory associated with the current module if it's not bound to some other
40124 const ngModule = isBoundToModule(componentFactory) ? undefined : this._injector.get(NgModuleRef);
40125 const selectorOrNode = rootSelectorOrNode || componentFactory.selector;
40126 const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);
40127 const nativeElement = compRef.location.nativeElement;
40128 const testability = compRef.injector.get(Testability, null);
40129 const testabilityRegistry = testability && compRef.injector.get(TestabilityRegistry);
40130 if (testability && testabilityRegistry) {
40131 testabilityRegistry.registerApplication(nativeElement, testability);
40132 }
40133 compRef.onDestroy(() => {
40134 this.detachView(compRef.hostView);
40135 remove(this.components, compRef);
40136 if (testabilityRegistry) {
40137 testabilityRegistry.unregisterApplication(nativeElement);
40138 }
40139 });
40140 this._loadComponent(compRef);
40141 {
40142 this._console.log(`Angular is running in development mode. Call enableProdMode() to enable production mode.`);
40143 }
40144 return compRef;
40145 }
40146 /**
40147 * Invoke this method to explicitly process change detection and its side-effects.
40148 *
40149 * In development mode, `tick()` also performs a second change detection cycle to ensure that no
40150 * further changes are detected. If additional changes are picked up during this second cycle,
40151 * bindings in the app have side-effects that cannot be resolved in a single change detection
40152 * pass.
40153 * In this case, Angular throws an error, since an Angular application can only have one change
40154 * detection pass during which all change detection must complete.
40155 */
40156 tick() {
40157 if (this._runningTick) {
40158 throw new Error('ApplicationRef.tick is called recursively');
40159 }
40160 try {
40161 this._runningTick = true;
40162 for (let view of this._views) {
40163 view.detectChanges();
40164 }
40165 // Note that we have still left the `isDevMode()` condition in order to avoid
40166 // creating a breaking change for projects that still use the View Engine.
40167 if ((typeof ngDevMode === 'undefined' || ngDevMode) && isDevMode()) {
40168 for (let view of this._views) {
40169 view.checkNoChanges();
40170 }
40171 }
40172 }
40173 catch (e) {
40174 // Attention: Don't rethrow as it could cancel subscriptions to Observables!
40175 this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));
40176 }
40177 finally {
40178 this._runningTick = false;
40179 }
40180 }
40181 /**
40182 * Attaches a view so that it will be dirty checked.
40183 * The view will be automatically detached when it is destroyed.
40184 * This will throw if the view is already attached to a ViewContainer.
40185 */
40186 attachView(viewRef) {
40187 const view = viewRef;
40188 this._views.push(view);
40189 view.attachToAppRef(this);
40190 }
40191 /**
40192 * Detaches a view from dirty checking again.
40193 */
40194 detachView(viewRef) {
40195 const view = viewRef;
40196 remove(this._views, view);
40197 view.detachFromAppRef();
40198 }
40199 _loadComponent(componentRef) {
40200 this.attachView(componentRef.hostView);
40201 this.tick();
40202 this.components.push(componentRef);
40203 // Get the listeners lazily to prevent DI cycles.
40204 const listeners = this._injector.get(APP_BOOTSTRAP_LISTENER, []).concat(this._bootstrapListeners);
40205 listeners.forEach((listener) => listener(componentRef));
40206 }
40207 /** @internal */
40208 ngOnDestroy() {
40209 this._views.slice().forEach((view) => view.destroy());
40210 this._onMicrotaskEmptySubscription.unsubscribe();
40211 }
40212 /**
40213 * Returns the number of attached views.
40214 */
40215 get viewCount() {
40216 return this._views.length;
40217 }
40218 }
40219 ApplicationRef.decorators = [
40220 { type: Injectable }
40221 ];
40222 ApplicationRef.ctorParameters = () => [
40223 { type: NgZone },
40224 { type: Console },
40225 { type: Injector },
40226 { type: ErrorHandler },
40227 { type: ComponentFactoryResolver },
40228 { type: ApplicationInitStatus }
40229 ];
40230 function remove(list, el) {
40231 const index = list.indexOf(el);
40232 if (index > -1) {
40233 list.splice(index, 1);
40234 }
40235 }
40236
40237 /**
40238 * @license
40239 * Copyright Google LLC All Rights Reserved.
40240 *
40241 * Use of this source code is governed by an MIT-style license that can be
40242 * found in the LICENSE file at https://angular.io/license
40243 */
40244 const _CORE_PLATFORM_PROVIDERS = [
40245 // Set a default platform name for platforms that don't set it explicitly.
40246 { provide: PLATFORM_ID, useValue: 'unknown' },
40247 { provide: PlatformRef, deps: [Injector] },
40248 { provide: TestabilityRegistry, deps: [] },
40249 { provide: Console, deps: [] },
40250 ];
40251 /**
40252 * This platform has to be included in any other platform
40253 *
40254 * @publicApi
40255 */
40256 const platformCore = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS);
40257
40258 /**
40259 * @license
40260 * Copyright Google LLC All Rights Reserved.
40261 *
40262 * Use of this source code is governed by an MIT-style license that can be
40263 * found in the LICENSE file at https://angular.io/license
40264 */
40265 function _iterableDiffersFactory() {
40266 return defaultIterableDiffers;
40267 }
40268 function _keyValueDiffersFactory() {
40269 return defaultKeyValueDiffers;
40270 }
40271 function _localeFactory(locale) {
40272 locale = locale || getGlobalLocale();
40273 return locale;
40274 }
40275 /**
40276 * Work out the locale from the potential global properties.
40277 *
40278 * * Closure Compiler: use `goog.LOCALE`.
40279 * * Ivy enabled: use `$localize.locale`
40280 */
40281 function getGlobalLocale() {
40282 if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
40283 typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
40284 // * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
40285 // * In order to preserve backwards compatibility, we use Angular default value over
40286 // Closure Compiler's one.
40287 return goog.LOCALE;
40288 }
40289 else {
40290 // KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
40291 // COMPILE-TIME INLINER.
40292 //
40293 // * During compile time inlining of translations the expression will be replaced
40294 // with a string literal that is the current locale. Other forms of this expression are not
40295 // guaranteed to be replaced.
40296 //
40297 // * During runtime translation evaluation, the developer is required to set `$localize.locale`
40298 // if required, or just to provide their own `LOCALE_ID` provider.
40299 return DEFAULT_LOCALE_ID;
40300 }
40301 }
40302 const ɵ0$b = USD_CURRENCY_CODE;
40303 /**
40304 * A built-in [dependency injection token](guide/glossary#di-token)
40305 * that is used to configure the root injector for bootstrapping.
40306 */
40307 const APPLICATION_MODULE_PROVIDERS = [
40308 {
40309 provide: ApplicationRef,
40310 useClass: ApplicationRef,
40311 deps: [NgZone, Console, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus]
40312 },
40313 { provide: SCHEDULER, deps: [NgZone], useFactory: zoneSchedulerFactory },
40314 {
40315 provide: ApplicationInitStatus,
40316 useClass: ApplicationInitStatus,
40317 deps: [[new Optional(), APP_INITIALIZER]]
40318 },
40319 { provide: Compiler, useClass: Compiler, deps: [] },
40320 APP_ID_RANDOM_PROVIDER,
40321 { provide: IterableDiffers, useFactory: _iterableDiffersFactory, deps: [] },
40322 { provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory, deps: [] },
40323 {
40324 provide: LOCALE_ID$1,
40325 useFactory: _localeFactory,
40326 deps: [[new Inject(LOCALE_ID$1), new Optional(), new SkipSelf()]]
40327 },
40328 { provide: DEFAULT_CURRENCY_CODE, useValue: ɵ0$b },
40329 ];
40330 /**
40331 * Schedule work at next available slot.
40332 *
40333 * In Ivy this is just `requestAnimationFrame`. For compatibility reasons when bootstrapped
40334 * using `platformRef.bootstrap` we need to use `NgZone.onStable` as the scheduling mechanism.
40335 * This overrides the scheduling mechanism in Ivy to `NgZone.onStable`.
40336 *
40337 * @param ngZone NgZone to use for scheduling.
40338 */
40339 function zoneSchedulerFactory(ngZone) {
40340 let queue = [];
40341 ngZone.onStable.subscribe(() => {
40342 while (queue.length) {
40343 queue.pop()();
40344 }
40345 });
40346 return function (fn) {
40347 queue.push(fn);
40348 };
40349 }
40350
40351 /**
40352 * @license
40353 * Copyright Google LLC All Rights Reserved.
40354 *
40355 * Use of this source code is governed by an MIT-style license that can be
40356 * found in the LICENSE file at https://angular.io/license
40357 */
40358 var ViewAction;
40359 (function (ViewAction) {
40360 ViewAction[ViewAction["CreateViewNodes"] = 0] = "CreateViewNodes";
40361 ViewAction[ViewAction["CheckNoChanges"] = 1] = "CheckNoChanges";
40362 ViewAction[ViewAction["CheckNoChangesProjectedViews"] = 2] = "CheckNoChangesProjectedViews";
40363 ViewAction[ViewAction["CheckAndUpdate"] = 3] = "CheckAndUpdate";
40364 ViewAction[ViewAction["CheckAndUpdateProjectedViews"] = 4] = "CheckAndUpdateProjectedViews";
40365 ViewAction[ViewAction["Destroy"] = 5] = "Destroy";
40366 })(ViewAction || (ViewAction = {}));
40367
40368 /**
40369 * @license
40370 * Copyright Google LLC All Rights Reserved.
40371 *
40372 * Use of this source code is governed by an MIT-style license that can be
40373 * found in the LICENSE file at https://angular.io/license
40374 */
40375 var DebugAction;
40376 (function (DebugAction) {
40377 DebugAction[DebugAction["create"] = 0] = "create";
40378 DebugAction[DebugAction["detectChanges"] = 1] = "detectChanges";
40379 DebugAction[DebugAction["checkNoChanges"] = 2] = "checkNoChanges";
40380 DebugAction[DebugAction["destroy"] = 3] = "destroy";
40381 DebugAction[DebugAction["handleEvent"] = 4] = "handleEvent";
40382 })(DebugAction || (DebugAction = {}));
40383
40384 /**
40385 * @license
40386 * Copyright Google LLC All Rights Reserved.
40387 *
40388 * Use of this source code is governed by an MIT-style license that can be
40389 * found in the LICENSE file at https://angular.io/license
40390 */
40391 if (typeof ngDevMode !== 'undefined' && ngDevMode) {
40392 // This helper is to give a reasonable error message to people upgrading to v9 that have not yet
40393 // installed `@angular/localize` in their app.
40394 // tslint:disable-next-line: no-toplevel-property-access
40395 _global$1.$localize = _global$1.$localize || function () {
40396 throw new Error('It looks like your application or one of its dependencies is using i18n.\n' +
40397 'Angular 9 introduced a global `$localize()` function that needs to be loaded.\n' +
40398 'Please run `ng add @angular/localize` from the Angular CLI.\n' +
40399 '(For non-CLI projects, add `import \'@angular/localize/init\';` to your `polyfills.ts` file.\n' +
40400 'For server-side rendering applications add the import to your `main.server.ts` file.)');
40401 };
40402 }
40403
40404 /**
40405 * @license
40406 * Copyright Google LLC All Rights Reserved.
40407 *
40408 * Use of this source code is governed by an MIT-style license that can be
40409 * found in the LICENSE file at https://angular.io/license
40410 */
40411 // Metadata Schema
40412 // If you make a backwards incompatible change to the schema, increment the METADTA_VERSION number.
40413 // If you make a backwards compatible change to the metadata (such as adding an option field) then
40414 // leave METADATA_VERSION the same. If possible, supply as many versions of the metadata that can
40415 // represent the semantics of the file in an array. For example, when generating a version 2 file,
40416 // if version 1 can accurately represent the metadata, generate both version 1 and version 2 in
40417 // an array.
40418 const METADATA_VERSION = 4;
40419 function isClassMetadata(value) {
40420 return value && value.__symbolic === 'class';
40421 }
40422 function isMethodMetadata(value) {
40423 return value && (value.__symbolic === 'constructor' || value.__symbolic === 'method');
40424 }
40425 function isConstructorMetadata(value) {
40426 return value && value.__symbolic === 'constructor';
40427 }
40428 function isFunctionMetadata(value) {
40429 return value && value.__symbolic === 'function';
40430 }
40431 function isMetadataSymbolicExpression(value) {
40432 if (value) {
40433 switch (value.__symbolic) {
40434 case 'binary':
40435 case 'call':
40436 case 'index':
40437 case 'new':
40438 case 'pre':
40439 case 'reference':
40440 case 'select':
40441 case 'spread':
40442 case 'if':
40443 return true;
40444 }
40445 }
40446 return false;
40447 }
40448 function isMetadataGlobalReferenceExpression(value) {
40449 return value && value.name && !value.module && isMetadataSymbolicReferenceExpression(value);
40450 }
40451 function isMetadataModuleReferenceExpression(value) {
40452 return value && value.module && !value.name && !value.default &&
40453 isMetadataSymbolicReferenceExpression(value);
40454 }
40455 function isMetadataImportedSymbolReferenceExpression(value) {
40456 return value && value.module && !!value.name && isMetadataSymbolicReferenceExpression(value);
40457 }
40458 function isMetadataImportDefaultReference(value) {
40459 return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value);
40460 }
40461 function isMetadataSymbolicReferenceExpression(value) {
40462 return value && value.__symbolic === 'reference';
40463 }
40464 function isMetadataSymbolicSelectExpression(value) {
40465 return value && value.__symbolic === 'select';
40466 }
40467 function isMetadataSymbolicSpreadExpression(value) {
40468 return value && value.__symbolic === 'spread';
40469 }
40470 function isMetadataError$1(value) {
40471 return value && value.__symbolic === 'error';
40472 }
40473
40474 /**
40475 * @license
40476 * Copyright Google LLC All Rights Reserved.
40477 *
40478 * Use of this source code is governed by an MIT-style license that can be
40479 * found in the LICENSE file at https://angular.io/license
40480 */
40481 // In TypeScript 2.1 the spread element kind was renamed.
40482 const spreadElementSyntaxKind = ts.SyntaxKind.SpreadElement || ts.SyntaxKind.SpreadElementExpression;
40483 function isMethodCallOf(callExpression, memberName) {
40484 const expression = callExpression.expression;
40485 if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
40486 const propertyAccessExpression = expression;
40487 const name = propertyAccessExpression.name;
40488 if (name.kind == ts.SyntaxKind.Identifier) {
40489 return name.text === memberName;
40490 }
40491 }
40492 return false;
40493 }
40494 function isCallOf(callExpression, ident) {
40495 const expression = callExpression.expression;
40496 if (expression.kind === ts.SyntaxKind.Identifier) {
40497 const identifier = expression;
40498 return identifier.text === ident;
40499 }
40500 return false;
40501 }
40502 /* @internal */
40503 function recordMapEntry(entry, node, nodeMap, sourceFile) {
40504 if (!nodeMap.has(entry)) {
40505 nodeMap.set(entry, node);
40506 if (node &&
40507 (isMetadataImportedSymbolReferenceExpression(entry) ||
40508 isMetadataImportDefaultReference(entry)) &&
40509 entry.line == null) {
40510 const info = sourceInfo(node, sourceFile);
40511 if (info.line != null)
40512 entry.line = info.line;
40513 if (info.character != null)
40514 entry.character = info.character;
40515 }
40516 }
40517 return entry;
40518 }
40519 /**
40520 * ts.forEachChild stops iterating children when the callback return a truthy value.
40521 * This method inverts this to implement an `every` style iterator. It will return
40522 * true if every call to `cb` returns `true`.
40523 */
40524 function everyNodeChild(node, cb) {
40525 return !ts.forEachChild(node, node => !cb(node));
40526 }
40527 function isPrimitive$1(value) {
40528 return Object(value) !== value;
40529 }
40530 function isDefined$1(obj) {
40531 return obj !== undefined;
40532 }
40533 function getSourceFileOfNode(node) {
40534 while (node && node.kind != ts.SyntaxKind.SourceFile) {
40535 node = node.parent;
40536 }
40537 return node;
40538 }
40539 /* @internal */
40540 function sourceInfo(node, sourceFile) {
40541 if (node) {
40542 sourceFile = sourceFile || getSourceFileOfNode(node);
40543 if (sourceFile) {
40544 return ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
40545 }
40546 }
40547 return {};
40548 }
40549 /* @internal */
40550 function errorSymbol(message, node, context, sourceFile) {
40551 const result = Object.assign({ __symbolic: 'error', message }, sourceInfo(node, sourceFile));
40552 if (context) {
40553 result.context = context;
40554 }
40555 return result;
40556 }
40557 /**
40558 * Produce a symbolic representation of an expression folding values into their final value when
40559 * possible.
40560 */
40561 class Evaluator {
40562 constructor(symbols, nodeMap, options = {}, recordExport) {
40563 this.symbols = symbols;
40564 this.nodeMap = nodeMap;
40565 this.options = options;
40566 this.recordExport = recordExport;
40567 }
40568 nameOf(node) {
40569 if (node && node.kind == ts.SyntaxKind.Identifier) {
40570 return node.text;
40571 }
40572 const result = node && this.evaluateNode(node);
40573 if (isMetadataError$1(result) || typeof result === 'string') {
40574 return result;
40575 }
40576 else {
40577 return errorSymbol('Name expected', node, { received: (node && node.getText()) || '<missing>' });
40578 }
40579 }
40580 /**
40581 * Returns true if the expression represented by `node` can be folded into a literal expression.
40582 *
40583 * For example, a literal is always foldable. This means that literal expressions such as `1.2`
40584 * `"Some value"` `true` `false` are foldable.
40585 *
40586 * - An object literal is foldable if all the properties in the literal are foldable.
40587 * - An array literal is foldable if all the elements are foldable.
40588 * - A call is foldable if it is a call to a Array.prototype.concat or a call to CONST_EXPR.
40589 * - A property access is foldable if the object is foldable.
40590 * - A array index is foldable if index expression is foldable and the array is foldable.
40591 * - Binary operator expressions are foldable if the left and right expressions are foldable and
40592 * it is one of '+', '-', '*', '/', '%', '||', and '&&'.
40593 * - An identifier is foldable if a value can be found for its symbol in the evaluator symbol
40594 * table.
40595 */
40596 isFoldable(node) {
40597 return this.isFoldableWorker(node, new Map());
40598 }
40599 isFoldableWorker(node, folding) {
40600 if (node) {
40601 switch (node.kind) {
40602 case ts.SyntaxKind.ObjectLiteralExpression:
40603 return everyNodeChild(node, child => {
40604 if (child.kind === ts.SyntaxKind.PropertyAssignment) {
40605 const propertyAssignment = child;
40606 return this.isFoldableWorker(propertyAssignment.initializer, folding);
40607 }
40608 return false;
40609 });
40610 case ts.SyntaxKind.ArrayLiteralExpression:
40611 return everyNodeChild(node, child => this.isFoldableWorker(child, folding));
40612 case ts.SyntaxKind.CallExpression:
40613 const callExpression = node;
40614 // We can fold a <array>.concat(<v>).
40615 if (isMethodCallOf(callExpression, 'concat') &&
40616 arrayOrEmpty(callExpression.arguments).length === 1) {
40617 const arrayNode = callExpression.expression.expression;
40618 if (this.isFoldableWorker(arrayNode, folding) &&
40619 this.isFoldableWorker(callExpression.arguments[0], folding)) {
40620 // It needs to be an array.
40621 const arrayValue = this.evaluateNode(arrayNode);
40622 if (arrayValue && Array.isArray(arrayValue)) {
40623 return true;
40624 }
40625 }
40626 }
40627 // We can fold a call to CONST_EXPR
40628 if (isCallOf(callExpression, 'CONST_EXPR') &&
40629 arrayOrEmpty(callExpression.arguments).length === 1)
40630 return this.isFoldableWorker(callExpression.arguments[0], folding);
40631 return false;
40632 case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
40633 case ts.SyntaxKind.StringLiteral:
40634 case ts.SyntaxKind.NumericLiteral:
40635 case ts.SyntaxKind.NullKeyword:
40636 case ts.SyntaxKind.TrueKeyword:
40637 case ts.SyntaxKind.FalseKeyword:
40638 case ts.SyntaxKind.TemplateHead:
40639 case ts.SyntaxKind.TemplateMiddle:
40640 case ts.SyntaxKind.TemplateTail:
40641 return true;
40642 case ts.SyntaxKind.ParenthesizedExpression:
40643 const parenthesizedExpression = node;
40644 return this.isFoldableWorker(parenthesizedExpression.expression, folding);
40645 case ts.SyntaxKind.BinaryExpression:
40646 const binaryExpression = node;
40647 switch (binaryExpression.operatorToken.kind) {
40648 case ts.SyntaxKind.PlusToken:
40649 case ts.SyntaxKind.MinusToken:
40650 case ts.SyntaxKind.AsteriskToken:
40651 case ts.SyntaxKind.SlashToken:
40652 case ts.SyntaxKind.PercentToken:
40653 case ts.SyntaxKind.AmpersandAmpersandToken:
40654 case ts.SyntaxKind.BarBarToken:
40655 return this.isFoldableWorker(binaryExpression.left, folding) &&
40656 this.isFoldableWorker(binaryExpression.right, folding);
40657 default:
40658 return false;
40659 }
40660 case ts.SyntaxKind.PropertyAccessExpression:
40661 const propertyAccessExpression = node;
40662 return this.isFoldableWorker(propertyAccessExpression.expression, folding);
40663 case ts.SyntaxKind.ElementAccessExpression:
40664 const elementAccessExpression = node;
40665 return this.isFoldableWorker(elementAccessExpression.expression, folding) &&
40666 this.isFoldableWorker(elementAccessExpression.argumentExpression, folding);
40667 case ts.SyntaxKind.Identifier:
40668 let identifier = node;
40669 let reference = this.symbols.resolve(identifier.text);
40670 if (reference !== undefined && isPrimitive$1(reference)) {
40671 return true;
40672 }
40673 break;
40674 case ts.SyntaxKind.TemplateExpression:
40675 const templateExpression = node;
40676 return templateExpression.templateSpans.every(span => this.isFoldableWorker(span.expression, folding));
40677 }
40678 }
40679 return false;
40680 }
40681 /**
40682 * Produce a JSON serialiable object representing `node`. The foldable values in the expression
40683 * tree are folded. For example, a node representing `1 + 2` is folded into `3`.
40684 */
40685 evaluateNode(node, preferReference) {
40686 const t = this;
40687 let error;
40688 function recordEntry(entry, node) {
40689 if (t.options.substituteExpression) {
40690 const newEntry = t.options.substituteExpression(entry, node);
40691 if (t.recordExport && newEntry != entry && isMetadataGlobalReferenceExpression(newEntry)) {
40692 t.recordExport(newEntry.name, entry);
40693 }
40694 entry = newEntry;
40695 }
40696 return recordMapEntry(entry, node, t.nodeMap);
40697 }
40698 function isFoldableError(value) {
40699 return !t.options.verboseInvalidExpression && isMetadataError$1(value);
40700 }
40701 const resolveName = (name, preferReference) => {
40702 const reference = this.symbols.resolve(name, preferReference);
40703 if (reference === undefined) {
40704 // Encode as a global reference. StaticReflector will check the reference.
40705 return recordEntry({ __symbolic: 'reference', name }, node);
40706 }
40707 if (reference && isMetadataSymbolicReferenceExpression(reference)) {
40708 return recordEntry(Object.assign({}, reference), node);
40709 }
40710 return reference;
40711 };
40712 switch (node.kind) {
40713 case ts.SyntaxKind.ObjectLiteralExpression:
40714 let obj = {};
40715 let quoted = [];
40716 ts.forEachChild(node, child => {
40717 switch (child.kind) {
40718 case ts.SyntaxKind.ShorthandPropertyAssignment:
40719 case ts.SyntaxKind.PropertyAssignment:
40720 const assignment = child;
40721 if (assignment.name.kind == ts.SyntaxKind.StringLiteral) {
40722 const name = assignment.name.text;
40723 quoted.push(name);
40724 }
40725 const propertyName = this.nameOf(assignment.name);
40726 if (isFoldableError(propertyName)) {
40727 error = propertyName;
40728 return true;
40729 }
40730 const propertyValue = isPropertyAssignment(assignment) ?
40731 this.evaluateNode(assignment.initializer, /* preferReference */ true) :
40732 resolveName(propertyName, /* preferReference */ true);
40733 if (isFoldableError(propertyValue)) {
40734 error = propertyValue;
40735 return true; // Stop the forEachChild.
40736 }
40737 else {
40738 obj[propertyName] = isPropertyAssignment(assignment) ?
40739 recordEntry(propertyValue, assignment.initializer) :
40740 propertyValue;
40741 }
40742 }
40743 });
40744 if (error)
40745 return error;
40746 if (this.options.quotedNames && quoted.length) {
40747 obj['$quoted$'] = quoted;
40748 }
40749 return recordEntry(obj, node);
40750 case ts.SyntaxKind.ArrayLiteralExpression:
40751 let arr = [];
40752 ts.forEachChild(node, child => {
40753 const value = this.evaluateNode(child, /* preferReference */ true);
40754 // Check for error
40755 if (isFoldableError(value)) {
40756 error = value;
40757 return true; // Stop the forEachChild.
40758 }
40759 // Handle spread expressions
40760 if (isMetadataSymbolicSpreadExpression(value)) {
40761 if (Array.isArray(value.expression)) {
40762 for (const spreadValue of value.expression) {
40763 arr.push(spreadValue);
40764 }
40765 return;
40766 }
40767 }
40768 arr.push(value);
40769 });
40770 if (error)
40771 return error;
40772 return recordEntry(arr, node);
40773 case spreadElementSyntaxKind:
40774 let spreadExpression = this.evaluateNode(node.expression);
40775 return recordEntry({ __symbolic: 'spread', expression: spreadExpression }, node);
40776 case ts.SyntaxKind.CallExpression:
40777 const callExpression = node;
40778 if (isCallOf(callExpression, 'forwardRef') &&
40779 arrayOrEmpty(callExpression.arguments).length === 1) {
40780 const firstArgument = callExpression.arguments[0];
40781 if (firstArgument.kind == ts.SyntaxKind.ArrowFunction) {
40782 const arrowFunction = firstArgument;
40783 return recordEntry(this.evaluateNode(arrowFunction.body), node);
40784 }
40785 }
40786 const args = arrayOrEmpty(callExpression.arguments).map(arg => this.evaluateNode(arg));
40787 if (this.isFoldable(callExpression)) {
40788 if (isMethodCallOf(callExpression, 'concat')) {
40789 const arrayValue = this.evaluateNode(callExpression.expression.expression);
40790 if (isFoldableError(arrayValue))
40791 return arrayValue;
40792 return arrayValue.concat(args[0]);
40793 }
40794 }
40795 // Always fold a CONST_EXPR even if the argument is not foldable.
40796 if (isCallOf(callExpression, 'CONST_EXPR') &&
40797 arrayOrEmpty(callExpression.arguments).length === 1) {
40798 return recordEntry(args[0], node);
40799 }
40800 const expression = this.evaluateNode(callExpression.expression);
40801 if (isFoldableError(expression)) {
40802 return recordEntry(expression, node);
40803 }
40804 let result = { __symbolic: 'call', expression: expression };
40805 if (args && args.length) {
40806 result.arguments = args;
40807 }
40808 return recordEntry(result, node);
40809 case ts.SyntaxKind.NewExpression:
40810 const newExpression = node;
40811 const newArgs = arrayOrEmpty(newExpression.arguments).map(arg => this.evaluateNode(arg));
40812 const newTarget = this.evaluateNode(newExpression.expression);
40813 if (isMetadataError$1(newTarget)) {
40814 return recordEntry(newTarget, node);
40815 }
40816 const call = { __symbolic: 'new', expression: newTarget };
40817 if (newArgs.length) {
40818 call.arguments = newArgs;
40819 }
40820 return recordEntry(call, node);
40821 case ts.SyntaxKind.PropertyAccessExpression: {
40822 const propertyAccessExpression = node;
40823 const expression = this.evaluateNode(propertyAccessExpression.expression);
40824 if (isFoldableError(expression)) {
40825 return recordEntry(expression, node);
40826 }
40827 const member = this.nameOf(propertyAccessExpression.name);
40828 if (isFoldableError(member)) {
40829 return recordEntry(member, node);
40830 }
40831 if (expression && this.isFoldable(propertyAccessExpression.expression))
40832 return expression[member];
40833 if (isMetadataModuleReferenceExpression(expression)) {
40834 // A select into a module reference and be converted into a reference to the symbol
40835 // in the module
40836 return recordEntry({ __symbolic: 'reference', module: expression.module, name: member }, node);
40837 }
40838 return recordEntry({ __symbolic: 'select', expression, member }, node);
40839 }
40840 case ts.SyntaxKind.ElementAccessExpression: {
40841 const elementAccessExpression = node;
40842 const expression = this.evaluateNode(elementAccessExpression.expression);
40843 if (isFoldableError(expression)) {
40844 return recordEntry(expression, node);
40845 }
40846 if (!elementAccessExpression.argumentExpression) {
40847 return recordEntry(errorSymbol('Expression form not supported', node), node);
40848 }
40849 const index = this.evaluateNode(elementAccessExpression.argumentExpression);
40850 if (isFoldableError(expression)) {
40851 return recordEntry(expression, node);
40852 }
40853 if (this.isFoldable(elementAccessExpression.expression) &&
40854 this.isFoldable(elementAccessExpression.argumentExpression))
40855 return expression[index];
40856 return recordEntry({ __symbolic: 'index', expression, index }, node);
40857 }
40858 case ts.SyntaxKind.Identifier:
40859 const identifier = node;
40860 const name = identifier.text;
40861 return resolveName(name, preferReference);
40862 case ts.SyntaxKind.TypeReference:
40863 const typeReferenceNode = node;
40864 const typeNameNode = typeReferenceNode.typeName;
40865 const getReference = node => {
40866 if (typeNameNode.kind === ts.SyntaxKind.QualifiedName) {
40867 const qualifiedName = node;
40868 const left = this.evaluateNode(qualifiedName.left);
40869 if (isMetadataModuleReferenceExpression(left)) {
40870 return recordEntry({
40871 __symbolic: 'reference',
40872 module: left.module,
40873 name: qualifiedName.right.text
40874 }, node);
40875 }
40876 // Record a type reference to a declared type as a select.
40877 return { __symbolic: 'select', expression: left, member: qualifiedName.right.text };
40878 }
40879 else {
40880 const identifier = typeNameNode;
40881 const symbol = this.symbols.resolve(identifier.text);
40882 if (isFoldableError(symbol) || isMetadataSymbolicReferenceExpression(symbol)) {
40883 return recordEntry(symbol, node);
40884 }
40885 return recordEntry(errorSymbol('Could not resolve type', node, { typeName: identifier.text }), node);
40886 }
40887 };
40888 const typeReference = getReference(typeNameNode);
40889 if (isFoldableError(typeReference)) {
40890 return recordEntry(typeReference, node);
40891 }
40892 if (!isMetadataModuleReferenceExpression(typeReference) &&
40893 typeReferenceNode.typeArguments && typeReferenceNode.typeArguments.length) {
40894 const args = typeReferenceNode.typeArguments.map(element => this.evaluateNode(element));
40895 // TODO: Remove typecast when upgraded to 2.0 as it will be correctly inferred.
40896 // Some versions of 1.9 do not infer this correctly.
40897 typeReference.arguments = args;
40898 }
40899 return recordEntry(typeReference, node);
40900 case ts.SyntaxKind.UnionType:
40901 const unionType = node;
40902 // Remove null and undefined from the list of unions.
40903 const references = unionType.types
40904 .filter(n => n.kind !== ts.SyntaxKind.UndefinedKeyword &&
40905 !(ts.isLiteralTypeNode(n) && n.literal.kind === ts.SyntaxKind.NullKeyword))
40906 .map(n => this.evaluateNode(n));
40907 // The remmaining reference must be the same. If two have type arguments consider them
40908 // different even if the type arguments are the same.
40909 let candidate = null;
40910 for (let i = 0; i < references.length; i++) {
40911 const reference = references[i];
40912 if (isMetadataSymbolicReferenceExpression(reference)) {
40913 if (candidate) {
40914 if (reference.name == candidate.name &&
40915 reference.module == candidate.module && !reference.arguments) {
40916 candidate = reference;
40917 }
40918 }
40919 else {
40920 candidate = reference;
40921 }
40922 }
40923 else {
40924 return reference;
40925 }
40926 }
40927 if (candidate)
40928 return candidate;
40929 break;
40930 case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
40931 case ts.SyntaxKind.StringLiteral:
40932 case ts.SyntaxKind.TemplateHead:
40933 case ts.SyntaxKind.TemplateTail:
40934 case ts.SyntaxKind.TemplateMiddle:
40935 return node.text;
40936 case ts.SyntaxKind.NumericLiteral:
40937 return parseFloat(node.text);
40938 case ts.SyntaxKind.AnyKeyword:
40939 return recordEntry({ __symbolic: 'reference', name: 'any' }, node);
40940 case ts.SyntaxKind.StringKeyword:
40941 return recordEntry({ __symbolic: 'reference', name: 'string' }, node);
40942 case ts.SyntaxKind.NumberKeyword:
40943 return recordEntry({ __symbolic: 'reference', name: 'number' }, node);
40944 case ts.SyntaxKind.BooleanKeyword:
40945 return recordEntry({ __symbolic: 'reference', name: 'boolean' }, node);
40946 case ts.SyntaxKind.ArrayType:
40947 const arrayTypeNode = node;
40948 return recordEntry({
40949 __symbolic: 'reference',
40950 name: 'Array',
40951 arguments: [this.evaluateNode(arrayTypeNode.elementType)]
40952 }, node);
40953 case ts.SyntaxKind.NullKeyword:
40954 return null;
40955 case ts.SyntaxKind.TrueKeyword:
40956 return true;
40957 case ts.SyntaxKind.FalseKeyword:
40958 return false;
40959 case ts.SyntaxKind.ParenthesizedExpression:
40960 const parenthesizedExpression = node;
40961 return this.evaluateNode(parenthesizedExpression.expression);
40962 case ts.SyntaxKind.TypeAssertionExpression:
40963 const typeAssertion = node;
40964 return this.evaluateNode(typeAssertion.expression);
40965 case ts.SyntaxKind.PrefixUnaryExpression:
40966 const prefixUnaryExpression = node;
40967 const operand = this.evaluateNode(prefixUnaryExpression.operand);
40968 if (isDefined$1(operand) && isPrimitive$1(operand)) {
40969 switch (prefixUnaryExpression.operator) {
40970 case ts.SyntaxKind.PlusToken:
40971 return +operand;
40972 case ts.SyntaxKind.MinusToken:
40973 return -operand;
40974 case ts.SyntaxKind.TildeToken:
40975 return ~operand;
40976 case ts.SyntaxKind.ExclamationToken:
40977 return !operand;
40978 }
40979 }
40980 let operatorText;
40981 switch (prefixUnaryExpression.operator) {
40982 case ts.SyntaxKind.PlusToken:
40983 operatorText = '+';
40984 break;
40985 case ts.SyntaxKind.MinusToken:
40986 operatorText = '-';
40987 break;
40988 case ts.SyntaxKind.TildeToken:
40989 operatorText = '~';
40990 break;
40991 case ts.SyntaxKind.ExclamationToken:
40992 operatorText = '!';
40993 break;
40994 default:
40995 return undefined;
40996 }
40997 return recordEntry({ __symbolic: 'pre', operator: operatorText, operand: operand }, node);
40998 case ts.SyntaxKind.BinaryExpression:
40999 const binaryExpression = node;
41000 const left = this.evaluateNode(binaryExpression.left);
41001 const right = this.evaluateNode(binaryExpression.right);
41002 if (isDefined$1(left) && isDefined$1(right)) {
41003 if (isPrimitive$1(left) && isPrimitive$1(right))
41004 switch (binaryExpression.operatorToken.kind) {
41005 case ts.SyntaxKind.BarBarToken:
41006 return left || right;
41007 case ts.SyntaxKind.AmpersandAmpersandToken:
41008 return left && right;
41009 case ts.SyntaxKind.AmpersandToken:
41010 return left & right;
41011 case ts.SyntaxKind.BarToken:
41012 return left | right;
41013 case ts.SyntaxKind.CaretToken:
41014 return left ^ right;
41015 case ts.SyntaxKind.EqualsEqualsToken:
41016 return left == right;
41017 case ts.SyntaxKind.ExclamationEqualsToken:
41018 return left != right;
41019 case ts.SyntaxKind.EqualsEqualsEqualsToken:
41020 return left === right;
41021 case ts.SyntaxKind.ExclamationEqualsEqualsToken:
41022 return left !== right;
41023 case ts.SyntaxKind.LessThanToken:
41024 return left < right;
41025 case ts.SyntaxKind.GreaterThanToken:
41026 return left > right;
41027 case ts.SyntaxKind.LessThanEqualsToken:
41028 return left <= right;
41029 case ts.SyntaxKind.GreaterThanEqualsToken:
41030 return left >= right;
41031 case ts.SyntaxKind.LessThanLessThanToken:
41032 return left << right;
41033 case ts.SyntaxKind.GreaterThanGreaterThanToken:
41034 return left >> right;
41035 case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
41036 return left >>> right;
41037 case ts.SyntaxKind.PlusToken:
41038 return left + right;
41039 case ts.SyntaxKind.MinusToken:
41040 return left - right;
41041 case ts.SyntaxKind.AsteriskToken:
41042 return left * right;
41043 case ts.SyntaxKind.SlashToken:
41044 return left / right;
41045 case ts.SyntaxKind.PercentToken:
41046 return left % right;
41047 }
41048 return recordEntry({
41049 __symbolic: 'binop',
41050 operator: binaryExpression.operatorToken.getText(),
41051 left: left,
41052 right: right
41053 }, node);
41054 }
41055 break;
41056 case ts.SyntaxKind.ConditionalExpression:
41057 const conditionalExpression = node;
41058 const condition = this.evaluateNode(conditionalExpression.condition);
41059 const thenExpression = this.evaluateNode(conditionalExpression.whenTrue);
41060 const elseExpression = this.evaluateNode(conditionalExpression.whenFalse);
41061 if (isPrimitive$1(condition)) {
41062 return condition ? thenExpression : elseExpression;
41063 }
41064 return recordEntry({ __symbolic: 'if', condition, thenExpression, elseExpression }, node);
41065 case ts.SyntaxKind.FunctionExpression:
41066 case ts.SyntaxKind.ArrowFunction:
41067 return recordEntry(errorSymbol('Lambda not supported', node), node);
41068 case ts.SyntaxKind.TaggedTemplateExpression:
41069 return recordEntry(errorSymbol('Tagged template expressions are not supported in metadata', node), node);
41070 case ts.SyntaxKind.TemplateExpression:
41071 const templateExpression = node;
41072 if (this.isFoldable(node)) {
41073 return templateExpression.templateSpans.reduce((previous, current) => previous + this.evaluateNode(current.expression) +
41074 this.evaluateNode(current.literal), this.evaluateNode(templateExpression.head));
41075 }
41076 else {
41077 return templateExpression.templateSpans.reduce((previous, current) => {
41078 const expr = this.evaluateNode(current.expression);
41079 const literal = this.evaluateNode(current.literal);
41080 if (isFoldableError(expr))
41081 return expr;
41082 if (isFoldableError(literal))
41083 return literal;
41084 if (typeof previous === 'string' && typeof expr === 'string' &&
41085 typeof literal === 'string') {
41086 return previous + expr + literal;
41087 }
41088 let result = expr;
41089 if (previous !== '') {
41090 result = { __symbolic: 'binop', operator: '+', left: previous, right: expr };
41091 }
41092 if (literal != '') {
41093 result = { __symbolic: 'binop', operator: '+', left: result, right: literal };
41094 }
41095 return result;
41096 }, this.evaluateNode(templateExpression.head));
41097 }
41098 case ts.SyntaxKind.AsExpression:
41099 const asExpression = node;
41100 return this.evaluateNode(asExpression.expression);
41101 case ts.SyntaxKind.ClassExpression:
41102 return { __symbolic: 'class' };
41103 }
41104 return recordEntry(errorSymbol('Expression form not supported', node), node);
41105 }
41106 }
41107 function isPropertyAssignment(node) {
41108 return node.kind == ts.SyntaxKind.PropertyAssignment;
41109 }
41110 const empty$1 = ts.createNodeArray();
41111 function arrayOrEmpty(v) {
41112 return v || empty$1;
41113 }
41114
41115 /**
41116 * @license
41117 * Copyright Google LLC All Rights Reserved.
41118 *
41119 * Use of this source code is governed by an MIT-style license that can be
41120 * found in the LICENSE file at https://angular.io/license
41121 */
41122 class Symbols {
41123 constructor(sourceFile) {
41124 this.sourceFile = sourceFile;
41125 this.references = new Map();
41126 }
41127 resolve(name, preferReference) {
41128 return (preferReference && this.references.get(name)) || this.symbols.get(name);
41129 }
41130 define(name, value) {
41131 this.symbols.set(name, value);
41132 }
41133 defineReference(name, value) {
41134 this.references.set(name, value);
41135 }
41136 has(name) {
41137 return this.symbols.has(name);
41138 }
41139 get symbols() {
41140 let result = this._symbols;
41141 if (!result) {
41142 result = this._symbols = new Map();
41143 populateBuiltins(result);
41144 this.buildImports();
41145 }
41146 return result;
41147 }
41148 buildImports() {
41149 const symbols = this._symbols;
41150 // Collect the imported symbols into this.symbols
41151 const stripQuotes = (s) => s.replace(/^['"]|['"]$/g, '');
41152 const visit = (node) => {
41153 switch (node.kind) {
41154 case ts.SyntaxKind.ImportEqualsDeclaration:
41155 const importEqualsDeclaration = node;
41156 if (importEqualsDeclaration.moduleReference.kind ===
41157 ts.SyntaxKind.ExternalModuleReference) {
41158 const externalReference = importEqualsDeclaration.moduleReference;
41159 if (externalReference.expression) {
41160 // An `import <identifier> = require(<module-specifier>);
41161 if (!externalReference.expression.parent) {
41162 // The `parent` field of a node is set by the TypeScript binder (run as
41163 // part of the type checker). Setting it here allows us to call `getText()`
41164 // even if the `SourceFile` was not type checked (which looks for `SourceFile`
41165 // in the parent chain). This doesn't damage the node as the binder unconditionally
41166 // sets the parent.
41167 externalReference.expression.parent = externalReference;
41168 externalReference.parent = this.sourceFile;
41169 }
41170 const from = stripQuotes(externalReference.expression.getText());
41171 symbols.set(importEqualsDeclaration.name.text, { __symbolic: 'reference', module: from });
41172 break;
41173 }
41174 }
41175 symbols.set(importEqualsDeclaration.name.text, { __symbolic: 'error', message: `Unsupported import syntax` });
41176 break;
41177 case ts.SyntaxKind.ImportDeclaration:
41178 const importDecl = node;
41179 if (!importDecl.importClause) {
41180 // An `import <module-specifier>` clause which does not bring symbols into scope.
41181 break;
41182 }
41183 if (!importDecl.moduleSpecifier.parent) {
41184 // See note above in the `ImportEqualDeclaration` case.
41185 importDecl.moduleSpecifier.parent = importDecl;
41186 importDecl.parent = this.sourceFile;
41187 }
41188 const from = stripQuotes(importDecl.moduleSpecifier.getText());
41189 if (importDecl.importClause.name) {
41190 // An `import <identifier> form <module-specifier>` clause. Record the default symbol.
41191 symbols.set(importDecl.importClause.name.text, { __symbolic: 'reference', module: from, default: true });
41192 }
41193 const bindings = importDecl.importClause.namedBindings;
41194 if (bindings) {
41195 switch (bindings.kind) {
41196 case ts.SyntaxKind.NamedImports:
41197 // An `import { [<identifier> [, <identifier>] } from <module-specifier>` clause
41198 for (const binding of bindings.elements) {
41199 symbols.set(binding.name.text, {
41200 __symbolic: 'reference',
41201 module: from,
41202 name: binding.propertyName ? binding.propertyName.text : binding.name.text
41203 });
41204 }
41205 break;
41206 case ts.SyntaxKind.NamespaceImport:
41207 // An `input * as <identifier> from <module-specifier>` clause.
41208 symbols.set(bindings.name.text, { __symbolic: 'reference', module: from });
41209 break;
41210 }
41211 }
41212 break;
41213 }
41214 ts.forEachChild(node, visit);
41215 };
41216 if (this.sourceFile) {
41217 ts.forEachChild(this.sourceFile, visit);
41218 }
41219 }
41220 }
41221 function populateBuiltins(symbols) {
41222 // From lib.core.d.ts (all "define const")
41223 ['Object', 'Function', 'String', 'Number', 'Array', 'Boolean', 'Map', 'NaN', 'Infinity', 'Math',
41224 'Date', 'RegExp', 'Error', 'Error', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError',
41225 'TypeError', 'URIError', 'JSON', 'ArrayBuffer', 'DataView', 'Int8Array', 'Uint8Array',
41226 'Uint8ClampedArray', 'Uint16Array', 'Int16Array', 'Int32Array', 'Uint32Array', 'Float32Array',
41227 'Float64Array']
41228 .forEach(name => symbols.set(name, { __symbolic: 'reference', name }));
41229 }
41230
41231 /**
41232 * @license
41233 * Copyright Google LLC All Rights Reserved.
41234 *
41235 * Use of this source code is governed by an MIT-style license that can be
41236 * found in the LICENSE file at https://angular.io/license
41237 */
41238 const isStatic = (node) => ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static;
41239 /**
41240 * Collect decorator metadata from a TypeScript module.
41241 */
41242 class MetadataCollector {
41243 constructor(options = {}) {
41244 this.options = options;
41245 }
41246 /**
41247 * Returns a JSON.stringify friendly form describing the decorators of the exported classes from
41248 * the source file that is expected to correspond to a module.
41249 */
41250 getMetadata(sourceFile, strict = false, substituteExpression) {
41251 const locals = new Symbols(sourceFile);
41252 const nodeMap = new Map();
41253 const composedSubstituter = substituteExpression && this.options.substituteExpression ?
41254 (value, node) => this.options.substituteExpression(substituteExpression(value, node), node) :
41255 substituteExpression;
41256 const evaluatorOptions = substituteExpression ? Object.assign(Object.assign({}, this.options), { substituteExpression: composedSubstituter }) :
41257 this.options;
41258 let metadata;
41259 const evaluator = new Evaluator(locals, nodeMap, evaluatorOptions, (name, value) => {
41260 if (!metadata)
41261 metadata = {};
41262 metadata[name] = value;
41263 });
41264 let exports = undefined;
41265 function objFromDecorator(decoratorNode) {
41266 return evaluator.evaluateNode(decoratorNode.expression);
41267 }
41268 function recordEntry(entry, node) {
41269 if (composedSubstituter) {
41270 entry = composedSubstituter(entry, node);
41271 }
41272 return recordMapEntry(entry, node, nodeMap, sourceFile);
41273 }
41274 function errorSym(message, node, context) {
41275 return errorSymbol(message, node, context, sourceFile);
41276 }
41277 function maybeGetSimpleFunction(functionDeclaration) {
41278 if (functionDeclaration.name && functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
41279 const nameNode = functionDeclaration.name;
41280 const functionName = nameNode.text;
41281 const functionBody = functionDeclaration.body;
41282 if (functionBody && functionBody.statements.length == 1) {
41283 const statement = functionBody.statements[0];
41284 if (statement.kind === ts.SyntaxKind.ReturnStatement) {
41285 const returnStatement = statement;
41286 if (returnStatement.expression) {
41287 const func = {
41288 __symbolic: 'function',
41289 parameters: namesOf(functionDeclaration.parameters),
41290 value: evaluator.evaluateNode(returnStatement.expression)
41291 };
41292 if (functionDeclaration.parameters.some(p => p.initializer != null)) {
41293 func.defaults = functionDeclaration.parameters.map(p => p.initializer && evaluator.evaluateNode(p.initializer));
41294 }
41295 return recordEntry({ func, name: functionName }, functionDeclaration);
41296 }
41297 }
41298 }
41299 }
41300 }
41301 function classMetadataOf(classDeclaration) {
41302 const result = { __symbolic: 'class' };
41303 function getDecorators(decorators) {
41304 if (decorators && decorators.length)
41305 return decorators.map(decorator => objFromDecorator(decorator));
41306 return undefined;
41307 }
41308 function referenceFrom(node) {
41309 const result = evaluator.evaluateNode(node);
41310 if (isMetadataError$1(result) || isMetadataSymbolicReferenceExpression(result) ||
41311 isMetadataSymbolicSelectExpression(result)) {
41312 return result;
41313 }
41314 else {
41315 return errorSym('Symbol reference expected', node);
41316 }
41317 }
41318 // Add class parents
41319 if (classDeclaration.heritageClauses) {
41320 classDeclaration.heritageClauses.forEach((hc) => {
41321 if (hc.token === ts.SyntaxKind.ExtendsKeyword && hc.types) {
41322 hc.types.forEach(type => result.extends = referenceFrom(type.expression));
41323 }
41324 });
41325 }
41326 // Add arity if the type is generic
41327 const typeParameters = classDeclaration.typeParameters;
41328 if (typeParameters && typeParameters.length) {
41329 result.arity = typeParameters.length;
41330 }
41331 // Add class decorators
41332 if (classDeclaration.decorators) {
41333 result.decorators = getDecorators(classDeclaration.decorators);
41334 }
41335 // member decorators
41336 let members = null;
41337 function recordMember(name, metadata) {
41338 if (!members)
41339 members = {};
41340 const data = members.hasOwnProperty(name) ? members[name] : [];
41341 data.push(metadata);
41342 members[name] = data;
41343 }
41344 // static member
41345 let statics = null;
41346 function recordStaticMember(name, value) {
41347 if (!statics)
41348 statics = {};
41349 statics[name] = value;
41350 }
41351 for (const member of classDeclaration.members) {
41352 let isConstructor = false;
41353 switch (member.kind) {
41354 case ts.SyntaxKind.Constructor:
41355 case ts.SyntaxKind.MethodDeclaration:
41356 isConstructor = member.kind === ts.SyntaxKind.Constructor;
41357 const method = member;
41358 if (isStatic(method)) {
41359 const maybeFunc = maybeGetSimpleFunction(method);
41360 if (maybeFunc) {
41361 recordStaticMember(maybeFunc.name, maybeFunc.func);
41362 }
41363 continue;
41364 }
41365 const methodDecorators = getDecorators(method.decorators);
41366 const parameters = method.parameters;
41367 const parameterDecoratorData = [];
41368 const parametersData = [];
41369 let hasDecoratorData = false;
41370 let hasParameterData = false;
41371 for (const parameter of parameters) {
41372 const parameterData = getDecorators(parameter.decorators);
41373 parameterDecoratorData.push(parameterData);
41374 hasDecoratorData = hasDecoratorData || !!parameterData;
41375 if (isConstructor) {
41376 if (parameter.type) {
41377 parametersData.push(referenceFrom(parameter.type));
41378 }
41379 else {
41380 parametersData.push(null);
41381 }
41382 hasParameterData = true;
41383 }
41384 }
41385 const data = { __symbolic: isConstructor ? 'constructor' : 'method' };
41386 const name = isConstructor ? '__ctor__' : evaluator.nameOf(member.name);
41387 if (methodDecorators) {
41388 data.decorators = methodDecorators;
41389 }
41390 if (hasDecoratorData) {
41391 data.parameterDecorators = parameterDecoratorData;
41392 }
41393 if (hasParameterData) {
41394 data.parameters = parametersData;
41395 }
41396 if (!isMetadataError$1(name)) {
41397 recordMember(name, data);
41398 }
41399 break;
41400 case ts.SyntaxKind.PropertyDeclaration:
41401 case ts.SyntaxKind.GetAccessor:
41402 case ts.SyntaxKind.SetAccessor:
41403 const property = member;
41404 if (isStatic(property)) {
41405 const name = evaluator.nameOf(property.name);
41406 if (!isMetadataError$1(name) && !shouldIgnoreStaticMember(name)) {
41407 if (property.initializer) {
41408 const value = evaluator.evaluateNode(property.initializer);
41409 recordStaticMember(name, value);
41410 }
41411 else {
41412 recordStaticMember(name, errorSym('Variable not initialized', property.name));
41413 }
41414 }
41415 }
41416 const propertyDecorators = getDecorators(property.decorators);
41417 if (propertyDecorators) {
41418 const name = evaluator.nameOf(property.name);
41419 if (!isMetadataError$1(name)) {
41420 recordMember(name, { __symbolic: 'property', decorators: propertyDecorators });
41421 }
41422 }
41423 break;
41424 }
41425 }
41426 if (members) {
41427 result.members = members;
41428 }
41429 if (statics) {
41430 result.statics = statics;
41431 }
41432 return recordEntry(result, classDeclaration);
41433 }
41434 // Collect all exported symbols from an exports clause.
41435 const exportMap = new Map();
41436 ts.forEachChild(sourceFile, node => {
41437 switch (node.kind) {
41438 case ts.SyntaxKind.ExportDeclaration:
41439 const exportDeclaration = node;
41440 const { moduleSpecifier, exportClause } = exportDeclaration;
41441 if (!moduleSpecifier && exportClause && ts.isNamedExports(exportClause)) {
41442 // If there is a module specifier there is also an exportClause
41443 exportClause.elements.forEach(spec => {
41444 const exportedAs = spec.name.text;
41445 const name = (spec.propertyName || spec.name).text;
41446 exportMap.set(name, exportedAs);
41447 });
41448 }
41449 }
41450 });
41451 const isExport = (node) => sourceFile.isDeclarationFile ||
41452 ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export;
41453 const isExportedIdentifier = (identifier) => identifier && exportMap.has(identifier.text);
41454 const isExported = (node) => isExport(node) || isExportedIdentifier(node.name);
41455 const exportedIdentifierName = (identifier) => identifier && (exportMap.get(identifier.text) || identifier.text);
41456 const exportedName = (node) => exportedIdentifierName(node.name);
41457 // Pre-declare classes and functions
41458 ts.forEachChild(sourceFile, node => {
41459 switch (node.kind) {
41460 case ts.SyntaxKind.ClassDeclaration:
41461 const classDeclaration = node;
41462 if (classDeclaration.name) {
41463 const className = classDeclaration.name.text;
41464 if (isExported(classDeclaration)) {
41465 locals.define(className, { __symbolic: 'reference', name: exportedName(classDeclaration) });
41466 }
41467 else {
41468 locals.define(className, errorSym('Reference to non-exported class', node, { className }));
41469 }
41470 }
41471 break;
41472 case ts.SyntaxKind.InterfaceDeclaration:
41473 const interfaceDeclaration = node;
41474 if (interfaceDeclaration.name) {
41475 const interfaceName = interfaceDeclaration.name.text;
41476 // All references to interfaces should be converted to references to `any`.
41477 locals.define(interfaceName, { __symbolic: 'reference', name: 'any' });
41478 }
41479 break;
41480 case ts.SyntaxKind.FunctionDeclaration:
41481 const functionDeclaration = node;
41482 if (!isExported(functionDeclaration)) {
41483 // Report references to this function as an error.
41484 const nameNode = functionDeclaration.name;
41485 if (nameNode && nameNode.text) {
41486 locals.define(nameNode.text, errorSym('Reference to a non-exported function', nameNode, { name: nameNode.text }));
41487 }
41488 }
41489 break;
41490 }
41491 });
41492 ts.forEachChild(sourceFile, node => {
41493 switch (node.kind) {
41494 case ts.SyntaxKind.ExportDeclaration:
41495 // Record export declarations
41496 const exportDeclaration = node;
41497 const { moduleSpecifier, exportClause } = exportDeclaration;
41498 if (!moduleSpecifier) {
41499 // no module specifier -> export {propName as name};
41500 if (exportClause && ts.isNamedExports(exportClause)) {
41501 exportClause.elements.forEach(spec => {
41502 const name = spec.name.text;
41503 // If the symbol was not already exported, export a reference since it is a
41504 // reference to an import
41505 if (!metadata || !metadata[name]) {
41506 const propNode = spec.propertyName || spec.name;
41507 const value = evaluator.evaluateNode(propNode);
41508 if (!metadata)
41509 metadata = {};
41510 metadata[name] = recordEntry(value, node);
41511 }
41512 });
41513 }
41514 }
41515 if (moduleSpecifier && moduleSpecifier.kind == ts.SyntaxKind.StringLiteral) {
41516 // Ignore exports that don't have string literals as exports.
41517 // This is allowed by the syntax but will be flagged as an error by the type checker.
41518 const from = moduleSpecifier.text;
41519 const moduleExport = { from };
41520 if (exportClause && ts.isNamedExports(exportClause)) {
41521 moduleExport.export = exportClause.elements.map(spec => spec.propertyName ? { name: spec.propertyName.text, as: spec.name.text } :
41522 spec.name.text);
41523 }
41524 if (!exports)
41525 exports = [];
41526 exports.push(moduleExport);
41527 }
41528 break;
41529 case ts.SyntaxKind.ClassDeclaration:
41530 const classDeclaration = node;
41531 if (classDeclaration.name) {
41532 if (isExported(classDeclaration)) {
41533 const name = exportedName(classDeclaration);
41534 if (name) {
41535 if (!metadata)
41536 metadata = {};
41537 metadata[name] = classMetadataOf(classDeclaration);
41538 }
41539 }
41540 }
41541 // Otherwise don't record metadata for the class.
41542 break;
41543 case ts.SyntaxKind.TypeAliasDeclaration:
41544 const typeDeclaration = node;
41545 if (typeDeclaration.name && isExported(typeDeclaration)) {
41546 const name = exportedName(typeDeclaration);
41547 if (name) {
41548 if (!metadata)
41549 metadata = {};
41550 metadata[name] = { __symbolic: 'interface' };
41551 }
41552 }
41553 break;
41554 case ts.SyntaxKind.InterfaceDeclaration:
41555 const interfaceDeclaration = node;
41556 if (interfaceDeclaration.name && isExported(interfaceDeclaration)) {
41557 const name = exportedName(interfaceDeclaration);
41558 if (name) {
41559 if (!metadata)
41560 metadata = {};
41561 metadata[name] = { __symbolic: 'interface' };
41562 }
41563 }
41564 break;
41565 case ts.SyntaxKind.FunctionDeclaration:
41566 // Record functions that return a single value. Record the parameter
41567 // names substitution will be performed by the StaticReflector.
41568 const functionDeclaration = node;
41569 if (isExported(functionDeclaration) && functionDeclaration.name) {
41570 const name = exportedName(functionDeclaration);
41571 const maybeFunc = maybeGetSimpleFunction(functionDeclaration);
41572 if (name) {
41573 if (!metadata)
41574 metadata = {};
41575 // TODO(alxhub): The literal here is not valid FunctionMetadata.
41576 metadata[name] =
41577 maybeFunc ? recordEntry(maybeFunc.func, node) : { __symbolic: 'function' };
41578 }
41579 }
41580 break;
41581 case ts.SyntaxKind.EnumDeclaration:
41582 const enumDeclaration = node;
41583 if (isExported(enumDeclaration)) {
41584 const enumValueHolder = {};
41585 const enumName = exportedName(enumDeclaration);
41586 let nextDefaultValue = 0;
41587 let writtenMembers = 0;
41588 for (const member of enumDeclaration.members) {
41589 let enumValue;
41590 if (!member.initializer) {
41591 enumValue = nextDefaultValue;
41592 }
41593 else {
41594 enumValue = evaluator.evaluateNode(member.initializer);
41595 }
41596 let name = undefined;
41597 if (member.name.kind == ts.SyntaxKind.Identifier) {
41598 const identifier = member.name;
41599 name = identifier.text;
41600 enumValueHolder[name] = enumValue;
41601 writtenMembers++;
41602 }
41603 if (typeof enumValue === 'number') {
41604 nextDefaultValue = enumValue + 1;
41605 }
41606 else if (name) {
41607 // TODO(alxhub): 'left' here has a name propery which is not valid for
41608 // MetadataSymbolicSelectExpression.
41609 nextDefaultValue = {
41610 __symbolic: 'binary',
41611 operator: '+',
41612 left: {
41613 __symbolic: 'select',
41614 expression: recordEntry({ __symbolic: 'reference', name: enumName }, node),
41615 name
41616 },
41617 };
41618 }
41619 else {
41620 nextDefaultValue =
41621 recordEntry(errorSym('Unsupported enum member name', member.name), node);
41622 }
41623 }
41624 if (writtenMembers) {
41625 if (enumName) {
41626 if (!metadata)
41627 metadata = {};
41628 metadata[enumName] = recordEntry(enumValueHolder, node);
41629 }
41630 }
41631 }
41632 break;
41633 case ts.SyntaxKind.VariableStatement:
41634 const variableStatement = node;
41635 for (const variableDeclaration of variableStatement.declarationList.declarations) {
41636 if (variableDeclaration.name.kind == ts.SyntaxKind.Identifier) {
41637 const nameNode = variableDeclaration.name;
41638 let varValue;
41639 if (variableDeclaration.initializer) {
41640 varValue = evaluator.evaluateNode(variableDeclaration.initializer);
41641 }
41642 else {
41643 varValue = recordEntry(errorSym('Variable not initialized', nameNode), nameNode);
41644 }
41645 let exported = false;
41646 if (isExport(variableStatement) || isExport(variableDeclaration) ||
41647 isExportedIdentifier(nameNode)) {
41648 const name = exportedIdentifierName(nameNode);
41649 if (name) {
41650 if (!metadata)
41651 metadata = {};
41652 metadata[name] = recordEntry(varValue, node);
41653 }
41654 exported = true;
41655 }
41656 if (typeof varValue == 'string' || typeof varValue == 'number' ||
41657 typeof varValue == 'boolean') {
41658 locals.define(nameNode.text, varValue);
41659 if (exported) {
41660 locals.defineReference(nameNode.text, { __symbolic: 'reference', name: nameNode.text });
41661 }
41662 }
41663 else if (!exported) {
41664 if (varValue && !isMetadataError$1(varValue)) {
41665 locals.define(nameNode.text, recordEntry(varValue, node));
41666 }
41667 else {
41668 locals.define(nameNode.text, recordEntry(errorSym('Reference to a local symbol', nameNode, { name: nameNode.text }), node));
41669 }
41670 }
41671 }
41672 else {
41673 // Destructuring (or binding) declarations are not supported,
41674 // var {<identifier>[, <identifier>]+} = <expression>;
41675 // or
41676 // var [<identifier>[, <identifier}+] = <expression>;
41677 // are not supported.
41678 const report = (nameNode) => {
41679 switch (nameNode.kind) {
41680 case ts.SyntaxKind.Identifier:
41681 const name = nameNode;
41682 const varValue = errorSym('Destructuring not supported', name);
41683 locals.define(name.text, varValue);
41684 if (isExport(node)) {
41685 if (!metadata)
41686 metadata = {};
41687 metadata[name.text] = varValue;
41688 }
41689 break;
41690 case ts.SyntaxKind.BindingElement:
41691 const bindingElement = nameNode;
41692 report(bindingElement.name);
41693 break;
41694 case ts.SyntaxKind.ObjectBindingPattern:
41695 case ts.SyntaxKind.ArrayBindingPattern:
41696 const bindings = nameNode;
41697 bindings.elements.forEach(report);
41698 break;
41699 }
41700 };
41701 report(variableDeclaration.name);
41702 }
41703 }
41704 break;
41705 }
41706 });
41707 if (metadata || exports) {
41708 if (!metadata)
41709 metadata = {};
41710 else if (strict) {
41711 validateMetadata(sourceFile, nodeMap, metadata);
41712 }
41713 const result = {
41714 __symbolic: 'module',
41715 version: this.options.version || METADATA_VERSION,
41716 metadata
41717 };
41718 if (sourceFile.moduleName)
41719 result.importAs = sourceFile.moduleName;
41720 if (exports)
41721 result.exports = exports;
41722 return result;
41723 }
41724 }
41725 }
41726 // This will throw if the metadata entry given contains an error node.
41727 function validateMetadata(sourceFile, nodeMap, metadata) {
41728 let locals = new Set(['Array', 'Object', 'Set', 'Map', 'string', 'number', 'any']);
41729 function validateExpression(expression) {
41730 if (!expression) {
41731 return;
41732 }
41733 else if (Array.isArray(expression)) {
41734 expression.forEach(validateExpression);
41735 }
41736 else if (typeof expression === 'object' && !expression.hasOwnProperty('__symbolic')) {
41737 Object.getOwnPropertyNames(expression).forEach(v => validateExpression(expression[v]));
41738 }
41739 else if (isMetadataError$1(expression)) {
41740 reportError(expression);
41741 }
41742 else if (isMetadataGlobalReferenceExpression(expression)) {
41743 if (!locals.has(expression.name)) {
41744 const reference = metadata[expression.name];
41745 if (reference) {
41746 validateExpression(reference);
41747 }
41748 }
41749 }
41750 else if (isFunctionMetadata(expression)) {
41751 validateFunction(expression);
41752 }
41753 else if (isMetadataSymbolicExpression(expression)) {
41754 switch (expression.__symbolic) {
41755 case 'binary':
41756 const binaryExpression = expression;
41757 validateExpression(binaryExpression.left);
41758 validateExpression(binaryExpression.right);
41759 break;
41760 case 'call':
41761 case 'new':
41762 const callExpression = expression;
41763 validateExpression(callExpression.expression);
41764 if (callExpression.arguments)
41765 callExpression.arguments.forEach(validateExpression);
41766 break;
41767 case 'index':
41768 const indexExpression = expression;
41769 validateExpression(indexExpression.expression);
41770 validateExpression(indexExpression.index);
41771 break;
41772 case 'pre':
41773 const prefixExpression = expression;
41774 validateExpression(prefixExpression.operand);
41775 break;
41776 case 'select':
41777 const selectExpression = expression;
41778 validateExpression(selectExpression.expression);
41779 break;
41780 case 'spread':
41781 const spreadExpression = expression;
41782 validateExpression(spreadExpression.expression);
41783 break;
41784 case 'if':
41785 const ifExpression = expression;
41786 validateExpression(ifExpression.condition);
41787 validateExpression(ifExpression.elseExpression);
41788 validateExpression(ifExpression.thenExpression);
41789 break;
41790 }
41791 }
41792 }
41793 function validateMember(classData, member) {
41794 if (member.decorators) {
41795 member.decorators.forEach(validateExpression);
41796 }
41797 if (isMethodMetadata(member) && member.parameterDecorators) {
41798 member.parameterDecorators.forEach(validateExpression);
41799 }
41800 // Only validate parameters of classes for which we know that are used with our DI
41801 if (classData.decorators && isConstructorMetadata(member) && member.parameters) {
41802 member.parameters.forEach(validateExpression);
41803 }
41804 }
41805 function validateClass(classData) {
41806 if (classData.decorators) {
41807 classData.decorators.forEach(validateExpression);
41808 }
41809 if (classData.members) {
41810 Object.getOwnPropertyNames(classData.members)
41811 .forEach(name => classData.members[name].forEach((m) => validateMember(classData, m)));
41812 }
41813 if (classData.statics) {
41814 Object.getOwnPropertyNames(classData.statics).forEach(name => {
41815 const staticMember = classData.statics[name];
41816 if (isFunctionMetadata(staticMember)) {
41817 validateExpression(staticMember.value);
41818 }
41819 else {
41820 validateExpression(staticMember);
41821 }
41822 });
41823 }
41824 }
41825 function validateFunction(functionDeclaration) {
41826 if (functionDeclaration.value) {
41827 const oldLocals = locals;
41828 if (functionDeclaration.parameters) {
41829 locals = new Set(oldLocals.values());
41830 if (functionDeclaration.parameters)
41831 functionDeclaration.parameters.forEach(n => locals.add(n));
41832 }
41833 validateExpression(functionDeclaration.value);
41834 locals = oldLocals;
41835 }
41836 }
41837 function shouldReportNode(node) {
41838 if (node) {
41839 const nodeStart = node.getStart();
41840 return !(node.pos != nodeStart &&
41841 sourceFile.text.substring(node.pos, nodeStart).indexOf('@dynamic') >= 0);
41842 }
41843 return true;
41844 }
41845 function reportError(error) {
41846 const node = nodeMap.get(error);
41847 if (shouldReportNode(node)) {
41848 const lineInfo = error.line != undefined ? error.character != undefined ?
41849 `:${error.line + 1}:${error.character + 1}` :
41850 `:${error.line + 1}` :
41851 '';
41852 throw new Error(`${sourceFile.fileName}${lineInfo}: Metadata collected contains an error that will be reported at runtime: ${expandedMessage$1(error)}.\n ${JSON.stringify(error)}`);
41853 }
41854 }
41855 Object.getOwnPropertyNames(metadata).forEach(name => {
41856 const entry = metadata[name];
41857 try {
41858 if (isClassMetadata(entry)) {
41859 validateClass(entry);
41860 }
41861 }
41862 catch (e) {
41863 const node = nodeMap.get(entry);
41864 if (shouldReportNode(node)) {
41865 if (node) {
41866 const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
41867 throw new Error(`${sourceFile.fileName}:${line + 1}:${character + 1}: Error encountered in metadata generated for exported symbol '${name}': \n ${e.message}`);
41868 }
41869 throw new Error(`Error encountered in metadata generated for exported symbol ${name}: \n ${e.message}`);
41870 }
41871 }
41872 });
41873 }
41874 // Collect parameter names from a function.
41875 function namesOf(parameters) {
41876 const result = [];
41877 function addNamesOf(name) {
41878 if (name.kind == ts.SyntaxKind.Identifier) {
41879 const identifier = name;
41880 result.push(identifier.text);
41881 }
41882 else {
41883 const bindingPattern = name;
41884 for (const element of bindingPattern.elements) {
41885 const name = element.name;
41886 if (name) {
41887 addNamesOf(name);
41888 }
41889 }
41890 }
41891 }
41892 for (const parameter of parameters) {
41893 addNamesOf(parameter.name);
41894 }
41895 return result;
41896 }
41897 function shouldIgnoreStaticMember(memberName) {
41898 return memberName.startsWith('ngAcceptInputType_') || memberName.startsWith('ngTemplateGuard_');
41899 }
41900 function expandedMessage$1(error) {
41901 switch (error.message) {
41902 case 'Reference to non-exported class':
41903 if (error.context && error.context.className) {
41904 return `Reference to a non-exported class ${error.context.className}. Consider exporting the class`;
41905 }
41906 break;
41907 case 'Variable not initialized':
41908 return 'Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler';
41909 case 'Destructuring not supported':
41910 return 'Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring';
41911 case 'Could not resolve type':
41912 if (error.context && error.context.typeName) {
41913 return `Could not resolve type ${error.context.typeName}`;
41914 }
41915 break;
41916 case 'Function call not supported':
41917 let prefix = error.context && error.context.name ? `Calling function '${error.context.name}', f` : 'F';
41918 return prefix +
41919 'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
41920 case 'Reference to a local symbol':
41921 if (error.context && error.context.name) {
41922 return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
41923 }
41924 }
41925 return error.message;
41926 }
41927
41928 /**
41929 * @license
41930 * Copyright Google LLC All Rights Reserved.
41931 *
41932 * Use of this source code is governed by an MIT-style license that can be
41933 * found in the LICENSE file at https://angular.io/license
41934 */
41935 var EmitFlags;
41936 (function (EmitFlags) {
41937 EmitFlags[EmitFlags["DTS"] = 1] = "DTS";
41938 EmitFlags[EmitFlags["JS"] = 2] = "JS";
41939 EmitFlags[EmitFlags["Metadata"] = 4] = "Metadata";
41940 EmitFlags[EmitFlags["I18nBundle"] = 8] = "I18nBundle";
41941 EmitFlags[EmitFlags["Codegen"] = 16] = "Codegen";
41942 EmitFlags[EmitFlags["Default"] = 19] = "Default";
41943 EmitFlags[EmitFlags["All"] = 31] = "All";
41944 })(EmitFlags || (EmitFlags = {}));
41945
41946 /**
41947 * @license
41948 * Copyright Google LLC All Rights Reserved.
41949 *
41950 * Use of this source code is governed by an MIT-style license that can be
41951 * found in the LICENSE file at https://angular.io/license
41952 */
41953 const DTS = /\.d\.ts$/;
41954
41955 /**
41956 * @license
41957 * Copyright Google LLC All Rights Reserved.
41958 *
41959 * Use of this source code is governed by an MIT-style license that can be
41960 * found in the LICENSE file at https://angular.io/license
41961 */
41962 function createMetadataReaderCache() {
41963 const data = new Map();
41964 return { data };
41965 }
41966 function readMetadata(filePath, host, cache) {
41967 let metadatas = cache && cache.data.get(filePath);
41968 if (metadatas) {
41969 return metadatas;
41970 }
41971 if (host.fileExists(filePath)) {
41972 // If the file doesn't exists then we cannot return metadata for the file.
41973 // This will occur if the user referenced a declared module for which no file
41974 // exists for the module (i.e. jQuery or angularjs).
41975 if (DTS.test(filePath)) {
41976 metadatas = readMetadataFile(host, filePath);
41977 if (!metadatas) {
41978 // If there is a .d.ts file but no metadata file we need to produce a
41979 // metadata from the .d.ts file as metadata files capture reexports
41980 // (starting with v3).
41981 metadatas = [upgradeMetadataWithDtsData(host, { '__symbolic': 'module', 'version': 1, 'metadata': {} }, filePath)];
41982 }
41983 }
41984 else {
41985 const metadata = host.getSourceFileMetadata(filePath);
41986 metadatas = metadata ? [metadata] : [];
41987 }
41988 }
41989 if (cache && (!host.cacheMetadata || host.cacheMetadata(filePath))) {
41990 cache.data.set(filePath, metadatas);
41991 }
41992 return metadatas;
41993 }
41994 function readMetadataFile(host, dtsFilePath) {
41995 const metadataPath = dtsFilePath.replace(DTS, '.metadata.json');
41996 if (!host.fileExists(metadataPath)) {
41997 return undefined;
41998 }
41999 try {
42000 const metadataOrMetadatas = JSON.parse(host.readFile(metadataPath));
42001 const metadatas = metadataOrMetadatas ?
42002 (Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
42003 [];
42004 if (metadatas.length) {
42005 let maxMetadata = metadatas.reduce((p, c) => p.version > c.version ? p : c);
42006 if (maxMetadata.version < METADATA_VERSION) {
42007 metadatas.push(upgradeMetadataWithDtsData(host, maxMetadata, dtsFilePath));
42008 }
42009 }
42010 return metadatas;
42011 }
42012 catch (e) {
42013 console.error(`Failed to read JSON file ${metadataPath}`);
42014 throw e;
42015 }
42016 }
42017 function upgradeMetadataWithDtsData(host, oldMetadata, dtsFilePath) {
42018 // patch v1 to v3 by adding exports and the `extends` clause.
42019 // patch v3 to v4 by adding `interface` symbols for TypeAlias
42020 let newMetadata = {
42021 '__symbolic': 'module',
42022 'version': METADATA_VERSION,
42023 'metadata': Object.assign({}, oldMetadata.metadata),
42024 };
42025 if (oldMetadata.exports) {
42026 newMetadata.exports = oldMetadata.exports;
42027 }
42028 if (oldMetadata.importAs) {
42029 newMetadata.importAs = oldMetadata.importAs;
42030 }
42031 if (oldMetadata.origins) {
42032 newMetadata.origins = oldMetadata.origins;
42033 }
42034 const dtsMetadata = host.getSourceFileMetadata(dtsFilePath);
42035 if (dtsMetadata) {
42036 for (let prop in dtsMetadata.metadata) {
42037 if (!newMetadata.metadata[prop]) {
42038 newMetadata.metadata[prop] = dtsMetadata.metadata[prop];
42039 }
42040 }
42041 if (dtsMetadata['importAs'])
42042 newMetadata['importAs'] = dtsMetadata['importAs'];
42043 // Only copy exports from exports from metadata prior to version 3.
42044 // Starting with version 3 the collector began collecting exports and
42045 // this should be redundant. Also, with bundler will rewrite the exports
42046 // which will hoist the exports from modules referenced indirectly causing
42047 // the imports to be different than the .d.ts files and using the .d.ts file
42048 // exports would cause the StaticSymbolResolver to redirect symbols to the
42049 // incorrect location.
42050 if ((!oldMetadata.version || oldMetadata.version < 3) && dtsMetadata.exports) {
42051 newMetadata.exports = dtsMetadata.exports;
42052 }
42053 }
42054 return newMetadata;
42055 }
42056
42057 /**
42058 * @license
42059 * Copyright Google LLC All Rights Reserved.
42060 *
42061 * Use of this source code is governed by an MIT-style license that can be
42062 * found in the LICENSE file at https://angular.io/license
42063 */
42064 class ReflectorModuleModuleResolutionHost {
42065 constructor(tsLSHost, getProgram) {
42066 this.tsLSHost = tsLSHost;
42067 this.getProgram = getProgram;
42068 this.metadataCollector = new MetadataCollector({
42069 // Note: verboseInvalidExpressions is important so that
42070 // the collector will collect errors instead of throwing
42071 verboseInvalidExpression: true,
42072 });
42073 if (tsLSHost.directoryExists) {
42074 this.directoryExists = directoryName => tsLSHost.directoryExists(directoryName);
42075 }
42076 if (tsLSHost.realpath) {
42077 this.realpath = path => tsLSHost.realpath(path);
42078 }
42079 }
42080 fileExists(fileName) {
42081 // TypeScript resolution logic walks through the following sequence in order:
42082 // package.json (read "types" field) -> .ts -> .tsx -> .d.ts
42083 // For more info, see
42084 // https://www.typescriptlang.org/docs/handbook/module-resolution.html
42085 // For Angular specifically, we can skip .tsx lookup
42086 if (fileName.endsWith('.tsx')) {
42087 return false;
42088 }
42089 if (this.tsLSHost.fileExists) {
42090 return this.tsLSHost.fileExists(fileName);
42091 }
42092 return !!this.tsLSHost.getScriptSnapshot(fileName);
42093 }
42094 readFile(fileName) {
42095 // readFile() is used by TypeScript to read package.json during module
42096 // resolution, and it's used by Angular to read metadata.json during
42097 // metadata resolution.
42098 if (this.tsLSHost.readFile) {
42099 return this.tsLSHost.readFile(fileName);
42100 }
42101 // As a fallback, read the JSON files from the editor snapshot.
42102 const snapshot = this.tsLSHost.getScriptSnapshot(fileName);
42103 if (!snapshot) {
42104 // MetadataReaderHost readFile() declaration should be
42105 // `readFile(fileName: string): string | undefined`
42106 return undefined;
42107 }
42108 return snapshot.getText(0, snapshot.getLength());
42109 }
42110 getSourceFileMetadata(fileName) {
42111 const sf = this.getProgram().getSourceFile(fileName);
42112 return sf ? this.metadataCollector.getMetadata(sf) : undefined;
42113 }
42114 cacheMetadata(fileName) {
42115 // Don't cache the metadata for .ts files as they might change in the editor!
42116 return fileName.endsWith('.d.ts');
42117 }
42118 }
42119 class ReflectorHost {
42120 constructor(getProgram, tsLSHost) {
42121 this.tsLSHost = tsLSHost;
42122 this.metadataReaderCache = createMetadataReaderCache();
42123 // tsLSHost.getCurrentDirectory() returns the directory where tsconfig.json
42124 // is located. This is not the same as process.cwd() because the language
42125 // service host sets the "project root path" as its current directory.
42126 const currentDir = tsLSHost.getCurrentDirectory();
42127 this.fakeContainingPath = currentDir ? path.join(currentDir, 'fakeContainingFile.ts') : '';
42128 this.hostAdapter = new ReflectorModuleModuleResolutionHost(tsLSHost, getProgram);
42129 this.moduleResolutionCache = ts.createModuleResolutionCache(currentDir, s => s, // getCanonicalFileName
42130 tsLSHost.getCompilationSettings());
42131 }
42132 getMetadataFor(modulePath) {
42133 return readMetadata(modulePath, this.hostAdapter, this.metadataReaderCache);
42134 }
42135 moduleNameToFileName(moduleName, containingFile) {
42136 if (!containingFile) {
42137 if (moduleName.startsWith('.')) {
42138 throw new Error('Resolution of relative paths requires a containing file.');
42139 }
42140 if (!this.fakeContainingPath) {
42141 // If current directory is empty then the file must belong to an inferred
42142 // project (no tsconfig.json), in which case it's not possible to resolve
42143 // the module without the caller explicitly providing a containing file.
42144 throw new Error(`Could not resolve '${moduleName}' without a containing file.`);
42145 }
42146 containingFile = this.fakeContainingPath;
42147 }
42148 const compilerOptions = this.tsLSHost.getCompilationSettings();
42149 const resolved = ts.resolveModuleName(moduleName, containingFile, compilerOptions, this.hostAdapter, this.moduleResolutionCache)
42150 .resolvedModule;
42151 return resolved ? resolved.resolvedFileName : null;
42152 }
42153 getOutputName(filePath) {
42154 return filePath;
42155 }
42156 }
42157
42158 /**
42159 * @license
42160 * Copyright Google LLC All Rights Reserved.
42161 *
42162 * Use of this source code is governed by an MIT-style license that can be
42163 * found in the LICENSE file at https://angular.io/license
42164 */
42165 /**
42166 * The language service never needs the normalized versions of the metadata. To avoid parsing
42167 * the content and resolving references, return an empty file. This also allows normalizing
42168 * template that are syntatically incorrect which is required to provide completions in
42169 * syntactically incorrect templates.
42170 */
42171 class DummyHtmlParser extends HtmlParser {
42172 parse() {
42173 return new ParseTreeResult([], []);
42174 }
42175 }
42176 /**
42177 * Avoid loading resources in the language servcie by using a dummy loader.
42178 */
42179 class DummyResourceLoader extends ResourceLoader {
42180 get(_url) {
42181 return Promise.resolve('');
42182 }
42183 }
42184 /**
42185 * An implementation of a `LanguageServiceHost` for a TypeScript project.
42186 *
42187 * The `TypeScriptServiceHost` implements the Angular `LanguageServiceHost` using
42188 * the TypeScript language services.
42189 *
42190 * @publicApi
42191 */
42192 class TypeScriptServiceHost {
42193 constructor(tsLsHost, tsLS) {
42194 this.tsLsHost = tsLsHost;
42195 this.tsLS = tsLS;
42196 this.staticSymbolCache = new StaticSymbolCache();
42197 /**
42198 * Key of the `fileToComponent` map must be TS internal normalized path (path
42199 * separator must be `/`), value of the map is the StaticSymbol for the
42200 * Component class declaration.
42201 */
42202 this.fileToComponent = new Map();
42203 this.collectedErrors = new Map();
42204 this.fileVersions = new Map();
42205 this.lastProgram = undefined;
42206 this.analyzedModules = {
42207 files: [],
42208 ngModuleByPipeOrDirective: new Map(),
42209 ngModules: [],
42210 };
42211 this.summaryResolver = new AotSummaryResolver({
42212 loadSummary(_filePath) {
42213 return null;
42214 },
42215 isSourceFile(_sourceFilePath) {
42216 return true;
42217 },
42218 toSummaryFileName(sourceFilePath) {
42219 return sourceFilePath;
42220 },
42221 fromSummaryFileName(filePath) {
42222 return filePath;
42223 },
42224 }, this.staticSymbolCache);
42225 this.reflectorHost = new ReflectorHost(() => this.program, tsLsHost);
42226 this.staticSymbolResolver = new StaticSymbolResolver(this.reflectorHost, this.staticSymbolCache, this.summaryResolver, (e, filePath) => this.collectError(e, filePath));
42227 this.urlResolver = {
42228 resolve: (baseUrl, url) => {
42229 // In practice, `directoryExists` is always defined.
42230 // https://github.com/microsoft/TypeScript/blob/0b6c9254a850dd07056259d4eefca7721745af75/src/server/project.ts#L1608-L1614
42231 if (tsLsHost.directoryExists(baseUrl)) {
42232 return path.resolve(baseUrl, url);
42233 }
42234 return path.resolve(path.dirname(baseUrl), url);
42235 }
42236 };
42237 }
42238 /**
42239 * Return the singleton instance of the MetadataResolver.
42240 */
42241 get resolver() {
42242 if (this._resolver) {
42243 return this._resolver;
42244 }
42245 // StaticReflector keeps its own private caches that are not clearable.
42246 // We have no choice but to create a new instance to invalidate the caches.
42247 // TODO: Revisit this when language service gets rewritten for Ivy.
42248 const staticReflector = new StaticReflector(this.summaryResolver, this.staticSymbolResolver, [], // knownMetadataClasses
42249 [], // knownMetadataFunctions
42250 (e, filePath) => this.collectError(e, filePath));
42251 // Because static reflector above is changed, we need to create a new
42252 // resolver.
42253 const moduleResolver = new NgModuleResolver(staticReflector);
42254 const directiveResolver = new DirectiveResolver(staticReflector);
42255 const pipeResolver = new PipeResolver(staticReflector);
42256 const elementSchemaRegistry = new DomElementSchemaRegistry();
42257 const resourceLoader = new DummyResourceLoader();
42258 const htmlParser = new DummyHtmlParser();
42259 // This tracks the CompileConfig in codegen.ts. Currently these options
42260 // are hard-coded.
42261 const config = new CompilerConfig({
42262 defaultEncapsulation: ViewEncapsulation$1.Emulated,
42263 useJit: false,
42264 });
42265 const directiveNormalizer = new DirectiveNormalizer(resourceLoader, this.urlResolver, htmlParser, config);
42266 this._resolver = new CompileMetadataResolver(config, htmlParser, moduleResolver, directiveResolver, pipeResolver, new JitSummaryResolver(), elementSchemaRegistry, directiveNormalizer, new Console(), this.staticSymbolCache, staticReflector, (error, type) => this.collectError(error, type && type.filePath));
42267 return this._resolver;
42268 }
42269 /**
42270 * Return the singleton instance of the StaticReflector hosted in the
42271 * MetadataResolver.
42272 */
42273 get reflector() {
42274 return this.resolver.getReflector();
42275 }
42276 /**
42277 * Return all known external templates.
42278 */
42279 getExternalTemplates() {
42280 return [...this.fileToComponent.keys()];
42281 }
42282 /**
42283 * Checks whether the program has changed and returns all analyzed modules.
42284 * If program has changed, invalidate all caches and update fileToComponent
42285 * and templateReferences.
42286 * In addition to returning information about NgModules, this method plays the
42287 * same role as 'synchronizeHostData' in tsserver.
42288 */
42289 getAnalyzedModules() {
42290 if (this.upToDate()) {
42291 return this.analyzedModules;
42292 }
42293 // Invalidate caches
42294 this.fileToComponent.clear();
42295 this.collectedErrors.clear();
42296 this.resolver.clearCache();
42297 const analyzeHost = {
42298 isSourceFile(_filePath) {
42299 return true;
42300 }
42301 };
42302 const programFiles = this.program.getSourceFiles().map(sf => sf.fileName);
42303 try {
42304 this.analyzedModules =
42305 analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver);
42306 }
42307 catch (e) {
42308 // Analyzing modules may throw; in that case, reuse the old modules.
42309 this.error(`Analyzing NgModules failed. ${e}`);
42310 return this.analyzedModules;
42311 }
42312 // update template references and fileToComponent
42313 for (const ngModule of this.analyzedModules.ngModules) {
42314 for (const directive of ngModule.declaredDirectives) {
42315 const { metadata } = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference);
42316 if (metadata.isComponent && metadata.template && metadata.template.templateUrl) {
42317 const templateName = this.urlResolver.resolve(this.reflector.componentModuleUrl(directive.reference), metadata.template.templateUrl);
42318 this.fileToComponent.set(tss.server.toNormalizedPath(templateName), directive.reference);
42319 }
42320 }
42321 }
42322 return this.analyzedModules;
42323 }
42324 /**
42325 * Checks whether the program has changed, and invalidate static symbols in
42326 * the source files that have changed.
42327 * Returns true if modules are up-to-date, false otherwise.
42328 * This should only be called by getAnalyzedModules().
42329 */
42330 upToDate() {
42331 const { lastProgram, program } = this;
42332 if (lastProgram === program) {
42333 return true;
42334 }
42335 this.lastProgram = program;
42336 // Even though the program has changed, it could be the case that none of
42337 // the source files have changed. If all source files remain the same, then
42338 // program is still up-to-date, and we should not invalidate caches.
42339 let filesAdded = 0;
42340 const filesChangedOrRemoved = [];
42341 // Check if any source files have been added / changed since last computation.
42342 const seen = new Set();
42343 const ANGULAR_CORE = '@angular/core';
42344 const corePath = this.reflectorHost.moduleNameToFileName(ANGULAR_CORE);
42345 for (const { fileName } of program.getSourceFiles()) {
42346 // If `@angular/core` is edited, the language service would have to be
42347 // restarted, so ignore changes to `@angular/core`.
42348 // When the StaticReflector is initialized at startup, it loads core
42349 // symbols from @angular/core by calling initializeConversionMap(). This
42350 // is only done once. If the file is invalidated, some of the core symbols
42351 // will be lost permanently.
42352 if (fileName === corePath) {
42353 continue;
42354 }
42355 seen.add(fileName);
42356 const version = this.tsLsHost.getScriptVersion(fileName);
42357 const lastVersion = this.fileVersions.get(fileName);
42358 if (lastVersion === undefined) {
42359 filesAdded++;
42360 this.fileVersions.set(fileName, version);
42361 }
42362 else if (version !== lastVersion) {
42363 filesChangedOrRemoved.push(fileName); // changed
42364 this.fileVersions.set(fileName, version);
42365 }
42366 }
42367 // Check if any source files have been removed since last computation.
42368 for (const [fileName] of this.fileVersions) {
42369 if (!seen.has(fileName)) {
42370 filesChangedOrRemoved.push(fileName); // removed
42371 // Because Maps are iterated in insertion order, it is safe to delete
42372 // entries from the same map while iterating.
42373 // See https://stackoverflow.com/questions/35940216 and
42374 // https://www.ecma-international.org/ecma-262/10.0/index.html#sec-map.prototype.foreach
42375 this.fileVersions.delete(fileName);
42376 }
42377 }
42378 for (const fileName of filesChangedOrRemoved) {
42379 const symbols = this.staticSymbolResolver.invalidateFile(fileName);
42380 this.reflector.invalidateSymbols(symbols);
42381 }
42382 // Program is up-to-date iff no files are added, changed, or removed.
42383 return filesAdded === 0 && filesChangedOrRemoved.length === 0;
42384 }
42385 /**
42386 * Find all templates in the specified `file`.
42387 * @param fileName TS or HTML file
42388 */
42389 getTemplates(fileName) {
42390 const results = [];
42391 if (fileName.endsWith('.ts')) {
42392 // Find every template string in the file
42393 const visit = (child) => {
42394 const template = this.getInternalTemplate(child);
42395 if (template) {
42396 results.push(template);
42397 }
42398 else {
42399 tss.forEachChild(child, visit);
42400 }
42401 };
42402 const sourceFile = this.getSourceFile(fileName);
42403 if (sourceFile) {
42404 tss.forEachChild(sourceFile, visit);
42405 }
42406 }
42407 else {
42408 const template = this.getExternalTemplate(fileName);
42409 if (template) {
42410 results.push(template);
42411 }
42412 }
42413 return results;
42414 }
42415 /**
42416 * Return metadata about all class declarations in the file that are Angular
42417 * directives. Potential matches are `@NgModule`, `@Component`, `@Directive`,
42418 * `@Pipes`, etc. class declarations.
42419 *
42420 * @param fileName TS file
42421 */
42422 getDeclarations(fileName) {
42423 if (!fileName.endsWith('.ts')) {
42424 return [];
42425 }
42426 const sourceFile = this.getSourceFile(fileName);
42427 if (!sourceFile) {
42428 return [];
42429 }
42430 const results = [];
42431 const visit = (child) => {
42432 const candidate = getDirectiveClassLike(child);
42433 if (candidate) {
42434 const { classId } = candidate;
42435 const declarationSpan = spanOf$2(classId);
42436 const className = classId.getText();
42437 const classSymbol = this.reflector.getStaticSymbol(sourceFile.fileName, className);
42438 // Ask the resolver to check if candidate is actually Angular directive
42439 if (!this.resolver.isDirective(classSymbol)) {
42440 return;
42441 }
42442 const data = this.resolver.getNonNormalizedDirectiveMetadata(classSymbol);
42443 if (!data) {
42444 return;
42445 }
42446 results.push({
42447 type: classSymbol,
42448 declarationSpan,
42449 metadata: data.metadata,
42450 errors: this.getCollectedErrors(declarationSpan, sourceFile),
42451 });
42452 }
42453 else {
42454 child.forEachChild(visit);
42455 }
42456 };
42457 tss.forEachChild(sourceFile, visit);
42458 return results;
42459 }
42460 getSourceFile(fileName) {
42461 if (!fileName.endsWith('.ts')) {
42462 throw new Error(`Non-TS source file requested: ${fileName}`);
42463 }
42464 return this.program.getSourceFile(fileName);
42465 }
42466 get program() {
42467 const program = this.tsLS.getProgram();
42468 if (!program) {
42469 // Program is very very unlikely to be undefined.
42470 throw new Error('No program in language service!');
42471 }
42472 return program;
42473 }
42474 /**
42475 * Return the TemplateSource if `node` is a template node.
42476 *
42477 * For example,
42478 *
42479 * @Component({
42480 * template: '<div></div>' <-- template node
42481 * })
42482 * class AppComponent {}
42483 * ^---- class declaration node
42484 *
42485 * @param node Potential template node
42486 */
42487 getInternalTemplate(node) {
42488 if (!tss.isStringLiteralLike(node)) {
42489 return;
42490 }
42491 const tmplAsgn = getPropertyAssignmentFromValue(node, 'template');
42492 if (!tmplAsgn) {
42493 return;
42494 }
42495 const classDecl = getClassDeclFromDecoratorProp(tmplAsgn);
42496 if (!classDecl || !classDecl.name) { // Does not handle anonymous class
42497 return;
42498 }
42499 const fileName = node.getSourceFile().fileName;
42500 const classSymbol = this.reflector.getStaticSymbol(fileName, classDecl.name.text);
42501 return new InlineTemplate(node, classDecl, classSymbol, this);
42502 }
42503 /**
42504 * Return the external template for `fileName`.
42505 * @param fileName HTML file
42506 */
42507 getExternalTemplate(fileName) {
42508 // First get the text for the template
42509 const snapshot = this.tsLsHost.getScriptSnapshot(fileName);
42510 if (!snapshot) {
42511 return;
42512 }
42513 const source = snapshot.getText(0, snapshot.getLength());
42514 // Next find the component class symbol
42515 const classSymbol = this.fileToComponent.get(tss.server.toNormalizedPath(fileName));
42516 if (!classSymbol) {
42517 return;
42518 }
42519 // Then use the class symbol to find the actual ts.ClassDeclaration node
42520 const sourceFile = this.getSourceFile(classSymbol.filePath);
42521 if (!sourceFile) {
42522 return;
42523 }
42524 // TODO: This only considers top-level class declarations in a source file.
42525 // This would not find a class declaration in a namespace, for example.
42526 const classDecl = sourceFile.forEachChild((child) => {
42527 if (tss.isClassDeclaration(child) && child.name && child.name.text === classSymbol.name) {
42528 return child;
42529 }
42530 });
42531 if (!classDecl) {
42532 return;
42533 }
42534 return new ExternalTemplate(source, fileName, classDecl, classSymbol, this);
42535 }
42536 collectError(error, filePath) {
42537 if (filePath) {
42538 let errors = this.collectedErrors.get(filePath);
42539 if (!errors) {
42540 errors = [];
42541 this.collectedErrors.set(filePath, errors);
42542 }
42543 errors.push(error);
42544 }
42545 }
42546 getCollectedErrors(defaultSpan, sourceFile) {
42547 const errors = this.collectedErrors.get(sourceFile.fileName);
42548 if (!errors) {
42549 return [];
42550 }
42551 // TODO: Add better typings for the errors
42552 return errors.map((e) => {
42553 const line = e.line || (e.position && e.position.line);
42554 const column = e.column || (e.position && e.position.column);
42555 const span = spanAt$1(sourceFile, line, column) || defaultSpan;
42556 if (isFormattedError(e)) {
42557 return errorToDiagnosticWithChain(e, span);
42558 }
42559 return { message: e.message, span };
42560 });
42561 }
42562 /**
42563 * Return the parsed template for the template at the specified `position`.
42564 * @param fileName TS or HTML file
42565 * @param position Position of the template in the TS file, otherwise ignored.
42566 */
42567 getTemplateAstAtPosition(fileName, position) {
42568 let template;
42569 if (fileName.endsWith('.ts')) {
42570 const sourceFile = this.getSourceFile(fileName);
42571 if (!sourceFile) {
42572 return;
42573 }
42574 // Find the node that most closely matches the position
42575 const node = findTightestNode(sourceFile, position);
42576 if (!node) {
42577 return;
42578 }
42579 template = this.getInternalTemplate(node);
42580 }
42581 else {
42582 template = this.getExternalTemplate(fileName);
42583 }
42584 if (!template) {
42585 return;
42586 }
42587 return this.getTemplateAst(template);
42588 }
42589 /**
42590 * Find the NgModule which the directive associated with the `classSymbol`
42591 * belongs to, then return its schema and transitive directives and pipes.
42592 * @param classSymbol Angular Symbol that defines a directive
42593 */
42594 getModuleMetadataForDirective(classSymbol) {
42595 const result = {
42596 directives: [],
42597 pipes: [],
42598 schemas: [],
42599 };
42600 // First find which NgModule the directive belongs to.
42601 const ngModule = this.analyzedModules.ngModuleByPipeOrDirective.get(classSymbol) ||
42602 findSuitableDefaultModule(this.analyzedModules);
42603 if (!ngModule) {
42604 return result;
42605 }
42606 // Then gather all transitive directives and pipes.
42607 const { directives, pipes } = ngModule.transitiveModule;
42608 for (const directive of directives) {
42609 const data = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference);
42610 if (data) {
42611 result.directives.push(data.metadata.toSummary());
42612 }
42613 }
42614 for (const pipe of pipes) {
42615 const metadata = this.resolver.getOrLoadPipeMetadata(pipe.reference);
42616 result.pipes.push(metadata.toSummary());
42617 }
42618 result.schemas.push(...ngModule.schemas);
42619 return result;
42620 }
42621 /**
42622 * Parse the `template` and return its AST, if any.
42623 * @param template template to be parsed
42624 */
42625 getTemplateAst(template) {
42626 const { type: classSymbol, fileName } = template;
42627 const data = this.resolver.getNonNormalizedDirectiveMetadata(classSymbol);
42628 if (!data) {
42629 return;
42630 }
42631 const htmlParser = new HtmlParser();
42632 const expressionParser = new Parser$1(new Lexer());
42633 const parser = new TemplateParser(new CompilerConfig(), this.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser, null, // console
42634 [] // tranforms
42635 );
42636 const htmlResult = htmlParser.parse(template.source, fileName, {
42637 tokenizeExpansionForms: true,
42638 preserveLineEndings: true,
42639 });
42640 const { directives, pipes, schemas } = this.getModuleMetadataForDirective(classSymbol);
42641 const parseResult = parser.tryParseHtml(htmlResult, data.metadata, directives, pipes, schemas);
42642 if (!parseResult.templateAst) {
42643 return;
42644 }
42645 return {
42646 htmlAst: htmlResult.rootNodes,
42647 templateAst: parseResult.templateAst,
42648 directive: data.metadata,
42649 directives,
42650 pipes,
42651 parseErrors: parseResult.errors,
42652 expressionParser,
42653 template,
42654 };
42655 }
42656 /**
42657 * Log the specified `msg` to file at INFO level. If logging is not enabled
42658 * this method is a no-op.
42659 * @param msg Log message
42660 */
42661 log(msg) {
42662 if (this.tsLsHost.log) {
42663 this.tsLsHost.log(msg);
42664 }
42665 }
42666 /**
42667 * Log the specified `msg` to file at ERROR level. If logging is not enabled
42668 * this method is a no-op.
42669 * @param msg error message
42670 */
42671 error(msg) {
42672 if (this.tsLsHost.error) {
42673 this.tsLsHost.error(msg);
42674 }
42675 }
42676 /**
42677 * Log debugging info to file at INFO level, only if verbose setting is turned
42678 * on. Otherwise, this method is a no-op.
42679 * @param msg debugging message
42680 */
42681 debug(msg) {
42682 const project = this.tsLsHost;
42683 if (!project.projectService) {
42684 // tsLsHost is not a Project
42685 return;
42686 }
42687 const { logger } = project.projectService;
42688 if (logger.hasLevel(tss.server.LogLevel.verbose)) {
42689 logger.info(msg);
42690 }
42691 }
42692 }
42693 function findSuitableDefaultModule(modules) {
42694 let result = undefined;
42695 let resultSize = 0;
42696 for (const module of modules.ngModules) {
42697 const moduleSize = module.transitiveModule.directives.length;
42698 if (moduleSize > resultSize) {
42699 result = module;
42700 resultSize = moduleSize;
42701 }
42702 }
42703 return result;
42704 }
42705 function spanOf$2(node) {
42706 return { start: node.getStart(), end: node.getEnd() };
42707 }
42708 function spanAt$1(sourceFile, line, column) {
42709 if (line != null && column != null) {
42710 const position = tss.getPositionOfLineAndCharacter(sourceFile, line, column);
42711 const findChild = function findChild(node) {
42712 if (node.kind > tss.SyntaxKind.LastToken && node.pos <= position && node.end > position) {
42713 const betterNode = tss.forEachChild(node, findChild);
42714 return betterNode || node;
42715 }
42716 };
42717 const node = tss.forEachChild(sourceFile, findChild);
42718 if (node) {
42719 return { start: node.getStart(), end: node.getEnd() };
42720 }
42721 }
42722 }
42723 function convertChain(chain) {
42724 return { message: chain.message, next: chain.next ? chain.next.map(convertChain) : undefined };
42725 }
42726 function errorToDiagnosticWithChain(error, span) {
42727 return { message: error.chain ? convertChain(error.chain) : error.message, span };
42728 }
42729
42730 /**
42731 * @license
42732 * Copyright Google LLC All Rights Reserved.
42733 *
42734 * Use of this source code is governed by an MIT-style license that can be
42735 * found in the LICENSE file at https://angular.io/license
42736 */
42737 // Use a WeakMap to keep track of Project to Host mapping so that when Project
42738 // is deleted Host could be garbage collected.
42739 const PROJECT_MAP = new WeakMap();
42740 /**
42741 * This function is called by tsserver to retrieve the external (non-TS) files
42742 * that should belong to the specified `project`. For Angular, these files are
42743 * external templates. This is called once when the project is loaded, then
42744 * every time when the program is updated.
42745 * @param project Project for which external files should be retrieved.
42746 */
42747 function getExternalFiles(project) {
42748 if (!project.hasRoots()) {
42749 // During project initialization where there is no root files yet we should
42750 // not do any work.
42751 return [];
42752 }
42753 const ngLsHost = PROJECT_MAP.get(project);
42754 if (ngLsHost === undefined) {
42755 return [];
42756 }
42757 ngLsHost.getAnalyzedModules();
42758 return ngLsHost.getExternalTemplates().filter(fileName => {
42759 // TODO(kyliau): Remove this when the following PR lands on the version of
42760 // TypeScript used in this repo.
42761 // https://github.com/microsoft/TypeScript/pull/41737
42762 return project.fileExists(fileName);
42763 });
42764 }
42765 function create(info) {
42766 const { languageService: tsLS, languageServiceHost: tsLSHost, config, project } = info;
42767 // This plugin could operate under two different modes:
42768 // 1. TS + Angular
42769 // Plugin augments TS language service to provide additional Angular
42770 // information. This only works with inline templates and is meant to be
42771 // used as a local plugin (configured via tsconfig.json)
42772 // 2. Angular only
42773 // Plugin only provides information on Angular templates, no TS info at all.
42774 // This effectively disables native TS features and is meant for internal
42775 // use only.
42776 const angularOnly = config ? config.angularOnly === true : false;
42777 const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS);
42778 const ngLS = createLanguageService(ngLSHost);
42779 PROJECT_MAP.set(project, ngLSHost);
42780 function getCompletionsAtPosition(fileName, position, options) {
42781 if (!angularOnly) {
42782 const results = tsLS.getCompletionsAtPosition(fileName, position, options);
42783 if (results && results.entries.length) {
42784 // If TS could answer the query, then return results immediately.
42785 return results;
42786 }
42787 }
42788 return ngLS.getCompletionsAtPosition(fileName, position, options);
42789 }
42790 function getQuickInfoAtPosition(fileName, position) {
42791 if (!angularOnly) {
42792 const result = tsLS.getQuickInfoAtPosition(fileName, position);
42793 if (result) {
42794 // If TS could answer the query, then return results immediately.
42795 return result;
42796 }
42797 }
42798 return ngLS.getQuickInfoAtPosition(fileName, position);
42799 }
42800 function getSemanticDiagnostics(fileName) {
42801 const results = [];
42802 if (!angularOnly) {
42803 results.push(...tsLS.getSemanticDiagnostics(fileName));
42804 }
42805 // For semantic diagnostics we need to combine both TS + Angular results
42806 results.push(...ngLS.getSemanticDiagnostics(fileName));
42807 return results;
42808 }
42809 function getDefinitionAtPosition(fileName, position) {
42810 if (!angularOnly) {
42811 const results = tsLS.getDefinitionAtPosition(fileName, position);
42812 if (results) {
42813 // If TS could answer the query, then return results immediately.
42814 return results;
42815 }
42816 }
42817 const result = ngLS.getDefinitionAndBoundSpan(fileName, position);
42818 if (!result || !result.definitions || !result.definitions.length) {
42819 return;
42820 }
42821 return result.definitions;
42822 }
42823 function getDefinitionAndBoundSpan(fileName, position) {
42824 if (!angularOnly) {
42825 const result = tsLS.getDefinitionAndBoundSpan(fileName, position);
42826 if (result) {
42827 // If TS could answer the query, then return results immediately.
42828 return result;
42829 }
42830 }
42831 return ngLS.getDefinitionAndBoundSpan(fileName, position);
42832 }
42833 function getTypeDefinitionAtPosition(fileName, position) {
42834 // Not implemented in VE Language Service
42835 return undefined;
42836 }
42837 function getReferencesAtPosition(fileName, position) {
42838 // Not implemented in VE Language Service
42839 return undefined;
42840 }
42841 function findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename) {
42842 // not implemented in VE Language Service
42843 return undefined;
42844 }
42845 function getTcb(fileName, position) {
42846 // Not implemented in VE Language Service
42847 return undefined;
42848 }
42849 return Object.assign(Object.assign({}, tsLS), {
42850 // Then override the methods supported by Angular language service
42851 getCompletionsAtPosition,
42852 getQuickInfoAtPosition,
42853 getSemanticDiagnostics,
42854 getDefinitionAtPosition,
42855 getDefinitionAndBoundSpan,
42856 getTypeDefinitionAtPosition,
42857 getReferencesAtPosition,
42858 findRenameLocations,
42859 getTcb });
42860 }
42861
42862 exports.create = create;
42863 exports.getExternalFiles = getExternalFiles;
42864
42865 Object.defineProperty(exports, '__esModule', { value: true });
42866
42867});
42868//# sourceMappingURL=language-service.js.map