UNPKG

1.92 MBJavaScriptView Raw
1/**
2 * @license Angular v11.2.4
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 function isNgLanguageService(ls) {
40 return 'getTcb' in ls;
41 }
42
43 /**
44 * @license
45 * Copyright Google LLC All Rights Reserved.
46 *
47 * Use of this source code is governed by an MIT-style license that can be
48 * found in the LICENSE file at https://angular.io/license
49 */
50 var TagContentType;
51 (function (TagContentType) {
52 TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
53 TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
54 TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
55 })(TagContentType || (TagContentType = {}));
56 function splitNsName(elementName) {
57 if (elementName[0] != ':') {
58 return [null, elementName];
59 }
60 const colonIndex = elementName.indexOf(':', 1);
61 if (colonIndex == -1) {
62 throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
63 }
64 return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
65 }
66 // `<ng-container>` tags work the same regardless the namespace
67 function isNgContainer(tagName) {
68 return splitNsName(tagName)[1] === 'ng-container';
69 }
70 // `<ng-content>` tags work the same regardless the namespace
71 function isNgContent(tagName) {
72 return splitNsName(tagName)[1] === 'ng-content';
73 }
74 // `<ng-template>` tags work the same regardless the namespace
75 function isNgTemplate(tagName) {
76 return splitNsName(tagName)[1] === 'ng-template';
77 }
78 function getNsPrefix(fullName) {
79 return fullName === null ? null : splitNsName(fullName)[0];
80 }
81 function mergeNsAndName(prefix, localName) {
82 return prefix ? `:${prefix}:${localName}` : localName;
83 }
84 // see https://www.w3.org/TR/html51/syntax.html#named-character-references
85 // see https://html.spec.whatwg.org/multipage/entities.json
86 // This list is not exhaustive to keep the compiler footprint low.
87 // The `&#123;` / `&#x1ab;` syntax should be used when the named character reference does not
88 // exist.
89 const NAMED_ENTITIES = {
90 'Aacute': '\u00C1',
91 'aacute': '\u00E1',
92 'Acirc': '\u00C2',
93 'acirc': '\u00E2',
94 'acute': '\u00B4',
95 'AElig': '\u00C6',
96 'aelig': '\u00E6',
97 'Agrave': '\u00C0',
98 'agrave': '\u00E0',
99 'alefsym': '\u2135',
100 'Alpha': '\u0391',
101 'alpha': '\u03B1',
102 'amp': '&',
103 'and': '\u2227',
104 'ang': '\u2220',
105 'apos': '\u0027',
106 'Aring': '\u00C5',
107 'aring': '\u00E5',
108 'asymp': '\u2248',
109 'Atilde': '\u00C3',
110 'atilde': '\u00E3',
111 'Auml': '\u00C4',
112 'auml': '\u00E4',
113 'bdquo': '\u201E',
114 'Beta': '\u0392',
115 'beta': '\u03B2',
116 'brvbar': '\u00A6',
117 'bull': '\u2022',
118 'cap': '\u2229',
119 'Ccedil': '\u00C7',
120 'ccedil': '\u00E7',
121 'cedil': '\u00B8',
122 'cent': '\u00A2',
123 'Chi': '\u03A7',
124 'chi': '\u03C7',
125 'circ': '\u02C6',
126 'clubs': '\u2663',
127 'cong': '\u2245',
128 'copy': '\u00A9',
129 'crarr': '\u21B5',
130 'cup': '\u222A',
131 'curren': '\u00A4',
132 'dagger': '\u2020',
133 'Dagger': '\u2021',
134 'darr': '\u2193',
135 'dArr': '\u21D3',
136 'deg': '\u00B0',
137 'Delta': '\u0394',
138 'delta': '\u03B4',
139 'diams': '\u2666',
140 'divide': '\u00F7',
141 'Eacute': '\u00C9',
142 'eacute': '\u00E9',
143 'Ecirc': '\u00CA',
144 'ecirc': '\u00EA',
145 'Egrave': '\u00C8',
146 'egrave': '\u00E8',
147 'empty': '\u2205',
148 'emsp': '\u2003',
149 'ensp': '\u2002',
150 'Epsilon': '\u0395',
151 'epsilon': '\u03B5',
152 'equiv': '\u2261',
153 'Eta': '\u0397',
154 'eta': '\u03B7',
155 'ETH': '\u00D0',
156 'eth': '\u00F0',
157 'Euml': '\u00CB',
158 'euml': '\u00EB',
159 'euro': '\u20AC',
160 'exist': '\u2203',
161 'fnof': '\u0192',
162 'forall': '\u2200',
163 'frac12': '\u00BD',
164 'frac14': '\u00BC',
165 'frac34': '\u00BE',
166 'frasl': '\u2044',
167 'Gamma': '\u0393',
168 'gamma': '\u03B3',
169 'ge': '\u2265',
170 'gt': '>',
171 'harr': '\u2194',
172 'hArr': '\u21D4',
173 'hearts': '\u2665',
174 'hellip': '\u2026',
175 'Iacute': '\u00CD',
176 'iacute': '\u00ED',
177 'Icirc': '\u00CE',
178 'icirc': '\u00EE',
179 'iexcl': '\u00A1',
180 'Igrave': '\u00CC',
181 'igrave': '\u00EC',
182 'image': '\u2111',
183 'infin': '\u221E',
184 'int': '\u222B',
185 'Iota': '\u0399',
186 'iota': '\u03B9',
187 'iquest': '\u00BF',
188 'isin': '\u2208',
189 'Iuml': '\u00CF',
190 'iuml': '\u00EF',
191 'Kappa': '\u039A',
192 'kappa': '\u03BA',
193 'Lambda': '\u039B',
194 'lambda': '\u03BB',
195 'lang': '\u27E8',
196 'laquo': '\u00AB',
197 'larr': '\u2190',
198 'lArr': '\u21D0',
199 'lceil': '\u2308',
200 'ldquo': '\u201C',
201 'le': '\u2264',
202 'lfloor': '\u230A',
203 'lowast': '\u2217',
204 'loz': '\u25CA',
205 'lrm': '\u200E',
206 'lsaquo': '\u2039',
207 'lsquo': '\u2018',
208 'lt': '<',
209 'macr': '\u00AF',
210 'mdash': '\u2014',
211 'micro': '\u00B5',
212 'middot': '\u00B7',
213 'minus': '\u2212',
214 'Mu': '\u039C',
215 'mu': '\u03BC',
216 'nabla': '\u2207',
217 'nbsp': '\u00A0',
218 'ndash': '\u2013',
219 'ne': '\u2260',
220 'ni': '\u220B',
221 'not': '\u00AC',
222 'notin': '\u2209',
223 'nsub': '\u2284',
224 'Ntilde': '\u00D1',
225 'ntilde': '\u00F1',
226 'Nu': '\u039D',
227 'nu': '\u03BD',
228 'Oacute': '\u00D3',
229 'oacute': '\u00F3',
230 'Ocirc': '\u00D4',
231 'ocirc': '\u00F4',
232 'OElig': '\u0152',
233 'oelig': '\u0153',
234 'Ograve': '\u00D2',
235 'ograve': '\u00F2',
236 'oline': '\u203E',
237 'Omega': '\u03A9',
238 'omega': '\u03C9',
239 'Omicron': '\u039F',
240 'omicron': '\u03BF',
241 'oplus': '\u2295',
242 'or': '\u2228',
243 'ordf': '\u00AA',
244 'ordm': '\u00BA',
245 'Oslash': '\u00D8',
246 'oslash': '\u00F8',
247 'Otilde': '\u00D5',
248 'otilde': '\u00F5',
249 'otimes': '\u2297',
250 'Ouml': '\u00D6',
251 'ouml': '\u00F6',
252 'para': '\u00B6',
253 'permil': '\u2030',
254 'perp': '\u22A5',
255 'Phi': '\u03A6',
256 'phi': '\u03C6',
257 'Pi': '\u03A0',
258 'pi': '\u03C0',
259 'piv': '\u03D6',
260 'plusmn': '\u00B1',
261 'pound': '\u00A3',
262 'prime': '\u2032',
263 'Prime': '\u2033',
264 'prod': '\u220F',
265 'prop': '\u221D',
266 'Psi': '\u03A8',
267 'psi': '\u03C8',
268 'quot': '\u0022',
269 'radic': '\u221A',
270 'rang': '\u27E9',
271 'raquo': '\u00BB',
272 'rarr': '\u2192',
273 'rArr': '\u21D2',
274 'rceil': '\u2309',
275 'rdquo': '\u201D',
276 'real': '\u211C',
277 'reg': '\u00AE',
278 'rfloor': '\u230B',
279 'Rho': '\u03A1',
280 'rho': '\u03C1',
281 'rlm': '\u200F',
282 'rsaquo': '\u203A',
283 'rsquo': '\u2019',
284 'sbquo': '\u201A',
285 'Scaron': '\u0160',
286 'scaron': '\u0161',
287 'sdot': '\u22C5',
288 'sect': '\u00A7',
289 'shy': '\u00AD',
290 'Sigma': '\u03A3',
291 'sigma': '\u03C3',
292 'sigmaf': '\u03C2',
293 'sim': '\u223C',
294 'spades': '\u2660',
295 'sub': '\u2282',
296 'sube': '\u2286',
297 'sum': '\u2211',
298 'sup': '\u2283',
299 'sup1': '\u00B9',
300 'sup2': '\u00B2',
301 'sup3': '\u00B3',
302 'supe': '\u2287',
303 'szlig': '\u00DF',
304 'Tau': '\u03A4',
305 'tau': '\u03C4',
306 'there4': '\u2234',
307 'Theta': '\u0398',
308 'theta': '\u03B8',
309 'thetasym': '\u03D1',
310 'thinsp': '\u2009',
311 'THORN': '\u00DE',
312 'thorn': '\u00FE',
313 'tilde': '\u02DC',
314 'times': '\u00D7',
315 'trade': '\u2122',
316 'Uacute': '\u00DA',
317 'uacute': '\u00FA',
318 'uarr': '\u2191',
319 'uArr': '\u21D1',
320 'Ucirc': '\u00DB',
321 'ucirc': '\u00FB',
322 'Ugrave': '\u00D9',
323 'ugrave': '\u00F9',
324 'uml': '\u00A8',
325 'upsih': '\u03D2',
326 'Upsilon': '\u03A5',
327 'upsilon': '\u03C5',
328 'Uuml': '\u00DC',
329 'uuml': '\u00FC',
330 'weierp': '\u2118',
331 'Xi': '\u039E',
332 'xi': '\u03BE',
333 'Yacute': '\u00DD',
334 'yacute': '\u00FD',
335 'yen': '\u00A5',
336 'yuml': '\u00FF',
337 'Yuml': '\u0178',
338 'Zeta': '\u0396',
339 'zeta': '\u03B6',
340 'zwj': '\u200D',
341 'zwnj': '\u200C',
342 };
343 // The &ngsp; pseudo-entity is denoting a space. see:
344 // https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart
345 const NGSP_UNICODE = '\uE500';
346 NAMED_ENTITIES['ngsp'] = NGSP_UNICODE;
347
348 /**
349 * @license
350 * Copyright Google LLC All Rights Reserved.
351 *
352 * Use of this source code is governed by an MIT-style license that can be
353 * found in the LICENSE file at https://angular.io/license
354 */
355 class HtmlTagDefinition {
356 constructor({ closedByChildren, implicitNamespacePrefix, contentType = TagContentType.PARSABLE_DATA, closedByParent = false, isVoid = false, ignoreFirstLf = false, preventNamespaceInheritance = false } = {}) {
357 this.closedByChildren = {};
358 this.closedByParent = false;
359 this.canSelfClose = false;
360 if (closedByChildren && closedByChildren.length > 0) {
361 closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
362 }
363 this.isVoid = isVoid;
364 this.closedByParent = closedByParent || isVoid;
365 this.implicitNamespacePrefix = implicitNamespacePrefix || null;
366 this.contentType = contentType;
367 this.ignoreFirstLf = ignoreFirstLf;
368 this.preventNamespaceInheritance = preventNamespaceInheritance;
369 }
370 isClosedByChild(name) {
371 return this.isVoid || name.toLowerCase() in this.closedByChildren;
372 }
373 getContentType(prefix) {
374 if (typeof this.contentType === 'object') {
375 const overrideType = prefix == null ? undefined : this.contentType[prefix];
376 return overrideType !== null && overrideType !== void 0 ? overrideType : this.contentType.default;
377 }
378 return this.contentType;
379 }
380 }
381 let _DEFAULT_TAG_DEFINITION;
382 // see https://www.w3.org/TR/html51/syntax.html#optional-tags
383 // This implementation does not fully conform to the HTML5 spec.
384 let TAG_DEFINITIONS;
385 function getHtmlTagDefinition(tagName) {
386 var _a, _b;
387 if (!TAG_DEFINITIONS) {
388 _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
389 TAG_DEFINITIONS = {
390 'base': new HtmlTagDefinition({ isVoid: true }),
391 'meta': new HtmlTagDefinition({ isVoid: true }),
392 'area': new HtmlTagDefinition({ isVoid: true }),
393 'embed': new HtmlTagDefinition({ isVoid: true }),
394 'link': new HtmlTagDefinition({ isVoid: true }),
395 'img': new HtmlTagDefinition({ isVoid: true }),
396 'input': new HtmlTagDefinition({ isVoid: true }),
397 'param': new HtmlTagDefinition({ isVoid: true }),
398 'hr': new HtmlTagDefinition({ isVoid: true }),
399 'br': new HtmlTagDefinition({ isVoid: true }),
400 'source': new HtmlTagDefinition({ isVoid: true }),
401 'track': new HtmlTagDefinition({ isVoid: true }),
402 'wbr': new HtmlTagDefinition({ isVoid: true }),
403 'p': new HtmlTagDefinition({
404 closedByChildren: [
405 'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset',
406 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',
407 'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol',
408 'p', 'pre', 'section', 'table', 'ul'
409 ],
410 closedByParent: true
411 }),
412 'thead': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'] }),
413 'tbody': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'], closedByParent: true }),
414 'tfoot': new HtmlTagDefinition({ closedByChildren: ['tbody'], closedByParent: true }),
415 'tr': new HtmlTagDefinition({ closedByChildren: ['tr'], closedByParent: true }),
416 'td': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
417 'th': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
418 'col': new HtmlTagDefinition({ isVoid: true }),
419 'svg': new HtmlTagDefinition({ implicitNamespacePrefix: 'svg' }),
420 'foreignObject': new HtmlTagDefinition({
421 // Usually the implicit namespace here would be redundant since it will be inherited from
422 // the parent `svg`, but we have to do it for `foreignObject`, because the way the parser
423 // works is that the parent node of an end tag is its own start tag which means that
424 // the `preventNamespaceInheritance` on `foreignObject` would have it default to the
425 // implicit namespace which is `html`, unless specified otherwise.
426 implicitNamespacePrefix: 'svg',
427 // We want to prevent children of foreignObject from inheriting its namespace, because
428 // the point of the element is to allow nodes from other namespaces to be inserted.
429 preventNamespaceInheritance: true,
430 }),
431 'math': new HtmlTagDefinition({ implicitNamespacePrefix: 'math' }),
432 'li': new HtmlTagDefinition({ closedByChildren: ['li'], closedByParent: true }),
433 'dt': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'] }),
434 'dd': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'], closedByParent: true }),
435 'rb': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
436 'rt': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
437 'rtc': new HtmlTagDefinition({ closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true }),
438 'rp': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
439 'optgroup': new HtmlTagDefinition({ closedByChildren: ['optgroup'], closedByParent: true }),
440 'option': new HtmlTagDefinition({ closedByChildren: ['option', 'optgroup'], closedByParent: true }),
441 'pre': new HtmlTagDefinition({ ignoreFirstLf: true }),
442 'listing': new HtmlTagDefinition({ ignoreFirstLf: true }),
443 'style': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }),
444 'script': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }),
445 'title': new HtmlTagDefinition({
446 // The browser supports two separate `title` tags which have to use
447 // a different content type: `HTMLTitleElement` and `SVGTitleElement`
448 contentType: { default: TagContentType.ESCAPABLE_RAW_TEXT, svg: TagContentType.PARSABLE_DATA }
449 }),
450 'textarea': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }),
451 };
452 }
453 // We have to make both a case-sensitive and a case-insesitive lookup, because
454 // HTML tag names are case insensitive, whereas some SVG tags are case sensitive.
455 return (_b = (_a = TAG_DEFINITIONS[tagName]) !== null && _a !== void 0 ? _a : TAG_DEFINITIONS[tagName.toLowerCase()]) !== null && _b !== void 0 ? _b : _DEFAULT_TAG_DEFINITION;
456 }
457
458 /**
459 * @license
460 * Copyright Google LLC All Rights Reserved.
461 *
462 * Use of this source code is governed by an MIT-style license that can be
463 * found in the LICENSE file at https://angular.io/license
464 */
465 const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + // 1: ":not("
466 '(([\\.\\#]?)[-\\w]+)|' + // 2: "tag"; 3: "."/"#";
467 // "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range
468 // 4: attribute; 5: attribute_string; 6: attribute_value
469 '(?:\\[([-.\\w*]+)(?:=([\"\']?)([^\\]\"\']*)\\5)?\\])|' + // "[name]", "[name=value]",
470 // "[name="value"]",
471 // "[name='value']"
472 '(\\))|' + // 7: ")"
473 '(\\s*,\\s*)', // 8: ","
474 'g');
475 /**
476 * A css selector contains an element name,
477 * css classes and attribute/value pairs with the purpose
478 * of selecting subsets out of them.
479 */
480 class CssSelector {
481 constructor() {
482 this.element = null;
483 this.classNames = [];
484 /**
485 * The selectors are encoded in pairs where:
486 * - even locations are attribute names
487 * - odd locations are attribute values.
488 *
489 * Example:
490 * Selector: `[key1=value1][key2]` would parse to:
491 * ```
492 * ['key1', 'value1', 'key2', '']
493 * ```
494 */
495 this.attrs = [];
496 this.notSelectors = [];
497 }
498 static parse(selector) {
499 const results = [];
500 const _addResult = (res, cssSel) => {
501 if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
502 cssSel.attrs.length == 0) {
503 cssSel.element = '*';
504 }
505 res.push(cssSel);
506 };
507 let cssSelector = new CssSelector();
508 let match;
509 let current = cssSelector;
510 let inNot = false;
511 _SELECTOR_REGEXP.lastIndex = 0;
512 while (match = _SELECTOR_REGEXP.exec(selector)) {
513 if (match[1 /* NOT */]) {
514 if (inNot) {
515 throw new Error('Nesting :not in a selector is not allowed');
516 }
517 inNot = true;
518 current = new CssSelector();
519 cssSelector.notSelectors.push(current);
520 }
521 const tag = match[2 /* TAG */];
522 if (tag) {
523 const prefix = match[3 /* PREFIX */];
524 if (prefix === '#') {
525 // #hash
526 current.addAttribute('id', tag.substr(1));
527 }
528 else if (prefix === '.') {
529 // Class
530 current.addClassName(tag.substr(1));
531 }
532 else {
533 // Element
534 current.setElement(tag);
535 }
536 }
537 const attribute = match[4 /* ATTRIBUTE */];
538 if (attribute) {
539 current.addAttribute(attribute, match[6 /* ATTRIBUTE_VALUE */]);
540 }
541 if (match[7 /* NOT_END */]) {
542 inNot = false;
543 current = cssSelector;
544 }
545 if (match[8 /* SEPARATOR */]) {
546 if (inNot) {
547 throw new Error('Multiple selectors in :not are not supported');
548 }
549 _addResult(results, cssSelector);
550 cssSelector = current = new CssSelector();
551 }
552 }
553 _addResult(results, cssSelector);
554 return results;
555 }
556 isElementSelector() {
557 return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 &&
558 this.notSelectors.length === 0;
559 }
560 hasElementSelector() {
561 return !!this.element;
562 }
563 setElement(element = null) {
564 this.element = element;
565 }
566 /** Gets a template string for an element that matches the selector. */
567 getMatchingElementTemplate() {
568 const tagName = this.element || 'div';
569 const classAttr = this.classNames.length > 0 ? ` class="${this.classNames.join(' ')}"` : '';
570 let attrs = '';
571 for (let i = 0; i < this.attrs.length; i += 2) {
572 const attrName = this.attrs[i];
573 const attrValue = this.attrs[i + 1] !== '' ? `="${this.attrs[i + 1]}"` : '';
574 attrs += ` ${attrName}${attrValue}`;
575 }
576 return getHtmlTagDefinition(tagName).isVoid ? `<${tagName}${classAttr}${attrs}/>` :
577 `<${tagName}${classAttr}${attrs}></${tagName}>`;
578 }
579 getAttrs() {
580 const result = [];
581 if (this.classNames.length > 0) {
582 result.push('class', this.classNames.join(' '));
583 }
584 return result.concat(this.attrs);
585 }
586 addAttribute(name, value = '') {
587 this.attrs.push(name, value && value.toLowerCase() || '');
588 }
589 addClassName(name) {
590 this.classNames.push(name.toLowerCase());
591 }
592 toString() {
593 let res = this.element || '';
594 if (this.classNames) {
595 this.classNames.forEach(klass => res += `.${klass}`);
596 }
597 if (this.attrs) {
598 for (let i = 0; i < this.attrs.length; i += 2) {
599 const name = this.attrs[i];
600 const value = this.attrs[i + 1];
601 res += `[${name}${value ? '=' + value : ''}]`;
602 }
603 }
604 this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
605 return res;
606 }
607 }
608 /**
609 * Reads a list of CssSelectors and allows to calculate which ones
610 * are contained in a given CssSelector.
611 */
612 class SelectorMatcher {
613 constructor() {
614 this._elementMap = new Map();
615 this._elementPartialMap = new Map();
616 this._classMap = new Map();
617 this._classPartialMap = new Map();
618 this._attrValueMap = new Map();
619 this._attrValuePartialMap = new Map();
620 this._listContexts = [];
621 }
622 static createNotMatcher(notSelectors) {
623 const notMatcher = new SelectorMatcher();
624 notMatcher.addSelectables(notSelectors, null);
625 return notMatcher;
626 }
627 addSelectables(cssSelectors, callbackCtxt) {
628 let listContext = null;
629 if (cssSelectors.length > 1) {
630 listContext = new SelectorListContext(cssSelectors);
631 this._listContexts.push(listContext);
632 }
633 for (let i = 0; i < cssSelectors.length; i++) {
634 this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
635 }
636 }
637 /**
638 * Add an object that can be found later on by calling `match`.
639 * @param cssSelector A css selector
640 * @param callbackCtxt An opaque object that will be given to the callback of the `match` function
641 */
642 _addSelectable(cssSelector, callbackCtxt, listContext) {
643 let matcher = this;
644 const element = cssSelector.element;
645 const classNames = cssSelector.classNames;
646 const attrs = cssSelector.attrs;
647 const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
648 if (element) {
649 const isTerminal = attrs.length === 0 && classNames.length === 0;
650 if (isTerminal) {
651 this._addTerminal(matcher._elementMap, element, selectable);
652 }
653 else {
654 matcher = this._addPartial(matcher._elementPartialMap, element);
655 }
656 }
657 if (classNames) {
658 for (let i = 0; i < classNames.length; i++) {
659 const isTerminal = attrs.length === 0 && i === classNames.length - 1;
660 const className = classNames[i];
661 if (isTerminal) {
662 this._addTerminal(matcher._classMap, className, selectable);
663 }
664 else {
665 matcher = this._addPartial(matcher._classPartialMap, className);
666 }
667 }
668 }
669 if (attrs) {
670 for (let i = 0; i < attrs.length; i += 2) {
671 const isTerminal = i === attrs.length - 2;
672 const name = attrs[i];
673 const value = attrs[i + 1];
674 if (isTerminal) {
675 const terminalMap = matcher._attrValueMap;
676 let terminalValuesMap = terminalMap.get(name);
677 if (!terminalValuesMap) {
678 terminalValuesMap = new Map();
679 terminalMap.set(name, terminalValuesMap);
680 }
681 this._addTerminal(terminalValuesMap, value, selectable);
682 }
683 else {
684 const partialMap = matcher._attrValuePartialMap;
685 let partialValuesMap = partialMap.get(name);
686 if (!partialValuesMap) {
687 partialValuesMap = new Map();
688 partialMap.set(name, partialValuesMap);
689 }
690 matcher = this._addPartial(partialValuesMap, value);
691 }
692 }
693 }
694 }
695 _addTerminal(map, name, selectable) {
696 let terminalList = map.get(name);
697 if (!terminalList) {
698 terminalList = [];
699 map.set(name, terminalList);
700 }
701 terminalList.push(selectable);
702 }
703 _addPartial(map, name) {
704 let matcher = map.get(name);
705 if (!matcher) {
706 matcher = new SelectorMatcher();
707 map.set(name, matcher);
708 }
709 return matcher;
710 }
711 /**
712 * Find the objects that have been added via `addSelectable`
713 * whose css selector is contained in the given css selector.
714 * @param cssSelector A css selector
715 * @param matchedCallback This callback will be called with the object handed into `addSelectable`
716 * @return boolean true if a match was found
717 */
718 match(cssSelector, matchedCallback) {
719 let result = false;
720 const element = cssSelector.element;
721 const classNames = cssSelector.classNames;
722 const attrs = cssSelector.attrs;
723 for (let i = 0; i < this._listContexts.length; i++) {
724 this._listContexts[i].alreadyMatched = false;
725 }
726 result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result;
727 result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
728 result;
729 if (classNames) {
730 for (let i = 0; i < classNames.length; i++) {
731 const className = classNames[i];
732 result =
733 this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
734 result =
735 this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) ||
736 result;
737 }
738 }
739 if (attrs) {
740 for (let i = 0; i < attrs.length; i += 2) {
741 const name = attrs[i];
742 const value = attrs[i + 1];
743 const terminalValuesMap = this._attrValueMap.get(name);
744 if (value) {
745 result =
746 this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
747 }
748 result =
749 this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
750 const partialValuesMap = this._attrValuePartialMap.get(name);
751 if (value) {
752 result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
753 }
754 result =
755 this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
756 }
757 }
758 return result;
759 }
760 /** @internal */
761 _matchTerminal(map, name, cssSelector, matchedCallback) {
762 if (!map || typeof name !== 'string') {
763 return false;
764 }
765 let selectables = map.get(name) || [];
766 const starSelectables = map.get('*');
767 if (starSelectables) {
768 selectables = selectables.concat(starSelectables);
769 }
770 if (selectables.length === 0) {
771 return false;
772 }
773 let selectable;
774 let result = false;
775 for (let i = 0; i < selectables.length; i++) {
776 selectable = selectables[i];
777 result = selectable.finalize(cssSelector, matchedCallback) || result;
778 }
779 return result;
780 }
781 /** @internal */
782 _matchPartial(map, name, cssSelector, matchedCallback) {
783 if (!map || typeof name !== 'string') {
784 return false;
785 }
786 const nestedSelector = map.get(name);
787 if (!nestedSelector) {
788 return false;
789 }
790 // TODO(perf): get rid of recursion and measure again
791 // TODO(perf): don't pass the whole selector into the recursion,
792 // but only the not processed parts
793 return nestedSelector.match(cssSelector, matchedCallback);
794 }
795 }
796 class SelectorListContext {
797 constructor(selectors) {
798 this.selectors = selectors;
799 this.alreadyMatched = false;
800 }
801 }
802 // Store context to pass back selector and context when a selector is matched
803 class SelectorContext {
804 constructor(selector, cbContext, listContext) {
805 this.selector = selector;
806 this.cbContext = cbContext;
807 this.listContext = listContext;
808 this.notSelectors = selector.notSelectors;
809 }
810 finalize(cssSelector, callback) {
811 let result = true;
812 if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
813 const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
814 result = !notMatcher.match(cssSelector, null);
815 }
816 if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
817 if (this.listContext) {
818 this.listContext.alreadyMatched = true;
819 }
820 callback(this.selector, this.cbContext);
821 }
822 return result;
823 }
824 }
825
826 /**
827 * @license
828 * Copyright Google LLC All Rights Reserved.
829 *
830 * Use of this source code is governed by an MIT-style license that can be
831 * found in the LICENSE file at https://angular.io/license
832 */
833 const createInject = makeMetadataFactory('Inject', (token) => ({ token }));
834 const createInjectionToken = makeMetadataFactory('InjectionToken', (desc) => ({ _desc: desc, ɵprov: undefined }));
835 const createAttribute = makeMetadataFactory('Attribute', (attributeName) => ({ attributeName }));
836 // Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
837 // explicitly set. This value will be changed to `true` in v12.
838 // TODO(misko): switch the default in v12 to `true`. See: packages/core/src/metadata/di.ts
839 const emitDistinctChangesOnlyDefaultValue = false;
840 const createContentChildren = makeMetadataFactory('ContentChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)));
841 const createContentChild = makeMetadataFactory('ContentChild', (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data)));
842 const createViewChildren = makeMetadataFactory('ViewChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data)));
843 const createViewChild = makeMetadataFactory('ViewChild', (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data)));
844 const createDirective = makeMetadataFactory('Directive', (dir = {}) => dir);
845 var ViewEncapsulation;
846 (function (ViewEncapsulation) {
847 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
848 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
849 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
850 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
851 })(ViewEncapsulation || (ViewEncapsulation = {}));
852 var ChangeDetectionStrategy;
853 (function (ChangeDetectionStrategy) {
854 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
855 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
856 })(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
857 const createComponent = makeMetadataFactory('Component', (c = {}) => (Object.assign({ changeDetection: ChangeDetectionStrategy.Default }, c)));
858 const createPipe = makeMetadataFactory('Pipe', (p) => (Object.assign({ pure: true }, p)));
859 const createInput = makeMetadataFactory('Input', (bindingPropertyName) => ({ bindingPropertyName }));
860 const createOutput = makeMetadataFactory('Output', (bindingPropertyName) => ({ bindingPropertyName }));
861 const createHostBinding = makeMetadataFactory('HostBinding', (hostPropertyName) => ({ hostPropertyName }));
862 const createHostListener = makeMetadataFactory('HostListener', (eventName, args) => ({ eventName, args }));
863 const createNgModule = makeMetadataFactory('NgModule', (ngModule) => ngModule);
864 const createInjectable = makeMetadataFactory('Injectable', (injectable = {}) => injectable);
865 const CUSTOM_ELEMENTS_SCHEMA = {
866 name: 'custom-elements'
867 };
868 const NO_ERRORS_SCHEMA = {
869 name: 'no-errors-schema'
870 };
871 const createOptional = makeMetadataFactory('Optional');
872 const createSelf = makeMetadataFactory('Self');
873 const createSkipSelf = makeMetadataFactory('SkipSelf');
874 const createHost = makeMetadataFactory('Host');
875 const Type = Function;
876 var SecurityContext;
877 (function (SecurityContext) {
878 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
879 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
880 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
881 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
882 SecurityContext[SecurityContext["URL"] = 4] = "URL";
883 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
884 })(SecurityContext || (SecurityContext = {}));
885 var MissingTranslationStrategy;
886 (function (MissingTranslationStrategy) {
887 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
888 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
889 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
890 })(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
891 function makeMetadataFactory(name, props) {
892 // This must be declared as a function, not a fat arrow, so that ES2015 devmode produces code
893 // that works with the static_reflector.ts in the ViewEngine compiler.
894 // In particular, `_registerDecoratorOrConstructor` assumes that the value returned here can be
895 // new'ed.
896 function factory(...args) {
897 const values = props ? props(...args) : {};
898 return Object.assign({ ngMetadataName: name }, values);
899 }
900 factory.isTypeOf = (obj) => obj && obj.ngMetadataName === name;
901 factory.ngMetadataName = name;
902 return factory;
903 }
904 function parserSelectorToSimpleSelector(selector) {
905 const classes = selector.classNames && selector.classNames.length ?
906 [8 /* CLASS */, ...selector.classNames] :
907 [];
908 const elementName = selector.element && selector.element !== '*' ? selector.element : '';
909 return [elementName, ...selector.attrs, ...classes];
910 }
911 function parserSelectorToNegativeSelector(selector) {
912 const classes = selector.classNames && selector.classNames.length ?
913 [8 /* CLASS */, ...selector.classNames] :
914 [];
915 if (selector.element) {
916 return [
917 1 /* NOT */ | 4 /* ELEMENT */, selector.element, ...selector.attrs, ...classes
918 ];
919 }
920 else if (selector.attrs.length) {
921 return [1 /* NOT */ | 2 /* ATTRIBUTE */, ...selector.attrs, ...classes];
922 }
923 else {
924 return selector.classNames && selector.classNames.length ?
925 [1 /* NOT */ | 8 /* CLASS */, ...selector.classNames] :
926 [];
927 }
928 }
929 function parserSelectorToR3Selector(selector) {
930 const positive = parserSelectorToSimpleSelector(selector);
931 const negative = selector.notSelectors && selector.notSelectors.length ?
932 selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) :
933 [];
934 return positive.concat(...negative);
935 }
936 function parseSelectorToR3Selector(selector) {
937 return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
938 }
939
940 /**
941 * @license
942 * Copyright Google LLC All Rights Reserved.
943 *
944 * Use of this source code is governed by an MIT-style license that can be
945 * found in the LICENSE file at https://angular.io/license
946 */
947 //// Types
948 var TypeModifier;
949 (function (TypeModifier) {
950 TypeModifier[TypeModifier["Const"] = 0] = "Const";
951 })(TypeModifier || (TypeModifier = {}));
952 class Type$1 {
953 constructor(modifiers = []) {
954 this.modifiers = modifiers;
955 }
956 hasModifier(modifier) {
957 return this.modifiers.indexOf(modifier) !== -1;
958 }
959 }
960 var BuiltinTypeName;
961 (function (BuiltinTypeName) {
962 BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic";
963 BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool";
964 BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String";
965 BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int";
966 BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number";
967 BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function";
968 BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred";
969 BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None";
970 })(BuiltinTypeName || (BuiltinTypeName = {}));
971 class BuiltinType extends Type$1 {
972 constructor(name, modifiers) {
973 super(modifiers);
974 this.name = name;
975 }
976 visitType(visitor, context) {
977 return visitor.visitBuiltinType(this, context);
978 }
979 }
980 class ExpressionType extends Type$1 {
981 constructor(value, modifiers, typeParams = null) {
982 super(modifiers);
983 this.value = value;
984 this.typeParams = typeParams;
985 }
986 visitType(visitor, context) {
987 return visitor.visitExpressionType(this, context);
988 }
989 }
990 const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
991 const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred);
992 const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool);
993 const INT_TYPE = new BuiltinType(BuiltinTypeName.Int);
994 const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number);
995 const STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
996 const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
997 const NONE_TYPE = new BuiltinType(BuiltinTypeName.None);
998 ///// Expressions
999 var UnaryOperator;
1000 (function (UnaryOperator) {
1001 UnaryOperator[UnaryOperator["Minus"] = 0] = "Minus";
1002 UnaryOperator[UnaryOperator["Plus"] = 1] = "Plus";
1003 })(UnaryOperator || (UnaryOperator = {}));
1004 var BinaryOperator;
1005 (function (BinaryOperator) {
1006 BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals";
1007 BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals";
1008 BinaryOperator[BinaryOperator["Identical"] = 2] = "Identical";
1009 BinaryOperator[BinaryOperator["NotIdentical"] = 3] = "NotIdentical";
1010 BinaryOperator[BinaryOperator["Minus"] = 4] = "Minus";
1011 BinaryOperator[BinaryOperator["Plus"] = 5] = "Plus";
1012 BinaryOperator[BinaryOperator["Divide"] = 6] = "Divide";
1013 BinaryOperator[BinaryOperator["Multiply"] = 7] = "Multiply";
1014 BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo";
1015 BinaryOperator[BinaryOperator["And"] = 9] = "And";
1016 BinaryOperator[BinaryOperator["Or"] = 10] = "Or";
1017 BinaryOperator[BinaryOperator["BitwiseAnd"] = 11] = "BitwiseAnd";
1018 BinaryOperator[BinaryOperator["Lower"] = 12] = "Lower";
1019 BinaryOperator[BinaryOperator["LowerEquals"] = 13] = "LowerEquals";
1020 BinaryOperator[BinaryOperator["Bigger"] = 14] = "Bigger";
1021 BinaryOperator[BinaryOperator["BiggerEquals"] = 15] = "BiggerEquals";
1022 })(BinaryOperator || (BinaryOperator = {}));
1023 function nullSafeIsEquivalent(base, other) {
1024 if (base == null || other == null) {
1025 return base == other;
1026 }
1027 return base.isEquivalent(other);
1028 }
1029 function areAllEquivalentPredicate(base, other, equivalentPredicate) {
1030 const len = base.length;
1031 if (len !== other.length) {
1032 return false;
1033 }
1034 for (let i = 0; i < len; i++) {
1035 if (!equivalentPredicate(base[i], other[i])) {
1036 return false;
1037 }
1038 }
1039 return true;
1040 }
1041 function areAllEquivalent(base, other) {
1042 return areAllEquivalentPredicate(base, other, (baseElement, otherElement) => baseElement.isEquivalent(otherElement));
1043 }
1044 class Expression {
1045 constructor(type, sourceSpan) {
1046 this.type = type || null;
1047 this.sourceSpan = sourceSpan || null;
1048 }
1049 prop(name, sourceSpan) {
1050 return new ReadPropExpr(this, name, null, sourceSpan);
1051 }
1052 key(index, type, sourceSpan) {
1053 return new ReadKeyExpr(this, index, type, sourceSpan);
1054 }
1055 callMethod(name, params, sourceSpan) {
1056 return new InvokeMethodExpr(this, name, params, null, sourceSpan);
1057 }
1058 callFn(params, sourceSpan, pure) {
1059 return new InvokeFunctionExpr(this, params, null, sourceSpan, pure);
1060 }
1061 instantiate(params, type, sourceSpan) {
1062 return new InstantiateExpr(this, params, type, sourceSpan);
1063 }
1064 conditional(trueCase, falseCase = null, sourceSpan) {
1065 return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan);
1066 }
1067 equals(rhs, sourceSpan) {
1068 return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan);
1069 }
1070 notEquals(rhs, sourceSpan) {
1071 return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan);
1072 }
1073 identical(rhs, sourceSpan) {
1074 return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan);
1075 }
1076 notIdentical(rhs, sourceSpan) {
1077 return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan);
1078 }
1079 minus(rhs, sourceSpan) {
1080 return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan);
1081 }
1082 plus(rhs, sourceSpan) {
1083 return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan);
1084 }
1085 divide(rhs, sourceSpan) {
1086 return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan);
1087 }
1088 multiply(rhs, sourceSpan) {
1089 return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan);
1090 }
1091 modulo(rhs, sourceSpan) {
1092 return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan);
1093 }
1094 and(rhs, sourceSpan) {
1095 return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan);
1096 }
1097 bitwiseAnd(rhs, sourceSpan, parens = true) {
1098 return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens);
1099 }
1100 or(rhs, sourceSpan) {
1101 return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan);
1102 }
1103 lower(rhs, sourceSpan) {
1104 return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan);
1105 }
1106 lowerEquals(rhs, sourceSpan) {
1107 return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan);
1108 }
1109 bigger(rhs, sourceSpan) {
1110 return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan);
1111 }
1112 biggerEquals(rhs, sourceSpan) {
1113 return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan);
1114 }
1115 isBlank(sourceSpan) {
1116 // Note: We use equals by purpose here to compare to null and undefined in JS.
1117 // We use the typed null to allow strictNullChecks to narrow types.
1118 return this.equals(TYPED_NULL_EXPR, sourceSpan);
1119 }
1120 cast(type, sourceSpan) {
1121 return new CastExpr(this, type, sourceSpan);
1122 }
1123 toStmt() {
1124 return new ExpressionStatement(this, null);
1125 }
1126 }
1127 var BuiltinVar;
1128 (function (BuiltinVar) {
1129 BuiltinVar[BuiltinVar["This"] = 0] = "This";
1130 BuiltinVar[BuiltinVar["Super"] = 1] = "Super";
1131 BuiltinVar[BuiltinVar["CatchError"] = 2] = "CatchError";
1132 BuiltinVar[BuiltinVar["CatchStack"] = 3] = "CatchStack";
1133 })(BuiltinVar || (BuiltinVar = {}));
1134 class ReadVarExpr extends Expression {
1135 constructor(name, type, sourceSpan) {
1136 super(type, sourceSpan);
1137 if (typeof name === 'string') {
1138 this.name = name;
1139 this.builtin = null;
1140 }
1141 else {
1142 this.name = null;
1143 this.builtin = name;
1144 }
1145 }
1146 isEquivalent(e) {
1147 return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin;
1148 }
1149 isConstant() {
1150 return false;
1151 }
1152 visitExpression(visitor, context) {
1153 return visitor.visitReadVarExpr(this, context);
1154 }
1155 set(value) {
1156 if (!this.name) {
1157 throw new Error(`Built in variable ${this.builtin} can not be assigned to.`);
1158 }
1159 return new WriteVarExpr(this.name, value, null, this.sourceSpan);
1160 }
1161 }
1162 class TypeofExpr extends Expression {
1163 constructor(expr, type, sourceSpan) {
1164 super(type, sourceSpan);
1165 this.expr = expr;
1166 }
1167 visitExpression(visitor, context) {
1168 return visitor.visitTypeofExpr(this, context);
1169 }
1170 isEquivalent(e) {
1171 return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
1172 }
1173 isConstant() {
1174 return this.expr.isConstant();
1175 }
1176 }
1177 class WrappedNodeExpr extends Expression {
1178 constructor(node, type, sourceSpan) {
1179 super(type, sourceSpan);
1180 this.node = node;
1181 }
1182 isEquivalent(e) {
1183 return e instanceof WrappedNodeExpr && this.node === e.node;
1184 }
1185 isConstant() {
1186 return false;
1187 }
1188 visitExpression(visitor, context) {
1189 return visitor.visitWrappedNodeExpr(this, context);
1190 }
1191 }
1192 class WriteVarExpr extends Expression {
1193 constructor(name, value, type, sourceSpan) {
1194 super(type || value.type, sourceSpan);
1195 this.name = name;
1196 this.value = value;
1197 }
1198 isEquivalent(e) {
1199 return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value);
1200 }
1201 isConstant() {
1202 return false;
1203 }
1204 visitExpression(visitor, context) {
1205 return visitor.visitWriteVarExpr(this, context);
1206 }
1207 toDeclStmt(type, modifiers) {
1208 return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
1209 }
1210 toConstDecl() {
1211 return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]);
1212 }
1213 }
1214 class WriteKeyExpr extends Expression {
1215 constructor(receiver, index, value, type, sourceSpan) {
1216 super(type || value.type, sourceSpan);
1217 this.receiver = receiver;
1218 this.index = index;
1219 this.value = value;
1220 }
1221 isEquivalent(e) {
1222 return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) &&
1223 this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value);
1224 }
1225 isConstant() {
1226 return false;
1227 }
1228 visitExpression(visitor, context) {
1229 return visitor.visitWriteKeyExpr(this, context);
1230 }
1231 }
1232 class WritePropExpr extends Expression {
1233 constructor(receiver, name, value, type, sourceSpan) {
1234 super(type || value.type, sourceSpan);
1235 this.receiver = receiver;
1236 this.name = name;
1237 this.value = value;
1238 }
1239 isEquivalent(e) {
1240 return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) &&
1241 this.name === e.name && this.value.isEquivalent(e.value);
1242 }
1243 isConstant() {
1244 return false;
1245 }
1246 visitExpression(visitor, context) {
1247 return visitor.visitWritePropExpr(this, context);
1248 }
1249 }
1250 var BuiltinMethod;
1251 (function (BuiltinMethod) {
1252 BuiltinMethod[BuiltinMethod["ConcatArray"] = 0] = "ConcatArray";
1253 BuiltinMethod[BuiltinMethod["SubscribeObservable"] = 1] = "SubscribeObservable";
1254 BuiltinMethod[BuiltinMethod["Bind"] = 2] = "Bind";
1255 })(BuiltinMethod || (BuiltinMethod = {}));
1256 class InvokeMethodExpr extends Expression {
1257 constructor(receiver, method, args, type, sourceSpan) {
1258 super(type, sourceSpan);
1259 this.receiver = receiver;
1260 this.args = args;
1261 if (typeof method === 'string') {
1262 this.name = method;
1263 this.builtin = null;
1264 }
1265 else {
1266 this.name = null;
1267 this.builtin = method;
1268 }
1269 }
1270 isEquivalent(e) {
1271 return e instanceof InvokeMethodExpr && this.receiver.isEquivalent(e.receiver) &&
1272 this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args);
1273 }
1274 isConstant() {
1275 return false;
1276 }
1277 visitExpression(visitor, context) {
1278 return visitor.visitInvokeMethodExpr(this, context);
1279 }
1280 }
1281 class InvokeFunctionExpr extends Expression {
1282 constructor(fn, args, type, sourceSpan, pure = false) {
1283 super(type, sourceSpan);
1284 this.fn = fn;
1285 this.args = args;
1286 this.pure = pure;
1287 }
1288 isEquivalent(e) {
1289 return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) &&
1290 areAllEquivalent(this.args, e.args) && this.pure === e.pure;
1291 }
1292 isConstant() {
1293 return false;
1294 }
1295 visitExpression(visitor, context) {
1296 return visitor.visitInvokeFunctionExpr(this, context);
1297 }
1298 }
1299 class TaggedTemplateExpr extends Expression {
1300 constructor(tag, template, type, sourceSpan) {
1301 super(type, sourceSpan);
1302 this.tag = tag;
1303 this.template = template;
1304 }
1305 isEquivalent(e) {
1306 return e instanceof TaggedTemplateExpr && this.tag.isEquivalent(e.tag) &&
1307 areAllEquivalentPredicate(this.template.elements, e.template.elements, (a, b) => a.text === b.text) &&
1308 areAllEquivalent(this.template.expressions, e.template.expressions);
1309 }
1310 isConstant() {
1311 return false;
1312 }
1313 visitExpression(visitor, context) {
1314 return visitor.visitTaggedTemplateExpr(this, context);
1315 }
1316 }
1317 class InstantiateExpr extends Expression {
1318 constructor(classExpr, args, type, sourceSpan) {
1319 super(type, sourceSpan);
1320 this.classExpr = classExpr;
1321 this.args = args;
1322 }
1323 isEquivalent(e) {
1324 return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) &&
1325 areAllEquivalent(this.args, e.args);
1326 }
1327 isConstant() {
1328 return false;
1329 }
1330 visitExpression(visitor, context) {
1331 return visitor.visitInstantiateExpr(this, context);
1332 }
1333 }
1334 class LiteralExpr extends Expression {
1335 constructor(value, type, sourceSpan) {
1336 super(type, sourceSpan);
1337 this.value = value;
1338 }
1339 isEquivalent(e) {
1340 return e instanceof LiteralExpr && this.value === e.value;
1341 }
1342 isConstant() {
1343 return true;
1344 }
1345 visitExpression(visitor, context) {
1346 return visitor.visitLiteralExpr(this, context);
1347 }
1348 }
1349 class TemplateLiteral {
1350 constructor(elements, expressions) {
1351 this.elements = elements;
1352 this.expressions = expressions;
1353 }
1354 }
1355 class TemplateLiteralElement {
1356 constructor(text, sourceSpan, rawText) {
1357 var _a;
1358 this.text = text;
1359 this.sourceSpan = sourceSpan;
1360 // If `rawText` is not provided, try to extract the raw string from its
1361 // associated `sourceSpan`. If that is also not available, "fake" the raw
1362 // string instead by escaping the following control sequences:
1363 // - "\" would otherwise indicate that the next character is a control character.
1364 // - "`" and "${" are template string control sequences that would otherwise prematurely
1365 // indicate the end of the template literal element.
1366 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));
1367 }
1368 }
1369 class MessagePiece {
1370 constructor(text, sourceSpan) {
1371 this.text = text;
1372 this.sourceSpan = sourceSpan;
1373 }
1374 }
1375 class LiteralPiece extends MessagePiece {
1376 }
1377 class PlaceholderPiece extends MessagePiece {
1378 }
1379 class LocalizedString extends Expression {
1380 constructor(metaBlock, messageParts, placeHolderNames, expressions, sourceSpan) {
1381 super(STRING_TYPE, sourceSpan);
1382 this.metaBlock = metaBlock;
1383 this.messageParts = messageParts;
1384 this.placeHolderNames = placeHolderNames;
1385 this.expressions = expressions;
1386 }
1387 isEquivalent(e) {
1388 // return e instanceof LocalizedString && this.message === e.message;
1389 return false;
1390 }
1391 isConstant() {
1392 return false;
1393 }
1394 visitExpression(visitor, context) {
1395 return visitor.visitLocalizedString(this, context);
1396 }
1397 /**
1398 * Serialize the given `meta` and `messagePart` into "cooked" and "raw" strings that can be used
1399 * in a `$localize` tagged string. The format of the metadata is the same as that parsed by
1400 * `parseI18nMeta()`.
1401 *
1402 * @param meta The metadata to serialize
1403 * @param messagePart The first part of the tagged string
1404 */
1405 serializeI18nHead() {
1406 const MEANING_SEPARATOR = '|';
1407 const ID_SEPARATOR = '@@';
1408 const LEGACY_ID_INDICATOR = '␟';
1409 let metaBlock = this.metaBlock.description || '';
1410 if (this.metaBlock.meaning) {
1411 metaBlock = `${this.metaBlock.meaning}${MEANING_SEPARATOR}${metaBlock}`;
1412 }
1413 if (this.metaBlock.customId) {
1414 metaBlock = `${metaBlock}${ID_SEPARATOR}${this.metaBlock.customId}`;
1415 }
1416 if (this.metaBlock.legacyIds) {
1417 this.metaBlock.legacyIds.forEach(legacyId => {
1418 metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`;
1419 });
1420 }
1421 return createCookedRawString(metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0));
1422 }
1423 getMessagePartSourceSpan(i) {
1424 var _a, _b;
1425 return (_b = (_a = this.messageParts[i]) === null || _a === void 0 ? void 0 : _a.sourceSpan) !== null && _b !== void 0 ? _b : this.sourceSpan;
1426 }
1427 getPlaceholderSourceSpan(i) {
1428 var _a, _b, _c, _d;
1429 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;
1430 }
1431 /**
1432 * Serialize the given `placeholderName` and `messagePart` into "cooked" and "raw" strings that
1433 * can be used in a `$localize` tagged string.
1434 *
1435 * @param placeholderName The placeholder name to serialize
1436 * @param messagePart The following message string after this placeholder
1437 */
1438 serializeI18nTemplatePart(partIndex) {
1439 const placeholderName = this.placeHolderNames[partIndex - 1].text;
1440 const messagePart = this.messageParts[partIndex];
1441 return createCookedRawString(placeholderName, messagePart.text, this.getMessagePartSourceSpan(partIndex));
1442 }
1443 }
1444 const escapeSlashes = (str) => str.replace(/\\/g, '\\\\');
1445 const escapeStartingColon = (str) => str.replace(/^:/, '\\:');
1446 const escapeColons = (str) => str.replace(/:/g, '\\:');
1447 const escapeForTemplateLiteral = (str) => str.replace(/`/g, '\\`').replace(/\${/g, '$\\{');
1448 /**
1449 * Creates a `{cooked, raw}` object from the `metaBlock` and `messagePart`.
1450 *
1451 * The `raw` text must have various character sequences escaped:
1452 * * "\" would otherwise indicate that the next character is a control character.
1453 * * "`" and "${" are template string control sequences that would otherwise prematurely indicate
1454 * the end of a message part.
1455 * * ":" inside a metablock would prematurely indicate the end of the metablock.
1456 * * ":" at the start of a messagePart with no metablock would erroneously indicate the start of a
1457 * metablock.
1458 *
1459 * @param metaBlock Any metadata that should be prepended to the string
1460 * @param messagePart The message part of the string
1461 */
1462 function createCookedRawString(metaBlock, messagePart, range) {
1463 if (metaBlock === '') {
1464 return {
1465 cooked: messagePart,
1466 raw: escapeForTemplateLiteral(escapeStartingColon(escapeSlashes(messagePart))),
1467 range,
1468 };
1469 }
1470 else {
1471 return {
1472 cooked: `:${metaBlock}:${messagePart}`,
1473 raw: escapeForTemplateLiteral(`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`),
1474 range,
1475 };
1476 }
1477 }
1478 class ExternalExpr extends Expression {
1479 constructor(value, type, typeParams = null, sourceSpan) {
1480 super(type, sourceSpan);
1481 this.value = value;
1482 this.typeParams = typeParams;
1483 }
1484 isEquivalent(e) {
1485 return e instanceof ExternalExpr && this.value.name === e.value.name &&
1486 this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime;
1487 }
1488 isConstant() {
1489 return false;
1490 }
1491 visitExpression(visitor, context) {
1492 return visitor.visitExternalExpr(this, context);
1493 }
1494 }
1495 class ConditionalExpr extends Expression {
1496 constructor(condition, trueCase, falseCase = null, type, sourceSpan) {
1497 super(type || trueCase.type, sourceSpan);
1498 this.condition = condition;
1499 this.falseCase = falseCase;
1500 this.trueCase = trueCase;
1501 }
1502 isEquivalent(e) {
1503 return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) &&
1504 this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
1505 }
1506 isConstant() {
1507 return false;
1508 }
1509 visitExpression(visitor, context) {
1510 return visitor.visitConditionalExpr(this, context);
1511 }
1512 }
1513 class NotExpr extends Expression {
1514 constructor(condition, sourceSpan) {
1515 super(BOOL_TYPE, sourceSpan);
1516 this.condition = condition;
1517 }
1518 isEquivalent(e) {
1519 return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
1520 }
1521 isConstant() {
1522 return false;
1523 }
1524 visitExpression(visitor, context) {
1525 return visitor.visitNotExpr(this, context);
1526 }
1527 }
1528 class AssertNotNull extends Expression {
1529 constructor(condition, sourceSpan) {
1530 super(condition.type, sourceSpan);
1531 this.condition = condition;
1532 }
1533 isEquivalent(e) {
1534 return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition);
1535 }
1536 isConstant() {
1537 return false;
1538 }
1539 visitExpression(visitor, context) {
1540 return visitor.visitAssertNotNullExpr(this, context);
1541 }
1542 }
1543 class CastExpr extends Expression {
1544 constructor(value, type, sourceSpan) {
1545 super(type, sourceSpan);
1546 this.value = value;
1547 }
1548 isEquivalent(e) {
1549 return e instanceof CastExpr && this.value.isEquivalent(e.value);
1550 }
1551 isConstant() {
1552 return false;
1553 }
1554 visitExpression(visitor, context) {
1555 return visitor.visitCastExpr(this, context);
1556 }
1557 }
1558 class FnParam {
1559 constructor(name, type = null) {
1560 this.name = name;
1561 this.type = type;
1562 }
1563 isEquivalent(param) {
1564 return this.name === param.name;
1565 }
1566 }
1567 class FunctionExpr extends Expression {
1568 constructor(params, statements, type, sourceSpan, name) {
1569 super(type, sourceSpan);
1570 this.params = params;
1571 this.statements = statements;
1572 this.name = name;
1573 }
1574 isEquivalent(e) {
1575 return e instanceof FunctionExpr && areAllEquivalent(this.params, e.params) &&
1576 areAllEquivalent(this.statements, e.statements);
1577 }
1578 isConstant() {
1579 return false;
1580 }
1581 visitExpression(visitor, context) {
1582 return visitor.visitFunctionExpr(this, context);
1583 }
1584 toDeclStmt(name, modifiers) {
1585 return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan);
1586 }
1587 }
1588 class UnaryOperatorExpr extends Expression {
1589 constructor(operator, expr, type, sourceSpan, parens = true) {
1590 super(type || NUMBER_TYPE, sourceSpan);
1591 this.operator = operator;
1592 this.expr = expr;
1593 this.parens = parens;
1594 }
1595 isEquivalent(e) {
1596 return e instanceof UnaryOperatorExpr && this.operator === e.operator &&
1597 this.expr.isEquivalent(e.expr);
1598 }
1599 isConstant() {
1600 return false;
1601 }
1602 visitExpression(visitor, context) {
1603 return visitor.visitUnaryOperatorExpr(this, context);
1604 }
1605 }
1606 class BinaryOperatorExpr extends Expression {
1607 constructor(operator, lhs, rhs, type, sourceSpan, parens = true) {
1608 super(type || lhs.type, sourceSpan);
1609 this.operator = operator;
1610 this.rhs = rhs;
1611 this.parens = parens;
1612 this.lhs = lhs;
1613 }
1614 isEquivalent(e) {
1615 return e instanceof BinaryOperatorExpr && this.operator === e.operator &&
1616 this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
1617 }
1618 isConstant() {
1619 return false;
1620 }
1621 visitExpression(visitor, context) {
1622 return visitor.visitBinaryOperatorExpr(this, context);
1623 }
1624 }
1625 class ReadPropExpr extends Expression {
1626 constructor(receiver, name, type, sourceSpan) {
1627 super(type, sourceSpan);
1628 this.receiver = receiver;
1629 this.name = name;
1630 }
1631 isEquivalent(e) {
1632 return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) &&
1633 this.name === e.name;
1634 }
1635 isConstant() {
1636 return false;
1637 }
1638 visitExpression(visitor, context) {
1639 return visitor.visitReadPropExpr(this, context);
1640 }
1641 set(value) {
1642 return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan);
1643 }
1644 }
1645 class ReadKeyExpr extends Expression {
1646 constructor(receiver, index, type, sourceSpan) {
1647 super(type, sourceSpan);
1648 this.receiver = receiver;
1649 this.index = index;
1650 }
1651 isEquivalent(e) {
1652 return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) &&
1653 this.index.isEquivalent(e.index);
1654 }
1655 isConstant() {
1656 return false;
1657 }
1658 visitExpression(visitor, context) {
1659 return visitor.visitReadKeyExpr(this, context);
1660 }
1661 set(value) {
1662 return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan);
1663 }
1664 }
1665 class LiteralArrayExpr extends Expression {
1666 constructor(entries, type, sourceSpan) {
1667 super(type, sourceSpan);
1668 this.entries = entries;
1669 }
1670 isConstant() {
1671 return this.entries.every(e => e.isConstant());
1672 }
1673 isEquivalent(e) {
1674 return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
1675 }
1676 visitExpression(visitor, context) {
1677 return visitor.visitLiteralArrayExpr(this, context);
1678 }
1679 }
1680 class LiteralMapEntry {
1681 constructor(key, value, quoted) {
1682 this.key = key;
1683 this.value = value;
1684 this.quoted = quoted;
1685 }
1686 isEquivalent(e) {
1687 return this.key === e.key && this.value.isEquivalent(e.value);
1688 }
1689 }
1690 class LiteralMapExpr extends Expression {
1691 constructor(entries, type, sourceSpan) {
1692 super(type, sourceSpan);
1693 this.entries = entries;
1694 this.valueType = null;
1695 if (type) {
1696 this.valueType = type.valueType;
1697 }
1698 }
1699 isEquivalent(e) {
1700 return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
1701 }
1702 isConstant() {
1703 return this.entries.every(e => e.value.isConstant());
1704 }
1705 visitExpression(visitor, context) {
1706 return visitor.visitLiteralMapExpr(this, context);
1707 }
1708 }
1709 const THIS_EXPR = new ReadVarExpr(BuiltinVar.This, null, null);
1710 const SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super, null, null);
1711 const CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError, null, null);
1712 const CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack, null, null);
1713 const NULL_EXPR = new LiteralExpr(null, null, null);
1714 const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
1715 //// Statements
1716 var StmtModifier;
1717 (function (StmtModifier) {
1718 StmtModifier[StmtModifier["Final"] = 0] = "Final";
1719 StmtModifier[StmtModifier["Private"] = 1] = "Private";
1720 StmtModifier[StmtModifier["Exported"] = 2] = "Exported";
1721 StmtModifier[StmtModifier["Static"] = 3] = "Static";
1722 })(StmtModifier || (StmtModifier = {}));
1723 class LeadingComment {
1724 constructor(text, multiline, trailingNewline) {
1725 this.text = text;
1726 this.multiline = multiline;
1727 this.trailingNewline = trailingNewline;
1728 }
1729 toString() {
1730 return this.multiline ? ` ${this.text} ` : this.text;
1731 }
1732 }
1733 class JSDocComment extends LeadingComment {
1734 constructor(tags) {
1735 super('', /* multiline */ true, /* trailingNewline */ true);
1736 this.tags = tags;
1737 }
1738 toString() {
1739 return serializeTags(this.tags);
1740 }
1741 }
1742 class Statement {
1743 constructor(modifiers = [], sourceSpan = null, leadingComments) {
1744 this.modifiers = modifiers;
1745 this.sourceSpan = sourceSpan;
1746 this.leadingComments = leadingComments;
1747 }
1748 hasModifier(modifier) {
1749 return this.modifiers.indexOf(modifier) !== -1;
1750 }
1751 addLeadingComment(leadingComment) {
1752 var _a;
1753 this.leadingComments = (_a = this.leadingComments) !== null && _a !== void 0 ? _a : [];
1754 this.leadingComments.push(leadingComment);
1755 }
1756 }
1757 class DeclareVarStmt extends Statement {
1758 constructor(name, value, type, modifiers, sourceSpan, leadingComments) {
1759 super(modifiers, sourceSpan, leadingComments);
1760 this.name = name;
1761 this.value = value;
1762 this.type = type || (value && value.type) || null;
1763 }
1764 isEquivalent(stmt) {
1765 return stmt instanceof DeclareVarStmt && this.name === stmt.name &&
1766 (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value);
1767 }
1768 visitStatement(visitor, context) {
1769 return visitor.visitDeclareVarStmt(this, context);
1770 }
1771 }
1772 class DeclareFunctionStmt extends Statement {
1773 constructor(name, params, statements, type, modifiers, sourceSpan, leadingComments) {
1774 super(modifiers, sourceSpan, leadingComments);
1775 this.name = name;
1776 this.params = params;
1777 this.statements = statements;
1778 this.type = type || null;
1779 }
1780 isEquivalent(stmt) {
1781 return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) &&
1782 areAllEquivalent(this.statements, stmt.statements);
1783 }
1784 visitStatement(visitor, context) {
1785 return visitor.visitDeclareFunctionStmt(this, context);
1786 }
1787 }
1788 class ExpressionStatement extends Statement {
1789 constructor(expr, sourceSpan, leadingComments) {
1790 super([], sourceSpan, leadingComments);
1791 this.expr = expr;
1792 }
1793 isEquivalent(stmt) {
1794 return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr);
1795 }
1796 visitStatement(visitor, context) {
1797 return visitor.visitExpressionStmt(this, context);
1798 }
1799 }
1800 class ReturnStatement extends Statement {
1801 constructor(value, sourceSpan = null, leadingComments) {
1802 super([], sourceSpan, leadingComments);
1803 this.value = value;
1804 }
1805 isEquivalent(stmt) {
1806 return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value);
1807 }
1808 visitStatement(visitor, context) {
1809 return visitor.visitReturnStmt(this, context);
1810 }
1811 }
1812 class IfStmt extends Statement {
1813 constructor(condition, trueCase, falseCase = [], sourceSpan, leadingComments) {
1814 super([], sourceSpan, leadingComments);
1815 this.condition = condition;
1816 this.trueCase = trueCase;
1817 this.falseCase = falseCase;
1818 }
1819 isEquivalent(stmt) {
1820 return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) &&
1821 areAllEquivalent(this.trueCase, stmt.trueCase) &&
1822 areAllEquivalent(this.falseCase, stmt.falseCase);
1823 }
1824 visitStatement(visitor, context) {
1825 return visitor.visitIfStmt(this, context);
1826 }
1827 }
1828 function jsDocComment(tags = []) {
1829 return new JSDocComment(tags);
1830 }
1831 function variable(name, type, sourceSpan) {
1832 return new ReadVarExpr(name, type, sourceSpan);
1833 }
1834 function importExpr(id, typeParams = null, sourceSpan) {
1835 return new ExternalExpr(id, null, typeParams, sourceSpan);
1836 }
1837 function expressionType(expr, typeModifiers, typeParams) {
1838 return new ExpressionType(expr, typeModifiers, typeParams);
1839 }
1840 function typeofExpr(expr) {
1841 return new TypeofExpr(expr);
1842 }
1843 function literalArr(values, type, sourceSpan) {
1844 return new LiteralArrayExpr(values, type, sourceSpan);
1845 }
1846 function literalMap(values, type = null) {
1847 return new LiteralMapExpr(values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null);
1848 }
1849 function not(expr, sourceSpan) {
1850 return new NotExpr(expr, sourceSpan);
1851 }
1852 function assertNotNull(expr, sourceSpan) {
1853 return new AssertNotNull(expr, sourceSpan);
1854 }
1855 function fn(params, body, type, sourceSpan, name) {
1856 return new FunctionExpr(params, body, type, sourceSpan, name);
1857 }
1858 function ifStmt(condition, thenClause, elseClause, sourceSpan, leadingComments) {
1859 return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments);
1860 }
1861 function taggedTemplate(tag, template, type, sourceSpan) {
1862 return new TaggedTemplateExpr(tag, template, type, sourceSpan);
1863 }
1864 function literal(value, type, sourceSpan) {
1865 return new LiteralExpr(value, type, sourceSpan);
1866 }
1867 function localizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan) {
1868 return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan);
1869 }
1870 function isNull(exp) {
1871 return exp instanceof LiteralExpr && exp.value === null;
1872 }
1873 /*
1874 * Serializes a `Tag` into a string.
1875 * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`).
1876 */
1877 function tagToString(tag) {
1878 let out = '';
1879 if (tag.tagName) {
1880 out += ` @${tag.tagName}`;
1881 }
1882 if (tag.text) {
1883 if (tag.text.match(/\/\*|\*\//)) {
1884 throw new Error('JSDoc text cannot contain "/*" and "*/"');
1885 }
1886 out += ' ' + tag.text.replace(/@/g, '\\@');
1887 }
1888 return out;
1889 }
1890 function serializeTags(tags) {
1891 if (tags.length === 0)
1892 return '';
1893 if (tags.length === 1 && tags[0].tagName && !tags[0].text) {
1894 // The JSDOC comment is a single simple tag: e.g `/** @tagname */`.
1895 return `*${tagToString(tags[0])} `;
1896 }
1897 let out = '*\n';
1898 for (const tag of tags) {
1899 out += ' *';
1900 // If the tagToString is multi-line, insert " * " prefixes on lines.
1901 out += tagToString(tag).replace(/\n/g, '\n * ');
1902 out += '\n';
1903 }
1904 out += ' ';
1905 return out;
1906 }
1907
1908 /**
1909 * @license
1910 * Copyright Google LLC All Rights Reserved.
1911 *
1912 * Use of this source code is governed by an MIT-style license that can be
1913 * found in the LICENSE file at https://angular.io/license
1914 */
1915 const CONSTANT_PREFIX = '_c';
1916 /**
1917 * `ConstantPool` tries to reuse literal factories when two or more literals are identical.
1918 * We determine whether literals are identical by creating a key out of their AST using the
1919 * `KeyVisitor`. This constant is used to replace dynamic expressions which can't be safely
1920 * converted into a key. E.g. given an expression `{foo: bar()}`, since we don't know what
1921 * the result of `bar` will be, we create a key that looks like `{foo: <unknown>}`. Note
1922 * that we use a variable, rather than something like `null` in order to avoid collisions.
1923 */
1924 const UNKNOWN_VALUE_KEY = variable('<unknown>');
1925 /**
1926 * Context to use when producing a key.
1927 *
1928 * This ensures we see the constant not the reference variable when producing
1929 * a key.
1930 */
1931 const KEY_CONTEXT = {};
1932 /**
1933 * Generally all primitive values are excluded from the `ConstantPool`, but there is an exclusion
1934 * for strings that reach a certain length threshold. This constant defines the length threshold for
1935 * strings.
1936 */
1937 const POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS = 50;
1938 /**
1939 * A node that is a place-holder that allows the node to be replaced when the actual
1940 * node is known.
1941 *
1942 * This allows the constant pool to change an expression from a direct reference to
1943 * a constant to a shared constant. It returns a fix-up node that is later allowed to
1944 * change the referenced expression.
1945 */
1946 class FixupExpression extends Expression {
1947 constructor(resolved) {
1948 super(resolved.type);
1949 this.resolved = resolved;
1950 this.original = resolved;
1951 }
1952 visitExpression(visitor, context) {
1953 if (context === KEY_CONTEXT) {
1954 // When producing a key we want to traverse the constant not the
1955 // variable used to refer to it.
1956 return this.original.visitExpression(visitor, context);
1957 }
1958 else {
1959 return this.resolved.visitExpression(visitor, context);
1960 }
1961 }
1962 isEquivalent(e) {
1963 return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
1964 }
1965 isConstant() {
1966 return true;
1967 }
1968 fixup(expression) {
1969 this.resolved = expression;
1970 this.shared = true;
1971 }
1972 }
1973 /**
1974 * A constant pool allows a code emitter to share constant in an output context.
1975 *
1976 * The constant pool also supports sharing access to ivy definitions references.
1977 */
1978 class ConstantPool {
1979 constructor(isClosureCompilerEnabled = false) {
1980 this.isClosureCompilerEnabled = isClosureCompilerEnabled;
1981 this.statements = [];
1982 this.literals = new Map();
1983 this.literalFactories = new Map();
1984 this.injectorDefinitions = new Map();
1985 this.directiveDefinitions = new Map();
1986 this.componentDefinitions = new Map();
1987 this.pipeDefinitions = new Map();
1988 this.nextNameIndex = 0;
1989 }
1990 getConstLiteral(literal, forceShared) {
1991 if ((literal instanceof LiteralExpr && !isLongStringLiteral(literal)) ||
1992 literal instanceof FixupExpression) {
1993 // Do no put simple literals into the constant pool or try to produce a constant for a
1994 // reference to a constant.
1995 return literal;
1996 }
1997 const key = this.keyOf(literal);
1998 let fixup = this.literals.get(key);
1999 let newValue = false;
2000 if (!fixup) {
2001 fixup = new FixupExpression(literal);
2002 this.literals.set(key, fixup);
2003 newValue = true;
2004 }
2005 if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
2006 // Replace the expression with a variable
2007 const name = this.freshName();
2008 let definition;
2009 let usage;
2010 if (this.isClosureCompilerEnabled && isLongStringLiteral(literal)) {
2011 // For string literals, Closure will **always** inline the string at
2012 // **all** usages, duplicating it each time. For large strings, this
2013 // unnecessarily bloats bundle size. To work around this restriction, we
2014 // wrap the string in a function, and call that function for each usage.
2015 // This tricks Closure into using inline logic for functions instead of
2016 // string literals. Function calls are only inlined if the body is small
2017 // enough to be worth it. By doing this, very large strings will be
2018 // shared across multiple usages, rather than duplicating the string at
2019 // each usage site.
2020 //
2021 // const myStr = function() { return "very very very long string"; };
2022 // const usage1 = myStr();
2023 // const usage2 = myStr();
2024 definition = variable(name).set(new FunctionExpr([], // Params.
2025 [
2026 // Statements.
2027 new ReturnStatement(literal),
2028 ]));
2029 usage = variable(name).callFn([]);
2030 }
2031 else {
2032 // Just declare and use the variable directly, without a function call
2033 // indirection. This saves a few bytes and avoids an unncessary call.
2034 definition = variable(name).set(literal);
2035 usage = variable(name);
2036 }
2037 this.statements.push(definition.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]));
2038 fixup.fixup(usage);
2039 }
2040 return fixup;
2041 }
2042 getDefinition(type, kind, ctx, forceShared = false) {
2043 const definitions = this.definitionsOf(kind);
2044 let fixup = definitions.get(type);
2045 let newValue = false;
2046 if (!fixup) {
2047 const property = this.propertyNameOf(kind);
2048 fixup = new FixupExpression(ctx.importExpr(type).prop(property));
2049 definitions.set(type, fixup);
2050 newValue = true;
2051 }
2052 if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
2053 const name = this.freshName();
2054 this.statements.push(variable(name).set(fixup.resolved).toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]));
2055 fixup.fixup(variable(name));
2056 }
2057 return fixup;
2058 }
2059 getLiteralFactory(literal) {
2060 // Create a pure function that builds an array of a mix of constant and variable expressions
2061 if (literal instanceof LiteralArrayExpr) {
2062 const argumentsForKey = literal.entries.map(e => e.isConstant() ? e : UNKNOWN_VALUE_KEY);
2063 const key = this.keyOf(literalArr(argumentsForKey));
2064 return this._getLiteralFactory(key, literal.entries, entries => literalArr(entries));
2065 }
2066 else {
2067 const expressionForKey = literalMap(literal.entries.map(e => ({
2068 key: e.key,
2069 value: e.value.isConstant() ? e.value : UNKNOWN_VALUE_KEY,
2070 quoted: e.quoted
2071 })));
2072 const key = this.keyOf(expressionForKey);
2073 return this._getLiteralFactory(key, literal.entries.map(e => e.value), entries => literalMap(entries.map((value, index) => ({
2074 key: literal.entries[index].key,
2075 value,
2076 quoted: literal.entries[index].quoted
2077 }))));
2078 }
2079 }
2080 _getLiteralFactory(key, values, resultMap) {
2081 let literalFactory = this.literalFactories.get(key);
2082 const literalFactoryArguments = values.filter((e => !e.isConstant()));
2083 if (!literalFactory) {
2084 const resultExpressions = values.map((e, index) => e.isConstant() ? this.getConstLiteral(e, true) : variable(`a${index}`));
2085 const parameters = resultExpressions.filter(isVariable).map(e => new FnParam(e.name, DYNAMIC_TYPE));
2086 const pureFunctionDeclaration = fn(parameters, [new ReturnStatement(resultMap(resultExpressions))], INFERRED_TYPE);
2087 const name = this.freshName();
2088 this.statements.push(variable(name).set(pureFunctionDeclaration).toDeclStmt(INFERRED_TYPE, [
2089 StmtModifier.Final
2090 ]));
2091 literalFactory = variable(name);
2092 this.literalFactories.set(key, literalFactory);
2093 }
2094 return { literalFactory, literalFactoryArguments };
2095 }
2096 /**
2097 * Produce a unique name.
2098 *
2099 * The name might be unique among different prefixes if any of the prefixes end in
2100 * a digit so the prefix should be a constant string (not based on user input) and
2101 * must not end in a digit.
2102 */
2103 uniqueName(prefix) {
2104 return `${prefix}${this.nextNameIndex++}`;
2105 }
2106 definitionsOf(kind) {
2107 switch (kind) {
2108 case 2 /* Component */:
2109 return this.componentDefinitions;
2110 case 1 /* Directive */:
2111 return this.directiveDefinitions;
2112 case 0 /* Injector */:
2113 return this.injectorDefinitions;
2114 case 3 /* Pipe */:
2115 return this.pipeDefinitions;
2116 }
2117 }
2118 propertyNameOf(kind) {
2119 switch (kind) {
2120 case 2 /* Component */:
2121 return 'ɵcmp';
2122 case 1 /* Directive */:
2123 return 'ɵdir';
2124 case 0 /* Injector */:
2125 return 'ɵinj';
2126 case 3 /* Pipe */:
2127 return 'ɵpipe';
2128 }
2129 }
2130 freshName() {
2131 return this.uniqueName(CONSTANT_PREFIX);
2132 }
2133 keyOf(expression) {
2134 return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT);
2135 }
2136 }
2137 /**
2138 * Visitor used to determine if 2 expressions are equivalent and can be shared in the
2139 * `ConstantPool`.
2140 *
2141 * When the id (string) generated by the visitor is equal, expressions are considered equivalent.
2142 */
2143 class KeyVisitor {
2144 constructor() {
2145 this.visitWrappedNodeExpr = invalid;
2146 this.visitWriteVarExpr = invalid;
2147 this.visitWriteKeyExpr = invalid;
2148 this.visitWritePropExpr = invalid;
2149 this.visitInvokeMethodExpr = invalid;
2150 this.visitInvokeFunctionExpr = invalid;
2151 this.visitTaggedTemplateExpr = invalid;
2152 this.visitInstantiateExpr = invalid;
2153 this.visitConditionalExpr = invalid;
2154 this.visitNotExpr = invalid;
2155 this.visitAssertNotNullExpr = invalid;
2156 this.visitCastExpr = invalid;
2157 this.visitFunctionExpr = invalid;
2158 this.visitUnaryOperatorExpr = invalid;
2159 this.visitBinaryOperatorExpr = invalid;
2160 this.visitReadPropExpr = invalid;
2161 this.visitReadKeyExpr = invalid;
2162 this.visitCommaExpr = invalid;
2163 this.visitLocalizedString = invalid;
2164 }
2165 visitLiteralExpr(ast) {
2166 return `${typeof ast.value === 'string' ? '"' + ast.value + '"' : ast.value}`;
2167 }
2168 visitLiteralArrayExpr(ast, context) {
2169 return `[${ast.entries.map(entry => entry.visitExpression(this, context)).join(',')}]`;
2170 }
2171 visitLiteralMapExpr(ast, context) {
2172 const mapKey = (entry) => {
2173 const quote = entry.quoted ? '"' : '';
2174 return `${quote}${entry.key}${quote}`;
2175 };
2176 const mapEntry = (entry) => `${mapKey(entry)}:${entry.value.visitExpression(this, context)}`;
2177 return `{${ast.entries.map(mapEntry).join(',')}`;
2178 }
2179 visitExternalExpr(ast) {
2180 return ast.value.moduleName ? `EX:${ast.value.moduleName}:${ast.value.name}` :
2181 `EX:${ast.value.runtime.name}`;
2182 }
2183 visitReadVarExpr(node) {
2184 return `VAR:${node.name}`;
2185 }
2186 visitTypeofExpr(node, context) {
2187 return `TYPEOF:${node.expr.visitExpression(this, context)}`;
2188 }
2189 }
2190 function invalid(arg) {
2191 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
2192 }
2193 function isVariable(e) {
2194 return e instanceof ReadVarExpr;
2195 }
2196 function isLongStringLiteral(expr) {
2197 return expr instanceof LiteralExpr && typeof expr.value === 'string' &&
2198 expr.value.length >= POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS;
2199 }
2200
2201 /**
2202 * @license
2203 * Copyright Google LLC All Rights Reserved.
2204 *
2205 * Use of this source code is governed by an MIT-style license that can be
2206 * found in the LICENSE file at https://angular.io/license
2207 */
2208 const CORE = '@angular/core';
2209 class Identifiers {
2210 }
2211 Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS = {
2212 name: 'ANALYZE_FOR_ENTRY_COMPONENTS',
2213 moduleName: CORE,
2214 };
2215 Identifiers.ElementRef = { name: 'ElementRef', moduleName: CORE };
2216 Identifiers.NgModuleRef = { name: 'NgModuleRef', moduleName: CORE };
2217 Identifiers.ViewContainerRef = { name: 'ViewContainerRef', moduleName: CORE };
2218 Identifiers.ChangeDetectorRef = {
2219 name: 'ChangeDetectorRef',
2220 moduleName: CORE,
2221 };
2222 Identifiers.QueryList = { name: 'QueryList', moduleName: CORE };
2223 Identifiers.TemplateRef = { name: 'TemplateRef', moduleName: CORE };
2224 Identifiers.Renderer2 = { name: 'Renderer2', moduleName: CORE };
2225 Identifiers.CodegenComponentFactoryResolver = {
2226 name: 'ɵCodegenComponentFactoryResolver',
2227 moduleName: CORE,
2228 };
2229 Identifiers.ComponentFactoryResolver = {
2230 name: 'ComponentFactoryResolver',
2231 moduleName: CORE,
2232 };
2233 Identifiers.ComponentFactory = { name: 'ComponentFactory', moduleName: CORE };
2234 Identifiers.ComponentRef = { name: 'ComponentRef', moduleName: CORE };
2235 Identifiers.NgModuleFactory = { name: 'NgModuleFactory', moduleName: CORE };
2236 Identifiers.createModuleFactory = {
2237 name: 'ɵcmf',
2238 moduleName: CORE,
2239 };
2240 Identifiers.moduleDef = {
2241 name: 'ɵmod',
2242 moduleName: CORE,
2243 };
2244 Identifiers.moduleProviderDef = {
2245 name: 'ɵmpd',
2246 moduleName: CORE,
2247 };
2248 Identifiers.RegisterModuleFactoryFn = {
2249 name: 'ɵregisterModuleFactory',
2250 moduleName: CORE,
2251 };
2252 Identifiers.inject = { name: 'ɵɵinject', moduleName: CORE };
2253 Identifiers.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE };
2254 Identifiers.INJECTOR = { name: 'INJECTOR', moduleName: CORE };
2255 Identifiers.Injector = { name: 'Injector', moduleName: CORE };
2256 Identifiers.ɵɵdefineInjectable = { name: 'ɵɵdefineInjectable', moduleName: CORE };
2257 Identifiers.InjectableDef = { name: 'ɵɵInjectableDef', moduleName: CORE };
2258 Identifiers.ViewEncapsulation = {
2259 name: 'ViewEncapsulation',
2260 moduleName: CORE,
2261 };
2262 Identifiers.ChangeDetectionStrategy = {
2263 name: 'ChangeDetectionStrategy',
2264 moduleName: CORE,
2265 };
2266 Identifiers.SecurityContext = {
2267 name: 'SecurityContext',
2268 moduleName: CORE,
2269 };
2270 Identifiers.LOCALE_ID = { name: 'LOCALE_ID', moduleName: CORE };
2271 Identifiers.TRANSLATIONS_FORMAT = {
2272 name: 'TRANSLATIONS_FORMAT',
2273 moduleName: CORE,
2274 };
2275 Identifiers.inlineInterpolate = {
2276 name: 'ɵinlineInterpolate',
2277 moduleName: CORE,
2278 };
2279 Identifiers.interpolate = { name: 'ɵinterpolate', moduleName: CORE };
2280 Identifiers.EMPTY_ARRAY = { name: 'ɵEMPTY_ARRAY', moduleName: CORE };
2281 Identifiers.EMPTY_MAP = { name: 'ɵEMPTY_MAP', moduleName: CORE };
2282 Identifiers.Renderer = { name: 'Renderer', moduleName: CORE };
2283 Identifiers.viewDef = { name: 'ɵvid', moduleName: CORE };
2284 Identifiers.elementDef = { name: 'ɵeld', moduleName: CORE };
2285 Identifiers.anchorDef = { name: 'ɵand', moduleName: CORE };
2286 Identifiers.textDef = { name: 'ɵted', moduleName: CORE };
2287 Identifiers.directiveDef = { name: 'ɵdid', moduleName: CORE };
2288 Identifiers.providerDef = { name: 'ɵprd', moduleName: CORE };
2289 Identifiers.queryDef = { name: 'ɵqud', moduleName: CORE };
2290 Identifiers.pureArrayDef = { name: 'ɵpad', moduleName: CORE };
2291 Identifiers.pureObjectDef = { name: 'ɵpod', moduleName: CORE };
2292 Identifiers.purePipeDef = { name: 'ɵppd', moduleName: CORE };
2293 Identifiers.pipeDef = { name: 'ɵpid', moduleName: CORE };
2294 Identifiers.nodeValue = { name: 'ɵnov', moduleName: CORE };
2295 Identifiers.ngContentDef = { name: 'ɵncd', moduleName: CORE };
2296 Identifiers.unwrapValue = { name: 'ɵunv', moduleName: CORE };
2297 Identifiers.createRendererType2 = { name: 'ɵcrt', moduleName: CORE };
2298 // type only
2299 Identifiers.RendererType2 = {
2300 name: 'RendererType2',
2301 moduleName: CORE,
2302 };
2303 // type only
2304 Identifiers.ViewDefinition = {
2305 name: 'ɵViewDefinition',
2306 moduleName: CORE,
2307 };
2308 Identifiers.createComponentFactory = { name: 'ɵccf', moduleName: CORE };
2309 Identifiers.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE };
2310 function createTokenForReference(reference) {
2311 return { identifier: { reference: reference } };
2312 }
2313 function createTokenForExternalReference(reflector, reference) {
2314 return createTokenForReference(reflector.resolveExternalReference(reference));
2315 }
2316
2317 /**
2318 * @license
2319 * Copyright Google LLC All Rights Reserved.
2320 *
2321 * Use of this source code is governed by an MIT-style license that can be
2322 * found in the LICENSE file at https://angular.io/license
2323 */
2324 /**
2325 * A token representing the a reference to a static type.
2326 *
2327 * This token is unique for a filePath and name and can be used as a hash table key.
2328 */
2329 class StaticSymbol {
2330 constructor(filePath, name, members) {
2331 this.filePath = filePath;
2332 this.name = name;
2333 this.members = members;
2334 }
2335 assertNoMembers() {
2336 if (this.members.length) {
2337 throw new Error(`Illegal state: symbol without members expected, but got ${JSON.stringify(this)}.`);
2338 }
2339 }
2340 }
2341 /**
2342 * A cache of static symbol used by the StaticReflector to return the same symbol for the
2343 * same symbol values.
2344 */
2345 class StaticSymbolCache {
2346 constructor() {
2347 this.cache = new Map();
2348 }
2349 get(declarationFile, name, members) {
2350 members = members || [];
2351 const memberSuffix = members.length ? `.${members.join('.')}` : '';
2352 const key = `"${declarationFile}".${name}${memberSuffix}`;
2353 let result = this.cache.get(key);
2354 if (!result) {
2355 result = new StaticSymbol(declarationFile, name, members);
2356 this.cache.set(key, result);
2357 }
2358 return result;
2359 }
2360 }
2361
2362 /**
2363 * @license
2364 * Copyright Google LLC All Rights Reserved.
2365 *
2366 * Use of this source code is governed by an MIT-style license that can be
2367 * found in the LICENSE file at https://angular.io/license
2368 */
2369 const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
2370 function dashCaseToCamelCase(input) {
2371 return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase());
2372 }
2373 function splitAtColon(input, defaultValues) {
2374 return _splitAt(input, ':', defaultValues);
2375 }
2376 function splitAtPeriod(input, defaultValues) {
2377 return _splitAt(input, '.', defaultValues);
2378 }
2379 function _splitAt(input, character, defaultValues) {
2380 const characterIndex = input.indexOf(character);
2381 if (characterIndex == -1)
2382 return defaultValues;
2383 return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()];
2384 }
2385 function visitValue(value, visitor, context) {
2386 if (Array.isArray(value)) {
2387 return visitor.visitArray(value, context);
2388 }
2389 if (isStrictStringMap(value)) {
2390 return visitor.visitStringMap(value, context);
2391 }
2392 if (value == null || typeof value == 'string' || typeof value == 'number' ||
2393 typeof value == 'boolean') {
2394 return visitor.visitPrimitive(value, context);
2395 }
2396 return visitor.visitOther(value, context);
2397 }
2398 function isDefined(val) {
2399 return val !== null && val !== undefined;
2400 }
2401 function noUndefined(val) {
2402 return val === undefined ? null : val;
2403 }
2404 class ValueTransformer {
2405 visitArray(arr, context) {
2406 return arr.map(value => visitValue(value, this, context));
2407 }
2408 visitStringMap(map, context) {
2409 const result = {};
2410 Object.keys(map).forEach(key => {
2411 result[key] = visitValue(map[key], this, context);
2412 });
2413 return result;
2414 }
2415 visitPrimitive(value, context) {
2416 return value;
2417 }
2418 visitOther(value, context) {
2419 return value;
2420 }
2421 }
2422 const SyncAsync = {
2423 assertSync: (value) => {
2424 if (isPromise(value)) {
2425 throw new Error(`Illegal state: value cannot be a promise`);
2426 }
2427 return value;
2428 },
2429 then: (value, cb) => {
2430 return isPromise(value) ? value.then(cb) : cb(value);
2431 },
2432 all: (syncAsyncValues) => {
2433 return syncAsyncValues.some(isPromise) ? Promise.all(syncAsyncValues) : syncAsyncValues;
2434 }
2435 };
2436 function error(msg) {
2437 throw new Error(`Internal Error: ${msg}`);
2438 }
2439 function syntaxError(msg, parseErrors) {
2440 const error = Error(msg);
2441 error[ERROR_SYNTAX_ERROR] = true;
2442 if (parseErrors)
2443 error[ERROR_PARSE_ERRORS] = parseErrors;
2444 return error;
2445 }
2446 const ERROR_SYNTAX_ERROR = 'ngSyntaxError';
2447 const ERROR_PARSE_ERRORS = 'ngParseErrors';
2448 const STRING_MAP_PROTO = Object.getPrototypeOf({});
2449 function isStrictStringMap(obj) {
2450 return typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === STRING_MAP_PROTO;
2451 }
2452 function utf8Encode(str) {
2453 let encoded = [];
2454 for (let index = 0; index < str.length; index++) {
2455 let codePoint = str.charCodeAt(index);
2456 // decode surrogate
2457 // see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
2458 if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > (index + 1)) {
2459 const low = str.charCodeAt(index + 1);
2460 if (low >= 0xdc00 && low <= 0xdfff) {
2461 index++;
2462 codePoint = ((codePoint - 0xd800) << 10) + low - 0xdc00 + 0x10000;
2463 }
2464 }
2465 if (codePoint <= 0x7f) {
2466 encoded.push(codePoint);
2467 }
2468 else if (codePoint <= 0x7ff) {
2469 encoded.push(((codePoint >> 6) & 0x1F) | 0xc0, (codePoint & 0x3f) | 0x80);
2470 }
2471 else if (codePoint <= 0xffff) {
2472 encoded.push((codePoint >> 12) | 0xe0, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80);
2473 }
2474 else if (codePoint <= 0x1fffff) {
2475 encoded.push(((codePoint >> 18) & 0x07) | 0xf0, ((codePoint >> 12) & 0x3f) | 0x80, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80);
2476 }
2477 }
2478 return encoded;
2479 }
2480 function stringify(token) {
2481 if (typeof token === 'string') {
2482 return token;
2483 }
2484 if (Array.isArray(token)) {
2485 return '[' + token.map(stringify).join(', ') + ']';
2486 }
2487 if (token == null) {
2488 return '' + token;
2489 }
2490 if (token.overriddenName) {
2491 return `${token.overriddenName}`;
2492 }
2493 if (token.name) {
2494 return `${token.name}`;
2495 }
2496 if (!token.toString) {
2497 return 'object';
2498 }
2499 // WARNING: do not try to `JSON.stringify(token)` here
2500 // see https://github.com/angular/angular/issues/23440
2501 const res = token.toString();
2502 if (res == null) {
2503 return '' + res;
2504 }
2505 const newLineIndex = res.indexOf('\n');
2506 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
2507 }
2508 /**
2509 * Lazily retrieves the reference value from a forwardRef.
2510 */
2511 function resolveForwardRef(type) {
2512 if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__')) {
2513 return type();
2514 }
2515 else {
2516 return type;
2517 }
2518 }
2519 /**
2520 * Determine if the argument is shaped like a Promise
2521 */
2522 function isPromise(obj) {
2523 // allow any Promise/A+ compliant thenable.
2524 // It's up to the caller to ensure that obj.then conforms to the spec
2525 return !!obj && typeof obj.then === 'function';
2526 }
2527 class Version {
2528 constructor(full) {
2529 this.full = full;
2530 const splits = full.split('.');
2531 this.major = splits[0];
2532 this.minor = splits[1];
2533 this.patch = splits.slice(2).join('.');
2534 }
2535 }
2536 const __window = typeof window !== 'undefined' && window;
2537 const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
2538 self instanceof WorkerGlobalScope && self;
2539 const __global = typeof global !== 'undefined' && global;
2540 // Check __global first, because in Node tests both __global and __window may be defined and _global
2541 // should be __global in that case.
2542 const _global = __global || __window || __self;
2543 function newArray(size, value) {
2544 const list = [];
2545 for (let i = 0; i < size; i++) {
2546 list.push(value);
2547 }
2548 return list;
2549 }
2550 /**
2551 * Partitions a given array into 2 arrays, based on a boolean value returned by the condition
2552 * function.
2553 *
2554 * @param arr Input array that should be partitioned
2555 * @param conditionFn Condition function that is called for each item in a given array and returns a
2556 * boolean value.
2557 */
2558 function partitionArray(arr, conditionFn) {
2559 const truthy = [];
2560 const falsy = [];
2561 for (const item of arr) {
2562 (conditionFn(item) ? truthy : falsy).push(item);
2563 }
2564 return [truthy, falsy];
2565 }
2566
2567 /**
2568 * @license
2569 * Copyright Google LLC All Rights Reserved.
2570 *
2571 * Use of this source code is governed by an MIT-style license that can be
2572 * found in the LICENSE file at https://angular.io/license
2573 */
2574 // group 0: "[prop] or (event) or @trigger"
2575 // group 1: "prop" from "[prop]"
2576 // group 2: "event" from "(event)"
2577 // group 3: "@trigger" from "@trigger"
2578 const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/;
2579 function sanitizeIdentifier(name) {
2580 return name.replace(/\W/g, '_');
2581 }
2582 let _anonymousTypeIndex = 0;
2583 function identifierName(compileIdentifier) {
2584 if (!compileIdentifier || !compileIdentifier.reference) {
2585 return null;
2586 }
2587 const ref = compileIdentifier.reference;
2588 if (ref instanceof StaticSymbol) {
2589 return ref.name;
2590 }
2591 if (ref['__anonymousType']) {
2592 return ref['__anonymousType'];
2593 }
2594 let identifier = stringify(ref);
2595 if (identifier.indexOf('(') >= 0) {
2596 // case: anonymous functions!
2597 identifier = `anonymous_${_anonymousTypeIndex++}`;
2598 ref['__anonymousType'] = identifier;
2599 }
2600 else {
2601 identifier = sanitizeIdentifier(identifier);
2602 }
2603 return identifier;
2604 }
2605 function viewClassName(compType, embeddedTemplateIndex) {
2606 return `View_${identifierName({ reference: compType })}_${embeddedTemplateIndex}`;
2607 }
2608 function rendererTypeName(compType) {
2609 return `RenderType_${identifierName({ reference: compType })}`;
2610 }
2611 function hostViewClassName(compType) {
2612 return `HostView_${identifierName({ reference: compType })}`;
2613 }
2614 function componentFactoryName(compType) {
2615 return `${identifierName({ reference: compType })}NgFactory`;
2616 }
2617 var CompileSummaryKind;
2618 (function (CompileSummaryKind) {
2619 CompileSummaryKind[CompileSummaryKind["Pipe"] = 0] = "Pipe";
2620 CompileSummaryKind[CompileSummaryKind["Directive"] = 1] = "Directive";
2621 CompileSummaryKind[CompileSummaryKind["NgModule"] = 2] = "NgModule";
2622 CompileSummaryKind[CompileSummaryKind["Injectable"] = 3] = "Injectable";
2623 })(CompileSummaryKind || (CompileSummaryKind = {}));
2624 function tokenName(token) {
2625 return token.value != null ? sanitizeIdentifier(token.value) : identifierName(token.identifier);
2626 }
2627 function tokenReference(token) {
2628 if (token.identifier != null) {
2629 return token.identifier.reference;
2630 }
2631 else {
2632 return token.value;
2633 }
2634 }
2635 /**
2636 * Metadata about a stylesheet
2637 */
2638 class CompileStylesheetMetadata {
2639 constructor({ moduleUrl, styles, styleUrls } = {}) {
2640 this.moduleUrl = moduleUrl || null;
2641 this.styles = _normalizeArray(styles);
2642 this.styleUrls = _normalizeArray(styleUrls);
2643 }
2644 }
2645 /**
2646 * Metadata regarding compilation of a template.
2647 */
2648 class CompileTemplateMetadata {
2649 constructor({ encapsulation, template, templateUrl, htmlAst, styles, styleUrls, externalStylesheets, animations, ngContentSelectors, interpolation, isInline, preserveWhitespaces }) {
2650 this.encapsulation = encapsulation;
2651 this.template = template;
2652 this.templateUrl = templateUrl;
2653 this.htmlAst = htmlAst;
2654 this.styles = _normalizeArray(styles);
2655 this.styleUrls = _normalizeArray(styleUrls);
2656 this.externalStylesheets = _normalizeArray(externalStylesheets);
2657 this.animations = animations ? flatten(animations) : [];
2658 this.ngContentSelectors = ngContentSelectors || [];
2659 if (interpolation && interpolation.length != 2) {
2660 throw new Error(`'interpolation' should have a start and an end symbol.`);
2661 }
2662 this.interpolation = interpolation;
2663 this.isInline = isInline;
2664 this.preserveWhitespaces = preserveWhitespaces;
2665 }
2666 toSummary() {
2667 return {
2668 ngContentSelectors: this.ngContentSelectors,
2669 encapsulation: this.encapsulation,
2670 styles: this.styles,
2671 animations: this.animations
2672 };
2673 }
2674 }
2675 /**
2676 * Metadata regarding compilation of a directive.
2677 */
2678 class CompileDirectiveMetadata {
2679 constructor({ isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, hostListeners, hostProperties, hostAttributes, providers, viewProviders, queries, guards, viewQueries, entryComponents, template, componentViewType, rendererType, componentFactory }) {
2680 this.isHost = !!isHost;
2681 this.type = type;
2682 this.isComponent = isComponent;
2683 this.selector = selector;
2684 this.exportAs = exportAs;
2685 this.changeDetection = changeDetection;
2686 this.inputs = inputs;
2687 this.outputs = outputs;
2688 this.hostListeners = hostListeners;
2689 this.hostProperties = hostProperties;
2690 this.hostAttributes = hostAttributes;
2691 this.providers = _normalizeArray(providers);
2692 this.viewProviders = _normalizeArray(viewProviders);
2693 this.queries = _normalizeArray(queries);
2694 this.guards = guards;
2695 this.viewQueries = _normalizeArray(viewQueries);
2696 this.entryComponents = _normalizeArray(entryComponents);
2697 this.template = template;
2698 this.componentViewType = componentViewType;
2699 this.rendererType = rendererType;
2700 this.componentFactory = componentFactory;
2701 }
2702 static create({ isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host, providers, viewProviders, queries, guards, viewQueries, entryComponents, template, componentViewType, rendererType, componentFactory }) {
2703 const hostListeners = {};
2704 const hostProperties = {};
2705 const hostAttributes = {};
2706 if (host != null) {
2707 Object.keys(host).forEach(key => {
2708 const value = host[key];
2709 const matches = key.match(HOST_REG_EXP);
2710 if (matches === null) {
2711 hostAttributes[key] = value;
2712 }
2713 else if (matches[1] != null) {
2714 hostProperties[matches[1]] = value;
2715 }
2716 else if (matches[2] != null) {
2717 hostListeners[matches[2]] = value;
2718 }
2719 });
2720 }
2721 const inputsMap = {};
2722 if (inputs != null) {
2723 inputs.forEach((bindConfig) => {
2724 // canonical syntax: `dirProp: elProp`
2725 // if there is no `:`, use dirProp = elProp
2726 const parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
2727 inputsMap[parts[0]] = parts[1];
2728 });
2729 }
2730 const outputsMap = {};
2731 if (outputs != null) {
2732 outputs.forEach((bindConfig) => {
2733 // canonical syntax: `dirProp: elProp`
2734 // if there is no `:`, use dirProp = elProp
2735 const parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
2736 outputsMap[parts[0]] = parts[1];
2737 });
2738 }
2739 return new CompileDirectiveMetadata({
2740 isHost,
2741 type,
2742 isComponent: !!isComponent,
2743 selector,
2744 exportAs,
2745 changeDetection,
2746 inputs: inputsMap,
2747 outputs: outputsMap,
2748 hostListeners,
2749 hostProperties,
2750 hostAttributes,
2751 providers,
2752 viewProviders,
2753 queries,
2754 guards,
2755 viewQueries,
2756 entryComponents,
2757 template,
2758 componentViewType,
2759 rendererType,
2760 componentFactory,
2761 });
2762 }
2763 toSummary() {
2764 return {
2765 summaryKind: CompileSummaryKind.Directive,
2766 type: this.type,
2767 isComponent: this.isComponent,
2768 selector: this.selector,
2769 exportAs: this.exportAs,
2770 inputs: this.inputs,
2771 outputs: this.outputs,
2772 hostListeners: this.hostListeners,
2773 hostProperties: this.hostProperties,
2774 hostAttributes: this.hostAttributes,
2775 providers: this.providers,
2776 viewProviders: this.viewProviders,
2777 queries: this.queries,
2778 guards: this.guards,
2779 viewQueries: this.viewQueries,
2780 entryComponents: this.entryComponents,
2781 changeDetection: this.changeDetection,
2782 template: this.template && this.template.toSummary(),
2783 componentViewType: this.componentViewType,
2784 rendererType: this.rendererType,
2785 componentFactory: this.componentFactory
2786 };
2787 }
2788 }
2789 class CompilePipeMetadata {
2790 constructor({ type, name, pure }) {
2791 this.type = type;
2792 this.name = name;
2793 this.pure = !!pure;
2794 }
2795 toSummary() {
2796 return {
2797 summaryKind: CompileSummaryKind.Pipe,
2798 type: this.type,
2799 name: this.name,
2800 pure: this.pure
2801 };
2802 }
2803 }
2804 /**
2805 * Metadata regarding compilation of a module.
2806 */
2807 class CompileNgModuleMetadata {
2808 constructor({ type, providers, declaredDirectives, exportedDirectives, declaredPipes, exportedPipes, entryComponents, bootstrapComponents, importedModules, exportedModules, schemas, transitiveModule, id }) {
2809 this.type = type || null;
2810 this.declaredDirectives = _normalizeArray(declaredDirectives);
2811 this.exportedDirectives = _normalizeArray(exportedDirectives);
2812 this.declaredPipes = _normalizeArray(declaredPipes);
2813 this.exportedPipes = _normalizeArray(exportedPipes);
2814 this.providers = _normalizeArray(providers);
2815 this.entryComponents = _normalizeArray(entryComponents);
2816 this.bootstrapComponents = _normalizeArray(bootstrapComponents);
2817 this.importedModules = _normalizeArray(importedModules);
2818 this.exportedModules = _normalizeArray(exportedModules);
2819 this.schemas = _normalizeArray(schemas);
2820 this.id = id || null;
2821 this.transitiveModule = transitiveModule || null;
2822 }
2823 toSummary() {
2824 const module = this.transitiveModule;
2825 return {
2826 summaryKind: CompileSummaryKind.NgModule,
2827 type: this.type,
2828 entryComponents: module.entryComponents,
2829 providers: module.providers,
2830 modules: module.modules,
2831 exportedDirectives: module.exportedDirectives,
2832 exportedPipes: module.exportedPipes
2833 };
2834 }
2835 }
2836 class TransitiveCompileNgModuleMetadata {
2837 constructor() {
2838 this.directivesSet = new Set();
2839 this.directives = [];
2840 this.exportedDirectivesSet = new Set();
2841 this.exportedDirectives = [];
2842 this.pipesSet = new Set();
2843 this.pipes = [];
2844 this.exportedPipesSet = new Set();
2845 this.exportedPipes = [];
2846 this.modulesSet = new Set();
2847 this.modules = [];
2848 this.entryComponentsSet = new Set();
2849 this.entryComponents = [];
2850 this.providers = [];
2851 }
2852 addProvider(provider, module) {
2853 this.providers.push({ provider: provider, module: module });
2854 }
2855 addDirective(id) {
2856 if (!this.directivesSet.has(id.reference)) {
2857 this.directivesSet.add(id.reference);
2858 this.directives.push(id);
2859 }
2860 }
2861 addExportedDirective(id) {
2862 if (!this.exportedDirectivesSet.has(id.reference)) {
2863 this.exportedDirectivesSet.add(id.reference);
2864 this.exportedDirectives.push(id);
2865 }
2866 }
2867 addPipe(id) {
2868 if (!this.pipesSet.has(id.reference)) {
2869 this.pipesSet.add(id.reference);
2870 this.pipes.push(id);
2871 }
2872 }
2873 addExportedPipe(id) {
2874 if (!this.exportedPipesSet.has(id.reference)) {
2875 this.exportedPipesSet.add(id.reference);
2876 this.exportedPipes.push(id);
2877 }
2878 }
2879 addModule(id) {
2880 if (!this.modulesSet.has(id.reference)) {
2881 this.modulesSet.add(id.reference);
2882 this.modules.push(id);
2883 }
2884 }
2885 addEntryComponent(ec) {
2886 if (!this.entryComponentsSet.has(ec.componentType)) {
2887 this.entryComponentsSet.add(ec.componentType);
2888 this.entryComponents.push(ec);
2889 }
2890 }
2891 }
2892 function _normalizeArray(obj) {
2893 return obj || [];
2894 }
2895 class ProviderMeta {
2896 constructor(token, { useClass, useValue, useExisting, useFactory, deps, multi }) {
2897 this.token = token;
2898 this.useClass = useClass || null;
2899 this.useValue = useValue;
2900 this.useExisting = useExisting;
2901 this.useFactory = useFactory || null;
2902 this.dependencies = deps || null;
2903 this.multi = !!multi;
2904 }
2905 }
2906 function flatten(list) {
2907 return list.reduce((flat, item) => {
2908 const flatItem = Array.isArray(item) ? flatten(item) : item;
2909 return flat.concat(flatItem);
2910 }, []);
2911 }
2912 function jitSourceUrl(url) {
2913 // Note: We need 3 "/" so that ng shows up as a separate domain
2914 // in the chrome dev tools.
2915 return url.replace(/(\w+:\/\/[\w:-]+)?(\/+)?/, 'ng:///');
2916 }
2917 function templateSourceUrl(ngModuleType, compMeta, templateMeta) {
2918 let url;
2919 if (templateMeta.isInline) {
2920 if (compMeta.type.reference instanceof StaticSymbol) {
2921 // Note: a .ts file might contain multiple components with inline templates,
2922 // so we need to give them unique urls, as these will be used for sourcemaps.
2923 url = `${compMeta.type.reference.filePath}.${compMeta.type.reference.name}.html`;
2924 }
2925 else {
2926 url = `${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.html`;
2927 }
2928 }
2929 else {
2930 url = templateMeta.templateUrl;
2931 }
2932 return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url);
2933 }
2934
2935 /**
2936 * @license
2937 * Copyright Google LLC All Rights Reserved.
2938 *
2939 * Use of this source code is governed by an MIT-style license that can be
2940 * found in the LICENSE file at https://angular.io/license
2941 */
2942 const CORE$1 = '@angular/core';
2943 class Identifiers$1 {
2944 }
2945 /* Methods */
2946 Identifiers$1.NEW_METHOD = 'factory';
2947 Identifiers$1.TRANSFORM_METHOD = 'transform';
2948 Identifiers$1.PATCH_DEPS = 'patchedDeps';
2949 Identifiers$1.core = { name: null, moduleName: CORE$1 };
2950 /* Instructions */
2951 Identifiers$1.namespaceHTML = { name: 'ɵɵnamespaceHTML', moduleName: CORE$1 };
2952 Identifiers$1.namespaceMathML = { name: 'ɵɵnamespaceMathML', moduleName: CORE$1 };
2953 Identifiers$1.namespaceSVG = { name: 'ɵɵnamespaceSVG', moduleName: CORE$1 };
2954 Identifiers$1.element = { name: 'ɵɵelement', moduleName: CORE$1 };
2955 Identifiers$1.elementStart = { name: 'ɵɵelementStart', moduleName: CORE$1 };
2956 Identifiers$1.elementEnd = { name: 'ɵɵelementEnd', moduleName: CORE$1 };
2957 Identifiers$1.advance = { name: 'ɵɵadvance', moduleName: CORE$1 };
2958 Identifiers$1.syntheticHostProperty = { name: 'ɵɵsyntheticHostProperty', moduleName: CORE$1 };
2959 Identifiers$1.syntheticHostListener = { name: 'ɵɵsyntheticHostListener', moduleName: CORE$1 };
2960 Identifiers$1.attribute = { name: 'ɵɵattribute', moduleName: CORE$1 };
2961 Identifiers$1.attributeInterpolate1 = { name: 'ɵɵattributeInterpolate1', moduleName: CORE$1 };
2962 Identifiers$1.attributeInterpolate2 = { name: 'ɵɵattributeInterpolate2', moduleName: CORE$1 };
2963 Identifiers$1.attributeInterpolate3 = { name: 'ɵɵattributeInterpolate3', moduleName: CORE$1 };
2964 Identifiers$1.attributeInterpolate4 = { name: 'ɵɵattributeInterpolate4', moduleName: CORE$1 };
2965 Identifiers$1.attributeInterpolate5 = { name: 'ɵɵattributeInterpolate5', moduleName: CORE$1 };
2966 Identifiers$1.attributeInterpolate6 = { name: 'ɵɵattributeInterpolate6', moduleName: CORE$1 };
2967 Identifiers$1.attributeInterpolate7 = { name: 'ɵɵattributeInterpolate7', moduleName: CORE$1 };
2968 Identifiers$1.attributeInterpolate8 = { name: 'ɵɵattributeInterpolate8', moduleName: CORE$1 };
2969 Identifiers$1.attributeInterpolateV = { name: 'ɵɵattributeInterpolateV', moduleName: CORE$1 };
2970 Identifiers$1.classProp = { name: 'ɵɵclassProp', moduleName: CORE$1 };
2971 Identifiers$1.elementContainerStart = { name: 'ɵɵelementContainerStart', moduleName: CORE$1 };
2972 Identifiers$1.elementContainerEnd = { name: 'ɵɵelementContainerEnd', moduleName: CORE$1 };
2973 Identifiers$1.elementContainer = { name: 'ɵɵelementContainer', moduleName: CORE$1 };
2974 Identifiers$1.styleMap = { name: 'ɵɵstyleMap', moduleName: CORE$1 };
2975 Identifiers$1.styleMapInterpolate1 = { name: 'ɵɵstyleMapInterpolate1', moduleName: CORE$1 };
2976 Identifiers$1.styleMapInterpolate2 = { name: 'ɵɵstyleMapInterpolate2', moduleName: CORE$1 };
2977 Identifiers$1.styleMapInterpolate3 = { name: 'ɵɵstyleMapInterpolate3', moduleName: CORE$1 };
2978 Identifiers$1.styleMapInterpolate4 = { name: 'ɵɵstyleMapInterpolate4', moduleName: CORE$1 };
2979 Identifiers$1.styleMapInterpolate5 = { name: 'ɵɵstyleMapInterpolate5', moduleName: CORE$1 };
2980 Identifiers$1.styleMapInterpolate6 = { name: 'ɵɵstyleMapInterpolate6', moduleName: CORE$1 };
2981 Identifiers$1.styleMapInterpolate7 = { name: 'ɵɵstyleMapInterpolate7', moduleName: CORE$1 };
2982 Identifiers$1.styleMapInterpolate8 = { name: 'ɵɵstyleMapInterpolate8', moduleName: CORE$1 };
2983 Identifiers$1.styleMapInterpolateV = { name: 'ɵɵstyleMapInterpolateV', moduleName: CORE$1 };
2984 Identifiers$1.classMap = { name: 'ɵɵclassMap', moduleName: CORE$1 };
2985 Identifiers$1.classMapInterpolate1 = { name: 'ɵɵclassMapInterpolate1', moduleName: CORE$1 };
2986 Identifiers$1.classMapInterpolate2 = { name: 'ɵɵclassMapInterpolate2', moduleName: CORE$1 };
2987 Identifiers$1.classMapInterpolate3 = { name: 'ɵɵclassMapInterpolate3', moduleName: CORE$1 };
2988 Identifiers$1.classMapInterpolate4 = { name: 'ɵɵclassMapInterpolate4', moduleName: CORE$1 };
2989 Identifiers$1.classMapInterpolate5 = { name: 'ɵɵclassMapInterpolate5', moduleName: CORE$1 };
2990 Identifiers$1.classMapInterpolate6 = { name: 'ɵɵclassMapInterpolate6', moduleName: CORE$1 };
2991 Identifiers$1.classMapInterpolate7 = { name: 'ɵɵclassMapInterpolate7', moduleName: CORE$1 };
2992 Identifiers$1.classMapInterpolate8 = { name: 'ɵɵclassMapInterpolate8', moduleName: CORE$1 };
2993 Identifiers$1.classMapInterpolateV = { name: 'ɵɵclassMapInterpolateV', moduleName: CORE$1 };
2994 Identifiers$1.styleProp = { name: 'ɵɵstyleProp', moduleName: CORE$1 };
2995 Identifiers$1.stylePropInterpolate1 = { name: 'ɵɵstylePropInterpolate1', moduleName: CORE$1 };
2996 Identifiers$1.stylePropInterpolate2 = { name: 'ɵɵstylePropInterpolate2', moduleName: CORE$1 };
2997 Identifiers$1.stylePropInterpolate3 = { name: 'ɵɵstylePropInterpolate3', moduleName: CORE$1 };
2998 Identifiers$1.stylePropInterpolate4 = { name: 'ɵɵstylePropInterpolate4', moduleName: CORE$1 };
2999 Identifiers$1.stylePropInterpolate5 = { name: 'ɵɵstylePropInterpolate5', moduleName: CORE$1 };
3000 Identifiers$1.stylePropInterpolate6 = { name: 'ɵɵstylePropInterpolate6', moduleName: CORE$1 };
3001 Identifiers$1.stylePropInterpolate7 = { name: 'ɵɵstylePropInterpolate7', moduleName: CORE$1 };
3002 Identifiers$1.stylePropInterpolate8 = { name: 'ɵɵstylePropInterpolate8', moduleName: CORE$1 };
3003 Identifiers$1.stylePropInterpolateV = { name: 'ɵɵstylePropInterpolateV', moduleName: CORE$1 };
3004 Identifiers$1.nextContext = { name: 'ɵɵnextContext', moduleName: CORE$1 };
3005 Identifiers$1.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE$1 };
3006 Identifiers$1.text = { name: 'ɵɵtext', moduleName: CORE$1 };
3007 Identifiers$1.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE$1 };
3008 Identifiers$1.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE$1 };
3009 Identifiers$1.getCurrentView = { name: 'ɵɵgetCurrentView', moduleName: CORE$1 };
3010 Identifiers$1.textInterpolate = { name: 'ɵɵtextInterpolate', moduleName: CORE$1 };
3011 Identifiers$1.textInterpolate1 = { name: 'ɵɵtextInterpolate1', moduleName: CORE$1 };
3012 Identifiers$1.textInterpolate2 = { name: 'ɵɵtextInterpolate2', moduleName: CORE$1 };
3013 Identifiers$1.textInterpolate3 = { name: 'ɵɵtextInterpolate3', moduleName: CORE$1 };
3014 Identifiers$1.textInterpolate4 = { name: 'ɵɵtextInterpolate4', moduleName: CORE$1 };
3015 Identifiers$1.textInterpolate5 = { name: 'ɵɵtextInterpolate5', moduleName: CORE$1 };
3016 Identifiers$1.textInterpolate6 = { name: 'ɵɵtextInterpolate6', moduleName: CORE$1 };
3017 Identifiers$1.textInterpolate7 = { name: 'ɵɵtextInterpolate7', moduleName: CORE$1 };
3018 Identifiers$1.textInterpolate8 = { name: 'ɵɵtextInterpolate8', moduleName: CORE$1 };
3019 Identifiers$1.textInterpolateV = { name: 'ɵɵtextInterpolateV', moduleName: CORE$1 };
3020 Identifiers$1.restoreView = { name: 'ɵɵrestoreView', moduleName: CORE$1 };
3021 Identifiers$1.pureFunction0 = { name: 'ɵɵpureFunction0', moduleName: CORE$1 };
3022 Identifiers$1.pureFunction1 = { name: 'ɵɵpureFunction1', moduleName: CORE$1 };
3023 Identifiers$1.pureFunction2 = { name: 'ɵɵpureFunction2', moduleName: CORE$1 };
3024 Identifiers$1.pureFunction3 = { name: 'ɵɵpureFunction3', moduleName: CORE$1 };
3025 Identifiers$1.pureFunction4 = { name: 'ɵɵpureFunction4', moduleName: CORE$1 };
3026 Identifiers$1.pureFunction5 = { name: 'ɵɵpureFunction5', moduleName: CORE$1 };
3027 Identifiers$1.pureFunction6 = { name: 'ɵɵpureFunction6', moduleName: CORE$1 };
3028 Identifiers$1.pureFunction7 = { name: 'ɵɵpureFunction7', moduleName: CORE$1 };
3029 Identifiers$1.pureFunction8 = { name: 'ɵɵpureFunction8', moduleName: CORE$1 };
3030 Identifiers$1.pureFunctionV = { name: 'ɵɵpureFunctionV', moduleName: CORE$1 };
3031 Identifiers$1.pipeBind1 = { name: 'ɵɵpipeBind1', moduleName: CORE$1 };
3032 Identifiers$1.pipeBind2 = { name: 'ɵɵpipeBind2', moduleName: CORE$1 };
3033 Identifiers$1.pipeBind3 = { name: 'ɵɵpipeBind3', moduleName: CORE$1 };
3034 Identifiers$1.pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE$1 };
3035 Identifiers$1.pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE$1 };
3036 Identifiers$1.hostProperty = { name: 'ɵɵhostProperty', moduleName: CORE$1 };
3037 Identifiers$1.property = { name: 'ɵɵproperty', moduleName: CORE$1 };
3038 Identifiers$1.propertyInterpolate = { name: 'ɵɵpropertyInterpolate', moduleName: CORE$1 };
3039 Identifiers$1.propertyInterpolate1 = { name: 'ɵɵpropertyInterpolate1', moduleName: CORE$1 };
3040 Identifiers$1.propertyInterpolate2 = { name: 'ɵɵpropertyInterpolate2', moduleName: CORE$1 };
3041 Identifiers$1.propertyInterpolate3 = { name: 'ɵɵpropertyInterpolate3', moduleName: CORE$1 };
3042 Identifiers$1.propertyInterpolate4 = { name: 'ɵɵpropertyInterpolate4', moduleName: CORE$1 };
3043 Identifiers$1.propertyInterpolate5 = { name: 'ɵɵpropertyInterpolate5', moduleName: CORE$1 };
3044 Identifiers$1.propertyInterpolate6 = { name: 'ɵɵpropertyInterpolate6', moduleName: CORE$1 };
3045 Identifiers$1.propertyInterpolate7 = { name: 'ɵɵpropertyInterpolate7', moduleName: CORE$1 };
3046 Identifiers$1.propertyInterpolate8 = { name: 'ɵɵpropertyInterpolate8', moduleName: CORE$1 };
3047 Identifiers$1.propertyInterpolateV = { name: 'ɵɵpropertyInterpolateV', moduleName: CORE$1 };
3048 Identifiers$1.i18n = { name: 'ɵɵi18n', moduleName: CORE$1 };
3049 Identifiers$1.i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE$1 };
3050 Identifiers$1.i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE$1 };
3051 Identifiers$1.i18nStart = { name: 'ɵɵi18nStart', moduleName: CORE$1 };
3052 Identifiers$1.i18nEnd = { name: 'ɵɵi18nEnd', moduleName: CORE$1 };
3053 Identifiers$1.i18nApply = { name: 'ɵɵi18nApply', moduleName: CORE$1 };
3054 Identifiers$1.i18nPostprocess = { name: 'ɵɵi18nPostprocess', moduleName: CORE$1 };
3055 Identifiers$1.pipe = { name: 'ɵɵpipe', moduleName: CORE$1 };
3056 Identifiers$1.projection = { name: 'ɵɵprojection', moduleName: CORE$1 };
3057 Identifiers$1.projectionDef = { name: 'ɵɵprojectionDef', moduleName: CORE$1 };
3058 Identifiers$1.reference = { name: 'ɵɵreference', moduleName: CORE$1 };
3059 Identifiers$1.inject = { name: 'ɵɵinject', moduleName: CORE$1 };
3060 Identifiers$1.injectAttribute = { name: 'ɵɵinjectAttribute', moduleName: CORE$1 };
3061 Identifiers$1.injectPipeChangeDetectorRef = { name: 'ɵɵinjectPipeChangeDetectorRef', moduleName: CORE$1 };
3062 Identifiers$1.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE$1 };
3063 Identifiers$1.invalidFactory = { name: 'ɵɵinvalidFactory', moduleName: CORE$1 };
3064 Identifiers$1.invalidFactoryDep = { name: 'ɵɵinvalidFactoryDep', moduleName: CORE$1 };
3065 Identifiers$1.templateRefExtractor = { name: 'ɵɵtemplateRefExtractor', moduleName: CORE$1 };
3066 Identifiers$1.forwardRef = { name: 'forwardRef', moduleName: CORE$1 };
3067 Identifiers$1.resolveForwardRef = { name: 'resolveForwardRef', moduleName: CORE$1 };
3068 Identifiers$1.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE$1 };
3069 Identifiers$1.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE$1 };
3070 Identifiers$1.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE$1 };
3071 Identifiers$1.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE$1 };
3072 Identifiers$1.declareComponent = { name: 'ɵɵngDeclareComponent', moduleName: CORE$1 };
3073 Identifiers$1.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE$1 };
3074 Identifiers$1.ChangeDetectionStrategy = {
3075 name: 'ChangeDetectionStrategy',
3076 moduleName: CORE$1,
3077 };
3078 Identifiers$1.ViewEncapsulation = {
3079 name: 'ViewEncapsulation',
3080 moduleName: CORE$1,
3081 };
3082 Identifiers$1.ComponentDefWithMeta = {
3083 name: 'ɵɵComponentDefWithMeta',
3084 moduleName: CORE$1,
3085 };
3086 Identifiers$1.FactoryDef = {
3087 name: 'ɵɵFactoryDef',
3088 moduleName: CORE$1,
3089 };
3090 Identifiers$1.defineDirective = { name: 'ɵɵdefineDirective', moduleName: CORE$1 };
3091 Identifiers$1.declareDirective = { name: 'ɵɵngDeclareDirective', moduleName: CORE$1 };
3092 Identifiers$1.DirectiveDefWithMeta = {
3093 name: 'ɵɵDirectiveDefWithMeta',
3094 moduleName: CORE$1,
3095 };
3096 Identifiers$1.InjectorDef = {
3097 name: 'ɵɵInjectorDef',
3098 moduleName: CORE$1,
3099 };
3100 Identifiers$1.defineInjector = {
3101 name: 'ɵɵdefineInjector',
3102 moduleName: CORE$1,
3103 };
3104 Identifiers$1.NgModuleDefWithMeta = {
3105 name: 'ɵɵNgModuleDefWithMeta',
3106 moduleName: CORE$1,
3107 };
3108 Identifiers$1.ModuleWithProviders = {
3109 name: 'ModuleWithProviders',
3110 moduleName: CORE$1,
3111 };
3112 Identifiers$1.defineNgModule = { name: 'ɵɵdefineNgModule', moduleName: CORE$1 };
3113 Identifiers$1.setNgModuleScope = { name: 'ɵɵsetNgModuleScope', moduleName: CORE$1 };
3114 Identifiers$1.PipeDefWithMeta = { name: 'ɵɵPipeDefWithMeta', moduleName: CORE$1 };
3115 Identifiers$1.definePipe = { name: 'ɵɵdefinePipe', moduleName: CORE$1 };
3116 Identifiers$1.declarePipe = { name: 'ɵɵngDeclarePipe', moduleName: CORE$1 };
3117 Identifiers$1.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE$1 };
3118 Identifiers$1.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE$1 };
3119 Identifiers$1.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE$1 };
3120 Identifiers$1.contentQuery = { name: 'ɵɵcontentQuery', moduleName: CORE$1 };
3121 Identifiers$1.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE$1 };
3122 Identifiers$1.InheritDefinitionFeature = { name: 'ɵɵInheritDefinitionFeature', moduleName: CORE$1 };
3123 Identifiers$1.CopyDefinitionFeature = { name: 'ɵɵCopyDefinitionFeature', moduleName: CORE$1 };
3124 Identifiers$1.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE$1 };
3125 Identifiers$1.listener = { name: 'ɵɵlistener', moduleName: CORE$1 };
3126 Identifiers$1.getFactoryOf = {
3127 name: 'ɵɵgetFactoryOf',
3128 moduleName: CORE$1,
3129 };
3130 Identifiers$1.getInheritedFactory = {
3131 name: 'ɵɵgetInheritedFactory',
3132 moduleName: CORE$1,
3133 };
3134 // sanitization-related functions
3135 Identifiers$1.sanitizeHtml = { name: 'ɵɵsanitizeHtml', moduleName: CORE$1 };
3136 Identifiers$1.sanitizeStyle = { name: 'ɵɵsanitizeStyle', moduleName: CORE$1 };
3137 Identifiers$1.sanitizeResourceUrl = { name: 'ɵɵsanitizeResourceUrl', moduleName: CORE$1 };
3138 Identifiers$1.sanitizeScript = { name: 'ɵɵsanitizeScript', moduleName: CORE$1 };
3139 Identifiers$1.sanitizeUrl = { name: 'ɵɵsanitizeUrl', moduleName: CORE$1 };
3140 Identifiers$1.sanitizeUrlOrResourceUrl = { name: 'ɵɵsanitizeUrlOrResourceUrl', moduleName: CORE$1 };
3141 Identifiers$1.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE$1 };
3142 Identifiers$1.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE$1 };
3143
3144 /**
3145 * @license
3146 * Copyright Google LLC All Rights Reserved.
3147 *
3148 * Use of this source code is governed by an MIT-style license that can be
3149 * found in the LICENSE file at https://angular.io/license
3150 */
3151 // https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
3152 const VERSION = 3;
3153 const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,';
3154 class SourceMapGenerator {
3155 constructor(file = null) {
3156 this.file = file;
3157 this.sourcesContent = new Map();
3158 this.lines = [];
3159 this.lastCol0 = 0;
3160 this.hasMappings = false;
3161 }
3162 // The content is `null` when the content is expected to be loaded using the URL
3163 addSource(url, content = null) {
3164 if (!this.sourcesContent.has(url)) {
3165 this.sourcesContent.set(url, content);
3166 }
3167 return this;
3168 }
3169 addLine() {
3170 this.lines.push([]);
3171 this.lastCol0 = 0;
3172 return this;
3173 }
3174 addMapping(col0, sourceUrl, sourceLine0, sourceCol0) {
3175 if (!this.currentLine) {
3176 throw new Error(`A line must be added before mappings can be added`);
3177 }
3178 if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) {
3179 throw new Error(`Unknown source file "${sourceUrl}"`);
3180 }
3181 if (col0 == null) {
3182 throw new Error(`The column in the generated code must be provided`);
3183 }
3184 if (col0 < this.lastCol0) {
3185 throw new Error(`Mapping should be added in output order`);
3186 }
3187 if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) {
3188 throw new Error(`The source location must be provided when a source url is provided`);
3189 }
3190 this.hasMappings = true;
3191 this.lastCol0 = col0;
3192 this.currentLine.push({ col0, sourceUrl, sourceLine0, sourceCol0 });
3193 return this;
3194 }
3195 /**
3196 * @internal strip this from published d.ts files due to
3197 * https://github.com/microsoft/TypeScript/issues/36216
3198 */
3199 get currentLine() {
3200 return this.lines.slice(-1)[0];
3201 }
3202 toJSON() {
3203 if (!this.hasMappings) {
3204 return null;
3205 }
3206 const sourcesIndex = new Map();
3207 const sources = [];
3208 const sourcesContent = [];
3209 Array.from(this.sourcesContent.keys()).forEach((url, i) => {
3210 sourcesIndex.set(url, i);
3211 sources.push(url);
3212 sourcesContent.push(this.sourcesContent.get(url) || null);
3213 });
3214 let mappings = '';
3215 let lastCol0 = 0;
3216 let lastSourceIndex = 0;
3217 let lastSourceLine0 = 0;
3218 let lastSourceCol0 = 0;
3219 this.lines.forEach(segments => {
3220 lastCol0 = 0;
3221 mappings += segments
3222 .map(segment => {
3223 // zero-based starting column of the line in the generated code
3224 let segAsStr = toBase64VLQ(segment.col0 - lastCol0);
3225 lastCol0 = segment.col0;
3226 if (segment.sourceUrl != null) {
3227 // zero-based index into the “sources” list
3228 segAsStr +=
3229 toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex);
3230 lastSourceIndex = sourcesIndex.get(segment.sourceUrl);
3231 // the zero-based starting line in the original source
3232 segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0);
3233 lastSourceLine0 = segment.sourceLine0;
3234 // the zero-based starting column in the original source
3235 segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0);
3236 lastSourceCol0 = segment.sourceCol0;
3237 }
3238 return segAsStr;
3239 })
3240 .join(',');
3241 mappings += ';';
3242 });
3243 mappings = mappings.slice(0, -1);
3244 return {
3245 'file': this.file || '',
3246 'version': VERSION,
3247 'sourceRoot': '',
3248 'sources': sources,
3249 'sourcesContent': sourcesContent,
3250 'mappings': mappings,
3251 };
3252 }
3253 toJsComment() {
3254 return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) :
3255 '';
3256 }
3257 }
3258 function toBase64String(value) {
3259 let b64 = '';
3260 const encoded = utf8Encode(value);
3261 for (let i = 0; i < encoded.length;) {
3262 const i1 = encoded[i++];
3263 const i2 = i < encoded.length ? encoded[i++] : null;
3264 const i3 = i < encoded.length ? encoded[i++] : null;
3265 b64 += toBase64Digit(i1 >> 2);
3266 b64 += toBase64Digit(((i1 & 3) << 4) | (i2 === null ? 0 : i2 >> 4));
3267 b64 += i2 === null ? '=' : toBase64Digit(((i2 & 15) << 2) | (i3 === null ? 0 : i3 >> 6));
3268 b64 += i2 === null || i3 === null ? '=' : toBase64Digit(i3 & 63);
3269 }
3270 return b64;
3271 }
3272 function toBase64VLQ(value) {
3273 value = value < 0 ? ((-value) << 1) + 1 : value << 1;
3274 let out = '';
3275 do {
3276 let digit = value & 31;
3277 value = value >> 5;
3278 if (value > 0) {
3279 digit = digit | 32;
3280 }
3281 out += toBase64Digit(digit);
3282 } while (value > 0);
3283 return out;
3284 }
3285 const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
3286 function toBase64Digit(value) {
3287 if (value < 0 || value >= 64) {
3288 throw new Error(`Can only encode value in the range [0, 63]`);
3289 }
3290 return B64_DIGITS[value];
3291 }
3292
3293 /**
3294 * @license
3295 * Copyright Google LLC All Rights Reserved.
3296 *
3297 * Use of this source code is governed by an MIT-style license that can be
3298 * found in the LICENSE file at https://angular.io/license
3299 */
3300 const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
3301 const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
3302 const _INDENT_WITH = ' ';
3303 const CATCH_ERROR_VAR$1 = variable('error', null, null);
3304 const CATCH_STACK_VAR$1 = variable('stack', null, null);
3305 class _EmittedLine {
3306 constructor(indent) {
3307 this.indent = indent;
3308 this.partsLength = 0;
3309 this.parts = [];
3310 this.srcSpans = [];
3311 }
3312 }
3313 class EmitterVisitorContext {
3314 constructor(_indent) {
3315 this._indent = _indent;
3316 this._classes = [];
3317 this._preambleLineCount = 0;
3318 this._lines = [new _EmittedLine(_indent)];
3319 }
3320 static createRoot() {
3321 return new EmitterVisitorContext(0);
3322 }
3323 /**
3324 * @internal strip this from published d.ts files due to
3325 * https://github.com/microsoft/TypeScript/issues/36216
3326 */
3327 get _currentLine() {
3328 return this._lines[this._lines.length - 1];
3329 }
3330 println(from, lastPart = '') {
3331 this.print(from || null, lastPart, true);
3332 }
3333 lineIsEmpty() {
3334 return this._currentLine.parts.length === 0;
3335 }
3336 lineLength() {
3337 return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength;
3338 }
3339 print(from, part, newLine = false) {
3340 if (part.length > 0) {
3341 this._currentLine.parts.push(part);
3342 this._currentLine.partsLength += part.length;
3343 this._currentLine.srcSpans.push(from && from.sourceSpan || null);
3344 }
3345 if (newLine) {
3346 this._lines.push(new _EmittedLine(this._indent));
3347 }
3348 }
3349 removeEmptyLastLine() {
3350 if (this.lineIsEmpty()) {
3351 this._lines.pop();
3352 }
3353 }
3354 incIndent() {
3355 this._indent++;
3356 if (this.lineIsEmpty()) {
3357 this._currentLine.indent = this._indent;
3358 }
3359 }
3360 decIndent() {
3361 this._indent--;
3362 if (this.lineIsEmpty()) {
3363 this._currentLine.indent = this._indent;
3364 }
3365 }
3366 pushClass(clazz) {
3367 this._classes.push(clazz);
3368 }
3369 popClass() {
3370 return this._classes.pop();
3371 }
3372 get currentClass() {
3373 return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null;
3374 }
3375 toSource() {
3376 return this.sourceLines
3377 .map(l => l.parts.length > 0 ? _createIndent(l.indent) + l.parts.join('') : '')
3378 .join('\n');
3379 }
3380 toSourceMapGenerator(genFilePath, startsAtLine = 0) {
3381 const map = new SourceMapGenerator(genFilePath);
3382 let firstOffsetMapped = false;
3383 const mapFirstOffsetIfNeeded = () => {
3384 if (!firstOffsetMapped) {
3385 // Add a single space so that tools won't try to load the file from disk.
3386 // Note: We are using virtual urls like `ng:///`, so we have to
3387 // provide a content here.
3388 map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0);
3389 firstOffsetMapped = true;
3390 }
3391 };
3392 for (let i = 0; i < startsAtLine; i++) {
3393 map.addLine();
3394 mapFirstOffsetIfNeeded();
3395 }
3396 this.sourceLines.forEach((line, lineIdx) => {
3397 map.addLine();
3398 const spans = line.srcSpans;
3399 const parts = line.parts;
3400 let col0 = line.indent * _INDENT_WITH.length;
3401 let spanIdx = 0;
3402 // skip leading parts without source spans
3403 while (spanIdx < spans.length && !spans[spanIdx]) {
3404 col0 += parts[spanIdx].length;
3405 spanIdx++;
3406 }
3407 if (spanIdx < spans.length && lineIdx === 0 && col0 === 0) {
3408 firstOffsetMapped = true;
3409 }
3410 else {
3411 mapFirstOffsetIfNeeded();
3412 }
3413 while (spanIdx < spans.length) {
3414 const span = spans[spanIdx];
3415 const source = span.start.file;
3416 const sourceLine = span.start.line;
3417 const sourceCol = span.start.col;
3418 map.addSource(source.url, source.content)
3419 .addMapping(col0, source.url, sourceLine, sourceCol);
3420 col0 += parts[spanIdx].length;
3421 spanIdx++;
3422 // assign parts without span or the same span to the previous segment
3423 while (spanIdx < spans.length && (span === spans[spanIdx] || !spans[spanIdx])) {
3424 col0 += parts[spanIdx].length;
3425 spanIdx++;
3426 }
3427 }
3428 });
3429 return map;
3430 }
3431 setPreambleLineCount(count) {
3432 return this._preambleLineCount = count;
3433 }
3434 spanOf(line, column) {
3435 const emittedLine = this._lines[line - this._preambleLineCount];
3436 if (emittedLine) {
3437 let columnsLeft = column - _createIndent(emittedLine.indent).length;
3438 for (let partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) {
3439 const part = emittedLine.parts[partIndex];
3440 if (part.length > columnsLeft) {
3441 return emittedLine.srcSpans[partIndex];
3442 }
3443 columnsLeft -= part.length;
3444 }
3445 }
3446 return null;
3447 }
3448 /**
3449 * @internal strip this from published d.ts files due to
3450 * https://github.com/microsoft/TypeScript/issues/36216
3451 */
3452 get sourceLines() {
3453 if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) {
3454 return this._lines.slice(0, -1);
3455 }
3456 return this._lines;
3457 }
3458 }
3459 class AbstractEmitterVisitor {
3460 constructor(_escapeDollarInStrings) {
3461 this._escapeDollarInStrings = _escapeDollarInStrings;
3462 }
3463 printLeadingComments(stmt, ctx) {
3464 if (stmt.leadingComments === undefined) {
3465 return;
3466 }
3467 for (const comment of stmt.leadingComments) {
3468 if (comment instanceof JSDocComment) {
3469 ctx.print(stmt, `/*${comment.toString()}*/`, comment.trailingNewline);
3470 }
3471 else {
3472 if (comment.multiline) {
3473 ctx.print(stmt, `/* ${comment.text} */`, comment.trailingNewline);
3474 }
3475 else {
3476 comment.text.split('\n').forEach((line) => {
3477 ctx.println(stmt, `// ${line}`);
3478 });
3479 }
3480 }
3481 }
3482 }
3483 visitExpressionStmt(stmt, ctx) {
3484 this.printLeadingComments(stmt, ctx);
3485 stmt.expr.visitExpression(this, ctx);
3486 ctx.println(stmt, ';');
3487 return null;
3488 }
3489 visitReturnStmt(stmt, ctx) {
3490 this.printLeadingComments(stmt, ctx);
3491 ctx.print(stmt, `return `);
3492 stmt.value.visitExpression(this, ctx);
3493 ctx.println(stmt, ';');
3494 return null;
3495 }
3496 visitIfStmt(stmt, ctx) {
3497 this.printLeadingComments(stmt, ctx);
3498 ctx.print(stmt, `if (`);
3499 stmt.condition.visitExpression(this, ctx);
3500 ctx.print(stmt, `) {`);
3501 const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0;
3502 if (stmt.trueCase.length <= 1 && !hasElseCase) {
3503 ctx.print(stmt, ` `);
3504 this.visitAllStatements(stmt.trueCase, ctx);
3505 ctx.removeEmptyLastLine();
3506 ctx.print(stmt, ` `);
3507 }
3508 else {
3509 ctx.println();
3510 ctx.incIndent();
3511 this.visitAllStatements(stmt.trueCase, ctx);
3512 ctx.decIndent();
3513 if (hasElseCase) {
3514 ctx.println(stmt, `} else {`);
3515 ctx.incIndent();
3516 this.visitAllStatements(stmt.falseCase, ctx);
3517 ctx.decIndent();
3518 }
3519 }
3520 ctx.println(stmt, `}`);
3521 return null;
3522 }
3523 visitThrowStmt(stmt, ctx) {
3524 this.printLeadingComments(stmt, ctx);
3525 ctx.print(stmt, `throw `);
3526 stmt.error.visitExpression(this, ctx);
3527 ctx.println(stmt, `;`);
3528 return null;
3529 }
3530 visitWriteVarExpr(expr, ctx) {
3531 const lineWasEmpty = ctx.lineIsEmpty();
3532 if (!lineWasEmpty) {
3533 ctx.print(expr, '(');
3534 }
3535 ctx.print(expr, `${expr.name} = `);
3536 expr.value.visitExpression(this, ctx);
3537 if (!lineWasEmpty) {
3538 ctx.print(expr, ')');
3539 }
3540 return null;
3541 }
3542 visitWriteKeyExpr(expr, ctx) {
3543 const lineWasEmpty = ctx.lineIsEmpty();
3544 if (!lineWasEmpty) {
3545 ctx.print(expr, '(');
3546 }
3547 expr.receiver.visitExpression(this, ctx);
3548 ctx.print(expr, `[`);
3549 expr.index.visitExpression(this, ctx);
3550 ctx.print(expr, `] = `);
3551 expr.value.visitExpression(this, ctx);
3552 if (!lineWasEmpty) {
3553 ctx.print(expr, ')');
3554 }
3555 return null;
3556 }
3557 visitWritePropExpr(expr, ctx) {
3558 const lineWasEmpty = ctx.lineIsEmpty();
3559 if (!lineWasEmpty) {
3560 ctx.print(expr, '(');
3561 }
3562 expr.receiver.visitExpression(this, ctx);
3563 ctx.print(expr, `.${expr.name} = `);
3564 expr.value.visitExpression(this, ctx);
3565 if (!lineWasEmpty) {
3566 ctx.print(expr, ')');
3567 }
3568 return null;
3569 }
3570 visitInvokeMethodExpr(expr, ctx) {
3571 expr.receiver.visitExpression(this, ctx);
3572 let name = expr.name;
3573 if (expr.builtin != null) {
3574 name = this.getBuiltinMethodName(expr.builtin);
3575 if (name == null) {
3576 // some builtins just mean to skip the call.
3577 return null;
3578 }
3579 }
3580 ctx.print(expr, `.${name}(`);
3581 this.visitAllExpressions(expr.args, ctx, `,`);
3582 ctx.print(expr, `)`);
3583 return null;
3584 }
3585 visitInvokeFunctionExpr(expr, ctx) {
3586 expr.fn.visitExpression(this, ctx);
3587 ctx.print(expr, `(`);
3588 this.visitAllExpressions(expr.args, ctx, ',');
3589 ctx.print(expr, `)`);
3590 return null;
3591 }
3592 visitTaggedTemplateExpr(expr, ctx) {
3593 expr.tag.visitExpression(this, ctx);
3594 ctx.print(expr, '`' + expr.template.elements[0].rawText);
3595 for (let i = 1; i < expr.template.elements.length; i++) {
3596 ctx.print(expr, '${');
3597 expr.template.expressions[i - 1].visitExpression(this, ctx);
3598 ctx.print(expr, `}${expr.template.elements[i].rawText}`);
3599 }
3600 ctx.print(expr, '`');
3601 return null;
3602 }
3603 visitWrappedNodeExpr(ast, ctx) {
3604 throw new Error('Abstract emitter cannot visit WrappedNodeExpr.');
3605 }
3606 visitTypeofExpr(expr, ctx) {
3607 ctx.print(expr, 'typeof ');
3608 expr.expr.visitExpression(this, ctx);
3609 }
3610 visitReadVarExpr(ast, ctx) {
3611 let varName = ast.name;
3612 if (ast.builtin != null) {
3613 switch (ast.builtin) {
3614 case BuiltinVar.Super:
3615 varName = 'super';
3616 break;
3617 case BuiltinVar.This:
3618 varName = 'this';
3619 break;
3620 case BuiltinVar.CatchError:
3621 varName = CATCH_ERROR_VAR$1.name;
3622 break;
3623 case BuiltinVar.CatchStack:
3624 varName = CATCH_STACK_VAR$1.name;
3625 break;
3626 default:
3627 throw new Error(`Unknown builtin variable ${ast.builtin}`);
3628 }
3629 }
3630 ctx.print(ast, varName);
3631 return null;
3632 }
3633 visitInstantiateExpr(ast, ctx) {
3634 ctx.print(ast, `new `);
3635 ast.classExpr.visitExpression(this, ctx);
3636 ctx.print(ast, `(`);
3637 this.visitAllExpressions(ast.args, ctx, ',');
3638 ctx.print(ast, `)`);
3639 return null;
3640 }
3641 visitLiteralExpr(ast, ctx) {
3642 const value = ast.value;
3643 if (typeof value === 'string') {
3644 ctx.print(ast, escapeIdentifier(value, this._escapeDollarInStrings));
3645 }
3646 else {
3647 ctx.print(ast, `${value}`);
3648 }
3649 return null;
3650 }
3651 visitLocalizedString(ast, ctx) {
3652 const head = ast.serializeI18nHead();
3653 ctx.print(ast, '$localize `' + head.raw);
3654 for (let i = 1; i < ast.messageParts.length; i++) {
3655 ctx.print(ast, '${');
3656 ast.expressions[i - 1].visitExpression(this, ctx);
3657 ctx.print(ast, `}${ast.serializeI18nTemplatePart(i).raw}`);
3658 }
3659 ctx.print(ast, '`');
3660 return null;
3661 }
3662 visitConditionalExpr(ast, ctx) {
3663 ctx.print(ast, `(`);
3664 ast.condition.visitExpression(this, ctx);
3665 ctx.print(ast, '? ');
3666 ast.trueCase.visitExpression(this, ctx);
3667 ctx.print(ast, ': ');
3668 ast.falseCase.visitExpression(this, ctx);
3669 ctx.print(ast, `)`);
3670 return null;
3671 }
3672 visitNotExpr(ast, ctx) {
3673 ctx.print(ast, '!');
3674 ast.condition.visitExpression(this, ctx);
3675 return null;
3676 }
3677 visitAssertNotNullExpr(ast, ctx) {
3678 ast.condition.visitExpression(this, ctx);
3679 return null;
3680 }
3681 visitUnaryOperatorExpr(ast, ctx) {
3682 let opStr;
3683 switch (ast.operator) {
3684 case UnaryOperator.Plus:
3685 opStr = '+';
3686 break;
3687 case UnaryOperator.Minus:
3688 opStr = '-';
3689 break;
3690 default:
3691 throw new Error(`Unknown operator ${ast.operator}`);
3692 }
3693 if (ast.parens)
3694 ctx.print(ast, `(`);
3695 ctx.print(ast, opStr);
3696 ast.expr.visitExpression(this, ctx);
3697 if (ast.parens)
3698 ctx.print(ast, `)`);
3699 return null;
3700 }
3701 visitBinaryOperatorExpr(ast, ctx) {
3702 let opStr;
3703 switch (ast.operator) {
3704 case BinaryOperator.Equals:
3705 opStr = '==';
3706 break;
3707 case BinaryOperator.Identical:
3708 opStr = '===';
3709 break;
3710 case BinaryOperator.NotEquals:
3711 opStr = '!=';
3712 break;
3713 case BinaryOperator.NotIdentical:
3714 opStr = '!==';
3715 break;
3716 case BinaryOperator.And:
3717 opStr = '&&';
3718 break;
3719 case BinaryOperator.BitwiseAnd:
3720 opStr = '&';
3721 break;
3722 case BinaryOperator.Or:
3723 opStr = '||';
3724 break;
3725 case BinaryOperator.Plus:
3726 opStr = '+';
3727 break;
3728 case BinaryOperator.Minus:
3729 opStr = '-';
3730 break;
3731 case BinaryOperator.Divide:
3732 opStr = '/';
3733 break;
3734 case BinaryOperator.Multiply:
3735 opStr = '*';
3736 break;
3737 case BinaryOperator.Modulo:
3738 opStr = '%';
3739 break;
3740 case BinaryOperator.Lower:
3741 opStr = '<';
3742 break;
3743 case BinaryOperator.LowerEquals:
3744 opStr = '<=';
3745 break;
3746 case BinaryOperator.Bigger:
3747 opStr = '>';
3748 break;
3749 case BinaryOperator.BiggerEquals:
3750 opStr = '>=';
3751 break;
3752 default:
3753 throw new Error(`Unknown operator ${ast.operator}`);
3754 }
3755 if (ast.parens)
3756 ctx.print(ast, `(`);
3757 ast.lhs.visitExpression(this, ctx);
3758 ctx.print(ast, ` ${opStr} `);
3759 ast.rhs.visitExpression(this, ctx);
3760 if (ast.parens)
3761 ctx.print(ast, `)`);
3762 return null;
3763 }
3764 visitReadPropExpr(ast, ctx) {
3765 ast.receiver.visitExpression(this, ctx);
3766 ctx.print(ast, `.`);
3767 ctx.print(ast, ast.name);
3768 return null;
3769 }
3770 visitReadKeyExpr(ast, ctx) {
3771 ast.receiver.visitExpression(this, ctx);
3772 ctx.print(ast, `[`);
3773 ast.index.visitExpression(this, ctx);
3774 ctx.print(ast, `]`);
3775 return null;
3776 }
3777 visitLiteralArrayExpr(ast, ctx) {
3778 ctx.print(ast, `[`);
3779 this.visitAllExpressions(ast.entries, ctx, ',');
3780 ctx.print(ast, `]`);
3781 return null;
3782 }
3783 visitLiteralMapExpr(ast, ctx) {
3784 ctx.print(ast, `{`);
3785 this.visitAllObjects(entry => {
3786 ctx.print(ast, `${escapeIdentifier(entry.key, this._escapeDollarInStrings, entry.quoted)}:`);
3787 entry.value.visitExpression(this, ctx);
3788 }, ast.entries, ctx, ',');
3789 ctx.print(ast, `}`);
3790 return null;
3791 }
3792 visitCommaExpr(ast, ctx) {
3793 ctx.print(ast, '(');
3794 this.visitAllExpressions(ast.parts, ctx, ',');
3795 ctx.print(ast, ')');
3796 return null;
3797 }
3798 visitAllExpressions(expressions, ctx, separator) {
3799 this.visitAllObjects(expr => expr.visitExpression(this, ctx), expressions, ctx, separator);
3800 }
3801 visitAllObjects(handler, expressions, ctx, separator) {
3802 let incrementedIndent = false;
3803 for (let i = 0; i < expressions.length; i++) {
3804 if (i > 0) {
3805 if (ctx.lineLength() > 80) {
3806 ctx.print(null, separator, true);
3807 if (!incrementedIndent) {
3808 // continuation are marked with double indent.
3809 ctx.incIndent();
3810 ctx.incIndent();
3811 incrementedIndent = true;
3812 }
3813 }
3814 else {
3815 ctx.print(null, separator, false);
3816 }
3817 }
3818 handler(expressions[i]);
3819 }
3820 if (incrementedIndent) {
3821 // continuation are marked with double indent.
3822 ctx.decIndent();
3823 ctx.decIndent();
3824 }
3825 }
3826 visitAllStatements(statements, ctx) {
3827 statements.forEach((stmt) => stmt.visitStatement(this, ctx));
3828 }
3829 }
3830 function escapeIdentifier(input, escapeDollar, alwaysQuote = true) {
3831 if (input == null) {
3832 return null;
3833 }
3834 const body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, (...match) => {
3835 if (match[0] == '$') {
3836 return escapeDollar ? '\\$' : '$';
3837 }
3838 else if (match[0] == '\n') {
3839 return '\\n';
3840 }
3841 else if (match[0] == '\r') {
3842 return '\\r';
3843 }
3844 else {
3845 return `\\${match[0]}`;
3846 }
3847 });
3848 const requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body);
3849 return requiresQuotes ? `'${body}'` : body;
3850 }
3851 function _createIndent(count) {
3852 let res = '';
3853 for (let i = 0; i < count; i++) {
3854 res += _INDENT_WITH;
3855 }
3856 return res;
3857 }
3858
3859 /**
3860 * @license
3861 * Copyright Google LLC All Rights Reserved.
3862 *
3863 * Use of this source code is governed by an MIT-style license that can be
3864 * found in the LICENSE file at https://angular.io/license
3865 */
3866 /**
3867 * Convert an object map with `Expression` values into a `LiteralMapExpr`.
3868 */
3869 function mapToMapExpression(map) {
3870 const result = Object.keys(map).map(key => ({
3871 key,
3872 // The assertion here is because really TypeScript doesn't allow us to express that if the
3873 // key is present, it will have a value, but this is true in reality.
3874 value: map[key],
3875 quoted: false,
3876 }));
3877 return literalMap(result);
3878 }
3879 function typeWithParameters(type, numParams) {
3880 if (numParams === 0) {
3881 return expressionType(type);
3882 }
3883 const params = [];
3884 for (let i = 0; i < numParams; i++) {
3885 params.push(DYNAMIC_TYPE);
3886 }
3887 return expressionType(type, undefined, params);
3888 }
3889 const ANIMATE_SYMBOL_PREFIX = '@';
3890 function prepareSyntheticPropertyName(name) {
3891 return `${ANIMATE_SYMBOL_PREFIX}${name}`;
3892 }
3893 function prepareSyntheticListenerName(name, phase) {
3894 return `${ANIMATE_SYMBOL_PREFIX}${name}.${phase}`;
3895 }
3896 function getSafePropertyAccessString(accessor, name) {
3897 const escapedName = escapeIdentifier(name, false, false);
3898 return escapedName !== name ? `${accessor}[${escapedName}]` : `${accessor}.${name}`;
3899 }
3900 function prepareSyntheticListenerFunctionName(name, phase) {
3901 return `animation_${name}_${phase}`;
3902 }
3903 function jitOnlyGuardedExpression(expr) {
3904 return guardedExpression('ngJitMode', expr);
3905 }
3906 function guardedExpression(guard, expr) {
3907 const guardExpr = new ExternalExpr({ name: guard, moduleName: null });
3908 const guardNotDefined = new BinaryOperatorExpr(BinaryOperator.Identical, new TypeofExpr(guardExpr), literal('undefined'));
3909 const guardUndefinedOrTrue = new BinaryOperatorExpr(BinaryOperator.Or, guardNotDefined, guardExpr, /* type */ undefined,
3910 /* sourceSpan */ undefined, true);
3911 return new BinaryOperatorExpr(BinaryOperator.And, guardUndefinedOrTrue, expr);
3912 }
3913
3914 /**
3915 * @license
3916 * Copyright Google LLC All Rights Reserved.
3917 *
3918 * Use of this source code is governed by an MIT-style license that can be
3919 * found in the LICENSE file at https://angular.io/license
3920 */
3921 class Text {
3922 constructor(value, sourceSpan) {
3923 this.value = value;
3924 this.sourceSpan = sourceSpan;
3925 }
3926 visit(visitor) {
3927 return visitor.visitText(this);
3928 }
3929 }
3930 class BoundText {
3931 constructor(value, sourceSpan, i18n) {
3932 this.value = value;
3933 this.sourceSpan = sourceSpan;
3934 this.i18n = i18n;
3935 }
3936 visit(visitor) {
3937 return visitor.visitBoundText(this);
3938 }
3939 }
3940 /**
3941 * Represents a text attribute in the template.
3942 *
3943 * `valueSpan` may not be present in cases where there is no value `<div a></div>`.
3944 * `keySpan` may also not be present for synthetic attributes from ICU expansions.
3945 */
3946 class TextAttribute {
3947 constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) {
3948 this.name = name;
3949 this.value = value;
3950 this.sourceSpan = sourceSpan;
3951 this.keySpan = keySpan;
3952 this.valueSpan = valueSpan;
3953 this.i18n = i18n;
3954 }
3955 visit(visitor) {
3956 return visitor.visitTextAttribute(this);
3957 }
3958 }
3959 class BoundAttribute {
3960 constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan, i18n) {
3961 this.name = name;
3962 this.type = type;
3963 this.securityContext = securityContext;
3964 this.value = value;
3965 this.unit = unit;
3966 this.sourceSpan = sourceSpan;
3967 this.keySpan = keySpan;
3968 this.valueSpan = valueSpan;
3969 this.i18n = i18n;
3970 }
3971 static fromBoundElementProperty(prop, i18n) {
3972 if (prop.keySpan === undefined) {
3973 throw new Error(`Unexpected state: keySpan must be defined for bound attributes but was not for ${prop.name}: ${prop.sourceSpan}`);
3974 }
3975 return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n);
3976 }
3977 visit(visitor) {
3978 return visitor.visitBoundAttribute(this);
3979 }
3980 }
3981 class BoundEvent {
3982 constructor(name, type, handler, target, phase, sourceSpan, handlerSpan, keySpan) {
3983 this.name = name;
3984 this.type = type;
3985 this.handler = handler;
3986 this.target = target;
3987 this.phase = phase;
3988 this.sourceSpan = sourceSpan;
3989 this.handlerSpan = handlerSpan;
3990 this.keySpan = keySpan;
3991 }
3992 static fromParsedEvent(event) {
3993 const target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
3994 const phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
3995 if (event.keySpan === undefined) {
3996 throw new Error(`Unexpected state: keySpan must be defined for bound event but was not for ${event.name}: ${event.sourceSpan}`);
3997 }
3998 return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan, event.keySpan);
3999 }
4000 visit(visitor) {
4001 return visitor.visitBoundEvent(this);
4002 }
4003 }
4004 class Element {
4005 constructor(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
4006 this.name = name;
4007 this.attributes = attributes;
4008 this.inputs = inputs;
4009 this.outputs = outputs;
4010 this.children = children;
4011 this.references = references;
4012 this.sourceSpan = sourceSpan;
4013 this.startSourceSpan = startSourceSpan;
4014 this.endSourceSpan = endSourceSpan;
4015 this.i18n = i18n;
4016 }
4017 visit(visitor) {
4018 return visitor.visitElement(this);
4019 }
4020 }
4021 class Template {
4022 constructor(tagName, attributes, inputs, outputs, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
4023 this.tagName = tagName;
4024 this.attributes = attributes;
4025 this.inputs = inputs;
4026 this.outputs = outputs;
4027 this.templateAttrs = templateAttrs;
4028 this.children = children;
4029 this.references = references;
4030 this.variables = variables;
4031 this.sourceSpan = sourceSpan;
4032 this.startSourceSpan = startSourceSpan;
4033 this.endSourceSpan = endSourceSpan;
4034 this.i18n = i18n;
4035 }
4036 visit(visitor) {
4037 return visitor.visitTemplate(this);
4038 }
4039 }
4040 class Content {
4041 constructor(selector, attributes, sourceSpan, i18n) {
4042 this.selector = selector;
4043 this.attributes = attributes;
4044 this.sourceSpan = sourceSpan;
4045 this.i18n = i18n;
4046 this.name = 'ng-content';
4047 }
4048 visit(visitor) {
4049 return visitor.visitContent(this);
4050 }
4051 }
4052 class Variable {
4053 constructor(name, value, sourceSpan, keySpan, valueSpan) {
4054 this.name = name;
4055 this.value = value;
4056 this.sourceSpan = sourceSpan;
4057 this.keySpan = keySpan;
4058 this.valueSpan = valueSpan;
4059 }
4060 visit(visitor) {
4061 return visitor.visitVariable(this);
4062 }
4063 }
4064 class Reference {
4065 constructor(name, value, sourceSpan, keySpan, valueSpan) {
4066 this.name = name;
4067 this.value = value;
4068 this.sourceSpan = sourceSpan;
4069 this.keySpan = keySpan;
4070 this.valueSpan = valueSpan;
4071 }
4072 visit(visitor) {
4073 return visitor.visitReference(this);
4074 }
4075 }
4076 class Icu {
4077 constructor(vars, placeholders, sourceSpan, i18n) {
4078 this.vars = vars;
4079 this.placeholders = placeholders;
4080 this.sourceSpan = sourceSpan;
4081 this.i18n = i18n;
4082 }
4083 visit(visitor) {
4084 return visitor.visitIcu(this);
4085 }
4086 }
4087 function visitAll(visitor, nodes) {
4088 const result = [];
4089 if (visitor.visit) {
4090 for (const node of nodes) {
4091 const newNode = visitor.visit(node) || node.visit(visitor);
4092 }
4093 }
4094 else {
4095 for (const node of nodes) {
4096 const newNode = node.visit(visitor);
4097 if (newNode) {
4098 result.push(newNode);
4099 }
4100 }
4101 }
4102 return result;
4103 }
4104
4105 /**
4106 * @license
4107 * Copyright Google LLC All Rights Reserved.
4108 *
4109 * Use of this source code is governed by an MIT-style license that can be
4110 * found in the LICENSE file at https://angular.io/license
4111 */
4112 class Message {
4113 /**
4114 * @param nodes message AST
4115 * @param placeholders maps placeholder names to static content and their source spans
4116 * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages)
4117 * @param meaning
4118 * @param description
4119 * @param customId
4120 */
4121 constructor(nodes, placeholders, placeholderToMessage, meaning, description, customId) {
4122 this.nodes = nodes;
4123 this.placeholders = placeholders;
4124 this.placeholderToMessage = placeholderToMessage;
4125 this.meaning = meaning;
4126 this.description = description;
4127 this.customId = customId;
4128 this.id = this.customId;
4129 /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */
4130 this.legacyIds = [];
4131 if (nodes.length) {
4132 this.sources = [{
4133 filePath: nodes[0].sourceSpan.start.file.url,
4134 startLine: nodes[0].sourceSpan.start.line + 1,
4135 startCol: nodes[0].sourceSpan.start.col + 1,
4136 endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1,
4137 endCol: nodes[0].sourceSpan.start.col + 1
4138 }];
4139 }
4140 else {
4141 this.sources = [];
4142 }
4143 }
4144 }
4145 class Text$1 {
4146 constructor(value, sourceSpan) {
4147 this.value = value;
4148 this.sourceSpan = sourceSpan;
4149 }
4150 visit(visitor, context) {
4151 return visitor.visitText(this, context);
4152 }
4153 }
4154 // TODO(vicb): do we really need this node (vs an array) ?
4155 class Container {
4156 constructor(children, sourceSpan) {
4157 this.children = children;
4158 this.sourceSpan = sourceSpan;
4159 }
4160 visit(visitor, context) {
4161 return visitor.visitContainer(this, context);
4162 }
4163 }
4164 class Icu$1 {
4165 constructor(expression, type, cases, sourceSpan) {
4166 this.expression = expression;
4167 this.type = type;
4168 this.cases = cases;
4169 this.sourceSpan = sourceSpan;
4170 }
4171 visit(visitor, context) {
4172 return visitor.visitIcu(this, context);
4173 }
4174 }
4175 class TagPlaceholder {
4176 constructor(tag, attrs, startName, closeName, children, isVoid,
4177 // TODO sourceSpan should cover all (we need a startSourceSpan and endSourceSpan)
4178 sourceSpan, startSourceSpan, endSourceSpan) {
4179 this.tag = tag;
4180 this.attrs = attrs;
4181 this.startName = startName;
4182 this.closeName = closeName;
4183 this.children = children;
4184 this.isVoid = isVoid;
4185 this.sourceSpan = sourceSpan;
4186 this.startSourceSpan = startSourceSpan;
4187 this.endSourceSpan = endSourceSpan;
4188 }
4189 visit(visitor, context) {
4190 return visitor.visitTagPlaceholder(this, context);
4191 }
4192 }
4193 class Placeholder {
4194 constructor(value, name, sourceSpan) {
4195 this.value = value;
4196 this.name = name;
4197 this.sourceSpan = sourceSpan;
4198 }
4199 visit(visitor, context) {
4200 return visitor.visitPlaceholder(this, context);
4201 }
4202 }
4203 class IcuPlaceholder {
4204 constructor(value, name, sourceSpan) {
4205 this.value = value;
4206 this.name = name;
4207 this.sourceSpan = sourceSpan;
4208 }
4209 visit(visitor, context) {
4210 return visitor.visitIcuPlaceholder(this, context);
4211 }
4212 }
4213
4214 /**
4215 * @license
4216 * Copyright Google LLC All Rights Reserved.
4217 *
4218 * Use of this source code is governed by an MIT-style license that can be
4219 * found in the LICENSE file at https://angular.io/license
4220 */
4221 /**
4222 * Represents a big integer using a buffer of its individual digits, with the least significant
4223 * digit stored at the beginning of the array (little endian).
4224 *
4225 * For performance reasons, each instance is mutable. The addition operation can be done in-place
4226 * to reduce memory pressure of allocation for the digits array.
4227 */
4228 class BigInteger {
4229 /**
4230 * Creates a big integer using its individual digits in little endian storage.
4231 */
4232 constructor(digits) {
4233 this.digits = digits;
4234 }
4235 static zero() {
4236 return new BigInteger([0]);
4237 }
4238 static one() {
4239 return new BigInteger([1]);
4240 }
4241 /**
4242 * Creates a clone of this instance.
4243 */
4244 clone() {
4245 return new BigInteger(this.digits.slice());
4246 }
4247 /**
4248 * Returns a new big integer with the sum of `this` and `other` as its value. This does not mutate
4249 * `this` but instead returns a new instance, unlike `addToSelf`.
4250 */
4251 add(other) {
4252 const result = this.clone();
4253 result.addToSelf(other);
4254 return result;
4255 }
4256 /**
4257 * Adds `other` to the instance itself, thereby mutating its value.
4258 */
4259 addToSelf(other) {
4260 const maxNrOfDigits = Math.max(this.digits.length, other.digits.length);
4261 let carry = 0;
4262 for (let i = 0; i < maxNrOfDigits; i++) {
4263 let digitSum = carry;
4264 if (i < this.digits.length) {
4265 digitSum += this.digits[i];
4266 }
4267 if (i < other.digits.length) {
4268 digitSum += other.digits[i];
4269 }
4270 if (digitSum >= 10) {
4271 this.digits[i] = digitSum - 10;
4272 carry = 1;
4273 }
4274 else {
4275 this.digits[i] = digitSum;
4276 carry = 0;
4277 }
4278 }
4279 // Apply a remaining carry if needed.
4280 if (carry > 0) {
4281 this.digits[maxNrOfDigits] = 1;
4282 }
4283 }
4284 /**
4285 * Builds the decimal string representation of the big integer. As this is stored in
4286 * little endian, the digits are concatenated in reverse order.
4287 */
4288 toString() {
4289 let res = '';
4290 for (let i = this.digits.length - 1; i >= 0; i--) {
4291 res += this.digits[i];
4292 }
4293 return res;
4294 }
4295 }
4296 /**
4297 * Represents a big integer which is optimized for multiplication operations, as its power-of-twos
4298 * are memoized. See `multiplyBy()` for details on the multiplication algorithm.
4299 */
4300 class BigIntForMultiplication {
4301 constructor(value) {
4302 this.powerOfTwos = [value];
4303 }
4304 /**
4305 * Returns the big integer itself.
4306 */
4307 getValue() {
4308 return this.powerOfTwos[0];
4309 }
4310 /**
4311 * Computes the value for `num * b`, where `num` is a JS number and `b` is a big integer. The
4312 * value for `b` is represented by a storage model that is optimized for this computation.
4313 *
4314 * This operation is implemented in N(log2(num)) by continuous halving of the number, where the
4315 * least-significant bit (LSB) is tested in each iteration. If the bit is set, the bit's index is
4316 * used as exponent into the power-of-two multiplication of `b`.
4317 *
4318 * As an example, consider the multiplication num=42, b=1337. In binary 42 is 0b00101010 and the
4319 * algorithm unrolls into the following iterations:
4320 *
4321 * Iteration | num | LSB | b * 2^iter | Add? | product
4322 * -----------|------------|------|------------|------|--------
4323 * 0 | 0b00101010 | 0 | 1337 | No | 0
4324 * 1 | 0b00010101 | 1 | 2674 | Yes | 2674
4325 * 2 | 0b00001010 | 0 | 5348 | No | 2674
4326 * 3 | 0b00000101 | 1 | 10696 | Yes | 13370
4327 * 4 | 0b00000010 | 0 | 21392 | No | 13370
4328 * 5 | 0b00000001 | 1 | 42784 | Yes | 56154
4329 * 6 | 0b00000000 | 0 | 85568 | No | 56154
4330 *
4331 * The computed product of 56154 is indeed the correct result.
4332 *
4333 * The `BigIntForMultiplication` representation for a big integer provides memoized access to the
4334 * power-of-two values to reduce the workload in computing those values.
4335 */
4336 multiplyBy(num) {
4337 const product = BigInteger.zero();
4338 this.multiplyByAndAddTo(num, product);
4339 return product;
4340 }
4341 /**
4342 * See `multiplyBy()` for details. This function allows for the computed product to be added
4343 * directly to the provided result big integer.
4344 */
4345 multiplyByAndAddTo(num, result) {
4346 for (let exponent = 0; num !== 0; num = num >>> 1, exponent++) {
4347 if (num & 1) {
4348 const value = this.getMultipliedByPowerOfTwo(exponent);
4349 result.addToSelf(value);
4350 }
4351 }
4352 }
4353 /**
4354 * Computes and memoizes the big integer value for `this.number * 2^exponent`.
4355 */
4356 getMultipliedByPowerOfTwo(exponent) {
4357 // Compute the powers up until the requested exponent, where each value is computed from its
4358 // predecessor. This is simple as `this.number * 2^(exponent - 1)` only has to be doubled (i.e.
4359 // added to itself) to reach `this.number * 2^exponent`.
4360 for (let i = this.powerOfTwos.length; i <= exponent; i++) {
4361 const previousPower = this.powerOfTwos[i - 1];
4362 this.powerOfTwos[i] = previousPower.add(previousPower);
4363 }
4364 return this.powerOfTwos[exponent];
4365 }
4366 }
4367 /**
4368 * Represents an exponentiation operation for the provided base, of which exponents are computed and
4369 * memoized. The results are represented by a `BigIntForMultiplication` which is tailored for
4370 * multiplication operations by memoizing the power-of-twos. This effectively results in a matrix
4371 * representation that is lazily computed upon request.
4372 */
4373 class BigIntExponentiation {
4374 constructor(base) {
4375 this.base = base;
4376 this.exponents = [new BigIntForMultiplication(BigInteger.one())];
4377 }
4378 /**
4379 * Compute the value for `this.base^exponent`, resulting in a big integer that is optimized for
4380 * further multiplication operations.
4381 */
4382 toThePowerOf(exponent) {
4383 // Compute the results up until the requested exponent, where every value is computed from its
4384 // predecessor. This is because `this.base^(exponent - 1)` only has to be multiplied by `base`
4385 // to reach `this.base^exponent`.
4386 for (let i = this.exponents.length; i <= exponent; i++) {
4387 const value = this.exponents[i - 1].multiplyBy(this.base);
4388 this.exponents[i] = new BigIntForMultiplication(value);
4389 }
4390 return this.exponents[exponent];
4391 }
4392 }
4393
4394 /**
4395 * @license
4396 * Copyright Google LLC All Rights Reserved.
4397 *
4398 * Use of this source code is governed by an MIT-style license that can be
4399 * found in the LICENSE file at https://angular.io/license
4400 */
4401 /**
4402 * Compute the message id using the XLIFF1 digest.
4403 */
4404 function computeDigest(message) {
4405 return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
4406 }
4407 /**
4408 * Return the message id or compute it using the XLIFF2/XMB/$localize digest.
4409 */
4410 function decimalDigest(message) {
4411 return message.id || computeDecimalDigest(message);
4412 }
4413 /**
4414 * Compute the message id using the XLIFF2/XMB/$localize digest.
4415 */
4416 function computeDecimalDigest(message) {
4417 const visitor = new _SerializerIgnoreIcuExpVisitor();
4418 const parts = message.nodes.map(a => a.visit(visitor, null));
4419 return computeMsgId(parts.join(''), message.meaning);
4420 }
4421 /**
4422 * Serialize the i18n ast to something xml-like in order to generate an UID.
4423 *
4424 * The visitor is also used in the i18n parser tests
4425 *
4426 * @internal
4427 */
4428 class _SerializerVisitor {
4429 visitText(text, context) {
4430 return text.value;
4431 }
4432 visitContainer(container, context) {
4433 return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
4434 }
4435 visitIcu(icu, context) {
4436 const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
4437 return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`;
4438 }
4439 visitTagPlaceholder(ph, context) {
4440 return ph.isVoid ?
4441 `<ph tag name="${ph.startName}"/>` :
4442 `<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
4443 }
4444 visitPlaceholder(ph, context) {
4445 return ph.value ? `<ph name="${ph.name}">${ph.value}</ph>` : `<ph name="${ph.name}"/>`;
4446 }
4447 visitIcuPlaceholder(ph, context) {
4448 return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
4449 }
4450 }
4451 const serializerVisitor = new _SerializerVisitor();
4452 function serializeNodes(nodes) {
4453 return nodes.map(a => a.visit(serializerVisitor, null));
4454 }
4455 /**
4456 * Serialize the i18n ast to something xml-like in order to generate an UID.
4457 *
4458 * Ignore the ICU expressions so that message IDs stays identical if only the expression changes.
4459 *
4460 * @internal
4461 */
4462 class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor {
4463 visitIcu(icu, context) {
4464 let strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
4465 // Do not take the expression into account
4466 return `{${icu.type}, ${strCases.join(', ')}}`;
4467 }
4468 }
4469 /**
4470 * Compute the SHA1 of the given string
4471 *
4472 * see https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
4473 *
4474 * WARNING: this function has not been designed not tested with security in mind.
4475 * DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT.
4476 */
4477 function sha1(str) {
4478 const utf8 = utf8Encode(str);
4479 const words32 = bytesToWords32(utf8, Endian.Big);
4480 const len = utf8.length * 8;
4481 const w = newArray(80);
4482 let a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476, e = 0xc3d2e1f0;
4483 words32[len >> 5] |= 0x80 << (24 - len % 32);
4484 words32[((len + 64 >> 9) << 4) + 15] = len;
4485 for (let i = 0; i < words32.length; i += 16) {
4486 const h0 = a, h1 = b, h2 = c, h3 = d, h4 = e;
4487 for (let j = 0; j < 80; j++) {
4488 if (j < 16) {
4489 w[j] = words32[i + j];
4490 }
4491 else {
4492 w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
4493 }
4494 const fkVal = fk(j, b, c, d);
4495 const f = fkVal[0];
4496 const k = fkVal[1];
4497 const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
4498 e = d;
4499 d = c;
4500 c = rol32(b, 30);
4501 b = a;
4502 a = temp;
4503 }
4504 a = add32(a, h0);
4505 b = add32(b, h1);
4506 c = add32(c, h2);
4507 d = add32(d, h3);
4508 e = add32(e, h4);
4509 }
4510 return bytesToHexString(words32ToByteString([a, b, c, d, e]));
4511 }
4512 function fk(index, b, c, d) {
4513 if (index < 20) {
4514 return [(b & c) | (~b & d), 0x5a827999];
4515 }
4516 if (index < 40) {
4517 return [b ^ c ^ d, 0x6ed9eba1];
4518 }
4519 if (index < 60) {
4520 return [(b & c) | (b & d) | (c & d), 0x8f1bbcdc];
4521 }
4522 return [b ^ c ^ d, 0xca62c1d6];
4523 }
4524 /**
4525 * Compute the fingerprint of the given string
4526 *
4527 * The output is 64 bit number encoded as a decimal string
4528 *
4529 * based on:
4530 * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
4531 */
4532 function fingerprint(str) {
4533 const utf8 = utf8Encode(str);
4534 let hi = hash32(utf8, 0);
4535 let lo = hash32(utf8, 102072);
4536 if (hi == 0 && (lo == 0 || lo == 1)) {
4537 hi = hi ^ 0x130f9bef;
4538 lo = lo ^ -0x6b5f56d8;
4539 }
4540 return [hi, lo];
4541 }
4542 function computeMsgId(msg, meaning = '') {
4543 let msgFingerprint = fingerprint(msg);
4544 if (meaning) {
4545 const meaningFingerprint = fingerprint(meaning);
4546 msgFingerprint = add64(rol64(msgFingerprint, 1), meaningFingerprint);
4547 }
4548 const hi = msgFingerprint[0];
4549 const lo = msgFingerprint[1];
4550 return wordsToDecimalString(hi & 0x7fffffff, lo);
4551 }
4552 function hash32(bytes, c) {
4553 let a = 0x9e3779b9, b = 0x9e3779b9;
4554 let i;
4555 const len = bytes.length;
4556 for (i = 0; i + 12 <= len; i += 12) {
4557 a = add32(a, wordAt(bytes, i, Endian.Little));
4558 b = add32(b, wordAt(bytes, i + 4, Endian.Little));
4559 c = add32(c, wordAt(bytes, i + 8, Endian.Little));
4560 const res = mix(a, b, c);
4561 a = res[0], b = res[1], c = res[2];
4562 }
4563 a = add32(a, wordAt(bytes, i, Endian.Little));
4564 b = add32(b, wordAt(bytes, i + 4, Endian.Little));
4565 // the first byte of c is reserved for the length
4566 c = add32(c, len);
4567 c = add32(c, wordAt(bytes, i + 8, Endian.Little) << 8);
4568 return mix(a, b, c)[2];
4569 }
4570 // clang-format off
4571 function mix(a, b, c) {
4572 a = sub32(a, b);
4573 a = sub32(a, c);
4574 a ^= c >>> 13;
4575 b = sub32(b, c);
4576 b = sub32(b, a);
4577 b ^= a << 8;
4578 c = sub32(c, a);
4579 c = sub32(c, b);
4580 c ^= b >>> 13;
4581 a = sub32(a, b);
4582 a = sub32(a, c);
4583 a ^= c >>> 12;
4584 b = sub32(b, c);
4585 b = sub32(b, a);
4586 b ^= a << 16;
4587 c = sub32(c, a);
4588 c = sub32(c, b);
4589 c ^= b >>> 5;
4590 a = sub32(a, b);
4591 a = sub32(a, c);
4592 a ^= c >>> 3;
4593 b = sub32(b, c);
4594 b = sub32(b, a);
4595 b ^= a << 10;
4596 c = sub32(c, a);
4597 c = sub32(c, b);
4598 c ^= b >>> 15;
4599 return [a, b, c];
4600 }
4601 // clang-format on
4602 // Utils
4603 var Endian;
4604 (function (Endian) {
4605 Endian[Endian["Little"] = 0] = "Little";
4606 Endian[Endian["Big"] = 1] = "Big";
4607 })(Endian || (Endian = {}));
4608 function add32(a, b) {
4609 return add32to64(a, b)[1];
4610 }
4611 function add32to64(a, b) {
4612 const low = (a & 0xffff) + (b & 0xffff);
4613 const high = (a >>> 16) + (b >>> 16) + (low >>> 16);
4614 return [high >>> 16, (high << 16) | (low & 0xffff)];
4615 }
4616 function add64(a, b) {
4617 const ah = a[0], al = a[1];
4618 const bh = b[0], bl = b[1];
4619 const result = add32to64(al, bl);
4620 const carry = result[0];
4621 const l = result[1];
4622 const h = add32(add32(ah, bh), carry);
4623 return [h, l];
4624 }
4625 function sub32(a, b) {
4626 const low = (a & 0xffff) - (b & 0xffff);
4627 const high = (a >> 16) - (b >> 16) + (low >> 16);
4628 return (high << 16) | (low & 0xffff);
4629 }
4630 // Rotate a 32b number left `count` position
4631 function rol32(a, count) {
4632 return (a << count) | (a >>> (32 - count));
4633 }
4634 // Rotate a 64b number left `count` position
4635 function rol64(num, count) {
4636 const hi = num[0], lo = num[1];
4637 const h = (hi << count) | (lo >>> (32 - count));
4638 const l = (lo << count) | (hi >>> (32 - count));
4639 return [h, l];
4640 }
4641 function bytesToWords32(bytes, endian) {
4642 const size = (bytes.length + 3) >>> 2;
4643 const words32 = [];
4644 for (let i = 0; i < size; i++) {
4645 words32[i] = wordAt(bytes, i * 4, endian);
4646 }
4647 return words32;
4648 }
4649 function byteAt(bytes, index) {
4650 return index >= bytes.length ? 0 : bytes[index];
4651 }
4652 function wordAt(bytes, index, endian) {
4653 let word = 0;
4654 if (endian === Endian.Big) {
4655 for (let i = 0; i < 4; i++) {
4656 word += byteAt(bytes, index + i) << (24 - 8 * i);
4657 }
4658 }
4659 else {
4660 for (let i = 0; i < 4; i++) {
4661 word += byteAt(bytes, index + i) << 8 * i;
4662 }
4663 }
4664 return word;
4665 }
4666 function words32ToByteString(words32) {
4667 return words32.reduce((bytes, word) => bytes.concat(word32ToByteString(word)), []);
4668 }
4669 function word32ToByteString(word) {
4670 let bytes = [];
4671 for (let i = 0; i < 4; i++) {
4672 bytes.push((word >>> 8 * (3 - i)) & 0xff);
4673 }
4674 return bytes;
4675 }
4676 function bytesToHexString(bytes) {
4677 let hex = '';
4678 for (let i = 0; i < bytes.length; i++) {
4679 const b = byteAt(bytes, i);
4680 hex += (b >>> 4).toString(16) + (b & 0x0f).toString(16);
4681 }
4682 return hex.toLowerCase();
4683 }
4684 /**
4685 * Create a shared exponentiation pool for base-256 computations. This shared pool provides memoized
4686 * power-of-256 results with memoized power-of-two computations for efficient multiplication.
4687 *
4688 * For our purposes, this can be safely stored as a global without memory concerns. The reason is
4689 * that we encode two words, so only need the 0th (for the low word) and 4th (for the high word)
4690 * exponent.
4691 */
4692 const base256 = new BigIntExponentiation(256);
4693 /**
4694 * Represents two 32-bit words as a single decimal number. This requires a big integer storage
4695 * model as JS numbers are not accurate enough to represent the 64-bit number.
4696 *
4697 * Based on https://www.danvk.org/hex2dec.html
4698 */
4699 function wordsToDecimalString(hi, lo) {
4700 // Encode the four bytes in lo in the lower digits of the decimal number.
4701 // Note: the multiplication results in lo itself but represented by a big integer using its
4702 // decimal digits.
4703 const decimal = base256.toThePowerOf(0).multiplyBy(lo);
4704 // Encode the four bytes in hi above the four lo bytes. lo is a maximum of (2^8)^4, which is why
4705 // this multiplication factor is applied.
4706 base256.toThePowerOf(4).multiplyByAndAddTo(hi, decimal);
4707 return decimal.toString();
4708 }
4709
4710 /**
4711 * @license
4712 * Copyright Google LLC All Rights Reserved.
4713 *
4714 * Use of this source code is governed by an MIT-style license that can be
4715 * found in the LICENSE file at https://angular.io/license
4716 */
4717 // XMB/XTB placeholders can only contain A-Z, 0-9 and _
4718 function toPublicName(internalName) {
4719 return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_');
4720 }
4721
4722 /**
4723 * @license
4724 * Copyright Google LLC All Rights Reserved.
4725 *
4726 * Use of this source code is governed by an MIT-style license that can be
4727 * found in the LICENSE file at https://angular.io/license
4728 */
4729 /* Closure variables holding messages must be named `MSG_[A-Z0-9]+` */
4730 const CLOSURE_TRANSLATION_VAR_PREFIX = 'MSG_';
4731 /**
4732 * Prefix for non-`goog.getMsg` i18n-related vars.
4733 * Note: the prefix uses lowercase characters intentionally due to a Closure behavior that
4734 * considers variables like `I18N_0` as constants and throws an error when their value changes.
4735 */
4736 const TRANSLATION_VAR_PREFIX = 'i18n_';
4737 /** Name of the i18n attributes **/
4738 const I18N_ATTR = 'i18n';
4739 const I18N_ATTR_PREFIX = 'i18n-';
4740 /** Prefix of var expressions used in ICUs */
4741 const I18N_ICU_VAR_PREFIX = 'VAR_';
4742 /** Prefix of ICU expressions for post processing */
4743 const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
4744 /** Placeholder wrapper for i18n expressions **/
4745 const I18N_PLACEHOLDER_SYMBOL = '�';
4746 function isI18nAttribute(name) {
4747 return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
4748 }
4749 function isI18nRootNode(meta) {
4750 return meta instanceof Message;
4751 }
4752 function isSingleI18nIcu(meta) {
4753 return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu$1;
4754 }
4755 function hasI18nMeta(node) {
4756 return !!node.i18n;
4757 }
4758 function hasI18nAttrs(element) {
4759 return element.attrs.some((attr) => isI18nAttribute(attr.name));
4760 }
4761 function icuFromI18nMessage(message) {
4762 return message.nodes[0];
4763 }
4764 function wrapI18nPlaceholder(content, contextId = 0) {
4765 const blockId = contextId > 0 ? `:${contextId}` : '';
4766 return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`;
4767 }
4768 function assembleI18nBoundString(strings, bindingStartIndex = 0, contextId = 0) {
4769 if (!strings.length)
4770 return '';
4771 let acc = '';
4772 const lastIdx = strings.length - 1;
4773 for (let i = 0; i < lastIdx; i++) {
4774 acc += `${strings[i]}${wrapI18nPlaceholder(bindingStartIndex + i, contextId)}`;
4775 }
4776 acc += strings[lastIdx];
4777 return acc;
4778 }
4779 function getSeqNumberGenerator(startsAt = 0) {
4780 let current = startsAt;
4781 return () => current++;
4782 }
4783 function placeholdersToParams(placeholders) {
4784 const params = {};
4785 placeholders.forEach((values, key) => {
4786 params[key] = literal(values.length > 1 ? `[${values.join('|')}]` : values[0]);
4787 });
4788 return params;
4789 }
4790 function updatePlaceholderMap(map, name, ...values) {
4791 const current = map.get(name) || [];
4792 current.push(...values);
4793 map.set(name, current);
4794 }
4795 function assembleBoundTextPlaceholders(meta, bindingStartIndex = 0, contextId = 0) {
4796 const startIdx = bindingStartIndex;
4797 const placeholders = new Map();
4798 const node = meta instanceof Message ? meta.nodes.find(node => node instanceof Container) : meta;
4799 if (node) {
4800 node
4801 .children
4802 .filter((child) => child instanceof Placeholder)
4803 .forEach((child, idx) => {
4804 const content = wrapI18nPlaceholder(startIdx + idx, contextId);
4805 updatePlaceholderMap(placeholders, child.name, content);
4806 });
4807 }
4808 return placeholders;
4809 }
4810 /**
4811 * Format the placeholder names in a map of placeholders to expressions.
4812 *
4813 * The placeholder names are converted from "internal" format (e.g. `START_TAG_DIV_1`) to "external"
4814 * format (e.g. `startTagDiv_1`).
4815 *
4816 * @param params A map of placeholder names to expressions.
4817 * @param useCamelCase whether to camelCase the placeholder name when formatting.
4818 * @returns A new map of formatted placeholder names to expressions.
4819 */
4820 function i18nFormatPlaceholderNames(params = {}, useCamelCase) {
4821 const _params = {};
4822 if (params && Object.keys(params).length) {
4823 Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key, useCamelCase)] = params[key]);
4824 }
4825 return _params;
4826 }
4827 /**
4828 * Converts internal placeholder names to public-facing format
4829 * (for example to use in goog.getMsg call).
4830 * Example: `START_TAG_DIV_1` is converted to `startTagDiv_1`.
4831 *
4832 * @param name The placeholder name that should be formatted
4833 * @returns Formatted placeholder name
4834 */
4835 function formatI18nPlaceholderName(name, useCamelCase = true) {
4836 const publicName = toPublicName(name);
4837 if (!useCamelCase) {
4838 return publicName;
4839 }
4840 const chunks = publicName.split('_');
4841 if (chunks.length === 1) {
4842 // if no "_" found - just lowercase the value
4843 return name.toLowerCase();
4844 }
4845 let postfix;
4846 // eject last element if it's a number
4847 if (/^\d+$/.test(chunks[chunks.length - 1])) {
4848 postfix = chunks.pop();
4849 }
4850 let raw = chunks.shift().toLowerCase();
4851 if (chunks.length) {
4852 raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join('');
4853 }
4854 return postfix ? `${raw}_${postfix}` : raw;
4855 }
4856 /**
4857 * Generates a prefix for translation const name.
4858 *
4859 * @param extra Additional local prefix that should be injected into translation var name
4860 * @returns Complete translation const prefix
4861 */
4862 function getTranslationConstPrefix(extra) {
4863 return `${CLOSURE_TRANSLATION_VAR_PREFIX}${extra}`.toUpperCase();
4864 }
4865 /**
4866 * Generate AST to declare a variable. E.g. `var I18N_1;`.
4867 * @param variable the name of the variable to declare.
4868 */
4869 function declareI18nVariable(variable) {
4870 return new DeclareVarStmt(variable.name, undefined, INFERRED_TYPE, undefined, variable.sourceSpan);
4871 }
4872
4873 /**
4874 * @license
4875 * Copyright Google LLC All Rights Reserved.
4876 *
4877 * Use of this source code is governed by an MIT-style license that can be
4878 * found in the LICENSE file at https://angular.io/license
4879 */
4880 /**
4881 * Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in
4882 * quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may
4883 * bot work in some cases when object keys are mangled by minifier.
4884 *
4885 * TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with
4886 * inputs that contain potentially unsafe chars.
4887 */
4888 const UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/;
4889 /** Name of the temporary to use during data binding */
4890 const TEMPORARY_NAME = '_t';
4891 /** Name of the context parameter passed into a template function */
4892 const CONTEXT_NAME = 'ctx';
4893 /** Name of the RenderFlag passed into a template function */
4894 const RENDER_FLAGS = 'rf';
4895 /** The prefix reference variables */
4896 const REFERENCE_PREFIX = '_r';
4897 /** The name of the implicit context reference */
4898 const IMPLICIT_REFERENCE = '$implicit';
4899 /** Non bindable attribute name **/
4900 const NON_BINDABLE_ATTR = 'ngNonBindable';
4901 /**
4902 * Creates an allocator for a temporary variable.
4903 *
4904 * A variable declaration is added to the statements the first time the allocator is invoked.
4905 */
4906 function temporaryAllocator(statements, name) {
4907 let temp = null;
4908 return () => {
4909 if (!temp) {
4910 statements.push(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE));
4911 temp = variable(name);
4912 }
4913 return temp;
4914 };
4915 }
4916 function unsupported(feature) {
4917 if (this) {
4918 throw new Error(`Builder ${this.constructor.name} doesn't support ${feature} yet`);
4919 }
4920 throw new Error(`Feature ${feature} is not supported yet`);
4921 }
4922 function invalid$1(arg) {
4923 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
4924 }
4925 function asLiteral(value) {
4926 if (Array.isArray(value)) {
4927 return literalArr(value.map(asLiteral));
4928 }
4929 return literal(value, INFERRED_TYPE);
4930 }
4931 function conditionallyCreateMapObjectLiteral(keys, keepDeclared) {
4932 if (Object.getOwnPropertyNames(keys).length > 0) {
4933 return mapToExpression(keys, keepDeclared);
4934 }
4935 return null;
4936 }
4937 function mapToExpression(map, keepDeclared) {
4938 return literalMap(Object.getOwnPropertyNames(map).map(key => {
4939 // canonical syntax: `dirProp: publicProp`
4940 // if there is no `:`, use dirProp = elProp
4941 const value = map[key];
4942 let declaredName;
4943 let publicName;
4944 let minifiedName;
4945 let needsDeclaredName;
4946 if (Array.isArray(value)) {
4947 [publicName, declaredName] = value;
4948 minifiedName = key;
4949 needsDeclaredName = publicName !== declaredName;
4950 }
4951 else {
4952 [declaredName, publicName] = splitAtColon(key, [key, value]);
4953 minifiedName = declaredName;
4954 // Only include the declared name if extracted from the key, i.e. the key contains a colon.
4955 // Otherwise the declared name should be omitted even if it is different from the public name,
4956 // as it may have already been minified.
4957 needsDeclaredName = publicName !== declaredName && key.includes(':');
4958 }
4959 return {
4960 key: minifiedName,
4961 // put quotes around keys that contain potentially unsafe characters
4962 quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName),
4963 value: (keepDeclared && needsDeclaredName) ?
4964 literalArr([asLiteral(publicName), asLiteral(declaredName)]) :
4965 asLiteral(publicName)
4966 };
4967 }));
4968 }
4969 /**
4970 * Remove trailing null nodes as they are implied.
4971 */
4972 function trimTrailingNulls(parameters) {
4973 while (isNull(parameters[parameters.length - 1])) {
4974 parameters.pop();
4975 }
4976 return parameters;
4977 }
4978 function getQueryPredicate(query, constantPool) {
4979 if (Array.isArray(query.predicate)) {
4980 let predicate = [];
4981 query.predicate.forEach((selector) => {
4982 // Each item in predicates array may contain strings with comma-separated refs
4983 // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them
4984 // as separate array entities
4985 const selectors = selector.split(',').map(token => literal(token.trim()));
4986 predicate.push(...selectors);
4987 });
4988 return constantPool.getConstLiteral(literalArr(predicate), true);
4989 }
4990 else {
4991 return query.predicate;
4992 }
4993 }
4994 /**
4995 * A representation for an object literal used during codegen of definition objects. The generic
4996 * type `T` allows to reference a documented type of the generated structure, such that the
4997 * property names that are set can be resolved to their documented declaration.
4998 */
4999 class DefinitionMap {
5000 constructor() {
5001 this.values = [];
5002 }
5003 set(key, value) {
5004 if (value) {
5005 this.values.push({ key: key, value, quoted: false });
5006 }
5007 }
5008 toLiteralMap() {
5009 return literalMap(this.values);
5010 }
5011 }
5012 /**
5013 * Extract a map of properties to values for a given element or template node, which can be used
5014 * by the directive matching machinery.
5015 *
5016 * @param elOrTpl the element or template in question
5017 * @return an object set up for directive matching. For attributes on the element/template, this
5018 * object maps a property name to its (static) value. For any bindings, this map simply maps the
5019 * property name to an empty string.
5020 */
5021 function getAttrsForDirectiveMatching(elOrTpl) {
5022 const attributesMap = {};
5023 if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') {
5024 elOrTpl.templateAttrs.forEach(a => attributesMap[a.name] = '');
5025 }
5026 else {
5027 elOrTpl.attributes.forEach(a => {
5028 if (!isI18nAttribute(a.name)) {
5029 attributesMap[a.name] = a.value;
5030 }
5031 });
5032 elOrTpl.inputs.forEach(i => {
5033 attributesMap[i.name] = '';
5034 });
5035 elOrTpl.outputs.forEach(o => {
5036 attributesMap[o.name] = '';
5037 });
5038 }
5039 return attributesMap;
5040 }
5041 /** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */
5042 function chainedInstruction(reference, calls, span) {
5043 let expression = importExpr(reference, null, span);
5044 if (calls.length > 0) {
5045 for (let i = 0; i < calls.length; i++) {
5046 expression = expression.callFn(calls[i], span);
5047 }
5048 }
5049 else {
5050 // Add a blank invocation, in case the `calls` array is empty.
5051 expression = expression.callFn([], span);
5052 }
5053 return expression;
5054 }
5055 /**
5056 * Gets the number of arguments expected to be passed to a generated instruction in the case of
5057 * interpolation instructions.
5058 * @param interpolation An interpolation ast
5059 */
5060 function getInterpolationArgsLength(interpolation) {
5061 const { expressions, strings } = interpolation;
5062 if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
5063 // If the interpolation has one interpolated value, but the prefix and suffix are both empty
5064 // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
5065 // `textInterpolate`.
5066 return 1;
5067 }
5068 else {
5069 return expressions.length + strings.length;
5070 }
5071 }
5072
5073 /**
5074 * @license
5075 * Copyright Google LLC All Rights Reserved.
5076 *
5077 * Use of this source code is governed by an MIT-style license that can be
5078 * found in the LICENSE file at https://angular.io/license
5079 */
5080 var R3FactoryDelegateType;
5081 (function (R3FactoryDelegateType) {
5082 R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class";
5083 R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function";
5084 R3FactoryDelegateType[R3FactoryDelegateType["Factory"] = 2] = "Factory";
5085 })(R3FactoryDelegateType || (R3FactoryDelegateType = {}));
5086 var R3FactoryTarget;
5087 (function (R3FactoryTarget) {
5088 R3FactoryTarget[R3FactoryTarget["Directive"] = 0] = "Directive";
5089 R3FactoryTarget[R3FactoryTarget["Component"] = 1] = "Component";
5090 R3FactoryTarget[R3FactoryTarget["Injectable"] = 2] = "Injectable";
5091 R3FactoryTarget[R3FactoryTarget["Pipe"] = 3] = "Pipe";
5092 R3FactoryTarget[R3FactoryTarget["NgModule"] = 4] = "NgModule";
5093 })(R3FactoryTarget || (R3FactoryTarget = {}));
5094 /**
5095 * Resolved type of a dependency.
5096 *
5097 * Occasionally, dependencies will have special significance which is known statically. In that
5098 * case the `R3ResolvedDependencyType` informs the factory generator that a particular dependency
5099 * should be generated specially (usually by calling a special injection function instead of the
5100 * standard one).
5101 */
5102 var R3ResolvedDependencyType;
5103 (function (R3ResolvedDependencyType) {
5104 /**
5105 * A normal token dependency.
5106 */
5107 R3ResolvedDependencyType[R3ResolvedDependencyType["Token"] = 0] = "Token";
5108 /**
5109 * The dependency is for an attribute.
5110 *
5111 * The token expression is a string representing the attribute name.
5112 */
5113 R3ResolvedDependencyType[R3ResolvedDependencyType["Attribute"] = 1] = "Attribute";
5114 /**
5115 * Injecting the `ChangeDetectorRef` token. Needs special handling when injected into a pipe.
5116 */
5117 R3ResolvedDependencyType[R3ResolvedDependencyType["ChangeDetectorRef"] = 2] = "ChangeDetectorRef";
5118 /**
5119 * An invalid dependency (no token could be determined). An error should be thrown at runtime.
5120 */
5121 R3ResolvedDependencyType[R3ResolvedDependencyType["Invalid"] = 3] = "Invalid";
5122 })(R3ResolvedDependencyType || (R3ResolvedDependencyType = {}));
5123 /**
5124 * Construct a factory function expression for the given `R3FactoryMetadata`.
5125 */
5126 function compileFactoryFunction(meta) {
5127 const t = variable('t');
5128 const statements = [];
5129 let ctorDepsType = NONE_TYPE;
5130 // The type to instantiate via constructor invocation. If there is no delegated factory, meaning
5131 // this type is always created by constructor invocation, then this is the type-to-create
5132 // parameter provided by the user (t) if specified, or the current type if not. If there is a
5133 // delegated factory (which is used to create the current type) then this is only the type-to-
5134 // create parameter (t).
5135 const typeForCtor = !isDelegatedMetadata(meta) ?
5136 new BinaryOperatorExpr(BinaryOperator.Or, t, meta.internalType) :
5137 t;
5138 let ctorExpr = null;
5139 if (meta.deps !== null) {
5140 // There is a constructor (either explicitly or implicitly defined).
5141 if (meta.deps !== 'invalid') {
5142 ctorExpr = new InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.injectFn, meta.target === R3FactoryTarget.Pipe));
5143 ctorDepsType = createCtorDepsType(meta.deps);
5144 }
5145 }
5146 else {
5147 const baseFactory = variable(${meta.name}_BaseFactory`);
5148 const getInheritedFactory = importExpr(Identifiers$1.getInheritedFactory);
5149 const baseFactoryStmt = baseFactory
5150 .set(getInheritedFactory.callFn([meta.internalType], /* sourceSpan */ undefined, /* pure */ true))
5151 .toDeclStmt(INFERRED_TYPE, [StmtModifier.Exported, StmtModifier.Final]);
5152 statements.push(baseFactoryStmt);
5153 // There is no constructor, use the base class' factory to construct typeForCtor.
5154 ctorExpr = baseFactory.callFn([typeForCtor]);
5155 }
5156 const ctorExprFinal = ctorExpr;
5157 const body = [];
5158 let retExpr = null;
5159 function makeConditionalFactory(nonCtorExpr) {
5160 const r = variable('r');
5161 body.push(r.set(NULL_EXPR).toDeclStmt());
5162 let ctorStmt = null;
5163 if (ctorExprFinal !== null) {
5164 ctorStmt = r.set(ctorExprFinal).toStmt();
5165 }
5166 else {
5167 ctorStmt = importExpr(Identifiers$1.invalidFactory).callFn([]).toStmt();
5168 }
5169 body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()]));
5170 return r;
5171 }
5172 if (isDelegatedMetadata(meta) && meta.delegateType === R3FactoryDelegateType.Factory) {
5173 const delegateFactory = variable(${meta.name}_BaseFactory`);
5174 const getFactoryOf = importExpr(Identifiers$1.getFactoryOf);
5175 if (meta.delegate.isEquivalent(meta.internalType)) {
5176 throw new Error(`Illegal state: compiling factory that delegates to itself`);
5177 }
5178 const delegateFactoryStmt = delegateFactory.set(getFactoryOf.callFn([meta.delegate])).toDeclStmt(INFERRED_TYPE, [
5179 StmtModifier.Exported, StmtModifier.Final
5180 ]);
5181 statements.push(delegateFactoryStmt);
5182 retExpr = makeConditionalFactory(delegateFactory.callFn([]));
5183 }
5184 else if (isDelegatedMetadata(meta)) {
5185 // This type is created with a delegated factory. If a type parameter is not specified, call
5186 // the factory instead.
5187 const delegateArgs = injectDependencies(meta.delegateDeps, meta.injectFn, meta.target === R3FactoryTarget.Pipe);
5188 // Either call `new delegate(...)` or `delegate(...)` depending on meta.delegateType.
5189 const factoryExpr = new (meta.delegateType === R3FactoryDelegateType.Class ?
5190 InstantiateExpr :
5191 InvokeFunctionExpr)(meta.delegate, delegateArgs);
5192 retExpr = makeConditionalFactory(factoryExpr);
5193 }
5194 else if (isExpressionFactoryMetadata(meta)) {
5195 // TODO(alxhub): decide whether to lower the value here or in the caller
5196 retExpr = makeConditionalFactory(meta.expression);
5197 }
5198 else {
5199 retExpr = ctorExpr;
5200 }
5201 if (retExpr !== null) {
5202 body.push(new ReturnStatement(retExpr));
5203 }
5204 else {
5205 body.push(importExpr(Identifiers$1.invalidFactory).callFn([]).toStmt());
5206 }
5207 return {
5208 factory: fn([new FnParam('t', DYNAMIC_TYPE)], body, INFERRED_TYPE, undefined, `${meta.name}_Factory`),
5209 statements,
5210 type: expressionType(importExpr(Identifiers$1.FactoryDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType]))
5211 };
5212 }
5213 function injectDependencies(deps, injectFn, isPipe) {
5214 return deps.map((dep, index) => compileInjectDependency(dep, injectFn, isPipe, index));
5215 }
5216 function compileInjectDependency(dep, injectFn, isPipe, index) {
5217 // Interpret the dependency according to its resolved type.
5218 switch (dep.resolved) {
5219 case R3ResolvedDependencyType.Token:
5220 case R3ResolvedDependencyType.ChangeDetectorRef:
5221 // Build up the injection flags according to the metadata.
5222 const flags = 0 /* Default */ | (dep.self ? 2 /* Self */ : 0) |
5223 (dep.skipSelf ? 4 /* SkipSelf */ : 0) | (dep.host ? 1 /* Host */ : 0) |
5224 (dep.optional ? 8 /* Optional */ : 0);
5225 // If this dependency is optional or otherwise has non-default flags, then additional
5226 // parameters describing how to inject the dependency must be passed to the inject function
5227 // that's being used.
5228 let flagsParam = (flags !== 0 /* Default */ || dep.optional) ? literal(flags) : null;
5229 // We have a separate instruction for injecting ChangeDetectorRef into a pipe.
5230 if (isPipe && dep.resolved === R3ResolvedDependencyType.ChangeDetectorRef) {
5231 return importExpr(Identifiers$1.injectPipeChangeDetectorRef).callFn(flagsParam ? [flagsParam] : []);
5232 }
5233 // Build up the arguments to the injectFn call.
5234 const injectArgs = [dep.token];
5235 if (flagsParam) {
5236 injectArgs.push(flagsParam);
5237 }
5238 return importExpr(injectFn).callFn(injectArgs);
5239 case R3ResolvedDependencyType.Attribute:
5240 // In the case of attributes, the attribute name in question is given as the token.
5241 return importExpr(Identifiers$1.injectAttribute).callFn([dep.token]);
5242 case R3ResolvedDependencyType.Invalid:
5243 return importExpr(Identifiers$1.invalidFactoryDep).callFn([literal(index)]);
5244 default:
5245 return unsupported(`Unknown R3ResolvedDependencyType: ${R3ResolvedDependencyType[dep.resolved]}`);
5246 }
5247 }
5248 function createCtorDepsType(deps) {
5249 let hasTypes = false;
5250 const attributeTypes = deps.map(dep => {
5251 const type = createCtorDepType(dep);
5252 if (type !== null) {
5253 hasTypes = true;
5254 return type;
5255 }
5256 else {
5257 return literal(null);
5258 }
5259 });
5260 if (hasTypes) {
5261 return expressionType(literalArr(attributeTypes));
5262 }
5263 else {
5264 return NONE_TYPE;
5265 }
5266 }
5267 function createCtorDepType(dep) {
5268 const entries = [];
5269 if (dep.resolved === R3ResolvedDependencyType.Attribute) {
5270 if (dep.attribute !== null) {
5271 entries.push({ key: 'attribute', value: dep.attribute, quoted: false });
5272 }
5273 }
5274 if (dep.optional) {
5275 entries.push({ key: 'optional', value: literal(true), quoted: false });
5276 }
5277 if (dep.host) {
5278 entries.push({ key: 'host', value: literal(true), quoted: false });
5279 }
5280 if (dep.self) {
5281 entries.push({ key: 'self', value: literal(true), quoted: false });
5282 }
5283 if (dep.skipSelf) {
5284 entries.push({ key: 'skipSelf', value: literal(true), quoted: false });
5285 }
5286 return entries.length > 0 ? literalMap(entries) : null;
5287 }
5288 function isDelegatedMetadata(meta) {
5289 return meta.delegateType !== undefined;
5290 }
5291 function isExpressionFactoryMetadata(meta) {
5292 return meta.expression !== undefined;
5293 }
5294
5295 /**
5296 * @license
5297 * Copyright Google LLC All Rights Reserved.
5298 *
5299 * Use of this source code is governed by an MIT-style license that can be
5300 * found in the LICENSE file at https://angular.io/license
5301 */
5302 function compileInjectable(meta) {
5303 let result = null;
5304 const factoryMeta = {
5305 name: meta.name,
5306 type: meta.type,
5307 internalType: meta.internalType,
5308 typeArgumentCount: meta.typeArgumentCount,
5309 deps: [],
5310 injectFn: Identifiers.inject,
5311 target: R3FactoryTarget.Injectable,
5312 };
5313 if (meta.useClass !== undefined) {
5314 // meta.useClass has two modes of operation. Either deps are specified, in which case `new` is
5315 // used to instantiate the class with dependencies injected, or deps are not specified and
5316 // the factory of the class is used to instantiate it.
5317 //
5318 // A special case exists for useClass: Type where Type is the injectable type itself and no
5319 // deps are specified, in which case 'useClass' is effectively ignored.
5320 const useClassOnSelf = meta.useClass.isEquivalent(meta.internalType);
5321 let deps = undefined;
5322 if (meta.userDeps !== undefined) {
5323 deps = meta.userDeps;
5324 }
5325 if (deps !== undefined) {
5326 // factory: () => new meta.useClass(...deps)
5327 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useClass, delegateDeps: deps, delegateType: R3FactoryDelegateType.Class }));
5328 }
5329 else if (useClassOnSelf) {
5330 result = compileFactoryFunction(factoryMeta);
5331 }
5332 else {
5333 result = delegateToFactory(meta.type.value, meta.useClass);
5334 }
5335 }
5336 else if (meta.useFactory !== undefined) {
5337 if (meta.userDeps !== undefined) {
5338 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useFactory, delegateDeps: meta.userDeps || [], delegateType: R3FactoryDelegateType.Function }));
5339 }
5340 else {
5341 result = {
5342 statements: [],
5343 factory: fn([], [new ReturnStatement(meta.useFactory.callFn([]))])
5344 };
5345 }
5346 }
5347 else if (meta.useValue !== undefined) {
5348 // Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for
5349 // client code because meta.useValue is an Expression which will be defined even if the actual
5350 // value is undefined.
5351 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: meta.useValue }));
5352 }
5353 else if (meta.useExisting !== undefined) {
5354 // useExisting is an `inject` call on the existing token.
5355 result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: importExpr(Identifiers.inject).callFn([meta.useExisting]) }));
5356 }
5357 else {
5358 result = delegateToFactory(meta.type.value, meta.internalType);
5359 }
5360 const token = meta.internalType;
5361 const injectableProps = { token, factory: result.factory };
5362 // Only generate providedIn property if it has a non-null value
5363 if (meta.providedIn.value !== null) {
5364 injectableProps.providedIn = meta.providedIn;
5365 }
5366 const expression = importExpr(Identifiers.ɵɵdefineInjectable).callFn([mapToMapExpression(injectableProps)]);
5367 const type = new ExpressionType(importExpr(Identifiers.InjectableDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount)]));
5368 return {
5369 expression,
5370 type,
5371 statements: result.statements,
5372 };
5373 }
5374 function delegateToFactory(type, internalType) {
5375 return {
5376 statements: [],
5377 // If types are the same, we can generate `factory: type.ɵfac`
5378 // If types are different, we have to generate a wrapper function to ensure
5379 // the internal type has been resolved (`factory: function(t) { return type.ɵfac(t); }`)
5380 factory: type.node === internalType.node ?
5381 internalType.prop('ɵfac') :
5382 fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement(internalType.callMethod('ɵfac', [variable('t')]))])
5383 };
5384 }
5385
5386 /**
5387 * @license
5388 * Copyright Google LLC All Rights Reserved.
5389 *
5390 * Use of this source code is governed by an MIT-style license that can be
5391 * found in the LICENSE file at https://angular.io/license
5392 */
5393 function assertArrayOfStrings(identifier, value) {
5394 if (value == null) {
5395 return;
5396 }
5397 if (!Array.isArray(value)) {
5398 throw new Error(`Expected '${identifier}' to be an array of strings.`);
5399 }
5400 for (let i = 0; i < value.length; i += 1) {
5401 if (typeof value[i] !== 'string') {
5402 throw new Error(`Expected '${identifier}' to be an array of strings.`);
5403 }
5404 }
5405 }
5406 const UNUSABLE_INTERPOLATION_REGEXPS = [
5407 /^\s*$/,
5408 /[<>]/,
5409 /^[{}]$/,
5410 /&(#|[a-z])/i,
5411 /^\/\//,
5412 ];
5413 function assertInterpolationSymbols(identifier, value) {
5414 if (value != null && !(Array.isArray(value) && value.length == 2)) {
5415 throw new Error(`Expected '${identifier}' to be an array, [start, end].`);
5416 }
5417 else if (value != null) {
5418 const start = value[0];
5419 const end = value[1];
5420 // Check for unusable interpolation symbols
5421 UNUSABLE_INTERPOLATION_REGEXPS.forEach(regexp => {
5422 if (regexp.test(start) || regexp.test(end)) {
5423 throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`);
5424 }
5425 });
5426 }
5427 }
5428
5429 /**
5430 * @license
5431 * Copyright Google LLC All Rights Reserved.
5432 *
5433 * Use of this source code is governed by an MIT-style license that can be
5434 * found in the LICENSE file at https://angular.io/license
5435 */
5436 class InterpolationConfig {
5437 constructor(start, end) {
5438 this.start = start;
5439 this.end = end;
5440 }
5441 static fromArray(markers) {
5442 if (!markers) {
5443 return DEFAULT_INTERPOLATION_CONFIG;
5444 }
5445 assertInterpolationSymbols('interpolation', markers);
5446 return new InterpolationConfig(markers[0], markers[1]);
5447 }
5448 }
5449 const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}');
5450
5451 /**
5452 * @license
5453 * Copyright Google LLC All Rights Reserved.
5454 *
5455 * Use of this source code is governed by an MIT-style license that can be
5456 * found in the LICENSE file at https://angular.io/license
5457 */
5458 /**
5459 * In TypeScript, tagged template functions expect a "template object", which is an array of
5460 * "cooked" strings plus a `raw` property that contains an array of "raw" strings. This is
5461 * typically constructed with a function called `__makeTemplateObject(cooked, raw)`, but it may not
5462 * be available in all environments.
5463 *
5464 * This is a JavaScript polyfill that uses __makeTemplateObject when it's available, but otherwise
5465 * creates an inline helper with the same functionality.
5466 *
5467 * In the inline function, if `Object.defineProperty` is available we use that to attach the `raw`
5468 * array.
5469 */
5470 const makeTemplateObjectPolyfill = '(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})';
5471 class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
5472 constructor() {
5473 super(false);
5474 }
5475 visitDeclareClassStmt(stmt, ctx) {
5476 ctx.pushClass(stmt);
5477 this._visitClassConstructor(stmt, ctx);
5478 if (stmt.parent != null) {
5479 ctx.print(stmt, `${stmt.name}.prototype = Object.create(`);
5480 stmt.parent.visitExpression(this, ctx);
5481 ctx.println(stmt, `.prototype);`);
5482 }
5483 stmt.getters.forEach((getter) => this._visitClassGetter(stmt, getter, ctx));
5484 stmt.methods.forEach((method) => this._visitClassMethod(stmt, method, ctx));
5485 ctx.popClass();
5486 return null;
5487 }
5488 _visitClassConstructor(stmt, ctx) {
5489 ctx.print(stmt, `function ${stmt.name}(`);
5490 if (stmt.constructorMethod != null) {
5491 this._visitParams(stmt.constructorMethod.params, ctx);
5492 }
5493 ctx.println(stmt, `) {`);
5494 ctx.incIndent();
5495 if (stmt.constructorMethod != null) {
5496 if (stmt.constructorMethod.body.length > 0) {
5497 ctx.println(stmt, `var self = this;`);
5498 this.visitAllStatements(stmt.constructorMethod.body, ctx);
5499 }
5500 }
5501 ctx.decIndent();
5502 ctx.println(stmt, `}`);
5503 }
5504 _visitClassGetter(stmt, getter, ctx) {
5505 ctx.println(stmt, `Object.defineProperty(${stmt.name}.prototype, '${getter.name}', { get: function() {`);
5506 ctx.incIndent();
5507 if (getter.body.length > 0) {
5508 ctx.println(stmt, `var self = this;`);
5509 this.visitAllStatements(getter.body, ctx);
5510 }
5511 ctx.decIndent();
5512 ctx.println(stmt, `}});`);
5513 }
5514 _visitClassMethod(stmt, method, ctx) {
5515 ctx.print(stmt, `${stmt.name}.prototype.${method.name} = function(`);
5516 this._visitParams(method.params, ctx);
5517 ctx.println(stmt, `) {`);
5518 ctx.incIndent();
5519 if (method.body.length > 0) {
5520 ctx.println(stmt, `var self = this;`);
5521 this.visitAllStatements(method.body, ctx);
5522 }
5523 ctx.decIndent();
5524 ctx.println(stmt, `};`);
5525 }
5526 visitWrappedNodeExpr(ast, ctx) {
5527 throw new Error('Cannot emit a WrappedNodeExpr in Javascript.');
5528 }
5529 visitReadVarExpr(ast, ctx) {
5530 if (ast.builtin === BuiltinVar.This) {
5531 ctx.print(ast, 'self');
5532 }
5533 else if (ast.builtin === BuiltinVar.Super) {
5534 throw new Error(`'super' needs to be handled at a parent ast node, not at the variable level!`);
5535 }
5536 else {
5537 super.visitReadVarExpr(ast, ctx);
5538 }
5539 return null;
5540 }
5541 visitDeclareVarStmt(stmt, ctx) {
5542 ctx.print(stmt, `var ${stmt.name}`);
5543 if (stmt.value) {
5544 ctx.print(stmt, ' = ');
5545 stmt.value.visitExpression(this, ctx);
5546 }
5547 ctx.println(stmt, `;`);
5548 return null;
5549 }
5550 visitCastExpr(ast, ctx) {
5551 ast.value.visitExpression(this, ctx);
5552 return null;
5553 }
5554 visitInvokeFunctionExpr(expr, ctx) {
5555 const fnExpr = expr.fn;
5556 if (fnExpr instanceof ReadVarExpr && fnExpr.builtin === BuiltinVar.Super) {
5557 ctx.currentClass.parent.visitExpression(this, ctx);
5558 ctx.print(expr, `.call(this`);
5559 if (expr.args.length > 0) {
5560 ctx.print(expr, `, `);
5561 this.visitAllExpressions(expr.args, ctx, ',');
5562 }
5563 ctx.print(expr, `)`);
5564 }
5565 else {
5566 super.visitInvokeFunctionExpr(expr, ctx);
5567 }
5568 return null;
5569 }
5570 visitTaggedTemplateExpr(ast, ctx) {
5571 // The following convoluted piece of code is effectively the downlevelled equivalent of
5572 // ```
5573 // tag`...`
5574 // ```
5575 // which is effectively like:
5576 // ```
5577 // tag(__makeTemplateObject(cooked, raw), expression1, expression2, ...);
5578 // ```
5579 const elements = ast.template.elements;
5580 ast.tag.visitExpression(this, ctx);
5581 ctx.print(ast, `(${makeTemplateObjectPolyfill}(`);
5582 ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.text, false)).join(', ')}], `);
5583 ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.rawText, false)).join(', ')}])`);
5584 ast.template.expressions.forEach(expression => {
5585 ctx.print(ast, ', ');
5586 expression.visitExpression(this, ctx);
5587 });
5588 ctx.print(ast, ')');
5589 return null;
5590 }
5591 visitFunctionExpr(ast, ctx) {
5592 ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`);
5593 this._visitParams(ast.params, ctx);
5594 ctx.println(ast, `) {`);
5595 ctx.incIndent();
5596 this.visitAllStatements(ast.statements, ctx);
5597 ctx.decIndent();
5598 ctx.print(ast, `}`);
5599 return null;
5600 }
5601 visitDeclareFunctionStmt(stmt, ctx) {
5602 ctx.print(stmt, `function ${stmt.name}(`);
5603 this._visitParams(stmt.params, ctx);
5604 ctx.println(stmt, `) {`);
5605 ctx.incIndent();
5606 this.visitAllStatements(stmt.statements, ctx);
5607 ctx.decIndent();
5608 ctx.println(stmt, `}`);
5609 return null;
5610 }
5611 visitTryCatchStmt(stmt, ctx) {
5612 ctx.println(stmt, `try {`);
5613 ctx.incIndent();
5614 this.visitAllStatements(stmt.bodyStmts, ctx);
5615 ctx.decIndent();
5616 ctx.println(stmt, `} catch (${CATCH_ERROR_VAR$1.name}) {`);
5617 ctx.incIndent();
5618 const catchStmts = [CATCH_STACK_VAR$1.set(CATCH_ERROR_VAR$1.prop('stack')).toDeclStmt(null, [
5619 StmtModifier.Final
5620 ])].concat(stmt.catchStmts);
5621 this.visitAllStatements(catchStmts, ctx);
5622 ctx.decIndent();
5623 ctx.println(stmt, `}`);
5624 return null;
5625 }
5626 visitLocalizedString(ast, ctx) {
5627 // The following convoluted piece of code is effectively the downlevelled equivalent of
5628 // ```
5629 // $localize `...`
5630 // ```
5631 // which is effectively like:
5632 // ```
5633 // $localize(__makeTemplateObject(cooked, raw), expression1, expression2, ...);
5634 // ```
5635 ctx.print(ast, `$localize(${makeTemplateObjectPolyfill}(`);
5636 const parts = [ast.serializeI18nHead()];
5637 for (let i = 1; i < ast.messageParts.length; i++) {
5638 parts.push(ast.serializeI18nTemplatePart(i));
5639 }
5640 ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.cooked, false)).join(', ')}], `);
5641 ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.raw, false)).join(', ')}])`);
5642 ast.expressions.forEach(expression => {
5643 ctx.print(ast, ', ');
5644 expression.visitExpression(this, ctx);
5645 });
5646 ctx.print(ast, ')');
5647 return null;
5648 }
5649 _visitParams(params, ctx) {
5650 this.visitAllObjects(param => ctx.print(null, param.name), params, ctx, ',');
5651 }
5652 getBuiltinMethodName(method) {
5653 let name;
5654 switch (method) {
5655 case BuiltinMethod.ConcatArray:
5656 name = 'concat';
5657 break;
5658 case BuiltinMethod.SubscribeObservable:
5659 name = 'subscribe';
5660 break;
5661 case BuiltinMethod.Bind:
5662 name = 'bind';
5663 break;
5664 default:
5665 throw new Error(`Unknown builtin method: ${method}`);
5666 }
5667 return name;
5668 }
5669 }
5670
5671 /**
5672 * @license
5673 * Copyright Google LLC All Rights Reserved.
5674 *
5675 * Use of this source code is governed by an MIT-style license that can be
5676 * found in the LICENSE file at https://angular.io/license
5677 */
5678 /**
5679 * The Trusted Types policy, or null if Trusted Types are not
5680 * enabled/supported, or undefined if the policy has not been created yet.
5681 */
5682 let policy;
5683 /**
5684 * Returns the Trusted Types policy, or null if Trusted Types are not
5685 * enabled/supported. The first call to this function will create the policy.
5686 */
5687 function getPolicy() {
5688 if (policy === undefined) {
5689 policy = null;
5690 if (_global.trustedTypes) {
5691 try {
5692 policy =
5693 _global.trustedTypes.createPolicy('angular#unsafe-jit', {
5694 createScript: (s) => s,
5695 });
5696 }
5697 catch (_a) {
5698 // trustedTypes.createPolicy throws if called with a name that is
5699 // already registered, even in report-only mode. Until the API changes,
5700 // catch the error not to break the applications functionally. In such
5701 // cases, the code will fall back to using strings.
5702 }
5703 }
5704 }
5705 return policy;
5706 }
5707 /**
5708 * Unsafely promote a string to a TrustedScript, falling back to strings when
5709 * Trusted Types are not available.
5710 * @security In particular, it must be assured that the provided string will
5711 * never cause an XSS vulnerability if used in a context that will be
5712 * interpreted and executed as a script by a browser, e.g. when calling eval.
5713 */
5714 function trustedScriptFromString(script) {
5715 var _a;
5716 return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
5717 }
5718 /**
5719 * Unsafely call the Function constructor with the given string arguments.
5720 * @security This is a security-sensitive function; any use of this function
5721 * must go through security review. In particular, it must be assured that it
5722 * is only called from the JIT compiler, as use in other code can lead to XSS
5723 * vulnerabilities.
5724 */
5725 function newTrustedFunctionForJIT(...args) {
5726 if (!_global.trustedTypes) {
5727 // In environments that don't support Trusted Types, fall back to the most
5728 // straightforward implementation:
5729 return new Function(...args);
5730 }
5731 // Chrome currently does not support passing TrustedScript to the Function
5732 // constructor. The following implements the workaround proposed on the page
5733 // below, where the Chromium bug is also referenced:
5734 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
5735 const fnArgs = args.slice(0, -1).join(',');
5736 const fnBody = args[args.length - 1];
5737 const body = `(function anonymous(${fnArgs}
5738) { ${fnBody}
5739})`;
5740 // Using eval directly confuses the compiler and prevents this module from
5741 // being stripped out of JS binaries even if not used. The global['eval']
5742 // indirection fixes that.
5743 const fn = _global['eval'](trustedScriptFromString(body));
5744 if (fn.bind === undefined) {
5745 // Workaround for a browser bug that only exists in Chrome 83, where passing
5746 // a TrustedScript to eval just returns the TrustedScript back without
5747 // evaluating it. In that case, fall back to the most straightforward
5748 // implementation:
5749 return new Function(...args);
5750 }
5751 // To completely mimic the behavior of calling "new Function", two more
5752 // things need to happen:
5753 // 1. Stringifying the resulting function should return its source code
5754 fn.toString = () => body;
5755 // 2. When calling the resulting function, `this` should refer to `global`
5756 return fn.bind(_global);
5757 // When Trusted Types support in Function constructors is widely available,
5758 // the implementation of this function can be simplified to:
5759 // return new Function(...args.map(a => trustedScriptFromString(a)));
5760 }
5761
5762 /**
5763 * @license
5764 * Copyright Google LLC All Rights Reserved.
5765 *
5766 * Use of this source code is governed by an MIT-style license that can be
5767 * found in the LICENSE file at https://angular.io/license
5768 */
5769 /**
5770 * A helper class to manage the evaluation of JIT generated code.
5771 */
5772 class JitEvaluator {
5773 /**
5774 *
5775 * @param sourceUrl The URL of the generated code.
5776 * @param statements An array of Angular statement AST nodes to be evaluated.
5777 * @param reflector A helper used when converting the statements to executable code.
5778 * @param createSourceMaps If true then create a source-map for the generated code and include it
5779 * inline as a source-map comment.
5780 * @returns A map of all the variables in the generated code.
5781 */
5782 evaluateStatements(sourceUrl, statements, reflector, createSourceMaps) {
5783 const converter = new JitEmitterVisitor(reflector);
5784 const ctx = EmitterVisitorContext.createRoot();
5785 // Ensure generated code is in strict mode
5786 if (statements.length > 0 && !isUseStrictStatement(statements[0])) {
5787 statements = [
5788 literal('use strict').toStmt(),
5789 ...statements,
5790 ];
5791 }
5792 converter.visitAllStatements(statements, ctx);
5793 converter.createReturnStmt(ctx);
5794 return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps);
5795 }
5796 /**
5797 * Evaluate a piece of JIT generated code.
5798 * @param sourceUrl The URL of this generated code.
5799 * @param ctx A context object that contains an AST of the code to be evaluated.
5800 * @param vars A map containing the names and values of variables that the evaluated code might
5801 * reference.
5802 * @param createSourceMap If true then create a source-map for the generated code and include it
5803 * inline as a source-map comment.
5804 * @returns The result of evaluating the code.
5805 */
5806 evaluateCode(sourceUrl, ctx, vars, createSourceMap) {
5807 let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`;
5808 const fnArgNames = [];
5809 const fnArgValues = [];
5810 for (const argName in vars) {
5811 fnArgValues.push(vars[argName]);
5812 fnArgNames.push(argName);
5813 }
5814 if (createSourceMap) {
5815 // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise
5816 // E.g. ```
5817 // function anonymous(a,b,c
5818 // /**/) { ... }```
5819 // We don't want to hard code this fact, so we auto detect it via an empty function first.
5820 const emptyFn = newTrustedFunctionForJIT(...fnArgNames.concat('return null;')).toString();
5821 const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
5822 fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`;
5823 }
5824 const fn = newTrustedFunctionForJIT(...fnArgNames.concat(fnBody));
5825 return this.executeFunction(fn, fnArgValues);
5826 }
5827 /**
5828 * Execute a JIT generated function by calling it.
5829 *
5830 * This method can be overridden in tests to capture the functions that are generated
5831 * by this `JitEvaluator` class.
5832 *
5833 * @param fn A function to execute.
5834 * @param args The arguments to pass to the function being executed.
5835 * @returns The return value of the executed function.
5836 */
5837 executeFunction(fn, args) {
5838 return fn(...args);
5839 }
5840 }
5841 /**
5842 * An Angular AST visitor that converts AST nodes into executable JavaScript code.
5843 */
5844 class JitEmitterVisitor extends AbstractJsEmitterVisitor {
5845 constructor(reflector) {
5846 super();
5847 this.reflector = reflector;
5848 this._evalArgNames = [];
5849 this._evalArgValues = [];
5850 this._evalExportedVars = [];
5851 }
5852 createReturnStmt(ctx) {
5853 const stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(resultVar => new LiteralMapEntry(resultVar, variable(resultVar), false))));
5854 stmt.visitStatement(this, ctx);
5855 }
5856 getArgs() {
5857 const result = {};
5858 for (let i = 0; i < this._evalArgNames.length; i++) {
5859 result[this._evalArgNames[i]] = this._evalArgValues[i];
5860 }
5861 return result;
5862 }
5863 visitExternalExpr(ast, ctx) {
5864 this._emitReferenceToExternal(ast, this.reflector.resolveExternalReference(ast.value), ctx);
5865 return null;
5866 }
5867 visitWrappedNodeExpr(ast, ctx) {
5868 this._emitReferenceToExternal(ast, ast.node, ctx);
5869 return null;
5870 }
5871 visitDeclareVarStmt(stmt, ctx) {
5872 if (stmt.hasModifier(StmtModifier.Exported)) {
5873 this._evalExportedVars.push(stmt.name);
5874 }
5875 return super.visitDeclareVarStmt(stmt, ctx);
5876 }
5877 visitDeclareFunctionStmt(stmt, ctx) {
5878 if (stmt.hasModifier(StmtModifier.Exported)) {
5879 this._evalExportedVars.push(stmt.name);
5880 }
5881 return super.visitDeclareFunctionStmt(stmt, ctx);
5882 }
5883 visitDeclareClassStmt(stmt, ctx) {
5884 if (stmt.hasModifier(StmtModifier.Exported)) {
5885 this._evalExportedVars.push(stmt.name);
5886 }
5887 return super.visitDeclareClassStmt(stmt, ctx);
5888 }
5889 _emitReferenceToExternal(ast, value, ctx) {
5890 let id = this._evalArgValues.indexOf(value);
5891 if (id === -1) {
5892 id = this._evalArgValues.length;
5893 this._evalArgValues.push(value);
5894 const name = identifierName({ reference: value }) || 'val';
5895 this._evalArgNames.push(`jit_${name}_${id}`);
5896 }
5897 ctx.print(ast, this._evalArgNames[id]);
5898 }
5899 }
5900 function isUseStrictStatement(statement) {
5901 return statement.isEquivalent(literal('use strict').toStmt());
5902 }
5903
5904 /**
5905 * @license
5906 * Copyright Google LLC All Rights Reserved.
5907 *
5908 * Use of this source code is governed by an MIT-style license that can be
5909 * found in the LICENSE file at https://angular.io/license
5910 */
5911 const $EOF = 0;
5912 const $BSPACE = 8;
5913 const $TAB = 9;
5914 const $LF = 10;
5915 const $VTAB = 11;
5916 const $FF = 12;
5917 const $CR = 13;
5918 const $SPACE = 32;
5919 const $BANG = 33;
5920 const $DQ = 34;
5921 const $HASH = 35;
5922 const $$ = 36;
5923 const $PERCENT = 37;
5924 const $AMPERSAND = 38;
5925 const $SQ = 39;
5926 const $LPAREN = 40;
5927 const $RPAREN = 41;
5928 const $STAR = 42;
5929 const $PLUS = 43;
5930 const $COMMA = 44;
5931 const $MINUS = 45;
5932 const $PERIOD = 46;
5933 const $SLASH = 47;
5934 const $COLON = 58;
5935 const $SEMICOLON = 59;
5936 const $LT = 60;
5937 const $EQ = 61;
5938 const $GT = 62;
5939 const $QUESTION = 63;
5940 const $0 = 48;
5941 const $7 = 55;
5942 const $9 = 57;
5943 const $A = 65;
5944 const $E = 69;
5945 const $F = 70;
5946 const $X = 88;
5947 const $Z = 90;
5948 const $LBRACKET = 91;
5949 const $BACKSLASH = 92;
5950 const $RBRACKET = 93;
5951 const $CARET = 94;
5952 const $_ = 95;
5953 const $a = 97;
5954 const $b = 98;
5955 const $e = 101;
5956 const $f = 102;
5957 const $n = 110;
5958 const $r = 114;
5959 const $t = 116;
5960 const $u = 117;
5961 const $v = 118;
5962 const $x = 120;
5963 const $z = 122;
5964 const $LBRACE = 123;
5965 const $BAR = 124;
5966 const $RBRACE = 125;
5967 const $NBSP = 160;
5968 const $BT = 96;
5969 function isWhitespace(code) {
5970 return (code >= $TAB && code <= $SPACE) || (code == $NBSP);
5971 }
5972 function isDigit(code) {
5973 return $0 <= code && code <= $9;
5974 }
5975 function isAsciiLetter(code) {
5976 return code >= $a && code <= $z || code >= $A && code <= $Z;
5977 }
5978 function isAsciiHexDigit(code) {
5979 return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code);
5980 }
5981 function isNewLine(code) {
5982 return code === $LF || code === $CR;
5983 }
5984 function isOctalDigit(code) {
5985 return $0 <= code && code <= $7;
5986 }
5987
5988 /**
5989 * @license
5990 * Copyright Google LLC All Rights Reserved.
5991 *
5992 * Use of this source code is governed by an MIT-style license that can be
5993 * found in the LICENSE file at https://angular.io/license
5994 */
5995 class ParseLocation {
5996 constructor(file, offset, line, col) {
5997 this.file = file;
5998 this.offset = offset;
5999 this.line = line;
6000 this.col = col;
6001 }
6002 toString() {
6003 return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url;
6004 }
6005 moveBy(delta) {
6006 const source = this.file.content;
6007 const len = source.length;
6008 let offset = this.offset;
6009 let line = this.line;
6010 let col = this.col;
6011 while (offset > 0 && delta < 0) {
6012 offset--;
6013 delta++;
6014 const ch = source.charCodeAt(offset);
6015 if (ch == $LF) {
6016 line--;
6017 const priorLine = source.substr(0, offset - 1).lastIndexOf(String.fromCharCode($LF));
6018 col = priorLine > 0 ? offset - priorLine : offset;
6019 }
6020 else {
6021 col--;
6022 }
6023 }
6024 while (offset < len && delta > 0) {
6025 const ch = source.charCodeAt(offset);
6026 offset++;
6027 delta--;
6028 if (ch == $LF) {
6029 line++;
6030 col = 0;
6031 }
6032 else {
6033 col++;
6034 }
6035 }
6036 return new ParseLocation(this.file, offset, line, col);
6037 }
6038 // Return the source around the location
6039 // Up to `maxChars` or `maxLines` on each side of the location
6040 getContext(maxChars, maxLines) {
6041 const content = this.file.content;
6042 let startOffset = this.offset;
6043 if (startOffset != null) {
6044 if (startOffset > content.length - 1) {
6045 startOffset = content.length - 1;
6046 }
6047 let endOffset = startOffset;
6048 let ctxChars = 0;
6049 let ctxLines = 0;
6050 while (ctxChars < maxChars && startOffset > 0) {
6051 startOffset--;
6052 ctxChars++;
6053 if (content[startOffset] == '\n') {
6054 if (++ctxLines == maxLines) {
6055 break;
6056 }
6057 }
6058 }
6059 ctxChars = 0;
6060 ctxLines = 0;
6061 while (ctxChars < maxChars && endOffset < content.length - 1) {
6062 endOffset++;
6063 ctxChars++;
6064 if (content[endOffset] == '\n') {
6065 if (++ctxLines == maxLines) {
6066 break;
6067 }
6068 }
6069 }
6070 return {
6071 before: content.substring(startOffset, this.offset),
6072 after: content.substring(this.offset, endOffset + 1),
6073 };
6074 }
6075 return null;
6076 }
6077 }
6078 class ParseSourceFile {
6079 constructor(content, url) {
6080 this.content = content;
6081 this.url = url;
6082 }
6083 }
6084 class ParseSourceSpan {
6085 /**
6086 * Create an object that holds information about spans of tokens/nodes captured during
6087 * lexing/parsing of text.
6088 *
6089 * @param start
6090 * The location of the start of the span (having skipped leading trivia).
6091 * Skipping leading trivia makes source-spans more "user friendly", since things like HTML
6092 * elements will appear to begin at the start of the opening tag, rather than at the start of any
6093 * leading trivia, which could include newlines.
6094 *
6095 * @param end
6096 * The location of the end of the span.
6097 *
6098 * @param fullStart
6099 * The start of the token without skipping the leading trivia.
6100 * This is used by tooling that splits tokens further, such as extracting Angular interpolations
6101 * from text tokens. Such tooling creates new source-spans relative to the original token's
6102 * source-span. If leading trivia characters have been skipped then the new source-spans may be
6103 * incorrectly offset.
6104 *
6105 * @param details
6106 * Additional information (such as identifier names) that should be associated with the span.
6107 */
6108 constructor(start, end, fullStart = start, details = null) {
6109 this.start = start;
6110 this.end = end;
6111 this.fullStart = fullStart;
6112 this.details = details;
6113 }
6114 toString() {
6115 return this.start.file.content.substring(this.start.offset, this.end.offset);
6116 }
6117 }
6118 var ParseErrorLevel;
6119 (function (ParseErrorLevel) {
6120 ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING";
6121 ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR";
6122 })(ParseErrorLevel || (ParseErrorLevel = {}));
6123 class ParseError {
6124 constructor(span, msg, level = ParseErrorLevel.ERROR) {
6125 this.span = span;
6126 this.msg = msg;
6127 this.level = level;
6128 }
6129 contextualMessage() {
6130 const ctx = this.span.start.getContext(100, 3);
6131 return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` :
6132 this.msg;
6133 }
6134 toString() {
6135 const details = this.span.details ? `, ${this.span.details}` : '';
6136 return `${this.contextualMessage()}: ${this.span.start}${details}`;
6137 }
6138 }
6139 /**
6140 * Generates Source Span object for a given R3 Type for JIT mode.
6141 *
6142 * @param kind Component or Directive.
6143 * @param typeName name of the Component or Directive.
6144 * @param sourceUrl reference to Component or Directive source.
6145 * @returns instance of ParseSourceSpan that represent a given Component or Directive.
6146 */
6147 function r3JitTypeSourceSpan(kind, typeName, sourceUrl) {
6148 const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`;
6149 const sourceFile = new ParseSourceFile('', sourceFileName);
6150 return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
6151 }
6152
6153 /**
6154 * @license
6155 * Copyright Google LLC All Rights Reserved.
6156 *
6157 * Use of this source code is governed by an MIT-style license that can be
6158 * found in the LICENSE file at https://angular.io/license
6159 */
6160 /**
6161 * Implementation of `CompileReflector` which resolves references to @angular/core
6162 * symbols at runtime, according to a consumer-provided mapping.
6163 *
6164 * Only supports `resolveExternalReference`, all other methods throw.
6165 */
6166 class R3JitReflector {
6167 constructor(context) {
6168 this.context = context;
6169 }
6170 resolveExternalReference(ref) {
6171 // This reflector only handles @angular/core imports.
6172 if (ref.moduleName !== '@angular/core') {
6173 throw new Error(`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`);
6174 }
6175 if (!this.context.hasOwnProperty(ref.name)) {
6176 throw new Error(`No value provided for @angular/core symbol '${ref.name}'.`);
6177 }
6178 return this.context[ref.name];
6179 }
6180 parameters(typeOrFunc) {
6181 throw new Error('Not implemented.');
6182 }
6183 annotations(typeOrFunc) {
6184 throw new Error('Not implemented.');
6185 }
6186 shallowAnnotations(typeOrFunc) {
6187 throw new Error('Not implemented.');
6188 }
6189 tryAnnotations(typeOrFunc) {
6190 throw new Error('Not implemented.');
6191 }
6192 propMetadata(typeOrFunc) {
6193 throw new Error('Not implemented.');
6194 }
6195 hasLifecycleHook(type, lcProperty) {
6196 throw new Error('Not implemented.');
6197 }
6198 guards(typeOrFunc) {
6199 throw new Error('Not implemented.');
6200 }
6201 componentModuleUrl(type, cmpMetadata) {
6202 throw new Error('Not implemented.');
6203 }
6204 }
6205
6206 /**
6207 * @license
6208 * Copyright Google LLC All Rights Reserved.
6209 *
6210 * Use of this source code is governed by an MIT-style license that can be
6211 * found in the LICENSE file at https://angular.io/license
6212 */
6213 function mapLiteral(obj, quoted = false) {
6214 return literalMap(Object.keys(obj).map(key => ({
6215 key,
6216 quoted,
6217 value: obj[key],
6218 })));
6219 }
6220
6221 /**
6222 * @license
6223 * Copyright Google LLC All Rights Reserved.
6224 *
6225 * Use of this source code is governed by an MIT-style license that can be
6226 * found in the LICENSE file at https://angular.io/license
6227 */
6228 /**
6229 * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
6230 */
6231 function compileNgModule(meta) {
6232 const { internalType, type: moduleType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, emitInline, id } = meta;
6233 const additionalStatements = [];
6234 const definitionMap = { type: internalType };
6235 // Only generate the keys in the metadata if the arrays have values.
6236 if (bootstrap.length) {
6237 definitionMap.bootstrap = refsToArray(bootstrap, containsForwardDecls);
6238 }
6239 // If requested to emit scope information inline, pass the declarations, imports and exports to
6240 // the `ɵɵdefineNgModule` call. The JIT compilation uses this.
6241 if (emitInline) {
6242 if (declarations.length) {
6243 definitionMap.declarations = refsToArray(declarations, containsForwardDecls);
6244 }
6245 if (imports.length) {
6246 definitionMap.imports = refsToArray(imports, containsForwardDecls);
6247 }
6248 if (exports.length) {
6249 definitionMap.exports = refsToArray(exports, containsForwardDecls);
6250 }
6251 }
6252 // If not emitting inline, the scope information is not passed into `ɵɵdefineNgModule` as it would
6253 // prevent tree-shaking of the declarations, imports and exports references.
6254 else {
6255 const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta);
6256 if (setNgModuleScopeCall !== null) {
6257 additionalStatements.push(setNgModuleScopeCall);
6258 }
6259 }
6260 if (schemas && schemas.length) {
6261 definitionMap.schemas = literalArr(schemas.map(ref => ref.value));
6262 }
6263 if (id) {
6264 definitionMap.id = id;
6265 }
6266 const expression = importExpr(Identifiers$1.defineNgModule).callFn([mapToMapExpression(definitionMap)]);
6267 const type = new ExpressionType(importExpr(Identifiers$1.NgModuleDefWithMeta, [
6268 new ExpressionType(moduleType.type), tupleTypeOf(declarations), tupleTypeOf(imports),
6269 tupleTypeOf(exports)
6270 ]));
6271 return { expression, type, additionalStatements };
6272 }
6273 /**
6274 * Generates a function call to `ɵɵsetNgModuleScope` with all necessary information so that the
6275 * transitive module scope can be computed during runtime in JIT mode. This call is marked pure
6276 * such that the references to declarations, imports and exports may be elided causing these
6277 * symbols to become tree-shakeable.
6278 */
6279 function generateSetNgModuleScopeCall(meta) {
6280 const { adjacentType: moduleType, declarations, imports, exports, containsForwardDecls } = meta;
6281 const scopeMap = {};
6282 if (declarations.length) {
6283 scopeMap.declarations = refsToArray(declarations, containsForwardDecls);
6284 }
6285 if (imports.length) {
6286 scopeMap.imports = refsToArray(imports, containsForwardDecls);
6287 }
6288 if (exports.length) {
6289 scopeMap.exports = refsToArray(exports, containsForwardDecls);
6290 }
6291 if (Object.keys(scopeMap).length === 0) {
6292 return null;
6293 }
6294 // setNgModuleScope(...)
6295 const fnCall = new InvokeFunctionExpr(
6296 /* fn */ importExpr(Identifiers$1.setNgModuleScope),
6297 /* args */ [moduleType, mapToMapExpression(scopeMap)]);
6298 // (ngJitMode guard) && setNgModuleScope(...)
6299 const guardedCall = jitOnlyGuardedExpression(fnCall);
6300 // function() { (ngJitMode guard) && setNgModuleScope(...); }
6301 const iife = new FunctionExpr(
6302 /* params */ [],
6303 /* statements */ [guardedCall.toStmt()]);
6304 // (function() { (ngJitMode guard) && setNgModuleScope(...); })()
6305 const iifeCall = new InvokeFunctionExpr(
6306 /* fn */ iife,
6307 /* args */ []);
6308 return iifeCall.toStmt();
6309 }
6310 function compileInjector(meta) {
6311 const result = compileFactoryFunction({
6312 name: meta.name,
6313 type: meta.type,
6314 internalType: meta.internalType,
6315 typeArgumentCount: 0,
6316 deps: meta.deps,
6317 injectFn: Identifiers$1.inject,
6318 target: R3FactoryTarget.NgModule,
6319 });
6320 const definitionMap = {
6321 factory: result.factory,
6322 };
6323 if (meta.providers !== null) {
6324 definitionMap.providers = meta.providers;
6325 }
6326 if (meta.imports.length > 0) {
6327 definitionMap.imports = literalArr(meta.imports);
6328 }
6329 const expression = importExpr(Identifiers$1.defineInjector).callFn([mapToMapExpression(definitionMap)]);
6330 const type = new ExpressionType(importExpr(Identifiers$1.InjectorDef, [new ExpressionType(meta.type.type)]));
6331 return { expression, type, statements: result.statements };
6332 }
6333 function tupleTypeOf(exp) {
6334 const types = exp.map(ref => typeofExpr(ref.type));
6335 return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE;
6336 }
6337 function refsToArray(refs, shouldForwardDeclare) {
6338 const values = literalArr(refs.map(ref => ref.value));
6339 return shouldForwardDeclare ? fn([], [new ReturnStatement(values)]) : values;
6340 }
6341
6342 /**
6343 * @license
6344 * Copyright Google LLC All Rights Reserved.
6345 *
6346 * Use of this source code is governed by an MIT-style license that can be
6347 * found in the LICENSE file at https://angular.io/license
6348 */
6349 function compilePipeFromMetadata(metadata) {
6350 const definitionMapValues = [];
6351 // e.g. `name: 'myPipe'`
6352 definitionMapValues.push({ key: 'name', value: literal(metadata.pipeName), quoted: false });
6353 // e.g. `type: MyPipe`
6354 definitionMapValues.push({ key: 'type', value: metadata.type.value, quoted: false });
6355 // e.g. `pure: true`
6356 definitionMapValues.push({ key: 'pure', value: literal(metadata.pure), quoted: false });
6357 const expression = importExpr(Identifiers$1.definePipe).callFn([literalMap(definitionMapValues)]);
6358 const type = createPipeType(metadata);
6359 return { expression, type };
6360 }
6361 function createPipeType(metadata) {
6362 return new ExpressionType(importExpr(Identifiers$1.PipeDefWithMeta, [
6363 typeWithParameters(metadata.type.type, metadata.typeArgumentCount),
6364 new ExpressionType(new LiteralExpr(metadata.pipeName)),
6365 ]));
6366 }
6367
6368 /**
6369 * @license
6370 * Copyright Google LLC All Rights Reserved.
6371 *
6372 * Use of this source code is governed by an MIT-style license that can be
6373 * found in the LICENSE file at https://angular.io/license
6374 */
6375 class ParserError {
6376 constructor(message, input, errLocation, ctxLocation) {
6377 this.input = input;
6378 this.errLocation = errLocation;
6379 this.ctxLocation = ctxLocation;
6380 this.message = `Parser Error: ${message} ${errLocation} [${input}] in ${ctxLocation}`;
6381 }
6382 }
6383 class ParseSpan {
6384 constructor(start, end) {
6385 this.start = start;
6386 this.end = end;
6387 }
6388 toAbsolute(absoluteOffset) {
6389 return new AbsoluteSourceSpan(absoluteOffset + this.start, absoluteOffset + this.end);
6390 }
6391 }
6392 class AST {
6393 constructor(span,
6394 /**
6395 * Absolute location of the expression AST in a source code file.
6396 */
6397 sourceSpan) {
6398 this.span = span;
6399 this.sourceSpan = sourceSpan;
6400 }
6401 visit(visitor, context = null) {
6402 return null;
6403 }
6404 toString() {
6405 return 'AST';
6406 }
6407 }
6408 class ASTWithName extends AST {
6409 constructor(span, sourceSpan, nameSpan) {
6410 super(span, sourceSpan);
6411 this.nameSpan = nameSpan;
6412 }
6413 }
6414 /**
6415 * Represents a quoted expression of the form:
6416 *
6417 * quote = prefix `:` uninterpretedExpression
6418 * prefix = identifier
6419 * uninterpretedExpression = arbitrary string
6420 *
6421 * A quoted expression is meant to be pre-processed by an AST transformer that
6422 * converts it into another AST that no longer contains quoted expressions.
6423 * It is meant to allow third-party developers to extend Angular template
6424 * expression language. The `uninterpretedExpression` part of the quote is
6425 * therefore not interpreted by the Angular's own expression parser.
6426 */
6427 class Quote extends AST {
6428 constructor(span, sourceSpan, prefix, uninterpretedExpression, location) {
6429 super(span, sourceSpan);
6430 this.prefix = prefix;
6431 this.uninterpretedExpression = uninterpretedExpression;
6432 this.location = location;
6433 }
6434 visit(visitor, context = null) {
6435 return visitor.visitQuote(this, context);
6436 }
6437 toString() {
6438 return 'Quote';
6439 }
6440 }
6441 class EmptyExpr extends AST {
6442 visit(visitor, context = null) {
6443 // do nothing
6444 }
6445 }
6446 class ImplicitReceiver extends AST {
6447 visit(visitor, context = null) {
6448 return visitor.visitImplicitReceiver(this, context);
6449 }
6450 }
6451 /**
6452 * Receiver when something is accessed through `this` (e.g. `this.foo`). Note that this class
6453 * inherits from `ImplicitReceiver`, because accessing something through `this` is treated the
6454 * same as accessing it implicitly inside of an Angular template (e.g. `[attr.title]="this.title"`
6455 * is the same as `[attr.title]="title"`.). Inheriting allows for the `this` accesses to be treated
6456 * the same as implicit ones, except for a couple of exceptions like `$event` and `$any`.
6457 * TODO: we should find a way for this class not to extend from `ImplicitReceiver` in the future.
6458 */
6459 class ThisReceiver extends ImplicitReceiver {
6460 visit(visitor, context = null) {
6461 var _a;
6462 return (_a = visitor.visitThisReceiver) === null || _a === void 0 ? void 0 : _a.call(visitor, this, context);
6463 }
6464 }
6465 /**
6466 * Multiple expressions separated by a semicolon.
6467 */
6468 class Chain extends AST {
6469 constructor(span, sourceSpan, expressions) {
6470 super(span, sourceSpan);
6471 this.expressions = expressions;
6472 }
6473 visit(visitor, context = null) {
6474 return visitor.visitChain(this, context);
6475 }
6476 }
6477 class Conditional extends AST {
6478 constructor(span, sourceSpan, condition, trueExp, falseExp) {
6479 super(span, sourceSpan);
6480 this.condition = condition;
6481 this.trueExp = trueExp;
6482 this.falseExp = falseExp;
6483 }
6484 visit(visitor, context = null) {
6485 return visitor.visitConditional(this, context);
6486 }
6487 }
6488 class PropertyRead extends ASTWithName {
6489 constructor(span, sourceSpan, nameSpan, receiver, name) {
6490 super(span, sourceSpan, nameSpan);
6491 this.receiver = receiver;
6492 this.name = name;
6493 }
6494 visit(visitor, context = null) {
6495 return visitor.visitPropertyRead(this, context);
6496 }
6497 }
6498 class PropertyWrite extends ASTWithName {
6499 constructor(span, sourceSpan, nameSpan, receiver, name, value) {
6500 super(span, sourceSpan, nameSpan);
6501 this.receiver = receiver;
6502 this.name = name;
6503 this.value = value;
6504 }
6505 visit(visitor, context = null) {
6506 return visitor.visitPropertyWrite(this, context);
6507 }
6508 }
6509 class SafePropertyRead extends ASTWithName {
6510 constructor(span, sourceSpan, nameSpan, receiver, name) {
6511 super(span, sourceSpan, nameSpan);
6512 this.receiver = receiver;
6513 this.name = name;
6514 }
6515 visit(visitor, context = null) {
6516 return visitor.visitSafePropertyRead(this, context);
6517 }
6518 }
6519 class KeyedRead extends AST {
6520 constructor(span, sourceSpan, obj, key) {
6521 super(span, sourceSpan);
6522 this.obj = obj;
6523 this.key = key;
6524 }
6525 visit(visitor, context = null) {
6526 return visitor.visitKeyedRead(this, context);
6527 }
6528 }
6529 class KeyedWrite extends AST {
6530 constructor(span, sourceSpan, obj, key, value) {
6531 super(span, sourceSpan);
6532 this.obj = obj;
6533 this.key = key;
6534 this.value = value;
6535 }
6536 visit(visitor, context = null) {
6537 return visitor.visitKeyedWrite(this, context);
6538 }
6539 }
6540 class BindingPipe extends ASTWithName {
6541 constructor(span, sourceSpan, exp, name, args, nameSpan) {
6542 super(span, sourceSpan, nameSpan);
6543 this.exp = exp;
6544 this.name = name;
6545 this.args = args;
6546 }
6547 visit(visitor, context = null) {
6548 return visitor.visitPipe(this, context);
6549 }
6550 }
6551 class LiteralPrimitive extends AST {
6552 constructor(span, sourceSpan, value) {
6553 super(span, sourceSpan);
6554 this.value = value;
6555 }
6556 visit(visitor, context = null) {
6557 return visitor.visitLiteralPrimitive(this, context);
6558 }
6559 }
6560 class LiteralArray extends AST {
6561 constructor(span, sourceSpan, expressions) {
6562 super(span, sourceSpan);
6563 this.expressions = expressions;
6564 }
6565 visit(visitor, context = null) {
6566 return visitor.visitLiteralArray(this, context);
6567 }
6568 }
6569 class LiteralMap extends AST {
6570 constructor(span, sourceSpan, keys, values) {
6571 super(span, sourceSpan);
6572 this.keys = keys;
6573 this.values = values;
6574 }
6575 visit(visitor, context = null) {
6576 return visitor.visitLiteralMap(this, context);
6577 }
6578 }
6579 class Interpolation extends AST {
6580 constructor(span, sourceSpan, strings, expressions) {
6581 super(span, sourceSpan);
6582 this.strings = strings;
6583 this.expressions = expressions;
6584 }
6585 visit(visitor, context = null) {
6586 return visitor.visitInterpolation(this, context);
6587 }
6588 }
6589 class Binary extends AST {
6590 constructor(span, sourceSpan, operation, left, right) {
6591 super(span, sourceSpan);
6592 this.operation = operation;
6593 this.left = left;
6594 this.right = right;
6595 }
6596 visit(visitor, context = null) {
6597 return visitor.visitBinary(this, context);
6598 }
6599 }
6600 /**
6601 * For backwards compatibility reasons, `Unary` inherits from `Binary` and mimics the binary AST
6602 * node that was originally used. This inheritance relation can be deleted in some future major,
6603 * after consumers have been given a chance to fully support Unary.
6604 */
6605 class Unary extends Binary {
6606 /**
6607 * During the deprecation period this constructor is private, to avoid consumers from creating
6608 * a `Unary` with the fallback properties for `Binary`.
6609 */
6610 constructor(span, sourceSpan, operator, expr, binaryOp, binaryLeft, binaryRight) {
6611 super(span, sourceSpan, binaryOp, binaryLeft, binaryRight);
6612 this.operator = operator;
6613 this.expr = expr;
6614 }
6615 /**
6616 * Creates a unary minus expression "-x", represented as `Binary` using "0 - x".
6617 */
6618 static createMinus(span, sourceSpan, expr) {
6619 return new Unary(span, sourceSpan, '-', expr, '-', new LiteralPrimitive(span, sourceSpan, 0), expr);
6620 }
6621 /**
6622 * Creates a unary plus expression "+x", represented as `Binary` using "x - 0".
6623 */
6624 static createPlus(span, sourceSpan, expr) {
6625 return new Unary(span, sourceSpan, '+', expr, '-', expr, new LiteralPrimitive(span, sourceSpan, 0));
6626 }
6627 visit(visitor, context = null) {
6628 if (visitor.visitUnary !== undefined) {
6629 return visitor.visitUnary(this, context);
6630 }
6631 return visitor.visitBinary(this, context);
6632 }
6633 }
6634 class PrefixNot extends AST {
6635 constructor(span, sourceSpan, expression) {
6636 super(span, sourceSpan);
6637 this.expression = expression;
6638 }
6639 visit(visitor, context = null) {
6640 return visitor.visitPrefixNot(this, context);
6641 }
6642 }
6643 class NonNullAssert extends AST {
6644 constructor(span, sourceSpan, expression) {
6645 super(span, sourceSpan);
6646 this.expression = expression;
6647 }
6648 visit(visitor, context = null) {
6649 return visitor.visitNonNullAssert(this, context);
6650 }
6651 }
6652 class MethodCall extends ASTWithName {
6653 constructor(span, sourceSpan, nameSpan, receiver, name, args) {
6654 super(span, sourceSpan, nameSpan);
6655 this.receiver = receiver;
6656 this.name = name;
6657 this.args = args;
6658 }
6659 visit(visitor, context = null) {
6660 return visitor.visitMethodCall(this, context);
6661 }
6662 }
6663 class SafeMethodCall extends ASTWithName {
6664 constructor(span, sourceSpan, nameSpan, receiver, name, args) {
6665 super(span, sourceSpan, nameSpan);
6666 this.receiver = receiver;
6667 this.name = name;
6668 this.args = args;
6669 }
6670 visit(visitor, context = null) {
6671 return visitor.visitSafeMethodCall(this, context);
6672 }
6673 }
6674 class FunctionCall extends AST {
6675 constructor(span, sourceSpan, target, args) {
6676 super(span, sourceSpan);
6677 this.target = target;
6678 this.args = args;
6679 }
6680 visit(visitor, context = null) {
6681 return visitor.visitFunctionCall(this, context);
6682 }
6683 }
6684 /**
6685 * Records the absolute position of a text span in a source file, where `start` and `end` are the
6686 * starting and ending byte offsets, respectively, of the text span in a source file.
6687 */
6688 class AbsoluteSourceSpan {
6689 constructor(start, end) {
6690 this.start = start;
6691 this.end = end;
6692 }
6693 }
6694 class ASTWithSource extends AST {
6695 constructor(ast, source, location, absoluteOffset, errors) {
6696 super(new ParseSpan(0, source === null ? 0 : source.length), new AbsoluteSourceSpan(absoluteOffset, source === null ? absoluteOffset : absoluteOffset + source.length));
6697 this.ast = ast;
6698 this.source = source;
6699 this.location = location;
6700 this.errors = errors;
6701 }
6702 visit(visitor, context = null) {
6703 if (visitor.visitASTWithSource) {
6704 return visitor.visitASTWithSource(this, context);
6705 }
6706 return this.ast.visit(visitor, context);
6707 }
6708 toString() {
6709 return `${this.source} in ${this.location}`;
6710 }
6711 }
6712 class VariableBinding {
6713 /**
6714 * @param sourceSpan entire span of the binding.
6715 * @param key name of the LHS along with its span.
6716 * @param value optional value for the RHS along with its span.
6717 */
6718 constructor(sourceSpan, key, value) {
6719 this.sourceSpan = sourceSpan;
6720 this.key = key;
6721 this.value = value;
6722 }
6723 }
6724 class ExpressionBinding {
6725 /**
6726 * @param sourceSpan entire span of the binding.
6727 * @param key binding name, like ngForOf, ngForTrackBy, ngIf, along with its
6728 * span. Note that the length of the span may not be the same as
6729 * `key.source.length`. For example,
6730 * 1. key.source = ngFor, key.span is for "ngFor"
6731 * 2. key.source = ngForOf, key.span is for "of"
6732 * 3. key.source = ngForTrackBy, key.span is for "trackBy"
6733 * @param value optional expression for the RHS.
6734 */
6735 constructor(sourceSpan, key, value) {
6736 this.sourceSpan = sourceSpan;
6737 this.key = key;
6738 this.value = value;
6739 }
6740 }
6741 class RecursiveAstVisitor {
6742 visit(ast, context) {
6743 // The default implementation just visits every node.
6744 // Classes that extend RecursiveAstVisitor should override this function
6745 // to selectively visit the specified node.
6746 ast.visit(this, context);
6747 }
6748 visitUnary(ast, context) {
6749 this.visit(ast.expr, context);
6750 }
6751 visitBinary(ast, context) {
6752 this.visit(ast.left, context);
6753 this.visit(ast.right, context);
6754 }
6755 visitChain(ast, context) {
6756 this.visitAll(ast.expressions, context);
6757 }
6758 visitConditional(ast, context) {
6759 this.visit(ast.condition, context);
6760 this.visit(ast.trueExp, context);
6761 this.visit(ast.falseExp, context);
6762 }
6763 visitPipe(ast, context) {
6764 this.visit(ast.exp, context);
6765 this.visitAll(ast.args, context);
6766 }
6767 visitFunctionCall(ast, context) {
6768 if (ast.target) {
6769 this.visit(ast.target, context);
6770 }
6771 this.visitAll(ast.args, context);
6772 }
6773 visitImplicitReceiver(ast, context) { }
6774 visitThisReceiver(ast, context) { }
6775 visitInterpolation(ast, context) {
6776 this.visitAll(ast.expressions, context);
6777 }
6778 visitKeyedRead(ast, context) {
6779 this.visit(ast.obj, context);
6780 this.visit(ast.key, context);
6781 }
6782 visitKeyedWrite(ast, context) {
6783 this.visit(ast.obj, context);
6784 this.visit(ast.key, context);
6785 this.visit(ast.value, context);
6786 }
6787 visitLiteralArray(ast, context) {
6788 this.visitAll(ast.expressions, context);
6789 }
6790 visitLiteralMap(ast, context) {
6791 this.visitAll(ast.values, context);
6792 }
6793 visitLiteralPrimitive(ast, context) { }
6794 visitMethodCall(ast, context) {
6795 this.visit(ast.receiver, context);
6796 this.visitAll(ast.args, context);
6797 }
6798 visitPrefixNot(ast, context) {
6799 this.visit(ast.expression, context);
6800 }
6801 visitNonNullAssert(ast, context) {
6802 this.visit(ast.expression, context);
6803 }
6804 visitPropertyRead(ast, context) {
6805 this.visit(ast.receiver, context);
6806 }
6807 visitPropertyWrite(ast, context) {
6808 this.visit(ast.receiver, context);
6809 this.visit(ast.value, context);
6810 }
6811 visitSafePropertyRead(ast, context) {
6812 this.visit(ast.receiver, context);
6813 }
6814 visitSafeMethodCall(ast, context) {
6815 this.visit(ast.receiver, context);
6816 this.visitAll(ast.args, context);
6817 }
6818 visitQuote(ast, context) { }
6819 // This is not part of the AstVisitor interface, just a helper method
6820 visitAll(asts, context) {
6821 for (const ast of asts) {
6822 this.visit(ast, context);
6823 }
6824 }
6825 }
6826 class AstTransformer {
6827 visitImplicitReceiver(ast, context) {
6828 return ast;
6829 }
6830 visitThisReceiver(ast, context) {
6831 return ast;
6832 }
6833 visitInterpolation(ast, context) {
6834 return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
6835 }
6836 visitLiteralPrimitive(ast, context) {
6837 return new LiteralPrimitive(ast.span, ast.sourceSpan, ast.value);
6838 }
6839 visitPropertyRead(ast, context) {
6840 return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
6841 }
6842 visitPropertyWrite(ast, context) {
6843 return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, ast.value.visit(this));
6844 }
6845 visitSafePropertyRead(ast, context) {
6846 return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
6847 }
6848 visitMethodCall(ast, context) {
6849 return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
6850 }
6851 visitSafeMethodCall(ast, context) {
6852 return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
6853 }
6854 visitFunctionCall(ast, context) {
6855 return new FunctionCall(ast.span, ast.sourceSpan, ast.target.visit(this), this.visitAll(ast.args));
6856 }
6857 visitLiteralArray(ast, context) {
6858 return new LiteralArray(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
6859 }
6860 visitLiteralMap(ast, context) {
6861 return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, this.visitAll(ast.values));
6862 }
6863 visitUnary(ast, context) {
6864 switch (ast.operator) {
6865 case '+':
6866 return Unary.createPlus(ast.span, ast.sourceSpan, ast.expr.visit(this));
6867 case '-':
6868 return Unary.createMinus(ast.span, ast.sourceSpan, ast.expr.visit(this));
6869 default:
6870 throw new Error(`Unknown unary operator ${ast.operator}`);
6871 }
6872 }
6873 visitBinary(ast, context) {
6874 return new Binary(ast.span, ast.sourceSpan, ast.operation, ast.left.visit(this), ast.right.visit(this));
6875 }
6876 visitPrefixNot(ast, context) {
6877 return new PrefixNot(ast.span, ast.sourceSpan, ast.expression.visit(this));
6878 }
6879 visitNonNullAssert(ast, context) {
6880 return new NonNullAssert(ast.span, ast.sourceSpan, ast.expression.visit(this));
6881 }
6882 visitConditional(ast, context) {
6883 return new Conditional(ast.span, ast.sourceSpan, ast.condition.visit(this), ast.trueExp.visit(this), ast.falseExp.visit(this));
6884 }
6885 visitPipe(ast, context) {
6886 return new BindingPipe(ast.span, ast.sourceSpan, ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.nameSpan);
6887 }
6888 visitKeyedRead(ast, context) {
6889 return new KeyedRead(ast.span, ast.sourceSpan, ast.obj.visit(this), ast.key.visit(this));
6890 }
6891 visitKeyedWrite(ast, context) {
6892 return new KeyedWrite(ast.span, ast.sourceSpan, ast.obj.visit(this), ast.key.visit(this), ast.value.visit(this));
6893 }
6894 visitAll(asts) {
6895 const res = [];
6896 for (let i = 0; i < asts.length; ++i) {
6897 res[i] = asts[i].visit(this);
6898 }
6899 return res;
6900 }
6901 visitChain(ast, context) {
6902 return new Chain(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
6903 }
6904 visitQuote(ast, context) {
6905 return new Quote(ast.span, ast.sourceSpan, ast.prefix, ast.uninterpretedExpression, ast.location);
6906 }
6907 }
6908 // A transformer that only creates new nodes if the transformer makes a change or
6909 // a change is made a child node.
6910 class AstMemoryEfficientTransformer {
6911 visitImplicitReceiver(ast, context) {
6912 return ast;
6913 }
6914 visitThisReceiver(ast, context) {
6915 return ast;
6916 }
6917 visitInterpolation(ast, context) {
6918 const expressions = this.visitAll(ast.expressions);
6919 if (expressions !== ast.expressions)
6920 return new Interpolation(ast.span, ast.sourceSpan, ast.strings, expressions);
6921 return ast;
6922 }
6923 visitLiteralPrimitive(ast, context) {
6924 return ast;
6925 }
6926 visitPropertyRead(ast, context) {
6927 const receiver = ast.receiver.visit(this);
6928 if (receiver !== ast.receiver) {
6929 return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
6930 }
6931 return ast;
6932 }
6933 visitPropertyWrite(ast, context) {
6934 const receiver = ast.receiver.visit(this);
6935 const value = ast.value.visit(this);
6936 if (receiver !== ast.receiver || value !== ast.value) {
6937 return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, value);
6938 }
6939 return ast;
6940 }
6941 visitSafePropertyRead(ast, context) {
6942 const receiver = ast.receiver.visit(this);
6943 if (receiver !== ast.receiver) {
6944 return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
6945 }
6946 return ast;
6947 }
6948 visitMethodCall(ast, context) {
6949 const receiver = ast.receiver.visit(this);
6950 const args = this.visitAll(ast.args);
6951 if (receiver !== ast.receiver || args !== ast.args) {
6952 return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args);
6953 }
6954 return ast;
6955 }
6956 visitSafeMethodCall(ast, context) {
6957 const receiver = ast.receiver.visit(this);
6958 const args = this.visitAll(ast.args);
6959 if (receiver !== ast.receiver || args !== ast.args) {
6960 return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args);
6961 }
6962 return ast;
6963 }
6964 visitFunctionCall(ast, context) {
6965 const target = ast.target && ast.target.visit(this);
6966 const args = this.visitAll(ast.args);
6967 if (target !== ast.target || args !== ast.args) {
6968 return new FunctionCall(ast.span, ast.sourceSpan, target, args);
6969 }
6970 return ast;
6971 }
6972 visitLiteralArray(ast, context) {
6973 const expressions = this.visitAll(ast.expressions);
6974 if (expressions !== ast.expressions) {
6975 return new LiteralArray(ast.span, ast.sourceSpan, expressions);
6976 }
6977 return ast;
6978 }
6979 visitLiteralMap(ast, context) {
6980 const values = this.visitAll(ast.values);
6981 if (values !== ast.values) {
6982 return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, values);
6983 }
6984 return ast;
6985 }
6986 visitUnary(ast, context) {
6987 const expr = ast.expr.visit(this);
6988 if (expr !== ast.expr) {
6989 switch (ast.operator) {
6990 case '+':
6991 return Unary.createPlus(ast.span, ast.sourceSpan, expr);
6992 case '-':
6993 return Unary.createMinus(ast.span, ast.sourceSpan, expr);
6994 default:
6995 throw new Error(`Unknown unary operator ${ast.operator}`);
6996 }
6997 }
6998 return ast;
6999 }
7000 visitBinary(ast, context) {
7001 const left = ast.left.visit(this);
7002 const right = ast.right.visit(this);
7003 if (left !== ast.left || right !== ast.right) {
7004 return new Binary(ast.span, ast.sourceSpan, ast.operation, left, right);
7005 }
7006 return ast;
7007 }
7008 visitPrefixNot(ast, context) {
7009 const expression = ast.expression.visit(this);
7010 if (expression !== ast.expression) {
7011 return new PrefixNot(ast.span, ast.sourceSpan, expression);
7012 }
7013 return ast;
7014 }
7015 visitNonNullAssert(ast, context) {
7016 const expression = ast.expression.visit(this);
7017 if (expression !== ast.expression) {
7018 return new NonNullAssert(ast.span, ast.sourceSpan, expression);
7019 }
7020 return ast;
7021 }
7022 visitConditional(ast, context) {
7023 const condition = ast.condition.visit(this);
7024 const trueExp = ast.trueExp.visit(this);
7025 const falseExp = ast.falseExp.visit(this);
7026 if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== ast.falseExp) {
7027 return new Conditional(ast.span, ast.sourceSpan, condition, trueExp, falseExp);
7028 }
7029 return ast;
7030 }
7031 visitPipe(ast, context) {
7032 const exp = ast.exp.visit(this);
7033 const args = this.visitAll(ast.args);
7034 if (exp !== ast.exp || args !== ast.args) {
7035 return new BindingPipe(ast.span, ast.sourceSpan, exp, ast.name, args, ast.nameSpan);
7036 }
7037 return ast;
7038 }
7039 visitKeyedRead(ast, context) {
7040 const obj = ast.obj.visit(this);
7041 const key = ast.key.visit(this);
7042 if (obj !== ast.obj || key !== ast.key) {
7043 return new KeyedRead(ast.span, ast.sourceSpan, obj, key);
7044 }
7045 return ast;
7046 }
7047 visitKeyedWrite(ast, context) {
7048 const obj = ast.obj.visit(this);
7049 const key = ast.key.visit(this);
7050 const value = ast.value.visit(this);
7051 if (obj !== ast.obj || key !== ast.key || value !== ast.value) {
7052 return new KeyedWrite(ast.span, ast.sourceSpan, obj, key, value);
7053 }
7054 return ast;
7055 }
7056 visitAll(asts) {
7057 const res = [];
7058 let modified = false;
7059 for (let i = 0; i < asts.length; ++i) {
7060 const original = asts[i];
7061 const value = original.visit(this);
7062 res[i] = value;
7063 modified = modified || value !== original;
7064 }
7065 return modified ? res : asts;
7066 }
7067 visitChain(ast, context) {
7068 const expressions = this.visitAll(ast.expressions);
7069 if (expressions !== ast.expressions) {
7070 return new Chain(ast.span, ast.sourceSpan, expressions);
7071 }
7072 return ast;
7073 }
7074 visitQuote(ast, context) {
7075 return ast;
7076 }
7077 }
7078 // Bindings
7079 class ParsedProperty {
7080 constructor(name, expression, type,
7081 // TODO(FW-2095): `keySpan` should really be required but allows `undefined` so VE does
7082 // not need to be updated. Make `keySpan` required when VE is removed.
7083 sourceSpan, keySpan, valueSpan) {
7084 this.name = name;
7085 this.expression = expression;
7086 this.type = type;
7087 this.sourceSpan = sourceSpan;
7088 this.keySpan = keySpan;
7089 this.valueSpan = valueSpan;
7090 this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR;
7091 this.isAnimation = this.type === ParsedPropertyType.ANIMATION;
7092 }
7093 }
7094 var ParsedPropertyType;
7095 (function (ParsedPropertyType) {
7096 ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT";
7097 ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
7098 ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION";
7099 })(ParsedPropertyType || (ParsedPropertyType = {}));
7100 class ParsedEvent {
7101 // Regular events have a target
7102 // Animation events have a phase
7103 constructor(name, targetOrPhase, type, handler, sourceSpan,
7104 // TODO(FW-2095): keySpan should be required but was made optional to avoid changing VE
7105 handlerSpan, keySpan) {
7106 this.name = name;
7107 this.targetOrPhase = targetOrPhase;
7108 this.type = type;
7109 this.handler = handler;
7110 this.sourceSpan = sourceSpan;
7111 this.handlerSpan = handlerSpan;
7112 this.keySpan = keySpan;
7113 }
7114 }
7115 /**
7116 * ParsedVariable represents a variable declaration in a microsyntax expression.
7117 */
7118 class ParsedVariable {
7119 constructor(name, value, sourceSpan, keySpan, valueSpan) {
7120 this.name = name;
7121 this.value = value;
7122 this.sourceSpan = sourceSpan;
7123 this.keySpan = keySpan;
7124 this.valueSpan = valueSpan;
7125 }
7126 }
7127 class BoundElementProperty {
7128 constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan) {
7129 this.name = name;
7130 this.type = type;
7131 this.securityContext = securityContext;
7132 this.value = value;
7133 this.unit = unit;
7134 this.sourceSpan = sourceSpan;
7135 this.keySpan = keySpan;
7136 this.valueSpan = valueSpan;
7137 }
7138 }
7139
7140 /**
7141 * @license
7142 * Copyright Google LLC All Rights Reserved.
7143 *
7144 * Use of this source code is governed by an MIT-style license that can be
7145 * found in the LICENSE file at https://angular.io/license
7146 */
7147 class EventHandlerVars {
7148 }
7149 EventHandlerVars.event = variable('$event');
7150 class ConvertActionBindingResult {
7151 constructor(
7152 /**
7153 * Render2 compatible statements,
7154 */
7155 stmts,
7156 /**
7157 * Variable name used with render2 compatible statements.
7158 */
7159 allowDefault) {
7160 this.stmts = stmts;
7161 this.allowDefault = allowDefault;
7162 /**
7163 * This is bit of a hack. It converts statements which render2 expects to statements which are
7164 * expected by render3.
7165 *
7166 * Example: `<div click="doSomething($event)">` will generate:
7167 *
7168 * Render3:
7169 * ```
7170 * const pd_b:any = ((<any>ctx.doSomething($event)) !== false);
7171 * return pd_b;
7172 * ```
7173 *
7174 * but render2 expects:
7175 * ```
7176 * return ctx.doSomething($event);
7177 * ```
7178 */
7179 // TODO(misko): remove this hack once we no longer support ViewEngine.
7180 this.render3Stmts = stmts.map((statement) => {
7181 if (statement instanceof DeclareVarStmt && statement.name == allowDefault.name &&
7182 statement.value instanceof BinaryOperatorExpr) {
7183 const lhs = statement.value.lhs;
7184 return new ReturnStatement(lhs.value);
7185 }
7186 return statement;
7187 });
7188 }
7189 }
7190 /**
7191 * Converts the given expression AST into an executable output AST, assuming the expression is
7192 * used in an action binding (e.g. an event handler).
7193 */
7194 function convertActionBinding(localResolver, implicitReceiver, action, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses, globals) {
7195 if (!localResolver) {
7196 localResolver = new DefaultLocalResolver(globals);
7197 }
7198 const actionWithoutBuiltins = convertPropertyBindingBuiltins({
7199 createLiteralArrayConverter: (argCount) => {
7200 // Note: no caching for literal arrays in actions.
7201 return (args) => literalArr(args);
7202 },
7203 createLiteralMapConverter: (keys) => {
7204 // Note: no caching for literal maps in actions.
7205 return (values) => {
7206 const entries = keys.map((k, i) => ({
7207 key: k.key,
7208 value: values[i],
7209 quoted: k.quoted,
7210 }));
7211 return literalMap(entries);
7212 };
7213 },
7214 createPipeConverter: (name) => {
7215 throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`);
7216 }
7217 }, action);
7218 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses);
7219 const actionStmts = [];
7220 flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
7221 prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
7222 if (visitor.usesImplicitReceiver) {
7223 localResolver.notifyImplicitReceiverUse();
7224 }
7225 const lastIndex = actionStmts.length - 1;
7226 let preventDefaultVar = null;
7227 if (lastIndex >= 0) {
7228 const lastStatement = actionStmts[lastIndex];
7229 const returnExpr = convertStmtIntoExpression(lastStatement);
7230 if (returnExpr) {
7231 // Note: We need to cast the result of the method call to dynamic,
7232 // as it might be a void method!
7233 preventDefaultVar = createPreventDefaultVar(bindingId);
7234 actionStmts[lastIndex] =
7235 preventDefaultVar.set(returnExpr.cast(DYNAMIC_TYPE).notIdentical(literal(false)))
7236 .toDeclStmt(null, [StmtModifier.Final]);
7237 }
7238 }
7239 return new ConvertActionBindingResult(actionStmts, preventDefaultVar);
7240 }
7241 function convertPropertyBindingBuiltins(converterFactory, ast) {
7242 return convertBuiltins(converterFactory, ast);
7243 }
7244 class ConvertPropertyBindingResult {
7245 constructor(stmts, currValExpr) {
7246 this.stmts = stmts;
7247 this.currValExpr = currValExpr;
7248 }
7249 }
7250 var BindingForm;
7251 (function (BindingForm) {
7252 // The general form of binding expression, supports all expressions.
7253 BindingForm[BindingForm["General"] = 0] = "General";
7254 // Try to generate a simple binding (no temporaries or statements)
7255 // otherwise generate a general binding
7256 BindingForm[BindingForm["TrySimple"] = 1] = "TrySimple";
7257 // Inlines assignment of temporaries into the generated expression. The result may still
7258 // have statements attached for declarations of temporary variables.
7259 // This is the only relevant form for Ivy, the other forms are only used in ViewEngine.
7260 BindingForm[BindingForm["Expression"] = 2] = "Expression";
7261 })(BindingForm || (BindingForm = {}));
7262 /**
7263 * Converts the given expression AST into an executable output AST, assuming the expression
7264 * is used in property binding. The expression has to be preprocessed via
7265 * `convertPropertyBindingBuiltins`.
7266 */
7267 function convertPropertyBinding(localResolver, implicitReceiver, expressionWithoutBuiltins, bindingId, form, interpolationFunction) {
7268 if (!localResolver) {
7269 localResolver = new DefaultLocalResolver();
7270 }
7271 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
7272 const outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
7273 const stmts = getStatementsFromVisitor(visitor, bindingId);
7274 if (visitor.usesImplicitReceiver) {
7275 localResolver.notifyImplicitReceiverUse();
7276 }
7277 if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) {
7278 return new ConvertPropertyBindingResult([], outputExpr);
7279 }
7280 else if (form === BindingForm.Expression) {
7281 return new ConvertPropertyBindingResult(stmts, outputExpr);
7282 }
7283 const currValExpr = createCurrValueExpr(bindingId);
7284 stmts.push(currValExpr.set(outputExpr).toDeclStmt(DYNAMIC_TYPE, [StmtModifier.Final]));
7285 return new ConvertPropertyBindingResult(stmts, currValExpr);
7286 }
7287 /**
7288 * Given some expression, such as a binding or interpolation expression, and a context expression to
7289 * look values up on, visit each facet of the given expression resolving values from the context
7290 * expression such that a list of arguments can be derived from the found values that can be used as
7291 * arguments to an external update instruction.
7292 *
7293 * @param localResolver The resolver to use to look up expressions by name appropriately
7294 * @param contextVariableExpression The expression representing the context variable used to create
7295 * the final argument expressions
7296 * @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to
7297 * be resolved and what arguments list to build.
7298 * @param bindingId A name prefix used to create temporary variable names if they're needed for the
7299 * arguments generated
7300 * @returns An array of expressions that can be passed as arguments to instruction expressions like
7301 * `o.importExpr(R3.propertyInterpolate).callFn(result)`
7302 */
7303 function convertUpdateArguments(localResolver, contextVariableExpression, expressionWithArgumentsToExtract, bindingId) {
7304 const visitor = new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, undefined);
7305 const outputExpr = expressionWithArgumentsToExtract.visit(visitor, _Mode.Expression);
7306 if (visitor.usesImplicitReceiver) {
7307 localResolver.notifyImplicitReceiverUse();
7308 }
7309 const stmts = getStatementsFromVisitor(visitor, bindingId);
7310 // Removing the first argument, because it was a length for ViewEngine, not Ivy.
7311 let args = outputExpr.args.slice(1);
7312 if (expressionWithArgumentsToExtract instanceof Interpolation) {
7313 // If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the
7314 // args returned to just the value, because we're going to pass it to a special instruction.
7315 const strings = expressionWithArgumentsToExtract.strings;
7316 if (args.length === 3 && strings[0] === '' && strings[1] === '') {
7317 // Single argument interpolate instructions.
7318 args = [args[1]];
7319 }
7320 else if (args.length >= 19) {
7321 // 19 or more arguments must be passed to the `interpolateV`-style instructions, which accept
7322 // an array of arguments
7323 args = [literalArr(args)];
7324 }
7325 }
7326 return { stmts, args };
7327 }
7328 function getStatementsFromVisitor(visitor, bindingId) {
7329 const stmts = [];
7330 for (let i = 0; i < visitor.temporaryCount; i++) {
7331 stmts.push(temporaryDeclaration(bindingId, i));
7332 }
7333 return stmts;
7334 }
7335 function convertBuiltins(converterFactory, ast) {
7336 const visitor = new _BuiltinAstConverter(converterFactory);
7337 return ast.visit(visitor);
7338 }
7339 function temporaryName(bindingId, temporaryNumber) {
7340 return `tmp_${bindingId}_${temporaryNumber}`;
7341 }
7342 function temporaryDeclaration(bindingId, temporaryNumber) {
7343 return new DeclareVarStmt(temporaryName(bindingId, temporaryNumber), NULL_EXPR);
7344 }
7345 function prependTemporaryDecls(temporaryCount, bindingId, statements) {
7346 for (let i = temporaryCount - 1; i >= 0; i--) {
7347 statements.unshift(temporaryDeclaration(bindingId, i));
7348 }
7349 }
7350 var _Mode;
7351 (function (_Mode) {
7352 _Mode[_Mode["Statement"] = 0] = "Statement";
7353 _Mode[_Mode["Expression"] = 1] = "Expression";
7354 })(_Mode || (_Mode = {}));
7355 function ensureStatementMode(mode, ast) {
7356 if (mode !== _Mode.Statement) {
7357 throw new Error(`Expected a statement, but saw ${ast}`);
7358 }
7359 }
7360 function ensureExpressionMode(mode, ast) {
7361 if (mode !== _Mode.Expression) {
7362 throw new Error(`Expected an expression, but saw ${ast}`);
7363 }
7364 }
7365 function convertToStatementIfNeeded(mode, expr) {
7366 if (mode === _Mode.Statement) {
7367 return expr.toStmt();
7368 }
7369 else {
7370 return expr;
7371 }
7372 }
7373 class _BuiltinAstConverter extends AstTransformer {
7374 constructor(_converterFactory) {
7375 super();
7376 this._converterFactory = _converterFactory;
7377 }
7378 visitPipe(ast, context) {
7379 const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context));
7380 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createPipeConverter(ast.name, args.length));
7381 }
7382 visitLiteralArray(ast, context) {
7383 const args = ast.expressions.map(ast => ast.visit(this, context));
7384 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralArrayConverter(ast.expressions.length));
7385 }
7386 visitLiteralMap(ast, context) {
7387 const args = ast.values.map(ast => ast.visit(this, context));
7388 return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralMapConverter(ast.keys));
7389 }
7390 }
7391 class _AstToIrVisitor {
7392 constructor(_localResolver, _implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses) {
7393 this._localResolver = _localResolver;
7394 this._implicitReceiver = _implicitReceiver;
7395 this.bindingId = bindingId;
7396 this.interpolationFunction = interpolationFunction;
7397 this.baseSourceSpan = baseSourceSpan;
7398 this.implicitReceiverAccesses = implicitReceiverAccesses;
7399 this._nodeMap = new Map();
7400 this._resultMap = new Map();
7401 this._currentTemporary = 0;
7402 this.temporaryCount = 0;
7403 this.usesImplicitReceiver = false;
7404 }
7405 visitUnary(ast, mode) {
7406 let op;
7407 switch (ast.operator) {
7408 case '+':
7409 op = UnaryOperator.Plus;
7410 break;
7411 case '-':
7412 op = UnaryOperator.Minus;
7413 break;
7414 default:
7415 throw new Error(`Unsupported operator ${ast.operator}`);
7416 }
7417 return convertToStatementIfNeeded(mode, new UnaryOperatorExpr(op, this._visit(ast.expr, _Mode.Expression), undefined, this.convertSourceSpan(ast.span)));
7418 }
7419 visitBinary(ast, mode) {
7420 let op;
7421 switch (ast.operation) {
7422 case '+':
7423 op = BinaryOperator.Plus;
7424 break;
7425 case '-':
7426 op = BinaryOperator.Minus;
7427 break;
7428 case '*':
7429 op = BinaryOperator.Multiply;
7430 break;
7431 case '/':
7432 op = BinaryOperator.Divide;
7433 break;
7434 case '%':
7435 op = BinaryOperator.Modulo;
7436 break;
7437 case '&&':
7438 op = BinaryOperator.And;
7439 break;
7440 case '||':
7441 op = BinaryOperator.Or;
7442 break;
7443 case '==':
7444 op = BinaryOperator.Equals;
7445 break;
7446 case '!=':
7447 op = BinaryOperator.NotEquals;
7448 break;
7449 case '===':
7450 op = BinaryOperator.Identical;
7451 break;
7452 case '!==':
7453 op = BinaryOperator.NotIdentical;
7454 break;
7455 case '<':
7456 op = BinaryOperator.Lower;
7457 break;
7458 case '>':
7459 op = BinaryOperator.Bigger;
7460 break;
7461 case '<=':
7462 op = BinaryOperator.LowerEquals;
7463 break;
7464 case '>=':
7465 op = BinaryOperator.BiggerEquals;
7466 break;
7467 default:
7468 throw new Error(`Unsupported operation ${ast.operation}`);
7469 }
7470 return convertToStatementIfNeeded(mode, new BinaryOperatorExpr(op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression), undefined, this.convertSourceSpan(ast.span)));
7471 }
7472 visitChain(ast, mode) {
7473 ensureStatementMode(mode, ast);
7474 return this.visitAll(ast.expressions, mode);
7475 }
7476 visitConditional(ast, mode) {
7477 const value = this._visit(ast.condition, _Mode.Expression);
7478 return convertToStatementIfNeeded(mode, value.conditional(this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span)));
7479 }
7480 visitPipe(ast, mode) {
7481 throw new Error(`Illegal state: Pipes should have been converted into functions. Pipe: ${ast.name}`);
7482 }
7483 visitFunctionCall(ast, mode) {
7484 const convertedArgs = this.visitAll(ast.args, _Mode.Expression);
7485 let fnResult;
7486 if (ast instanceof BuiltinFunctionCall) {
7487 fnResult = ast.converter(convertedArgs);
7488 }
7489 else {
7490 fnResult = this._visit(ast.target, _Mode.Expression)
7491 .callFn(convertedArgs, this.convertSourceSpan(ast.span));
7492 }
7493 return convertToStatementIfNeeded(mode, fnResult);
7494 }
7495 visitImplicitReceiver(ast, mode) {
7496 ensureExpressionMode(mode, ast);
7497 this.usesImplicitReceiver = true;
7498 return this._implicitReceiver;
7499 }
7500 visitThisReceiver(ast, mode) {
7501 return this.visitImplicitReceiver(ast, mode);
7502 }
7503 visitInterpolation(ast, mode) {
7504 ensureExpressionMode(mode, ast);
7505 const args = [literal(ast.expressions.length)];
7506 for (let i = 0; i < ast.strings.length - 1; i++) {
7507 args.push(literal(ast.strings[i]));
7508 args.push(this._visit(ast.expressions[i], _Mode.Expression));
7509 }
7510 args.push(literal(ast.strings[ast.strings.length - 1]));
7511 if (this.interpolationFunction) {
7512 return this.interpolationFunction(args);
7513 }
7514 return ast.expressions.length <= 9 ?
7515 importExpr(Identifiers.inlineInterpolate).callFn(args) :
7516 importExpr(Identifiers.interpolate).callFn([
7517 args[0], literalArr(args.slice(1), undefined, this.convertSourceSpan(ast.span))
7518 ]);
7519 }
7520 visitKeyedRead(ast, mode) {
7521 const leftMostSafe = this.leftMostSafeNode(ast);
7522 if (leftMostSafe) {
7523 return this.convertSafeAccess(ast, leftMostSafe, mode);
7524 }
7525 else {
7526 return convertToStatementIfNeeded(mode, this._visit(ast.obj, _Mode.Expression).key(this._visit(ast.key, _Mode.Expression)));
7527 }
7528 }
7529 visitKeyedWrite(ast, mode) {
7530 const obj = this._visit(ast.obj, _Mode.Expression);
7531 const key = this._visit(ast.key, _Mode.Expression);
7532 const value = this._visit(ast.value, _Mode.Expression);
7533 return convertToStatementIfNeeded(mode, obj.key(key).set(value));
7534 }
7535 visitLiteralArray(ast, mode) {
7536 throw new Error(`Illegal State: literal arrays should have been converted into functions`);
7537 }
7538 visitLiteralMap(ast, mode) {
7539 throw new Error(`Illegal State: literal maps should have been converted into functions`);
7540 }
7541 visitLiteralPrimitive(ast, mode) {
7542 // For literal values of null, undefined, true, or false allow type interference
7543 // to infer the type.
7544 const type = ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
7545 INFERRED_TYPE :
7546 undefined;
7547 return convertToStatementIfNeeded(mode, literal(ast.value, type, this.convertSourceSpan(ast.span)));
7548 }
7549 _getLocal(name, receiver) {
7550 var _a;
7551 if (((_a = this._localResolver.globals) === null || _a === void 0 ? void 0 : _a.has(name)) && receiver instanceof ThisReceiver) {
7552 return null;
7553 }
7554 return this._localResolver.getLocal(name);
7555 }
7556 visitMethodCall(ast, mode) {
7557 if (ast.receiver instanceof ImplicitReceiver &&
7558 !(ast.receiver instanceof ThisReceiver) && ast.name === '$any') {
7559 const args = this.visitAll(ast.args, _Mode.Expression);
7560 if (args.length != 1) {
7561 throw new Error(`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
7562 }
7563 return args[0].cast(DYNAMIC_TYPE, this.convertSourceSpan(ast.span));
7564 }
7565 const leftMostSafe = this.leftMostSafeNode(ast);
7566 if (leftMostSafe) {
7567 return this.convertSafeAccess(ast, leftMostSafe, mode);
7568 }
7569 else {
7570 const args = this.visitAll(ast.args, _Mode.Expression);
7571 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7572 let result = null;
7573 const receiver = this._visit(ast.receiver, _Mode.Expression);
7574 if (receiver === this._implicitReceiver) {
7575 const varExpr = this._getLocal(ast.name, ast.receiver);
7576 if (varExpr) {
7577 // Restore the previous "usesImplicitReceiver" state since the implicit
7578 // receiver has been replaced with a resolved local expression.
7579 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7580 result = varExpr.callFn(args);
7581 this.addImplicitReceiverAccess(ast.name);
7582 }
7583 }
7584 if (result == null) {
7585 result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span));
7586 }
7587 return convertToStatementIfNeeded(mode, result);
7588 }
7589 }
7590 visitPrefixNot(ast, mode) {
7591 return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression)));
7592 }
7593 visitNonNullAssert(ast, mode) {
7594 return convertToStatementIfNeeded(mode, assertNotNull(this._visit(ast.expression, _Mode.Expression)));
7595 }
7596 visitPropertyRead(ast, mode) {
7597 const leftMostSafe = this.leftMostSafeNode(ast);
7598 if (leftMostSafe) {
7599 return this.convertSafeAccess(ast, leftMostSafe, mode);
7600 }
7601 else {
7602 let result = null;
7603 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7604 const receiver = this._visit(ast.receiver, _Mode.Expression);
7605 if (receiver === this._implicitReceiver) {
7606 result = this._getLocal(ast.name, ast.receiver);
7607 if (result) {
7608 // Restore the previous "usesImplicitReceiver" state since the implicit
7609 // receiver has been replaced with a resolved local expression.
7610 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7611 this.addImplicitReceiverAccess(ast.name);
7612 }
7613 }
7614 if (result == null) {
7615 result = receiver.prop(ast.name);
7616 }
7617 return convertToStatementIfNeeded(mode, result);
7618 }
7619 }
7620 visitPropertyWrite(ast, mode) {
7621 const receiver = this._visit(ast.receiver, _Mode.Expression);
7622 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7623 let varExpr = null;
7624 if (receiver === this._implicitReceiver) {
7625 const localExpr = this._getLocal(ast.name, ast.receiver);
7626 if (localExpr) {
7627 if (localExpr instanceof ReadPropExpr) {
7628 // If the local variable is a property read expression, it's a reference
7629 // to a 'context.property' value and will be used as the target of the
7630 // write expression.
7631 varExpr = localExpr;
7632 // Restore the previous "usesImplicitReceiver" state since the implicit
7633 // receiver has been replaced with a resolved local expression.
7634 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7635 this.addImplicitReceiverAccess(ast.name);
7636 }
7637 else {
7638 // Otherwise it's an error.
7639 const receiver = ast.name;
7640 const value = (ast.value instanceof PropertyRead) ? ast.value.name : undefined;
7641 throw new Error(`Cannot assign value "${value}" to template variable "${receiver}". Template variables are read-only.`);
7642 }
7643 }
7644 }
7645 // If no local expression could be produced, use the original receiver's
7646 // property as the target.
7647 if (varExpr === null) {
7648 varExpr = receiver.prop(ast.name);
7649 }
7650 return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression)));
7651 }
7652 visitSafePropertyRead(ast, mode) {
7653 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7654 }
7655 visitSafeMethodCall(ast, mode) {
7656 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7657 }
7658 visitAll(asts, mode) {
7659 return asts.map(ast => this._visit(ast, mode));
7660 }
7661 visitQuote(ast, mode) {
7662 throw new Error(`Quotes are not supported for evaluation!
7663 Statement: ${ast.uninterpretedExpression} located at ${ast.location}`);
7664 }
7665 _visit(ast, mode) {
7666 const result = this._resultMap.get(ast);
7667 if (result)
7668 return result;
7669 return (this._nodeMap.get(ast) || ast).visit(this, mode);
7670 }
7671 convertSafeAccess(ast, leftMostSafe, mode) {
7672 // If the expression contains a safe access node on the left it needs to be converted to
7673 // an expression that guards the access to the member by checking the receiver for blank. As
7674 // execution proceeds from left to right, the left most part of the expression must be guarded
7675 // first but, because member access is left associative, the right side of the expression is at
7676 // the top of the AST. The desired result requires lifting a copy of the left part of the
7677 // expression up to test it for blank before generating the unguarded version.
7678 // Consider, for example the following expression: a?.b.c?.d.e
7679 // This results in the ast:
7680 // .
7681 // / \
7682 // ?. e
7683 // / \
7684 // . d
7685 // / \
7686 // ?. c
7687 // / \
7688 // a b
7689 // The following tree should be generated:
7690 //
7691 // /---- ? ----\
7692 // / | \
7693 // a /--- ? ---\ null
7694 // / | \
7695 // . . null
7696 // / \ / \
7697 // . c . e
7698 // / \ / \
7699 // a b . d
7700 // / \
7701 // . c
7702 // / \
7703 // a b
7704 //
7705 // Notice that the first guard condition is the left hand of the left most safe access node
7706 // which comes in as leftMostSafe to this routine.
7707 let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression);
7708 let temporary = undefined;
7709 if (this.needsTemporary(leftMostSafe.receiver)) {
7710 // If the expression has method calls or pipes then we need to save the result into a
7711 // temporary variable to avoid calling stateful or impure code more than once.
7712 temporary = this.allocateTemporary();
7713 // Preserve the result in the temporary variable
7714 guardedExpression = temporary.set(guardedExpression);
7715 // Ensure all further references to the guarded expression refer to the temporary instead.
7716 this._resultMap.set(leftMostSafe.receiver, temporary);
7717 }
7718 const condition = guardedExpression.isBlank();
7719 // Convert the ast to an unguarded access to the receiver's member. The map will substitute
7720 // leftMostNode with its unguarded version in the call to `this.visit()`.
7721 if (leftMostSafe instanceof SafeMethodCall) {
7722 this._nodeMap.set(leftMostSafe, new MethodCall(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args));
7723 }
7724 else {
7725 this._nodeMap.set(leftMostSafe, new PropertyRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name));
7726 }
7727 // Recursively convert the node now without the guarded member access.
7728 const access = this._visit(ast, _Mode.Expression);
7729 // Remove the mapping. This is not strictly required as the converter only traverses each node
7730 // once but is safer if the conversion is changed to traverse the nodes more than once.
7731 this._nodeMap.delete(leftMostSafe);
7732 // If we allocated a temporary, release it.
7733 if (temporary) {
7734 this.releaseTemporary(temporary);
7735 }
7736 // Produce the conditional
7737 return convertToStatementIfNeeded(mode, condition.conditional(literal(null), access));
7738 }
7739 // Given an expression of the form a?.b.c?.d.e then the left most safe node is
7740 // the (a?.b). The . and ?. are left associative thus can be rewritten as:
7741 // ((((a?.c).b).c)?.d).e. This returns the most deeply nested safe read or
7742 // safe method call as this needs to be transformed initially to:
7743 // a == null ? null : a.c.b.c?.d.e
7744 // then to:
7745 // a == null ? null : a.b.c == null ? null : a.b.c.d.e
7746 leftMostSafeNode(ast) {
7747 const visit = (visitor, ast) => {
7748 return (this._nodeMap.get(ast) || ast).visit(visitor);
7749 };
7750 return ast.visit({
7751 visitUnary(ast) {
7752 return null;
7753 },
7754 visitBinary(ast) {
7755 return null;
7756 },
7757 visitChain(ast) {
7758 return null;
7759 },
7760 visitConditional(ast) {
7761 return null;
7762 },
7763 visitFunctionCall(ast) {
7764 return null;
7765 },
7766 visitImplicitReceiver(ast) {
7767 return null;
7768 },
7769 visitThisReceiver(ast) {
7770 return null;
7771 },
7772 visitInterpolation(ast) {
7773 return null;
7774 },
7775 visitKeyedRead(ast) {
7776 return visit(this, ast.obj);
7777 },
7778 visitKeyedWrite(ast) {
7779 return null;
7780 },
7781 visitLiteralArray(ast) {
7782 return null;
7783 },
7784 visitLiteralMap(ast) {
7785 return null;
7786 },
7787 visitLiteralPrimitive(ast) {
7788 return null;
7789 },
7790 visitMethodCall(ast) {
7791 return visit(this, ast.receiver);
7792 },
7793 visitPipe(ast) {
7794 return null;
7795 },
7796 visitPrefixNot(ast) {
7797 return null;
7798 },
7799 visitNonNullAssert(ast) {
7800 return null;
7801 },
7802 visitPropertyRead(ast) {
7803 return visit(this, ast.receiver);
7804 },
7805 visitPropertyWrite(ast) {
7806 return null;
7807 },
7808 visitQuote(ast) {
7809 return null;
7810 },
7811 visitSafeMethodCall(ast) {
7812 return visit(this, ast.receiver) || ast;
7813 },
7814 visitSafePropertyRead(ast) {
7815 return visit(this, ast.receiver) || ast;
7816 }
7817 });
7818 }
7819 // Returns true of the AST includes a method or a pipe indicating that, if the
7820 // expression is used as the target of a safe property or method access then
7821 // the expression should be stored into a temporary variable.
7822 needsTemporary(ast) {
7823 const visit = (visitor, ast) => {
7824 return ast && (this._nodeMap.get(ast) || ast).visit(visitor);
7825 };
7826 const visitSome = (visitor, ast) => {
7827 return ast.some(ast => visit(visitor, ast));
7828 };
7829 return ast.visit({
7830 visitUnary(ast) {
7831 return visit(this, ast.expr);
7832 },
7833 visitBinary(ast) {
7834 return visit(this, ast.left) || visit(this, ast.right);
7835 },
7836 visitChain(ast) {
7837 return false;
7838 },
7839 visitConditional(ast) {
7840 return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp);
7841 },
7842 visitFunctionCall(ast) {
7843 return true;
7844 },
7845 visitImplicitReceiver(ast) {
7846 return false;
7847 },
7848 visitThisReceiver(ast) {
7849 return false;
7850 },
7851 visitInterpolation(ast) {
7852 return visitSome(this, ast.expressions);
7853 },
7854 visitKeyedRead(ast) {
7855 return false;
7856 },
7857 visitKeyedWrite(ast) {
7858 return false;
7859 },
7860 visitLiteralArray(ast) {
7861 return true;
7862 },
7863 visitLiteralMap(ast) {
7864 return true;
7865 },
7866 visitLiteralPrimitive(ast) {
7867 return false;
7868 },
7869 visitMethodCall(ast) {
7870 return true;
7871 },
7872 visitPipe(ast) {
7873 return true;
7874 },
7875 visitPrefixNot(ast) {
7876 return visit(this, ast.expression);
7877 },
7878 visitNonNullAssert(ast) {
7879 return visit(this, ast.expression);
7880 },
7881 visitPropertyRead(ast) {
7882 return false;
7883 },
7884 visitPropertyWrite(ast) {
7885 return false;
7886 },
7887 visitQuote(ast) {
7888 return false;
7889 },
7890 visitSafeMethodCall(ast) {
7891 return true;
7892 },
7893 visitSafePropertyRead(ast) {
7894 return false;
7895 }
7896 });
7897 }
7898 allocateTemporary() {
7899 const tempNumber = this._currentTemporary++;
7900 this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount);
7901 return new ReadVarExpr(temporaryName(this.bindingId, tempNumber));
7902 }
7903 releaseTemporary(temporary) {
7904 this._currentTemporary--;
7905 if (temporary.name != temporaryName(this.bindingId, this._currentTemporary)) {
7906 throw new Error(`Temporary ${temporary.name} released out of order`);
7907 }
7908 }
7909 /**
7910 * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`.
7911 *
7912 * `ParseSpan` objects are relative to the start of the expression.
7913 * This method converts these to full `ParseSourceSpan` objects that
7914 * show where the span is within the overall source file.
7915 *
7916 * @param span the relative span to convert.
7917 * @returns a `ParseSourceSpan` for the given span or null if no
7918 * `baseSourceSpan` was provided to this class.
7919 */
7920 convertSourceSpan(span) {
7921 if (this.baseSourceSpan) {
7922 const start = this.baseSourceSpan.start.moveBy(span.start);
7923 const end = this.baseSourceSpan.start.moveBy(span.end);
7924 const fullStart = this.baseSourceSpan.fullStart.moveBy(span.start);
7925 return new ParseSourceSpan(start, end, fullStart);
7926 }
7927 else {
7928 return null;
7929 }
7930 }
7931 /** Adds the name of an AST to the list of implicit receiver accesses. */
7932 addImplicitReceiverAccess(name) {
7933 if (this.implicitReceiverAccesses) {
7934 this.implicitReceiverAccesses.add(name);
7935 }
7936 }
7937 }
7938 function flattenStatements(arg, output) {
7939 if (Array.isArray(arg)) {
7940 arg.forEach((entry) => flattenStatements(entry, output));
7941 }
7942 else {
7943 output.push(arg);
7944 }
7945 }
7946 class DefaultLocalResolver {
7947 constructor(globals) {
7948 this.globals = globals;
7949 }
7950 notifyImplicitReceiverUse() { }
7951 getLocal(name) {
7952 if (name === EventHandlerVars.event.name) {
7953 return EventHandlerVars.event;
7954 }
7955 return null;
7956 }
7957 }
7958 function createCurrValueExpr(bindingId) {
7959 return variable(`currVal_${bindingId}`); // fix syntax highlighting: `
7960 }
7961 function createPreventDefaultVar(bindingId) {
7962 return variable(`pd_${bindingId}`);
7963 }
7964 function convertStmtIntoExpression(stmt) {
7965 if (stmt instanceof ExpressionStatement) {
7966 return stmt.expr;
7967 }
7968 else if (stmt instanceof ReturnStatement) {
7969 return stmt.value;
7970 }
7971 return null;
7972 }
7973 class BuiltinFunctionCall extends FunctionCall {
7974 constructor(span, sourceSpan, args, converter) {
7975 super(span, sourceSpan, null, args);
7976 this.args = args;
7977 this.converter = converter;
7978 }
7979 }
7980
7981 /**
7982 * @license
7983 * Copyright Google LLC All Rights Reserved.
7984 *
7985 * Use of this source code is governed by an MIT-style license that can be
7986 * found in the LICENSE file at https://angular.io/license
7987 */
7988 /**
7989 * This file is a port of shadowCSS from webcomponents.js to TypeScript.
7990 *
7991 * Please make sure to keep to edits in sync with the source file.
7992 *
7993 * Source:
7994 * https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
7995 *
7996 * The original file level comment is reproduced below
7997 */
7998 /*
7999 This is a limited shim for ShadowDOM css styling.
8000 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles
8001
8002 The intention here is to support only the styling features which can be
8003 relatively simply implemented. The goal is to allow users to avoid the
8004 most obvious pitfalls and do so without compromising performance significantly.
8005 For ShadowDOM styling that's not covered here, a set of best practices
8006 can be provided that should allow users to accomplish more complex styling.
8007
8008 The following is a list of specific ShadowDOM styling features and a brief
8009 discussion of the approach used to shim.
8010
8011 Shimmed features:
8012
8013 * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
8014 element using the :host rule. To shim this feature, the :host styles are
8015 reformatted and prefixed with a given scope name and promoted to a
8016 document level stylesheet.
8017 For example, given a scope name of .foo, a rule like this:
8018
8019 :host {
8020 background: red;
8021 }
8022 }
8023
8024 becomes:
8025
8026 .foo {
8027 background: red;
8028 }
8029
8030 * encapsulation: Styles defined within ShadowDOM, apply only to
8031 dom inside the ShadowDOM. Polymer uses one of two techniques to implement
8032 this feature.
8033
8034 By default, rules are prefixed with the host element tag name
8035 as a descendant selector. This ensures styling does not leak out of the 'top'
8036 of the element's ShadowDOM. For example,
8037
8038 div {
8039 font-weight: bold;
8040 }
8041
8042 becomes:
8043
8044 x-foo div {
8045 font-weight: bold;
8046 }
8047
8048 becomes:
8049
8050
8051 Alternatively, if WebComponents.ShadowCSS.strictStyling is set to true then
8052 selectors are scoped by adding an attribute selector suffix to each
8053 simple selector that contains the host element tag name. Each element
8054 in the element's ShadowDOM template is also given the scope attribute.
8055 Thus, these rules match only elements that have the scope attribute.
8056 For example, given a scope name of x-foo, a rule like this:
8057
8058 div {
8059 font-weight: bold;
8060 }
8061
8062 becomes:
8063
8064 div[x-foo] {
8065 font-weight: bold;
8066 }
8067
8068 Note that elements that are dynamically added to a scope must have the scope
8069 selector added to them manually.
8070
8071 * upper/lower bound encapsulation: Styles which are defined outside a
8072 shadowRoot should not cross the ShadowDOM boundary and should not apply
8073 inside a shadowRoot.
8074
8075 This styling behavior is not emulated. Some possible ways to do this that
8076 were rejected due to complexity and/or performance concerns include: (1) reset
8077 every possible property for every possible selector for a given scope name;
8078 (2) re-implement css in javascript.
8079
8080 As an alternative, users should make sure to use selectors
8081 specific to the scope in which they are working.
8082
8083 * ::distributed: This behavior is not emulated. It's often not necessary
8084 to style the contents of a specific insertion point and instead, descendants
8085 of the host element can be styled selectively. Users can also create an
8086 extra node around an insertion point and style that node's contents
8087 via descendent selectors. For example, with a shadowRoot like this:
8088
8089 <style>
8090 ::content(div) {
8091 background: red;
8092 }
8093 </style>
8094 <content></content>
8095
8096 could become:
8097
8098 <style>
8099 / *@polyfill .content-container div * /
8100 ::content(div) {
8101 background: red;
8102 }
8103 </style>
8104 <div class="content-container">
8105 <content></content>
8106 </div>
8107
8108 Note the use of @polyfill in the comment above a ShadowDOM specific style
8109 declaration. This is a directive to the styling shim to use the selector
8110 in comments in lieu of the next selector when running under polyfill.
8111 */
8112 class ShadowCss {
8113 constructor() {
8114 this.strictStyling = true;
8115 }
8116 /*
8117 * Shim some cssText with the given selector. Returns cssText that can
8118 * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css).
8119 *
8120 * When strictStyling is true:
8121 * - selector is the attribute added to all elements inside the host,
8122 * - hostSelector is the attribute added to the host itself.
8123 */
8124 shimCssText(cssText, selector, hostSelector = '') {
8125 const commentsWithHash = extractCommentsWithHash(cssText);
8126 cssText = stripComments(cssText);
8127 cssText = this._insertDirectives(cssText);
8128 const scopedCssText = this._scopeCssText(cssText, selector, hostSelector);
8129 return [scopedCssText, ...commentsWithHash].join('\n');
8130 }
8131 _insertDirectives(cssText) {
8132 cssText = this._insertPolyfillDirectivesInCssText(cssText);
8133 return this._insertPolyfillRulesInCssText(cssText);
8134 }
8135 /*
8136 * Process styles to convert native ShadowDOM rules that will trip
8137 * up the css parser; we rely on decorating the stylesheet with inert rules.
8138 *
8139 * For example, we convert this rule:
8140 *
8141 * polyfill-next-selector { content: ':host menu-item'; }
8142 * ::content menu-item {
8143 *
8144 * to this:
8145 *
8146 * scopeName menu-item {
8147 *
8148 **/
8149 _insertPolyfillDirectivesInCssText(cssText) {
8150 // Difference with webcomponents.js: does not handle comments
8151 return cssText.replace(_cssContentNextSelectorRe, function (...m) {
8152 return m[2] + '{';
8153 });
8154 }
8155 /*
8156 * Process styles to add rules which will only apply under the polyfill
8157 *
8158 * For example, we convert this rule:
8159 *
8160 * polyfill-rule {
8161 * content: ':host menu-item';
8162 * ...
8163 * }
8164 *
8165 * to this:
8166 *
8167 * scopeName menu-item {...}
8168 *
8169 **/
8170 _insertPolyfillRulesInCssText(cssText) {
8171 // Difference with webcomponents.js: does not handle comments
8172 return cssText.replace(_cssContentRuleRe, (...m) => {
8173 const rule = m[0].replace(m[1], '').replace(m[2], '');
8174 return m[4] + rule;
8175 });
8176 }
8177 /* Ensure styles are scoped. Pseudo-scoping takes a rule like:
8178 *
8179 * .foo {... }
8180 *
8181 * and converts this to
8182 *
8183 * scopeName .foo { ... }
8184 */
8185 _scopeCssText(cssText, scopeSelector, hostSelector) {
8186 const unscopedRules = this._extractUnscopedRulesFromCssText(cssText);
8187 // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively
8188 cssText = this._insertPolyfillHostInCssText(cssText);
8189 cssText = this._convertColonHost(cssText);
8190 cssText = this._convertColonHostContext(cssText);
8191 cssText = this._convertShadowDOMSelectors(cssText);
8192 if (scopeSelector) {
8193 cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
8194 }
8195 cssText = cssText + '\n' + unscopedRules;
8196 return cssText.trim();
8197 }
8198 /*
8199 * Process styles to add rules which will only apply under the polyfill
8200 * and do not process via CSSOM. (CSSOM is destructive to rules on rare
8201 * occasions, e.g. -webkit-calc on Safari.)
8202 * For example, we convert this rule:
8203 *
8204 * @polyfill-unscoped-rule {
8205 * content: 'menu-item';
8206 * ... }
8207 *
8208 * to this:
8209 *
8210 * menu-item {...}
8211 *
8212 **/
8213 _extractUnscopedRulesFromCssText(cssText) {
8214 // Difference with webcomponents.js: does not handle comments
8215 let r = '';
8216 let m;
8217 _cssContentUnscopedRuleRe.lastIndex = 0;
8218 while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
8219 const rule = m[0].replace(m[2], '').replace(m[1], m[4]);
8220 r += rule + '\n\n';
8221 }
8222 return r;
8223 }
8224 /*
8225 * convert a rule like :host(.foo) > .bar { }
8226 *
8227 * to
8228 *
8229 * .foo<scopeName> > .bar
8230 */
8231 _convertColonHost(cssText) {
8232 return cssText.replace(_cssColonHostRe, (_, hostSelectors, otherSelectors) => {
8233 if (hostSelectors) {
8234 const convertedSelectors = [];
8235 const hostSelectorArray = hostSelectors.split(',').map(p => p.trim());
8236 for (const hostSelector of hostSelectorArray) {
8237 if (!hostSelector)
8238 break;
8239 const convertedSelector = _polyfillHostNoCombinator + hostSelector.replace(_polyfillHost, '') + otherSelectors;
8240 convertedSelectors.push(convertedSelector);
8241 }
8242 return convertedSelectors.join(',');
8243 }
8244 else {
8245 return _polyfillHostNoCombinator + otherSelectors;
8246 }
8247 });
8248 }
8249 /*
8250 * convert a rule like :host-context(.foo) > .bar { }
8251 *
8252 * to
8253 *
8254 * .foo<scopeName> > .bar, .foo <scopeName> > .bar { }
8255 *
8256 * and
8257 *
8258 * :host-context(.foo:host) .bar { ... }
8259 *
8260 * to
8261 *
8262 * .foo<scopeName> .bar { ... }
8263 */
8264 _convertColonHostContext(cssText) {
8265 return cssText.replace(_cssColonHostContextReGlobal, selectorText => {
8266 // We have captured a selector that contains a `:host-context` rule.
8267 var _a;
8268 // For backward compatibility `:host-context` may contain a comma separated list of selectors.
8269 // Each context selector group will contain a list of host-context selectors that must match
8270 // an ancestor of the host.
8271 // (Normally `contextSelectorGroups` will only contain a single array of context selectors.)
8272 const contextSelectorGroups = [[]];
8273 // There may be more than `:host-context` in this selector so `selectorText` could look like:
8274 // `:host-context(.one):host-context(.two)`.
8275 // Execute `_cssColonHostContextRe` over and over until we have extracted all the
8276 // `:host-context` selectors from this selector.
8277 let match;
8278 while (match = _cssColonHostContextRe.exec(selectorText)) {
8279 // `match` = [':host-context(<selectors>)<rest>', <selectors>, <rest>]
8280 // The `<selectors>` could actually be a comma separated list: `:host-context(.one, .two)`.
8281 const newContextSelectors = ((_a = match[1]) !== null && _a !== void 0 ? _a : '').trim().split(',').map(m => m.trim()).filter(m => m !== '');
8282 // We must duplicate the current selector group for each of these new selectors.
8283 // For example if the current groups are:
8284 // ```
8285 // [
8286 // ['a', 'b', 'c'],
8287 // ['x', 'y', 'z'],
8288 // ]
8289 // ```
8290 // And we have a new set of comma separated selectors: `:host-context(m,n)` then the new
8291 // groups are:
8292 // ```
8293 // [
8294 // ['a', 'b', 'c', 'm'],
8295 // ['x', 'y', 'z', 'm'],
8296 // ['a', 'b', 'c', 'n'],
8297 // ['x', 'y', 'z', 'n'],
8298 // ]
8299 // ```
8300 const contextSelectorGroupsLength = contextSelectorGroups.length;
8301 repeatGroups(contextSelectorGroups, newContextSelectors.length);
8302 for (let i = 0; i < newContextSelectors.length; i++) {
8303 for (let j = 0; j < contextSelectorGroupsLength; j++) {
8304 contextSelectorGroups[j + (i * contextSelectorGroupsLength)].push(newContextSelectors[i]);
8305 }
8306 }
8307 // Update the `selectorText` and see repeat to see if there are more `:host-context`s.
8308 selectorText = match[2];
8309 }
8310 // The context selectors now must be combined with each other to capture all the possible
8311 // selectors that `:host-context` can match. See `combineHostContextSelectors()` for more
8312 // info about how this is done.
8313 return contextSelectorGroups
8314 .map(contextSelectors => combineHostContextSelectors(contextSelectors, selectorText))
8315 .join(', ');
8316 });
8317 }
8318 /*
8319 * Convert combinators like ::shadow and pseudo-elements like ::content
8320 * by replacing with space.
8321 */
8322 _convertShadowDOMSelectors(cssText) {
8323 return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText);
8324 }
8325 // change a selector like 'div' to 'name div'
8326 _scopeSelectors(cssText, scopeSelector, hostSelector) {
8327 return processRules(cssText, (rule) => {
8328 let selector = rule.selector;
8329 let content = rule.content;
8330 if (rule.selector[0] != '@') {
8331 selector =
8332 this._scopeSelector(rule.selector, scopeSelector, hostSelector, this.strictStyling);
8333 }
8334 else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') ||
8335 rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) {
8336 content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
8337 }
8338 return new CssRule(selector, content);
8339 });
8340 }
8341 _scopeSelector(selector, scopeSelector, hostSelector, strict) {
8342 return selector.split(',')
8343 .map(part => part.trim().split(_shadowDeepSelectors))
8344 .map((deepParts) => {
8345 const [shallowPart, ...otherParts] = deepParts;
8346 const applyScope = (shallowPart) => {
8347 if (this._selectorNeedsScoping(shallowPart, scopeSelector)) {
8348 return strict ?
8349 this._applyStrictSelectorScope(shallowPart, scopeSelector, hostSelector) :
8350 this._applySelectorScope(shallowPart, scopeSelector, hostSelector);
8351 }
8352 else {
8353 return shallowPart;
8354 }
8355 };
8356 return [applyScope(shallowPart), ...otherParts].join(' ');
8357 })
8358 .join(', ');
8359 }
8360 _selectorNeedsScoping(selector, scopeSelector) {
8361 const re = this._makeScopeMatcher(scopeSelector);
8362 return !re.test(selector);
8363 }
8364 _makeScopeMatcher(scopeSelector) {
8365 const lre = /\[/g;
8366 const rre = /\]/g;
8367 scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
8368 return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
8369 }
8370 _applySelectorScope(selector, scopeSelector, hostSelector) {
8371 // Difference from webcomponents.js: scopeSelector could not be an array
8372 return this._applySimpleSelectorScope(selector, scopeSelector, hostSelector);
8373 }
8374 // scope via name and [is=name]
8375 _applySimpleSelectorScope(selector, scopeSelector, hostSelector) {
8376 // In Android browser, the lastIndex is not reset when the regex is used in String.replace()
8377 _polyfillHostRe.lastIndex = 0;
8378 if (_polyfillHostRe.test(selector)) {
8379 const replaceBy = this.strictStyling ? `[${hostSelector}]` : scopeSelector;
8380 return selector
8381 .replace(_polyfillHostNoCombinatorRe, (hnc, selector) => {
8382 return selector.replace(/([^:]*)(:*)(.*)/, (_, before, colon, after) => {
8383 return before + replaceBy + colon + after;
8384 });
8385 })
8386 .replace(_polyfillHostRe, replaceBy + ' ');
8387 }
8388 return scopeSelector + ' ' + selector;
8389 }
8390 // return a selector with [name] suffix on each simple selector
8391 // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */
8392 _applyStrictSelectorScope(selector, scopeSelector, hostSelector) {
8393 const isRe = /\[is=([^\]]*)\]/g;
8394 scopeSelector = scopeSelector.replace(isRe, (_, ...parts) => parts[0]);
8395 const attrName = '[' + scopeSelector + ']';
8396 const _scopeSelectorPart = (p) => {
8397 let scopedP = p.trim();
8398 if (!scopedP) {
8399 return '';
8400 }
8401 if (p.indexOf(_polyfillHostNoCombinator) > -1) {
8402 scopedP = this._applySimpleSelectorScope(p, scopeSelector, hostSelector);
8403 }
8404 else {
8405 // remove :host since it should be unnecessary
8406 const t = p.replace(_polyfillHostRe, '');
8407 if (t.length > 0) {
8408 const matches = t.match(/([^:]*)(:*)(.*)/);
8409 if (matches) {
8410 scopedP = matches[1] + attrName + matches[2] + matches[3];
8411 }
8412 }
8413 }
8414 return scopedP;
8415 };
8416 const safeContent = new SafeSelector(selector);
8417 selector = safeContent.content();
8418 let scopedSelector = '';
8419 let startIndex = 0;
8420 let res;
8421 const sep = /( |>|\+|~(?!=))\s*/g;
8422 // If a selector appears before :host it should not be shimmed as it
8423 // matches on ancestor elements and not on elements in the host's shadow
8424 // `:host-context(div)` is transformed to
8425 // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator`
8426 // the `div` is not part of the component in the 2nd selectors and should not be scoped.
8427 // Historically `component-tag:host` was matching the component so we also want to preserve
8428 // this behavior to avoid breaking legacy apps (it should not match).
8429 // The behavior should be:
8430 // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything)
8431 // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a
8432 // `:host-context(tag)`)
8433 const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;
8434 // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present
8435 let shouldScope = !hasHost;
8436 while ((res = sep.exec(selector)) !== null) {
8437 const separator = res[1];
8438 const part = selector.slice(startIndex, res.index).trim();
8439 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
8440 const scopedPart = shouldScope ? _scopeSelectorPart(part) : part;
8441 scopedSelector += `${scopedPart} ${separator} `;
8442 startIndex = sep.lastIndex;
8443 }
8444 const part = selector.substring(startIndex);
8445 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
8446 scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;
8447 // replace the placeholders with their original values
8448 return safeContent.restore(scopedSelector);
8449 }
8450 _insertPolyfillHostInCssText(selector) {
8451 return selector.replace(_colonHostContextRe, _polyfillHostContext)
8452 .replace(_colonHostRe, _polyfillHost);
8453 }
8454 }
8455 class SafeSelector {
8456 constructor(selector) {
8457 this.placeholders = [];
8458 this.index = 0;
8459 // Replaces attribute selectors with placeholders.
8460 // The WS in [attr="va lue"] would otherwise be interpreted as a selector separator.
8461 selector = this._escapeRegexMatches(selector, /(\[[^\]]*\])/g);
8462 // CSS allows for certain special characters to be used in selectors if they're escaped.
8463 // E.g. `.foo:blue` won't match a class called `foo:blue`, because the colon denotes a
8464 // pseudo-class, but writing `.foo\:blue` will match, because the colon was escaped.
8465 // Replace all escape sequences (`\` followed by a character) with a placeholder so
8466 // that our handling of pseudo-selectors doesn't mess with them.
8467 selector = this._escapeRegexMatches(selector, /(\\.)/g);
8468 // Replaces the expression in `:nth-child(2n + 1)` with a placeholder.
8469 // WS and "+" would otherwise be interpreted as selector separators.
8470 this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => {
8471 const replaceBy = `__ph-${this.index}__`;
8472 this.placeholders.push(exp);
8473 this.index++;
8474 return pseudo + replaceBy;
8475 });
8476 }
8477 restore(content) {
8478 return content.replace(/__ph-(\d+)__/g, (_ph, index) => this.placeholders[+index]);
8479 }
8480 content() {
8481 return this._content;
8482 }
8483 /**
8484 * Replaces all of the substrings that match a regex within a
8485 * special string (e.g. `__ph-0__`, `__ph-1__`, etc).
8486 */
8487 _escapeRegexMatches(content, pattern) {
8488 return content.replace(pattern, (_, keep) => {
8489 const replaceBy = `__ph-${this.index}__`;
8490 this.placeholders.push(keep);
8491 this.index++;
8492 return replaceBy;
8493 });
8494 }
8495 }
8496 const _cssContentNextSelectorRe = /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim;
8497 const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
8498 const _cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
8499 const _polyfillHost = '-shadowcsshost';
8500 // note: :host-context pre-processed to -shadowcsshostcontext.
8501 const _polyfillHostContext = '-shadowcsscontext';
8502 const _parenSuffix = '(?:\\((' +
8503 '(?:\\([^)(]*\\)|[^)(]*)+?' +
8504 ')\\))?([^,{]*)';
8505 const _cssColonHostRe = new RegExp(_polyfillHost + _parenSuffix, 'gim');
8506 const _cssColonHostContextReGlobal = new RegExp(_polyfillHostContext + _parenSuffix, 'gim');
8507 const _cssColonHostContextRe = new RegExp(_polyfillHostContext + _parenSuffix, 'im');
8508 const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
8509 const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
8510 const _shadowDOMSelectorsRe = [
8511 /::shadow/g,
8512 /::content/g,
8513 // Deprecated selectors
8514 /\/shadow-deep\//g,
8515 /\/shadow\//g,
8516 ];
8517 // The deep combinator is deprecated in the CSS spec
8518 // Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future.
8519 // see https://github.com/angular/angular/pull/17677
8520 const _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g;
8521 const _selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$';
8522 const _polyfillHostRe = /-shadowcsshost/gim;
8523 const _colonHostRe = /:host/gim;
8524 const _colonHostContextRe = /:host-context/gim;
8525 const _commentRe = /\/\*\s*[\s\S]*?\*\//g;
8526 function stripComments(input) {
8527 return input.replace(_commentRe, '');
8528 }
8529 const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g;
8530 function extractCommentsWithHash(input) {
8531 return input.match(_commentWithHashRe) || [];
8532 }
8533 const BLOCK_PLACEHOLDER = '%BLOCK%';
8534 const QUOTE_PLACEHOLDER = '%QUOTED%';
8535 const _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g;
8536 const _quotedRe = /%QUOTED%/g;
8537 const CONTENT_PAIRS = new Map([['{', '}']]);
8538 const QUOTE_PAIRS = new Map([[`"`, `"`], [`'`, `'`]]);
8539 class CssRule {
8540 constructor(selector, content) {
8541 this.selector = selector;
8542 this.content = content;
8543 }
8544 }
8545 function processRules(input, ruleCallback) {
8546 const inputWithEscapedQuotes = escapeBlocks(input, QUOTE_PAIRS, QUOTE_PLACEHOLDER);
8547 const inputWithEscapedBlocks = escapeBlocks(inputWithEscapedQuotes.escapedString, CONTENT_PAIRS, BLOCK_PLACEHOLDER);
8548 let nextBlockIndex = 0;
8549 let nextQuoteIndex = 0;
8550 return inputWithEscapedBlocks.escapedString
8551 .replace(_ruleRe, (...m) => {
8552 const selector = m[2];
8553 let content = '';
8554 let suffix = m[4];
8555 let contentPrefix = '';
8556 if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
8557 content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
8558 suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
8559 contentPrefix = '{';
8560 }
8561 const rule = ruleCallback(new CssRule(selector, content));
8562 return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
8563 })
8564 .replace(_quotedRe, () => inputWithEscapedQuotes.blocks[nextQuoteIndex++]);
8565 }
8566 class StringWithEscapedBlocks {
8567 constructor(escapedString, blocks) {
8568 this.escapedString = escapedString;
8569 this.blocks = blocks;
8570 }
8571 }
8572 function escapeBlocks(input, charPairs, placeholder) {
8573 const resultParts = [];
8574 const escapedBlocks = [];
8575 let openCharCount = 0;
8576 let nonBlockStartIndex = 0;
8577 let blockStartIndex = -1;
8578 let openChar;
8579 let closeChar;
8580 for (let i = 0; i < input.length; i++) {
8581 const char = input[i];
8582 if (char === '\\') {
8583 i++;
8584 }
8585 else if (char === closeChar) {
8586 openCharCount--;
8587 if (openCharCount === 0) {
8588 escapedBlocks.push(input.substring(blockStartIndex, i));
8589 resultParts.push(placeholder);
8590 nonBlockStartIndex = i;
8591 blockStartIndex = -1;
8592 openChar = closeChar = undefined;
8593 }
8594 }
8595 else if (char === openChar) {
8596 openCharCount++;
8597 }
8598 else if (openCharCount === 0 && charPairs.has(char)) {
8599 openChar = char;
8600 closeChar = charPairs.get(char);
8601 openCharCount = 1;
8602 blockStartIndex = i + 1;
8603 resultParts.push(input.substring(nonBlockStartIndex, blockStartIndex));
8604 }
8605 }
8606 if (blockStartIndex !== -1) {
8607 escapedBlocks.push(input.substring(blockStartIndex));
8608 resultParts.push(placeholder);
8609 }
8610 else {
8611 resultParts.push(input.substring(nonBlockStartIndex));
8612 }
8613 return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
8614 }
8615 /**
8616 * Combine the `contextSelectors` with the `hostMarker` and the `otherSelectors`
8617 * to create a selector that matches the same as `:host-context()`.
8618 *
8619 * Given a single context selector `A` we need to output selectors that match on the host and as an
8620 * ancestor of the host:
8621 *
8622 * ```
8623 * A <hostMarker>, A<hostMarker> {}
8624 * ```
8625 *
8626 * When there is more than one context selector we also have to create combinations of those
8627 * selectors with each other. For example if there are `A` and `B` selectors the output is:
8628 *
8629 * ```
8630 * AB<hostMarker>, AB <hostMarker>, A B<hostMarker>,
8631 * B A<hostMarker>, A B <hostMarker>, B A <hostMarker> {}
8632 * ```
8633 *
8634 * And so on...
8635 *
8636 * @param hostMarker the string that selects the host element.
8637 * @param contextSelectors an array of context selectors that will be combined.
8638 * @param otherSelectors the rest of the selectors that are not context selectors.
8639 */
8640 function combineHostContextSelectors(contextSelectors, otherSelectors) {
8641 const hostMarker = _polyfillHostNoCombinator;
8642 const otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors);
8643 // If there are no context selectors then just output a host marker
8644 if (contextSelectors.length === 0) {
8645 return hostMarker + otherSelectors;
8646 }
8647 const combined = [contextSelectors.pop() || ''];
8648 while (contextSelectors.length > 0) {
8649 const length = combined.length;
8650 const contextSelector = contextSelectors.pop();
8651 for (let i = 0; i < length; i++) {
8652 const previousSelectors = combined[i];
8653 // Add the new selector as a descendant of the previous selectors
8654 combined[length * 2 + i] = previousSelectors + ' ' + contextSelector;
8655 // Add the new selector as an ancestor of the previous selectors
8656 combined[length + i] = contextSelector + ' ' + previousSelectors;
8657 // Add the new selector to act on the same element as the previous selectors
8658 combined[i] = contextSelector + previousSelectors;
8659 }
8660 }
8661 // Finally connect the selector to the `hostMarker`s: either acting directly on the host
8662 // (A<hostMarker>) or as an ancestor (A <hostMarker>).
8663 return combined
8664 .map(s => otherSelectorsHasHost ?
8665 `${s}${otherSelectors}` :
8666 `${s}${hostMarker}${otherSelectors}, ${s} ${hostMarker}${otherSelectors}`)
8667 .join(',');
8668 }
8669 /**
8670 * Mutate the given `groups` array so that there are `multiples` clones of the original array
8671 * stored.
8672 *
8673 * For example `repeatGroups([a, b], 3)` will result in `[a, b, a, b, a, b]` - but importantly the
8674 * newly added groups will be clones of the original.
8675 *
8676 * @param groups An array of groups of strings that will be repeated. This array is mutated
8677 * in-place.
8678 * @param multiples The number of times the current groups should appear.
8679 */
8680 function repeatGroups(groups, multiples) {
8681 const length = groups.length;
8682 for (let i = 1; i < multiples; i++) {
8683 for (let j = 0; j < length; j++) {
8684 groups[j + (i * length)] = groups[j].slice(0);
8685 }
8686 }
8687 }
8688
8689 /**
8690 * @license
8691 * Copyright Google LLC All Rights Reserved.
8692 *
8693 * Use of this source code is governed by an MIT-style license that can be
8694 * found in the LICENSE file at https://angular.io/license
8695 */
8696 const COMPONENT_VARIABLE = '%COMP%';
8697 const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
8698 const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
8699
8700 /**
8701 * @license
8702 * Copyright Google LLC All Rights Reserved.
8703 *
8704 * Use of this source code is governed by an MIT-style license that can be
8705 * found in the LICENSE file at https://angular.io/license
8706 */
8707 /**
8708 * A path is an ordered set of elements. Typically a path is to a
8709 * particular offset in a source file. The head of the list is the top
8710 * most node. The tail is the node that contains the offset directly.
8711 *
8712 * For example, the expression `a + b + c` might have an ast that looks
8713 * like:
8714 * +
8715 * / \
8716 * a +
8717 * / \
8718 * b c
8719 *
8720 * The path to the node at offset 9 would be `['+' at 1-10, '+' at 7-10,
8721 * 'c' at 9-10]` and the path the node at offset 1 would be
8722 * `['+' at 1-10, 'a' at 1-2]`.
8723 */
8724 class AstPath {
8725 constructor(path, position = -1) {
8726 this.path = path;
8727 this.position = position;
8728 }
8729 get empty() {
8730 return !this.path || !this.path.length;
8731 }
8732 get head() {
8733 return this.path[0];
8734 }
8735 get tail() {
8736 return this.path[this.path.length - 1];
8737 }
8738 parentOf(node) {
8739 return node && this.path[this.path.indexOf(node) - 1];
8740 }
8741 childOf(node) {
8742 return this.path[this.path.indexOf(node) + 1];
8743 }
8744 first(ctor) {
8745 for (let i = this.path.length - 1; i >= 0; i--) {
8746 let item = this.path[i];
8747 if (item instanceof ctor)
8748 return item;
8749 }
8750 }
8751 push(node) {
8752 this.path.push(node);
8753 }
8754 pop() {
8755 return this.path.pop();
8756 }
8757 }
8758
8759 /**
8760 * @license
8761 * Copyright Google LLC All Rights Reserved.
8762 *
8763 * Use of this source code is governed by an MIT-style license that can be
8764 * found in the LICENSE file at https://angular.io/license
8765 */
8766 class NodeWithI18n {
8767 constructor(sourceSpan, i18n) {
8768 this.sourceSpan = sourceSpan;
8769 this.i18n = i18n;
8770 }
8771 }
8772 class Text$2 extends NodeWithI18n {
8773 constructor(value, sourceSpan, i18n) {
8774 super(sourceSpan, i18n);
8775 this.value = value;
8776 }
8777 visit(visitor, context) {
8778 return visitor.visitText(this, context);
8779 }
8780 }
8781 class Expansion extends NodeWithI18n {
8782 constructor(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) {
8783 super(sourceSpan, i18n);
8784 this.switchValue = switchValue;
8785 this.type = type;
8786 this.cases = cases;
8787 this.switchValueSourceSpan = switchValueSourceSpan;
8788 }
8789 visit(visitor, context) {
8790 return visitor.visitExpansion(this, context);
8791 }
8792 }
8793 class ExpansionCase {
8794 constructor(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) {
8795 this.value = value;
8796 this.expression = expression;
8797 this.sourceSpan = sourceSpan;
8798 this.valueSourceSpan = valueSourceSpan;
8799 this.expSourceSpan = expSourceSpan;
8800 }
8801 visit(visitor, context) {
8802 return visitor.visitExpansionCase(this, context);
8803 }
8804 }
8805 class Attribute extends NodeWithI18n {
8806 constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) {
8807 super(sourceSpan, i18n);
8808 this.name = name;
8809 this.value = value;
8810 this.keySpan = keySpan;
8811 this.valueSpan = valueSpan;
8812 }
8813 visit(visitor, context) {
8814 return visitor.visitAttribute(this, context);
8815 }
8816 }
8817 class Element$1 extends NodeWithI18n {
8818 constructor(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
8819 super(sourceSpan, i18n);
8820 this.name = name;
8821 this.attrs = attrs;
8822 this.children = children;
8823 this.startSourceSpan = startSourceSpan;
8824 this.endSourceSpan = endSourceSpan;
8825 }
8826 visit(visitor, context) {
8827 return visitor.visitElement(this, context);
8828 }
8829 }
8830 class Comment {
8831 constructor(value, sourceSpan) {
8832 this.value = value;
8833 this.sourceSpan = sourceSpan;
8834 }
8835 visit(visitor, context) {
8836 return visitor.visitComment(this, context);
8837 }
8838 }
8839 function visitAll$1(visitor, nodes, context = null) {
8840 const result = [];
8841 const visit = visitor.visit ?
8842 (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) :
8843 (ast) => ast.visit(visitor, context);
8844 nodes.forEach(ast => {
8845 const astResult = visit(ast);
8846 if (astResult) {
8847 result.push(astResult);
8848 }
8849 });
8850 return result;
8851 }
8852 class RecursiveVisitor {
8853 constructor() { }
8854 visitElement(ast, context) {
8855 this.visitChildren(context, visit => {
8856 visit(ast.attrs);
8857 visit(ast.children);
8858 });
8859 }
8860 visitAttribute(ast, context) { }
8861 visitText(ast, context) { }
8862 visitComment(ast, context) { }
8863 visitExpansion(ast, context) {
8864 return this.visitChildren(context, visit => {
8865 visit(ast.cases);
8866 });
8867 }
8868 visitExpansionCase(ast, context) { }
8869 visitChildren(context, cb) {
8870 let results = [];
8871 let t = this;
8872 function visit(children) {
8873 if (children)
8874 results.push(visitAll$1(t, children, context));
8875 }
8876 cb(visit);
8877 return Array.prototype.concat.apply([], results);
8878 }
8879 }
8880
8881 /**
8882 * @license
8883 * Copyright Google LLC All Rights Reserved.
8884 *
8885 * Use of this source code is governed by an MIT-style license that can be
8886 * found in the LICENSE file at https://angular.io/license
8887 */
8888 var TokenType;
8889 (function (TokenType) {
8890 TokenType[TokenType["TAG_OPEN_START"] = 0] = "TAG_OPEN_START";
8891 TokenType[TokenType["TAG_OPEN_END"] = 1] = "TAG_OPEN_END";
8892 TokenType[TokenType["TAG_OPEN_END_VOID"] = 2] = "TAG_OPEN_END_VOID";
8893 TokenType[TokenType["TAG_CLOSE"] = 3] = "TAG_CLOSE";
8894 TokenType[TokenType["INCOMPLETE_TAG_OPEN"] = 4] = "INCOMPLETE_TAG_OPEN";
8895 TokenType[TokenType["TEXT"] = 5] = "TEXT";
8896 TokenType[TokenType["ESCAPABLE_RAW_TEXT"] = 6] = "ESCAPABLE_RAW_TEXT";
8897 TokenType[TokenType["RAW_TEXT"] = 7] = "RAW_TEXT";
8898 TokenType[TokenType["COMMENT_START"] = 8] = "COMMENT_START";
8899 TokenType[TokenType["COMMENT_END"] = 9] = "COMMENT_END";
8900 TokenType[TokenType["CDATA_START"] = 10] = "CDATA_START";
8901 TokenType[TokenType["CDATA_END"] = 11] = "CDATA_END";
8902 TokenType[TokenType["ATTR_NAME"] = 12] = "ATTR_NAME";
8903 TokenType[TokenType["ATTR_QUOTE"] = 13] = "ATTR_QUOTE";
8904 TokenType[TokenType["ATTR_VALUE"] = 14] = "ATTR_VALUE";
8905 TokenType[TokenType["DOC_TYPE"] = 15] = "DOC_TYPE";
8906 TokenType[TokenType["EXPANSION_FORM_START"] = 16] = "EXPANSION_FORM_START";
8907 TokenType[TokenType["EXPANSION_CASE_VALUE"] = 17] = "EXPANSION_CASE_VALUE";
8908 TokenType[TokenType["EXPANSION_CASE_EXP_START"] = 18] = "EXPANSION_CASE_EXP_START";
8909 TokenType[TokenType["EXPANSION_CASE_EXP_END"] = 19] = "EXPANSION_CASE_EXP_END";
8910 TokenType[TokenType["EXPANSION_FORM_END"] = 20] = "EXPANSION_FORM_END";
8911 TokenType[TokenType["EOF"] = 21] = "EOF";
8912 })(TokenType || (TokenType = {}));
8913 class Token {
8914 constructor(type, parts, sourceSpan) {
8915 this.type = type;
8916 this.parts = parts;
8917 this.sourceSpan = sourceSpan;
8918 }
8919 }
8920 class TokenError extends ParseError {
8921 constructor(errorMsg, tokenType, span) {
8922 super(span, errorMsg);
8923 this.tokenType = tokenType;
8924 }
8925 }
8926 class TokenizeResult {
8927 constructor(tokens, errors, nonNormalizedIcuExpressions) {
8928 this.tokens = tokens;
8929 this.errors = errors;
8930 this.nonNormalizedIcuExpressions = nonNormalizedIcuExpressions;
8931 }
8932 }
8933 function tokenize(source, url, getTagDefinition, options = {}) {
8934 const tokenizer = new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options);
8935 tokenizer.tokenize();
8936 return new TokenizeResult(mergeTextTokens(tokenizer.tokens), tokenizer.errors, tokenizer.nonNormalizedIcuExpressions);
8937 }
8938 const _CR_OR_CRLF_REGEXP = /\r\n?/g;
8939 function _unexpectedCharacterErrorMsg(charCode) {
8940 const char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode);
8941 return `Unexpected character "${char}"`;
8942 }
8943 function _unknownEntityErrorMsg(entitySrc) {
8944 return `Unknown entity "${entitySrc}" - use the "&#<decimal>;" or "&#x<hex>;" syntax`;
8945 }
8946 function _unparsableEntityErrorMsg(type, entityStr) {
8947 return `Unable to parse entity "${entityStr}" - ${type} character reference entities must end with ";"`;
8948 }
8949 var CharacterReferenceType;
8950 (function (CharacterReferenceType) {
8951 CharacterReferenceType["HEX"] = "hexadecimal";
8952 CharacterReferenceType["DEC"] = "decimal";
8953 })(CharacterReferenceType || (CharacterReferenceType = {}));
8954 class _ControlFlowError {
8955 constructor(error) {
8956 this.error = error;
8957 }
8958 }
8959 // See https://www.w3.org/TR/html51/syntax.html#writing-html-documents
8960 class _Tokenizer {
8961 /**
8962 * @param _file The html source file being tokenized.
8963 * @param _getTagDefinition A function that will retrieve a tag definition for a given tag name.
8964 * @param options Configuration of the tokenization.
8965 */
8966 constructor(_file, _getTagDefinition, options) {
8967 this._getTagDefinition = _getTagDefinition;
8968 this._currentTokenStart = null;
8969 this._currentTokenType = null;
8970 this._expansionCaseStack = [];
8971 this._inInterpolation = false;
8972 this.tokens = [];
8973 this.errors = [];
8974 this.nonNormalizedIcuExpressions = [];
8975 this._tokenizeIcu = options.tokenizeExpansionForms || false;
8976 this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
8977 this._leadingTriviaCodePoints =
8978 options.leadingTriviaChars && options.leadingTriviaChars.map(c => c.codePointAt(0) || 0);
8979 const range = options.range || { endPos: _file.content.length, startPos: 0, startLine: 0, startCol: 0 };
8980 this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) :
8981 new PlainCharacterCursor(_file, range);
8982 this._preserveLineEndings = options.preserveLineEndings || false;
8983 this._escapedString = options.escapedString || false;
8984 this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
8985 try {
8986 this._cursor.init();
8987 }
8988 catch (e) {
8989 this.handleError(e);
8990 }
8991 }
8992 _processCarriageReturns(content) {
8993 if (this._preserveLineEndings) {
8994 return content;
8995 }
8996 // https://www.w3.org/TR/html51/syntax.html#preprocessing-the-input-stream
8997 // In order to keep the original position in the source, we can not
8998 // pre-process it.
8999 // Instead CRs are processed right before instantiating the tokens.
9000 return content.replace(_CR_OR_CRLF_REGEXP, '\n');
9001 }
9002 tokenize() {
9003 while (this._cursor.peek() !== $EOF) {
9004 const start = this._cursor.clone();
9005 try {
9006 if (this._attemptCharCode($LT)) {
9007 if (this._attemptCharCode($BANG)) {
9008 if (this._attemptCharCode($LBRACKET)) {
9009 this._consumeCdata(start);
9010 }
9011 else if (this._attemptCharCode($MINUS)) {
9012 this._consumeComment(start);
9013 }
9014 else {
9015 this._consumeDocType(start);
9016 }
9017 }
9018 else if (this._attemptCharCode($SLASH)) {
9019 this._consumeTagClose(start);
9020 }
9021 else {
9022 this._consumeTagOpen(start);
9023 }
9024 }
9025 else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
9026 this._consumeText();
9027 }
9028 }
9029 catch (e) {
9030 this.handleError(e);
9031 }
9032 }
9033 this._beginToken(TokenType.EOF);
9034 this._endToken([]);
9035 }
9036 /**
9037 * @returns whether an ICU token has been created
9038 * @internal
9039 */
9040 _tokenizeExpansionForm() {
9041 if (this.isExpansionFormStart()) {
9042 this._consumeExpansionFormStart();
9043 return true;
9044 }
9045 if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) {
9046 this._consumeExpansionCaseStart();
9047 return true;
9048 }
9049 if (this._cursor.peek() === $RBRACE) {
9050 if (this._isInExpansionCase()) {
9051 this._consumeExpansionCaseEnd();
9052 return true;
9053 }
9054 if (this._isInExpansionForm()) {
9055 this._consumeExpansionFormEnd();
9056 return true;
9057 }
9058 }
9059 return false;
9060 }
9061 _beginToken(type, start = this._cursor.clone()) {
9062 this._currentTokenStart = start;
9063 this._currentTokenType = type;
9064 }
9065 _endToken(parts, end) {
9066 if (this._currentTokenStart === null) {
9067 throw new TokenError('Programming error - attempted to end a token when there was no start to the token', this._currentTokenType, this._cursor.getSpan(end));
9068 }
9069 if (this._currentTokenType === null) {
9070 throw new TokenError('Programming error - attempted to end a token which has no token type', null, this._cursor.getSpan(this._currentTokenStart));
9071 }
9072 const token = new Token(this._currentTokenType, parts, this._cursor.getSpan(this._currentTokenStart, this._leadingTriviaCodePoints));
9073 this.tokens.push(token);
9074 this._currentTokenStart = null;
9075 this._currentTokenType = null;
9076 return token;
9077 }
9078 _createError(msg, span) {
9079 if (this._isInExpansionForm()) {
9080 msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`;
9081 }
9082 const error = new TokenError(msg, this._currentTokenType, span);
9083 this._currentTokenStart = null;
9084 this._currentTokenType = null;
9085 return new _ControlFlowError(error);
9086 }
9087 handleError(e) {
9088 if (e instanceof CursorError) {
9089 e = this._createError(e.msg, this._cursor.getSpan(e.cursor));
9090 }
9091 if (e instanceof _ControlFlowError) {
9092 this.errors.push(e.error);
9093 }
9094 else {
9095 throw e;
9096 }
9097 }
9098 _attemptCharCode(charCode) {
9099 if (this._cursor.peek() === charCode) {
9100 this._cursor.advance();
9101 return true;
9102 }
9103 return false;
9104 }
9105 _attemptCharCodeCaseInsensitive(charCode) {
9106 if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCode)) {
9107 this._cursor.advance();
9108 return true;
9109 }
9110 return false;
9111 }
9112 _requireCharCode(charCode) {
9113 const location = this._cursor.clone();
9114 if (!this._attemptCharCode(charCode)) {
9115 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
9116 }
9117 }
9118 _attemptStr(chars) {
9119 const len = chars.length;
9120 if (this._cursor.charsLeft() < len) {
9121 return false;
9122 }
9123 const initialPosition = this._cursor.clone();
9124 for (let i = 0; i < len; i++) {
9125 if (!this._attemptCharCode(chars.charCodeAt(i))) {
9126 // If attempting to parse the string fails, we want to reset the parser
9127 // to where it was before the attempt
9128 this._cursor = initialPosition;
9129 return false;
9130 }
9131 }
9132 return true;
9133 }
9134 _attemptStrCaseInsensitive(chars) {
9135 for (let i = 0; i < chars.length; i++) {
9136 if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) {
9137 return false;
9138 }
9139 }
9140 return true;
9141 }
9142 _requireStr(chars) {
9143 const location = this._cursor.clone();
9144 if (!this._attemptStr(chars)) {
9145 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
9146 }
9147 }
9148 _attemptCharCodeUntilFn(predicate) {
9149 while (!predicate(this._cursor.peek())) {
9150 this._cursor.advance();
9151 }
9152 }
9153 _requireCharCodeUntilFn(predicate, len) {
9154 const start = this._cursor.clone();
9155 this._attemptCharCodeUntilFn(predicate);
9156 if (this._cursor.diff(start) < len) {
9157 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
9158 }
9159 }
9160 _attemptUntilChar(char) {
9161 while (this._cursor.peek() !== char) {
9162 this._cursor.advance();
9163 }
9164 }
9165 _readChar(decodeEntities) {
9166 if (decodeEntities && this._cursor.peek() === $AMPERSAND) {
9167 return this._decodeEntity();
9168 }
9169 else {
9170 // Don't rely upon reading directly from `_input` as the actual char value
9171 // may have been generated from an escape sequence.
9172 const char = String.fromCodePoint(this._cursor.peek());
9173 this._cursor.advance();
9174 return char;
9175 }
9176 }
9177 _decodeEntity() {
9178 const start = this._cursor.clone();
9179 this._cursor.advance();
9180 if (this._attemptCharCode($HASH)) {
9181 const isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
9182 const codeStart = this._cursor.clone();
9183 this._attemptCharCodeUntilFn(isDigitEntityEnd);
9184 if (this._cursor.peek() != $SEMICOLON) {
9185 // Advance cursor to include the peeked character in the string provided to the error
9186 // message.
9187 this._cursor.advance();
9188 const entityType = isHex ? CharacterReferenceType.HEX : CharacterReferenceType.DEC;
9189 throw this._createError(_unparsableEntityErrorMsg(entityType, this._cursor.getChars(start)), this._cursor.getSpan());
9190 }
9191 const strNum = this._cursor.getChars(codeStart);
9192 this._cursor.advance();
9193 try {
9194 const charCode = parseInt(strNum, isHex ? 16 : 10);
9195 return String.fromCharCode(charCode);
9196 }
9197 catch (_a) {
9198 throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan());
9199 }
9200 }
9201 else {
9202 const nameStart = this._cursor.clone();
9203 this._attemptCharCodeUntilFn(isNamedEntityEnd);
9204 if (this._cursor.peek() != $SEMICOLON) {
9205 this._cursor = nameStart;
9206 return '&';
9207 }
9208 const name = this._cursor.getChars(nameStart);
9209 this._cursor.advance();
9210 const char = NAMED_ENTITIES[name];
9211 if (!char) {
9212 throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
9213 }
9214 return char;
9215 }
9216 }
9217 _consumeRawText(decodeEntities, endMarkerPredicate) {
9218 this._beginToken(decodeEntities ? TokenType.ESCAPABLE_RAW_TEXT : TokenType.RAW_TEXT);
9219 const parts = [];
9220 while (true) {
9221 const tagCloseStart = this._cursor.clone();
9222 const foundEndMarker = endMarkerPredicate();
9223 this._cursor = tagCloseStart;
9224 if (foundEndMarker) {
9225 break;
9226 }
9227 parts.push(this._readChar(decodeEntities));
9228 }
9229 return this._endToken([this._processCarriageReturns(parts.join(''))]);
9230 }
9231 _consumeComment(start) {
9232 this._beginToken(TokenType.COMMENT_START, start);
9233 this._requireCharCode($MINUS);
9234 this._endToken([]);
9235 this._consumeRawText(false, () => this._attemptStr('-->'));
9236 this._beginToken(TokenType.COMMENT_END);
9237 this._requireStr('-->');
9238 this._endToken([]);
9239 }
9240 _consumeCdata(start) {
9241 this._beginToken(TokenType.CDATA_START, start);
9242 this._requireStr('CDATA[');
9243 this._endToken([]);
9244 this._consumeRawText(false, () => this._attemptStr(']]>'));
9245 this._beginToken(TokenType.CDATA_END);
9246 this._requireStr(']]>');
9247 this._endToken([]);
9248 }
9249 _consumeDocType(start) {
9250 this._beginToken(TokenType.DOC_TYPE, start);
9251 const contentStart = this._cursor.clone();
9252 this._attemptUntilChar($GT);
9253 const content = this._cursor.getChars(contentStart);
9254 this._cursor.advance();
9255 this._endToken([content]);
9256 }
9257 _consumePrefixAndName() {
9258 const nameOrPrefixStart = this._cursor.clone();
9259 let prefix = '';
9260 while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) {
9261 this._cursor.advance();
9262 }
9263 let nameStart;
9264 if (this._cursor.peek() === $COLON) {
9265 prefix = this._cursor.getChars(nameOrPrefixStart);
9266 this._cursor.advance();
9267 nameStart = this._cursor.clone();
9268 }
9269 else {
9270 nameStart = nameOrPrefixStart;
9271 }
9272 this._requireCharCodeUntilFn(isNameEnd, prefix === '' ? 0 : 1);
9273 const name = this._cursor.getChars(nameStart);
9274 return [prefix, name];
9275 }
9276 _consumeTagOpen(start) {
9277 let tagName;
9278 let prefix;
9279 let openTagToken;
9280 try {
9281 if (!isAsciiLetter(this._cursor.peek())) {
9282 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
9283 }
9284 openTagToken = this._consumeTagOpenStart(start);
9285 prefix = openTagToken.parts[0];
9286 tagName = openTagToken.parts[1];
9287 this._attemptCharCodeUntilFn(isNotWhitespace);
9288 while (this._cursor.peek() !== $SLASH && this._cursor.peek() !== $GT &&
9289 this._cursor.peek() !== $LT && this._cursor.peek() !== $EOF) {
9290 this._consumeAttributeName();
9291 this._attemptCharCodeUntilFn(isNotWhitespace);
9292 if (this._attemptCharCode($EQ)) {
9293 this._attemptCharCodeUntilFn(isNotWhitespace);
9294 this._consumeAttributeValue();
9295 }
9296 this._attemptCharCodeUntilFn(isNotWhitespace);
9297 }
9298 this._consumeTagOpenEnd();
9299 }
9300 catch (e) {
9301 if (e instanceof _ControlFlowError) {
9302 if (openTagToken) {
9303 // We errored before we could close the opening tag, so it is incomplete.
9304 openTagToken.type = TokenType.INCOMPLETE_TAG_OPEN;
9305 }
9306 else {
9307 // When the start tag is invalid, assume we want a "<" as text.
9308 // Back to back text tokens are merged at the end.
9309 this._beginToken(TokenType.TEXT, start);
9310 this._endToken(['<']);
9311 }
9312 return;
9313 }
9314 throw e;
9315 }
9316 const contentTokenType = this._getTagDefinition(tagName).getContentType(prefix);
9317 if (contentTokenType === TagContentType.RAW_TEXT) {
9318 this._consumeRawTextWithTagClose(prefix, tagName, false);
9319 }
9320 else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) {
9321 this._consumeRawTextWithTagClose(prefix, tagName, true);
9322 }
9323 }
9324 _consumeRawTextWithTagClose(prefix, tagName, decodeEntities) {
9325 this._consumeRawText(decodeEntities, () => {
9326 if (!this._attemptCharCode($LT))
9327 return false;
9328 if (!this._attemptCharCode($SLASH))
9329 return false;
9330 this._attemptCharCodeUntilFn(isNotWhitespace);
9331 if (!this._attemptStrCaseInsensitive(tagName))
9332 return false;
9333 this._attemptCharCodeUntilFn(isNotWhitespace);
9334 return this._attemptCharCode($GT);
9335 });
9336 this._beginToken(TokenType.TAG_CLOSE);
9337 this._requireCharCodeUntilFn(code => code === $GT, 3);
9338 this._cursor.advance(); // Consume the `>`
9339 this._endToken([prefix, tagName]);
9340 }
9341 _consumeTagOpenStart(start) {
9342 this._beginToken(TokenType.TAG_OPEN_START, start);
9343 const parts = this._consumePrefixAndName();
9344 return this._endToken(parts);
9345 }
9346 _consumeAttributeName() {
9347 const attrNameStart = this._cursor.peek();
9348 if (attrNameStart === $SQ || attrNameStart === $DQ) {
9349 throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
9350 }
9351 this._beginToken(TokenType.ATTR_NAME);
9352 const prefixAndName = this._consumePrefixAndName();
9353 this._endToken(prefixAndName);
9354 }
9355 _consumeAttributeValue() {
9356 let value;
9357 if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
9358 this._beginToken(TokenType.ATTR_QUOTE);
9359 const quoteChar = this._cursor.peek();
9360 this._cursor.advance();
9361 this._endToken([String.fromCodePoint(quoteChar)]);
9362 this._beginToken(TokenType.ATTR_VALUE);
9363 const parts = [];
9364 while (this._cursor.peek() !== quoteChar) {
9365 parts.push(this._readChar(true));
9366 }
9367 value = parts.join('');
9368 this._endToken([this._processCarriageReturns(value)]);
9369 this._beginToken(TokenType.ATTR_QUOTE);
9370 this._cursor.advance();
9371 this._endToken([String.fromCodePoint(quoteChar)]);
9372 }
9373 else {
9374 this._beginToken(TokenType.ATTR_VALUE);
9375 const valueStart = this._cursor.clone();
9376 this._requireCharCodeUntilFn(isNameEnd, 1);
9377 value = this._cursor.getChars(valueStart);
9378 this._endToken([this._processCarriageReturns(value)]);
9379 }
9380 }
9381 _consumeTagOpenEnd() {
9382 const tokenType = this._attemptCharCode($SLASH) ? TokenType.TAG_OPEN_END_VOID : TokenType.TAG_OPEN_END;
9383 this._beginToken(tokenType);
9384 this._requireCharCode($GT);
9385 this._endToken([]);
9386 }
9387 _consumeTagClose(start) {
9388 this._beginToken(TokenType.TAG_CLOSE, start);
9389 this._attemptCharCodeUntilFn(isNotWhitespace);
9390 const prefixAndName = this._consumePrefixAndName();
9391 this._attemptCharCodeUntilFn(isNotWhitespace);
9392 this._requireCharCode($GT);
9393 this._endToken(prefixAndName);
9394 }
9395 _consumeExpansionFormStart() {
9396 this._beginToken(TokenType.EXPANSION_FORM_START);
9397 this._requireCharCode($LBRACE);
9398 this._endToken([]);
9399 this._expansionCaseStack.push(TokenType.EXPANSION_FORM_START);
9400 this._beginToken(TokenType.RAW_TEXT);
9401 const condition = this._readUntil($COMMA);
9402 const normalizedCondition = this._processCarriageReturns(condition);
9403 if (this._i18nNormalizeLineEndingsInICUs) {
9404 // We explicitly want to normalize line endings for this text.
9405 this._endToken([normalizedCondition]);
9406 }
9407 else {
9408 // We are not normalizing line endings.
9409 const conditionToken = this._endToken([condition]);
9410 if (normalizedCondition !== condition) {
9411 this.nonNormalizedIcuExpressions.push(conditionToken);
9412 }
9413 }
9414 this._requireCharCode($COMMA);
9415 this._attemptCharCodeUntilFn(isNotWhitespace);
9416 this._beginToken(TokenType.RAW_TEXT);
9417 const type = this._readUntil($COMMA);
9418 this._endToken([type]);
9419 this._requireCharCode($COMMA);
9420 this._attemptCharCodeUntilFn(isNotWhitespace);
9421 }
9422 _consumeExpansionCaseStart() {
9423 this._beginToken(TokenType.EXPANSION_CASE_VALUE);
9424 const value = this._readUntil($LBRACE).trim();
9425 this._endToken([value]);
9426 this._attemptCharCodeUntilFn(isNotWhitespace);
9427 this._beginToken(TokenType.EXPANSION_CASE_EXP_START);
9428 this._requireCharCode($LBRACE);
9429 this._endToken([]);
9430 this._attemptCharCodeUntilFn(isNotWhitespace);
9431 this._expansionCaseStack.push(TokenType.EXPANSION_CASE_EXP_START);
9432 }
9433 _consumeExpansionCaseEnd() {
9434 this._beginToken(TokenType.EXPANSION_CASE_EXP_END);
9435 this._requireCharCode($RBRACE);
9436 this._endToken([]);
9437 this._attemptCharCodeUntilFn(isNotWhitespace);
9438 this._expansionCaseStack.pop();
9439 }
9440 _consumeExpansionFormEnd() {
9441 this._beginToken(TokenType.EXPANSION_FORM_END);
9442 this._requireCharCode($RBRACE);
9443 this._endToken([]);
9444 this._expansionCaseStack.pop();
9445 }
9446 _consumeText() {
9447 const start = this._cursor.clone();
9448 this._beginToken(TokenType.TEXT, start);
9449 const parts = [];
9450 do {
9451 if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) {
9452 parts.push(this._interpolationConfig.start);
9453 this._inInterpolation = true;
9454 }
9455 else if (this._interpolationConfig && this._inInterpolation &&
9456 this._attemptStr(this._interpolationConfig.end)) {
9457 parts.push(this._interpolationConfig.end);
9458 this._inInterpolation = false;
9459 }
9460 else {
9461 parts.push(this._readChar(true));
9462 }
9463 } while (!this._isTextEnd());
9464 this._endToken([this._processCarriageReturns(parts.join(''))]);
9465 }
9466 _isTextEnd() {
9467 if (this._cursor.peek() === $LT || this._cursor.peek() === $EOF) {
9468 return true;
9469 }
9470 if (this._tokenizeIcu && !this._inInterpolation) {
9471 if (this.isExpansionFormStart()) {
9472 // start of an expansion form
9473 return true;
9474 }
9475 if (this._cursor.peek() === $RBRACE && this._isInExpansionCase()) {
9476 // end of and expansion case
9477 return true;
9478 }
9479 }
9480 return false;
9481 }
9482 _readUntil(char) {
9483 const start = this._cursor.clone();
9484 this._attemptUntilChar(char);
9485 return this._cursor.getChars(start);
9486 }
9487 _isInExpansionCase() {
9488 return this._expansionCaseStack.length > 0 &&
9489 this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
9490 TokenType.EXPANSION_CASE_EXP_START;
9491 }
9492 _isInExpansionForm() {
9493 return this._expansionCaseStack.length > 0 &&
9494 this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
9495 TokenType.EXPANSION_FORM_START;
9496 }
9497 isExpansionFormStart() {
9498 if (this._cursor.peek() !== $LBRACE) {
9499 return false;
9500 }
9501 if (this._interpolationConfig) {
9502 const start = this._cursor.clone();
9503 const isInterpolation = this._attemptStr(this._interpolationConfig.start);
9504 this._cursor = start;
9505 return !isInterpolation;
9506 }
9507 return true;
9508 }
9509 }
9510 function isNotWhitespace(code) {
9511 return !isWhitespace(code) || code === $EOF;
9512 }
9513 function isNameEnd(code) {
9514 return isWhitespace(code) || code === $GT || code === $LT ||
9515 code === $SLASH || code === $SQ || code === $DQ || code === $EQ ||
9516 code === $EOF;
9517 }
9518 function isPrefixEnd(code) {
9519 return (code < $a || $z < code) && (code < $A || $Z < code) &&
9520 (code < $0 || code > $9);
9521 }
9522 function isDigitEntityEnd(code) {
9523 return code == $SEMICOLON || code == $EOF || !isAsciiHexDigit(code);
9524 }
9525 function isNamedEntityEnd(code) {
9526 return code == $SEMICOLON || code == $EOF || !isAsciiLetter(code);
9527 }
9528 function isExpansionCaseStart(peek) {
9529 return peek !== $RBRACE;
9530 }
9531 function compareCharCodeCaseInsensitive(code1, code2) {
9532 return toUpperCaseCharCode(code1) == toUpperCaseCharCode(code2);
9533 }
9534 function toUpperCaseCharCode(code) {
9535 return code >= $a && code <= $z ? code - $a + $A : code;
9536 }
9537 function mergeTextTokens(srcTokens) {
9538 const dstTokens = [];
9539 let lastDstToken = undefined;
9540 for (let i = 0; i < srcTokens.length; i++) {
9541 const token = srcTokens[i];
9542 if (lastDstToken && lastDstToken.type == TokenType.TEXT && token.type == TokenType.TEXT) {
9543 lastDstToken.parts[0] += token.parts[0];
9544 lastDstToken.sourceSpan.end = token.sourceSpan.end;
9545 }
9546 else {
9547 lastDstToken = token;
9548 dstTokens.push(lastDstToken);
9549 }
9550 }
9551 return dstTokens;
9552 }
9553 class PlainCharacterCursor {
9554 constructor(fileOrCursor, range) {
9555 if (fileOrCursor instanceof PlainCharacterCursor) {
9556 this.file = fileOrCursor.file;
9557 this.input = fileOrCursor.input;
9558 this.end = fileOrCursor.end;
9559 const state = fileOrCursor.state;
9560 // Note: avoid using `{...fileOrCursor.state}` here as that has a severe performance penalty.
9561 // In ES5 bundles the object spread operator is translated into the `__assign` helper, which
9562 // is not optimized by VMs as efficiently as a raw object literal. Since this constructor is
9563 // called in tight loops, this difference matters.
9564 this.state = {
9565 peek: state.peek,
9566 offset: state.offset,
9567 line: state.line,
9568 column: state.column,
9569 };
9570 }
9571 else {
9572 if (!range) {
9573 throw new Error('Programming error: the range argument must be provided with a file argument.');
9574 }
9575 this.file = fileOrCursor;
9576 this.input = fileOrCursor.content;
9577 this.end = range.endPos;
9578 this.state = {
9579 peek: -1,
9580 offset: range.startPos,
9581 line: range.startLine,
9582 column: range.startCol,
9583 };
9584 }
9585 }
9586 clone() {
9587 return new PlainCharacterCursor(this);
9588 }
9589 peek() {
9590 return this.state.peek;
9591 }
9592 charsLeft() {
9593 return this.end - this.state.offset;
9594 }
9595 diff(other) {
9596 return this.state.offset - other.state.offset;
9597 }
9598 advance() {
9599 this.advanceState(this.state);
9600 }
9601 init() {
9602 this.updatePeek(this.state);
9603 }
9604 getSpan(start, leadingTriviaCodePoints) {
9605 start = start || this;
9606 let fullStart = start;
9607 if (leadingTriviaCodePoints) {
9608 while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) {
9609 if (fullStart === start) {
9610 start = start.clone();
9611 }
9612 start.advance();
9613 }
9614 }
9615 const startLocation = this.locationFromCursor(start);
9616 const endLocation = this.locationFromCursor(this);
9617 const fullStartLocation = fullStart !== start ? this.locationFromCursor(fullStart) : startLocation;
9618 return new ParseSourceSpan(startLocation, endLocation, fullStartLocation);
9619 }
9620 getChars(start) {
9621 return this.input.substring(start.state.offset, this.state.offset);
9622 }
9623 charAt(pos) {
9624 return this.input.charCodeAt(pos);
9625 }
9626 advanceState(state) {
9627 if (state.offset >= this.end) {
9628 this.state = state;
9629 throw new CursorError('Unexpected character "EOF"', this);
9630 }
9631 const currentChar = this.charAt(state.offset);
9632 if (currentChar === $LF) {
9633 state.line++;
9634 state.column = 0;
9635 }
9636 else if (!isNewLine(currentChar)) {
9637 state.column++;
9638 }
9639 state.offset++;
9640 this.updatePeek(state);
9641 }
9642 updatePeek(state) {
9643 state.peek = state.offset >= this.end ? $EOF : this.charAt(state.offset);
9644 }
9645 locationFromCursor(cursor) {
9646 return new ParseLocation(cursor.file, cursor.state.offset, cursor.state.line, cursor.state.column);
9647 }
9648 }
9649 class EscapedCharacterCursor extends PlainCharacterCursor {
9650 constructor(fileOrCursor, range) {
9651 if (fileOrCursor instanceof EscapedCharacterCursor) {
9652 super(fileOrCursor);
9653 this.internalState = Object.assign({}, fileOrCursor.internalState);
9654 }
9655 else {
9656 super(fileOrCursor, range);
9657 this.internalState = this.state;
9658 }
9659 }
9660 advance() {
9661 this.state = this.internalState;
9662 super.advance();
9663 this.processEscapeSequence();
9664 }
9665 init() {
9666 super.init();
9667 this.processEscapeSequence();
9668 }
9669 clone() {
9670 return new EscapedCharacterCursor(this);
9671 }
9672 getChars(start) {
9673 const cursor = start.clone();
9674 let chars = '';
9675 while (cursor.internalState.offset < this.internalState.offset) {
9676 chars += String.fromCodePoint(cursor.peek());
9677 cursor.advance();
9678 }
9679 return chars;
9680 }
9681 /**
9682 * Process the escape sequence that starts at the current position in the text.
9683 *
9684 * This method is called to ensure that `peek` has the unescaped value of escape sequences.
9685 */
9686 processEscapeSequence() {
9687 const peek = () => this.internalState.peek;
9688 if (peek() === $BACKSLASH) {
9689 // We have hit an escape sequence so we need the internal state to become independent
9690 // of the external state.
9691 this.internalState = Object.assign({}, this.state);
9692 // Move past the backslash
9693 this.advanceState(this.internalState);
9694 // First check for standard control char sequences
9695 if (peek() === $n) {
9696 this.state.peek = $LF;
9697 }
9698 else if (peek() === $r) {
9699 this.state.peek = $CR;
9700 }
9701 else if (peek() === $v) {
9702 this.state.peek = $VTAB;
9703 }
9704 else if (peek() === $t) {
9705 this.state.peek = $TAB;
9706 }
9707 else if (peek() === $b) {
9708 this.state.peek = $BSPACE;
9709 }
9710 else if (peek() === $f) {
9711 this.state.peek = $FF;
9712 }
9713 // Now consider more complex sequences
9714 else if (peek() === $u) {
9715 // Unicode code-point sequence
9716 this.advanceState(this.internalState); // advance past the `u` char
9717 if (peek() === $LBRACE) {
9718 // Variable length Unicode, e.g. `\x{123}`
9719 this.advanceState(this.internalState); // advance past the `{` char
9720 // Advance past the variable number of hex digits until we hit a `}` char
9721 const digitStart = this.clone();
9722 let length = 0;
9723 while (peek() !== $RBRACE) {
9724 this.advanceState(this.internalState);
9725 length++;
9726 }
9727 this.state.peek = this.decodeHexDigits(digitStart, length);
9728 }
9729 else {
9730 // Fixed length Unicode, e.g. `\u1234`
9731 const digitStart = this.clone();
9732 this.advanceState(this.internalState);
9733 this.advanceState(this.internalState);
9734 this.advanceState(this.internalState);
9735 this.state.peek = this.decodeHexDigits(digitStart, 4);
9736 }
9737 }
9738 else if (peek() === $x) {
9739 // Hex char code, e.g. `\x2F`
9740 this.advanceState(this.internalState); // advance past the `x` char
9741 const digitStart = this.clone();
9742 this.advanceState(this.internalState);
9743 this.state.peek = this.decodeHexDigits(digitStart, 2);
9744 }
9745 else if (isOctalDigit(peek())) {
9746 // Octal char code, e.g. `\012`,
9747 let octal = '';
9748 let length = 0;
9749 let previous = this.clone();
9750 while (isOctalDigit(peek()) && length < 3) {
9751 previous = this.clone();
9752 octal += String.fromCodePoint(peek());
9753 this.advanceState(this.internalState);
9754 length++;
9755 }
9756 this.state.peek = parseInt(octal, 8);
9757 // Backup one char
9758 this.internalState = previous.internalState;
9759 }
9760 else if (isNewLine(this.internalState.peek)) {
9761 // Line continuation `\` followed by a new line
9762 this.advanceState(this.internalState); // advance over the newline
9763 this.state = this.internalState;
9764 }
9765 else {
9766 // If none of the `if` blocks were executed then we just have an escaped normal character.
9767 // In that case we just, effectively, skip the backslash from the character.
9768 this.state.peek = this.internalState.peek;
9769 }
9770 }
9771 }
9772 decodeHexDigits(start, length) {
9773 const hex = this.input.substr(start.internalState.offset, length);
9774 const charCode = parseInt(hex, 16);
9775 if (!isNaN(charCode)) {
9776 return charCode;
9777 }
9778 else {
9779 start.state = start.internalState;
9780 throw new CursorError('Invalid hexadecimal escape sequence', start);
9781 }
9782 }
9783 }
9784 class CursorError {
9785 constructor(msg, cursor) {
9786 this.msg = msg;
9787 this.cursor = cursor;
9788 }
9789 }
9790
9791 /**
9792 * @license
9793 * Copyright Google LLC All Rights Reserved.
9794 *
9795 * Use of this source code is governed by an MIT-style license that can be
9796 * found in the LICENSE file at https://angular.io/license
9797 */
9798 class TreeError extends ParseError {
9799 constructor(elementName, span, msg) {
9800 super(span, msg);
9801 this.elementName = elementName;
9802 }
9803 static create(elementName, span, msg) {
9804 return new TreeError(elementName, span, msg);
9805 }
9806 }
9807 class ParseTreeResult {
9808 constructor(rootNodes, errors) {
9809 this.rootNodes = rootNodes;
9810 this.errors = errors;
9811 }
9812 }
9813 class Parser {
9814 constructor(getTagDefinition) {
9815 this.getTagDefinition = getTagDefinition;
9816 }
9817 parse(source, url, options) {
9818 const tokenizeResult = tokenize(source, url, this.getTagDefinition, options);
9819 const parser = new _TreeBuilder(tokenizeResult.tokens, this.getTagDefinition);
9820 parser.build();
9821 return new ParseTreeResult(parser.rootNodes, tokenizeResult.errors.concat(parser.errors));
9822 }
9823 }
9824 class _TreeBuilder {
9825 constructor(tokens, getTagDefinition) {
9826 this.tokens = tokens;
9827 this.getTagDefinition = getTagDefinition;
9828 this._index = -1;
9829 this._elementStack = [];
9830 this.rootNodes = [];
9831 this.errors = [];
9832 this._advance();
9833 }
9834 build() {
9835 while (this._peek.type !== TokenType.EOF) {
9836 if (this._peek.type === TokenType.TAG_OPEN_START ||
9837 this._peek.type === TokenType.INCOMPLETE_TAG_OPEN) {
9838 this._consumeStartTag(this._advance());
9839 }
9840 else if (this._peek.type === TokenType.TAG_CLOSE) {
9841 this._consumeEndTag(this._advance());
9842 }
9843 else if (this._peek.type === TokenType.CDATA_START) {
9844 this._closeVoidElement();
9845 this._consumeCdata(this._advance());
9846 }
9847 else if (this._peek.type === TokenType.COMMENT_START) {
9848 this._closeVoidElement();
9849 this._consumeComment(this._advance());
9850 }
9851 else if (this._peek.type === TokenType.TEXT || this._peek.type === TokenType.RAW_TEXT ||
9852 this._peek.type === TokenType.ESCAPABLE_RAW_TEXT) {
9853 this._closeVoidElement();
9854 this._consumeText(this._advance());
9855 }
9856 else if (this._peek.type === TokenType.EXPANSION_FORM_START) {
9857 this._consumeExpansion(this._advance());
9858 }
9859 else {
9860 // Skip all other tokens...
9861 this._advance();
9862 }
9863 }
9864 }
9865 _advance() {
9866 const prev = this._peek;
9867 if (this._index < this.tokens.length - 1) {
9868 // Note: there is always an EOF token at the end
9869 this._index++;
9870 }
9871 this._peek = this.tokens[this._index];
9872 return prev;
9873 }
9874 _advanceIf(type) {
9875 if (this._peek.type === type) {
9876 return this._advance();
9877 }
9878 return null;
9879 }
9880 _consumeCdata(_startToken) {
9881 this._consumeText(this._advance());
9882 this._advanceIf(TokenType.CDATA_END);
9883 }
9884 _consumeComment(token) {
9885 const text = this._advanceIf(TokenType.RAW_TEXT);
9886 this._advanceIf(TokenType.COMMENT_END);
9887 const value = text != null ? text.parts[0].trim() : null;
9888 this._addToParent(new Comment(value, token.sourceSpan));
9889 }
9890 _consumeExpansion(token) {
9891 const switchValue = this._advance();
9892 const type = this._advance();
9893 const cases = [];
9894 // read =
9895 while (this._peek.type === TokenType.EXPANSION_CASE_VALUE) {
9896 const expCase = this._parseExpansionCase();
9897 if (!expCase)
9898 return; // error
9899 cases.push(expCase);
9900 }
9901 // read the final }
9902 if (this._peek.type !== TokenType.EXPANSION_FORM_END) {
9903 this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`));
9904 return;
9905 }
9906 const sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end, token.sourceSpan.fullStart);
9907 this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan));
9908 this._advance();
9909 }
9910 _parseExpansionCase() {
9911 const value = this._advance();
9912 // read {
9913 if (this._peek.type !== TokenType.EXPANSION_CASE_EXP_START) {
9914 this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`));
9915 return null;
9916 }
9917 // read until }
9918 const start = this._advance();
9919 const exp = this._collectExpansionExpTokens(start);
9920 if (!exp)
9921 return null;
9922 const end = this._advance();
9923 exp.push(new Token(TokenType.EOF, [], end.sourceSpan));
9924 // parse everything in between { and }
9925 const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
9926 expansionCaseParser.build();
9927 if (expansionCaseParser.errors.length > 0) {
9928 this.errors = this.errors.concat(expansionCaseParser.errors);
9929 return null;
9930 }
9931 const sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end, value.sourceSpan.fullStart);
9932 const expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end, start.sourceSpan.fullStart);
9933 return new ExpansionCase(value.parts[0], expansionCaseParser.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan);
9934 }
9935 _collectExpansionExpTokens(start) {
9936 const exp = [];
9937 const expansionFormStack = [TokenType.EXPANSION_CASE_EXP_START];
9938 while (true) {
9939 if (this._peek.type === TokenType.EXPANSION_FORM_START ||
9940 this._peek.type === TokenType.EXPANSION_CASE_EXP_START) {
9941 expansionFormStack.push(this._peek.type);
9942 }
9943 if (this._peek.type === TokenType.EXPANSION_CASE_EXP_END) {
9944 if (lastOnStack(expansionFormStack, TokenType.EXPANSION_CASE_EXP_START)) {
9945 expansionFormStack.pop();
9946 if (expansionFormStack.length == 0)
9947 return exp;
9948 }
9949 else {
9950 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9951 return null;
9952 }
9953 }
9954 if (this._peek.type === TokenType.EXPANSION_FORM_END) {
9955 if (lastOnStack(expansionFormStack, TokenType.EXPANSION_FORM_START)) {
9956 expansionFormStack.pop();
9957 }
9958 else {
9959 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9960 return null;
9961 }
9962 }
9963 if (this._peek.type === TokenType.EOF) {
9964 this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9965 return null;
9966 }
9967 exp.push(this._advance());
9968 }
9969 }
9970 _consumeText(token) {
9971 let text = token.parts[0];
9972 if (text.length > 0 && text[0] == '\n') {
9973 const parent = this._getParentElement();
9974 if (parent != null && parent.children.length == 0 &&
9975 this.getTagDefinition(parent.name).ignoreFirstLf) {
9976 text = text.substring(1);
9977 }
9978 }
9979 if (text.length > 0) {
9980 this._addToParent(new Text$2(text, token.sourceSpan));
9981 }
9982 }
9983 _closeVoidElement() {
9984 const el = this._getParentElement();
9985 if (el && this.getTagDefinition(el.name).isVoid) {
9986 this._elementStack.pop();
9987 }
9988 }
9989 _consumeStartTag(startTagToken) {
9990 const [prefix, name] = startTagToken.parts;
9991 const attrs = [];
9992 while (this._peek.type === TokenType.ATTR_NAME) {
9993 attrs.push(this._consumeAttr(this._advance()));
9994 }
9995 const fullName = this._getElementFullName(prefix, name, this._getParentElement());
9996 let selfClosing = false;
9997 // Note: There could have been a tokenizer error
9998 // so that we don't get a token for the end tag...
9999 if (this._peek.type === TokenType.TAG_OPEN_END_VOID) {
10000 this._advance();
10001 selfClosing = true;
10002 const tagDef = this.getTagDefinition(fullName);
10003 if (!(tagDef.canSelfClose || getNsPrefix(fullName) !== null || tagDef.isVoid)) {
10004 this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void and foreign elements can be self closed "${startTagToken.parts[1]}"`));
10005 }
10006 }
10007 else if (this._peek.type === TokenType.TAG_OPEN_END) {
10008 this._advance();
10009 selfClosing = false;
10010 }
10011 const end = this._peek.sourceSpan.fullStart;
10012 const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
10013 // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
10014 const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
10015 const el = new Element$1(fullName, attrs, [], span, startSpan, undefined);
10016 this._pushElement(el);
10017 if (selfClosing) {
10018 // Elements that are self-closed have their `endSourceSpan` set to the full span, as the
10019 // element start tag also represents the end tag.
10020 this._popElement(fullName, span);
10021 }
10022 else if (startTagToken.type === TokenType.INCOMPLETE_TAG_OPEN) {
10023 // We already know the opening tag is not complete, so it is unlikely it has a corresponding
10024 // close tag. Let's optimistically parse it as a full element and emit an error.
10025 this._popElement(fullName, null);
10026 this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
10027 }
10028 }
10029 _pushElement(el) {
10030 const parentEl = this._getParentElement();
10031 if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
10032 this._elementStack.pop();
10033 }
10034 this._addToParent(el);
10035 this._elementStack.push(el);
10036 }
10037 _consumeEndTag(endTagToken) {
10038 const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
10039 if (this.getTagDefinition(fullName).isVoid) {
10040 this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
10041 }
10042 else if (!this._popElement(fullName, endTagToken.sourceSpan)) {
10043 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`;
10044 this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
10045 }
10046 }
10047 /**
10048 * Closes the nearest element with the tag name `fullName` in the parse tree.
10049 * `endSourceSpan` is the span of the closing tag, or null if the element does
10050 * not have a closing tag (for example, this happens when an incomplete
10051 * opening tag is recovered).
10052 */
10053 _popElement(fullName, endSourceSpan) {
10054 for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
10055 const el = this._elementStack[stackIndex];
10056 if (el.name == fullName) {
10057 // Record the parse span with the element that is being closed. Any elements that are
10058 // removed from the element stack at this point are closed implicitly, so they won't get
10059 // an end source span (as there is no explicit closing element).
10060 el.endSourceSpan = endSourceSpan;
10061 el.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : el.sourceSpan.end;
10062 this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
10063 return true;
10064 }
10065 if (!this.getTagDefinition(el.name).closedByParent) {
10066 return false;
10067 }
10068 }
10069 return false;
10070 }
10071 _consumeAttr(attrName) {
10072 const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
10073 let end = attrName.sourceSpan.end;
10074 let value = '';
10075 let valueSpan = undefined;
10076 if (this._peek.type === TokenType.ATTR_QUOTE) {
10077 this._advance();
10078 }
10079 if (this._peek.type === TokenType.ATTR_VALUE) {
10080 const valueToken = this._advance();
10081 value = valueToken.parts[0];
10082 end = valueToken.sourceSpan.end;
10083 valueSpan = valueToken.sourceSpan;
10084 }
10085 if (this._peek.type === TokenType.ATTR_QUOTE) {
10086 const quoteToken = this._advance();
10087 end = quoteToken.sourceSpan.end;
10088 }
10089 const keySpan = new ParseSourceSpan(attrName.sourceSpan.start, attrName.sourceSpan.end);
10090 return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end, attrName.sourceSpan.fullStart), keySpan, valueSpan);
10091 }
10092 _getParentElement() {
10093 return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
10094 }
10095 _addToParent(node) {
10096 const parent = this._getParentElement();
10097 if (parent != null) {
10098 parent.children.push(node);
10099 }
10100 else {
10101 this.rootNodes.push(node);
10102 }
10103 }
10104 _getElementFullName(prefix, localName, parentElement) {
10105 if (prefix === '') {
10106 prefix = this.getTagDefinition(localName).implicitNamespacePrefix || '';
10107 if (prefix === '' && parentElement != null) {
10108 const parentTagName = splitNsName(parentElement.name)[1];
10109 const parentTagDefinition = this.getTagDefinition(parentTagName);
10110 if (!parentTagDefinition.preventNamespaceInheritance) {
10111 prefix = getNsPrefix(parentElement.name);
10112 }
10113 }
10114 }
10115 return mergeNsAndName(prefix, localName);
10116 }
10117 }
10118 function lastOnStack(stack, element) {
10119 return stack.length > 0 && stack[stack.length - 1] === element;
10120 }
10121
10122 /**
10123 * @license
10124 * Copyright Google LLC All Rights Reserved.
10125 *
10126 * Use of this source code is governed by an MIT-style license that can be
10127 * found in the LICENSE file at https://angular.io/license
10128 */
10129 class HtmlParser extends Parser {
10130 constructor() {
10131 super(getHtmlTagDefinition);
10132 }
10133 parse(source, url, options) {
10134 return super.parse(source, url, options);
10135 }
10136 }
10137
10138 /**
10139 * @license
10140 * Copyright Google LLC All Rights Reserved.
10141 *
10142 * Use of this source code is governed by an MIT-style license that can be
10143 * found in the LICENSE file at https://angular.io/license
10144 */
10145 const PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces';
10146 const SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']);
10147 // Equivalent to \s with \u00a0 (non-breaking space) excluded.
10148 // Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
10149 const WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
10150 const NO_WS_REGEXP = new RegExp(`[^${WS_CHARS}]`);
10151 const WS_REPLACE_REGEXP = new RegExp(`[${WS_CHARS}]{2,}`, 'g');
10152 function hasPreserveWhitespacesAttr(attrs) {
10153 return attrs.some((attr) => attr.name === PRESERVE_WS_ATTR_NAME);
10154 }
10155 /**
10156 * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
10157 * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
10158 * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
10159 * and later on replaced by a space. We are re-implementing the same idea here.
10160 */
10161 function replaceNgsp(value) {
10162 // lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE
10163 return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' ');
10164 }
10165 /**
10166 * This visitor can walk HTML parse tree and remove / trim text nodes using the following rules:
10167 * - consider spaces, tabs and new lines as whitespace characters;
10168 * - drop text nodes consisting of whitespace characters only;
10169 * - for all other text nodes replace consecutive whitespace characters with one space;
10170 * - convert &ngsp; pseudo-entity to a single space;
10171 *
10172 * Removal and trimming of whitespaces have positive performance impact (less code to generate
10173 * while compiling templates, faster view creation). At the same time it can be "destructive"
10174 * in some cases (whitespaces can influence layout). Because of the potential of breaking layout
10175 * this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for
10176 * whitespace removal. The default option for whitespace removal will be revisited in Angular 6
10177 * and might be changed to "on" by default.
10178 */
10179 class WhitespaceVisitor {
10180 visitElement(element, context) {
10181 if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
10182 // don't descent into elements where we need to preserve whitespaces
10183 // but still visit all attributes to eliminate one used as a market to preserve WS
10184 return new Element$1(element.name, visitAll$1(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
10185 }
10186 return new Element$1(element.name, element.attrs, visitAllWithSiblings(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
10187 }
10188 visitAttribute(attribute, context) {
10189 return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null;
10190 }
10191 visitText(text, context) {
10192 const isNotBlank = text.value.match(NO_WS_REGEXP);
10193 const hasExpansionSibling = context &&
10194 (context.prev instanceof Expansion || context.next instanceof Expansion);
10195 if (isNotBlank || hasExpansionSibling) {
10196 return new Text$2(replaceNgsp(text.value).replace(WS_REPLACE_REGEXP, ' '), text.sourceSpan, text.i18n);
10197 }
10198 return null;
10199 }
10200 visitComment(comment, context) {
10201 return comment;
10202 }
10203 visitExpansion(expansion, context) {
10204 return expansion;
10205 }
10206 visitExpansionCase(expansionCase, context) {
10207 return expansionCase;
10208 }
10209 }
10210 function removeWhitespaces(htmlAstWithErrors) {
10211 return new ParseTreeResult(visitAll$1(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors);
10212 }
10213 function visitAllWithSiblings(visitor, nodes) {
10214 const result = [];
10215 nodes.forEach((ast, i) => {
10216 const context = { prev: nodes[i - 1], next: nodes[i + 1] };
10217 const astResult = ast.visit(visitor, context);
10218 if (astResult) {
10219 result.push(astResult);
10220 }
10221 });
10222 return result;
10223 }
10224
10225 /**
10226 * @license
10227 * Copyright Google LLC All Rights Reserved.
10228 *
10229 * Use of this source code is governed by an MIT-style license that can be
10230 * found in the LICENSE file at https://angular.io/license
10231 */
10232 // http://cldr.unicode.org/index/cldr-spec/plural-rules
10233 const PLURAL_CASES = ['zero', 'one', 'two', 'few', 'many', 'other'];
10234 /**
10235 * Expands special forms into elements.
10236 *
10237 * For example,
10238 *
10239 * ```
10240 * { messages.length, plural,
10241 * =0 {zero}
10242 * =1 {one}
10243 * other {more than one}
10244 * }
10245 * ```
10246 *
10247 * will be expanded into
10248 *
10249 * ```
10250 * <ng-container [ngPlural]="messages.length">
10251 * <ng-template ngPluralCase="=0">zero</ng-template>
10252 * <ng-template ngPluralCase="=1">one</ng-template>
10253 * <ng-template ngPluralCase="other">more than one</ng-template>
10254 * </ng-container>
10255 * ```
10256 */
10257 function expandNodes(nodes) {
10258 const expander = new _Expander();
10259 return new ExpansionResult(visitAll$1(expander, nodes), expander.isExpanded, expander.errors);
10260 }
10261 class ExpansionResult {
10262 constructor(nodes, expanded, errors) {
10263 this.nodes = nodes;
10264 this.expanded = expanded;
10265 this.errors = errors;
10266 }
10267 }
10268 class ExpansionError extends ParseError {
10269 constructor(span, errorMsg) {
10270 super(span, errorMsg);
10271 }
10272 }
10273 /**
10274 * Expand expansion forms (plural, select) to directives
10275 *
10276 * @internal
10277 */
10278 class _Expander {
10279 constructor() {
10280 this.isExpanded = false;
10281 this.errors = [];
10282 }
10283 visitElement(element, context) {
10284 return new Element$1(element.name, element.attrs, visitAll$1(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
10285 }
10286 visitAttribute(attribute, context) {
10287 return attribute;
10288 }
10289 visitText(text, context) {
10290 return text;
10291 }
10292 visitComment(comment, context) {
10293 return comment;
10294 }
10295 visitExpansion(icu, context) {
10296 this.isExpanded = true;
10297 return icu.type == 'plural' ? _expandPluralForm(icu, this.errors) :
10298 _expandDefaultForm(icu, this.errors);
10299 }
10300 visitExpansionCase(icuCase, context) {
10301 throw new Error('Should not be reached');
10302 }
10303 }
10304 // Plural forms are expanded to `NgPlural` and `NgPluralCase`s
10305 function _expandPluralForm(ast, errors) {
10306 const children = ast.cases.map(c => {
10307 if (PLURAL_CASES.indexOf(c.value) == -1 && !c.value.match(/^=\d+$/)) {
10308 errors.push(new ExpansionError(c.valueSourceSpan, `Plural cases should be "=<number>" or one of ${PLURAL_CASES.join(', ')}`));
10309 }
10310 const expansionResult = expandNodes(c.expression);
10311 errors.push(...expansionResult.errors);
10312 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);
10313 });
10314 const switchAttr = new Attribute('[ngPlural]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* i18n */);
10315 return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
10316 }
10317 // ICU messages (excluding plural form) are expanded to `NgSwitch` and `NgSwitchCase`s
10318 function _expandDefaultForm(ast, errors) {
10319 const children = ast.cases.map(c => {
10320 const expansionResult = expandNodes(c.expression);
10321 errors.push(...expansionResult.errors);
10322 if (c.value === 'other') {
10323 // other is the default case when no values match
10324 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);
10325 }
10326 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);
10327 });
10328 const switchAttr = new Attribute('[ngSwitch]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* i18n */);
10329 return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
10330 }
10331
10332 /**
10333 * @license
10334 * Copyright Google LLC All Rights Reserved.
10335 *
10336 * Use of this source code is governed by an MIT-style license that can be
10337 * found in the LICENSE file at https://angular.io/license
10338 */
10339 /**
10340 * A segment of text within the template.
10341 */
10342 class TextAst {
10343 constructor(value, ngContentIndex, sourceSpan) {
10344 this.value = value;
10345 this.ngContentIndex = ngContentIndex;
10346 this.sourceSpan = sourceSpan;
10347 }
10348 visit(visitor, context) {
10349 return visitor.visitText(this, context);
10350 }
10351 }
10352 /**
10353 * A bound expression within the text of a template.
10354 */
10355 class BoundTextAst {
10356 constructor(value, ngContentIndex, sourceSpan) {
10357 this.value = value;
10358 this.ngContentIndex = ngContentIndex;
10359 this.sourceSpan = sourceSpan;
10360 }
10361 visit(visitor, context) {
10362 return visitor.visitBoundText(this, context);
10363 }
10364 }
10365 /**
10366 * A plain attribute on an element.
10367 */
10368 class AttrAst {
10369 constructor(name, value, sourceSpan) {
10370 this.name = name;
10371 this.value = value;
10372 this.sourceSpan = sourceSpan;
10373 }
10374 visit(visitor, context) {
10375 return visitor.visitAttr(this, context);
10376 }
10377 }
10378 const BoundPropertyMapping = {
10379 [4 /* Animation */]: 4 /* Animation */,
10380 [1 /* Attribute */]: 1 /* Attribute */,
10381 [2 /* Class */]: 2 /* Class */,
10382 [0 /* Property */]: 0 /* Property */,
10383 [3 /* Style */]: 3 /* Style */,
10384 };
10385 /**
10386 * A binding for an element property (e.g. `[property]="expression"`) or an animation trigger (e.g.
10387 * `[@trigger]="stateExp"`)
10388 */
10389 class BoundElementPropertyAst {
10390 constructor(name, type, securityContext, value, unit, sourceSpan) {
10391 this.name = name;
10392 this.type = type;
10393 this.securityContext = securityContext;
10394 this.value = value;
10395 this.unit = unit;
10396 this.sourceSpan = sourceSpan;
10397 this.isAnimation = this.type === 4 /* Animation */;
10398 }
10399 static fromBoundProperty(prop) {
10400 const type = BoundPropertyMapping[prop.type];
10401 return new BoundElementPropertyAst(prop.name, type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan);
10402 }
10403 visit(visitor, context) {
10404 return visitor.visitElementProperty(this, context);
10405 }
10406 }
10407 /**
10408 * A binding for an element event (e.g. `(event)="handler()"`) or an animation trigger event (e.g.
10409 * `(@trigger.phase)="callback($event)"`).
10410 */
10411 class BoundEventAst {
10412 constructor(name, target, phase, handler, sourceSpan, handlerSpan) {
10413 this.name = name;
10414 this.target = target;
10415 this.phase = phase;
10416 this.handler = handler;
10417 this.sourceSpan = sourceSpan;
10418 this.handlerSpan = handlerSpan;
10419 this.fullName = BoundEventAst.calcFullName(this.name, this.target, this.phase);
10420 this.isAnimation = !!this.phase;
10421 }
10422 static calcFullName(name, target, phase) {
10423 if (target) {
10424 return `${target}:${name}`;
10425 }
10426 if (phase) {
10427 return `@${name}.${phase}`;
10428 }
10429 return name;
10430 }
10431 static fromParsedEvent(event) {
10432 const target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
10433 const phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
10434 return new BoundEventAst(event.name, target, phase, event.handler, event.sourceSpan, event.handlerSpan);
10435 }
10436 visit(visitor, context) {
10437 return visitor.visitEvent(this, context);
10438 }
10439 }
10440 /**
10441 * A reference declaration on an element (e.g. `let someName="expression"`).
10442 */
10443 class ReferenceAst {
10444 constructor(name, value, originalValue, sourceSpan) {
10445 this.name = name;
10446 this.value = value;
10447 this.originalValue = originalValue;
10448 this.sourceSpan = sourceSpan;
10449 }
10450 visit(visitor, context) {
10451 return visitor.visitReference(this, context);
10452 }
10453 }
10454 /**
10455 * A variable declaration on a <ng-template> (e.g. `var-someName="someLocalName"`).
10456 */
10457 class VariableAst {
10458 constructor(name, value, sourceSpan, valueSpan) {
10459 this.name = name;
10460 this.value = value;
10461 this.sourceSpan = sourceSpan;
10462 this.valueSpan = valueSpan;
10463 }
10464 static fromParsedVariable(v) {
10465 return new VariableAst(v.name, v.value, v.sourceSpan, v.valueSpan);
10466 }
10467 visit(visitor, context) {
10468 return visitor.visitVariable(this, context);
10469 }
10470 }
10471 /**
10472 * An element declaration in a template.
10473 */
10474 class ElementAst {
10475 constructor(name, attrs, inputs, outputs, references, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan, endSourceSpan) {
10476 this.name = name;
10477 this.attrs = attrs;
10478 this.inputs = inputs;
10479 this.outputs = outputs;
10480 this.references = references;
10481 this.directives = directives;
10482 this.providers = providers;
10483 this.hasViewContainer = hasViewContainer;
10484 this.queryMatches = queryMatches;
10485 this.children = children;
10486 this.ngContentIndex = ngContentIndex;
10487 this.sourceSpan = sourceSpan;
10488 this.endSourceSpan = endSourceSpan;
10489 }
10490 visit(visitor, context) {
10491 return visitor.visitElement(this, context);
10492 }
10493 }
10494 /**
10495 * A `<ng-template>` element included in an Angular template.
10496 */
10497 class EmbeddedTemplateAst {
10498 constructor(attrs, outputs, references, variables, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan) {
10499 this.attrs = attrs;
10500 this.outputs = outputs;
10501 this.references = references;
10502 this.variables = variables;
10503 this.directives = directives;
10504 this.providers = providers;
10505 this.hasViewContainer = hasViewContainer;
10506 this.queryMatches = queryMatches;
10507 this.children = children;
10508 this.ngContentIndex = ngContentIndex;
10509 this.sourceSpan = sourceSpan;
10510 }
10511 visit(visitor, context) {
10512 return visitor.visitEmbeddedTemplate(this, context);
10513 }
10514 }
10515 /**
10516 * A directive property with a bound value (e.g. `*ngIf="condition").
10517 */
10518 class BoundDirectivePropertyAst {
10519 constructor(directiveName, templateName, value, sourceSpan) {
10520 this.directiveName = directiveName;
10521 this.templateName = templateName;
10522 this.value = value;
10523 this.sourceSpan = sourceSpan;
10524 }
10525 visit(visitor, context) {
10526 return visitor.visitDirectiveProperty(this, context);
10527 }
10528 }
10529 /**
10530 * A directive declared on an element.
10531 */
10532 class DirectiveAst {
10533 constructor(directive, inputs, hostProperties, hostEvents, contentQueryStartId, sourceSpan) {
10534 this.directive = directive;
10535 this.inputs = inputs;
10536 this.hostProperties = hostProperties;
10537 this.hostEvents = hostEvents;
10538 this.contentQueryStartId = contentQueryStartId;
10539 this.sourceSpan = sourceSpan;
10540 }
10541 visit(visitor, context) {
10542 return visitor.visitDirective(this, context);
10543 }
10544 }
10545 /**
10546 * A provider declared on an element
10547 */
10548 class ProviderAst {
10549 constructor(token, multiProvider, eager, providers, providerType, lifecycleHooks, sourceSpan, isModule) {
10550 this.token = token;
10551 this.multiProvider = multiProvider;
10552 this.eager = eager;
10553 this.providers = providers;
10554 this.providerType = providerType;
10555 this.lifecycleHooks = lifecycleHooks;
10556 this.sourceSpan = sourceSpan;
10557 this.isModule = isModule;
10558 }
10559 visit(visitor, context) {
10560 // No visit method in the visitor for now...
10561 return null;
10562 }
10563 }
10564 var ProviderAstType;
10565 (function (ProviderAstType) {
10566 ProviderAstType[ProviderAstType["PublicService"] = 0] = "PublicService";
10567 ProviderAstType[ProviderAstType["PrivateService"] = 1] = "PrivateService";
10568 ProviderAstType[ProviderAstType["Component"] = 2] = "Component";
10569 ProviderAstType[ProviderAstType["Directive"] = 3] = "Directive";
10570 ProviderAstType[ProviderAstType["Builtin"] = 4] = "Builtin";
10571 })(ProviderAstType || (ProviderAstType = {}));
10572 /**
10573 * Position where content is to be projected (instance of `<ng-content>` in a template).
10574 */
10575 class NgContentAst {
10576 constructor(index, ngContentIndex, sourceSpan) {
10577 this.index = index;
10578 this.ngContentIndex = ngContentIndex;
10579 this.sourceSpan = sourceSpan;
10580 }
10581 visit(visitor, context) {
10582 return visitor.visitNgContent(this, context);
10583 }
10584 }
10585 /**
10586 * A visitor that accepts each node but doesn't do anything. It is intended to be used
10587 * as the base class for a visitor that is only interested in a subset of the node types.
10588 */
10589 class NullTemplateVisitor {
10590 visitNgContent(ast, context) { }
10591 visitEmbeddedTemplate(ast, context) { }
10592 visitElement(ast, context) { }
10593 visitReference(ast, context) { }
10594 visitVariable(ast, context) { }
10595 visitEvent(ast, context) { }
10596 visitElementProperty(ast, context) { }
10597 visitAttr(ast, context) { }
10598 visitBoundText(ast, context) { }
10599 visitText(ast, context) { }
10600 visitDirective(ast, context) { }
10601 visitDirectiveProperty(ast, context) { }
10602 }
10603 /**
10604 * Base class that can be used to build a visitor that visits each node
10605 * in an template ast recursively.
10606 */
10607 class RecursiveTemplateAstVisitor extends NullTemplateVisitor {
10608 constructor() {
10609 super();
10610 }
10611 // Nodes with children
10612 visitEmbeddedTemplate(ast, context) {
10613 return this.visitChildren(context, visit => {
10614 visit(ast.attrs);
10615 visit(ast.references);
10616 visit(ast.variables);
10617 visit(ast.directives);
10618 visit(ast.providers);
10619 visit(ast.children);
10620 });
10621 }
10622 visitElement(ast, context) {
10623 return this.visitChildren(context, visit => {
10624 visit(ast.attrs);
10625 visit(ast.inputs);
10626 visit(ast.outputs);
10627 visit(ast.references);
10628 visit(ast.directives);
10629 visit(ast.providers);
10630 visit(ast.children);
10631 });
10632 }
10633 visitDirective(ast, context) {
10634 return this.visitChildren(context, visit => {
10635 visit(ast.inputs);
10636 visit(ast.hostProperties);
10637 visit(ast.hostEvents);
10638 });
10639 }
10640 visitChildren(context, cb) {
10641 let results = [];
10642 let t = this;
10643 function visit(children) {
10644 if (children && children.length)
10645 results.push(templateVisitAll(t, children, context));
10646 }
10647 cb(visit);
10648 return Array.prototype.concat.apply([], results);
10649 }
10650 }
10651 /**
10652 * Visit every node in a list of {@link TemplateAst}s with the given {@link TemplateAstVisitor}.
10653 */
10654 function templateVisitAll(visitor, asts, context = null) {
10655 const result = [];
10656 const visit = visitor.visit ?
10657 (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) :
10658 (ast) => ast.visit(visitor, context);
10659 asts.forEach(ast => {
10660 const astResult = visit(ast);
10661 if (astResult) {
10662 result.push(astResult);
10663 }
10664 });
10665 return result;
10666 }
10667
10668 /**
10669 * @license
10670 * Copyright Google LLC All Rights Reserved.
10671 *
10672 * Use of this source code is governed by an MIT-style license that can be
10673 * found in the LICENSE file at https://angular.io/license
10674 */
10675 class ProviderError extends ParseError {
10676 constructor(message, span) {
10677 super(span, message);
10678 }
10679 }
10680 class ProviderViewContext {
10681 constructor(reflector, component) {
10682 this.reflector = reflector;
10683 this.component = component;
10684 this.errors = [];
10685 this.viewQueries = _getViewQueries(component);
10686 this.viewProviders = new Map();
10687 component.viewProviders.forEach((provider) => {
10688 if (this.viewProviders.get(tokenReference(provider.token)) == null) {
10689 this.viewProviders.set(tokenReference(provider.token), true);
10690 }
10691 });
10692 }
10693 }
10694 class ProviderElementContext {
10695 constructor(viewContext, _parent, _isViewRoot, _directiveAsts, attrs, refs, isTemplate, contentQueryStartId, _sourceSpan) {
10696 this.viewContext = viewContext;
10697 this._parent = _parent;
10698 this._isViewRoot = _isViewRoot;
10699 this._directiveAsts = _directiveAsts;
10700 this._sourceSpan = _sourceSpan;
10701 this._transformedProviders = new Map();
10702 this._seenProviders = new Map();
10703 this._queriedTokens = new Map();
10704 this.transformedHasViewContainer = false;
10705 this._attrs = {};
10706 attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
10707 const directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
10708 this._allProviders =
10709 _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, viewContext.errors);
10710 this._contentQueries = _getContentQueries(contentQueryStartId, directivesMeta);
10711 Array.from(this._allProviders.values()).forEach((provider) => {
10712 this._addQueryReadsTo(provider.token, provider.token, this._queriedTokens);
10713 });
10714 if (isTemplate) {
10715 const templateRefId = createTokenForExternalReference(this.viewContext.reflector, Identifiers.TemplateRef);
10716 this._addQueryReadsTo(templateRefId, templateRefId, this._queriedTokens);
10717 }
10718 refs.forEach((refAst) => {
10719 let defaultQueryValue = refAst.value ||
10720 createTokenForExternalReference(this.viewContext.reflector, Identifiers.ElementRef);
10721 this._addQueryReadsTo({ value: refAst.name }, defaultQueryValue, this._queriedTokens);
10722 });
10723 if (this._queriedTokens.get(this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef))) {
10724 this.transformedHasViewContainer = true;
10725 }
10726 // create the providers that we know are eager first
10727 Array.from(this._allProviders.values()).forEach((provider) => {
10728 const eager = provider.eager || this._queriedTokens.get(tokenReference(provider.token));
10729 if (eager) {
10730 this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
10731 }
10732 });
10733 }
10734 afterElement() {
10735 // collect lazy providers
10736 Array.from(this._allProviders.values()).forEach((provider) => {
10737 this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
10738 });
10739 }
10740 get transformProviders() {
10741 // Note: Maps keep their insertion order.
10742 const lazyProviders = [];
10743 const eagerProviders = [];
10744 this._transformedProviders.forEach(provider => {
10745 if (provider.eager) {
10746 eagerProviders.push(provider);
10747 }
10748 else {
10749 lazyProviders.push(provider);
10750 }
10751 });
10752 return lazyProviders.concat(eagerProviders);
10753 }
10754 get transformedDirectiveAsts() {
10755 const sortedProviderTypes = this.transformProviders.map(provider => provider.token.identifier);
10756 const sortedDirectives = this._directiveAsts.slice();
10757 sortedDirectives.sort((dir1, dir2) => sortedProviderTypes.indexOf(dir1.directive.type) -
10758 sortedProviderTypes.indexOf(dir2.directive.type));
10759 return sortedDirectives;
10760 }
10761 get queryMatches() {
10762 const allMatches = [];
10763 this._queriedTokens.forEach((matches) => {
10764 allMatches.push(...matches);
10765 });
10766 return allMatches;
10767 }
10768 _addQueryReadsTo(token, defaultValue, queryReadTokens) {
10769 this._getQueriesFor(token).forEach((query) => {
10770 const queryValue = query.meta.read || defaultValue;
10771 const tokenRef = tokenReference(queryValue);
10772 let queryMatches = queryReadTokens.get(tokenRef);
10773 if (!queryMatches) {
10774 queryMatches = [];
10775 queryReadTokens.set(tokenRef, queryMatches);
10776 }
10777 queryMatches.push({ queryId: query.queryId, value: queryValue });
10778 });
10779 }
10780 _getQueriesFor(token) {
10781 const result = [];
10782 let currentEl = this;
10783 let distance = 0;
10784 let queries;
10785 while (currentEl !== null) {
10786 queries = currentEl._contentQueries.get(tokenReference(token));
10787 if (queries) {
10788 result.push(...queries.filter((query) => query.meta.descendants || distance <= 1));
10789 }
10790 if (currentEl._directiveAsts.length > 0) {
10791 distance++;
10792 }
10793 currentEl = currentEl._parent;
10794 }
10795 queries = this.viewContext.viewQueries.get(tokenReference(token));
10796 if (queries) {
10797 result.push(...queries);
10798 }
10799 return result;
10800 }
10801 _getOrCreateLocalProvider(requestingProviderType, token, eager) {
10802 const resolvedProvider = this._allProviders.get(tokenReference(token));
10803 if (!resolvedProvider ||
10804 ((requestingProviderType === ProviderAstType.Directive ||
10805 requestingProviderType === ProviderAstType.PublicService) &&
10806 resolvedProvider.providerType === ProviderAstType.PrivateService) ||
10807 ((requestingProviderType === ProviderAstType.PrivateService ||
10808 requestingProviderType === ProviderAstType.PublicService) &&
10809 resolvedProvider.providerType === ProviderAstType.Builtin)) {
10810 return null;
10811 }
10812 let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
10813 if (transformedProviderAst) {
10814 return transformedProviderAst;
10815 }
10816 if (this._seenProviders.get(tokenReference(token)) != null) {
10817 this.viewContext.errors.push(new ProviderError(`Cannot instantiate cyclic dependency! ${tokenName(token)}`, this._sourceSpan));
10818 return null;
10819 }
10820 this._seenProviders.set(tokenReference(token), true);
10821 const transformedProviders = resolvedProvider.providers.map((provider) => {
10822 let transformedUseValue = provider.useValue;
10823 let transformedUseExisting = provider.useExisting;
10824 let transformedDeps = undefined;
10825 if (provider.useExisting != null) {
10826 const existingDiDep = this._getDependency(resolvedProvider.providerType, { token: provider.useExisting }, eager);
10827 if (existingDiDep.token != null) {
10828 transformedUseExisting = existingDiDep.token;
10829 }
10830 else {
10831 transformedUseExisting = null;
10832 transformedUseValue = existingDiDep.value;
10833 }
10834 }
10835 else if (provider.useFactory) {
10836 const deps = provider.deps || provider.useFactory.diDeps;
10837 transformedDeps =
10838 deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
10839 }
10840 else if (provider.useClass) {
10841 const deps = provider.deps || provider.useClass.diDeps;
10842 transformedDeps =
10843 deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
10844 }
10845 return _transformProvider(provider, {
10846 useExisting: transformedUseExisting,
10847 useValue: transformedUseValue,
10848 deps: transformedDeps
10849 });
10850 });
10851 transformedProviderAst =
10852 _transformProviderAst(resolvedProvider, { eager: eager, providers: transformedProviders });
10853 this._transformedProviders.set(tokenReference(token), transformedProviderAst);
10854 return transformedProviderAst;
10855 }
10856 _getLocalDependency(requestingProviderType, dep, eager = false) {
10857 if (dep.isAttribute) {
10858 const attrValue = this._attrs[dep.token.value];
10859 return { isValue: true, value: attrValue == null ? null : attrValue };
10860 }
10861 if (dep.token != null) {
10862 // access builtints
10863 if ((requestingProviderType === ProviderAstType.Directive ||
10864 requestingProviderType === ProviderAstType.Component)) {
10865 if (tokenReference(dep.token) ===
10866 this.viewContext.reflector.resolveExternalReference(Identifiers.Renderer) ||
10867 tokenReference(dep.token) ===
10868 this.viewContext.reflector.resolveExternalReference(Identifiers.ElementRef) ||
10869 tokenReference(dep.token) ===
10870 this.viewContext.reflector.resolveExternalReference(Identifiers.ChangeDetectorRef) ||
10871 tokenReference(dep.token) ===
10872 this.viewContext.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
10873 return dep;
10874 }
10875 if (tokenReference(dep.token) ===
10876 this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
10877 this.transformedHasViewContainer = true;
10878 }
10879 }
10880 // access the injector
10881 if (tokenReference(dep.token) ===
10882 this.viewContext.reflector.resolveExternalReference(Identifiers.Injector)) {
10883 return dep;
10884 }
10885 // access providers
10886 if (this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager) != null) {
10887 return dep;
10888 }
10889 }
10890 return null;
10891 }
10892 _getDependency(requestingProviderType, dep, eager = false) {
10893 let currElement = this;
10894 let currEager = eager;
10895 let result = null;
10896 if (!dep.isSkipSelf) {
10897 result = this._getLocalDependency(requestingProviderType, dep, eager);
10898 }
10899 if (dep.isSelf) {
10900 if (!result && dep.isOptional) {
10901 result = { isValue: true, value: null };
10902 }
10903 }
10904 else {
10905 // check parent elements
10906 while (!result && currElement._parent) {
10907 const prevElement = currElement;
10908 currElement = currElement._parent;
10909 if (prevElement._isViewRoot) {
10910 currEager = false;
10911 }
10912 result = currElement._getLocalDependency(ProviderAstType.PublicService, dep, currEager);
10913 }
10914 // check @Host restriction
10915 if (!result) {
10916 if (!dep.isHost || this.viewContext.component.isHost ||
10917 this.viewContext.component.type.reference === tokenReference(dep.token) ||
10918 this.viewContext.viewProviders.get(tokenReference(dep.token)) != null) {
10919 result = dep;
10920 }
10921 else {
10922 result = dep.isOptional ? { isValue: true, value: null } : null;
10923 }
10924 }
10925 }
10926 if (!result) {
10927 this.viewContext.errors.push(new ProviderError(`No provider for ${tokenName(dep.token)}`, this._sourceSpan));
10928 }
10929 return result;
10930 }
10931 }
10932 function _transformProvider(provider, { useExisting, useValue, deps }) {
10933 return {
10934 token: provider.token,
10935 useClass: provider.useClass,
10936 useExisting: useExisting,
10937 useFactory: provider.useFactory,
10938 useValue: useValue,
10939 deps: deps,
10940 multi: provider.multi
10941 };
10942 }
10943 function _transformProviderAst(provider, { eager, providers }) {
10944 return new ProviderAst(provider.token, provider.multiProvider, provider.eager || eager, providers, provider.providerType, provider.lifecycleHooks, provider.sourceSpan, provider.isModule);
10945 }
10946 function _resolveProvidersFromDirectives(directives, sourceSpan, targetErrors) {
10947 const providersByToken = new Map();
10948 directives.forEach((directive) => {
10949 const dirProvider = { token: { identifier: directive.type }, useClass: directive.type };
10950 _resolveProviders([dirProvider], directive.isComponent ? ProviderAstType.Component : ProviderAstType.Directive, true, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10951 });
10952 // Note: directives need to be able to overwrite providers of a component!
10953 const directivesWithComponentFirst = directives.filter(dir => dir.isComponent).concat(directives.filter(dir => !dir.isComponent));
10954 directivesWithComponentFirst.forEach((directive) => {
10955 _resolveProviders(directive.providers, ProviderAstType.PublicService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10956 _resolveProviders(directive.viewProviders, ProviderAstType.PrivateService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10957 });
10958 return providersByToken;
10959 }
10960 function _resolveProviders(providers, providerType, eager, sourceSpan, targetErrors, targetProvidersByToken, isModule) {
10961 providers.forEach((provider) => {
10962 let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
10963 if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
10964 targetErrors.push(new ProviderError(`Mixing multi and non multi provider is not possible for token ${tokenName(resolvedProvider.token)}`, sourceSpan));
10965 }
10966 if (!resolvedProvider) {
10967 const lifecycleHooks = provider.token.identifier &&
10968 provider.token.identifier.lifecycleHooks ?
10969 provider.token.identifier.lifecycleHooks :
10970 [];
10971 const isUseValue = !(provider.useClass || provider.useExisting || provider.useFactory);
10972 resolvedProvider = new ProviderAst(provider.token, !!provider.multi, eager || isUseValue, [provider], providerType, lifecycleHooks, sourceSpan, isModule);
10973 targetProvidersByToken.set(tokenReference(provider.token), resolvedProvider);
10974 }
10975 else {
10976 if (!provider.multi) {
10977 resolvedProvider.providers.length = 0;
10978 }
10979 resolvedProvider.providers.push(provider);
10980 }
10981 });
10982 }
10983 function _getViewQueries(component) {
10984 // Note: queries start with id 1 so we can use the number in a Bloom filter!
10985 let viewQueryId = 1;
10986 const viewQueries = new Map();
10987 if (component.viewQueries) {
10988 component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, { meta: query, queryId: viewQueryId++ }));
10989 }
10990 return viewQueries;
10991 }
10992 function _getContentQueries(contentQueryStartId, directives) {
10993 let contentQueryId = contentQueryStartId;
10994 const contentQueries = new Map();
10995 directives.forEach((directive, directiveIndex) => {
10996 if (directive.queries) {
10997 directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, { meta: query, queryId: contentQueryId++ }));
10998 }
10999 });
11000 return contentQueries;
11001 }
11002 function _addQueryToTokenMap(map, query) {
11003 query.meta.selectors.forEach((token) => {
11004 let entry = map.get(tokenReference(token));
11005 if (!entry) {
11006 entry = [];
11007 map.set(tokenReference(token), entry);
11008 }
11009 entry.push(query);
11010 });
11011 }
11012
11013 /**
11014 * @license
11015 * Copyright Google LLC All Rights Reserved.
11016 *
11017 * Use of this source code is governed by an MIT-style license that can be
11018 * found in the LICENSE file at https://angular.io/license
11019 */
11020 class StyleWithImports {
11021 constructor(style, styleUrls) {
11022 this.style = style;
11023 this.styleUrls = styleUrls;
11024 }
11025 }
11026 function isStyleUrlResolvable(url) {
11027 if (url == null || url.length === 0 || url[0] == '/')
11028 return false;
11029 const schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP);
11030 return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset';
11031 }
11032 /**
11033 * Rewrites stylesheets by resolving and removing the @import urls that
11034 * are either relative or don't have a `package:` scheme
11035 */
11036 function extractStyleUrls(resolver, baseUrl, cssText) {
11037 const foundUrls = [];
11038 const modifiedCssText = cssText.replace(CSS_STRIPPABLE_COMMENT_REGEXP, '')
11039 .replace(CSS_IMPORT_REGEXP, (...m) => {
11040 const url = m[1] || m[2];
11041 if (!isStyleUrlResolvable(url)) {
11042 // Do not attempt to resolve non-package absolute URLs with URI
11043 // scheme
11044 return m[0];
11045 }
11046 foundUrls.push(resolver.resolve(baseUrl, url));
11047 return '';
11048 });
11049 return new StyleWithImports(modifiedCssText, foundUrls);
11050 }
11051 const CSS_IMPORT_REGEXP = /@import\s+(?:url\()?\s*(?:(?:['"]([^'"]*))|([^;\)\s]*))[^;]*;?/g;
11052 const CSS_STRIPPABLE_COMMENT_REGEXP = /\/\*(?!#\s*(?:sourceURL|sourceMappingURL)=)[\s\S]+?\*\//g;
11053 const URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/;
11054
11055 /**
11056 * @license
11057 * Copyright Google LLC All Rights Reserved.
11058 *
11059 * Use of this source code is governed by an MIT-style license that can be
11060 * found in the LICENSE file at https://angular.io/license
11061 */
11062 const PROPERTY_PARTS_SEPARATOR = '.';
11063 const ATTRIBUTE_PREFIX = 'attr';
11064 const CLASS_PREFIX = 'class';
11065 const STYLE_PREFIX = 'style';
11066 const TEMPLATE_ATTR_PREFIX = '*';
11067 const ANIMATE_PROP_PREFIX = 'animate-';
11068 /**
11069 * Parses bindings in templates and in the directive host area.
11070 */
11071 class BindingParser {
11072 constructor(_exprParser, _interpolationConfig, _schemaRegistry, pipes, errors) {
11073 this._exprParser = _exprParser;
11074 this._interpolationConfig = _interpolationConfig;
11075 this._schemaRegistry = _schemaRegistry;
11076 this.errors = errors;
11077 this.pipesByName = null;
11078 this._usedPipes = new Map();
11079 // When the `pipes` parameter is `null`, do not check for used pipes
11080 // This is used in IVY when we might not know the available pipes at compile time
11081 if (pipes) {
11082 const pipesByName = new Map();
11083 pipes.forEach(pipe => pipesByName.set(pipe.name, pipe));
11084 this.pipesByName = pipesByName;
11085 }
11086 }
11087 get interpolationConfig() {
11088 return this._interpolationConfig;
11089 }
11090 getUsedPipes() {
11091 return Array.from(this._usedPipes.values());
11092 }
11093 createBoundHostProperties(dirMeta, sourceSpan) {
11094 if (dirMeta.hostProperties) {
11095 const boundProps = [];
11096 Object.keys(dirMeta.hostProperties).forEach(propName => {
11097 const expression = dirMeta.hostProperties[propName];
11098 if (typeof expression === 'string') {
11099 this.parsePropertyBinding(propName, expression, true, sourceSpan, sourceSpan.start.offset, undefined, [],
11100 // Use the `sourceSpan` for `keySpan`. This isn't really accurate, but neither is the
11101 // sourceSpan, as it represents the sourceSpan of the host itself rather than the
11102 // source of the host binding (which doesn't exist in the template). Regardless,
11103 // neither of these values are used in Ivy but are only here to satisfy the function
11104 // signature. This should likely be refactored in the future so that `sourceSpan`
11105 // isn't being used inaccurately.
11106 boundProps, sourceSpan);
11107 }
11108 else {
11109 this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
11110 }
11111 });
11112 return boundProps;
11113 }
11114 return null;
11115 }
11116 createDirectiveHostPropertyAsts(dirMeta, elementSelector, sourceSpan) {
11117 const boundProps = this.createBoundHostProperties(dirMeta, sourceSpan);
11118 return boundProps &&
11119 boundProps.map((prop) => this.createBoundElementProperty(elementSelector, prop));
11120 }
11121 createDirectiveHostEventAsts(dirMeta, sourceSpan) {
11122 if (dirMeta.hostListeners) {
11123 const targetEvents = [];
11124 Object.keys(dirMeta.hostListeners).forEach(propName => {
11125 const expression = dirMeta.hostListeners[propName];
11126 if (typeof expression === 'string') {
11127 // Use the `sourceSpan` for `keySpan` and `handlerSpan`. This isn't really accurate, but
11128 // neither is the `sourceSpan`, as it represents the `sourceSpan` of the host itself
11129 // rather than the source of the host binding (which doesn't exist in the template).
11130 // Regardless, neither of these values are used in Ivy but are only here to satisfy the
11131 // function signature. This should likely be refactored in the future so that `sourceSpan`
11132 // isn't being used inaccurately.
11133 this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents, sourceSpan);
11134 }
11135 else {
11136 this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
11137 }
11138 });
11139 return targetEvents;
11140 }
11141 return null;
11142 }
11143 parseInterpolation(value, sourceSpan) {
11144 const sourceInfo = sourceSpan.start.toString();
11145 const absoluteOffset = sourceSpan.fullStart.offset;
11146 try {
11147 const ast = this._exprParser.parseInterpolation(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11148 if (ast)
11149 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11150 this._checkPipes(ast, sourceSpan);
11151 return ast;
11152 }
11153 catch (e) {
11154 this._reportError(`${e}`, sourceSpan);
11155 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11156 }
11157 }
11158 /**
11159 * Similar to `parseInterpolation`, but treats the provided string as a single expression
11160 * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
11161 * This is used for parsing the switch expression in ICUs.
11162 */
11163 parseInterpolationExpression(expression, sourceSpan) {
11164 const sourceInfo = sourceSpan.start.toString();
11165 const absoluteOffset = sourceSpan.start.offset;
11166 try {
11167 const ast = this._exprParser.parseInterpolationExpression(expression, sourceInfo, absoluteOffset);
11168 if (ast)
11169 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11170 this._checkPipes(ast, sourceSpan);
11171 return ast;
11172 }
11173 catch (e) {
11174 this._reportError(`${e}`, sourceSpan);
11175 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11176 }
11177 }
11178 /**
11179 * Parses the bindings in a microsyntax expression, and converts them to
11180 * `ParsedProperty` or `ParsedVariable`.
11181 *
11182 * @param tplKey template binding name
11183 * @param tplValue template binding value
11184 * @param sourceSpan span of template binding relative to entire the template
11185 * @param absoluteValueOffset start of the tplValue relative to the entire template
11186 * @param targetMatchableAttrs potential attributes to match in the template
11187 * @param targetProps target property bindings in the template
11188 * @param targetVars target variables in the template
11189 */
11190 parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) {
11191 const absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX.length;
11192 const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
11193 for (const binding of bindings) {
11194 // sourceSpan is for the entire HTML attribute. bindingSpan is for a particular
11195 // binding within the microsyntax expression so it's more narrow than sourceSpan.
11196 const bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan);
11197 const key = binding.key.source;
11198 const keySpan = moveParseSourceSpan(sourceSpan, binding.key.span);
11199 if (binding instanceof VariableBinding) {
11200 const value = binding.value ? binding.value.source : '$implicit';
11201 const valueSpan = binding.value ? moveParseSourceSpan(sourceSpan, binding.value.span) : undefined;
11202 targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan));
11203 }
11204 else if (binding.value) {
11205 const srcSpan = isIvyAst ? bindingSpan : sourceSpan;
11206 const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
11207 this._parsePropertyAst(key, binding.value, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11208 }
11209 else {
11210 targetMatchableAttrs.push([key, '' /* value */]);
11211 // Since this is a literal attribute with no RHS, source span should be
11212 // just the key span.
11213 this.parseLiteralAttr(key, null /* value */, keySpan, absoluteValueOffset, undefined /* valueSpan */, targetMatchableAttrs, targetProps, keySpan);
11214 }
11215 }
11216 }
11217 /**
11218 * Parses the bindings in a microsyntax expression, e.g.
11219 * ```
11220 * <tag *tplKey="let value1 = prop; let value2 = localVar">
11221 * ```
11222 *
11223 * @param tplKey template binding name
11224 * @param tplValue template binding value
11225 * @param sourceSpan span of template binding relative to entire the template
11226 * @param absoluteKeyOffset start of the `tplKey`
11227 * @param absoluteValueOffset start of the `tplValue`
11228 */
11229 _parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) {
11230 const sourceInfo = sourceSpan.start.toString();
11231 try {
11232 const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo, absoluteKeyOffset, absoluteValueOffset);
11233 this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
11234 bindingsResult.templateBindings.forEach((binding) => {
11235 if (binding.value instanceof ASTWithSource) {
11236 this._checkPipes(binding.value, sourceSpan);
11237 }
11238 });
11239 bindingsResult.warnings.forEach((warning) => {
11240 this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING);
11241 });
11242 return bindingsResult.templateBindings;
11243 }
11244 catch (e) {
11245 this._reportError(`${e}`, sourceSpan);
11246 return [];
11247 }
11248 }
11249 parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs,
11250 // TODO(atscott): keySpan is only optional here so VE template parser implementation does not
11251 // have to change This should be required when VE is removed.
11252 targetProps, keySpan) {
11253 if (isAnimationLabel(name)) {
11254 name = name.substring(1);
11255 if (keySpan !== undefined) {
11256 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
11257 }
11258 if (value) {
11259 this._reportError(`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
11260 ` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`, sourceSpan, ParseErrorLevel.ERROR);
11261 }
11262 this._parseAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11263 }
11264 else {
11265 targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
11266 }
11267 }
11268 parsePropertyBinding(name, expression, isHost, sourceSpan, absoluteOffset, valueSpan,
11269 // TODO(atscott): keySpan is only optional here so VE template parser implementation does not
11270 // have to change This should be required when VE is removed.
11271 targetMatchableAttrs, targetProps, keySpan) {
11272 if (name.length === 0) {
11273 this._reportError(`Property name is missing in binding`, sourceSpan);
11274 }
11275 let isAnimationProp = false;
11276 if (name.startsWith(ANIMATE_PROP_PREFIX)) {
11277 isAnimationProp = true;
11278 name = name.substring(ANIMATE_PROP_PREFIX.length);
11279 if (keySpan !== undefined) {
11280 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
11281 }
11282 }
11283 else if (isAnimationLabel(name)) {
11284 isAnimationProp = true;
11285 name = name.substring(1);
11286 if (keySpan !== undefined) {
11287 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
11288 }
11289 }
11290 if (isAnimationProp) {
11291 this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11292 }
11293 else {
11294 this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11295 }
11296 }
11297 parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs,
11298 // TODO(atscott): keySpan is only optional here so VE template parser implementation does not
11299 // have to change This should be required when VE is removed.
11300 targetProps, keySpan) {
11301 const expr = this.parseInterpolation(value, valueSpan || sourceSpan);
11302 if (expr) {
11303 this._parsePropertyAst(name, expr, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
11304 return true;
11305 }
11306 return false;
11307 }
11308 _parsePropertyAst(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
11309 targetMatchableAttrs.push([name, ast.source]);
11310 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
11311 }
11312 _parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
11313 if (name.length === 0) {
11314 this._reportError('Animation trigger is missing', sourceSpan);
11315 }
11316 // This will occur when a @trigger is not paired with an expression.
11317 // For animations it is valid to not have an expression since */void
11318 // states will be applied by angular when the element is attached/detached
11319 const ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
11320 targetMatchableAttrs.push([name, ast.source]);
11321 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
11322 }
11323 _parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
11324 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
11325 try {
11326 const ast = isHostBinding ?
11327 this._exprParser.parseSimpleBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig) :
11328 this._exprParser.parseBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11329 if (ast)
11330 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11331 this._checkPipes(ast, sourceSpan);
11332 return ast;
11333 }
11334 catch (e) {
11335 this._reportError(`${e}`, sourceSpan);
11336 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11337 }
11338 }
11339 createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) {
11340 if (boundProp.isAnimation) {
11341 return new BoundElementProperty(boundProp.name, 4 /* Animation */, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
11342 }
11343 let unit = null;
11344 let bindingType = undefined;
11345 let boundPropertyName = null;
11346 const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
11347 let securityContexts = undefined;
11348 // Check for special cases (prefix style, attr, class)
11349 if (parts.length > 1) {
11350 if (parts[0] == ATTRIBUTE_PREFIX) {
11351 boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR);
11352 if (!skipValidation) {
11353 this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
11354 }
11355 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
11356 const nsSeparatorIdx = boundPropertyName.indexOf(':');
11357 if (nsSeparatorIdx > -1) {
11358 const ns = boundPropertyName.substring(0, nsSeparatorIdx);
11359 const name = boundPropertyName.substring(nsSeparatorIdx + 1);
11360 boundPropertyName = mergeNsAndName(ns, name);
11361 }
11362 bindingType = 1 /* Attribute */;
11363 }
11364 else if (parts[0] == CLASS_PREFIX) {
11365 boundPropertyName = parts[1];
11366 bindingType = 2 /* Class */;
11367 securityContexts = [SecurityContext.NONE];
11368 }
11369 else if (parts[0] == STYLE_PREFIX) {
11370 unit = parts.length > 2 ? parts[2] : null;
11371 boundPropertyName = parts[1];
11372 bindingType = 3 /* Style */;
11373 securityContexts = [SecurityContext.STYLE];
11374 }
11375 }
11376 // If not a special case, use the full property name
11377 if (boundPropertyName === null) {
11378 const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
11379 boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
11380 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
11381 bindingType = 0 /* Property */;
11382 if (!skipValidation) {
11383 this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
11384 }
11385 }
11386 return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
11387 }
11388 // TODO: keySpan should be required but was made optional to avoid changing VE parser.
11389 parseEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
11390 if (name.length === 0) {
11391 this._reportError(`Event name is missing in binding`, sourceSpan);
11392 }
11393 if (isAnimationLabel(name)) {
11394 name = name.substr(1);
11395 if (keySpan !== undefined) {
11396 keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
11397 }
11398 this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
11399 }
11400 else {
11401 this._parseRegularEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
11402 }
11403 }
11404 calcPossibleSecurityContexts(selector, propName, isAttribute) {
11405 const prop = this._schemaRegistry.getMappedPropName(propName);
11406 return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
11407 }
11408 _parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
11409 const matches = splitAtPeriod(name, [name, '']);
11410 const eventName = matches[0];
11411 const phase = matches[1].toLowerCase();
11412 const ast = this._parseAction(expression, handlerSpan);
11413 targetEvents.push(new ParsedEvent(eventName, phase, 1 /* Animation */, ast, sourceSpan, handlerSpan, keySpan));
11414 if (eventName.length === 0) {
11415 this._reportError(`Animation event name is missing in binding`, sourceSpan);
11416 }
11417 if (phase) {
11418 if (phase !== 'start' && phase !== 'done') {
11419 this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan);
11420 }
11421 }
11422 else {
11423 this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan);
11424 }
11425 }
11426 _parseRegularEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
11427 // long format: 'target: eventName'
11428 const [target, eventName] = splitAtColon(name, [null, name]);
11429 const ast = this._parseAction(expression, handlerSpan);
11430 targetMatchableAttrs.push([name, ast.source]);
11431 targetEvents.push(new ParsedEvent(eventName, target, 0 /* Regular */, ast, sourceSpan, handlerSpan, keySpan));
11432 // Don't detect directives for event names for now,
11433 // so don't add the event name to the matchableAttrs
11434 }
11435 _parseAction(value, sourceSpan) {
11436 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString();
11437 const absoluteOffset = (sourceSpan && sourceSpan.start) ? sourceSpan.start.offset : 0;
11438 try {
11439 const ast = this._exprParser.parseAction(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11440 if (ast) {
11441 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11442 }
11443 if (!ast || ast.ast instanceof EmptyExpr) {
11444 this._reportError(`Empty expressions are not allowed`, sourceSpan);
11445 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11446 }
11447 this._checkPipes(ast, sourceSpan);
11448 return ast;
11449 }
11450 catch (e) {
11451 this._reportError(`${e}`, sourceSpan);
11452 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11453 }
11454 }
11455 _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
11456 this.errors.push(new ParseError(sourceSpan, message, level));
11457 }
11458 _reportExpressionParserErrors(errors, sourceSpan) {
11459 for (const error of errors) {
11460 this._reportError(error.message, sourceSpan);
11461 }
11462 }
11463 // Make sure all the used pipes are known in `this.pipesByName`
11464 _checkPipes(ast, sourceSpan) {
11465 if (ast && this.pipesByName) {
11466 const collector = new PipeCollector();
11467 ast.visit(collector);
11468 collector.pipes.forEach((ast, pipeName) => {
11469 const pipeMeta = this.pipesByName.get(pipeName);
11470 if (!pipeMeta) {
11471 this._reportError(`The pipe '${pipeName}' could not be found`, new ParseSourceSpan(sourceSpan.start.moveBy(ast.span.start), sourceSpan.start.moveBy(ast.span.end)));
11472 }
11473 else {
11474 this._usedPipes.set(pipeName, pipeMeta);
11475 }
11476 });
11477 }
11478 }
11479 /**
11480 * @param propName the name of the property / attribute
11481 * @param sourceSpan
11482 * @param isAttr true when binding to an attribute
11483 */
11484 _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) {
11485 const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
11486 this._schemaRegistry.validateProperty(propName);
11487 if (report.error) {
11488 this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
11489 }
11490 }
11491 }
11492 class PipeCollector extends RecursiveAstVisitor {
11493 constructor() {
11494 super(...arguments);
11495 this.pipes = new Map();
11496 }
11497 visitPipe(ast, context) {
11498 this.pipes.set(ast.name, ast);
11499 ast.exp.visit(this);
11500 this.visitAll(ast.args, context);
11501 return null;
11502 }
11503 }
11504 function isAnimationLabel(name) {
11505 return name[0] == '@';
11506 }
11507 function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
11508 const ctxs = [];
11509 CssSelector.parse(selector).forEach((selector) => {
11510 const elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
11511 const notElementNames = new Set(selector.notSelectors.filter(selector => selector.isElementSelector())
11512 .map((selector) => selector.element));
11513 const possibleElementNames = elementNames.filter(elementName => !notElementNames.has(elementName));
11514 ctxs.push(...possibleElementNames.map(elementName => registry.securityContext(elementName, propName, isAttribute)));
11515 });
11516 return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
11517 }
11518 /**
11519 * Compute a new ParseSourceSpan based off an original `sourceSpan` by using
11520 * absolute offsets from the specified `absoluteSpan`.
11521 *
11522 * @param sourceSpan original source span
11523 * @param absoluteSpan absolute source span to move to
11524 */
11525 function moveParseSourceSpan(sourceSpan, absoluteSpan) {
11526 // The difference of two absolute offsets provide the relative offset
11527 const startDiff = absoluteSpan.start - sourceSpan.start.offset;
11528 const endDiff = absoluteSpan.end - sourceSpan.end.offset;
11529 return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details);
11530 }
11531
11532 /**
11533 * @license
11534 * Copyright Google LLC All Rights Reserved.
11535 *
11536 * Use of this source code is governed by an MIT-style license that can be
11537 * found in the LICENSE file at https://angular.io/license
11538 */
11539 const NG_CONTENT_SELECT_ATTR = 'select';
11540 const LINK_ELEMENT = 'link';
11541 const LINK_STYLE_REL_ATTR = 'rel';
11542 const LINK_STYLE_HREF_ATTR = 'href';
11543 const LINK_STYLE_REL_VALUE = 'stylesheet';
11544 const STYLE_ELEMENT = 'style';
11545 const SCRIPT_ELEMENT = 'script';
11546 const NG_NON_BINDABLE_ATTR = 'ngNonBindable';
11547 const NG_PROJECT_AS = 'ngProjectAs';
11548 function preparseElement(ast) {
11549 let selectAttr = null;
11550 let hrefAttr = null;
11551 let relAttr = null;
11552 let nonBindable = false;
11553 let projectAs = '';
11554 ast.attrs.forEach(attr => {
11555 const lcAttrName = attr.name.toLowerCase();
11556 if (lcAttrName == NG_CONTENT_SELECT_ATTR) {
11557 selectAttr = attr.value;
11558 }
11559 else if (lcAttrName == LINK_STYLE_HREF_ATTR) {
11560 hrefAttr = attr.value;
11561 }
11562 else if (lcAttrName == LINK_STYLE_REL_ATTR) {
11563 relAttr = attr.value;
11564 }
11565 else if (attr.name == NG_NON_BINDABLE_ATTR) {
11566 nonBindable = true;
11567 }
11568 else if (attr.name == NG_PROJECT_AS) {
11569 if (attr.value.length > 0) {
11570 projectAs = attr.value;
11571 }
11572 }
11573 });
11574 selectAttr = normalizeNgContentSelect(selectAttr);
11575 const nodeName = ast.name.toLowerCase();
11576 let type = PreparsedElementType.OTHER;
11577 if (isNgContent(nodeName)) {
11578 type = PreparsedElementType.NG_CONTENT;
11579 }
11580 else if (nodeName == STYLE_ELEMENT) {
11581 type = PreparsedElementType.STYLE;
11582 }
11583 else if (nodeName == SCRIPT_ELEMENT) {
11584 type = PreparsedElementType.SCRIPT;
11585 }
11586 else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
11587 type = PreparsedElementType.STYLESHEET;
11588 }
11589 return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs);
11590 }
11591 var PreparsedElementType;
11592 (function (PreparsedElementType) {
11593 PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT";
11594 PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE";
11595 PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET";
11596 PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT";
11597 PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER";
11598 })(PreparsedElementType || (PreparsedElementType = {}));
11599 class PreparsedElement {
11600 constructor(type, selectAttr, hrefAttr, nonBindable, projectAs) {
11601 this.type = type;
11602 this.selectAttr = selectAttr;
11603 this.hrefAttr = hrefAttr;
11604 this.nonBindable = nonBindable;
11605 this.projectAs = projectAs;
11606 }
11607 }
11608 function normalizeNgContentSelect(selectAttr) {
11609 if (selectAttr === null || selectAttr.length === 0) {
11610 return '*';
11611 }
11612 return selectAttr;
11613 }
11614
11615 /**
11616 * @license
11617 * Copyright Google LLC All Rights Reserved.
11618 *
11619 * Use of this source code is governed by an MIT-style license that can be
11620 * found in the LICENSE file at https://angular.io/license
11621 */
11622 const BIND_NAME_REGEXP = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/;
11623 // Group 1 = "bind-"
11624 const KW_BIND_IDX = 1;
11625 // Group 2 = "let-"
11626 const KW_LET_IDX = 2;
11627 // Group 3 = "ref-/#"
11628 const KW_REF_IDX = 3;
11629 // Group 4 = "on-"
11630 const KW_ON_IDX = 4;
11631 // Group 5 = "bindon-"
11632 const KW_BINDON_IDX = 5;
11633 // Group 6 = "@"
11634 const KW_AT_IDX = 6;
11635 // Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
11636 const IDENT_KW_IDX = 7;
11637 // Group 8 = identifier inside [()]
11638 const IDENT_BANANA_BOX_IDX = 8;
11639 // Group 9 = identifier inside []
11640 const IDENT_PROPERTY_IDX = 9;
11641 // Group 10 = identifier inside ()
11642 const IDENT_EVENT_IDX = 10;
11643 const TEMPLATE_ATTR_PREFIX$1 = '*';
11644 const CLASS_ATTR = 'class';
11645 let _TEXT_CSS_SELECTOR;
11646 function TEXT_CSS_SELECTOR() {
11647 if (!_TEXT_CSS_SELECTOR) {
11648 _TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
11649 }
11650 return _TEXT_CSS_SELECTOR;
11651 }
11652 class TemplateParseError extends ParseError {
11653 constructor(message, span, level) {
11654 super(span, message, level);
11655 }
11656 }
11657 class TemplateParseResult {
11658 constructor(templateAst, usedPipes, errors) {
11659 this.templateAst = templateAst;
11660 this.usedPipes = usedPipes;
11661 this.errors = errors;
11662 }
11663 }
11664 class TemplateParser {
11665 constructor(_config, _reflector, _exprParser, _schemaRegistry, _htmlParser, _console, transforms) {
11666 this._config = _config;
11667 this._reflector = _reflector;
11668 this._exprParser = _exprParser;
11669 this._schemaRegistry = _schemaRegistry;
11670 this._htmlParser = _htmlParser;
11671 this._console = _console;
11672 this.transforms = transforms;
11673 }
11674 get expressionParser() {
11675 return this._exprParser;
11676 }
11677 parse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
11678 var _a;
11679 const result = this.tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
11680 const warnings = result.errors.filter(error => error.level === ParseErrorLevel.WARNING);
11681 const errors = result.errors.filter(error => error.level === ParseErrorLevel.ERROR);
11682 if (warnings.length > 0) {
11683 (_a = this._console) === null || _a === void 0 ? void 0 : _a.warn(`Template parse warnings:\n${warnings.join('\n')}`);
11684 }
11685 if (errors.length > 0) {
11686 const errorString = errors.join('\n');
11687 throw syntaxError(`Template parse errors:\n${errorString}`, errors);
11688 }
11689 return { template: result.templateAst, pipes: result.usedPipes };
11690 }
11691 tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
11692 let htmlParseResult = typeof template === 'string' ?
11693 this._htmlParser.parse(template, templateUrl, {
11694 tokenizeExpansionForms: true,
11695 interpolationConfig: this.getInterpolationConfig(component)
11696 }) :
11697 template;
11698 if (!preserveWhitespaces) {
11699 htmlParseResult = removeWhitespaces(htmlParseResult);
11700 }
11701 return this.tryParseHtml(this.expandHtml(htmlParseResult), component, directives, pipes, schemas);
11702 }
11703 tryParseHtml(htmlAstWithErrors, component, directives, pipes, schemas) {
11704 let result;
11705 const errors = htmlAstWithErrors.errors;
11706 const usedPipes = [];
11707 if (htmlAstWithErrors.rootNodes.length > 0) {
11708 const uniqDirectives = removeSummaryDuplicates(directives);
11709 const uniqPipes = removeSummaryDuplicates(pipes);
11710 const providerViewContext = new ProviderViewContext(this._reflector, component);
11711 let interpolationConfig = undefined;
11712 if (component.template && component.template.interpolation) {
11713 interpolationConfig = {
11714 start: component.template.interpolation[0],
11715 end: component.template.interpolation[1]
11716 };
11717 }
11718 const bindingParser = new BindingParser(this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors);
11719 const parseVisitor = new TemplateParseVisitor(this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas, errors);
11720 result = visitAll$1(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
11721 errors.push(...providerViewContext.errors);
11722 usedPipes.push(...bindingParser.getUsedPipes());
11723 }
11724 else {
11725 result = [];
11726 }
11727 this._assertNoReferenceDuplicationOnTemplate(result, errors);
11728 if (errors.length > 0) {
11729 return new TemplateParseResult(result, usedPipes, errors);
11730 }
11731 if (this.transforms) {
11732 this.transforms.forEach((transform) => {
11733 result = templateVisitAll(transform, result);
11734 });
11735 }
11736 return new TemplateParseResult(result, usedPipes, errors);
11737 }
11738 expandHtml(htmlAstWithErrors, forced = false) {
11739 const errors = htmlAstWithErrors.errors;
11740 if (errors.length == 0 || forced) {
11741 // Transform ICU messages to angular directives
11742 const expandedHtmlAst = expandNodes(htmlAstWithErrors.rootNodes);
11743 errors.push(...expandedHtmlAst.errors);
11744 htmlAstWithErrors = new ParseTreeResult(expandedHtmlAst.nodes, errors);
11745 }
11746 return htmlAstWithErrors;
11747 }
11748 getInterpolationConfig(component) {
11749 if (component.template) {
11750 return InterpolationConfig.fromArray(component.template.interpolation);
11751 }
11752 return undefined;
11753 }
11754 /** @internal */
11755 _assertNoReferenceDuplicationOnTemplate(result, errors) {
11756 const existingReferences = [];
11757 result.filter(element => !!element.references)
11758 .forEach(element => element.references.forEach((reference) => {
11759 const name = reference.name;
11760 if (existingReferences.indexOf(name) < 0) {
11761 existingReferences.push(name);
11762 }
11763 else {
11764 const error = new TemplateParseError(`Reference "#${name}" is defined several times`, reference.sourceSpan, ParseErrorLevel.ERROR);
11765 errors.push(error);
11766 }
11767 }));
11768 }
11769 }
11770 class TemplateParseVisitor {
11771 constructor(reflector, config, providerViewContext, directives, _bindingParser, _schemaRegistry, _schemas, _targetErrors) {
11772 this.reflector = reflector;
11773 this.config = config;
11774 this.providerViewContext = providerViewContext;
11775 this._bindingParser = _bindingParser;
11776 this._schemaRegistry = _schemaRegistry;
11777 this._schemas = _schemas;
11778 this._targetErrors = _targetErrors;
11779 this.selectorMatcher = new SelectorMatcher();
11780 this.directivesIndex = new Map();
11781 this.ngContentCount = 0;
11782 // Note: queries start with id 1 so we can use the number in a Bloom filter!
11783 this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
11784 directives.forEach((directive, index) => {
11785 const selector = CssSelector.parse(directive.selector);
11786 this.selectorMatcher.addSelectables(selector, directive);
11787 this.directivesIndex.set(directive, index);
11788 });
11789 }
11790 visitExpansion(expansion, context) {
11791 return null;
11792 }
11793 visitExpansionCase(expansionCase, context) {
11794 return null;
11795 }
11796 visitText(text, parent) {
11797 const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
11798 const valueNoNgsp = replaceNgsp(text.value);
11799 const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan);
11800 return expr ? new BoundTextAst(expr, ngContentIndex, text.sourceSpan) :
11801 new TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan);
11802 }
11803 visitAttribute(attribute, context) {
11804 return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
11805 }
11806 visitComment(comment, context) {
11807 return null;
11808 }
11809 visitElement(element, parent) {
11810 const queryStartIndex = this.contentQueryStartId;
11811 const elName = element.name;
11812 const preparsedElement = preparseElement(element);
11813 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
11814 preparsedElement.type === PreparsedElementType.STYLE) {
11815 // Skipping <script> for security reasons
11816 // Skipping <style> as we already processed them
11817 // in the StyleCompiler
11818 return null;
11819 }
11820 if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
11821 isStyleUrlResolvable(preparsedElement.hrefAttr)) {
11822 // Skipping stylesheets with either relative urls or package scheme as we already processed
11823 // them in the StyleCompiler
11824 return null;
11825 }
11826 const matchableAttrs = [];
11827 const elementOrDirectiveProps = [];
11828 const elementOrDirectiveRefs = [];
11829 const elementVars = [];
11830 const events = [];
11831 const templateElementOrDirectiveProps = [];
11832 const templateMatchableAttrs = [];
11833 const templateElementVars = [];
11834 let hasInlineTemplates = false;
11835 const attrs = [];
11836 const isTemplateElement = isNgTemplate(element.name);
11837 element.attrs.forEach(attr => {
11838 const parsedVariables = [];
11839 const hasBinding = this._parseAttr(isTemplateElement, attr, matchableAttrs, elementOrDirectiveProps, events, elementOrDirectiveRefs, elementVars);
11840 elementVars.push(...parsedVariables.map(v => VariableAst.fromParsedVariable(v)));
11841 let templateValue;
11842 let templateKey;
11843 const normalizedName = this._normalizeAttributeName(attr.name);
11844 if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX$1)) {
11845 templateValue = attr.value;
11846 templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX$1.length);
11847 }
11848 const hasTemplateBinding = templateValue != null;
11849 if (hasTemplateBinding) {
11850 if (hasInlineTemplates) {
11851 this._reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attr.sourceSpan);
11852 }
11853 hasInlineTemplates = true;
11854 const parsedVariables = [];
11855 const absoluteOffset = (attr.valueSpan || attr.sourceSpan).start.offset;
11856 this._bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attr.sourceSpan, absoluteOffset, templateMatchableAttrs, templateElementOrDirectiveProps, parsedVariables, false /* isIvyAst */);
11857 templateElementVars.push(...parsedVariables.map(v => VariableAst.fromParsedVariable(v)));
11858 }
11859 if (!hasBinding && !hasTemplateBinding) {
11860 // don't include the bindings as attributes as well in the AST
11861 attrs.push(this.visitAttribute(attr, null));
11862 matchableAttrs.push([attr.name, attr.value]);
11863 }
11864 });
11865 const elementCssSelector = createElementCssSelector(elName, matchableAttrs);
11866 const { directives: directiveMetas, matchElement } = this._parseDirectives(this.selectorMatcher, elementCssSelector);
11867 const references = [];
11868 const boundDirectivePropNames = new Set();
11869 const directiveAsts = this._createDirectiveAsts(isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps, elementOrDirectiveRefs, element.sourceSpan, references, boundDirectivePropNames);
11870 const elementProps = this._createElementPropertyAsts(element.name, elementOrDirectiveProps, boundDirectivePropNames);
11871 const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
11872 const providerContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot, directiveAsts, attrs, references, isTemplateElement, queryStartIndex, element.sourceSpan);
11873 const children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, ElementContext.create(isTemplateElement, directiveAsts, isTemplateElement ? parent.providerContext : providerContext));
11874 providerContext.afterElement();
11875 // Override the actual selector when the `ngProjectAs` attribute is provided
11876 const projectionSelector = preparsedElement.projectAs != '' ?
11877 CssSelector.parse(preparsedElement.projectAs)[0] :
11878 elementCssSelector;
11879 const ngContentIndex = parent.findNgContentIndex(projectionSelector);
11880 let parsedElement;
11881 if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
11882 // `<ng-content>` element
11883 if (element.children && !element.children.every(_isEmptyTextNode)) {
11884 this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
11885 }
11886 parsedElement = new NgContentAst(this.ngContentCount++, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
11887 }
11888 else if (isTemplateElement) {
11889 // `<ng-template>` element
11890 this._assertAllEventsPublishedByDirectives(directiveAsts, events);
11891 this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps, element.sourceSpan);
11892 parsedElement = new EmbeddedTemplateAst(attrs, events, references, elementVars, providerContext.transformedDirectiveAsts, providerContext.transformProviders, providerContext.transformedHasViewContainer, providerContext.queryMatches, children, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
11893 }
11894 else {
11895 // element other than `<ng-content>` and `<ng-template>`
11896 this._assertElementExists(matchElement, element);
11897 this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
11898 const ngContentIndex = hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
11899 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);
11900 }
11901 if (hasInlineTemplates) {
11902 // The element as a *-attribute
11903 const templateQueryStartIndex = this.contentQueryStartId;
11904 const templateSelector = createElementCssSelector('ng-template', templateMatchableAttrs);
11905 const { directives } = this._parseDirectives(this.selectorMatcher, templateSelector);
11906 const templateBoundDirectivePropNames = new Set();
11907 const templateDirectiveAsts = this._createDirectiveAsts(true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan, [], templateBoundDirectivePropNames);
11908 const templateElementProps = this._createElementPropertyAsts(elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames);
11909 this._assertNoComponentsNorElementBindingsOnTemplate(templateDirectiveAsts, templateElementProps, element.sourceSpan);
11910 const templateProviderContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, parent.isTemplateElement, templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan);
11911 templateProviderContext.afterElement();
11912 parsedElement = new EmbeddedTemplateAst([], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts, templateProviderContext.transformProviders, templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches, [parsedElement], ngContentIndex, element.sourceSpan);
11913 }
11914 return parsedElement;
11915 }
11916 _parseAttr(isTemplateElement, attr, targetMatchableAttrs, targetProps, targetEvents, targetRefs, targetVars) {
11917 const name = this._normalizeAttributeName(attr.name);
11918 const value = attr.value;
11919 const srcSpan = attr.sourceSpan;
11920 const absoluteOffset = attr.valueSpan ? attr.valueSpan.start.offset : srcSpan.start.offset;
11921 const boundEvents = [];
11922 const bindParts = name.match(BIND_NAME_REGEXP);
11923 let hasBinding = false;
11924 if (bindParts !== null) {
11925 hasBinding = true;
11926 if (bindParts[KW_BIND_IDX] != null) {
11927 this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11928 }
11929 else if (bindParts[KW_LET_IDX]) {
11930 if (isTemplateElement) {
11931 const identifier = bindParts[IDENT_KW_IDX];
11932 this._parseVariable(identifier, value, srcSpan, targetVars);
11933 }
11934 else {
11935 this._reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
11936 }
11937 }
11938 else if (bindParts[KW_REF_IDX]) {
11939 const identifier = bindParts[IDENT_KW_IDX];
11940 this._parseReference(identifier, value, srcSpan, targetRefs);
11941 }
11942 else if (bindParts[KW_ON_IDX]) {
11943 this._bindingParser.parseEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11944 }
11945 else if (bindParts[KW_BINDON_IDX]) {
11946 this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11947 this._parseAssignmentEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11948 }
11949 else if (bindParts[KW_AT_IDX]) {
11950 this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11951 }
11952 else if (bindParts[IDENT_BANANA_BOX_IDX]) {
11953 this._bindingParser.parsePropertyBinding(bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11954 this._parseAssignmentEvent(bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11955 }
11956 else if (bindParts[IDENT_PROPERTY_IDX]) {
11957 this._bindingParser.parsePropertyBinding(bindParts[IDENT_PROPERTY_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11958 }
11959 else if (bindParts[IDENT_EVENT_IDX]) {
11960 this._bindingParser.parseEvent(bindParts[IDENT_EVENT_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11961 }
11962 }
11963 else {
11964 hasBinding = this._bindingParser.parsePropertyInterpolation(name, value, srcSpan, attr.valueSpan, targetMatchableAttrs, targetProps);
11965 }
11966 if (!hasBinding) {
11967 this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11968 }
11969 targetEvents.push(...boundEvents.map(e => BoundEventAst.fromParsedEvent(e)));
11970 return hasBinding;
11971 }
11972 _normalizeAttributeName(attrName) {
11973 return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
11974 }
11975 _parseVariable(identifier, value, sourceSpan, targetVars) {
11976 if (identifier.indexOf('-') > -1) {
11977 this._reportError(`"-" is not allowed in variable names`, sourceSpan);
11978 }
11979 else if (identifier.length === 0) {
11980 this._reportError(`Variable does not have a name`, sourceSpan);
11981 }
11982 targetVars.push(new VariableAst(identifier, value, sourceSpan));
11983 }
11984 _parseReference(identifier, value, sourceSpan, targetRefs) {
11985 if (identifier.indexOf('-') > -1) {
11986 this._reportError(`"-" is not allowed in reference names`, sourceSpan);
11987 }
11988 else if (identifier.length === 0) {
11989 this._reportError(`Reference does not have a name`, sourceSpan);
11990 }
11991 targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
11992 }
11993 _parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, targetEvents) {
11994 this._bindingParser.parseEvent(`${name}Change`, `${expression}=$event`, sourceSpan, valueSpan, targetMatchableAttrs, targetEvents);
11995 }
11996 _parseDirectives(selectorMatcher, elementCssSelector) {
11997 // Need to sort the directives so that we get consistent results throughout,
11998 // as selectorMatcher uses Maps inside.
11999 // Also deduplicate directives as they might match more than one time!
12000 const directives = newArray(this.directivesIndex.size);
12001 // Whether any directive selector matches on the element name
12002 let matchElement = false;
12003 selectorMatcher.match(elementCssSelector, (selector, directive) => {
12004 directives[this.directivesIndex.get(directive)] = directive;
12005 matchElement = matchElement || selector.hasElementSelector();
12006 });
12007 return {
12008 directives: directives.filter(dir => !!dir),
12009 matchElement,
12010 };
12011 }
12012 _createDirectiveAsts(isTemplateElement, elementName, directives, props, elementOrDirectiveRefs, elementSourceSpan, targetReferences, targetBoundDirectivePropNames) {
12013 const matchedReferences = new Set();
12014 let component = null;
12015 const directiveAsts = directives.map((directive) => {
12016 const sourceSpan = new ParseSourceSpan(elementSourceSpan.start, elementSourceSpan.end, elementSourceSpan.fullStart, `Directive ${identifierName(directive.type)}`);
12017 if (directive.isComponent) {
12018 component = directive;
12019 }
12020 const directiveProperties = [];
12021 const boundProperties = this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan);
12022 let hostProperties = boundProperties.map(prop => BoundElementPropertyAst.fromBoundProperty(prop));
12023 // Note: We need to check the host properties here as well,
12024 // as we don't know the element name in the DirectiveWrapperCompiler yet.
12025 hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);
12026 const parsedEvents = this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan);
12027 this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties, targetBoundDirectivePropNames);
12028 elementOrDirectiveRefs.forEach((elOrDirRef) => {
12029 if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
12030 (elOrDirRef.isReferenceToDirective(directive))) {
12031 targetReferences.push(new ReferenceAst(elOrDirRef.name, createTokenForReference(directive.type.reference), elOrDirRef.value, elOrDirRef.sourceSpan));
12032 matchedReferences.add(elOrDirRef.name);
12033 }
12034 });
12035 const hostEvents = parsedEvents.map(e => BoundEventAst.fromParsedEvent(e));
12036 const contentQueryStartId = this.contentQueryStartId;
12037 this.contentQueryStartId += directive.queries.length;
12038 return new DirectiveAst(directive, directiveProperties, hostProperties, hostEvents, contentQueryStartId, sourceSpan);
12039 });
12040 elementOrDirectiveRefs.forEach((elOrDirRef) => {
12041 if (elOrDirRef.value.length > 0) {
12042 if (!matchedReferences.has(elOrDirRef.name)) {
12043 this._reportError(`There is no directive with "exportAs" set to "${elOrDirRef.value}"`, elOrDirRef.sourceSpan);
12044 }
12045 }
12046 else if (!component) {
12047 let refToken = null;
12048 if (isTemplateElement) {
12049 refToken = createTokenForExternalReference(this.reflector, Identifiers.TemplateRef);
12050 }
12051 targetReferences.push(new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.value, elOrDirRef.sourceSpan));
12052 }
12053 });
12054 return directiveAsts;
12055 }
12056 _createDirectivePropertyAsts(directiveProperties, boundProps, targetBoundDirectiveProps, targetBoundDirectivePropNames) {
12057 if (directiveProperties) {
12058 const boundPropsByName = new Map();
12059 boundProps.forEach(boundProp => {
12060 const prevValue = boundPropsByName.get(boundProp.name);
12061 if (!prevValue || prevValue.isLiteral) {
12062 // give [a]="b" a higher precedence than a="b" on the same element
12063 boundPropsByName.set(boundProp.name, boundProp);
12064 }
12065 });
12066 Object.keys(directiveProperties).forEach(dirProp => {
12067 const elProp = directiveProperties[dirProp];
12068 const boundProp = boundPropsByName.get(elProp);
12069 // Bindings are optional, so this binding only needs to be set up if an expression is given.
12070 if (boundProp) {
12071 targetBoundDirectivePropNames.add(boundProp.name);
12072 if (!isEmptyExpression(boundProp.expression)) {
12073 targetBoundDirectiveProps.push(new BoundDirectivePropertyAst(dirProp, boundProp.name, boundProp.expression, boundProp.sourceSpan));
12074 }
12075 }
12076 });
12077 }
12078 }
12079 _createElementPropertyAsts(elementName, props, boundDirectivePropNames) {
12080 const boundElementProps = [];
12081 props.forEach((prop) => {
12082 if (!prop.isLiteral && !boundDirectivePropNames.has(prop.name)) {
12083 const boundProp = this._bindingParser.createBoundElementProperty(elementName, prop);
12084 boundElementProps.push(BoundElementPropertyAst.fromBoundProperty(boundProp));
12085 }
12086 });
12087 return this._checkPropertiesInSchema(elementName, boundElementProps);
12088 }
12089 _findComponentDirectives(directives) {
12090 return directives.filter(directive => directive.directive.isComponent);
12091 }
12092 _findComponentDirectiveNames(directives) {
12093 return this._findComponentDirectives(directives)
12094 .map(directive => identifierName(directive.directive.type));
12095 }
12096 _assertOnlyOneComponent(directives, sourceSpan) {
12097 const componentTypeNames = this._findComponentDirectiveNames(directives);
12098 if (componentTypeNames.length > 1) {
12099 this._reportError(`More than one component matched on this element.\n` +
12100 `Make sure that only one component's selector can match a given element.\n` +
12101 `Conflicting components: ${componentTypeNames.join(',')}`, sourceSpan);
12102 }
12103 }
12104 /**
12105 * Make sure that non-angular tags conform to the schemas.
12106 *
12107 * Note: An element is considered an angular tag when at least one directive selector matches the
12108 * tag name.
12109 *
12110 * @param matchElement Whether any directive has matched on the tag name
12111 * @param element the html element
12112 */
12113 _assertElementExists(matchElement, element) {
12114 const elName = element.name.replace(/^:xhtml:/, '');
12115 if (!matchElement && !this._schemaRegistry.hasElement(elName, this._schemas)) {
12116 let errorMsg = `'${elName}' is not a known element:\n`;
12117 errorMsg += `1. If '${elName}' is an Angular component, then verify that it is part of this module.\n`;
12118 if (elName.indexOf('-') > -1) {
12119 errorMsg += `2. If '${elName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`;
12120 }
12121 else {
12122 errorMsg +=
12123 `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
12124 }
12125 this._reportError(errorMsg, element.sourceSpan);
12126 }
12127 }
12128 _assertNoComponentsNorElementBindingsOnTemplate(directives, elementProps, sourceSpan) {
12129 const componentTypeNames = this._findComponentDirectiveNames(directives);
12130 if (componentTypeNames.length > 0) {
12131 this._reportError(`Components on an embedded template: ${componentTypeNames.join(',')}`, sourceSpan);
12132 }
12133 elementProps.forEach(prop => {
12134 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);
12135 });
12136 }
12137 _assertAllEventsPublishedByDirectives(directives, events) {
12138 const allDirectiveEvents = new Set();
12139 directives.forEach(directive => {
12140 Object.keys(directive.directive.outputs).forEach(k => {
12141 const eventName = directive.directive.outputs[k];
12142 allDirectiveEvents.add(eventName);
12143 });
12144 });
12145 events.forEach(event => {
12146 if (event.target != null || !allDirectiveEvents.has(event.name)) {
12147 this._reportError(`Event binding ${event
12148 .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);
12149 }
12150 });
12151 }
12152 _checkPropertiesInSchema(elementName, boundProps) {
12153 // Note: We can't filter out empty expressions before this method,
12154 // as we still want to validate them!
12155 return boundProps.filter((boundProp) => {
12156 if (boundProp.type === 0 /* Property */ &&
12157 !this._schemaRegistry.hasProperty(elementName, boundProp.name, this._schemas)) {
12158 let errorMsg = `Can't bind to '${boundProp.name}' since it isn't a known property of '${elementName}'.`;
12159 if (elementName.startsWith('ng-')) {
12160 errorMsg +=
12161 `\n1. If '${boundProp
12162 .name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` +
12163 `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
12164 }
12165 else if (elementName.indexOf('-') > -1) {
12166 errorMsg +=
12167 `\n1. If '${elementName}' is an Angular component and it has '${boundProp.name}' input, then verify that it is part of this module.` +
12168 `\n2. If '${elementName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` +
12169 `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
12170 }
12171 this._reportError(errorMsg, boundProp.sourceSpan);
12172 }
12173 return !isEmptyExpression(boundProp.value);
12174 });
12175 }
12176 _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
12177 this._targetErrors.push(new ParseError(sourceSpan, message, level));
12178 }
12179 }
12180 class NonBindableVisitor {
12181 visitElement(ast, parent) {
12182 const preparsedElement = preparseElement(ast);
12183 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
12184 preparsedElement.type === PreparsedElementType.STYLE ||
12185 preparsedElement.type === PreparsedElementType.STYLESHEET) {
12186 // Skipping <script> for security reasons
12187 // Skipping <style> and stylesheets as we already processed them
12188 // in the StyleCompiler
12189 return null;
12190 }
12191 const attrNameAndValues = ast.attrs.map((attr) => [attr.name, attr.value]);
12192 const selector = createElementCssSelector(ast.name, attrNameAndValues);
12193 const ngContentIndex = parent.findNgContentIndex(selector);
12194 const children = visitAll$1(this, ast.children, EMPTY_ELEMENT_CONTEXT);
12195 return new ElementAst(ast.name, visitAll$1(this, ast.attrs), [], [], [], [], [], false, [], children, ngContentIndex, ast.sourceSpan, ast.endSourceSpan);
12196 }
12197 visitComment(comment, context) {
12198 return null;
12199 }
12200 visitAttribute(attribute, context) {
12201 return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
12202 }
12203 visitText(text, parent) {
12204 const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
12205 return new TextAst(text.value, ngContentIndex, text.sourceSpan);
12206 }
12207 visitExpansion(expansion, context) {
12208 return expansion;
12209 }
12210 visitExpansionCase(expansionCase, context) {
12211 return expansionCase;
12212 }
12213 }
12214 /**
12215 * A reference to an element or directive in a template. E.g., the reference in this template:
12216 *
12217 * <div #myMenu="coolMenu">
12218 *
12219 * would be {name: 'myMenu', value: 'coolMenu', sourceSpan: ...}
12220 */
12221 class ElementOrDirectiveRef {
12222 constructor(name, value, sourceSpan) {
12223 this.name = name;
12224 this.value = value;
12225 this.sourceSpan = sourceSpan;
12226 }
12227 /** Gets whether this is a reference to the given directive. */
12228 isReferenceToDirective(directive) {
12229 return splitExportAs(directive.exportAs).indexOf(this.value) !== -1;
12230 }
12231 }
12232 /** Splits a raw, potentially comma-delimited `exportAs` value into an array of names. */
12233 function splitExportAs(exportAs) {
12234 return exportAs ? exportAs.split(',').map(e => e.trim()) : [];
12235 }
12236 function splitClasses(classAttrValue) {
12237 return classAttrValue.trim().split(/\s+/g);
12238 }
12239 class ElementContext {
12240 constructor(isTemplateElement, _ngContentIndexMatcher, _wildcardNgContentIndex, providerContext) {
12241 this.isTemplateElement = isTemplateElement;
12242 this._ngContentIndexMatcher = _ngContentIndexMatcher;
12243 this._wildcardNgContentIndex = _wildcardNgContentIndex;
12244 this.providerContext = providerContext;
12245 }
12246 static create(isTemplateElement, directives, providerContext) {
12247 const matcher = new SelectorMatcher();
12248 let wildcardNgContentIndex = null;
12249 const component = directives.find(directive => directive.directive.isComponent);
12250 if (component) {
12251 const ngContentSelectors = component.directive.template.ngContentSelectors;
12252 for (let i = 0; i < ngContentSelectors.length; i++) {
12253 const selector = ngContentSelectors[i];
12254 if (selector === '*') {
12255 wildcardNgContentIndex = i;
12256 }
12257 else {
12258 matcher.addSelectables(CssSelector.parse(ngContentSelectors[i]), i);
12259 }
12260 }
12261 }
12262 return new ElementContext(isTemplateElement, matcher, wildcardNgContentIndex, providerContext);
12263 }
12264 findNgContentIndex(selector) {
12265 const ngContentIndices = [];
12266 this._ngContentIndexMatcher.match(selector, (selector, ngContentIndex) => {
12267 ngContentIndices.push(ngContentIndex);
12268 });
12269 ngContentIndices.sort();
12270 if (this._wildcardNgContentIndex != null) {
12271 ngContentIndices.push(this._wildcardNgContentIndex);
12272 }
12273 return ngContentIndices.length > 0 ? ngContentIndices[0] : null;
12274 }
12275 }
12276 function createElementCssSelector(elementName, attributes) {
12277 const cssSelector = new CssSelector();
12278 const elNameNoNs = splitNsName(elementName)[1];
12279 cssSelector.setElement(elNameNoNs);
12280 for (let i = 0; i < attributes.length; i++) {
12281 const attrName = attributes[i][0];
12282 const attrNameNoNs = splitNsName(attrName)[1];
12283 const attrValue = attributes[i][1];
12284 cssSelector.addAttribute(attrNameNoNs, attrValue);
12285 if (attrName.toLowerCase() == CLASS_ATTR) {
12286 const classes = splitClasses(attrValue);
12287 classes.forEach(className => cssSelector.addClassName(className));
12288 }
12289 }
12290 return cssSelector;
12291 }
12292 const EMPTY_ELEMENT_CONTEXT = new ElementContext(true, new SelectorMatcher(), null, null);
12293 const NON_BINDABLE_VISITOR = new NonBindableVisitor();
12294 function _isEmptyTextNode(node) {
12295 return node instanceof Text$2 && node.value.trim().length == 0;
12296 }
12297 function removeSummaryDuplicates(items) {
12298 const map = new Map();
12299 items.forEach((item) => {
12300 if (!map.get(item.type.reference)) {
12301 map.set(item.type.reference, item);
12302 }
12303 });
12304 return Array.from(map.values());
12305 }
12306 function isEmptyExpression(ast) {
12307 if (ast instanceof ASTWithSource) {
12308 ast = ast.ast;
12309 }
12310 return ast instanceof EmptyExpr;
12311 }
12312
12313 /**
12314 * @license
12315 * Copyright Google LLC All Rights Reserved.
12316 *
12317 * Use of this source code is governed by an MIT-style license that can be
12318 * found in the LICENSE file at https://angular.io/license
12319 */
12320 /**
12321 * Parses string representation of a style and converts it into object literal.
12322 *
12323 * @param value string representation of style as used in the `style` attribute in HTML.
12324 * Example: `color: red; height: auto`.
12325 * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
12326 * 'auto']`
12327 */
12328 function parse(value) {
12329 // we use a string array here instead of a string map
12330 // because a string-map is not guaranteed to retain the
12331 // order of the entries whereas a string array can be
12332 // constructed in a [key, value, key, value] format.
12333 const styles = [];
12334 let i = 0;
12335 let parenDepth = 0;
12336 let quote = 0 /* QuoteNone */;
12337 let valueStart = 0;
12338 let propStart = 0;
12339 let currentProp = null;
12340 let valueHasQuotes = false;
12341 while (i < value.length) {
12342 const token = value.charCodeAt(i++);
12343 switch (token) {
12344 case 40 /* OpenParen */:
12345 parenDepth++;
12346 break;
12347 case 41 /* CloseParen */:
12348 parenDepth--;
12349 break;
12350 case 39 /* QuoteSingle */:
12351 // valueStart needs to be there since prop values don't
12352 // have quotes in CSS
12353 valueHasQuotes = valueHasQuotes || valueStart > 0;
12354 if (quote === 0 /* QuoteNone */) {
12355 quote = 39 /* QuoteSingle */;
12356 }
12357 else if (quote === 39 /* QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
12358 quote = 0 /* QuoteNone */;
12359 }
12360 break;
12361 case 34 /* QuoteDouble */:
12362 // same logic as above
12363 valueHasQuotes = valueHasQuotes || valueStart > 0;
12364 if (quote === 0 /* QuoteNone */) {
12365 quote = 34 /* QuoteDouble */;
12366 }
12367 else if (quote === 34 /* QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
12368 quote = 0 /* QuoteNone */;
12369 }
12370 break;
12371 case 58 /* Colon */:
12372 if (!currentProp && parenDepth === 0 && quote === 0 /* QuoteNone */) {
12373 currentProp = hyphenate(value.substring(propStart, i - 1).trim());
12374 valueStart = i;
12375 }
12376 break;
12377 case 59 /* Semicolon */:
12378 if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* QuoteNone */) {
12379 const styleVal = value.substring(valueStart, i - 1).trim();
12380 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
12381 propStart = i;
12382 valueStart = 0;
12383 currentProp = null;
12384 valueHasQuotes = false;
12385 }
12386 break;
12387 }
12388 }
12389 if (currentProp && valueStart) {
12390 const styleVal = value.substr(valueStart).trim();
12391 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
12392 }
12393 return styles;
12394 }
12395 function stripUnnecessaryQuotes(value) {
12396 const qS = value.charCodeAt(0);
12397 const qE = value.charCodeAt(value.length - 1);
12398 if (qS == qE && (qS == 39 /* QuoteSingle */ || qS == 34 /* QuoteDouble */)) {
12399 const tempValue = value.substring(1, value.length - 1);
12400 // special case to avoid using a multi-quoted string that was just chomped
12401 // (e.g. `font-family: "Verdana", "sans-serif"`)
12402 if (tempValue.indexOf('\'') == -1 && tempValue.indexOf('"') == -1) {
12403 value = tempValue;
12404 }
12405 }
12406 return value;
12407 }
12408 function hyphenate(value) {
12409 return value
12410 .replace(/[a-z][A-Z]/g, v => {
12411 return v.charAt(0) + '-' + v.charAt(1);
12412 })
12413 .toLowerCase();
12414 }
12415
12416 const IMPORTANT_FLAG = '!important';
12417 /**
12418 * Minimum amount of binding slots required in the runtime for style/class bindings.
12419 *
12420 * Styling in Angular uses up two slots in the runtime LView/TData data structures to
12421 * record binding data, property information and metadata.
12422 *
12423 * When a binding is registered it will place the following information in the `LView`:
12424 *
12425 * slot 1) binding value
12426 * slot 2) cached value (all other values collected before it in string form)
12427 *
12428 * When a binding is registered it will place the following information in the `TData`:
12429 *
12430 * slot 1) prop name
12431 * slot 2) binding index that points to the previous style/class binding (and some extra config
12432 * values)
12433 *
12434 * Let's imagine we have a binding that looks like so:
12435 *
12436 * ```
12437 * <div [style.width]="x" [style.height]="y">
12438 * ```
12439 *
12440 * Our `LView` and `TData` data-structures look like so:
12441 *
12442 * ```typescript
12443 * LView = [
12444 * // ...
12445 * x, // value of x
12446 * "width: x",
12447 *
12448 * y, // value of y
12449 * "width: x; height: y",
12450 * // ...
12451 * ];
12452 *
12453 * TData = [
12454 * // ...
12455 * "width", // binding slot 20
12456 * 0,
12457 *
12458 * "height",
12459 * 20,
12460 * // ...
12461 * ];
12462 * ```
12463 *
12464 * */
12465 const MIN_STYLING_BINDING_SLOTS_REQUIRED = 2;
12466 /**
12467 * Produces creation/update instructions for all styling bindings (class and style)
12468 *
12469 * It also produces the creation instruction to register all initial styling values
12470 * (which are all the static class="..." and style="..." attribute values that exist
12471 * on an element within a template).
12472 *
12473 * The builder class below handles producing instructions for the following cases:
12474 *
12475 * - Static style/class attributes (style="..." and class="...")
12476 * - Dynamic style/class map bindings ([style]="map" and [class]="map|string")
12477 * - Dynamic style/class property bindings ([style.prop]="exp" and [class.name]="exp")
12478 *
12479 * Due to the complex relationship of all of these cases, the instructions generated
12480 * for these attributes/properties/bindings must be done so in the correct order. The
12481 * order which these must be generated is as follows:
12482 *
12483 * if (createMode) {
12484 * styling(...)
12485 * }
12486 * if (updateMode) {
12487 * styleMap(...)
12488 * classMap(...)
12489 * styleProp(...)
12490 * classProp(...)
12491 * }
12492 *
12493 * The creation/update methods within the builder class produce these instructions.
12494 */
12495 class StylingBuilder {
12496 constructor(_directiveExpr) {
12497 this._directiveExpr = _directiveExpr;
12498 /** Whether or not there are any static styling values present */
12499 this._hasInitialValues = false;
12500 /**
12501 * Whether or not there are any styling bindings present
12502 * (i.e. `[style]`, `[class]`, `[style.prop]` or `[class.name]`)
12503 */
12504 this.hasBindings = false;
12505 this.hasBindingsWithPipes = false;
12506 /** the input for [class] (if it exists) */
12507 this._classMapInput = null;
12508 /** the input for [style] (if it exists) */
12509 this._styleMapInput = null;
12510 /** an array of each [style.prop] input */
12511 this._singleStyleInputs = null;
12512 /** an array of each [class.name] input */
12513 this._singleClassInputs = null;
12514 this._lastStylingInput = null;
12515 this._firstStylingInput = null;
12516 // maps are used instead of hash maps because a Map will
12517 // retain the ordering of the keys
12518 /**
12519 * Represents the location of each style binding in the template
12520 * (e.g. `<div [style.width]="w" [style.height]="h">` implies
12521 * that `width=0` and `height=1`)
12522 */
12523 this._stylesIndex = new Map();
12524 /**
12525 * Represents the location of each class binding in the template
12526 * (e.g. `<div [class.big]="b" [class.hidden]="h">` implies
12527 * that `big=0` and `hidden=1`)
12528 */
12529 this._classesIndex = new Map();
12530 this._initialStyleValues = [];
12531 this._initialClassValues = [];
12532 }
12533 /**
12534 * Registers a given input to the styling builder to be later used when producing AOT code.
12535 *
12536 * The code below will only accept the input if it is somehow tied to styling (whether it be
12537 * style/class bindings or static style/class attributes).
12538 */
12539 registerBoundInput(input) {
12540 // [attr.style] or [attr.class] are skipped in the code below,
12541 // they should not be treated as styling-based bindings since
12542 // they are intended to be written directly to the attr and
12543 // will therefore skip all style/class resolution that is present
12544 // with style="", [style]="" and [style.prop]="", class="",
12545 // [class.prop]="". [class]="" assignments
12546 let binding = null;
12547 let name = input.name;
12548 switch (input.type) {
12549 case 0 /* Property */:
12550 binding = this.registerInputBasedOnName(name, input.value, input.sourceSpan);
12551 break;
12552 case 3 /* Style */:
12553 binding = this.registerStyleInput(name, false, input.value, input.sourceSpan, input.unit);
12554 break;
12555 case 2 /* Class */:
12556 binding = this.registerClassInput(name, false, input.value, input.sourceSpan);
12557 break;
12558 }
12559 return binding ? true : false;
12560 }
12561 registerInputBasedOnName(name, expression, sourceSpan) {
12562 let binding = null;
12563 const prefix = name.substring(0, 6);
12564 const isStyle = name === 'style' || prefix === 'style.' || prefix === 'style!';
12565 const isClass = !isStyle && (name === 'class' || prefix === 'class.' || prefix === 'class!');
12566 if (isStyle || isClass) {
12567 const isMapBased = name.charAt(5) !== '.'; // style.prop or class.prop makes this a no
12568 const property = name.substr(isMapBased ? 5 : 6); // the dot explains why there's a +1
12569 if (isStyle) {
12570 binding = this.registerStyleInput(property, isMapBased, expression, sourceSpan);
12571 }
12572 else {
12573 binding = this.registerClassInput(property, isMapBased, expression, sourceSpan);
12574 }
12575 }
12576 return binding;
12577 }
12578 registerStyleInput(name, isMapBased, value, sourceSpan, suffix) {
12579 if (isEmptyExpression(value)) {
12580 return null;
12581 }
12582 name = normalizePropName(name);
12583 const { property, hasOverrideFlag, suffix: bindingSuffix } = parseProperty(name);
12584 suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
12585 const entry = { name: property, suffix: suffix, value, sourceSpan, hasOverrideFlag };
12586 if (isMapBased) {
12587 this._styleMapInput = entry;
12588 }
12589 else {
12590 (this._singleStyleInputs = this._singleStyleInputs || []).push(entry);
12591 registerIntoMap(this._stylesIndex, property);
12592 }
12593 this._lastStylingInput = entry;
12594 this._firstStylingInput = this._firstStylingInput || entry;
12595 this._checkForPipes(value);
12596 this.hasBindings = true;
12597 return entry;
12598 }
12599 registerClassInput(name, isMapBased, value, sourceSpan) {
12600 if (isEmptyExpression(value)) {
12601 return null;
12602 }
12603 const { property, hasOverrideFlag } = parseProperty(name);
12604 const entry = { name: property, value, sourceSpan, hasOverrideFlag, suffix: null };
12605 if (isMapBased) {
12606 if (this._classMapInput) {
12607 throw new Error('[class] and [className] bindings cannot be used on the same element simultaneously');
12608 }
12609 this._classMapInput = entry;
12610 }
12611 else {
12612 (this._singleClassInputs = this._singleClassInputs || []).push(entry);
12613 registerIntoMap(this._classesIndex, property);
12614 }
12615 this._lastStylingInput = entry;
12616 this._firstStylingInput = this._firstStylingInput || entry;
12617 this._checkForPipes(value);
12618 this.hasBindings = true;
12619 return entry;
12620 }
12621 _checkForPipes(value) {
12622 if ((value instanceof ASTWithSource) && (value.ast instanceof BindingPipe)) {
12623 this.hasBindingsWithPipes = true;
12624 }
12625 }
12626 /**
12627 * Registers the element's static style string value to the builder.
12628 *
12629 * @param value the style string (e.g. `width:100px; height:200px;`)
12630 */
12631 registerStyleAttr(value) {
12632 this._initialStyleValues = parse(value);
12633 this._hasInitialValues = true;
12634 }
12635 /**
12636 * Registers the element's static class string value to the builder.
12637 *
12638 * @param value the className string (e.g. `disabled gold zoom`)
12639 */
12640 registerClassAttr(value) {
12641 this._initialClassValues = value.trim().split(/\s+/g);
12642 this._hasInitialValues = true;
12643 }
12644 /**
12645 * Appends all styling-related expressions to the provided attrs array.
12646 *
12647 * @param attrs an existing array where each of the styling expressions
12648 * will be inserted into.
12649 */
12650 populateInitialStylingAttrs(attrs) {
12651 // [CLASS_MARKER, 'foo', 'bar', 'baz' ...]
12652 if (this._initialClassValues.length) {
12653 attrs.push(literal(1 /* Classes */));
12654 for (let i = 0; i < this._initialClassValues.length; i++) {
12655 attrs.push(literal(this._initialClassValues[i]));
12656 }
12657 }
12658 // [STYLE_MARKER, 'width', '200px', 'height', '100px', ...]
12659 if (this._initialStyleValues.length) {
12660 attrs.push(literal(2 /* Styles */));
12661 for (let i = 0; i < this._initialStyleValues.length; i += 2) {
12662 attrs.push(literal(this._initialStyleValues[i]), literal(this._initialStyleValues[i + 1]));
12663 }
12664 }
12665 }
12666 /**
12667 * Builds an instruction with all the expressions and parameters for `elementHostAttrs`.
12668 *
12669 * The instruction generation code below is used for producing the AOT statement code which is
12670 * responsible for registering initial styles (within a directive hostBindings' creation block),
12671 * as well as any of the provided attribute values, to the directive host element.
12672 */
12673 assignHostAttrs(attrs, definitionMap) {
12674 if (this._directiveExpr && (attrs.length || this._hasInitialValues)) {
12675 this.populateInitialStylingAttrs(attrs);
12676 definitionMap.set('hostAttrs', literalArr(attrs));
12677 }
12678 }
12679 /**
12680 * Builds an instruction with all the expressions and parameters for `classMap`.
12681 *
12682 * The instruction data will contain all expressions for `classMap` to function
12683 * which includes the `[class]` expression params.
12684 */
12685 buildClassMapInstruction(valueConverter) {
12686 if (this._classMapInput) {
12687 return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput);
12688 }
12689 return null;
12690 }
12691 /**
12692 * Builds an instruction with all the expressions and parameters for `styleMap`.
12693 *
12694 * The instruction data will contain all expressions for `styleMap` to function
12695 * which includes the `[style]` expression params.
12696 */
12697 buildStyleMapInstruction(valueConverter) {
12698 if (this._styleMapInput) {
12699 return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput);
12700 }
12701 return null;
12702 }
12703 _buildMapBasedInstruction(valueConverter, isClassBased, stylingInput) {
12704 // each styling binding value is stored in the LView
12705 // map-based bindings allocate two slots: one for the
12706 // previous binding value and another for the previous
12707 // className or style attribute value.
12708 let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
12709 // these values must be outside of the update block so that they can
12710 // be evaluated (the AST visit call) during creation time so that any
12711 // pipes can be picked up in time before the template is built
12712 const mapValue = stylingInput.value.visit(valueConverter);
12713 let reference;
12714 if (mapValue instanceof Interpolation) {
12715 totalBindingSlotsRequired += mapValue.expressions.length;
12716 reference = isClassBased ? getClassMapInterpolationExpression(mapValue) :
12717 getStyleMapInterpolationExpression(mapValue);
12718 }
12719 else {
12720 reference = isClassBased ? Identifiers$1.classMap : Identifiers$1.styleMap;
12721 }
12722 return {
12723 reference,
12724 calls: [{
12725 supportsInterpolation: true,
12726 sourceSpan: stylingInput.sourceSpan,
12727 allocateBindingSlots: totalBindingSlotsRequired,
12728 params: (convertFn) => {
12729 const convertResult = convertFn(mapValue);
12730 const params = Array.isArray(convertResult) ? convertResult : [convertResult];
12731 return params;
12732 }
12733 }]
12734 };
12735 }
12736 _buildSingleInputs(reference, inputs, valueConverter, getInterpolationExpressionFn, isClassBased) {
12737 const instructions = [];
12738 inputs.forEach(input => {
12739 const previousInstruction = instructions[instructions.length - 1];
12740 const value = input.value.visit(valueConverter);
12741 let referenceForCall = reference;
12742 // each styling binding value is stored in the LView
12743 // but there are two values stored for each binding:
12744 // 1) the value itself
12745 // 2) an intermediate value (concatenation of style up to this point).
12746 // We need to store the intermediate value so that we don't allocate
12747 // the strings on each CD.
12748 let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
12749 if (value instanceof Interpolation) {
12750 totalBindingSlotsRequired += value.expressions.length;
12751 if (getInterpolationExpressionFn) {
12752 referenceForCall = getInterpolationExpressionFn(value);
12753 }
12754 }
12755 const call = {
12756 sourceSpan: input.sourceSpan,
12757 allocateBindingSlots: totalBindingSlotsRequired,
12758 supportsInterpolation: !!getInterpolationExpressionFn,
12759 params: (convertFn) => {
12760 // params => stylingProp(propName, value, suffix)
12761 const params = [];
12762 params.push(literal(input.name));
12763 const convertResult = convertFn(value);
12764 if (Array.isArray(convertResult)) {
12765 params.push(...convertResult);
12766 }
12767 else {
12768 params.push(convertResult);
12769 }
12770 // [style.prop] bindings may use suffix values (e.g. px, em, etc...), therefore,
12771 // if that is detected then we need to pass that in as an optional param.
12772 if (!isClassBased && input.suffix !== null) {
12773 params.push(literal(input.suffix));
12774 }
12775 return params;
12776 }
12777 };
12778 // If we ended up generating a call to the same instruction as the previous styling property
12779 // we can chain the calls together safely to save some bytes, otherwise we have to generate
12780 // a separate instruction call. This is primarily a concern with interpolation instructions
12781 // where we may start off with one `reference`, but end up using another based on the
12782 // number of interpolations.
12783 if (previousInstruction && previousInstruction.reference === referenceForCall) {
12784 previousInstruction.calls.push(call);
12785 }
12786 else {
12787 instructions.push({ reference: referenceForCall, calls: [call] });
12788 }
12789 });
12790 return instructions;
12791 }
12792 _buildClassInputs(valueConverter) {
12793 if (this._singleClassInputs) {
12794 return this._buildSingleInputs(Identifiers$1.classProp, this._singleClassInputs, valueConverter, null, true);
12795 }
12796 return [];
12797 }
12798 _buildStyleInputs(valueConverter) {
12799 if (this._singleStyleInputs) {
12800 return this._buildSingleInputs(Identifiers$1.styleProp, this._singleStyleInputs, valueConverter, getStylePropInterpolationExpression, false);
12801 }
12802 return [];
12803 }
12804 /**
12805 * Constructs all instructions which contain the expressions that will be placed
12806 * into the update block of a template function or a directive hostBindings function.
12807 */
12808 buildUpdateLevelInstructions(valueConverter) {
12809 const instructions = [];
12810 if (this.hasBindings) {
12811 const styleMapInstruction = this.buildStyleMapInstruction(valueConverter);
12812 if (styleMapInstruction) {
12813 instructions.push(styleMapInstruction);
12814 }
12815 const classMapInstruction = this.buildClassMapInstruction(valueConverter);
12816 if (classMapInstruction) {
12817 instructions.push(classMapInstruction);
12818 }
12819 instructions.push(...this._buildStyleInputs(valueConverter));
12820 instructions.push(...this._buildClassInputs(valueConverter));
12821 }
12822 return instructions;
12823 }
12824 }
12825 function registerIntoMap(map, key) {
12826 if (!map.has(key)) {
12827 map.set(key, map.size);
12828 }
12829 }
12830 function parseProperty(name) {
12831 let hasOverrideFlag = false;
12832 const overrideIndex = name.indexOf(IMPORTANT_FLAG);
12833 if (overrideIndex !== -1) {
12834 name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
12835 hasOverrideFlag = true;
12836 }
12837 let suffix = null;
12838 let property = name;
12839 const unitIndex = name.lastIndexOf('.');
12840 if (unitIndex > 0) {
12841 suffix = name.substr(unitIndex + 1);
12842 property = name.substring(0, unitIndex);
12843 }
12844 return { property, suffix, hasOverrideFlag };
12845 }
12846 /**
12847 * Gets the instruction to generate for an interpolated class map.
12848 * @param interpolation An Interpolation AST
12849 */
12850 function getClassMapInterpolationExpression(interpolation) {
12851 switch (getInterpolationArgsLength(interpolation)) {
12852 case 1:
12853 return Identifiers$1.classMap;
12854 case 3:
12855 return Identifiers$1.classMapInterpolate1;
12856 case 5:
12857 return Identifiers$1.classMapInterpolate2;
12858 case 7:
12859 return Identifiers$1.classMapInterpolate3;
12860 case 9:
12861 return Identifiers$1.classMapInterpolate4;
12862 case 11:
12863 return Identifiers$1.classMapInterpolate5;
12864 case 13:
12865 return Identifiers$1.classMapInterpolate6;
12866 case 15:
12867 return Identifiers$1.classMapInterpolate7;
12868 case 17:
12869 return Identifiers$1.classMapInterpolate8;
12870 default:
12871 return Identifiers$1.classMapInterpolateV;
12872 }
12873 }
12874 /**
12875 * Gets the instruction to generate for an interpolated style map.
12876 * @param interpolation An Interpolation AST
12877 */
12878 function getStyleMapInterpolationExpression(interpolation) {
12879 switch (getInterpolationArgsLength(interpolation)) {
12880 case 1:
12881 return Identifiers$1.styleMap;
12882 case 3:
12883 return Identifiers$1.styleMapInterpolate1;
12884 case 5:
12885 return Identifiers$1.styleMapInterpolate2;
12886 case 7:
12887 return Identifiers$1.styleMapInterpolate3;
12888 case 9:
12889 return Identifiers$1.styleMapInterpolate4;
12890 case 11:
12891 return Identifiers$1.styleMapInterpolate5;
12892 case 13:
12893 return Identifiers$1.styleMapInterpolate6;
12894 case 15:
12895 return Identifiers$1.styleMapInterpolate7;
12896 case 17:
12897 return Identifiers$1.styleMapInterpolate8;
12898 default:
12899 return Identifiers$1.styleMapInterpolateV;
12900 }
12901 }
12902 /**
12903 * Gets the instruction to generate for an interpolated style prop.
12904 * @param interpolation An Interpolation AST
12905 */
12906 function getStylePropInterpolationExpression(interpolation) {
12907 switch (getInterpolationArgsLength(interpolation)) {
12908 case 1:
12909 return Identifiers$1.styleProp;
12910 case 3:
12911 return Identifiers$1.stylePropInterpolate1;
12912 case 5:
12913 return Identifiers$1.stylePropInterpolate2;
12914 case 7:
12915 return Identifiers$1.stylePropInterpolate3;
12916 case 9:
12917 return Identifiers$1.stylePropInterpolate4;
12918 case 11:
12919 return Identifiers$1.stylePropInterpolate5;
12920 case 13:
12921 return Identifiers$1.stylePropInterpolate6;
12922 case 15:
12923 return Identifiers$1.stylePropInterpolate7;
12924 case 17:
12925 return Identifiers$1.stylePropInterpolate8;
12926 default:
12927 return Identifiers$1.stylePropInterpolateV;
12928 }
12929 }
12930 function normalizePropName(prop) {
12931 return hyphenate(prop);
12932 }
12933
12934 /**
12935 * @license
12936 * Copyright Google LLC All Rights Reserved.
12937 *
12938 * Use of this source code is governed by an MIT-style license that can be
12939 * found in the LICENSE file at https://angular.io/license
12940 */
12941 var TokenType$1;
12942 (function (TokenType) {
12943 TokenType[TokenType["Character"] = 0] = "Character";
12944 TokenType[TokenType["Identifier"] = 1] = "Identifier";
12945 TokenType[TokenType["Keyword"] = 2] = "Keyword";
12946 TokenType[TokenType["String"] = 3] = "String";
12947 TokenType[TokenType["Operator"] = 4] = "Operator";
12948 TokenType[TokenType["Number"] = 5] = "Number";
12949 TokenType[TokenType["Error"] = 6] = "Error";
12950 })(TokenType$1 || (TokenType$1 = {}));
12951 const KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
12952 class Lexer {
12953 tokenize(text) {
12954 const scanner = new _Scanner(text);
12955 const tokens = [];
12956 let token = scanner.scanToken();
12957 while (token != null) {
12958 tokens.push(token);
12959 token = scanner.scanToken();
12960 }
12961 return tokens;
12962 }
12963 }
12964 class Token$1 {
12965 constructor(index, end, type, numValue, strValue) {
12966 this.index = index;
12967 this.end = end;
12968 this.type = type;
12969 this.numValue = numValue;
12970 this.strValue = strValue;
12971 }
12972 isCharacter(code) {
12973 return this.type == TokenType$1.Character && this.numValue == code;
12974 }
12975 isNumber() {
12976 return this.type == TokenType$1.Number;
12977 }
12978 isString() {
12979 return this.type == TokenType$1.String;
12980 }
12981 isOperator(operator) {
12982 return this.type == TokenType$1.Operator && this.strValue == operator;
12983 }
12984 isIdentifier() {
12985 return this.type == TokenType$1.Identifier;
12986 }
12987 isKeyword() {
12988 return this.type == TokenType$1.Keyword;
12989 }
12990 isKeywordLet() {
12991 return this.type == TokenType$1.Keyword && this.strValue == 'let';
12992 }
12993 isKeywordAs() {
12994 return this.type == TokenType$1.Keyword && this.strValue == 'as';
12995 }
12996 isKeywordNull() {
12997 return this.type == TokenType$1.Keyword && this.strValue == 'null';
12998 }
12999 isKeywordUndefined() {
13000 return this.type == TokenType$1.Keyword && this.strValue == 'undefined';
13001 }
13002 isKeywordTrue() {
13003 return this.type == TokenType$1.Keyword && this.strValue == 'true';
13004 }
13005 isKeywordFalse() {
13006 return this.type == TokenType$1.Keyword && this.strValue == 'false';
13007 }
13008 isKeywordThis() {
13009 return this.type == TokenType$1.Keyword && this.strValue == 'this';
13010 }
13011 isError() {
13012 return this.type == TokenType$1.Error;
13013 }
13014 toNumber() {
13015 return this.type == TokenType$1.Number ? this.numValue : -1;
13016 }
13017 toString() {
13018 switch (this.type) {
13019 case TokenType$1.Character:
13020 case TokenType$1.Identifier:
13021 case TokenType$1.Keyword:
13022 case TokenType$1.Operator:
13023 case TokenType$1.String:
13024 case TokenType$1.Error:
13025 return this.strValue;
13026 case TokenType$1.Number:
13027 return this.numValue.toString();
13028 default:
13029 return null;
13030 }
13031 }
13032 }
13033 function newCharacterToken(index, end, code) {
13034 return new Token$1(index, end, TokenType$1.Character, code, String.fromCharCode(code));
13035 }
13036 function newIdentifierToken(index, end, text) {
13037 return new Token$1(index, end, TokenType$1.Identifier, 0, text);
13038 }
13039 function newKeywordToken(index, end, text) {
13040 return new Token$1(index, end, TokenType$1.Keyword, 0, text);
13041 }
13042 function newOperatorToken(index, end, text) {
13043 return new Token$1(index, end, TokenType$1.Operator, 0, text);
13044 }
13045 function newStringToken(index, end, text) {
13046 return new Token$1(index, end, TokenType$1.String, 0, text);
13047 }
13048 function newNumberToken(index, end, n) {
13049 return new Token$1(index, end, TokenType$1.Number, n, '');
13050 }
13051 function newErrorToken(index, end, message) {
13052 return new Token$1(index, end, TokenType$1.Error, 0, message);
13053 }
13054 const EOF = new Token$1(-1, -1, TokenType$1.Character, 0, '');
13055 class _Scanner {
13056 constructor(input) {
13057 this.input = input;
13058 this.peek = 0;
13059 this.index = -1;
13060 this.length = input.length;
13061 this.advance();
13062 }
13063 advance() {
13064 this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index);
13065 }
13066 scanToken() {
13067 const input = this.input, length = this.length;
13068 let peek = this.peek, index = this.index;
13069 // Skip whitespace.
13070 while (peek <= $SPACE) {
13071 if (++index >= length) {
13072 peek = $EOF;
13073 break;
13074 }
13075 else {
13076 peek = input.charCodeAt(index);
13077 }
13078 }
13079 this.peek = peek;
13080 this.index = index;
13081 if (index >= length) {
13082 return null;
13083 }
13084 // Handle identifiers and numbers.
13085 if (isIdentifierStart(peek))
13086 return this.scanIdentifier();
13087 if (isDigit(peek))
13088 return this.scanNumber(index);
13089 const start = index;
13090 switch (peek) {
13091 case $PERIOD:
13092 this.advance();
13093 return isDigit(this.peek) ? this.scanNumber(start) :
13094 newCharacterToken(start, this.index, $PERIOD);
13095 case $LPAREN:
13096 case $RPAREN:
13097 case $LBRACE:
13098 case $RBRACE:
13099 case $LBRACKET:
13100 case $RBRACKET:
13101 case $COMMA:
13102 case $COLON:
13103 case $SEMICOLON:
13104 return this.scanCharacter(start, peek);
13105 case $SQ:
13106 case $DQ:
13107 return this.scanString();
13108 case $HASH:
13109 case $PLUS:
13110 case $MINUS:
13111 case $STAR:
13112 case $SLASH:
13113 case $PERCENT:
13114 case $CARET:
13115 return this.scanOperator(start, String.fromCharCode(peek));
13116 case $QUESTION:
13117 return this.scanComplexOperator(start, '?', $PERIOD, '.');
13118 case $LT:
13119 case $GT:
13120 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=');
13121 case $BANG:
13122 case $EQ:
13123 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=', $EQ, '=');
13124 case $AMPERSAND:
13125 return this.scanComplexOperator(start, '&', $AMPERSAND, '&');
13126 case $BAR:
13127 return this.scanComplexOperator(start, '|', $BAR, '|');
13128 case $NBSP:
13129 while (isWhitespace(this.peek))
13130 this.advance();
13131 return this.scanToken();
13132 }
13133 this.advance();
13134 return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0);
13135 }
13136 scanCharacter(start, code) {
13137 this.advance();
13138 return newCharacterToken(start, this.index, code);
13139 }
13140 scanOperator(start, str) {
13141 this.advance();
13142 return newOperatorToken(start, this.index, str);
13143 }
13144 /**
13145 * Tokenize a 2/3 char long operator
13146 *
13147 * @param start start index in the expression
13148 * @param one first symbol (always part of the operator)
13149 * @param twoCode code point for the second symbol
13150 * @param two second symbol (part of the operator when the second code point matches)
13151 * @param threeCode code point for the third symbol
13152 * @param three third symbol (part of the operator when provided and matches source expression)
13153 */
13154 scanComplexOperator(start, one, twoCode, two, threeCode, three) {
13155 this.advance();
13156 let str = one;
13157 if (this.peek == twoCode) {
13158 this.advance();
13159 str += two;
13160 }
13161 if (threeCode != null && this.peek == threeCode) {
13162 this.advance();
13163 str += three;
13164 }
13165 return newOperatorToken(start, this.index, str);
13166 }
13167 scanIdentifier() {
13168 const start = this.index;
13169 this.advance();
13170 while (isIdentifierPart(this.peek))
13171 this.advance();
13172 const str = this.input.substring(start, this.index);
13173 return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, this.index, str) :
13174 newIdentifierToken(start, this.index, str);
13175 }
13176 scanNumber(start) {
13177 let simple = (this.index === start);
13178 this.advance(); // Skip initial digit.
13179 while (true) {
13180 if (isDigit(this.peek)) ;
13181 else if (this.peek == $PERIOD) {
13182 simple = false;
13183 }
13184 else if (isExponentStart(this.peek)) {
13185 this.advance();
13186 if (isExponentSign(this.peek))
13187 this.advance();
13188 if (!isDigit(this.peek))
13189 return this.error('Invalid exponent', -1);
13190 simple = false;
13191 }
13192 else {
13193 break;
13194 }
13195 this.advance();
13196 }
13197 const str = this.input.substring(start, this.index);
13198 const value = simple ? parseIntAutoRadix(str) : parseFloat(str);
13199 return newNumberToken(start, this.index, value);
13200 }
13201 scanString() {
13202 const start = this.index;
13203 const quote = this.peek;
13204 this.advance(); // Skip initial quote.
13205 let buffer = '';
13206 let marker = this.index;
13207 const input = this.input;
13208 while (this.peek != quote) {
13209 if (this.peek == $BACKSLASH) {
13210 buffer += input.substring(marker, this.index);
13211 this.advance();
13212 let unescapedCode;
13213 // Workaround for TS2.1-introduced type strictness
13214 this.peek = this.peek;
13215 if (this.peek == $u) {
13216 // 4 character hex code for unicode character.
13217 const hex = input.substring(this.index + 1, this.index + 5);
13218 if (/^[0-9a-f]+$/i.test(hex)) {
13219 unescapedCode = parseInt(hex, 16);
13220 }
13221 else {
13222 return this.error(`Invalid unicode escape [\\u${hex}]`, 0);
13223 }
13224 for (let i = 0; i < 5; i++) {
13225 this.advance();
13226 }
13227 }
13228 else {
13229 unescapedCode = unescape(this.peek);
13230 this.advance();
13231 }
13232 buffer += String.fromCharCode(unescapedCode);
13233 marker = this.index;
13234 }
13235 else if (this.peek == $EOF) {
13236 return this.error('Unterminated quote', 0);
13237 }
13238 else {
13239 this.advance();
13240 }
13241 }
13242 const last = input.substring(marker, this.index);
13243 this.advance(); // Skip terminating quote.
13244 return newStringToken(start, this.index, buffer + last);
13245 }
13246 error(message, offset) {
13247 const position = this.index + offset;
13248 return newErrorToken(position, this.index, `Lexer Error: ${message} at column ${position} in expression [${this.input}]`);
13249 }
13250 }
13251 function isIdentifierStart(code) {
13252 return ($a <= code && code <= $z) || ($A <= code && code <= $Z) ||
13253 (code == $_) || (code == $$);
13254 }
13255 function isIdentifier(input) {
13256 if (input.length == 0)
13257 return false;
13258 const scanner = new _Scanner(input);
13259 if (!isIdentifierStart(scanner.peek))
13260 return false;
13261 scanner.advance();
13262 while (scanner.peek !== $EOF) {
13263 if (!isIdentifierPart(scanner.peek))
13264 return false;
13265 scanner.advance();
13266 }
13267 return true;
13268 }
13269 function isIdentifierPart(code) {
13270 return isAsciiLetter(code) || isDigit(code) || (code == $_) ||
13271 (code == $$);
13272 }
13273 function isExponentStart(code) {
13274 return code == $e || code == $E;
13275 }
13276 function isExponentSign(code) {
13277 return code == $MINUS || code == $PLUS;
13278 }
13279 function isQuote(code) {
13280 return code === $SQ || code === $DQ || code === $BT;
13281 }
13282 function unescape(code) {
13283 switch (code) {
13284 case $n:
13285 return $LF;
13286 case $f:
13287 return $FF;
13288 case $r:
13289 return $CR;
13290 case $t:
13291 return $TAB;
13292 case $v:
13293 return $VTAB;
13294 default:
13295 return code;
13296 }
13297 }
13298 function parseIntAutoRadix(text) {
13299 const result = parseInt(text);
13300 if (isNaN(result)) {
13301 throw new Error('Invalid integer literal when parsing ' + text);
13302 }
13303 return result;
13304 }
13305
13306 /**
13307 * @license
13308 * Copyright Google LLC All Rights Reserved.
13309 *
13310 * Use of this source code is governed by an MIT-style license that can be
13311 * found in the LICENSE file at https://angular.io/license
13312 */
13313 class SplitInterpolation {
13314 constructor(strings, expressions, offsets) {
13315 this.strings = strings;
13316 this.expressions = expressions;
13317 this.offsets = offsets;
13318 }
13319 }
13320 class TemplateBindingParseResult {
13321 constructor(templateBindings, warnings, errors) {
13322 this.templateBindings = templateBindings;
13323 this.warnings = warnings;
13324 this.errors = errors;
13325 }
13326 }
13327 class Parser$1 {
13328 constructor(_lexer) {
13329 this._lexer = _lexer;
13330 this.errors = [];
13331 this.simpleExpressionChecker = SimpleExpressionChecker;
13332 }
13333 parseAction(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13334 this._checkNoInterpolation(input, location, interpolationConfig);
13335 const sourceToLex = this._stripComments(input);
13336 const tokens = this._lexer.tokenize(this._stripComments(input));
13337 const ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, true, this.errors, input.length - sourceToLex.length)
13338 .parseChain();
13339 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
13340 }
13341 parseBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13342 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
13343 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
13344 }
13345 checkSimpleExpression(ast) {
13346 const checker = new this.simpleExpressionChecker();
13347 ast.visit(checker);
13348 return checker.errors;
13349 }
13350 parseSimpleBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13351 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
13352 const errors = this.checkSimpleExpression(ast);
13353 if (errors.length > 0) {
13354 this._reportError(`Host binding expression cannot contain ${errors.join(' ')}`, input, location);
13355 }
13356 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
13357 }
13358 _reportError(message, input, errLocation, ctxLocation) {
13359 this.errors.push(new ParserError(message, input, errLocation, ctxLocation));
13360 }
13361 _parseBindingAst(input, location, absoluteOffset, interpolationConfig) {
13362 // Quotes expressions use 3rd-party expression language. We don't want to use
13363 // our lexer or parser for that, so we check for that ahead of time.
13364 const quote = this._parseQuote(input, location, absoluteOffset);
13365 if (quote != null) {
13366 return quote;
13367 }
13368 this._checkNoInterpolation(input, location, interpolationConfig);
13369 const sourceToLex = this._stripComments(input);
13370 const tokens = this._lexer.tokenize(sourceToLex);
13371 return new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, input.length - sourceToLex.length)
13372 .parseChain();
13373 }
13374 _parseQuote(input, location, absoluteOffset) {
13375 if (input == null)
13376 return null;
13377 const prefixSeparatorIndex = input.indexOf(':');
13378 if (prefixSeparatorIndex == -1)
13379 return null;
13380 const prefix = input.substring(0, prefixSeparatorIndex).trim();
13381 if (!isIdentifier(prefix))
13382 return null;
13383 const uninterpretedExpression = input.substring(prefixSeparatorIndex + 1);
13384 const span = new ParseSpan(0, input.length);
13385 return new Quote(span, span.toAbsolute(absoluteOffset), prefix, uninterpretedExpression, location);
13386 }
13387 /**
13388 * Parse microsyntax template expression and return a list of bindings or
13389 * parsing errors in case the given expression is invalid.
13390 *
13391 * For example,
13392 * ```
13393 * <div *ngFor="let item of items">
13394 * ^ ^ absoluteValueOffset for `templateValue`
13395 * absoluteKeyOffset for `templateKey`
13396 * ```
13397 * contains three bindings:
13398 * 1. ngFor -> null
13399 * 2. item -> NgForOfContext.$implicit
13400 * 3. ngForOf -> items
13401 *
13402 * This is apparent from the de-sugared template:
13403 * ```
13404 * <ng-template ngFor let-item [ngForOf]="items">
13405 * ```
13406 *
13407 * @param templateKey name of directive, without the * prefix. For example: ngIf, ngFor
13408 * @param templateValue RHS of the microsyntax attribute
13409 * @param templateUrl template filename if it's external, component filename if it's inline
13410 * @param absoluteKeyOffset start of the `templateKey`
13411 * @param absoluteValueOffset start of the `templateValue`
13412 */
13413 parseTemplateBindings(templateKey, templateValue, templateUrl, absoluteKeyOffset, absoluteValueOffset) {
13414 const tokens = this._lexer.tokenize(templateValue);
13415 const parser = new _ParseAST(templateValue, templateUrl, absoluteValueOffset, tokens, templateValue.length, false /* parseAction */, this.errors, 0 /* relative offset */);
13416 return parser.parseTemplateBindings({
13417 source: templateKey,
13418 span: new AbsoluteSourceSpan(absoluteKeyOffset, absoluteKeyOffset + templateKey.length),
13419 });
13420 }
13421 parseInterpolation(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13422 const { strings, expressions, offsets } = this.splitInterpolation(input, location, interpolationConfig);
13423 if (expressions.length === 0)
13424 return null;
13425 const expressionNodes = [];
13426 for (let i = 0; i < expressions.length; ++i) {
13427 const expressionText = expressions[i].text;
13428 const sourceToLex = this._stripComments(expressionText);
13429 const tokens = this._lexer.tokenize(sourceToLex);
13430 const ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, offsets[i] + (expressionText.length - sourceToLex.length))
13431 .parseChain();
13432 expressionNodes.push(ast);
13433 }
13434 return this.createInterpolationAst(strings.map(s => s.text), expressionNodes, input, location, absoluteOffset);
13435 }
13436 /**
13437 * Similar to `parseInterpolation`, but treats the provided string as a single expression
13438 * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
13439 * This is used for parsing the switch expression in ICUs.
13440 */
13441 parseInterpolationExpression(expression, location, absoluteOffset) {
13442 const sourceToLex = this._stripComments(expression);
13443 const tokens = this._lexer.tokenize(sourceToLex);
13444 const ast = new _ParseAST(expression, location, absoluteOffset, tokens, sourceToLex.length,
13445 /* parseAction */ false, this.errors, 0)
13446 .parseChain();
13447 const strings = ['', '']; // The prefix and suffix strings are both empty
13448 return this.createInterpolationAst(strings, [ast], expression, location, absoluteOffset);
13449 }
13450 createInterpolationAst(strings, expressions, input, location, absoluteOffset) {
13451 const span = new ParseSpan(0, input.length);
13452 const interpolation = new Interpolation(span, span.toAbsolute(absoluteOffset), strings, expressions);
13453 return new ASTWithSource(interpolation, input, location, absoluteOffset, this.errors);
13454 }
13455 /**
13456 * Splits a string of text into "raw" text segments and expressions present in interpolations in
13457 * the string.
13458 * Returns `null` if there are no interpolations, otherwise a
13459 * `SplitInterpolation` with splits that look like
13460 * <raw text> <expression> <raw text> ... <raw text> <expression> <raw text>
13461 */
13462 splitInterpolation(input, location, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13463 const strings = [];
13464 const expressions = [];
13465 const offsets = [];
13466 let i = 0;
13467 let atInterpolation = false;
13468 let extendLastString = false;
13469 let { start: interpStart, end: interpEnd } = interpolationConfig;
13470 while (i < input.length) {
13471 if (!atInterpolation) {
13472 // parse until starting {{
13473 const start = i;
13474 i = input.indexOf(interpStart, i);
13475 if (i === -1) {
13476 i = input.length;
13477 }
13478 const text = input.substring(start, i);
13479 strings.push({ text, start, end: i });
13480 atInterpolation = true;
13481 }
13482 else {
13483 // parse from starting {{ to ending }} while ignoring content inside quotes.
13484 const fullStart = i;
13485 const exprStart = fullStart + interpStart.length;
13486 const exprEnd = this._getInterpolationEndIndex(input, interpEnd, exprStart);
13487 if (exprEnd === -1) {
13488 // Could not find the end of the interpolation; do not parse an expression.
13489 // Instead we should extend the content on the last raw string.
13490 atInterpolation = false;
13491 extendLastString = true;
13492 break;
13493 }
13494 const fullEnd = exprEnd + interpEnd.length;
13495 const text = input.substring(exprStart, exprEnd);
13496 if (text.trim().length === 0) {
13497 this._reportError('Blank expressions are not allowed in interpolated strings', input, `at column ${i} in`, location);
13498 }
13499 expressions.push({ text, start: fullStart, end: fullEnd });
13500 offsets.push(exprStart);
13501 i = fullEnd;
13502 atInterpolation = false;
13503 }
13504 }
13505 if (!atInterpolation) {
13506 // If we are now at a text section, add the remaining content as a raw string.
13507 if (extendLastString) {
13508 const piece = strings[strings.length - 1];
13509 piece.text += input.substring(i);
13510 piece.end = input.length;
13511 }
13512 else {
13513 strings.push({ text: input.substring(i), start: i, end: input.length });
13514 }
13515 }
13516 return new SplitInterpolation(strings, expressions, offsets);
13517 }
13518 wrapLiteralPrimitive(input, location, absoluteOffset) {
13519 const span = new ParseSpan(0, input == null ? 0 : input.length);
13520 return new ASTWithSource(new LiteralPrimitive(span, span.toAbsolute(absoluteOffset), input), input, location, absoluteOffset, this.errors);
13521 }
13522 _stripComments(input) {
13523 const i = this._commentStart(input);
13524 return i != null ? input.substring(0, i).trim() : input;
13525 }
13526 _commentStart(input) {
13527 let outerQuote = null;
13528 for (let i = 0; i < input.length - 1; i++) {
13529 const char = input.charCodeAt(i);
13530 const nextChar = input.charCodeAt(i + 1);
13531 if (char === $SLASH && nextChar == $SLASH && outerQuote == null)
13532 return i;
13533 if (outerQuote === char) {
13534 outerQuote = null;
13535 }
13536 else if (outerQuote == null && isQuote(char)) {
13537 outerQuote = char;
13538 }
13539 }
13540 return null;
13541 }
13542 _checkNoInterpolation(input, location, { start, end }) {
13543 let startIndex = -1;
13544 let endIndex = -1;
13545 for (const charIndex of this._forEachUnquotedChar(input, 0)) {
13546 if (startIndex === -1) {
13547 if (input.startsWith(start)) {
13548 startIndex = charIndex;
13549 }
13550 }
13551 else {
13552 endIndex = this._getInterpolationEndIndex(input, end, charIndex);
13553 if (endIndex > -1) {
13554 break;
13555 }
13556 }
13557 }
13558 if (startIndex > -1 && endIndex > -1) {
13559 this._reportError(`Got interpolation (${start}${end}) where expression was expected`, input, `at column ${startIndex} in`, location);
13560 }
13561 }
13562 /**
13563 * Finds the index of the end of an interpolation expression
13564 * while ignoring comments and quoted content.
13565 */
13566 _getInterpolationEndIndex(input, expressionEnd, start) {
13567 for (const charIndex of this._forEachUnquotedChar(input, start)) {
13568 if (input.startsWith(expressionEnd, charIndex)) {
13569 return charIndex;
13570 }
13571 // Nothing else in the expression matters after we've
13572 // hit a comment so look directly for the end token.
13573 if (input.startsWith('//', charIndex)) {
13574 return input.indexOf(expressionEnd, charIndex);
13575 }
13576 }
13577 return -1;
13578 }
13579 /**
13580 * Generator used to iterate over the character indexes of a string that are outside of quotes.
13581 * @param input String to loop through.
13582 * @param start Index within the string at which to start.
13583 */
13584 *_forEachUnquotedChar(input, start) {
13585 let currentQuote = null;
13586 let escapeCount = 0;
13587 for (let i = start; i < input.length; i++) {
13588 const char = input[i];
13589 // Skip the characters inside quotes. Note that we only care about the outer-most
13590 // quotes matching up and we need to account for escape characters.
13591 if (isQuote(input.charCodeAt(i)) && (currentQuote === null || currentQuote === char) &&
13592 escapeCount % 2 === 0) {
13593 currentQuote = currentQuote === null ? char : null;
13594 }
13595 else if (currentQuote === null) {
13596 yield i;
13597 }
13598 escapeCount = char === '\\' ? escapeCount + 1 : 0;
13599 }
13600 }
13601 }
13602 class IvyParser extends Parser$1 {
13603 constructor() {
13604 super(...arguments);
13605 this.simpleExpressionChecker = IvySimpleExpressionChecker;
13606 }
13607 }
13608 /** Describes a stateful context an expression parser is in. */
13609 var ParseContextFlags;
13610 (function (ParseContextFlags) {
13611 ParseContextFlags[ParseContextFlags["None"] = 0] = "None";
13612 /**
13613 * A Writable context is one in which a value may be written to an lvalue.
13614 * For example, after we see a property access, we may expect a write to the
13615 * property via the "=" operator.
13616 * prop
13617 * ^ possible "=" after
13618 */
13619 ParseContextFlags[ParseContextFlags["Writable"] = 1] = "Writable";
13620 })(ParseContextFlags || (ParseContextFlags = {}));
13621 class _ParseAST {
13622 constructor(input, location, absoluteOffset, tokens, inputLength, parseAction, errors, offset) {
13623 this.input = input;
13624 this.location = location;
13625 this.absoluteOffset = absoluteOffset;
13626 this.tokens = tokens;
13627 this.inputLength = inputLength;
13628 this.parseAction = parseAction;
13629 this.errors = errors;
13630 this.offset = offset;
13631 this.rparensExpected = 0;
13632 this.rbracketsExpected = 0;
13633 this.rbracesExpected = 0;
13634 this.context = ParseContextFlags.None;
13635 // Cache of expression start and input indeces to the absolute source span they map to, used to
13636 // prevent creating superfluous source spans in `sourceSpan`.
13637 // A serial of the expression start and input index is used for mapping because both are stateful
13638 // and may change for subsequent expressions visited by the parser.
13639 this.sourceSpanCache = new Map();
13640 this.index = 0;
13641 }
13642 peek(offset) {
13643 const i = this.index + offset;
13644 return i < this.tokens.length ? this.tokens[i] : EOF;
13645 }
13646 get next() {
13647 return this.peek(0);
13648 }
13649 /** Whether all the parser input has been processed. */
13650 get atEOF() {
13651 return this.index >= this.tokens.length;
13652 }
13653 /**
13654 * Index of the next token to be processed, or the end of the last token if all have been
13655 * processed.
13656 */
13657 get inputIndex() {
13658 return this.atEOF ? this.currentEndIndex : this.next.index + this.offset;
13659 }
13660 /**
13661 * End index of the last processed token, or the start of the first token if none have been
13662 * processed.
13663 */
13664 get currentEndIndex() {
13665 if (this.index > 0) {
13666 const curToken = this.peek(-1);
13667 return curToken.end + this.offset;
13668 }
13669 // No tokens have been processed yet; return the next token's start or the length of the input
13670 // if there is no token.
13671 if (this.tokens.length === 0) {
13672 return this.inputLength + this.offset;
13673 }
13674 return this.next.index + this.offset;
13675 }
13676 /**
13677 * Returns the absolute offset of the start of the current token.
13678 */
13679 get currentAbsoluteOffset() {
13680 return this.absoluteOffset + this.inputIndex;
13681 }
13682 /**
13683 * Retrieve a `ParseSpan` from `start` to the current position (or to `artificialEndIndex` if
13684 * provided).
13685 *
13686 * @param start Position from which the `ParseSpan` will start.
13687 * @param artificialEndIndex Optional ending index to be used if provided (and if greater than the
13688 * natural ending index)
13689 */
13690 span(start, artificialEndIndex) {
13691 let endIndex = this.currentEndIndex;
13692 if (artificialEndIndex !== undefined && artificialEndIndex > this.currentEndIndex) {
13693 endIndex = artificialEndIndex;
13694 }
13695 return new ParseSpan(start, endIndex);
13696 }
13697 sourceSpan(start, artificialEndIndex) {
13698 const serial = `${start}@${this.inputIndex}:${artificialEndIndex}`;
13699 if (!this.sourceSpanCache.has(serial)) {
13700 this.sourceSpanCache.set(serial, this.span(start, artificialEndIndex).toAbsolute(this.absoluteOffset));
13701 }
13702 return this.sourceSpanCache.get(serial);
13703 }
13704 advance() {
13705 this.index++;
13706 }
13707 /**
13708 * Executes a callback in the provided context.
13709 */
13710 withContext(context, cb) {
13711 this.context |= context;
13712 const ret = cb();
13713 this.context ^= context;
13714 return ret;
13715 }
13716 consumeOptionalCharacter(code) {
13717 if (this.next.isCharacter(code)) {
13718 this.advance();
13719 return true;
13720 }
13721 else {
13722 return false;
13723 }
13724 }
13725 peekKeywordLet() {
13726 return this.next.isKeywordLet();
13727 }
13728 peekKeywordAs() {
13729 return this.next.isKeywordAs();
13730 }
13731 /**
13732 * Consumes an expected character, otherwise emits an error about the missing expected character
13733 * and skips over the token stream until reaching a recoverable point.
13734 *
13735 * See `this.error` and `this.skip` for more details.
13736 */
13737 expectCharacter(code) {
13738 if (this.consumeOptionalCharacter(code))
13739 return;
13740 this.error(`Missing expected ${String.fromCharCode(code)}`);
13741 }
13742 consumeOptionalOperator(op) {
13743 if (this.next.isOperator(op)) {
13744 this.advance();
13745 return true;
13746 }
13747 else {
13748 return false;
13749 }
13750 }
13751 expectOperator(operator) {
13752 if (this.consumeOptionalOperator(operator))
13753 return;
13754 this.error(`Missing expected operator ${operator}`);
13755 }
13756 prettyPrintToken(tok) {
13757 return tok === EOF ? 'end of input' : `token ${tok}`;
13758 }
13759 expectIdentifierOrKeyword() {
13760 const n = this.next;
13761 if (!n.isIdentifier() && !n.isKeyword()) {
13762 this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier or keyword`);
13763 return null;
13764 }
13765 this.advance();
13766 return n.toString();
13767 }
13768 expectIdentifierOrKeywordOrString() {
13769 const n = this.next;
13770 if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) {
13771 this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier, keyword, or string`);
13772 return '';
13773 }
13774 this.advance();
13775 return n.toString();
13776 }
13777 parseChain() {
13778 const exprs = [];
13779 const start = this.inputIndex;
13780 while (this.index < this.tokens.length) {
13781 const expr = this.parsePipe();
13782 exprs.push(expr);
13783 if (this.consumeOptionalCharacter($SEMICOLON)) {
13784 if (!this.parseAction) {
13785 this.error('Binding expression cannot contain chained expression');
13786 }
13787 while (this.consumeOptionalCharacter($SEMICOLON)) {
13788 } // read all semicolons
13789 }
13790 else if (this.index < this.tokens.length) {
13791 this.error(`Unexpected token '${this.next}'`);
13792 }
13793 }
13794 if (exprs.length == 0) {
13795 // We have no expressions so create an empty expression that spans the entire input length
13796 const artificialStart = this.offset;
13797 const artificialEnd = this.offset + this.inputLength;
13798 return new EmptyExpr(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd));
13799 }
13800 if (exprs.length == 1)
13801 return exprs[0];
13802 return new Chain(this.span(start), this.sourceSpan(start), exprs);
13803 }
13804 parsePipe() {
13805 const start = this.inputIndex;
13806 let result = this.parseExpression();
13807 if (this.consumeOptionalOperator('|')) {
13808 if (this.parseAction) {
13809 this.error('Cannot have a pipe in an action expression');
13810 }
13811 do {
13812 const nameStart = this.inputIndex;
13813 let nameId = this.expectIdentifierOrKeyword();
13814 let nameSpan;
13815 let fullSpanEnd = undefined;
13816 if (nameId !== null) {
13817 nameSpan = this.sourceSpan(nameStart);
13818 }
13819 else {
13820 // No valid identifier was found, so we'll assume an empty pipe name ('').
13821 nameId = '';
13822 // However, there may have been whitespace present between the pipe character and the next
13823 // token in the sequence (or the end of input). We want to track this whitespace so that
13824 // the `BindingPipe` we produce covers not just the pipe character, but any trailing
13825 // whitespace beyond it. Another way of thinking about this is that the zero-length name
13826 // is assumed to be at the end of any whitespace beyond the pipe character.
13827 //
13828 // Therefore, we push the end of the `ParseSpan` for this pipe all the way up to the
13829 // beginning of the next token, or until the end of input if the next token is EOF.
13830 fullSpanEnd = this.next.index !== -1 ? this.next.index : this.inputLength + this.offset;
13831 // The `nameSpan` for an empty pipe name is zero-length at the end of any whitespace
13832 // beyond the pipe character.
13833 nameSpan = new ParseSpan(fullSpanEnd, fullSpanEnd).toAbsolute(this.absoluteOffset);
13834 }
13835 const args = [];
13836 while (this.consumeOptionalCharacter($COLON)) {
13837 args.push(this.parseExpression());
13838 // If there are additional expressions beyond the name, then the artificial end for the
13839 // name is no longer relevant.
13840 }
13841 result = new BindingPipe(this.span(start), this.sourceSpan(start, fullSpanEnd), result, nameId, args, nameSpan);
13842 } while (this.consumeOptionalOperator('|'));
13843 }
13844 return result;
13845 }
13846 parseExpression() {
13847 return this.parseConditional();
13848 }
13849 parseConditional() {
13850 const start = this.inputIndex;
13851 const result = this.parseLogicalOr();
13852 if (this.consumeOptionalOperator('?')) {
13853 const yes = this.parsePipe();
13854 let no;
13855 if (!this.consumeOptionalCharacter($COLON)) {
13856 const end = this.inputIndex;
13857 const expression = this.input.substring(start, end);
13858 this.error(`Conditional expression ${expression} requires all 3 expressions`);
13859 no = new EmptyExpr(this.span(start), this.sourceSpan(start));
13860 }
13861 else {
13862 no = this.parsePipe();
13863 }
13864 return new Conditional(this.span(start), this.sourceSpan(start), result, yes, no);
13865 }
13866 else {
13867 return result;
13868 }
13869 }
13870 parseLogicalOr() {
13871 // '||'
13872 const start = this.inputIndex;
13873 let result = this.parseLogicalAnd();
13874 while (this.consumeOptionalOperator('||')) {
13875 const right = this.parseLogicalAnd();
13876 result = new Binary(this.span(start), this.sourceSpan(start), '||', result, right);
13877 }
13878 return result;
13879 }
13880 parseLogicalAnd() {
13881 // '&&'
13882 const start = this.inputIndex;
13883 let result = this.parseEquality();
13884 while (this.consumeOptionalOperator('&&')) {
13885 const right = this.parseEquality();
13886 result = new Binary(this.span(start), this.sourceSpan(start), '&&', result, right);
13887 }
13888 return result;
13889 }
13890 parseEquality() {
13891 // '==','!=','===','!=='
13892 const start = this.inputIndex;
13893 let result = this.parseRelational();
13894 while (this.next.type == TokenType$1.Operator) {
13895 const operator = this.next.strValue;
13896 switch (operator) {
13897 case '==':
13898 case '===':
13899 case '!=':
13900 case '!==':
13901 this.advance();
13902 const right = this.parseRelational();
13903 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13904 continue;
13905 }
13906 break;
13907 }
13908 return result;
13909 }
13910 parseRelational() {
13911 // '<', '>', '<=', '>='
13912 const start = this.inputIndex;
13913 let result = this.parseAdditive();
13914 while (this.next.type == TokenType$1.Operator) {
13915 const operator = this.next.strValue;
13916 switch (operator) {
13917 case '<':
13918 case '>':
13919 case '<=':
13920 case '>=':
13921 this.advance();
13922 const right = this.parseAdditive();
13923 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13924 continue;
13925 }
13926 break;
13927 }
13928 return result;
13929 }
13930 parseAdditive() {
13931 // '+', '-'
13932 const start = this.inputIndex;
13933 let result = this.parseMultiplicative();
13934 while (this.next.type == TokenType$1.Operator) {
13935 const operator = this.next.strValue;
13936 switch (operator) {
13937 case '+':
13938 case '-':
13939 this.advance();
13940 let right = this.parseMultiplicative();
13941 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13942 continue;
13943 }
13944 break;
13945 }
13946 return result;
13947 }
13948 parseMultiplicative() {
13949 // '*', '%', '/'
13950 const start = this.inputIndex;
13951 let result = this.parsePrefix();
13952 while (this.next.type == TokenType$1.Operator) {
13953 const operator = this.next.strValue;
13954 switch (operator) {
13955 case '*':
13956 case '%':
13957 case '/':
13958 this.advance();
13959 let right = this.parsePrefix();
13960 result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
13961 continue;
13962 }
13963 break;
13964 }
13965 return result;
13966 }
13967 parsePrefix() {
13968 if (this.next.type == TokenType$1.Operator) {
13969 const start = this.inputIndex;
13970 const operator = this.next.strValue;
13971 let result;
13972 switch (operator) {
13973 case '+':
13974 this.advance();
13975 result = this.parsePrefix();
13976 return Unary.createPlus(this.span(start), this.sourceSpan(start), result);
13977 case '-':
13978 this.advance();
13979 result = this.parsePrefix();
13980 return Unary.createMinus(this.span(start), this.sourceSpan(start), result);
13981 case '!':
13982 this.advance();
13983 result = this.parsePrefix();
13984 return new PrefixNot(this.span(start), this.sourceSpan(start), result);
13985 }
13986 }
13987 return this.parseCallChain();
13988 }
13989 parseCallChain() {
13990 const start = this.inputIndex;
13991 let result = this.parsePrimary();
13992 while (true) {
13993 if (this.consumeOptionalCharacter($PERIOD)) {
13994 result = this.parseAccessMemberOrMethodCall(result, start, false);
13995 }
13996 else if (this.consumeOptionalOperator('?.')) {
13997 result = this.parseAccessMemberOrMethodCall(result, start, true);
13998 }
13999 else if (this.consumeOptionalCharacter($LBRACKET)) {
14000 this.withContext(ParseContextFlags.Writable, () => {
14001 this.rbracketsExpected++;
14002 const key = this.parsePipe();
14003 if (key instanceof EmptyExpr) {
14004 this.error(`Key access cannot be empty`);
14005 }
14006 this.rbracketsExpected--;
14007 this.expectCharacter($RBRACKET);
14008 if (this.consumeOptionalOperator('=')) {
14009 const value = this.parseConditional();
14010 result = new KeyedWrite(this.span(start), this.sourceSpan(start), result, key, value);
14011 }
14012 else {
14013 result = new KeyedRead(this.span(start), this.sourceSpan(start), result, key);
14014 }
14015 });
14016 }
14017 else if (this.consumeOptionalCharacter($LPAREN)) {
14018 this.rparensExpected++;
14019 const args = this.parseCallArguments();
14020 this.rparensExpected--;
14021 this.expectCharacter($RPAREN);
14022 result = new FunctionCall(this.span(start), this.sourceSpan(start), result, args);
14023 }
14024 else if (this.consumeOptionalOperator('!')) {
14025 result = new NonNullAssert(this.span(start), this.sourceSpan(start), result);
14026 }
14027 else {
14028 return result;
14029 }
14030 }
14031 }
14032 parsePrimary() {
14033 const start = this.inputIndex;
14034 if (this.consumeOptionalCharacter($LPAREN)) {
14035 this.rparensExpected++;
14036 const result = this.parsePipe();
14037 this.rparensExpected--;
14038 this.expectCharacter($RPAREN);
14039 return result;
14040 }
14041 else if (this.next.isKeywordNull()) {
14042 this.advance();
14043 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), null);
14044 }
14045 else if (this.next.isKeywordUndefined()) {
14046 this.advance();
14047 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), void 0);
14048 }
14049 else if (this.next.isKeywordTrue()) {
14050 this.advance();
14051 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), true);
14052 }
14053 else if (this.next.isKeywordFalse()) {
14054 this.advance();
14055 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), false);
14056 }
14057 else if (this.next.isKeywordThis()) {
14058 this.advance();
14059 return new ThisReceiver(this.span(start), this.sourceSpan(start));
14060 }
14061 else if (this.consumeOptionalCharacter($LBRACKET)) {
14062 this.rbracketsExpected++;
14063 const elements = this.parseExpressionList($RBRACKET);
14064 this.rbracketsExpected--;
14065 this.expectCharacter($RBRACKET);
14066 return new LiteralArray(this.span(start), this.sourceSpan(start), elements);
14067 }
14068 else if (this.next.isCharacter($LBRACE)) {
14069 return this.parseLiteralMap();
14070 }
14071 else if (this.next.isIdentifier()) {
14072 return this.parseAccessMemberOrMethodCall(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false);
14073 }
14074 else if (this.next.isNumber()) {
14075 const value = this.next.toNumber();
14076 this.advance();
14077 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value);
14078 }
14079 else if (this.next.isString()) {
14080 const literalValue = this.next.toString();
14081 this.advance();
14082 return new LiteralPrimitive(this.span(start), this.sourceSpan(start), literalValue);
14083 }
14084 else if (this.index >= this.tokens.length) {
14085 this.error(`Unexpected end of expression: ${this.input}`);
14086 return new EmptyExpr(this.span(start), this.sourceSpan(start));
14087 }
14088 else {
14089 this.error(`Unexpected token ${this.next}`);
14090 return new EmptyExpr(this.span(start), this.sourceSpan(start));
14091 }
14092 }
14093 parseExpressionList(terminator) {
14094 const result = [];
14095 do {
14096 if (!this.next.isCharacter(terminator)) {
14097 result.push(this.parsePipe());
14098 }
14099 else {
14100 break;
14101 }
14102 } while (this.consumeOptionalCharacter($COMMA));
14103 return result;
14104 }
14105 parseLiteralMap() {
14106 const keys = [];
14107 const values = [];
14108 const start = this.inputIndex;
14109 this.expectCharacter($LBRACE);
14110 if (!this.consumeOptionalCharacter($RBRACE)) {
14111 this.rbracesExpected++;
14112 do {
14113 const quoted = this.next.isString();
14114 const key = this.expectIdentifierOrKeywordOrString();
14115 keys.push({ key, quoted });
14116 this.expectCharacter($COLON);
14117 values.push(this.parsePipe());
14118 } while (this.consumeOptionalCharacter($COMMA));
14119 this.rbracesExpected--;
14120 this.expectCharacter($RBRACE);
14121 }
14122 return new LiteralMap(this.span(start), this.sourceSpan(start), keys, values);
14123 }
14124 parseAccessMemberOrMethodCall(receiver, start, isSafe = false) {
14125 const nameStart = this.inputIndex;
14126 const id = this.withContext(ParseContextFlags.Writable, () => {
14127 var _a;
14128 const id = (_a = this.expectIdentifierOrKeyword()) !== null && _a !== void 0 ? _a : '';
14129 if (id.length === 0) {
14130 this.error(`Expected identifier for property access`, receiver.span.end);
14131 }
14132 return id;
14133 });
14134 const nameSpan = this.sourceSpan(nameStart);
14135 if (this.consumeOptionalCharacter($LPAREN)) {
14136 this.rparensExpected++;
14137 const args = this.parseCallArguments();
14138 this.expectCharacter($RPAREN);
14139 this.rparensExpected--;
14140 const span = this.span(start);
14141 const sourceSpan = this.sourceSpan(start);
14142 return isSafe ? new SafeMethodCall(span, sourceSpan, nameSpan, receiver, id, args) :
14143 new MethodCall(span, sourceSpan, nameSpan, receiver, id, args);
14144 }
14145 else {
14146 if (isSafe) {
14147 if (this.consumeOptionalOperator('=')) {
14148 this.error('The \'?.\' operator cannot be used in the assignment');
14149 return new EmptyExpr(this.span(start), this.sourceSpan(start));
14150 }
14151 else {
14152 return new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
14153 }
14154 }
14155 else {
14156 if (this.consumeOptionalOperator('=')) {
14157 if (!this.parseAction) {
14158 this.error('Bindings cannot contain assignments');
14159 return new EmptyExpr(this.span(start), this.sourceSpan(start));
14160 }
14161 const value = this.parseConditional();
14162 return new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, receiver, id, value);
14163 }
14164 else {
14165 return new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
14166 }
14167 }
14168 }
14169 }
14170 parseCallArguments() {
14171 if (this.next.isCharacter($RPAREN))
14172 return [];
14173 const positionals = [];
14174 do {
14175 positionals.push(this.parsePipe());
14176 } while (this.consumeOptionalCharacter($COMMA));
14177 return positionals;
14178 }
14179 /**
14180 * Parses an identifier, a keyword, a string with an optional `-` in between,
14181 * and returns the string along with its absolute source span.
14182 */
14183 expectTemplateBindingKey() {
14184 let result = '';
14185 let operatorFound = false;
14186 const start = this.currentAbsoluteOffset;
14187 do {
14188 result += this.expectIdentifierOrKeywordOrString();
14189 operatorFound = this.consumeOptionalOperator('-');
14190 if (operatorFound) {
14191 result += '-';
14192 }
14193 } while (operatorFound);
14194 return {
14195 source: result,
14196 span: new AbsoluteSourceSpan(start, start + result.length),
14197 };
14198 }
14199 /**
14200 * Parse microsyntax template expression and return a list of bindings or
14201 * parsing errors in case the given expression is invalid.
14202 *
14203 * For example,
14204 * ```
14205 * <div *ngFor="let item of items; index as i; trackBy: func">
14206 * ```
14207 * contains five bindings:
14208 * 1. ngFor -> null
14209 * 2. item -> NgForOfContext.$implicit
14210 * 3. ngForOf -> items
14211 * 4. i -> NgForOfContext.index
14212 * 5. ngForTrackBy -> func
14213 *
14214 * For a full description of the microsyntax grammar, see
14215 * https://gist.github.com/mhevery/d3530294cff2e4a1b3fe15ff75d08855
14216 *
14217 * @param templateKey name of the microsyntax directive, like ngIf, ngFor,
14218 * without the *, along with its absolute span.
14219 */
14220 parseTemplateBindings(templateKey) {
14221 const bindings = [];
14222 // The first binding is for the template key itself
14223 // In *ngFor="let item of items", key = "ngFor", value = null
14224 // In *ngIf="cond | pipe", key = "ngIf", value = "cond | pipe"
14225 bindings.push(...this.parseDirectiveKeywordBindings(templateKey));
14226 while (this.index < this.tokens.length) {
14227 // If it starts with 'let', then this must be variable declaration
14228 const letBinding = this.parseLetBinding();
14229 if (letBinding) {
14230 bindings.push(letBinding);
14231 }
14232 else {
14233 // Two possible cases here, either `value "as" key` or
14234 // "directive-keyword expression". We don't know which case, but both
14235 // "value" and "directive-keyword" are template binding key, so consume
14236 // the key first.
14237 const key = this.expectTemplateBindingKey();
14238 // Peek at the next token, if it is "as" then this must be variable
14239 // declaration.
14240 const binding = this.parseAsBinding(key);
14241 if (binding) {
14242 bindings.push(binding);
14243 }
14244 else {
14245 // Otherwise the key must be a directive keyword, like "of". Transform
14246 // the key to actual key. Eg. of -> ngForOf, trackBy -> ngForTrackBy
14247 key.source =
14248 templateKey.source + key.source.charAt(0).toUpperCase() + key.source.substring(1);
14249 bindings.push(...this.parseDirectiveKeywordBindings(key));
14250 }
14251 }
14252 this.consumeStatementTerminator();
14253 }
14254 return new TemplateBindingParseResult(bindings, [] /* warnings */, this.errors);
14255 }
14256 /**
14257 * Parse a directive keyword, followed by a mandatory expression.
14258 * For example, "of items", "trackBy: func".
14259 * The bindings are: ngForOf -> items, ngForTrackBy -> func
14260 * There could be an optional "as" binding that follows the expression.
14261 * For example,
14262 * ```
14263 * *ngFor="let item of items | slice:0:1 as collection".
14264 * ^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
14265 * keyword bound target optional 'as' binding
14266 * ```
14267 *
14268 * @param key binding key, for example, ngFor, ngIf, ngForOf, along with its
14269 * absolute span.
14270 */
14271 parseDirectiveKeywordBindings(key) {
14272 const bindings = [];
14273 this.consumeOptionalCharacter($COLON); // trackBy: trackByFunction
14274 const value = this.getDirectiveBoundTarget();
14275 let spanEnd = this.currentAbsoluteOffset;
14276 // The binding could optionally be followed by "as". For example,
14277 // *ngIf="cond | pipe as x". In this case, the key in the "as" binding
14278 // is "x" and the value is the template key itself ("ngIf"). Note that the
14279 // 'key' in the current context now becomes the "value" in the next binding.
14280 const asBinding = this.parseAsBinding(key);
14281 if (!asBinding) {
14282 this.consumeStatementTerminator();
14283 spanEnd = this.currentAbsoluteOffset;
14284 }
14285 const sourceSpan = new AbsoluteSourceSpan(key.span.start, spanEnd);
14286 bindings.push(new ExpressionBinding(sourceSpan, key, value));
14287 if (asBinding) {
14288 bindings.push(asBinding);
14289 }
14290 return bindings;
14291 }
14292 /**
14293 * Return the expression AST for the bound target of a directive keyword
14294 * binding. For example,
14295 * ```
14296 * *ngIf="condition | pipe"
14297 * ^^^^^^^^^^^^^^^^ bound target for "ngIf"
14298 * *ngFor="let item of items"
14299 * ^^^^^ bound target for "ngForOf"
14300 * ```
14301 */
14302 getDirectiveBoundTarget() {
14303 if (this.next === EOF || this.peekKeywordAs() || this.peekKeywordLet()) {
14304 return null;
14305 }
14306 const ast = this.parsePipe(); // example: "condition | async"
14307 const { start, end } = ast.span;
14308 const value = this.input.substring(start, end);
14309 return new ASTWithSource(ast, value, this.location, this.absoluteOffset + start, this.errors);
14310 }
14311 /**
14312 * Return the binding for a variable declared using `as`. Note that the order
14313 * of the key-value pair in this declaration is reversed. For example,
14314 * ```
14315 * *ngFor="let item of items; index as i"
14316 * ^^^^^ ^
14317 * value key
14318 * ```
14319 *
14320 * @param value name of the value in the declaration, "ngIf" in the example
14321 * above, along with its absolute span.
14322 */
14323 parseAsBinding(value) {
14324 if (!this.peekKeywordAs()) {
14325 return null;
14326 }
14327 this.advance(); // consume the 'as' keyword
14328 const key = this.expectTemplateBindingKey();
14329 this.consumeStatementTerminator();
14330 const sourceSpan = new AbsoluteSourceSpan(value.span.start, this.currentAbsoluteOffset);
14331 return new VariableBinding(sourceSpan, key, value);
14332 }
14333 /**
14334 * Return the binding for a variable declared using `let`. For example,
14335 * ```
14336 * *ngFor="let item of items; let i=index;"
14337 * ^^^^^^^^ ^^^^^^^^^^^
14338 * ```
14339 * In the first binding, `item` is bound to `NgForOfContext.$implicit`.
14340 * In the second binding, `i` is bound to `NgForOfContext.index`.
14341 */
14342 parseLetBinding() {
14343 if (!this.peekKeywordLet()) {
14344 return null;
14345 }
14346 const spanStart = this.currentAbsoluteOffset;
14347 this.advance(); // consume the 'let' keyword
14348 const key = this.expectTemplateBindingKey();
14349 let value = null;
14350 if (this.consumeOptionalOperator('=')) {
14351 value = this.expectTemplateBindingKey();
14352 }
14353 this.consumeStatementTerminator();
14354 const sourceSpan = new AbsoluteSourceSpan(spanStart, this.currentAbsoluteOffset);
14355 return new VariableBinding(sourceSpan, key, value);
14356 }
14357 /**
14358 * Consume the optional statement terminator: semicolon or comma.
14359 */
14360 consumeStatementTerminator() {
14361 this.consumeOptionalCharacter($SEMICOLON) || this.consumeOptionalCharacter($COMMA);
14362 }
14363 /**
14364 * Records an error and skips over the token stream until reaching a recoverable point. See
14365 * `this.skip` for more details on token skipping.
14366 */
14367 error(message, index = null) {
14368 this.errors.push(new ParserError(message, this.input, this.locationText(index), this.location));
14369 this.skip();
14370 }
14371 locationText(index = null) {
14372 if (index == null)
14373 index = this.index;
14374 return (index < this.tokens.length) ? `at column ${this.tokens[index].index + 1} in` :
14375 `at the end of the expression`;
14376 }
14377 /**
14378 * Error recovery should skip tokens until it encounters a recovery point.
14379 *
14380 * The following are treated as unconditional recovery points:
14381 * - end of input
14382 * - ';' (parseChain() is always the root production, and it expects a ';')
14383 * - '|' (since pipes may be chained and each pipe expression may be treated independently)
14384 *
14385 * The following are conditional recovery points:
14386 * - ')', '}', ']' if one of calling productions is expecting one of these symbols
14387 * - This allows skip() to recover from errors such as '(a.) + 1' allowing more of the AST to
14388 * be retained (it doesn't skip any tokens as the ')' is retained because of the '(' begins
14389 * an '(' <expr> ')' production).
14390 * The recovery points of grouping symbols must be conditional as they must be skipped if
14391 * none of the calling productions are not expecting the closing token else we will never
14392 * make progress in the case of an extraneous group closing symbol (such as a stray ')').
14393 * That is, we skip a closing symbol if we are not in a grouping production.
14394 * - '=' in a `Writable` context
14395 * - In this context, we are able to recover after seeing the `=` operator, which
14396 * signals the presence of an independent rvalue expression following the `=` operator.
14397 *
14398 * If a production expects one of these token it increments the corresponding nesting count,
14399 * and then decrements it just prior to checking if the token is in the input.
14400 */
14401 skip() {
14402 let n = this.next;
14403 while (this.index < this.tokens.length && !n.isCharacter($SEMICOLON) &&
14404 !n.isOperator('|') && (this.rparensExpected <= 0 || !n.isCharacter($RPAREN)) &&
14405 (this.rbracesExpected <= 0 || !n.isCharacter($RBRACE)) &&
14406 (this.rbracketsExpected <= 0 || !n.isCharacter($RBRACKET)) &&
14407 (!(this.context & ParseContextFlags.Writable) || !n.isOperator('='))) {
14408 if (this.next.isError()) {
14409 this.errors.push(new ParserError(this.next.toString(), this.input, this.locationText(), this.location));
14410 }
14411 this.advance();
14412 n = this.next;
14413 }
14414 }
14415 }
14416 class SimpleExpressionChecker {
14417 constructor() {
14418 this.errors = [];
14419 }
14420 visitImplicitReceiver(ast, context) { }
14421 visitThisReceiver(ast, context) { }
14422 visitInterpolation(ast, context) { }
14423 visitLiteralPrimitive(ast, context) { }
14424 visitPropertyRead(ast, context) { }
14425 visitPropertyWrite(ast, context) { }
14426 visitSafePropertyRead(ast, context) { }
14427 visitMethodCall(ast, context) { }
14428 visitSafeMethodCall(ast, context) { }
14429 visitFunctionCall(ast, context) { }
14430 visitLiteralArray(ast, context) {
14431 this.visitAll(ast.expressions, context);
14432 }
14433 visitLiteralMap(ast, context) {
14434 this.visitAll(ast.values, context);
14435 }
14436 visitUnary(ast, context) { }
14437 visitBinary(ast, context) { }
14438 visitPrefixNot(ast, context) { }
14439 visitNonNullAssert(ast, context) { }
14440 visitConditional(ast, context) { }
14441 visitPipe(ast, context) {
14442 this.errors.push('pipes');
14443 }
14444 visitKeyedRead(ast, context) { }
14445 visitKeyedWrite(ast, context) { }
14446 visitAll(asts, context) {
14447 return asts.map(node => node.visit(this, context));
14448 }
14449 visitChain(ast, context) { }
14450 visitQuote(ast, context) { }
14451 }
14452 /**
14453 * This class implements SimpleExpressionChecker used in View Engine and performs more strict checks
14454 * to make sure host bindings do not contain pipes. In View Engine, having pipes in host bindings is
14455 * not supported as well, but in some cases (like `!(value | async)`) the error is not triggered at
14456 * compile time. In order to preserve View Engine behavior, more strict checks are introduced for
14457 * Ivy mode only.
14458 */
14459 class IvySimpleExpressionChecker extends RecursiveAstVisitor {
14460 constructor() {
14461 super(...arguments);
14462 this.errors = [];
14463 }
14464 visitPipe() {
14465 this.errors.push('pipes');
14466 }
14467 }
14468
14469 /**
14470 * @license
14471 * Copyright Google LLC All Rights Reserved.
14472 *
14473 * Use of this source code is governed by an MIT-style license that can be
14474 * found in the LICENSE file at https://angular.io/license
14475 */
14476 // =================================================================================================
14477 // =================================================================================================
14478 // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
14479 // =================================================================================================
14480 // =================================================================================================
14481 //
14482 // DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
14483 // Reach out to mprobst for details.
14484 //
14485 // =================================================================================================
14486 /** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */
14487 let _SECURITY_SCHEMA;
14488 function SECURITY_SCHEMA() {
14489 if (!_SECURITY_SCHEMA) {
14490 _SECURITY_SCHEMA = {};
14491 // Case is insignificant below, all element and attribute names are lower-cased for lookup.
14492 registerContext(SecurityContext.HTML, [
14493 'iframe|srcdoc',
14494 '*|innerHTML',
14495 '*|outerHTML',
14496 ]);
14497 registerContext(SecurityContext.STYLE, ['*|style']);
14498 // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
14499 registerContext(SecurityContext.URL, [
14500 '*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href',
14501 'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action',
14502 'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite',
14503 'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src',
14504 ]);
14505 registerContext(SecurityContext.RESOURCE_URL, [
14506 'applet|code',
14507 'applet|codebase',
14508 'base|href',
14509 'embed|src',
14510 'frame|src',
14511 'head|profile',
14512 'html|manifest',
14513 'iframe|src',
14514 'link|href',
14515 'media|src',
14516 'object|codebase',
14517 'object|data',
14518 'script|src',
14519 ]);
14520 }
14521 return _SECURITY_SCHEMA;
14522 }
14523 function registerContext(ctx, specs) {
14524 for (const spec of specs)
14525 _SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
14526 }
14527
14528 /**
14529 * @license
14530 * Copyright Google LLC All Rights Reserved.
14531 *
14532 * Use of this source code is governed by an MIT-style license that can be
14533 * found in the LICENSE file at https://angular.io/license
14534 */
14535 class ElementSchemaRegistry {
14536 }
14537
14538 /**
14539 * @license
14540 * Copyright Google LLC All Rights Reserved.
14541 *
14542 * Use of this source code is governed by an MIT-style license that can be
14543 * found in the LICENSE file at https://angular.io/license
14544 */
14545 const BOOLEAN = 'boolean';
14546 const NUMBER = 'number';
14547 const STRING = 'string';
14548 const OBJECT = 'object';
14549 /**
14550 * This array represents the DOM schema. It encodes inheritance, properties, and events.
14551 *
14552 * ## Overview
14553 *
14554 * Each line represents one kind of element. The `element_inheritance` and properties are joined
14555 * using `element_inheritance|properties` syntax.
14556 *
14557 * ## Element Inheritance
14558 *
14559 * The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
14560 * Here the individual elements are separated by `,` (commas). Every element in the list
14561 * has identical properties.
14562 *
14563 * An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
14564 * specified then `""` (blank) element is assumed.
14565 *
14566 * NOTE: The blank element inherits from root `[Element]` element, the super element of all
14567 * elements.
14568 *
14569 * NOTE an element prefix such as `:svg:` has no special meaning to the schema.
14570 *
14571 * ## Properties
14572 *
14573 * Each element has a set of properties separated by `,` (commas). Each property can be prefixed
14574 * by a special character designating its type:
14575 *
14576 * - (no prefix): property is a string.
14577 * - `*`: property represents an event.
14578 * - `!`: property is a boolean.
14579 * - `#`: property is a number.
14580 * - `%`: property is an object.
14581 *
14582 * ## Query
14583 *
14584 * The class creates an internal squas representation which allows to easily answer the query of
14585 * if a given property exist on a given element.
14586 *
14587 * NOTE: We don't yet support querying for types or events.
14588 * NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder,
14589 * see dom_element_schema_registry_spec.ts
14590 */
14591 // =================================================================================================
14592 // =================================================================================================
14593 // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
14594 // =================================================================================================
14595 // =================================================================================================
14596 //
14597 // DO NOT EDIT THIS DOM SCHEMA WITHOUT A SECURITY REVIEW!
14598 //
14599 // Newly added properties must be security reviewed and assigned an appropriate SecurityContext in
14600 // dom_security_schema.ts. Reach out to mprobst & rjamet for details.
14601 //
14602 // =================================================================================================
14603 const SCHEMA = [
14604 '[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop,slot' +
14605 /* added manually to avoid breaking changes */
14606 ',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored',
14607 '[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',
14608 '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',
14609 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume',
14610 ':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',
14611 ':svg:graphics^:svg:|',
14612 ':svg:animation^:svg:|*begin,*end,*repeat',
14613 ':svg:geometry^:svg:|',
14614 ':svg:componentTransferFunction^:svg:|',
14615 ':svg:gradient^:svg:|',
14616 ':svg:textContent^:svg:graphics|',
14617 ':svg:textPositioning^:svg:textContent|',
14618 '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',
14619 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username',
14620 'audio^media|',
14621 'br^[HTMLElement]|clear',
14622 'base^[HTMLElement]|href,target',
14623 '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',
14624 'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
14625 'canvas^[HTMLElement]|#height,#width',
14626 'content^[HTMLElement]|select',
14627 'dl^[HTMLElement]|!compact',
14628 'datalist^[HTMLElement]|',
14629 'details^[HTMLElement]|!open',
14630 'dialog^[HTMLElement]|!open,returnValue',
14631 'dir^[HTMLElement]|!compact',
14632 'div^[HTMLElement]|align',
14633 'embed^[HTMLElement]|align,height,name,src,type,width',
14634 'fieldset^[HTMLElement]|!disabled,name',
14635 'font^[HTMLElement]|color,face,size',
14636 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
14637 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
14638 'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
14639 'hr^[HTMLElement]|align,color,!noShade,size,width',
14640 'head^[HTMLElement]|',
14641 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align',
14642 'html^[HTMLElement]|version',
14643 'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width',
14644 'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width',
14645 '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',
14646 'li^[HTMLElement]|type,#value',
14647 'label^[HTMLElement]|htmlFor',
14648 'legend^[HTMLElement]|align',
14649 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type',
14650 'map^[HTMLElement]|name',
14651 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
14652 'menu^[HTMLElement]|!compact',
14653 'meta^[HTMLElement]|content,httpEquiv,name,scheme',
14654 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value',
14655 'ins,del^[HTMLElement]|cite,dateTime',
14656 'ol^[HTMLElement]|!compact,!reversed,#start,type',
14657 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
14658 'optgroup^[HTMLElement]|!disabled,label',
14659 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value',
14660 'output^[HTMLElement]|defaultValue,%htmlFor,name,value',
14661 'p^[HTMLElement]|align',
14662 'param^[HTMLElement]|name,type,value,valueType',
14663 'picture^[HTMLElement]|',
14664 'pre^[HTMLElement]|#width',
14665 'progress^[HTMLElement]|#max,#value',
14666 'q,blockquote,cite^[HTMLElement]|',
14667 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
14668 'select^[HTMLElement]|autocomplete,!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
14669 'shadow^[HTMLElement]|',
14670 'slot^[HTMLElement]|name',
14671 'source^[HTMLElement]|media,sizes,src,srcset,type',
14672 'span^[HTMLElement]|',
14673 'style^[HTMLElement]|!disabled,media,type',
14674 'caption^[HTMLElement]|align',
14675 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
14676 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width',
14677 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
14678 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign',
14679 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign',
14680 'template^[HTMLElement]|',
14681 'textarea^[HTMLElement]|autocapitalize,autocomplete,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
14682 'title^[HTMLElement]|text',
14683 'track^[HTMLElement]|!default,kind,label,src,srclang',
14684 'ul^[HTMLElement]|!compact,type',
14685 'unknown^[HTMLElement]|',
14686 'video^media|#height,poster,#width',
14687 ':svg:a^:svg:graphics|',
14688 ':svg:animate^:svg:animation|',
14689 ':svg:animateMotion^:svg:animation|',
14690 ':svg:animateTransform^:svg:animation|',
14691 ':svg:circle^:svg:geometry|',
14692 ':svg:clipPath^:svg:graphics|',
14693 ':svg:defs^:svg:graphics|',
14694 ':svg:desc^:svg:|',
14695 ':svg:discard^:svg:|',
14696 ':svg:ellipse^:svg:geometry|',
14697 ':svg:feBlend^:svg:|',
14698 ':svg:feColorMatrix^:svg:|',
14699 ':svg:feComponentTransfer^:svg:|',
14700 ':svg:feComposite^:svg:|',
14701 ':svg:feConvolveMatrix^:svg:|',
14702 ':svg:feDiffuseLighting^:svg:|',
14703 ':svg:feDisplacementMap^:svg:|',
14704 ':svg:feDistantLight^:svg:|',
14705 ':svg:feDropShadow^:svg:|',
14706 ':svg:feFlood^:svg:|',
14707 ':svg:feFuncA^:svg:componentTransferFunction|',
14708 ':svg:feFuncB^:svg:componentTransferFunction|',
14709 ':svg:feFuncG^:svg:componentTransferFunction|',
14710 ':svg:feFuncR^:svg:componentTransferFunction|',
14711 ':svg:feGaussianBlur^:svg:|',
14712 ':svg:feImage^:svg:|',
14713 ':svg:feMerge^:svg:|',
14714 ':svg:feMergeNode^:svg:|',
14715 ':svg:feMorphology^:svg:|',
14716 ':svg:feOffset^:svg:|',
14717 ':svg:fePointLight^:svg:|',
14718 ':svg:feSpecularLighting^:svg:|',
14719 ':svg:feSpotLight^:svg:|',
14720 ':svg:feTile^:svg:|',
14721 ':svg:feTurbulence^:svg:|',
14722 ':svg:filter^:svg:|',
14723 ':svg:foreignObject^:svg:graphics|',
14724 ':svg:g^:svg:graphics|',
14725 ':svg:image^:svg:graphics|',
14726 ':svg:line^:svg:geometry|',
14727 ':svg:linearGradient^:svg:gradient|',
14728 ':svg:mpath^:svg:|',
14729 ':svg:marker^:svg:|',
14730 ':svg:mask^:svg:|',
14731 ':svg:metadata^:svg:|',
14732 ':svg:path^:svg:geometry|',
14733 ':svg:pattern^:svg:|',
14734 ':svg:polygon^:svg:geometry|',
14735 ':svg:polyline^:svg:geometry|',
14736 ':svg:radialGradient^:svg:gradient|',
14737 ':svg:rect^:svg:geometry|',
14738 ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan',
14739 ':svg:script^:svg:|type',
14740 ':svg:set^:svg:animation|',
14741 ':svg:stop^:svg:|',
14742 ':svg:style^:svg:|!disabled,media,title,type',
14743 ':svg:switch^:svg:graphics|',
14744 ':svg:symbol^:svg:|',
14745 ':svg:tspan^:svg:textPositioning|',
14746 ':svg:text^:svg:textPositioning|',
14747 ':svg:textPath^:svg:textContent|',
14748 ':svg:title^:svg:|',
14749 ':svg:use^:svg:graphics|',
14750 ':svg:view^:svg:|#zoomAndPan',
14751 'data^[HTMLElement]|value',
14752 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name',
14753 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
14754 'summary^[HTMLElement]|',
14755 'time^[HTMLElement]|dateTime',
14756 ':svg:cursor^:svg:|',
14757 ];
14758 const _ATTR_TO_PROP = {
14759 'class': 'className',
14760 'for': 'htmlFor',
14761 'formaction': 'formAction',
14762 'innerHtml': 'innerHTML',
14763 'readonly': 'readOnly',
14764 'tabindex': 'tabIndex',
14765 };
14766 // Invert _ATTR_TO_PROP.
14767 const _PROP_TO_ATTR = Object.keys(_ATTR_TO_PROP).reduce((inverted, attr) => {
14768 inverted[_ATTR_TO_PROP[attr]] = attr;
14769 return inverted;
14770 }, {});
14771 class DomElementSchemaRegistry extends ElementSchemaRegistry {
14772 constructor() {
14773 super();
14774 this._schema = {};
14775 SCHEMA.forEach(encodedType => {
14776 const type = {};
14777 const [strType, strProperties] = encodedType.split('|');
14778 const properties = strProperties.split(',');
14779 const [typeNames, superName] = strType.split('^');
14780 typeNames.split(',').forEach(tag => this._schema[tag.toLowerCase()] = type);
14781 const superType = superName && this._schema[superName.toLowerCase()];
14782 if (superType) {
14783 Object.keys(superType).forEach((prop) => {
14784 type[prop] = superType[prop];
14785 });
14786 }
14787 properties.forEach((property) => {
14788 if (property.length > 0) {
14789 switch (property[0]) {
14790 case '*':
14791 // We don't yet support events.
14792 // If ever allowing to bind to events, GO THROUGH A SECURITY REVIEW, allowing events
14793 // will
14794 // almost certainly introduce bad XSS vulnerabilities.
14795 // type[property.substring(1)] = EVENT;
14796 break;
14797 case '!':
14798 type[property.substring(1)] = BOOLEAN;
14799 break;
14800 case '#':
14801 type[property.substring(1)] = NUMBER;
14802 break;
14803 case '%':
14804 type[property.substring(1)] = OBJECT;
14805 break;
14806 default:
14807 type[property] = STRING;
14808 }
14809 }
14810 });
14811 });
14812 }
14813 hasProperty(tagName, propName, schemaMetas) {
14814 if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) {
14815 return true;
14816 }
14817 if (tagName.indexOf('-') > -1) {
14818 if (isNgContainer(tagName) || isNgContent(tagName)) {
14819 return false;
14820 }
14821 if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
14822 // Can't tell now as we don't know which properties a custom element will get
14823 // once it is instantiated
14824 return true;
14825 }
14826 }
14827 const elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
14828 return !!elementProperties[propName];
14829 }
14830 hasElement(tagName, schemaMetas) {
14831 if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) {
14832 return true;
14833 }
14834 if (tagName.indexOf('-') > -1) {
14835 if (isNgContainer(tagName) || isNgContent(tagName)) {
14836 return true;
14837 }
14838 if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
14839 // Allow any custom elements
14840 return true;
14841 }
14842 }
14843 return !!this._schema[tagName.toLowerCase()];
14844 }
14845 /**
14846 * securityContext returns the security context for the given property on the given DOM tag.
14847 *
14848 * Tag and property name are statically known and cannot change at runtime, i.e. it is not
14849 * possible to bind a value into a changing attribute or tag name.
14850 *
14851 * The filtering is based on a list of allowed tags|attributes. All attributes in the schema
14852 * above are assumed to have the 'NONE' security context, i.e. that they are safe inert
14853 * string values. Only specific well known attack vectors are assigned their appropriate context.
14854 */
14855 securityContext(tagName, propName, isAttribute) {
14856 if (isAttribute) {
14857 // NB: For security purposes, use the mapped property name, not the attribute name.
14858 propName = this.getMappedPropName(propName);
14859 }
14860 // Make sure comparisons are case insensitive, so that case differences between attribute and
14861 // property names do not have a security impact.
14862 tagName = tagName.toLowerCase();
14863 propName = propName.toLowerCase();
14864 let ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
14865 if (ctx) {
14866 return ctx;
14867 }
14868 ctx = SECURITY_SCHEMA()['*|' + propName];
14869 return ctx ? ctx : SecurityContext.NONE;
14870 }
14871 getMappedPropName(propName) {
14872 return _ATTR_TO_PROP[propName] || propName;
14873 }
14874 getDefaultComponentElementName() {
14875 return 'ng-component';
14876 }
14877 validateProperty(name) {
14878 if (name.toLowerCase().startsWith('on')) {
14879 const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
14880 `please use (${name.slice(2)})=...` +
14881 `\nIf '${name}' is a directive input, make sure the directive is imported by the` +
14882 ` current module.`;
14883 return { error: true, msg: msg };
14884 }
14885 else {
14886 return { error: false };
14887 }
14888 }
14889 validateAttribute(name) {
14890 if (name.toLowerCase().startsWith('on')) {
14891 const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
14892 `please use (${name.slice(2)})=...`;
14893 return { error: true, msg: msg };
14894 }
14895 else {
14896 return { error: false };
14897 }
14898 }
14899 allKnownElementNames() {
14900 return Object.keys(this._schema);
14901 }
14902 allKnownAttributesOfElement(tagName) {
14903 const elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
14904 // Convert properties to attributes.
14905 return Object.keys(elementProperties).map(prop => { var _a; return (_a = _PROP_TO_ATTR[prop]) !== null && _a !== void 0 ? _a : prop; });
14906 }
14907 normalizeAnimationStyleProperty(propName) {
14908 return dashCaseToCamelCase(propName);
14909 }
14910 normalizeAnimationStyleValue(camelCaseProp, userProvidedProp, val) {
14911 let unit = '';
14912 const strVal = val.toString().trim();
14913 let errorMsg = null;
14914 if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
14915 if (typeof val === 'number') {
14916 unit = 'px';
14917 }
14918 else {
14919 const valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/);
14920 if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
14921 errorMsg = `Please provide a CSS unit value for ${userProvidedProp}:${val}`;
14922 }
14923 }
14924 }
14925 return { error: errorMsg, value: strVal + unit };
14926 }
14927 }
14928 function _isPixelDimensionStyle(prop) {
14929 switch (prop) {
14930 case 'width':
14931 case 'height':
14932 case 'minWidth':
14933 case 'minHeight':
14934 case 'maxWidth':
14935 case 'maxHeight':
14936 case 'left':
14937 case 'top':
14938 case 'bottom':
14939 case 'right':
14940 case 'fontSize':
14941 case 'outlineWidth':
14942 case 'outlineOffset':
14943 case 'paddingTop':
14944 case 'paddingLeft':
14945 case 'paddingBottom':
14946 case 'paddingRight':
14947 case 'marginTop':
14948 case 'marginLeft':
14949 case 'marginBottom':
14950 case 'marginRight':
14951 case 'borderRadius':
14952 case 'borderWidth':
14953 case 'borderTopWidth':
14954 case 'borderLeftWidth':
14955 case 'borderRightWidth':
14956 case 'borderBottomWidth':
14957 case 'textIndent':
14958 return true;
14959 default:
14960 return false;
14961 }
14962 }
14963
14964 /**
14965 * @license
14966 * Copyright Google LLC All Rights Reserved.
14967 *
14968 * Use of this source code is governed by an MIT-style license that can be
14969 * found in the LICENSE file at https://angular.io/license
14970 */
14971 /**
14972 * Set of tagName|propertyName corresponding to Trusted Types sinks. Properties applying to all
14973 * tags use '*'.
14974 *
14975 * Extracted from, and should be kept in sync with
14976 * https://w3c.github.io/webappsec-trusted-types/dist/spec/#integrations
14977 */
14978 const TRUSTED_TYPES_SINKS = new Set([
14979 // NOTE: All strings in this set *must* be lowercase!
14980 // TrustedHTML
14981 'iframe|srcdoc',
14982 '*|innerhtml',
14983 '*|outerhtml',
14984 // NB: no TrustedScript here, as the corresponding tags are stripped by the compiler.
14985 // TrustedScriptURL
14986 'embed|src',
14987 'object|codebase',
14988 'object|data',
14989 ]);
14990 /**
14991 * isTrustedTypesSink returns true if the given property on the given DOM tag is a Trusted Types
14992 * sink. In that case, use `ElementSchemaRegistry.securityContext` to determine which particular
14993 * Trusted Type is required for values passed to the sink:
14994 * - SecurityContext.HTML corresponds to TrustedHTML
14995 * - SecurityContext.RESOURCE_URL corresponds to TrustedScriptURL
14996 */
14997 function isTrustedTypesSink(tagName, propName) {
14998 // Make sure comparisons are case insensitive, so that case differences between attribute and
14999 // property names do not have a security impact.
15000 tagName = tagName.toLowerCase();
15001 propName = propName.toLowerCase();
15002 return TRUSTED_TYPES_SINKS.has(tagName + '|' + propName) ||
15003 TRUSTED_TYPES_SINKS.has('*|' + propName);
15004 }
15005
15006 /**
15007 * @license
15008 * Copyright Google LLC All Rights Reserved.
15009 *
15010 * Use of this source code is governed by an MIT-style license that can be
15011 * found in the LICENSE file at https://angular.io/license
15012 */
15013 const BIND_NAME_REGEXP$1 = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
15014 // Group 1 = "bind-"
15015 const KW_BIND_IDX$1 = 1;
15016 // Group 2 = "let-"
15017 const KW_LET_IDX$1 = 2;
15018 // Group 3 = "ref-/#"
15019 const KW_REF_IDX$1 = 3;
15020 // Group 4 = "on-"
15021 const KW_ON_IDX$1 = 4;
15022 // Group 5 = "bindon-"
15023 const KW_BINDON_IDX$1 = 5;
15024 // Group 6 = "@"
15025 const KW_AT_IDX$1 = 6;
15026 // Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
15027 const IDENT_KW_IDX$1 = 7;
15028 const BINDING_DELIMS = {
15029 BANANA_BOX: { start: '[(', end: ')]' },
15030 PROPERTY: { start: '[', end: ']' },
15031 EVENT: { start: '(', end: ')' },
15032 };
15033 const TEMPLATE_ATTR_PREFIX$2 = '*';
15034 function htmlAstToRender3Ast(htmlNodes, bindingParser) {
15035 const transformer = new HtmlAstToIvyAst(bindingParser);
15036 const ivyNodes = visitAll$1(transformer, htmlNodes);
15037 // Errors might originate in either the binding parser or the html to ivy transformer
15038 const allErrors = bindingParser.errors.concat(transformer.errors);
15039 return {
15040 nodes: ivyNodes,
15041 errors: allErrors,
15042 styleUrls: transformer.styleUrls,
15043 styles: transformer.styles,
15044 ngContentSelectors: transformer.ngContentSelectors,
15045 };
15046 }
15047 class HtmlAstToIvyAst {
15048 constructor(bindingParser) {
15049 this.bindingParser = bindingParser;
15050 this.errors = [];
15051 this.styles = [];
15052 this.styleUrls = [];
15053 this.ngContentSelectors = [];
15054 this.inI18nBlock = false;
15055 }
15056 // HTML visitor
15057 visitElement(element) {
15058 const isI18nRootElement = isI18nRootNode(element.i18n);
15059 if (isI18nRootElement) {
15060 if (this.inI18nBlock) {
15061 this.reportError('Cannot mark an element as translatable inside of a translatable section. Please remove the nested i18n marker.', element.sourceSpan);
15062 }
15063 this.inI18nBlock = true;
15064 }
15065 const preparsedElement = preparseElement(element);
15066 if (preparsedElement.type === PreparsedElementType.SCRIPT) {
15067 return null;
15068 }
15069 else if (preparsedElement.type === PreparsedElementType.STYLE) {
15070 const contents = textContents(element);
15071 if (contents !== null) {
15072 this.styles.push(contents);
15073 }
15074 return null;
15075 }
15076 else if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
15077 isStyleUrlResolvable(preparsedElement.hrefAttr)) {
15078 this.styleUrls.push(preparsedElement.hrefAttr);
15079 return null;
15080 }
15081 // Whether the element is a `<ng-template>`
15082 const isTemplateElement = isNgTemplate(element.name);
15083 const parsedProperties = [];
15084 const boundEvents = [];
15085 const variables = [];
15086 const references = [];
15087 const attributes = [];
15088 const i18nAttrsMeta = {};
15089 const templateParsedProperties = [];
15090 const templateVariables = [];
15091 // Whether the element has any *-attribute
15092 let elementHasInlineTemplate = false;
15093 for (const attribute of element.attrs) {
15094 let hasBinding = false;
15095 const normalizedName = normalizeAttributeName(attribute.name);
15096 // `*attr` defines template bindings
15097 let isTemplateBinding = false;
15098 if (attribute.i18n) {
15099 i18nAttrsMeta[attribute.name] = attribute.i18n;
15100 }
15101 if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX$2)) {
15102 // *-attributes
15103 if (elementHasInlineTemplate) {
15104 this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan);
15105 }
15106 isTemplateBinding = true;
15107 elementHasInlineTemplate = true;
15108 const templateValue = attribute.value;
15109 const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX$2.length);
15110 const parsedVariables = [];
15111 const absoluteValueOffset = attribute.valueSpan ?
15112 attribute.valueSpan.start.offset :
15113 // If there is no value span the attribute does not have a value, like `attr` in
15114 //`<div attr></div>`. In this case, point to one character beyond the last character of
15115 // the attribute name.
15116 attribute.sourceSpan.start.offset + attribute.name.length;
15117 this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true /* isIvyAst */);
15118 templateVariables.push(...parsedVariables.map(v => new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan)));
15119 }
15120 else {
15121 // Check for variables, events, property bindings, interpolation
15122 hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
15123 }
15124 if (!hasBinding && !isTemplateBinding) {
15125 // don't include the bindings as attributes as well in the AST
15126 attributes.push(this.visitAttribute(attribute));
15127 }
15128 }
15129 const children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR$1 : this, element.children);
15130 let parsedElement;
15131 if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
15132 // `<ng-content>`
15133 if (element.children &&
15134 !element.children.every((node) => isEmptyTextNode(node) || isCommentNode(node))) {
15135 this.reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
15136 }
15137 const selector = preparsedElement.selectAttr;
15138 const attrs = element.attrs.map(attr => this.visitAttribute(attr));
15139 parsedElement = new Content(selector, attrs, element.sourceSpan, element.i18n);
15140 this.ngContentSelectors.push(selector);
15141 }
15142 else if (isTemplateElement) {
15143 // `<ng-template>`
15144 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
15145 parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, [ /* no template attributes */], children, references, variables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
15146 }
15147 else {
15148 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
15149 parsedElement = new Element(element.name, attributes, attrs.bound, boundEvents, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
15150 }
15151 if (elementHasInlineTemplate) {
15152 // If this node is an inline-template (e.g. has *ngFor) then we need to create a template
15153 // node that contains this node.
15154 // Moreover, if the node is an element, then we need to hoist its attributes to the template
15155 // node for matching against content projection selectors.
15156 const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
15157 const templateAttrs = [];
15158 attrs.literal.forEach(attr => templateAttrs.push(attr));
15159 attrs.bound.forEach(attr => templateAttrs.push(attr));
15160 const hoistedAttrs = parsedElement instanceof Element ?
15161 {
15162 attributes: parsedElement.attributes,
15163 inputs: parsedElement.inputs,
15164 outputs: parsedElement.outputs,
15165 } :
15166 { attributes: [], inputs: [], outputs: [] };
15167 // For <ng-template>s with structural directives on them, avoid passing i18n information to
15168 // the wrapping template to prevent unnecessary i18n instructions from being generated. The
15169 // necessary i18n meta information will be extracted from child elements.
15170 const i18n = isTemplateElement && isI18nRootElement ? undefined : element.i18n;
15171 // TODO(pk): test for this case
15172 parsedElement = new Template(parsedElement.name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, templateAttrs, [parsedElement], [ /* no references */], templateVariables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, i18n);
15173 }
15174 if (isI18nRootElement) {
15175 this.inI18nBlock = false;
15176 }
15177 return parsedElement;
15178 }
15179 visitAttribute(attribute) {
15180 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
15181 }
15182 visitText(text) {
15183 return this._visitTextWithInterpolation(text.value, text.sourceSpan, text.i18n);
15184 }
15185 visitExpansion(expansion) {
15186 if (!expansion.i18n) {
15187 // do not generate Icu in case it was created
15188 // outside of i18n block in a template
15189 return null;
15190 }
15191 if (!isI18nRootNode(expansion.i18n)) {
15192 throw new Error(`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${expansion.sourceSpan.toString()}. Expected a "Message"`);
15193 }
15194 const message = expansion.i18n;
15195 const vars = {};
15196 const placeholders = {};
15197 // extract VARs from ICUs - we process them separately while
15198 // assembling resulting message via goog.getMsg function, since
15199 // we need to pass them to top-level goog.getMsg call
15200 Object.keys(message.placeholders).forEach(key => {
15201 const value = message.placeholders[key];
15202 if (key.startsWith(I18N_ICU_VAR_PREFIX)) {
15203 // Currently when the `plural` or `select` keywords in an ICU contain trailing spaces (e.g.
15204 // `{count, select , ...}`), these spaces are also included into the key names in ICU vars
15205 // (e.g. "VAR_SELECT "). These trailing spaces are not desirable, since they will later be
15206 // converted into `_` symbols while normalizing placeholder names, which might lead to
15207 // mismatches at runtime (i.e. placeholder will not be replaced with the correct value).
15208 const formattedKey = key.trim();
15209 const ast = this.bindingParser.parseInterpolationExpression(value.text, value.sourceSpan);
15210 vars[formattedKey] = new BoundText(ast, value.sourceSpan);
15211 }
15212 else {
15213 placeholders[key] = this._visitTextWithInterpolation(value.text, value.sourceSpan);
15214 }
15215 });
15216 return new Icu(vars, placeholders, expansion.sourceSpan, message);
15217 }
15218 visitExpansionCase(expansionCase) {
15219 return null;
15220 }
15221 visitComment(comment) {
15222 return null;
15223 }
15224 // convert view engine `ParsedProperty` to a format suitable for IVY
15225 extractAttributes(elementName, properties, i18nPropsMeta) {
15226 const bound = [];
15227 const literal = [];
15228 properties.forEach(prop => {
15229 const i18n = i18nPropsMeta[prop.name];
15230 if (prop.isLiteral) {
15231 literal.push(new TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n));
15232 }
15233 else {
15234 // Note that validation is skipped and property mapping is disabled
15235 // due to the fact that we need to make sure a given prop is not an
15236 // input of a directive and directive matching happens at runtime.
15237 const bep = this.bindingParser.createBoundElementProperty(elementName, prop, /* skipValidation */ true, /* mapPropertyName */ false);
15238 bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n));
15239 }
15240 });
15241 return { bound, literal };
15242 }
15243 parseAttribute(isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) {
15244 const name = normalizeAttributeName(attribute.name);
15245 const value = attribute.value;
15246 const srcSpan = attribute.sourceSpan;
15247 const absoluteOffset = attribute.valueSpan ? attribute.valueSpan.start.offset : srcSpan.start.offset;
15248 function createKeySpan(srcSpan, prefix, identifier) {
15249 // We need to adjust the start location for the keySpan to account for the removed 'data-'
15250 // prefix from `normalizeAttributeName`.
15251 const normalizationAdjustment = attribute.name.length - name.length;
15252 const keySpanStart = srcSpan.start.moveBy(prefix.length + normalizationAdjustment);
15253 const keySpanEnd = keySpanStart.moveBy(identifier.length);
15254 return new ParseSourceSpan(keySpanStart, keySpanEnd, keySpanStart, identifier);
15255 }
15256 const bindParts = name.match(BIND_NAME_REGEXP$1);
15257 if (bindParts) {
15258 if (bindParts[KW_BIND_IDX$1] != null) {
15259 const identifier = bindParts[IDENT_KW_IDX$1];
15260 const keySpan = createKeySpan(srcSpan, bindParts[KW_BIND_IDX$1], identifier);
15261 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15262 }
15263 else if (bindParts[KW_LET_IDX$1]) {
15264 if (isTemplateElement) {
15265 const identifier = bindParts[IDENT_KW_IDX$1];
15266 const keySpan = createKeySpan(srcSpan, bindParts[KW_LET_IDX$1], identifier);
15267 this.parseVariable(identifier, value, srcSpan, keySpan, attribute.valueSpan, variables);
15268 }
15269 else {
15270 this.reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
15271 }
15272 }
15273 else if (bindParts[KW_REF_IDX$1]) {
15274 const identifier = bindParts[IDENT_KW_IDX$1];
15275 const keySpan = createKeySpan(srcSpan, bindParts[KW_REF_IDX$1], identifier);
15276 this.parseReference(identifier, value, srcSpan, keySpan, attribute.valueSpan, references);
15277 }
15278 else if (bindParts[KW_ON_IDX$1]) {
15279 const events = [];
15280 const identifier = bindParts[IDENT_KW_IDX$1];
15281 const keySpan = createKeySpan(srcSpan, bindParts[KW_ON_IDX$1], identifier);
15282 this.bindingParser.parseEvent(identifier, value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
15283 addEvents(events, boundEvents);
15284 }
15285 else if (bindParts[KW_BINDON_IDX$1]) {
15286 const identifier = bindParts[IDENT_KW_IDX$1];
15287 const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX$1], identifier);
15288 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15289 this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
15290 }
15291 else if (bindParts[KW_AT_IDX$1]) {
15292 const keySpan = createKeySpan(srcSpan, '', name);
15293 this.bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15294 }
15295 return true;
15296 }
15297 // We didn't see a kw-prefixed property binding, but we have not yet checked
15298 // for the []/()/[()] syntax.
15299 let delims = null;
15300 if (name.startsWith(BINDING_DELIMS.BANANA_BOX.start)) {
15301 delims = BINDING_DELIMS.BANANA_BOX;
15302 }
15303 else if (name.startsWith(BINDING_DELIMS.PROPERTY.start)) {
15304 delims = BINDING_DELIMS.PROPERTY;
15305 }
15306 else if (name.startsWith(BINDING_DELIMS.EVENT.start)) {
15307 delims = BINDING_DELIMS.EVENT;
15308 }
15309 if (delims !== null &&
15310 // NOTE: older versions of the parser would match a start/end delimited
15311 // binding iff the property name was terminated by the ending delimiter
15312 // and the identifier in the binding was non-empty.
15313 // TODO(ayazhafiz): update this to handle malformed bindings.
15314 name.endsWith(delims.end) && name.length > delims.start.length + delims.end.length) {
15315 const identifier = name.substring(delims.start.length, name.length - delims.end.length);
15316 const keySpan = createKeySpan(srcSpan, delims.start, identifier);
15317 if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
15318 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15319 this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
15320 }
15321 else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
15322 this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15323 }
15324 else {
15325 const events = [];
15326 this.bindingParser.parseEvent(identifier, value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
15327 addEvents(events, boundEvents);
15328 }
15329 return true;
15330 }
15331 // No explicit binding found.
15332 const keySpan = createKeySpan(srcSpan, '' /* prefix */, name);
15333 const hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
15334 return hasBinding;
15335 }
15336 _visitTextWithInterpolation(value, sourceSpan, i18n) {
15337 const valueNoNgsp = replaceNgsp(value);
15338 const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan);
15339 return expr ? new BoundText(expr, sourceSpan, i18n) : new Text(valueNoNgsp, sourceSpan);
15340 }
15341 parseVariable(identifier, value, sourceSpan, keySpan, valueSpan, variables) {
15342 if (identifier.indexOf('-') > -1) {
15343 this.reportError(`"-" is not allowed in variable names`, sourceSpan);
15344 }
15345 else if (identifier.length === 0) {
15346 this.reportError(`Variable does not have a name`, sourceSpan);
15347 }
15348 variables.push(new Variable(identifier, value, sourceSpan, keySpan, valueSpan));
15349 }
15350 parseReference(identifier, value, sourceSpan, keySpan, valueSpan, references) {
15351 if (identifier.indexOf('-') > -1) {
15352 this.reportError(`"-" is not allowed in reference names`, sourceSpan);
15353 }
15354 else if (identifier.length === 0) {
15355 this.reportError(`Reference does not have a name`, sourceSpan);
15356 }
15357 else if (references.some(reference => reference.name === identifier)) {
15358 this.reportError(`Reference "#${identifier}" is defined more than once`, sourceSpan);
15359 }
15360 references.push(new Reference(identifier, value, sourceSpan, keySpan, valueSpan));
15361 }
15362 parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) {
15363 const events = [];
15364 this.bindingParser.parseEvent(`${name}Change`, `${expression}=$event`, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
15365 addEvents(events, boundEvents);
15366 }
15367 reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
15368 this.errors.push(new ParseError(sourceSpan, message, level));
15369 }
15370 }
15371 class NonBindableVisitor$1 {
15372 visitElement(ast) {
15373 const preparsedElement = preparseElement(ast);
15374 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
15375 preparsedElement.type === PreparsedElementType.STYLE ||
15376 preparsedElement.type === PreparsedElementType.STYLESHEET) {
15377 // Skipping <script> for security reasons
15378 // Skipping <style> and stylesheets as we already processed them
15379 // in the StyleCompiler
15380 return null;
15381 }
15382 const children = visitAll$1(this, ast.children, null);
15383 return new Element(ast.name, visitAll$1(this, ast.attrs),
15384 /* inputs */ [], /* outputs */ [], children, /* references */ [], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
15385 }
15386 visitComment(comment) {
15387 return null;
15388 }
15389 visitAttribute(attribute) {
15390 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
15391 }
15392 visitText(text) {
15393 return new Text(text.value, text.sourceSpan);
15394 }
15395 visitExpansion(expansion) {
15396 return null;
15397 }
15398 visitExpansionCase(expansionCase) {
15399 return null;
15400 }
15401 }
15402 const NON_BINDABLE_VISITOR$1 = new NonBindableVisitor$1();
15403 function normalizeAttributeName(attrName) {
15404 return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
15405 }
15406 function addEvents(events, boundEvents) {
15407 boundEvents.push(...events.map(e => BoundEvent.fromParsedEvent(e)));
15408 }
15409 function isEmptyTextNode(node) {
15410 return node instanceof Text$2 && node.value.trim().length == 0;
15411 }
15412 function isCommentNode(node) {
15413 return node instanceof Comment;
15414 }
15415 function textContents(node) {
15416 if (node.children.length !== 1 || !(node.children[0] instanceof Text$2)) {
15417 return null;
15418 }
15419 else {
15420 return node.children[0].value;
15421 }
15422 }
15423
15424 /**
15425 * @license
15426 * Copyright Google LLC All Rights Reserved.
15427 *
15428 * Use of this source code is governed by an MIT-style license that can be
15429 * found in the LICENSE file at https://angular.io/license
15430 */
15431 var TagType;
15432 (function (TagType) {
15433 TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
15434 TagType[TagType["TEMPLATE"] = 1] = "TEMPLATE";
15435 })(TagType || (TagType = {}));
15436 /**
15437 * Generates an object that is used as a shared state between parent and all child contexts.
15438 */
15439 function setupRegistry() {
15440 return { getUniqueId: getSeqNumberGenerator(), icus: new Map() };
15441 }
15442 /**
15443 * I18nContext is a helper class which keeps track of all i18n-related aspects
15444 * (accumulates placeholders, bindings, etc) between i18nStart and i18nEnd instructions.
15445 *
15446 * When we enter a nested template, the top-level context is being passed down
15447 * to the nested component, which uses this context to generate a child instance
15448 * of I18nContext class (to handle nested template) and at the end, reconciles it back
15449 * with the parent context.
15450 *
15451 * @param index Instruction index of i18nStart, which initiates this context
15452 * @param ref Reference to a translation const that represents the content if thus context
15453 * @param level Nestng level defined for child contexts
15454 * @param templateIndex Instruction index of a template which this context belongs to
15455 * @param meta Meta information (id, meaning, description, etc) associated with this context
15456 */
15457 class I18nContext {
15458 constructor(index, ref, level = 0, templateIndex = null, meta, registry) {
15459 this.index = index;
15460 this.ref = ref;
15461 this.level = level;
15462 this.templateIndex = templateIndex;
15463 this.meta = meta;
15464 this.registry = registry;
15465 this.bindings = new Set();
15466 this.placeholders = new Map();
15467 this.isEmitted = false;
15468 this._unresolvedCtxCount = 0;
15469 this._registry = registry || setupRegistry();
15470 this.id = this._registry.getUniqueId();
15471 }
15472 appendTag(type, node, index, closed) {
15473 if (node.isVoid && closed) {
15474 return; // ignore "close" for void tags
15475 }
15476 const ph = node.isVoid || !closed ? node.startName : node.closeName;
15477 const content = { type, index, ctx: this.id, isVoid: node.isVoid, closed };
15478 updatePlaceholderMap(this.placeholders, ph, content);
15479 }
15480 get icus() {
15481 return this._registry.icus;
15482 }
15483 get isRoot() {
15484 return this.level === 0;
15485 }
15486 get isResolved() {
15487 return this._unresolvedCtxCount === 0;
15488 }
15489 getSerializedPlaceholders() {
15490 const result = new Map();
15491 this.placeholders.forEach((values, key) => result.set(key, values.map(serializePlaceholderValue)));
15492 return result;
15493 }
15494 // public API to accumulate i18n-related content
15495 appendBinding(binding) {
15496 this.bindings.add(binding);
15497 }
15498 appendIcu(name, ref) {
15499 updatePlaceholderMap(this._registry.icus, name, ref);
15500 }
15501 appendBoundText(node) {
15502 const phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id);
15503 phs.forEach((values, key) => updatePlaceholderMap(this.placeholders, key, ...values));
15504 }
15505 appendTemplate(node, index) {
15506 // add open and close tags at the same time,
15507 // since we process nested templates separately
15508 this.appendTag(TagType.TEMPLATE, node, index, false);
15509 this.appendTag(TagType.TEMPLATE, node, index, true);
15510 this._unresolvedCtxCount++;
15511 }
15512 appendElement(node, index, closed) {
15513 this.appendTag(TagType.ELEMENT, node, index, closed);
15514 }
15515 appendProjection(node, index) {
15516 // Add open and close tags at the same time, since `<ng-content>` has no content,
15517 // so when we come across `<ng-content>` we can register both open and close tags.
15518 // Note: runtime i18n logic doesn't distinguish `<ng-content>` tag placeholders and
15519 // regular element tag placeholders, so we generate element placeholders for both types.
15520 this.appendTag(TagType.ELEMENT, node, index, false);
15521 this.appendTag(TagType.ELEMENT, node, index, true);
15522 }
15523 /**
15524 * Generates an instance of a child context based on the root one,
15525 * when we enter a nested template within I18n section.
15526 *
15527 * @param index Instruction index of corresponding i18nStart, which initiates this context
15528 * @param templateIndex Instruction index of a template which this context belongs to
15529 * @param meta Meta information (id, meaning, description, etc) associated with this context
15530 *
15531 * @returns I18nContext instance
15532 */
15533 forkChildContext(index, templateIndex, meta) {
15534 return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry);
15535 }
15536 /**
15537 * Reconciles child context into parent one once the end of the i18n block is reached (i18nEnd).
15538 *
15539 * @param context Child I18nContext instance to be reconciled with parent context.
15540 */
15541 reconcileChildContext(context) {
15542 // set the right context id for open and close
15543 // template tags, so we can use it as sub-block ids
15544 ['start', 'close'].forEach((op) => {
15545 const key = context.meta[`${op}Name`];
15546 const phs = this.placeholders.get(key) || [];
15547 const tag = phs.find(findTemplateFn(this.id, context.templateIndex));
15548 if (tag) {
15549 tag.ctx = context.id;
15550 }
15551 });
15552 // reconcile placeholders
15553 const childPhs = context.placeholders;
15554 childPhs.forEach((values, key) => {
15555 const phs = this.placeholders.get(key);
15556 if (!phs) {
15557 this.placeholders.set(key, values);
15558 return;
15559 }
15560 // try to find matching template...
15561 const tmplIdx = phs.findIndex(findTemplateFn(context.id, context.templateIndex));
15562 if (tmplIdx >= 0) {
15563 // ... if found - replace it with nested template content
15564 const isCloseTag = key.startsWith('CLOSE');
15565 const isTemplateTag = key.endsWith('NG-TEMPLATE');
15566 if (isTemplateTag) {
15567 // current template's content is placed before or after
15568 // parent template tag, depending on the open/close atrribute
15569 phs.splice(tmplIdx + (isCloseTag ? 0 : 1), 0, ...values);
15570 }
15571 else {
15572 const idx = isCloseTag ? values.length - 1 : 0;
15573 values[idx].tmpl = phs[tmplIdx];
15574 phs.splice(tmplIdx, 1, ...values);
15575 }
15576 }
15577 else {
15578 // ... otherwise just append content to placeholder value
15579 phs.push(...values);
15580 }
15581 this.placeholders.set(key, phs);
15582 });
15583 this._unresolvedCtxCount--;
15584 }
15585 }
15586 //
15587 // Helper methods
15588 //
15589 function wrap(symbol, index, contextId, closed) {
15590 const state = closed ? '/' : '';
15591 return wrapI18nPlaceholder(`${state}${symbol}${index}`, contextId);
15592 }
15593 function wrapTag(symbol, { index, ctx, isVoid }, closed) {
15594 return isVoid ? wrap(symbol, index, ctx) + wrap(symbol, index, ctx, true) :
15595 wrap(symbol, index, ctx, closed);
15596 }
15597 function findTemplateFn(ctx, templateIndex) {
15598 return (token) => typeof token === 'object' && token.type === TagType.TEMPLATE &&
15599 token.index === templateIndex && token.ctx === ctx;
15600 }
15601 function serializePlaceholderValue(value) {
15602 const element = (data, closed) => wrapTag('#', data, closed);
15603 const template = (data, closed) => wrapTag('*', data, closed);
15604 switch (value.type) {
15605 case TagType.ELEMENT:
15606 // close element tag
15607 if (value.closed) {
15608 return element(value, true) + (value.tmpl ? template(value.tmpl, true) : '');
15609 }
15610 // open element tag that also initiates a template
15611 if (value.tmpl) {
15612 return template(value.tmpl) + element(value) +
15613 (value.isVoid ? template(value.tmpl, true) : '');
15614 }
15615 return element(value);
15616 case TagType.TEMPLATE:
15617 return template(value, value.closed);
15618 default:
15619 return value;
15620 }
15621 }
15622
15623 /**
15624 * @license
15625 * Copyright Google LLC All Rights Reserved.
15626 *
15627 * Use of this source code is governed by an MIT-style license that can be
15628 * found in the LICENSE file at https://angular.io/license
15629 */
15630 class IcuSerializerVisitor {
15631 visitText(text) {
15632 return text.value;
15633 }
15634 visitContainer(container) {
15635 return container.children.map(child => child.visit(this)).join('');
15636 }
15637 visitIcu(icu) {
15638 const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
15639 const result = `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`;
15640 return result;
15641 }
15642 visitTagPlaceholder(ph) {
15643 return ph.isVoid ?
15644 this.formatPh(ph.startName) :
15645 `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
15646 }
15647 visitPlaceholder(ph) {
15648 return this.formatPh(ph.name);
15649 }
15650 visitIcuPlaceholder(ph, context) {
15651 return this.formatPh(ph.name);
15652 }
15653 formatPh(value) {
15654 return `{${formatI18nPlaceholderName(value, /* useCamelCase */ false)}}`;
15655 }
15656 }
15657 const serializer = new IcuSerializerVisitor();
15658 function serializeIcuNode(icu) {
15659 return icu.visit(serializer);
15660 }
15661
15662 /**
15663 * @license
15664 * Copyright Google LLC All Rights Reserved.
15665 *
15666 * Use of this source code is governed by an MIT-style license that can be
15667 * found in the LICENSE file at https://angular.io/license
15668 */
15669 const TAG_TO_PLACEHOLDER_NAMES = {
15670 'A': 'LINK',
15671 'B': 'BOLD_TEXT',
15672 'BR': 'LINE_BREAK',
15673 'EM': 'EMPHASISED_TEXT',
15674 'H1': 'HEADING_LEVEL1',
15675 'H2': 'HEADING_LEVEL2',
15676 'H3': 'HEADING_LEVEL3',
15677 'H4': 'HEADING_LEVEL4',
15678 'H5': 'HEADING_LEVEL5',
15679 'H6': 'HEADING_LEVEL6',
15680 'HR': 'HORIZONTAL_RULE',
15681 'I': 'ITALIC_TEXT',
15682 'LI': 'LIST_ITEM',
15683 'LINK': 'MEDIA_LINK',
15684 'OL': 'ORDERED_LIST',
15685 'P': 'PARAGRAPH',
15686 'Q': 'QUOTATION',
15687 'S': 'STRIKETHROUGH_TEXT',
15688 'SMALL': 'SMALL_TEXT',
15689 'SUB': 'SUBSTRIPT',
15690 'SUP': 'SUPERSCRIPT',
15691 'TBODY': 'TABLE_BODY',
15692 'TD': 'TABLE_CELL',
15693 'TFOOT': 'TABLE_FOOTER',
15694 'TH': 'TABLE_HEADER_CELL',
15695 'THEAD': 'TABLE_HEADER',
15696 'TR': 'TABLE_ROW',
15697 'TT': 'MONOSPACED_TEXT',
15698 'U': 'UNDERLINED_TEXT',
15699 'UL': 'UNORDERED_LIST',
15700 };
15701 /**
15702 * Creates unique names for placeholder with different content.
15703 *
15704 * Returns the same placeholder name when the content is identical.
15705 */
15706 class PlaceholderRegistry {
15707 constructor() {
15708 // Count the occurrence of the base name top generate a unique name
15709 this._placeHolderNameCounts = {};
15710 // Maps signature to placeholder names
15711 this._signatureToName = {};
15712 }
15713 getStartTagPlaceholderName(tag, attrs, isVoid) {
15714 const signature = this._hashTag(tag, attrs, isVoid);
15715 if (this._signatureToName[signature]) {
15716 return this._signatureToName[signature];
15717 }
15718 const upperTag = tag.toUpperCase();
15719 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
15720 const name = this._generateUniqueName(isVoid ? baseName : `START_${baseName}`);
15721 this._signatureToName[signature] = name;
15722 return name;
15723 }
15724 getCloseTagPlaceholderName(tag) {
15725 const signature = this._hashClosingTag(tag);
15726 if (this._signatureToName[signature]) {
15727 return this._signatureToName[signature];
15728 }
15729 const upperTag = tag.toUpperCase();
15730 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
15731 const name = this._generateUniqueName(`CLOSE_${baseName}`);
15732 this._signatureToName[signature] = name;
15733 return name;
15734 }
15735 getPlaceholderName(name, content) {
15736 const upperName = name.toUpperCase();
15737 const signature = `PH: ${upperName}=${content}`;
15738 if (this._signatureToName[signature]) {
15739 return this._signatureToName[signature];
15740 }
15741 const uniqueName = this._generateUniqueName(upperName);
15742 this._signatureToName[signature] = uniqueName;
15743 return uniqueName;
15744 }
15745 getUniquePlaceholder(name) {
15746 return this._generateUniqueName(name.toUpperCase());
15747 }
15748 // Generate a hash for a tag - does not take attribute order into account
15749 _hashTag(tag, attrs, isVoid) {
15750 const start = `<${tag}`;
15751 const strAttrs = Object.keys(attrs).sort().map((name) => ` ${name}=${attrs[name]}`).join('');
15752 const end = isVoid ? '/>' : `></${tag}>`;
15753 return start + strAttrs + end;
15754 }
15755 _hashClosingTag(tag) {
15756 return this._hashTag(`/${tag}`, {}, false);
15757 }
15758 _generateUniqueName(base) {
15759 const seen = this._placeHolderNameCounts.hasOwnProperty(base);
15760 if (!seen) {
15761 this._placeHolderNameCounts[base] = 1;
15762 return base;
15763 }
15764 const id = this._placeHolderNameCounts[base];
15765 this._placeHolderNameCounts[base] = id + 1;
15766 return `${base}_${id}`;
15767 }
15768 }
15769
15770 /**
15771 * @license
15772 * Copyright Google LLC All Rights Reserved.
15773 *
15774 * Use of this source code is governed by an MIT-style license that can be
15775 * found in the LICENSE file at https://angular.io/license
15776 */
15777 const _expParser = new Parser$1(new Lexer());
15778 /**
15779 * Returns a function converting html nodes to an i18n Message given an interpolationConfig
15780 */
15781 function createI18nMessageFactory(interpolationConfig) {
15782 const visitor = new _I18nVisitor(_expParser, interpolationConfig);
15783 return (nodes, meaning, description, customId, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn);
15784 }
15785 function noopVisitNodeFn(_html, i18n) {
15786 return i18n;
15787 }
15788 class _I18nVisitor {
15789 constructor(_expressionParser, _interpolationConfig) {
15790 this._expressionParser = _expressionParser;
15791 this._interpolationConfig = _interpolationConfig;
15792 }
15793 toI18nMessage(nodes, meaning = '', description = '', customId = '', visitNodeFn) {
15794 const context = {
15795 isIcu: nodes.length == 1 && nodes[0] instanceof Expansion,
15796 icuDepth: 0,
15797 placeholderRegistry: new PlaceholderRegistry(),
15798 placeholderToContent: {},
15799 placeholderToMessage: {},
15800 visitNodeFn: visitNodeFn || noopVisitNodeFn,
15801 };
15802 const i18nodes = visitAll$1(this, nodes, context);
15803 return new Message(i18nodes, context.placeholderToContent, context.placeholderToMessage, meaning, description, customId);
15804 }
15805 visitElement(el, context) {
15806 var _a;
15807 const children = visitAll$1(this, el.children, context);
15808 const attrs = {};
15809 el.attrs.forEach(attr => {
15810 // Do not visit the attributes, translatable ones are top-level ASTs
15811 attrs[attr.name] = attr.value;
15812 });
15813 const isVoid = getHtmlTagDefinition(el.name).isVoid;
15814 const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
15815 context.placeholderToContent[startPhName] = {
15816 text: el.startSourceSpan.toString(),
15817 sourceSpan: el.startSourceSpan,
15818 };
15819 let closePhName = '';
15820 if (!isVoid) {
15821 closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(el.name);
15822 context.placeholderToContent[closePhName] = {
15823 text: `</${el.name}>`,
15824 sourceSpan: (_a = el.endSourceSpan) !== null && _a !== void 0 ? _a : el.sourceSpan,
15825 };
15826 }
15827 const node = new TagPlaceholder(el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
15828 return context.visitNodeFn(el, node);
15829 }
15830 visitAttribute(attribute, context) {
15831 const node = this._visitTextWithInterpolation(attribute.value, attribute.valueSpan || attribute.sourceSpan, context, attribute.i18n);
15832 return context.visitNodeFn(attribute, node);
15833 }
15834 visitText(text, context) {
15835 const node = this._visitTextWithInterpolation(text.value, text.sourceSpan, context, text.i18n);
15836 return context.visitNodeFn(text, node);
15837 }
15838 visitComment(comment, context) {
15839 return null;
15840 }
15841 visitExpansion(icu, context) {
15842 context.icuDepth++;
15843 const i18nIcuCases = {};
15844 const i18nIcu = new Icu$1(icu.switchValue, icu.type, i18nIcuCases, icu.sourceSpan);
15845 icu.cases.forEach((caze) => {
15846 i18nIcuCases[caze.value] = new Container(caze.expression.map((node) => node.visit(this, context)), caze.expSourceSpan);
15847 });
15848 context.icuDepth--;
15849 if (context.isIcu || context.icuDepth > 0) {
15850 // Returns an ICU node when:
15851 // - the message (vs a part of the message) is an ICU message, or
15852 // - the ICU message is nested.
15853 const expPh = context.placeholderRegistry.getUniquePlaceholder(`VAR_${icu.type}`);
15854 i18nIcu.expressionPlaceholder = expPh;
15855 context.placeholderToContent[expPh] = {
15856 text: icu.switchValue,
15857 sourceSpan: icu.switchValueSourceSpan,
15858 };
15859 return context.visitNodeFn(icu, i18nIcu);
15860 }
15861 // Else returns a placeholder
15862 // ICU placeholders should not be replaced with their original content but with the their
15863 // translations.
15864 // TODO(vicb): add a html.Node -> i18n.Message cache to avoid having to re-create the msg
15865 const phName = context.placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
15866 context.placeholderToMessage[phName] = this.toI18nMessage([icu], '', '', '', undefined);
15867 const node = new IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
15868 return context.visitNodeFn(icu, node);
15869 }
15870 visitExpansionCase(_icuCase, _context) {
15871 throw new Error('Unreachable code');
15872 }
15873 /**
15874 * Split the, potentially interpolated, text up into text and placeholder pieces.
15875 *
15876 * @param text The potentially interpolated string to be split.
15877 * @param sourceSpan The span of the whole of the `text` string.
15878 * @param context The current context of the visitor, used to compute and store placeholders.
15879 * @param previousI18n Any i18n metadata associated with this `text` from a previous pass.
15880 */
15881 _visitTextWithInterpolation(text, sourceSpan, context, previousI18n) {
15882 const { strings, expressions } = this._expressionParser.splitInterpolation(text, sourceSpan.start.toString(), this._interpolationConfig);
15883 // No expressions, return a single text.
15884 if (expressions.length === 0) {
15885 return new Text$1(text, sourceSpan);
15886 }
15887 // Return a sequence of `Text` and `Placeholder` nodes grouped in a `Container`.
15888 const nodes = [];
15889 for (let i = 0; i < strings.length - 1; i++) {
15890 this._addText(nodes, strings[i], sourceSpan);
15891 this._addPlaceholder(nodes, context, expressions[i], sourceSpan);
15892 }
15893 // The last index contains no expression
15894 this._addText(nodes, strings[strings.length - 1], sourceSpan);
15895 // Whitespace removal may have invalidated the interpolation source-spans.
15896 reusePreviousSourceSpans(nodes, previousI18n);
15897 return new Container(nodes, sourceSpan);
15898 }
15899 /**
15900 * Create a new `Text` node from the `textPiece` and add it to the `nodes` collection.
15901 *
15902 * @param nodes The nodes to which the created `Text` node should be added.
15903 * @param textPiece The text and relative span information for this `Text` node.
15904 * @param interpolationSpan The span of the whole interpolated text.
15905 */
15906 _addText(nodes, textPiece, interpolationSpan) {
15907 if (textPiece.text.length > 0) {
15908 // No need to add empty strings
15909 const stringSpan = getOffsetSourceSpan(interpolationSpan, textPiece);
15910 nodes.push(new Text$1(textPiece.text, stringSpan));
15911 }
15912 }
15913 /**
15914 * Create a new `Placeholder` node from the `expression` and add it to the `nodes` collection.
15915 *
15916 * @param nodes The nodes to which the created `Text` node should be added.
15917 * @param context The current context of the visitor, used to compute and store placeholders.
15918 * @param expression The expression text and relative span information for this `Placeholder`
15919 * node.
15920 * @param interpolationSpan The span of the whole interpolated text.
15921 */
15922 _addPlaceholder(nodes, context, expression, interpolationSpan) {
15923 const sourceSpan = getOffsetSourceSpan(interpolationSpan, expression);
15924 const baseName = extractPlaceholderName(expression.text) || 'INTERPOLATION';
15925 const phName = context.placeholderRegistry.getPlaceholderName(baseName, expression.text);
15926 const text = this._interpolationConfig.start + expression.text + this._interpolationConfig.end;
15927 context.placeholderToContent[phName] = { text, sourceSpan };
15928 nodes.push(new Placeholder(expression.text, phName, sourceSpan));
15929 }
15930 }
15931 /**
15932 * Re-use the source-spans from `previousI18n` metadata for the `nodes`.
15933 *
15934 * Whitespace removal can invalidate the source-spans of interpolation nodes, so we
15935 * reuse the source-span stored from a previous pass before the whitespace was removed.
15936 *
15937 * @param nodes The `Text` and `Placeholder` nodes to be processed.
15938 * @param previousI18n Any i18n metadata for these `nodes` stored from a previous pass.
15939 */
15940 function reusePreviousSourceSpans(nodes, previousI18n) {
15941 if (previousI18n instanceof Message) {
15942 // The `previousI18n` is an i18n `Message`, so we are processing an `Attribute` with i18n
15943 // metadata. The `Message` should consist only of a single `Container` that contains the
15944 // parts (`Text` and `Placeholder`) to process.
15945 assertSingleContainerMessage(previousI18n);
15946 previousI18n = previousI18n.nodes[0];
15947 }
15948 if (previousI18n instanceof Container) {
15949 // The `previousI18n` is a `Container`, which means that this is a second i18n extraction pass
15950 // after whitespace has been removed from the AST ndoes.
15951 assertEquivalentNodes(previousI18n.children, nodes);
15952 // Reuse the source-spans from the first pass.
15953 for (let i = 0; i < nodes.length; i++) {
15954 nodes[i].sourceSpan = previousI18n.children[i].sourceSpan;
15955 }
15956 }
15957 }
15958 /**
15959 * Asserts that the `message` contains exactly one `Container` node.
15960 */
15961 function assertSingleContainerMessage(message) {
15962 const nodes = message.nodes;
15963 if (nodes.length !== 1 || !(nodes[0] instanceof Container)) {
15964 throw new Error('Unexpected previous i18n message - expected it to consist of only a single `Container` node.');
15965 }
15966 }
15967 /**
15968 * Asserts that the `previousNodes` and `node` collections have the same number of elements and
15969 * corresponding elements have the same node type.
15970 */
15971 function assertEquivalentNodes(previousNodes, nodes) {
15972 if (previousNodes.length !== nodes.length) {
15973 throw new Error('The number of i18n message children changed between first and second pass.');
15974 }
15975 if (previousNodes.some((node, i) => nodes[i].constructor !== node.constructor)) {
15976 throw new Error('The types of the i18n message children changed between first and second pass.');
15977 }
15978 }
15979 /**
15980 * Create a new `ParseSourceSpan` from the `sourceSpan`, offset by the `start` and `end` values.
15981 */
15982 function getOffsetSourceSpan(sourceSpan, { start, end }) {
15983 return new ParseSourceSpan(sourceSpan.fullStart.moveBy(start), sourceSpan.fullStart.moveBy(end));
15984 }
15985 const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
15986 function extractPlaceholderName(input) {
15987 return input.split(_CUSTOM_PH_EXP)[2];
15988 }
15989
15990 /**
15991 * @license
15992 * Copyright Google LLC All Rights Reserved.
15993 *
15994 * Use of this source code is governed by an MIT-style license that can be
15995 * found in the LICENSE file at https://angular.io/license
15996 */
15997 /**
15998 * An i18n error.
15999 */
16000 class I18nError extends ParseError {
16001 constructor(span, msg) {
16002 super(span, msg);
16003 }
16004 }
16005
16006 /**
16007 * @license
16008 * Copyright Google LLC All Rights Reserved.
16009 *
16010 * Use of this source code is governed by an MIT-style license that can be
16011 * found in the LICENSE file at https://angular.io/license
16012 */
16013 const setI18nRefs = (htmlNode, i18nNode) => {
16014 if (htmlNode instanceof NodeWithI18n) {
16015 if (i18nNode instanceof IcuPlaceholder && htmlNode.i18n instanceof Message) {
16016 // This html node represents an ICU but this is a second processing pass, and the legacy id
16017 // was computed in the previous pass and stored in the `i18n` property as a message.
16018 // We are about to wipe out that property so capture the previous message to be reused when
16019 // generating the message for this ICU later. See `_generateI18nMessage()`.
16020 i18nNode.previousMessage = htmlNode.i18n;
16021 }
16022 htmlNode.i18n = i18nNode;
16023 }
16024 return i18nNode;
16025 };
16026 /**
16027 * This visitor walks over HTML parse tree and converts information stored in
16028 * i18n-related attributes ("i18n" and "i18n-*") into i18n meta object that is
16029 * stored with other element's and attribute's information.
16030 */
16031 class I18nMetaVisitor {
16032 constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false) {
16033 this.interpolationConfig = interpolationConfig;
16034 this.keepI18nAttrs = keepI18nAttrs;
16035 this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat;
16036 // whether visited nodes contain i18n information
16037 this.hasI18nMeta = false;
16038 this._errors = [];
16039 // i18n message generation factory
16040 this._createI18nMessage = createI18nMessageFactory(this.interpolationConfig);
16041 }
16042 _generateI18nMessage(nodes, meta = '', visitNodeFn) {
16043 const { meaning, description, customId } = this._parseMetadata(meta);
16044 const message = this._createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
16045 this._setMessageId(message, meta);
16046 this._setLegacyIds(message, meta);
16047 return message;
16048 }
16049 visitAllWithErrors(nodes) {
16050 const result = nodes.map(node => node.visit(this, null));
16051 return new ParseTreeResult(result, this._errors);
16052 }
16053 visitElement(element) {
16054 if (hasI18nAttrs(element)) {
16055 this.hasI18nMeta = true;
16056 const attrs = [];
16057 const attrsMeta = {};
16058 for (const attr of element.attrs) {
16059 if (attr.name === I18N_ATTR) {
16060 // root 'i18n' node attribute
16061 const i18n = element.i18n || attr.value;
16062 const message = this._generateI18nMessage(element.children, i18n, setI18nRefs);
16063 // do not assign empty i18n meta
16064 if (message.nodes.length) {
16065 element.i18n = message;
16066 }
16067 }
16068 else if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
16069 // 'i18n-*' attributes
16070 const name = attr.name.slice(I18N_ATTR_PREFIX.length);
16071 if (isTrustedTypesSink(element.name, name)) {
16072 this._reportError(attr, `Translating attribute '${name}' is disallowed for security reasons.`);
16073 }
16074 else {
16075 attrsMeta[name] = attr.value;
16076 }
16077 }
16078 else {
16079 // non-i18n attributes
16080 attrs.push(attr);
16081 }
16082 }
16083 // set i18n meta for attributes
16084 if (Object.keys(attrsMeta).length) {
16085 for (const attr of attrs) {
16086 const meta = attrsMeta[attr.name];
16087 // do not create translation for empty attributes
16088 if (meta !== undefined && attr.value) {
16089 attr.i18n = this._generateI18nMessage([attr], attr.i18n || meta);
16090 }
16091 }
16092 }
16093 if (!this.keepI18nAttrs) {
16094 // update element's attributes,
16095 // keeping only non-i18n related ones
16096 element.attrs = attrs;
16097 }
16098 }
16099 visitAll$1(this, element.children, element.i18n);
16100 return element;
16101 }
16102 visitExpansion(expansion, currentMessage) {
16103 let message;
16104 const meta = expansion.i18n;
16105 this.hasI18nMeta = true;
16106 if (meta instanceof IcuPlaceholder) {
16107 // set ICU placeholder name (e.g. "ICU_1"),
16108 // generated while processing root element contents,
16109 // so we can reference it when we output translation
16110 const name = meta.name;
16111 message = this._generateI18nMessage([expansion], meta);
16112 const icu = icuFromI18nMessage(message);
16113 icu.name = name;
16114 }
16115 else {
16116 // ICU is a top level message, try to use metadata from container element if provided via
16117 // `context` argument. Note: context may not be available for standalone ICUs (without
16118 // wrapping element), so fallback to ICU metadata in this case.
16119 message = this._generateI18nMessage([expansion], currentMessage || meta);
16120 }
16121 expansion.i18n = message;
16122 return expansion;
16123 }
16124 visitText(text) {
16125 return text;
16126 }
16127 visitAttribute(attribute) {
16128 return attribute;
16129 }
16130 visitComment(comment) {
16131 return comment;
16132 }
16133 visitExpansionCase(expansionCase) {
16134 return expansionCase;
16135 }
16136 /**
16137 * Parse the general form `meta` passed into extract the explicit metadata needed to create a
16138 * `Message`.
16139 *
16140 * There are three possibilities for the `meta` variable
16141 * 1) a string from an `i18n` template attribute: parse it to extract the metadata values.
16142 * 2) a `Message` from a previous processing pass: reuse the metadata values in the message.
16143 * 4) other: ignore this and just process the message metadata as normal
16144 *
16145 * @param meta the bucket that holds information about the message
16146 * @returns the parsed metadata.
16147 */
16148 _parseMetadata(meta) {
16149 return typeof meta === 'string' ? parseI18nMeta(meta) :
16150 meta instanceof Message ? meta : {};
16151 }
16152 /**
16153 * Generate (or restore) message id if not specified already.
16154 */
16155 _setMessageId(message, meta) {
16156 if (!message.id) {
16157 message.id = meta instanceof Message && meta.id || decimalDigest(message);
16158 }
16159 }
16160 /**
16161 * Update the `message` with a `legacyId` if necessary.
16162 *
16163 * @param message the message whose legacy id should be set
16164 * @param meta information about the message being processed
16165 */
16166 _setLegacyIds(message, meta) {
16167 if (this.enableI18nLegacyMessageIdFormat) {
16168 message.legacyIds = [computeDigest(message), computeDecimalDigest(message)];
16169 }
16170 else if (typeof meta !== 'string') {
16171 // This occurs if we are doing the 2nd pass after whitespace removal (see `parseTemplate()` in
16172 // `packages/compiler/src/render3/view/template.ts`).
16173 // In that case we want to reuse the legacy message generated in the 1st pass (see
16174 // `setI18nRefs()`).
16175 const previousMessage = meta instanceof Message ?
16176 meta :
16177 meta instanceof IcuPlaceholder ? meta.previousMessage : undefined;
16178 message.legacyIds = previousMessage ? previousMessage.legacyIds : [];
16179 }
16180 }
16181 _reportError(node, msg) {
16182 this._errors.push(new I18nError(node.sourceSpan, msg));
16183 }
16184 }
16185 /** I18n separators for metadata **/
16186 const I18N_MEANING_SEPARATOR = '|';
16187 const I18N_ID_SEPARATOR = '@@';
16188 /**
16189 * Parses i18n metas like:
16190 * - "@@id",
16191 * - "description[@@id]",
16192 * - "meaning|description[@@id]"
16193 * and returns an object with parsed output.
16194 *
16195 * @param meta String that represents i18n meta
16196 * @returns Object with id, meaning and description fields
16197 */
16198 function parseI18nMeta(meta = '') {
16199 let customId;
16200 let meaning;
16201 let description;
16202 meta = meta.trim();
16203 if (meta) {
16204 const idIndex = meta.indexOf(I18N_ID_SEPARATOR);
16205 const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
16206 let meaningAndDesc;
16207 [meaningAndDesc, customId] =
16208 (idIndex > -1) ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''];
16209 [meaning, description] = (descIndex > -1) ?
16210 [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
16211 ['', meaningAndDesc];
16212 }
16213 return { customId, meaning, description };
16214 }
16215 // Converts i18n meta information for a message (id, description, meaning)
16216 // to a JsDoc statement formatted as expected by the Closure compiler.
16217 function i18nMetaToJSDoc(meta) {
16218 const tags = [];
16219 if (meta.description) {
16220 tags.push({ tagName: "desc" /* Desc */, text: meta.description });
16221 }
16222 if (meta.meaning) {
16223 tags.push({ tagName: "meaning" /* Meaning */, text: meta.meaning });
16224 }
16225 return tags.length == 0 ? null : jsDocComment(tags);
16226 }
16227
16228 /** Closure uses `goog.getMsg(message)` to lookup translations */
16229 const GOOG_GET_MSG = 'goog.getMsg';
16230 function createGoogleGetMsgStatements(variable$1, message, closureVar, params) {
16231 const messageString = serializeI18nMessageForGetMsg(message);
16232 const args = [literal(messageString)];
16233 if (Object.keys(params).length) {
16234 args.push(mapLiteral(params, true));
16235 }
16236 // /**
16237 // * @desc description of message
16238 // * @meaning meaning of message
16239 // */
16240 // const MSG_... = goog.getMsg(..);
16241 // I18N_X = MSG_...;
16242 const googGetMsgStmt = closureVar.set(variable(GOOG_GET_MSG).callFn(args)).toConstDecl();
16243 const metaComment = i18nMetaToJSDoc(message);
16244 if (metaComment !== null) {
16245 googGetMsgStmt.addLeadingComment(metaComment);
16246 }
16247 const i18nAssignmentStmt = new ExpressionStatement(variable$1.set(closureVar));
16248 return [googGetMsgStmt, i18nAssignmentStmt];
16249 }
16250 /**
16251 * This visitor walks over i18n tree and generates its string representation, including ICUs and
16252 * placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format.
16253 */
16254 class GetMsgSerializerVisitor {
16255 formatPh(value) {
16256 return `{$${formatI18nPlaceholderName(value)}}`;
16257 }
16258 visitText(text) {
16259 return text.value;
16260 }
16261 visitContainer(container) {
16262 return container.children.map(child => child.visit(this)).join('');
16263 }
16264 visitIcu(icu) {
16265 return serializeIcuNode(icu);
16266 }
16267 visitTagPlaceholder(ph) {
16268 return ph.isVoid ?
16269 this.formatPh(ph.startName) :
16270 `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
16271 }
16272 visitPlaceholder(ph) {
16273 return this.formatPh(ph.name);
16274 }
16275 visitIcuPlaceholder(ph, context) {
16276 return this.formatPh(ph.name);
16277 }
16278 }
16279 const serializerVisitor$1 = new GetMsgSerializerVisitor();
16280 function serializeI18nMessageForGetMsg(message) {
16281 return message.nodes.map(node => node.visit(serializerVisitor$1, null)).join('');
16282 }
16283
16284 function createLocalizeStatements(variable, message, params) {
16285 const { messageParts, placeHolders } = serializeI18nMessageForLocalize(message);
16286 const sourceSpan = getSourceSpan(message);
16287 const expressions = placeHolders.map(ph => params[ph.text]);
16288 const localizedString$1 = localizedString(message, messageParts, placeHolders, expressions, sourceSpan);
16289 const variableInitialization = variable.set(localizedString$1);
16290 return [new ExpressionStatement(variableInitialization)];
16291 }
16292 /**
16293 * This visitor walks over an i18n tree, capturing literal strings and placeholders.
16294 *
16295 * The result can be used for generating the `$localize` tagged template literals.
16296 */
16297 class LocalizeSerializerVisitor {
16298 visitText(text, context) {
16299 if (context[context.length - 1] instanceof LiteralPiece) {
16300 // Two literal pieces in a row means that there was some comment node in-between.
16301 context[context.length - 1].text += text.value;
16302 }
16303 else {
16304 context.push(new LiteralPiece(text.value, text.sourceSpan));
16305 }
16306 }
16307 visitContainer(container, context) {
16308 container.children.forEach(child => child.visit(this, context));
16309 }
16310 visitIcu(icu, context) {
16311 context.push(new LiteralPiece(serializeIcuNode(icu), icu.sourceSpan));
16312 }
16313 visitTagPlaceholder(ph, context) {
16314 var _a, _b;
16315 context.push(this.createPlaceholderPiece(ph.startName, (_a = ph.startSourceSpan) !== null && _a !== void 0 ? _a : ph.sourceSpan));
16316 if (!ph.isVoid) {
16317 ph.children.forEach(child => child.visit(this, context));
16318 context.push(this.createPlaceholderPiece(ph.closeName, (_b = ph.endSourceSpan) !== null && _b !== void 0 ? _b : ph.sourceSpan));
16319 }
16320 }
16321 visitPlaceholder(ph, context) {
16322 context.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
16323 }
16324 visitIcuPlaceholder(ph, context) {
16325 context.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
16326 }
16327 createPlaceholderPiece(name, sourceSpan) {
16328 return new PlaceholderPiece(formatI18nPlaceholderName(name, /* useCamelCase */ false), sourceSpan);
16329 }
16330 }
16331 const serializerVisitor$2 = new LocalizeSerializerVisitor();
16332 /**
16333 * Serialize an i18n message into two arrays: messageParts and placeholders.
16334 *
16335 * These arrays will be used to generate `$localize` tagged template literals.
16336 *
16337 * @param message The message to be serialized.
16338 * @returns an object containing the messageParts and placeholders.
16339 */
16340 function serializeI18nMessageForLocalize(message) {
16341 const pieces = [];
16342 message.nodes.forEach(node => node.visit(serializerVisitor$2, pieces));
16343 return processMessagePieces(pieces);
16344 }
16345 function getSourceSpan(message) {
16346 const startNode = message.nodes[0];
16347 const endNode = message.nodes[message.nodes.length - 1];
16348 return new ParseSourceSpan(startNode.sourceSpan.start, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details);
16349 }
16350 /**
16351 * Convert the list of serialized MessagePieces into two arrays.
16352 *
16353 * One contains the literal string pieces and the other the placeholders that will be replaced by
16354 * expressions when rendering `$localize` tagged template literals.
16355 *
16356 * @param pieces The pieces to process.
16357 * @returns an object containing the messageParts and placeholders.
16358 */
16359 function processMessagePieces(pieces) {
16360 const messageParts = [];
16361 const placeHolders = [];
16362 if (pieces[0] instanceof PlaceholderPiece) {
16363 // The first piece was a placeholder so we need to add an initial empty message part.
16364 messageParts.push(createEmptyMessagePart(pieces[0].sourceSpan.start));
16365 }
16366 for (let i = 0; i < pieces.length; i++) {
16367 const part = pieces[i];
16368 if (part instanceof LiteralPiece) {
16369 messageParts.push(part);
16370 }
16371 else {
16372 placeHolders.push(part);
16373 if (pieces[i - 1] instanceof PlaceholderPiece) {
16374 // There were two placeholders in a row, so we need to add an empty message part.
16375 messageParts.push(createEmptyMessagePart(pieces[i - 1].sourceSpan.end));
16376 }
16377 }
16378 }
16379 if (pieces[pieces.length - 1] instanceof PlaceholderPiece) {
16380 // The last piece was a placeholder so we need to add a final empty message part.
16381 messageParts.push(createEmptyMessagePart(pieces[pieces.length - 1].sourceSpan.end));
16382 }
16383 return { messageParts, placeHolders };
16384 }
16385 function createEmptyMessagePart(location) {
16386 return new LiteralPiece('', new ParseSourceSpan(location, location));
16387 }
16388
16389 /**
16390 * @license
16391 * Copyright Google LLC All Rights Reserved.
16392 *
16393 * Use of this source code is governed by an MIT-style license that can be
16394 * found in the LICENSE file at https://angular.io/license
16395 */
16396 // Selector attribute name of `<ng-content>`
16397 const NG_CONTENT_SELECT_ATTR$1 = 'select';
16398 // Attribute name of `ngProjectAs`.
16399 const NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs';
16400 // Global symbols available only inside event bindings.
16401 const EVENT_BINDING_SCOPE_GLOBALS = new Set(['$event']);
16402 // List of supported global targets for event listeners
16403 const GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers$1.resolveWindow], ['document', Identifiers$1.resolveDocument], ['body', Identifiers$1.resolveBody]]);
16404 const LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t'];
16405 // if (rf & flags) { .. }
16406 function renderFlagCheckIfStmt(flags, statements) {
16407 return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null, false), statements);
16408 }
16409 function prepareEventListenerParameters(eventAst, handlerName = null, scope = null) {
16410 const { type, name, target, phase, handler } = eventAst;
16411 if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) {
16412 throw new Error(`Unexpected global target '${target}' defined for '${name}' event.
16413 Supported list of global targets: ${Array.from(GLOBAL_TARGET_RESOLVERS.keys())}.`);
16414 }
16415 const eventArgumentName = '$event';
16416 const implicitReceiverAccesses = new Set();
16417 const implicitReceiverExpr = (scope === null || scope.bindingLevel === 0) ?
16418 variable(CONTEXT_NAME) :
16419 scope.getOrCreateSharedContextVar(0);
16420 const bindingExpr = convertActionBinding(scope, implicitReceiverExpr, handler, 'b', () => error('Unexpected interpolation'), eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS);
16421 const statements = [];
16422 if (scope) {
16423 statements.push(...scope.restoreViewStatement());
16424 statements.push(...scope.variableDeclarations());
16425 }
16426 statements.push(...bindingExpr.render3Stmts);
16427 const eventName = type === 1 /* Animation */ ? prepareSyntheticListenerName(name, phase) : name;
16428 const fnName = handlerName && sanitizeIdentifier(handlerName);
16429 const fnArgs = [];
16430 if (implicitReceiverAccesses.has(eventArgumentName)) {
16431 fnArgs.push(new FnParam(eventArgumentName, DYNAMIC_TYPE));
16432 }
16433 const handlerFn = fn(fnArgs, statements, INFERRED_TYPE, null, fnName);
16434 const params = [literal(eventName), handlerFn];
16435 if (target) {
16436 params.push(literal(false), // `useCapture` flag, defaults to `false`
16437 importExpr(GLOBAL_TARGET_RESOLVERS.get(target)));
16438 }
16439 return params;
16440 }
16441 function createComponentDefConsts() {
16442 return {
16443 prepareStatements: [],
16444 constExpressions: [],
16445 i18nVarRefsCache: new Map(),
16446 };
16447 }
16448 class TemplateDefinitionBuilder {
16449 constructor(constantPool, parentBindingScope, level = 0, contextName, i18nContext, templateIndex, templateName, directiveMatcher, directives, pipeTypeByName, pipes, _namespace, relativeContextFilePath, i18nUseExternalIds, _constants = createComponentDefConsts()) {
16450 this.constantPool = constantPool;
16451 this.level = level;
16452 this.contextName = contextName;
16453 this.i18nContext = i18nContext;
16454 this.templateIndex = templateIndex;
16455 this.templateName = templateName;
16456 this.directiveMatcher = directiveMatcher;
16457 this.directives = directives;
16458 this.pipeTypeByName = pipeTypeByName;
16459 this.pipes = pipes;
16460 this._namespace = _namespace;
16461 this.i18nUseExternalIds = i18nUseExternalIds;
16462 this._constants = _constants;
16463 this._dataIndex = 0;
16464 this._bindingContext = 0;
16465 this._prefixCode = [];
16466 /**
16467 * List of callbacks to generate creation mode instructions. We store them here as we process
16468 * the template so bindings in listeners are resolved only once all nodes have been visited.
16469 * This ensures all local refs and context variables are available for matching.
16470 */
16471 this._creationCodeFns = [];
16472 /**
16473 * List of callbacks to generate update mode instructions. We store them here as we process
16474 * the template so bindings are resolved only once all nodes have been visited. This ensures
16475 * all local refs and context variables are available for matching.
16476 */
16477 this._updateCodeFns = [];
16478 /** Index of the currently-selected node. */
16479 this._currentIndex = 0;
16480 /** Temporary variable declarations generated from visiting pipes, literals, etc. */
16481 this._tempVariables = [];
16482 /**
16483 * List of callbacks to build nested templates. Nested templates must not be visited until
16484 * after the parent template has finished visiting all of its nodes. This ensures that all
16485 * local ref bindings in nested templates are able to find local ref values if the refs
16486 * are defined after the template declaration.
16487 */
16488 this._nestedTemplateFns = [];
16489 this._unsupported = unsupported;
16490 // i18n context local to this template
16491 this.i18n = null;
16492 // Number of slots to reserve for pureFunctions
16493 this._pureFunctionSlots = 0;
16494 // Number of binding slots
16495 this._bindingSlots = 0;
16496 // Projection slots found in the template. Projection slots can distribute projected
16497 // nodes based on a selector, or can just use the wildcard selector to match
16498 // all nodes which aren't matching any selector.
16499 this._ngContentReservedSlots = [];
16500 // Number of non-default selectors found in all parent templates of this template. We need to
16501 // track it to properly adjust projection slot index in the `projection` instruction.
16502 this._ngContentSelectorsOffset = 0;
16503 // Expression that should be used as implicit receiver when converting template
16504 // expressions to output AST.
16505 this._implicitReceiverExpr = null;
16506 // These should be handled in the template or element directly.
16507 this.visitReference = invalid$1;
16508 this.visitVariable = invalid$1;
16509 this.visitTextAttribute = invalid$1;
16510 this.visitBoundAttribute = invalid$1;
16511 this.visitBoundEvent = invalid$1;
16512 this._bindingScope = parentBindingScope.nestedScope(level);
16513 // Turn the relative context file path into an identifier by replacing non-alphanumeric
16514 // characters with underscores.
16515 this.fileBasedI18nSuffix = relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_') + '_';
16516 this._valueConverter = new ValueConverter(constantPool, () => this.allocateDataSlot(), (numSlots) => this.allocatePureFunctionSlots(numSlots), (name, localName, slot, value) => {
16517 const pipeType = pipeTypeByName.get(name);
16518 if (pipeType) {
16519 this.pipes.add(pipeType);
16520 }
16521 this._bindingScope.set(this.level, localName, value);
16522 this.creationInstruction(null, Identifiers$1.pipe, [literal(slot), literal(name)]);
16523 });
16524 }
16525 buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n) {
16526 this._ngContentSelectorsOffset = ngContentSelectorsOffset;
16527 if (this._namespace !== Identifiers$1.namespaceHTML) {
16528 this.creationInstruction(null, this._namespace);
16529 }
16530 // Create variable bindings
16531 variables.forEach(v => this.registerContextVariables(v));
16532 // Initiate i18n context in case:
16533 // - this template has parent i18n context
16534 // - or the template has i18n meta associated with it,
16535 // but it's not initiated by the Element (e.g. <ng-template i18n>)
16536 const initI18nContext = this.i18nContext ||
16537 (isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) &&
16538 !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n));
16539 const selfClosingI18nInstruction = hasTextChildrenOnly(nodes);
16540 if (initI18nContext) {
16541 this.i18nStart(null, i18n, selfClosingI18nInstruction);
16542 }
16543 // This is the initial pass through the nodes of this template. In this pass, we
16544 // queue all creation mode and update mode instructions for generation in the second
16545 // pass. It's necessary to separate the passes to ensure local refs are defined before
16546 // resolving bindings. We also count bindings in this pass as we walk bound expressions.
16547 visitAll(this, nodes);
16548 // Add total binding count to pure function count so pure function instructions are
16549 // generated with the correct slot offset when update instructions are processed.
16550 this._pureFunctionSlots += this._bindingSlots;
16551 // Pipes are walked in the first pass (to enqueue `pipe()` creation instructions and
16552 // `pipeBind` update instructions), so we have to update the slot offsets manually
16553 // to account for bindings.
16554 this._valueConverter.updatePipeSlotOffsets(this._bindingSlots);
16555 // Nested templates must be processed before creation instructions so template()
16556 // instructions can be generated with the correct internal const count.
16557 this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn());
16558 // Output the `projectionDef` instruction when some `<ng-content>` tags are present.
16559 // The `projectionDef` instruction is only emitted for the component template and
16560 // is skipped for nested templates (<ng-template> tags).
16561 if (this.level === 0 && this._ngContentReservedSlots.length) {
16562 const parameters = [];
16563 // By default the `projectionDef` instructions creates one slot for the wildcard
16564 // selector if no parameters are passed. Therefore we only want to allocate a new
16565 // array for the projection slots if the default projection slot is not sufficient.
16566 if (this._ngContentReservedSlots.length > 1 || this._ngContentReservedSlots[0] !== '*') {
16567 const r3ReservedSlots = this._ngContentReservedSlots.map(s => s !== '*' ? parseSelectorToR3Selector(s) : s);
16568 parameters.push(this.constantPool.getConstLiteral(asLiteral(r3ReservedSlots), true));
16569 }
16570 // Since we accumulate ngContent selectors while processing template elements,
16571 // we *prepend* `projectionDef` to creation instructions block, to put it before
16572 // any `projection` instructions
16573 this.creationInstruction(null, Identifiers$1.projectionDef, parameters, /* prepend */ true);
16574 }
16575 if (initI18nContext) {
16576 this.i18nEnd(null, selfClosingI18nInstruction);
16577 }
16578 // Generate all the creation mode instructions (e.g. resolve bindings in listeners)
16579 const creationStatements = this._creationCodeFns.map((fn) => fn());
16580 // Generate all the update mode instructions (e.g. resolve property or text bindings)
16581 const updateStatements = this._updateCodeFns.map((fn) => fn());
16582 // Variable declaration must occur after binding resolution so we can generate context
16583 // instructions that build on each other.
16584 // e.g. const b = nextContext().$implicit(); const b = nextContext();
16585 const creationVariables = this._bindingScope.viewSnapshotStatements();
16586 const updateVariables = this._bindingScope.variableDeclarations().concat(this._tempVariables);
16587 const creationBlock = creationStatements.length > 0 ?
16588 [renderFlagCheckIfStmt(1 /* Create */, creationVariables.concat(creationStatements))] :
16589 [];
16590 const updateBlock = updateStatements.length > 0 ?
16591 [renderFlagCheckIfStmt(2 /* Update */, updateVariables.concat(updateStatements))] :
16592 [];
16593 return fn(
16594 // i.e. (rf: RenderFlags, ctx: any)
16595 [new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
16596 // Temporary variable declarations for query refresh (i.e. let _t: any;)
16597 ...this._prefixCode,
16598 // Creating mode (i.e. if (rf & RenderFlags.Create) { ... })
16599 ...creationBlock,
16600 // Binding and refresh mode (i.e. if (rf & RenderFlags.Update) {...})
16601 ...updateBlock,
16602 ], INFERRED_TYPE, null, this.templateName);
16603 }
16604 // LocalResolver
16605 getLocal(name) {
16606 return this._bindingScope.get(name);
16607 }
16608 // LocalResolver
16609 notifyImplicitReceiverUse() {
16610 this._bindingScope.notifyImplicitReceiverUse();
16611 }
16612 i18nTranslate(message, params = {}, ref, transformFn) {
16613 const _ref = ref || this.i18nGenerateMainBlockVar();
16614 // Closure Compiler requires const names to start with `MSG_` but disallows any other const to
16615 // start with `MSG_`. We define a variable starting with `MSG_` just for the `goog.getMsg` call
16616 const closureVar = this.i18nGenerateClosureVar(message.id);
16617 const statements = getTranslationDeclStmts(message, _ref, closureVar, params, transformFn);
16618 this._constants.prepareStatements.push(...statements);
16619 return _ref;
16620 }
16621 registerContextVariables(variable$1) {
16622 const scopedName = this._bindingScope.freshReferenceName();
16623 const retrievalLevel = this.level;
16624 const lhs = variable(variable$1.name + scopedName);
16625 this._bindingScope.set(retrievalLevel, variable$1.name, lhs, 1 /* CONTEXT */, (scope, relativeLevel) => {
16626 let rhs;
16627 if (scope.bindingLevel === retrievalLevel) {
16628 // e.g. ctx
16629 rhs = variable(CONTEXT_NAME);
16630 }
16631 else {
16632 const sharedCtxVar = scope.getSharedContextName(retrievalLevel);
16633 // e.g. ctx_r0 OR x(2);
16634 rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel);
16635 }
16636 // e.g. const $item$ = x(2).$implicit;
16637 return [lhs.set(rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()];
16638 });
16639 }
16640 i18nAppendBindings(expressions) {
16641 if (expressions.length > 0) {
16642 expressions.forEach(expression => this.i18n.appendBinding(expression));
16643 }
16644 }
16645 i18nBindProps(props) {
16646 const bound = {};
16647 Object.keys(props).forEach(key => {
16648 const prop = props[key];
16649 if (prop instanceof Text) {
16650 bound[key] = literal(prop.value);
16651 }
16652 else {
16653 const value = prop.value.visit(this._valueConverter);
16654 this.allocateBindingSlots(value);
16655 if (value instanceof Interpolation) {
16656 const { strings, expressions } = value;
16657 const { id, bindings } = this.i18n;
16658 const label = assembleI18nBoundString(strings, bindings.size, id);
16659 this.i18nAppendBindings(expressions);
16660 bound[key] = literal(label);
16661 }
16662 }
16663 });
16664 return bound;
16665 }
16666 // Generates top level vars for i18n blocks (i.e. `i18n_N`).
16667 i18nGenerateMainBlockVar() {
16668 return variable(this.constantPool.uniqueName(TRANSLATION_VAR_PREFIX));
16669 }
16670 // Generates vars with Closure-specific names for i18n blocks (i.e. `MSG_XXX`).
16671 i18nGenerateClosureVar(messageId) {
16672 let name;
16673 const suffix = this.fileBasedI18nSuffix.toUpperCase();
16674 if (this.i18nUseExternalIds) {
16675 const prefix = getTranslationConstPrefix(`EXTERNAL_`);
16676 const uniqueSuffix = this.constantPool.uniqueName(suffix);
16677 name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`;
16678 }
16679 else {
16680 const prefix = getTranslationConstPrefix(suffix);
16681 name = this.constantPool.uniqueName(prefix);
16682 }
16683 return variable(name);
16684 }
16685 i18nUpdateRef(context) {
16686 const { icus, meta, isRoot, isResolved, isEmitted } = context;
16687 if (isRoot && isResolved && !isEmitted && !isSingleI18nIcu(meta)) {
16688 context.isEmitted = true;
16689 const placeholders = context.getSerializedPlaceholders();
16690 let icuMapping = {};
16691 let params = placeholders.size ? placeholdersToParams(placeholders) : {};
16692 if (icus.size) {
16693 icus.forEach((refs, key) => {
16694 if (refs.length === 1) {
16695 // if we have one ICU defined for a given
16696 // placeholder - just output its reference
16697 params[key] = refs[0];
16698 }
16699 else {
16700 // ... otherwise we need to activate post-processing
16701 // to replace ICU placeholders with proper values
16702 const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX}${key}`);
16703 params[key] = literal(placeholder);
16704 icuMapping[key] = literalArr(refs);
16705 }
16706 });
16707 }
16708 // translation requires post processing in 2 cases:
16709 // - if we have placeholders with multiple values (ex. `START_DIV`: [�#1�, �#2�, ...])
16710 // - if we have multiple ICUs that refer to the same placeholder name
16711 const needsPostprocessing = Array.from(placeholders.values()).some((value) => value.length > 1) ||
16712 Object.keys(icuMapping).length;
16713 let transformFn;
16714 if (needsPostprocessing) {
16715 transformFn = (raw) => {
16716 const args = [raw];
16717 if (Object.keys(icuMapping).length) {
16718 args.push(mapLiteral(icuMapping, true));
16719 }
16720 return instruction(null, Identifiers$1.i18nPostprocess, args);
16721 };
16722 }
16723 this.i18nTranslate(meta, params, context.ref, transformFn);
16724 }
16725 }
16726 i18nStart(span = null, meta, selfClosing) {
16727 const index = this.allocateDataSlot();
16728 this.i18n = this.i18nContext ?
16729 this.i18nContext.forkChildContext(index, this.templateIndex, meta) :
16730 new I18nContext(index, this.i18nGenerateMainBlockVar(), 0, this.templateIndex, meta);
16731 // generate i18nStart instruction
16732 const { id, ref } = this.i18n;
16733 const params = [literal(index), this.addToConsts(ref)];
16734 if (id > 0) {
16735 // do not push 3rd argument (sub-block id)
16736 // into i18nStart call for top level i18n context
16737 params.push(literal(id));
16738 }
16739 this.creationInstruction(span, selfClosing ? Identifiers$1.i18n : Identifiers$1.i18nStart, params);
16740 }
16741 i18nEnd(span = null, selfClosing) {
16742 if (!this.i18n) {
16743 throw new Error('i18nEnd is executed with no i18n context present');
16744 }
16745 if (this.i18nContext) {
16746 this.i18nContext.reconcileChildContext(this.i18n);
16747 this.i18nUpdateRef(this.i18nContext);
16748 }
16749 else {
16750 this.i18nUpdateRef(this.i18n);
16751 }
16752 // setup accumulated bindings
16753 const { index, bindings } = this.i18n;
16754 if (bindings.size) {
16755 const chainBindings = [];
16756 bindings.forEach(binding => {
16757 chainBindings.push({ sourceSpan: span, value: () => this.convertPropertyBinding(binding) });
16758 });
16759 // for i18n block, advance to the most recent element index (by taking the current number of
16760 // elements and subtracting one) before invoking `i18nExp` instructions, to make sure the
16761 // necessary lifecycle hooks of components/directives are properly flushed.
16762 this.updateInstructionChainWithAdvance(this.getConstCount() - 1, Identifiers$1.i18nExp, chainBindings);
16763 this.updateInstruction(span, Identifiers$1.i18nApply, [literal(index)]);
16764 }
16765 if (!selfClosing) {
16766 this.creationInstruction(span, Identifiers$1.i18nEnd);
16767 }
16768 this.i18n = null; // reset local i18n context
16769 }
16770 i18nAttributesInstruction(nodeIndex, attrs, sourceSpan) {
16771 let hasBindings = false;
16772 const i18nAttrArgs = [];
16773 const bindings = [];
16774 attrs.forEach(attr => {
16775 const message = attr.i18n;
16776 const converted = attr.value.visit(this._valueConverter);
16777 this.allocateBindingSlots(converted);
16778 if (converted instanceof Interpolation) {
16779 const placeholders = assembleBoundTextPlaceholders(message);
16780 const params = placeholdersToParams(placeholders);
16781 i18nAttrArgs.push(literal(attr.name), this.i18nTranslate(message, params));
16782 converted.expressions.forEach(expression => {
16783 hasBindings = true;
16784 bindings.push({
16785 sourceSpan,
16786 value: () => this.convertPropertyBinding(expression),
16787 });
16788 });
16789 }
16790 });
16791 if (bindings.length > 0) {
16792 this.updateInstructionChainWithAdvance(nodeIndex, Identifiers$1.i18nExp, bindings);
16793 }
16794 if (i18nAttrArgs.length > 0) {
16795 const index = literal(this.allocateDataSlot());
16796 const constIndex = this.addToConsts(literalArr(i18nAttrArgs));
16797 this.creationInstruction(sourceSpan, Identifiers$1.i18nAttributes, [index, constIndex]);
16798 if (hasBindings) {
16799 this.updateInstruction(sourceSpan, Identifiers$1.i18nApply, [index]);
16800 }
16801 }
16802 }
16803 getNamespaceInstruction(namespaceKey) {
16804 switch (namespaceKey) {
16805 case 'math':
16806 return Identifiers$1.namespaceMathML;
16807 case 'svg':
16808 return Identifiers$1.namespaceSVG;
16809 default:
16810 return Identifiers$1.namespaceHTML;
16811 }
16812 }
16813 addNamespaceInstruction(nsInstruction, element) {
16814 this._namespace = nsInstruction;
16815 this.creationInstruction(element.startSourceSpan, nsInstruction);
16816 }
16817 /**
16818 * Adds an update instruction for an interpolated property or attribute, such as
16819 * `prop="{{value}}"` or `attr.title="{{value}}"`
16820 */
16821 interpolatedUpdateInstruction(instruction, elementIndex, attrName, input, value, params) {
16822 this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, instruction, () => [literal(attrName), ...this.getUpdateInstructionArguments(value), ...params]);
16823 }
16824 visitContent(ngContent) {
16825 const slot = this.allocateDataSlot();
16826 const projectionSlotIdx = this._ngContentSelectorsOffset + this._ngContentReservedSlots.length;
16827 const parameters = [literal(slot)];
16828 this._ngContentReservedSlots.push(ngContent.selector);
16829 const nonContentSelectAttributes = ngContent.attributes.filter(attr => attr.name.toLowerCase() !== NG_CONTENT_SELECT_ATTR$1);
16830 const attributes = this.getAttributeExpressions(ngContent.name, nonContentSelectAttributes, [], []);
16831 if (attributes.length > 0) {
16832 parameters.push(literal(projectionSlotIdx), literalArr(attributes));
16833 }
16834 else if (projectionSlotIdx !== 0) {
16835 parameters.push(literal(projectionSlotIdx));
16836 }
16837 this.creationInstruction(ngContent.sourceSpan, Identifiers$1.projection, parameters);
16838 if (this.i18n) {
16839 this.i18n.appendProjection(ngContent.i18n, slot);
16840 }
16841 }
16842 visitElement(element) {
16843 var _a, _b;
16844 const elementIndex = this.allocateDataSlot();
16845 const stylingBuilder = new StylingBuilder(null);
16846 let isNonBindableMode = false;
16847 const isI18nRootElement = isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n);
16848 const outputAttrs = [];
16849 const [namespaceKey, elementName] = splitNsName(element.name);
16850 const isNgContainer$1 = isNgContainer(element.name);
16851 // Handle styling, i18n, ngNonBindable attributes
16852 for (const attr of element.attributes) {
16853 const { name, value } = attr;
16854 if (name === NON_BINDABLE_ATTR) {
16855 isNonBindableMode = true;
16856 }
16857 else if (name === 'style') {
16858 stylingBuilder.registerStyleAttr(value);
16859 }
16860 else if (name === 'class') {
16861 stylingBuilder.registerClassAttr(value);
16862 }
16863 else {
16864 outputAttrs.push(attr);
16865 }
16866 }
16867 // Match directives on non i18n attributes
16868 this.matchDirectives(element.name, element);
16869 // Regular element or ng-container creation mode
16870 const parameters = [literal(elementIndex)];
16871 if (!isNgContainer$1) {
16872 parameters.push(literal(elementName));
16873 }
16874 // Add the attributes
16875 const allOtherInputs = [];
16876 const boundI18nAttrs = [];
16877 element.inputs.forEach(input => {
16878 const stylingInputWasSet = stylingBuilder.registerBoundInput(input);
16879 if (!stylingInputWasSet) {
16880 if (input.type === 0 /* Property */ && input.i18n) {
16881 boundI18nAttrs.push(input);
16882 }
16883 else {
16884 allOtherInputs.push(input);
16885 }
16886 }
16887 });
16888 // add attributes for directive and projection matching purposes
16889 const attributes = this.getAttributeExpressions(element.name, outputAttrs, allOtherInputs, element.outputs, stylingBuilder, [], boundI18nAttrs);
16890 parameters.push(this.addAttrsToConsts(attributes));
16891 // local refs (ex.: <div #foo #bar="baz">)
16892 const refs = this.prepareRefsArray(element.references);
16893 parameters.push(this.addToConsts(refs));
16894 const wasInNamespace = this._namespace;
16895 const currentNamespace = this.getNamespaceInstruction(namespaceKey);
16896 // If the namespace is changing now, include an instruction to change it
16897 // during element creation.
16898 if (currentNamespace !== wasInNamespace) {
16899 this.addNamespaceInstruction(currentNamespace, element);
16900 }
16901 if (this.i18n) {
16902 this.i18n.appendElement(element.i18n, elementIndex);
16903 }
16904 // Note that we do not append text node instructions and ICUs inside i18n section,
16905 // so we exclude them while calculating whether current element has children
16906 const hasChildren = (!isI18nRootElement && this.i18n) ? !hasTextChildrenOnly(element.children) :
16907 element.children.length > 0;
16908 const createSelfClosingInstruction = !stylingBuilder.hasBindingsWithPipes &&
16909 element.outputs.length === 0 && boundI18nAttrs.length === 0 && !hasChildren;
16910 const createSelfClosingI18nInstruction = !createSelfClosingInstruction && hasTextChildrenOnly(element.children);
16911 if (createSelfClosingInstruction) {
16912 this.creationInstruction(element.sourceSpan, isNgContainer$1 ? Identifiers$1.elementContainer : Identifiers$1.element, trimTrailingNulls(parameters));
16913 }
16914 else {
16915 this.creationInstruction(element.startSourceSpan, isNgContainer$1 ? Identifiers$1.elementContainerStart : Identifiers$1.elementStart, trimTrailingNulls(parameters));
16916 if (isNonBindableMode) {
16917 this.creationInstruction(element.startSourceSpan, Identifiers$1.disableBindings);
16918 }
16919 if (boundI18nAttrs.length > 0) {
16920 this.i18nAttributesInstruction(elementIndex, boundI18nAttrs, (_a = element.startSourceSpan) !== null && _a !== void 0 ? _a : element.sourceSpan);
16921 }
16922 // Generate Listeners (outputs)
16923 if (element.outputs.length > 0) {
16924 const listeners = element.outputs.map((outputAst) => ({
16925 sourceSpan: outputAst.sourceSpan,
16926 params: this.prepareListenerParameter(element.name, outputAst, elementIndex)
16927 }));
16928 this.creationInstructionChain(Identifiers$1.listener, listeners);
16929 }
16930 // Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
16931 // listeners, to make sure i18nAttributes instruction targets current element at runtime.
16932 if (isI18nRootElement) {
16933 this.i18nStart(element.startSourceSpan, element.i18n, createSelfClosingI18nInstruction);
16934 }
16935 }
16936 // the code here will collect all update-level styling instructions and add them to the
16937 // update block of the template function AOT code. Instructions like `styleProp`,
16938 // `styleMap`, `classMap`, `classProp`
16939 // are all generated and assigned in the code below.
16940 const stylingInstructions = stylingBuilder.buildUpdateLevelInstructions(this._valueConverter);
16941 const limit = stylingInstructions.length - 1;
16942 for (let i = 0; i <= limit; i++) {
16943 const instruction = stylingInstructions[i];
16944 this._bindingSlots += this.processStylingUpdateInstruction(elementIndex, instruction);
16945 }
16946 // the reason why `undefined` is used is because the renderer understands this as a
16947 // special value to symbolize that there is no RHS to this binding
16948 // TODO (matsko): revisit this once FW-959 is approached
16949 const emptyValueBindInstruction = literal(undefined);
16950 const propertyBindings = [];
16951 const attributeBindings = [];
16952 // Generate element input bindings
16953 allOtherInputs.forEach(input => {
16954 const inputType = input.type;
16955 if (inputType === 4 /* Animation */) {
16956 const value = input.value.visit(this._valueConverter);
16957 // animation bindings can be presented in the following formats:
16958 // 1. [@binding]="fooExp"
16959 // 2. [@binding]="{value:fooExp, params:{...}}"
16960 // 3. [@binding]
16961 // 4. @binding
16962 // All formats will be valid for when a synthetic binding is created.
16963 // The reasoning for this is because the renderer should get each
16964 // synthetic binding value in the order of the array that they are
16965 // defined in...
16966 const hasValue = value instanceof LiteralPrimitive ? !!value.value : true;
16967 this.allocateBindingSlots(value);
16968 propertyBindings.push({
16969 name: prepareSyntheticPropertyName(input.name),
16970 sourceSpan: input.sourceSpan,
16971 value: () => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction
16972 });
16973 }
16974 else {
16975 // we must skip attributes with associated i18n context, since these attributes are handled
16976 // separately and corresponding `i18nExp` and `i18nApply` instructions will be generated
16977 if (input.i18n)
16978 return;
16979 const value = input.value.visit(this._valueConverter);
16980 if (value !== undefined) {
16981 const params = [];
16982 const [attrNamespace, attrName] = splitNsName(input.name);
16983 const isAttributeBinding = inputType === 1 /* Attribute */;
16984 const sanitizationRef = resolveSanitizationFn(input.securityContext, isAttributeBinding);
16985 if (sanitizationRef)
16986 params.push(sanitizationRef);
16987 if (attrNamespace) {
16988 const namespaceLiteral = literal(attrNamespace);
16989 if (sanitizationRef) {
16990 params.push(namespaceLiteral);
16991 }
16992 else {
16993 // If there wasn't a sanitization ref, we need to add
16994 // an extra param so that we can pass in the namespace.
16995 params.push(literal(null), namespaceLiteral);
16996 }
16997 }
16998 this.allocateBindingSlots(value);
16999 if (inputType === 0 /* Property */) {
17000 if (value instanceof Interpolation) {
17001 // prop="{{value}}" and friends
17002 this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), elementIndex, attrName, input, value, params);
17003 }
17004 else {
17005 // [prop]="value"
17006 // Collect all the properties so that we can chain into a single function at the end.
17007 propertyBindings.push({
17008 name: attrName,
17009 sourceSpan: input.sourceSpan,
17010 value: () => this.convertPropertyBinding(value),
17011 params
17012 });
17013 }
17014 }
17015 else if (inputType === 1 /* Attribute */) {
17016 if (value instanceof Interpolation && getInterpolationArgsLength(value) > 1) {
17017 // attr.name="text{{value}}" and friends
17018 this.interpolatedUpdateInstruction(getAttributeInterpolationExpression(value), elementIndex, attrName, input, value, params);
17019 }
17020 else {
17021 const boundValue = value instanceof Interpolation ? value.expressions[0] : value;
17022 // [attr.name]="value" or attr.name="{{value}}"
17023 // Collect the attribute bindings so that they can be chained at the end.
17024 attributeBindings.push({
17025 name: attrName,
17026 sourceSpan: input.sourceSpan,
17027 value: () => this.convertPropertyBinding(boundValue),
17028 params
17029 });
17030 }
17031 }
17032 else {
17033 // class prop
17034 this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, Identifiers$1.classProp, () => {
17035 return [
17036 literal(elementIndex), literal(attrName), this.convertPropertyBinding(value),
17037 ...params
17038 ];
17039 });
17040 }
17041 }
17042 }
17043 });
17044 if (propertyBindings.length > 0) {
17045 this.updateInstructionChainWithAdvance(elementIndex, Identifiers$1.property, propertyBindings);
17046 }
17047 if (attributeBindings.length > 0) {
17048 this.updateInstructionChainWithAdvance(elementIndex, Identifiers$1.attribute, attributeBindings);
17049 }
17050 // Traverse element child nodes
17051 visitAll(this, element.children);
17052 if (!isI18nRootElement && this.i18n) {
17053 this.i18n.appendElement(element.i18n, elementIndex, true);
17054 }
17055 if (!createSelfClosingInstruction) {
17056 // Finish element construction mode.
17057 const span = (_b = element.endSourceSpan) !== null && _b !== void 0 ? _b : element.sourceSpan;
17058 if (isI18nRootElement) {
17059 this.i18nEnd(span, createSelfClosingI18nInstruction);
17060 }
17061 if (isNonBindableMode) {
17062 this.creationInstruction(span, Identifiers$1.enableBindings);
17063 }
17064 this.creationInstruction(span, isNgContainer$1 ? Identifiers$1.elementContainerEnd : Identifiers$1.elementEnd);
17065 }
17066 }
17067 visitTemplate(template) {
17068 var _a;
17069 const NG_TEMPLATE_TAG_NAME = 'ng-template';
17070 const templateIndex = this.allocateDataSlot();
17071 if (this.i18n) {
17072 this.i18n.appendTemplate(template.i18n, templateIndex);
17073 }
17074 const tagName = sanitizeIdentifier(template.tagName || '');
17075 const contextName = `${this.contextName}${tagName ? '_' + tagName : ''}_${templateIndex}`;
17076 const templateName = `${contextName}_Template`;
17077 const parameters = [
17078 literal(templateIndex),
17079 variable(templateName),
17080 // We don't care about the tag's namespace here, because we infer
17081 // it based on the parent nodes inside the template instruction.
17082 literal(template.tagName ? splitNsName(template.tagName)[1] : template.tagName),
17083 ];
17084 // find directives matching on a given <ng-template> node
17085 this.matchDirectives(NG_TEMPLATE_TAG_NAME, template);
17086 // prepare attributes parameter (including attributes used for directive matching)
17087 const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
17088 parameters.push(this.addAttrsToConsts(attrsExprs));
17089 // local refs (ex.: <ng-template #foo>)
17090 if (template.references && template.references.length) {
17091 const refs = this.prepareRefsArray(template.references);
17092 parameters.push(this.addToConsts(refs));
17093 parameters.push(importExpr(Identifiers$1.templateRefExtractor));
17094 }
17095 // Create the template function
17096 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);
17097 // Nested templates must not be visited until after their parent templates have completed
17098 // processing, so they are queued here until after the initial pass. Otherwise, we wouldn't
17099 // be able to support bindings in nested templates to local refs that occur after the
17100 // template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
17101 this._nestedTemplateFns.push(() => {
17102 const templateFunctionExpr = templateVisitor.buildTemplateFunction(template.children, template.variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, template.i18n);
17103 this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName));
17104 if (templateVisitor._ngContentReservedSlots.length) {
17105 this._ngContentReservedSlots.push(...templateVisitor._ngContentReservedSlots);
17106 }
17107 });
17108 // e.g. template(1, MyComp_Template_1)
17109 this.creationInstruction(template.sourceSpan, Identifiers$1.templateCreate, () => {
17110 parameters.splice(2, 0, literal(templateVisitor.getConstCount()), literal(templateVisitor.getVarCount()));
17111 return trimTrailingNulls(parameters);
17112 });
17113 // handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al;
17114 this.templatePropertyBindings(templateIndex, template.templateAttrs);
17115 // Only add normal input/output binding instructions on explicit <ng-template> elements.
17116 if (template.tagName === NG_TEMPLATE_TAG_NAME) {
17117 const [i18nInputs, inputs] = partitionArray(template.inputs, hasI18nMeta);
17118 // Add i18n attributes that may act as inputs to directives. If such attributes are present,
17119 // generate `i18nAttributes` instruction. Note: we generate it only for explicit <ng-template>
17120 // elements, in case of inline templates, corresponding instructions will be generated in the
17121 // nested template function.
17122 if (i18nInputs.length > 0) {
17123 this.i18nAttributesInstruction(templateIndex, i18nInputs, (_a = template.startSourceSpan) !== null && _a !== void 0 ? _a : template.sourceSpan);
17124 }
17125 // Add the input bindings
17126 if (inputs.length > 0) {
17127 this.templatePropertyBindings(templateIndex, inputs);
17128 }
17129 // Generate listeners for directive output
17130 if (template.outputs.length > 0) {
17131 const listeners = template.outputs.map((outputAst) => ({
17132 sourceSpan: outputAst.sourceSpan,
17133 params: this.prepareListenerParameter('ng_template', outputAst, templateIndex)
17134 }));
17135 this.creationInstructionChain(Identifiers$1.listener, listeners);
17136 }
17137 }
17138 }
17139 visitBoundText(text) {
17140 if (this.i18n) {
17141 const value = text.value.visit(this._valueConverter);
17142 this.allocateBindingSlots(value);
17143 if (value instanceof Interpolation) {
17144 this.i18n.appendBoundText(text.i18n);
17145 this.i18nAppendBindings(value.expressions);
17146 }
17147 return;
17148 }
17149 const nodeIndex = this.allocateDataSlot();
17150 this.creationInstruction(text.sourceSpan, Identifiers$1.text, [literal(nodeIndex)]);
17151 const value = text.value.visit(this._valueConverter);
17152 this.allocateBindingSlots(value);
17153 if (value instanceof Interpolation) {
17154 this.updateInstructionWithAdvance(nodeIndex, text.sourceSpan, getTextInterpolationExpression(value), () => this.getUpdateInstructionArguments(value));
17155 }
17156 else {
17157 error('Text nodes should be interpolated and never bound directly.');
17158 }
17159 }
17160 visitText(text) {
17161 // when a text element is located within a translatable
17162 // block, we exclude this text element from instructions set,
17163 // since it will be captured in i18n content and processed at runtime
17164 if (!this.i18n) {
17165 this.creationInstruction(text.sourceSpan, Identifiers$1.text, [literal(this.allocateDataSlot()), literal(text.value)]);
17166 }
17167 }
17168 visitIcu(icu) {
17169 let initWasInvoked = false;
17170 // if an ICU was created outside of i18n block, we still treat
17171 // it as a translatable entity and invoke i18nStart and i18nEnd
17172 // to generate i18n context and the necessary instructions
17173 if (!this.i18n) {
17174 initWasInvoked = true;
17175 this.i18nStart(null, icu.i18n, true);
17176 }
17177 const i18n = this.i18n;
17178 const vars = this.i18nBindProps(icu.vars);
17179 const placeholders = this.i18nBindProps(icu.placeholders);
17180 // output ICU directly and keep ICU reference in context
17181 const message = icu.i18n;
17182 // we always need post-processing function for ICUs, to make sure that:
17183 // - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note:
17184 // `goog.getMsg` does not process ICUs and uses the `{PLACEHOLDER}` format for placeholders
17185 // inside ICUs)
17186 // - all ICU vars (such as `VAR_SELECT` or `VAR_PLURAL`) are replaced with correct values
17187 const transformFn = (raw) => {
17188 const params = Object.assign(Object.assign({}, vars), placeholders);
17189 const formatted = i18nFormatPlaceholderNames(params, /* useCamelCase */ false);
17190 return instruction(null, Identifiers$1.i18nPostprocess, [raw, mapLiteral(formatted, true)]);
17191 };
17192 // in case the whole i18n message is a single ICU - we do not need to
17193 // create a separate top-level translation, we can use the root ref instead
17194 // and make this ICU a top-level translation
17195 // note: ICU placeholders are replaced with actual values in `i18nPostprocess` function
17196 // separately, so we do not pass placeholders into `i18nTranslate` function.
17197 if (isSingleI18nIcu(i18n.meta)) {
17198 this.i18nTranslate(message, /* placeholders */ {}, i18n.ref, transformFn);
17199 }
17200 else {
17201 // output ICU directly and keep ICU reference in context
17202 const ref = this.i18nTranslate(message, /* placeholders */ {}, /* ref */ undefined, transformFn);
17203 i18n.appendIcu(icuFromI18nMessage(message).name, ref);
17204 }
17205 if (initWasInvoked) {
17206 this.i18nEnd(null, true);
17207 }
17208 return null;
17209 }
17210 allocateDataSlot() {
17211 return this._dataIndex++;
17212 }
17213 getConstCount() {
17214 return this._dataIndex;
17215 }
17216 getVarCount() {
17217 return this._pureFunctionSlots;
17218 }
17219 getConsts() {
17220 return this._constants;
17221 }
17222 getNgContentSelectors() {
17223 return this._ngContentReservedSlots.length ?
17224 this.constantPool.getConstLiteral(asLiteral(this._ngContentReservedSlots), true) :
17225 null;
17226 }
17227 bindingContext() {
17228 return `${this._bindingContext++}`;
17229 }
17230 templatePropertyBindings(templateIndex, attrs) {
17231 const propertyBindings = [];
17232 attrs.forEach(input => {
17233 if (input instanceof BoundAttribute) {
17234 const value = input.value.visit(this._valueConverter);
17235 if (value !== undefined) {
17236 this.allocateBindingSlots(value);
17237 if (value instanceof Interpolation) {
17238 // Params typically contain attribute namespace and value sanitizer, which is applicable
17239 // for regular HTML elements, but not applicable for <ng-template> (since props act as
17240 // inputs to directives), so keep params array empty.
17241 const params = [];
17242 // prop="{{value}}" case
17243 this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), templateIndex, input.name, input, value, params);
17244 }
17245 else {
17246 // [prop]="value" case
17247 propertyBindings.push({
17248 name: input.name,
17249 sourceSpan: input.sourceSpan,
17250 value: () => this.convertPropertyBinding(value)
17251 });
17252 }
17253 }
17254 }
17255 });
17256 if (propertyBindings.length > 0) {
17257 this.updateInstructionChainWithAdvance(templateIndex, Identifiers$1.property, propertyBindings);
17258 }
17259 }
17260 // Bindings must only be resolved after all local refs have been visited, so all
17261 // instructions are queued in callbacks that execute once the initial pass has completed.
17262 // Otherwise, we wouldn't be able to support local refs that are defined after their
17263 // bindings. e.g. {{ foo }} <div #foo></div>
17264 instructionFn(fns, span, reference, paramsOrFn, prepend = false) {
17265 fns[prepend ? 'unshift' : 'push'](() => {
17266 const params = Array.isArray(paramsOrFn) ? paramsOrFn : paramsOrFn();
17267 return instruction(span, reference, params).toStmt();
17268 });
17269 }
17270 processStylingUpdateInstruction(elementIndex, instruction) {
17271 let allocateBindingSlots = 0;
17272 if (instruction) {
17273 const calls = [];
17274 instruction.calls.forEach(call => {
17275 allocateBindingSlots += call.allocateBindingSlots;
17276 calls.push({
17277 sourceSpan: call.sourceSpan,
17278 value: () => {
17279 return call.params(value => (call.supportsInterpolation && value instanceof Interpolation) ?
17280 this.getUpdateInstructionArguments(value) :
17281 this.convertPropertyBinding(value));
17282 }
17283 });
17284 });
17285 this.updateInstructionChainWithAdvance(elementIndex, instruction.reference, calls);
17286 }
17287 return allocateBindingSlots;
17288 }
17289 creationInstruction(span, reference, paramsOrFn, prepend) {
17290 this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend);
17291 }
17292 creationInstructionChain(reference, calls) {
17293 const span = calls.length ? calls[0].sourceSpan : null;
17294 this._creationCodeFns.push(() => {
17295 return chainedInstruction(reference, calls.map(call => call.params()), span).toStmt();
17296 });
17297 }
17298 updateInstructionWithAdvance(nodeIndex, span, reference, paramsOrFn) {
17299 this.addAdvanceInstructionIfNecessary(nodeIndex, span);
17300 this.updateInstruction(span, reference, paramsOrFn);
17301 }
17302 updateInstruction(span, reference, paramsOrFn) {
17303 this.instructionFn(this._updateCodeFns, span, reference, paramsOrFn || []);
17304 }
17305 updateInstructionChain(reference, bindings) {
17306 const span = bindings.length ? bindings[0].sourceSpan : null;
17307 this._updateCodeFns.push(() => {
17308 const calls = bindings.map(property => {
17309 const value = property.value();
17310 const fnParams = Array.isArray(value) ? value : [value];
17311 if (property.params) {
17312 fnParams.push(...property.params);
17313 }
17314 if (property.name) {
17315 // We want the property name to always be the first function parameter.
17316 fnParams.unshift(literal(property.name));
17317 }
17318 return fnParams;
17319 });
17320 return chainedInstruction(reference, calls, span).toStmt();
17321 });
17322 }
17323 updateInstructionChainWithAdvance(nodeIndex, reference, bindings) {
17324 this.addAdvanceInstructionIfNecessary(nodeIndex, bindings.length ? bindings[0].sourceSpan : null);
17325 this.updateInstructionChain(reference, bindings);
17326 }
17327 addAdvanceInstructionIfNecessary(nodeIndex, span) {
17328 if (nodeIndex !== this._currentIndex) {
17329 const delta = nodeIndex - this._currentIndex;
17330 if (delta < 1) {
17331 throw new Error('advance instruction can only go forwards');
17332 }
17333 this.instructionFn(this._updateCodeFns, span, Identifiers$1.advance, [literal(delta)]);
17334 this._currentIndex = nodeIndex;
17335 }
17336 }
17337 allocatePureFunctionSlots(numSlots) {
17338 const originalSlots = this._pureFunctionSlots;
17339 this._pureFunctionSlots += numSlots;
17340 return originalSlots;
17341 }
17342 allocateBindingSlots(value) {
17343 this._bindingSlots += value instanceof Interpolation ? value.expressions.length : 1;
17344 }
17345 /**
17346 * Gets an expression that refers to the implicit receiver. The implicit
17347 * receiver is always the root level context.
17348 */
17349 getImplicitReceiverExpr() {
17350 if (this._implicitReceiverExpr) {
17351 return this._implicitReceiverExpr;
17352 }
17353 return this._implicitReceiverExpr = this.level === 0 ?
17354 variable(CONTEXT_NAME) :
17355 this._bindingScope.getOrCreateSharedContextVar(0);
17356 }
17357 convertPropertyBinding(value) {
17358 const convertedPropertyBinding = convertPropertyBinding(this, this.getImplicitReceiverExpr(), value, this.bindingContext(), BindingForm.Expression, () => error('Unexpected interpolation'));
17359 const valExpr = convertedPropertyBinding.currValExpr;
17360 this._tempVariables.push(...convertedPropertyBinding.stmts);
17361 return valExpr;
17362 }
17363 /**
17364 * Gets a list of argument expressions to pass to an update instruction expression. Also updates
17365 * the temp variables state with temp variables that were identified as needing to be created
17366 * while visiting the arguments.
17367 * @param value The original expression we will be resolving an arguments list from.
17368 */
17369 getUpdateInstructionArguments(value) {
17370 const { args, stmts } = convertUpdateArguments(this, this.getImplicitReceiverExpr(), value, this.bindingContext());
17371 this._tempVariables.push(...stmts);
17372 return args;
17373 }
17374 matchDirectives(elementName, elOrTpl) {
17375 if (this.directiveMatcher) {
17376 const selector = createCssSelector(elementName, getAttrsForDirectiveMatching(elOrTpl));
17377 this.directiveMatcher.match(selector, (cssSelector, staticType) => {
17378 this.directives.add(staticType);
17379 });
17380 }
17381 }
17382 /**
17383 * Prepares all attribute expression values for the `TAttributes` array.
17384 *
17385 * The purpose of this function is to properly construct an attributes array that
17386 * is passed into the `elementStart` (or just `element`) functions. Because there
17387 * are many different types of attributes, the array needs to be constructed in a
17388 * special way so that `elementStart` can properly evaluate them.
17389 *
17390 * The format looks like this:
17391 *
17392 * ```
17393 * attrs = [prop, value, prop2, value2,
17394 * PROJECT_AS, selector,
17395 * CLASSES, class1, class2,
17396 * STYLES, style1, value1, style2, value2,
17397 * BINDINGS, name1, name2, name3,
17398 * TEMPLATE, name4, name5, name6,
17399 * I18N, name7, name8, ...]
17400 * ```
17401 *
17402 * Note that this function will fully ignore all synthetic (@foo) attribute values
17403 * because those values are intended to always be generated as property instructions.
17404 */
17405 getAttributeExpressions(elementName, renderAttributes, inputs, outputs, styles, templateAttrs = [], boundI18nAttrs = []) {
17406 const alreadySeen = new Set();
17407 const attrExprs = [];
17408 let ngProjectAsAttr;
17409 for (const attr of renderAttributes) {
17410 if (attr.name === NG_PROJECT_AS_ATTR_NAME) {
17411 ngProjectAsAttr = attr;
17412 }
17413 // Note that static i18n attributes aren't in the i18n array,
17414 // because they're treated in the same way as regular attributes.
17415 if (attr.i18n) {
17416 // When i18n attributes are present on elements with structural directives
17417 // (e.g. `<div *ngIf title="Hello" i18n-title>`), we want to avoid generating
17418 // duplicate i18n translation blocks for `ɵɵtemplate` and `ɵɵelement` instruction
17419 // attributes. So we do a cache lookup to see if suitable i18n translation block
17420 // already exists.
17421 const { i18nVarRefsCache } = this._constants;
17422 let i18nVarRef;
17423 if (i18nVarRefsCache.has(attr.i18n)) {
17424 i18nVarRef = i18nVarRefsCache.get(attr.i18n);
17425 }
17426 else {
17427 i18nVarRef = this.i18nTranslate(attr.i18n);
17428 i18nVarRefsCache.set(attr.i18n, i18nVarRef);
17429 }
17430 attrExprs.push(literal(attr.name), i18nVarRef);
17431 }
17432 else {
17433 attrExprs.push(...getAttributeNameLiterals(attr.name), trustedConstAttribute(elementName, attr));
17434 }
17435 }
17436 // Keep ngProjectAs next to the other name, value pairs so we can verify that we match
17437 // ngProjectAs marker in the attribute name slot.
17438 if (ngProjectAsAttr) {
17439 attrExprs.push(...getNgProjectAsLiteral(ngProjectAsAttr));
17440 }
17441 function addAttrExpr(key, value) {
17442 if (typeof key === 'string') {
17443 if (!alreadySeen.has(key)) {
17444 attrExprs.push(...getAttributeNameLiterals(key));
17445 value !== undefined && attrExprs.push(value);
17446 alreadySeen.add(key);
17447 }
17448 }
17449 else {
17450 attrExprs.push(literal(key));
17451 }
17452 }
17453 // it's important that this occurs before BINDINGS and TEMPLATE because once `elementStart`
17454 // comes across the BINDINGS or TEMPLATE markers then it will continue reading each value as
17455 // as single property value cell by cell.
17456 if (styles) {
17457 styles.populateInitialStylingAttrs(attrExprs);
17458 }
17459 if (inputs.length || outputs.length) {
17460 const attrsLengthBeforeInputs = attrExprs.length;
17461 for (let i = 0; i < inputs.length; i++) {
17462 const input = inputs[i];
17463 // We don't want the animation and attribute bindings in the
17464 // attributes array since they aren't used for directive matching.
17465 if (input.type !== 4 /* Animation */ && input.type !== 1 /* Attribute */) {
17466 addAttrExpr(input.name);
17467 }
17468 }
17469 for (let i = 0; i < outputs.length; i++) {
17470 const output = outputs[i];
17471 if (output.type !== 1 /* Animation */) {
17472 addAttrExpr(output.name);
17473 }
17474 }
17475 // this is a cheap way of adding the marker only after all the input/output
17476 // values have been filtered (by not including the animation ones) and added
17477 // to the expressions. The marker is important because it tells the runtime
17478 // code that this is where attributes without values start...
17479 if (attrExprs.length !== attrsLengthBeforeInputs) {
17480 attrExprs.splice(attrsLengthBeforeInputs, 0, literal(3 /* Bindings */));
17481 }
17482 }
17483 if (templateAttrs.length) {
17484 attrExprs.push(literal(4 /* Template */));
17485 templateAttrs.forEach(attr => addAttrExpr(attr.name));
17486 }
17487 if (boundI18nAttrs.length) {
17488 attrExprs.push(literal(6 /* I18n */));
17489 boundI18nAttrs.forEach(attr => addAttrExpr(attr.name));
17490 }
17491 return attrExprs;
17492 }
17493 addToConsts(expression) {
17494 if (isNull(expression)) {
17495 return TYPED_NULL_EXPR;
17496 }
17497 const consts = this._constants.constExpressions;
17498 // Try to reuse a literal that's already in the array, if possible.
17499 for (let i = 0; i < consts.length; i++) {
17500 if (consts[i].isEquivalent(expression)) {
17501 return literal(i);
17502 }
17503 }
17504 return literal(consts.push(expression) - 1);
17505 }
17506 addAttrsToConsts(attrs) {
17507 return attrs.length > 0 ? this.addToConsts(literalArr(attrs)) : TYPED_NULL_EXPR;
17508 }
17509 prepareRefsArray(references) {
17510 if (!references || references.length === 0) {
17511 return TYPED_NULL_EXPR;
17512 }
17513 const refsParam = flatten(references.map(reference => {
17514 const slot = this.allocateDataSlot();
17515 // Generate the update temporary.
17516 const variableName = this._bindingScope.freshReferenceName();
17517 const retrievalLevel = this.level;
17518 const lhs = variable(variableName);
17519 this._bindingScope.set(retrievalLevel, reference.name, lhs, 0 /* DEFAULT */, (scope, relativeLevel) => {
17520 // e.g. nextContext(2);
17521 const nextContextStmt = relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : [];
17522 // e.g. const $foo$ = reference(1);
17523 const refExpr = lhs.set(importExpr(Identifiers$1.reference).callFn([literal(slot)]));
17524 return nextContextStmt.concat(refExpr.toConstDecl());
17525 }, true);
17526 return [reference.name, reference.value];
17527 }));
17528 return asLiteral(refsParam);
17529 }
17530 prepareListenerParameter(tagName, outputAst, index) {
17531 return () => {
17532 const eventName = outputAst.name;
17533 const bindingFnName = outputAst.type === 1 /* Animation */ ?
17534 // synthetic @listener.foo values are treated the exact same as are standard listeners
17535 prepareSyntheticListenerFunctionName(eventName, outputAst.phase) :
17536 sanitizeIdentifier(eventName);
17537 const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`;
17538 const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel, EVENT_BINDING_SCOPE_GLOBALS);
17539 return prepareEventListenerParameters(outputAst, handlerName, scope);
17540 };
17541 }
17542 }
17543 class ValueConverter extends AstMemoryEfficientTransformer {
17544 constructor(constantPool, allocateSlot, allocatePureFunctionSlots, definePipe) {
17545 super();
17546 this.constantPool = constantPool;
17547 this.allocateSlot = allocateSlot;
17548 this.allocatePureFunctionSlots = allocatePureFunctionSlots;
17549 this.definePipe = definePipe;
17550 this._pipeBindExprs = [];
17551 }
17552 // AstMemoryEfficientTransformer
17553 visitPipe(pipe, context) {
17554 // Allocate a slot to create the pipe
17555 const slot = this.allocateSlot();
17556 const slotPseudoLocal = `PIPE:${slot}`;
17557 // Allocate one slot for the result plus one slot per pipe argument
17558 const pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length);
17559 const target = new PropertyRead(pipe.span, pipe.sourceSpan, pipe.nameSpan, new ImplicitReceiver(pipe.span, pipe.sourceSpan), slotPseudoLocal);
17560 const { identifier, isVarLength } = pipeBindingCallInfo(pipe.args);
17561 this.definePipe(pipe.name, slotPseudoLocal, slot, importExpr(identifier));
17562 const args = [pipe.exp, ...pipe.args];
17563 const convertedArgs = isVarLength ?
17564 this.visitAll([new LiteralArray(pipe.span, pipe.sourceSpan, args)]) :
17565 this.visitAll(args);
17566 const pipeBindExpr = new FunctionCall(pipe.span, pipe.sourceSpan, target, [
17567 new LiteralPrimitive(pipe.span, pipe.sourceSpan, slot),
17568 new LiteralPrimitive(pipe.span, pipe.sourceSpan, pureFunctionSlot),
17569 ...convertedArgs,
17570 ]);
17571 this._pipeBindExprs.push(pipeBindExpr);
17572 return pipeBindExpr;
17573 }
17574 updatePipeSlotOffsets(bindingSlots) {
17575 this._pipeBindExprs.forEach((pipe) => {
17576 // update the slot offset arg (index 1) to account for binding slots
17577 const slotOffset = pipe.args[1];
17578 slotOffset.value += bindingSlots;
17579 });
17580 }
17581 visitLiteralArray(array, context) {
17582 return new BuiltinFunctionCall(array.span, array.sourceSpan, this.visitAll(array.expressions), values => {
17583 // If the literal has calculated (non-literal) elements transform it into
17584 // calls to literal factories that compose the literal and will cache intermediate
17585 // values.
17586 const literal = literalArr(values);
17587 return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
17588 });
17589 }
17590 visitLiteralMap(map, context) {
17591 return new BuiltinFunctionCall(map.span, map.sourceSpan, this.visitAll(map.values), values => {
17592 // If the literal has calculated (non-literal) elements transform it into
17593 // calls to literal factories that compose the literal and will cache intermediate
17594 // values.
17595 const literal = literalMap(values.map((value, index) => ({ key: map.keys[index].key, value, quoted: map.keys[index].quoted })));
17596 return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
17597 });
17598 }
17599 }
17600 // Pipes always have at least one parameter, the value they operate on
17601 const pipeBindingIdentifiers = [Identifiers$1.pipeBind1, Identifiers$1.pipeBind2, Identifiers$1.pipeBind3, Identifiers$1.pipeBind4];
17602 function pipeBindingCallInfo(args) {
17603 const identifier = pipeBindingIdentifiers[args.length];
17604 return {
17605 identifier: identifier || Identifiers$1.pipeBindV,
17606 isVarLength: !identifier,
17607 };
17608 }
17609 const pureFunctionIdentifiers = [
17610 Identifiers$1.pureFunction0, Identifiers$1.pureFunction1, Identifiers$1.pureFunction2, Identifiers$1.pureFunction3, Identifiers$1.pureFunction4,
17611 Identifiers$1.pureFunction5, Identifiers$1.pureFunction6, Identifiers$1.pureFunction7, Identifiers$1.pureFunction8
17612 ];
17613 function pureFunctionCallInfo(args) {
17614 const identifier = pureFunctionIdentifiers[args.length];
17615 return {
17616 identifier: identifier || Identifiers$1.pureFunctionV,
17617 isVarLength: !identifier,
17618 };
17619 }
17620 function instruction(span, reference, params) {
17621 return importExpr(reference, null, span).callFn(params, span);
17622 }
17623 // e.g. x(2);
17624 function generateNextContextExpr(relativeLevelDiff) {
17625 return importExpr(Identifiers$1.nextContext)
17626 .callFn(relativeLevelDiff > 1 ? [literal(relativeLevelDiff)] : []);
17627 }
17628 function getLiteralFactory(constantPool, literal$1, allocateSlots) {
17629 const { literalFactory, literalFactoryArguments } = constantPool.getLiteralFactory(literal$1);
17630 // Allocate 1 slot for the result plus 1 per argument
17631 const startSlot = allocateSlots(1 + literalFactoryArguments.length);
17632 const { identifier, isVarLength } = pureFunctionCallInfo(literalFactoryArguments);
17633 // Literal factories are pure functions that only need to be re-invoked when the parameters
17634 // change.
17635 const args = [literal(startSlot), literalFactory];
17636 if (isVarLength) {
17637 args.push(literalArr(literalFactoryArguments));
17638 }
17639 else {
17640 args.push(...literalFactoryArguments);
17641 }
17642 return importExpr(identifier).callFn(args);
17643 }
17644 /**
17645 * Gets an array of literals that can be added to an expression
17646 * to represent the name and namespace of an attribute. E.g.
17647 * `:xlink:href` turns into `[AttributeMarker.NamespaceURI, 'xlink', 'href']`.
17648 *
17649 * @param name Name of the attribute, including the namespace.
17650 */
17651 function getAttributeNameLiterals(name) {
17652 const [attributeNamespace, attributeName] = splitNsName(name);
17653 const nameLiteral = literal(attributeName);
17654 if (attributeNamespace) {
17655 return [
17656 literal(0 /* NamespaceURI */), literal(attributeNamespace), nameLiteral
17657 ];
17658 }
17659 return [nameLiteral];
17660 }
17661 /** The prefix used to get a shared context in BindingScope's map. */
17662 const SHARED_CONTEXT_KEY = '$$shared_ctx$$';
17663 class BindingScope {
17664 constructor(bindingLevel = 0, parent = null, globals) {
17665 this.bindingLevel = bindingLevel;
17666 this.parent = parent;
17667 this.globals = globals;
17668 /** Keeps a map from local variables to their BindingData. */
17669 this.map = new Map();
17670 this.referenceNameIndex = 0;
17671 this.restoreViewVariable = null;
17672 if (globals !== undefined) {
17673 for (const name of globals) {
17674 this.set(0, name, variable(name));
17675 }
17676 }
17677 }
17678 static createRootScope() {
17679 return new BindingScope();
17680 }
17681 get(name) {
17682 let current = this;
17683 while (current) {
17684 let value = current.map.get(name);
17685 if (value != null) {
17686 if (current !== this) {
17687 // make a local copy and reset the `declare` state
17688 value = {
17689 retrievalLevel: value.retrievalLevel,
17690 lhs: value.lhs,
17691 declareLocalCallback: value.declareLocalCallback,
17692 declare: false,
17693 priority: value.priority,
17694 localRef: value.localRef
17695 };
17696 // Cache the value locally.
17697 this.map.set(name, value);
17698 // Possibly generate a shared context var
17699 this.maybeGenerateSharedContextVar(value);
17700 this.maybeRestoreView(value.retrievalLevel, value.localRef);
17701 }
17702 if (value.declareLocalCallback && !value.declare) {
17703 value.declare = true;
17704 }
17705 return value.lhs;
17706 }
17707 current = current.parent;
17708 }
17709 // If we get to this point, we are looking for a property on the top level component
17710 // - If level === 0, we are on the top and don't need to re-declare `ctx`.
17711 // - If level > 0, we are in an embedded view. We need to retrieve the name of the
17712 // local var we used to store the component context, e.g. const $comp$ = x();
17713 return this.bindingLevel === 0 ? null : this.getComponentProperty(name);
17714 }
17715 /**
17716 * Create a local variable for later reference.
17717 *
17718 * @param retrievalLevel The level from which this value can be retrieved
17719 * @param name Name of the variable.
17720 * @param lhs AST representing the left hand side of the `let lhs = rhs;`.
17721 * @param priority The sorting priority of this var
17722 * @param declareLocalCallback The callback to invoke when declaring this local var
17723 * @param localRef Whether or not this is a local ref
17724 */
17725 set(retrievalLevel, name, lhs, priority = 0 /* DEFAULT */, declareLocalCallback, localRef) {
17726 if (this.map.has(name)) {
17727 if (localRef) {
17728 // Do not throw an error if it's a local ref and do not update existing value,
17729 // so the first defined ref is always returned.
17730 return this;
17731 }
17732 error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`);
17733 }
17734 this.map.set(name, {
17735 retrievalLevel: retrievalLevel,
17736 lhs: lhs,
17737 declare: false,
17738 declareLocalCallback: declareLocalCallback,
17739 priority: priority,
17740 localRef: localRef || false
17741 });
17742 return this;
17743 }
17744 // Implemented as part of LocalResolver.
17745 getLocal(name) {
17746 return this.get(name);
17747 }
17748 // Implemented as part of LocalResolver.
17749 notifyImplicitReceiverUse() {
17750 if (this.bindingLevel !== 0) {
17751 // Since the implicit receiver is accessed in an embedded view, we need to
17752 // ensure that we declare a shared context variable for the current template
17753 // in the update variables.
17754 this.map.get(SHARED_CONTEXT_KEY + 0).declare = true;
17755 }
17756 }
17757 nestedScope(level, globals) {
17758 const newScope = new BindingScope(level, this, globals);
17759 if (level > 0)
17760 newScope.generateSharedContextVar(0);
17761 return newScope;
17762 }
17763 /**
17764 * Gets or creates a shared context variable and returns its expression. Note that
17765 * this does not mean that the shared variable will be declared. Variables in the
17766 * binding scope will be only declared if they are used.
17767 */
17768 getOrCreateSharedContextVar(retrievalLevel) {
17769 const bindingKey = SHARED_CONTEXT_KEY + retrievalLevel;
17770 if (!this.map.has(bindingKey)) {
17771 this.generateSharedContextVar(retrievalLevel);
17772 }
17773 // Shared context variables are always generated as "ReadVarExpr".
17774 return this.map.get(bindingKey).lhs;
17775 }
17776 getSharedContextName(retrievalLevel) {
17777 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + retrievalLevel);
17778 // Shared context variables are always generated as "ReadVarExpr".
17779 return sharedCtxObj && sharedCtxObj.declare ? sharedCtxObj.lhs : null;
17780 }
17781 maybeGenerateSharedContextVar(value) {
17782 if (value.priority === 1 /* CONTEXT */ &&
17783 value.retrievalLevel < this.bindingLevel) {
17784 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + value.retrievalLevel);
17785 if (sharedCtxObj) {
17786 sharedCtxObj.declare = true;
17787 }
17788 else {
17789 this.generateSharedContextVar(value.retrievalLevel);
17790 }
17791 }
17792 }
17793 generateSharedContextVar(retrievalLevel) {
17794 const lhs = variable(CONTEXT_NAME + this.freshReferenceName());
17795 this.map.set(SHARED_CONTEXT_KEY + retrievalLevel, {
17796 retrievalLevel: retrievalLevel,
17797 lhs: lhs,
17798 declareLocalCallback: (scope, relativeLevel) => {
17799 // const ctx_r0 = nextContext(2);
17800 return [lhs.set(generateNextContextExpr(relativeLevel)).toConstDecl()];
17801 },
17802 declare: false,
17803 priority: 2 /* SHARED_CONTEXT */,
17804 localRef: false
17805 });
17806 }
17807 getComponentProperty(name) {
17808 const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
17809 componentValue.declare = true;
17810 this.maybeRestoreView(0, false);
17811 return componentValue.lhs.prop(name);
17812 }
17813 maybeRestoreView(retrievalLevel, localRefLookup) {
17814 // We want to restore the current view in listener fns if:
17815 // 1 - we are accessing a value in a parent view, which requires walking the view tree rather
17816 // than using the ctx arg. In this case, the retrieval and binding level will be different.
17817 // 2 - we are looking up a local ref, which requires restoring the view where the local
17818 // ref is stored
17819 if (this.isListenerScope() && (retrievalLevel < this.bindingLevel || localRefLookup)) {
17820 if (!this.parent.restoreViewVariable) {
17821 // parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction
17822 this.parent.restoreViewVariable = variable(this.parent.freshReferenceName());
17823 }
17824 this.restoreViewVariable = this.parent.restoreViewVariable;
17825 }
17826 }
17827 restoreViewStatement() {
17828 // restoreView($state$);
17829 return this.restoreViewVariable ?
17830 [instruction(null, Identifiers$1.restoreView, [this.restoreViewVariable]).toStmt()] :
17831 [];
17832 }
17833 viewSnapshotStatements() {
17834 // const $state$ = getCurrentView();
17835 const getCurrentViewInstruction = instruction(null, Identifiers$1.getCurrentView, []);
17836 return this.restoreViewVariable ?
17837 [this.restoreViewVariable.set(getCurrentViewInstruction).toConstDecl()] :
17838 [];
17839 }
17840 isListenerScope() {
17841 return this.parent && this.parent.bindingLevel === this.bindingLevel;
17842 }
17843 variableDeclarations() {
17844 let currentContextLevel = 0;
17845 return Array.from(this.map.values())
17846 .filter(value => value.declare)
17847 .sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority)
17848 .reduce((stmts, value) => {
17849 const levelDiff = this.bindingLevel - value.retrievalLevel;
17850 const currStmts = value.declareLocalCallback(this, levelDiff - currentContextLevel);
17851 currentContextLevel = levelDiff;
17852 return stmts.concat(currStmts);
17853 }, []);
17854 }
17855 freshReferenceName() {
17856 let current = this;
17857 // Find the top scope as it maintains the global reference count
17858 while (current.parent)
17859 current = current.parent;
17860 const ref = `${REFERENCE_PREFIX}${current.referenceNameIndex++}`;
17861 return ref;
17862 }
17863 }
17864 /**
17865 * Creates a `CssSelector` given a tag name and a map of attributes
17866 */
17867 function createCssSelector(elementName, attributes) {
17868 const cssSelector = new CssSelector();
17869 const elementNameNoNs = splitNsName(elementName)[1];
17870 cssSelector.setElement(elementNameNoNs);
17871 Object.getOwnPropertyNames(attributes).forEach((name) => {
17872 const nameNoNs = splitNsName(name)[1];
17873 const value = attributes[name];
17874 cssSelector.addAttribute(nameNoNs, value);
17875 if (name.toLowerCase() === 'class') {
17876 const classes = value.trim().split(/\s+/);
17877 classes.forEach(className => cssSelector.addClassName(className));
17878 }
17879 });
17880 return cssSelector;
17881 }
17882 /**
17883 * Creates an array of expressions out of an `ngProjectAs` attributes
17884 * which can be added to the instruction parameters.
17885 */
17886 function getNgProjectAsLiteral(attribute) {
17887 // Parse the attribute value into a CssSelectorList. Note that we only take the
17888 // first selector, because we don't support multiple selectors in ngProjectAs.
17889 const parsedR3Selector = parseSelectorToR3Selector(attribute.value)[0];
17890 return [literal(5 /* ProjectAs */), asLiteral(parsedR3Selector)];
17891 }
17892 /**
17893 * Gets the instruction to generate for an interpolated property
17894 * @param interpolation An Interpolation AST
17895 */
17896 function getPropertyInterpolationExpression(interpolation) {
17897 switch (getInterpolationArgsLength(interpolation)) {
17898 case 1:
17899 return Identifiers$1.propertyInterpolate;
17900 case 3:
17901 return Identifiers$1.propertyInterpolate1;
17902 case 5:
17903 return Identifiers$1.propertyInterpolate2;
17904 case 7:
17905 return Identifiers$1.propertyInterpolate3;
17906 case 9:
17907 return Identifiers$1.propertyInterpolate4;
17908 case 11:
17909 return Identifiers$1.propertyInterpolate5;
17910 case 13:
17911 return Identifiers$1.propertyInterpolate6;
17912 case 15:
17913 return Identifiers$1.propertyInterpolate7;
17914 case 17:
17915 return Identifiers$1.propertyInterpolate8;
17916 default:
17917 return Identifiers$1.propertyInterpolateV;
17918 }
17919 }
17920 /**
17921 * Gets the instruction to generate for an interpolated attribute
17922 * @param interpolation An Interpolation AST
17923 */
17924 function getAttributeInterpolationExpression(interpolation) {
17925 switch (getInterpolationArgsLength(interpolation)) {
17926 case 3:
17927 return Identifiers$1.attributeInterpolate1;
17928 case 5:
17929 return Identifiers$1.attributeInterpolate2;
17930 case 7:
17931 return Identifiers$1.attributeInterpolate3;
17932 case 9:
17933 return Identifiers$1.attributeInterpolate4;
17934 case 11:
17935 return Identifiers$1.attributeInterpolate5;
17936 case 13:
17937 return Identifiers$1.attributeInterpolate6;
17938 case 15:
17939 return Identifiers$1.attributeInterpolate7;
17940 case 17:
17941 return Identifiers$1.attributeInterpolate8;
17942 default:
17943 return Identifiers$1.attributeInterpolateV;
17944 }
17945 }
17946 /**
17947 * Gets the instruction to generate for interpolated text.
17948 * @param interpolation An Interpolation AST
17949 */
17950 function getTextInterpolationExpression(interpolation) {
17951 switch (getInterpolationArgsLength(interpolation)) {
17952 case 1:
17953 return Identifiers$1.textInterpolate;
17954 case 3:
17955 return Identifiers$1.textInterpolate1;
17956 case 5:
17957 return Identifiers$1.textInterpolate2;
17958 case 7:
17959 return Identifiers$1.textInterpolate3;
17960 case 9:
17961 return Identifiers$1.textInterpolate4;
17962 case 11:
17963 return Identifiers$1.textInterpolate5;
17964 case 13:
17965 return Identifiers$1.textInterpolate6;
17966 case 15:
17967 return Identifiers$1.textInterpolate7;
17968 case 17:
17969 return Identifiers$1.textInterpolate8;
17970 default:
17971 return Identifiers$1.textInterpolateV;
17972 }
17973 }
17974 /**
17975 * Parse a template into render3 `Node`s and additional metadata, with no other dependencies.
17976 *
17977 * @param template text of the template to parse
17978 * @param templateUrl URL to use for source mapping of the parsed template
17979 * @param options options to modify how the template is parsed
17980 */
17981 function parseTemplate(template, templateUrl, options = {}) {
17982 var _a;
17983 const { interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat } = options;
17984 const isInline = (_a = options.isInline) !== null && _a !== void 0 ? _a : false;
17985 const bindingParser = makeBindingParser(interpolationConfig);
17986 const htmlParser = new HtmlParser();
17987 const parseResult = htmlParser.parse(template, templateUrl, Object.assign(Object.assign({ leadingTriviaChars: LEADING_TRIVIA_CHARS }, options), { tokenizeExpansionForms: true }));
17988 if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
17989 parseResult.errors.length > 0) {
17990 return {
17991 interpolationConfig,
17992 preserveWhitespaces,
17993 template,
17994 templateUrl,
17995 isInline,
17996 errors: parseResult.errors,
17997 nodes: [],
17998 styleUrls: [],
17999 styles: [],
18000 ngContentSelectors: []
18001 };
18002 }
18003 let rootNodes = parseResult.rootNodes;
18004 // process i18n meta information (scan attributes, generate ids)
18005 // before we run whitespace removal process, because existing i18n
18006 // extraction process (ng extract-i18n) relies on a raw content to generate
18007 // message ids
18008 const i18nMetaVisitor = new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ !preserveWhitespaces, enableI18nLegacyMessageIdFormat);
18009 const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
18010 if (!options.alwaysAttemptHtmlToR3AstConversion && i18nMetaResult.errors &&
18011 i18nMetaResult.errors.length > 0) {
18012 return {
18013 interpolationConfig,
18014 preserveWhitespaces,
18015 template,
18016 templateUrl,
18017 isInline,
18018 errors: i18nMetaResult.errors,
18019 nodes: [],
18020 styleUrls: [],
18021 styles: [],
18022 ngContentSelectors: []
18023 };
18024 }
18025 rootNodes = i18nMetaResult.rootNodes;
18026 if (!preserveWhitespaces) {
18027 rootNodes = visitAll$1(new WhitespaceVisitor(), rootNodes);
18028 // run i18n meta visitor again in case whitespaces are removed (because that might affect
18029 // generated i18n message content) and first pass indicated that i18n content is present in a
18030 // template. During this pass i18n IDs generated at the first pass will be preserved, so we can
18031 // mimic existing extraction process (ng extract-i18n)
18032 if (i18nMetaVisitor.hasI18nMeta) {
18033 rootNodes = visitAll$1(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
18034 }
18035 }
18036 const { nodes, errors, styleUrls, styles, ngContentSelectors } = htmlAstToRender3Ast(rootNodes, bindingParser);
18037 errors.push(...parseResult.errors, ...i18nMetaResult.errors);
18038 return {
18039 interpolationConfig,
18040 preserveWhitespaces,
18041 errors: errors.length > 0 ? errors : null,
18042 template,
18043 templateUrl,
18044 isInline,
18045 nodes,
18046 styleUrls,
18047 styles,
18048 ngContentSelectors
18049 };
18050 }
18051 const elementRegistry = new DomElementSchemaRegistry();
18052 /**
18053 * Construct a `BindingParser` with a default configuration.
18054 */
18055 function makeBindingParser(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
18056 return new BindingParser(new IvyParser(new Lexer()), interpolationConfig, elementRegistry, null, []);
18057 }
18058 function resolveSanitizationFn(context, isAttribute) {
18059 switch (context) {
18060 case SecurityContext.HTML:
18061 return importExpr(Identifiers$1.sanitizeHtml);
18062 case SecurityContext.SCRIPT:
18063 return importExpr(Identifiers$1.sanitizeScript);
18064 case SecurityContext.STYLE:
18065 // the compiler does not fill in an instruction for [style.prop?] binding
18066 // values because the style algorithm knows internally what props are subject
18067 // to sanitization (only [attr.style] values are explicitly sanitized)
18068 return isAttribute ? importExpr(Identifiers$1.sanitizeStyle) : null;
18069 case SecurityContext.URL:
18070 return importExpr(Identifiers$1.sanitizeUrl);
18071 case SecurityContext.RESOURCE_URL:
18072 return importExpr(Identifiers$1.sanitizeResourceUrl);
18073 default:
18074 return null;
18075 }
18076 }
18077 function trustedConstAttribute(tagName, attr) {
18078 const value = asLiteral(attr.value);
18079 if (isTrustedTypesSink(tagName, attr.name)) {
18080 switch (elementRegistry.securityContext(tagName, attr.name, /* isAttribute */ true)) {
18081 case SecurityContext.HTML:
18082 return taggedTemplate(importExpr(Identifiers$1.trustConstantHtml), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
18083 // NB: no SecurityContext.SCRIPT here, as the corresponding tags are stripped by the compiler.
18084 case SecurityContext.RESOURCE_URL:
18085 return taggedTemplate(importExpr(Identifiers$1.trustConstantResourceUrl), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
18086 default:
18087 return value;
18088 }
18089 }
18090 else {
18091 return value;
18092 }
18093 }
18094 function isSingleElementTemplate(children) {
18095 return children.length === 1 && children[0] instanceof Element;
18096 }
18097 function isTextNode(node) {
18098 return node instanceof Text || node instanceof BoundText || node instanceof Icu;
18099 }
18100 function hasTextChildrenOnly(children) {
18101 return children.every(isTextNode);
18102 }
18103 /** Name of the global variable that is used to determine if we use Closure translations or not */
18104 const NG_I18N_CLOSURE_MODE = 'ngI18nClosureMode';
18105 /**
18106 * Generate statements that define a given translation message.
18107 *
18108 * ```
18109 * var I18N_1;
18110 * if (typeof ngI18nClosureMode !== undefined && ngI18nClosureMode) {
18111 * var MSG_EXTERNAL_XXX = goog.getMsg(
18112 * "Some message with {$interpolation}!",
18113 * { "interpolation": "\uFFFD0\uFFFD" }
18114 * );
18115 * I18N_1 = MSG_EXTERNAL_XXX;
18116 * }
18117 * else {
18118 * I18N_1 = $localize`Some message with ${'\uFFFD0\uFFFD'}!`;
18119 * }
18120 * ```
18121 *
18122 * @param message The original i18n AST message node
18123 * @param variable The variable that will be assigned the translation, e.g. `I18N_1`.
18124 * @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
18125 * @param params Object mapping placeholder names to their values (e.g.
18126 * `{ "interpolation": "\uFFFD0\uFFFD" }`).
18127 * @param transformFn Optional transformation function that will be applied to the translation (e.g.
18128 * post-processing).
18129 * @returns An array of statements that defined a given translation.
18130 */
18131 function getTranslationDeclStmts(message, variable, closureVar, params = {}, transformFn) {
18132 const statements = [
18133 declareI18nVariable(variable),
18134 ifStmt(createClosureModeGuard(), createGoogleGetMsgStatements(variable, message, closureVar, i18nFormatPlaceholderNames(params, /* useCamelCase */ true)), createLocalizeStatements(variable, message, i18nFormatPlaceholderNames(params, /* useCamelCase */ false))),
18135 ];
18136 if (transformFn) {
18137 statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
18138 }
18139 return statements;
18140 }
18141 /**
18142 * Create the expression that will be used to guard the closure mode block
18143 * It is equivalent to:
18144 *
18145 * ```
18146 * typeof ngI18nClosureMode !== undefined && ngI18nClosureMode
18147 * ```
18148 */
18149 function createClosureModeGuard() {
18150 return typeofExpr(variable(NG_I18N_CLOSURE_MODE))
18151 .notIdentical(literal('undefined', STRING_TYPE))
18152 .and(variable(NG_I18N_CLOSURE_MODE));
18153 }
18154
18155 /**
18156 * @license
18157 * Copyright Google LLC All Rights Reserved.
18158 *
18159 * Use of this source code is governed by an MIT-style license that can be
18160 * found in the LICENSE file at https://angular.io/license
18161 */
18162 // This regex matches any binding names that contain the "attr." prefix, e.g. "attr.required"
18163 // If there is a match, the first matching group will contain the attribute name to bind.
18164 const ATTR_REGEX = /attr\.([^\]]+)/;
18165 function baseDirectiveFields(meta, constantPool, bindingParser) {
18166 const definitionMap = new DefinitionMap();
18167 const selectors = parseSelectorToR3Selector(meta.selector);
18168 // e.g. `type: MyDirective`
18169 definitionMap.set('type', meta.internalType);
18170 // e.g. `selectors: [['', 'someDir', '']]`
18171 if (selectors.length > 0) {
18172 definitionMap.set('selectors', asLiteral(selectors));
18173 }
18174 if (meta.queries.length > 0) {
18175 // e.g. `contentQueries: (rf, ctx, dirIndex) => { ... }
18176 definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name));
18177 }
18178 if (meta.viewQueries.length) {
18179 definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name));
18180 }
18181 // e.g. `hostBindings: (rf, ctx) => { ... }
18182 definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', meta.name, definitionMap));
18183 // e.g 'inputs: {a: 'a'}`
18184 definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
18185 // e.g 'outputs: {a: 'a'}`
18186 definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
18187 if (meta.exportAs !== null) {
18188 definitionMap.set('exportAs', literalArr(meta.exportAs.map(e => literal(e))));
18189 }
18190 return definitionMap;
18191 }
18192 /**
18193 * Add features to the definition map.
18194 */
18195 function addFeatures(definitionMap, meta) {
18196 // e.g. `features: [NgOnChangesFeature]`
18197 const features = [];
18198 const providers = meta.providers;
18199 const viewProviders = meta.viewProviders;
18200 if (providers || viewProviders) {
18201 const args = [providers || new LiteralArrayExpr([])];
18202 if (viewProviders) {
18203 args.push(viewProviders);
18204 }
18205 features.push(importExpr(Identifiers$1.ProvidersFeature).callFn(args));
18206 }
18207 if (meta.usesInheritance) {
18208 features.push(importExpr(Identifiers$1.InheritDefinitionFeature));
18209 }
18210 if (meta.fullInheritance) {
18211 features.push(importExpr(Identifiers$1.CopyDefinitionFeature));
18212 }
18213 if (meta.lifecycle.usesOnChanges) {
18214 features.push(importExpr(Identifiers$1.NgOnChangesFeature));
18215 }
18216 if (features.length) {
18217 definitionMap.set('features', literalArr(features));
18218 }
18219 }
18220 /**
18221 * Compile a directive for the render3 runtime as defined by the `R3DirectiveMetadata`.
18222 */
18223 function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
18224 const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
18225 addFeatures(definitionMap, meta);
18226 const expression = importExpr(Identifiers$1.defineDirective).callFn([definitionMap.toLiteralMap()]);
18227 const type = createDirectiveType(meta);
18228 return { expression, type };
18229 }
18230 /**
18231 * Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
18232 */
18233 function compileComponentFromMetadata(meta, constantPool, bindingParser) {
18234 const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
18235 addFeatures(definitionMap, meta);
18236 const selector = meta.selector && CssSelector.parse(meta.selector);
18237 const firstSelector = selector && selector[0];
18238 // e.g. `attr: ["class", ".my.app"]`
18239 // This is optional an only included if the first selector of a component specifies attributes.
18240 if (firstSelector) {
18241 const selectorAttributes = firstSelector.getAttrs();
18242 if (selectorAttributes.length) {
18243 definitionMap.set('attrs', constantPool.getConstLiteral(literalArr(selectorAttributes.map(value => value != null ? literal(value) : literal(undefined))),
18244 /* forceShared */ true));
18245 }
18246 }
18247 // Generate the CSS matcher that recognize directive
18248 let directiveMatcher = null;
18249 if (meta.directives.length > 0) {
18250 const matcher = new SelectorMatcher();
18251 for (const { selector, type } of meta.directives) {
18252 matcher.addSelectables(CssSelector.parse(selector), type);
18253 }
18254 directiveMatcher = matcher;
18255 }
18256 // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
18257 const templateTypeName = meta.name;
18258 const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
18259 const directivesUsed = new Set();
18260 const pipesUsed = new Set();
18261 const changeDetection = meta.changeDetection;
18262 const template = meta.template;
18263 const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, Identifiers$1.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);
18264 const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
18265 // We need to provide this so that dynamically generated components know what
18266 // projected content blocks to pass through to the component when it is instantiated.
18267 const ngContentSelectors = templateBuilder.getNgContentSelectors();
18268 if (ngContentSelectors) {
18269 definitionMap.set('ngContentSelectors', ngContentSelectors);
18270 }
18271 // e.g. `decls: 2`
18272 definitionMap.set('decls', literal(templateBuilder.getConstCount()));
18273 // e.g. `vars: 2`
18274 definitionMap.set('vars', literal(templateBuilder.getVarCount()));
18275 // Generate `consts` section of ComponentDef:
18276 // - either as an array:
18277 // `consts: [['one', 'two'], ['three', 'four']]`
18278 // - or as a factory function in case additional statements are present (to support i18n):
18279 // `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0]; }`
18280 const { constExpressions, prepareStatements } = templateBuilder.getConsts();
18281 if (constExpressions.length > 0) {
18282 let constsExpr = literalArr(constExpressions);
18283 // Prepare statements are present - turn `consts` into a function.
18284 if (prepareStatements.length > 0) {
18285 constsExpr = fn([], [...prepareStatements, new ReturnStatement(constsExpr)]);
18286 }
18287 definitionMap.set('consts', constsExpr);
18288 }
18289 definitionMap.set('template', templateFunctionExpression);
18290 // e.g. `directives: [MyDirective]`
18291 if (directivesUsed.size) {
18292 const directivesList = literalArr(Array.from(directivesUsed));
18293 const directivesExpr = compileDeclarationList(directivesList, meta.declarationListEmitMode);
18294 definitionMap.set('directives', directivesExpr);
18295 }
18296 // e.g. `pipes: [MyPipe]`
18297 if (pipesUsed.size) {
18298 const pipesList = literalArr(Array.from(pipesUsed));
18299 const pipesExpr = compileDeclarationList(pipesList, meta.declarationListEmitMode);
18300 definitionMap.set('pipes', pipesExpr);
18301 }
18302 if (meta.encapsulation === null) {
18303 meta.encapsulation = ViewEncapsulation.Emulated;
18304 }
18305 // e.g. `styles: [str1, str2]`
18306 if (meta.styles && meta.styles.length) {
18307 const styleValues = meta.encapsulation == ViewEncapsulation.Emulated ?
18308 compileStyles(meta.styles, CONTENT_ATTR, HOST_ATTR) :
18309 meta.styles;
18310 const strings = styleValues.map(str => constantPool.getConstLiteral(literal(str)));
18311 definitionMap.set('styles', literalArr(strings));
18312 }
18313 else if (meta.encapsulation === ViewEncapsulation.Emulated) {
18314 // If there is no style, don't generate css selectors on elements
18315 meta.encapsulation = ViewEncapsulation.None;
18316 }
18317 // Only set view encapsulation if it's not the default value
18318 if (meta.encapsulation !== ViewEncapsulation.Emulated) {
18319 definitionMap.set('encapsulation', literal(meta.encapsulation));
18320 }
18321 // e.g. `animation: [trigger('123', [])]`
18322 if (meta.animations !== null) {
18323 definitionMap.set('data', literalMap([{ key: 'animation', value: meta.animations, quoted: false }]));
18324 }
18325 // Only set the change detection flag if it's defined and it's not the default.
18326 if (changeDetection != null && changeDetection !== ChangeDetectionStrategy.Default) {
18327 definitionMap.set('changeDetection', literal(changeDetection));
18328 }
18329 const expression = importExpr(Identifiers$1.defineComponent).callFn([definitionMap.toLiteralMap()]);
18330 const type = createComponentType(meta);
18331 return { expression, type };
18332 }
18333 /**
18334 * Creates the type specification from the component meta. This type is inserted into .d.ts files
18335 * to be consumed by upstream compilations.
18336 */
18337 function createComponentType(meta) {
18338 const typeParams = createDirectiveTypeParams(meta);
18339 typeParams.push(stringArrayAsType(meta.template.ngContentSelectors));
18340 return expressionType(importExpr(Identifiers$1.ComponentDefWithMeta, typeParams));
18341 }
18342 /**
18343 * Compiles the array literal of declarations into an expression according to the provided emit
18344 * mode.
18345 */
18346 function compileDeclarationList(list, mode) {
18347 switch (mode) {
18348 case 0 /* Direct */:
18349 // directives: [MyDir],
18350 return list;
18351 case 1 /* Closure */:
18352 // directives: function () { return [MyDir]; }
18353 return fn([], [new ReturnStatement(list)]);
18354 case 2 /* ClosureResolved */:
18355 // directives: function () { return [MyDir].map(ng.resolveForwardRef); }
18356 const resolvedList = list.callMethod('map', [importExpr(Identifiers$1.resolveForwardRef)]);
18357 return fn([], [new ReturnStatement(resolvedList)]);
18358 }
18359 }
18360 function prepareQueryParams(query, constantPool) {
18361 const parameters = [getQueryPredicate(query, constantPool), literal(toQueryFlags(query))];
18362 if (query.read) {
18363 parameters.push(query.read);
18364 }
18365 return parameters;
18366 }
18367 /**
18368 * Translates query flags into `TQueryFlags` type in packages/core/src/render3/interfaces/query.ts
18369 * @param query
18370 */
18371 function toQueryFlags(query) {
18372 return (query.descendants ? 1 /* descendants */ : 0 /* none */) |
18373 (query.static ? 2 /* isStatic */ : 0 /* none */) |
18374 (query.emitDistinctChangesOnly ? 4 /* emitDistinctChangesOnly */ : 0 /* none */);
18375 }
18376 function convertAttributesToExpressions(attributes) {
18377 const values = [];
18378 for (let key of Object.getOwnPropertyNames(attributes)) {
18379 const value = attributes[key];
18380 values.push(literal(key), value);
18381 }
18382 return values;
18383 }
18384 // Define and update any content queries
18385 function createContentQueriesFunction(queries, constantPool, name) {
18386 const createStatements = [];
18387 const updateStatements = [];
18388 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
18389 for (const query of queries) {
18390 // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null);
18391 createStatements.push(importExpr(Identifiers$1.contentQuery)
18392 .callFn([variable('dirIndex'), ...prepareQueryParams(query, constantPool)])
18393 .toStmt());
18394 // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
18395 const temporary = tempAllocator();
18396 const getQueryList = importExpr(Identifiers$1.loadQuery).callFn([]);
18397 const refresh = importExpr(Identifiers$1.queryRefresh).callFn([temporary.set(getQueryList)]);
18398 const updateDirective = variable(CONTEXT_NAME)
18399 .prop(query.propertyName)
18400 .set(query.first ? temporary.prop('first') : temporary);
18401 updateStatements.push(refresh.and(updateDirective).toStmt());
18402 }
18403 const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
18404 return fn([
18405 new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null),
18406 new FnParam('dirIndex', null)
18407 ], [
18408 renderFlagCheckIfStmt(1 /* Create */, createStatements),
18409 renderFlagCheckIfStmt(2 /* Update */, updateStatements)
18410 ], INFERRED_TYPE, null, contentQueriesFnName);
18411 }
18412 function stringAsType(str) {
18413 return expressionType(literal(str));
18414 }
18415 function stringMapAsType(map) {
18416 const mapValues = Object.keys(map).map(key => {
18417 const value = Array.isArray(map[key]) ? map[key][0] : map[key];
18418 return {
18419 key,
18420 value: literal(value),
18421 quoted: true,
18422 };
18423 });
18424 return expressionType(literalMap(mapValues));
18425 }
18426 function stringArrayAsType(arr) {
18427 return arr.length > 0 ? expressionType(literalArr(arr.map(value => literal(value)))) :
18428 NONE_TYPE;
18429 }
18430 function createDirectiveTypeParams(meta) {
18431 // On the type side, remove newlines from the selector as it will need to fit into a TypeScript
18432 // string literal, which must be on one line.
18433 const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null;
18434 return [
18435 typeWithParameters(meta.type.type, meta.typeArgumentCount),
18436 selectorForType !== null ? stringAsType(selectorForType) : NONE_TYPE,
18437 meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : NONE_TYPE,
18438 stringMapAsType(meta.inputs),
18439 stringMapAsType(meta.outputs),
18440 stringArrayAsType(meta.queries.map(q => q.propertyName)),
18441 ];
18442 }
18443 /**
18444 * Creates the type specification from the directive meta. This type is inserted into .d.ts files
18445 * to be consumed by upstream compilations.
18446 */
18447 function createDirectiveType(meta) {
18448 const typeParams = createDirectiveTypeParams(meta);
18449 return expressionType(importExpr(Identifiers$1.DirectiveDefWithMeta, typeParams));
18450 }
18451 // Define and update any view queries
18452 function createViewQueriesFunction(viewQueries, constantPool, name) {
18453 const createStatements = [];
18454 const updateStatements = [];
18455 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
18456 viewQueries.forEach((query) => {
18457 // creation, e.g. r3.viewQuery(somePredicate, true);
18458 const queryDefinition = importExpr(Identifiers$1.viewQuery).callFn(prepareQueryParams(query, constantPool));
18459 createStatements.push(queryDefinition.toStmt());
18460 // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
18461 const temporary = tempAllocator();
18462 const getQueryList = importExpr(Identifiers$1.loadQuery).callFn([]);
18463 const refresh = importExpr(Identifiers$1.queryRefresh).callFn([temporary.set(getQueryList)]);
18464 const updateDirective = variable(CONTEXT_NAME)
18465 .prop(query.propertyName)
18466 .set(query.first ? temporary.prop('first') : temporary);
18467 updateStatements.push(refresh.and(updateDirective).toStmt());
18468 });
18469 const viewQueryFnName = name ? `${name}_Query` : null;
18470 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
18471 renderFlagCheckIfStmt(1 /* Create */, createStatements),
18472 renderFlagCheckIfStmt(2 /* Update */, updateStatements)
18473 ], INFERRED_TYPE, null, viewQueryFnName);
18474 }
18475 // Return a host binding function or null if one is not necessary.
18476 function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name, definitionMap) {
18477 const bindingContext = variable(CONTEXT_NAME);
18478 const styleBuilder = new StylingBuilder(bindingContext);
18479 const { styleAttr, classAttr } = hostBindingsMetadata.specialAttributes;
18480 if (styleAttr !== undefined) {
18481 styleBuilder.registerStyleAttr(styleAttr);
18482 }
18483 if (classAttr !== undefined) {
18484 styleBuilder.registerClassAttr(classAttr);
18485 }
18486 const createStatements = [];
18487 const updateStatements = [];
18488 const hostBindingSourceSpan = typeSourceSpan;
18489 const directiveSummary = metadataAsSummary(hostBindingsMetadata);
18490 // Calculate host event bindings
18491 const eventBindings = bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan);
18492 if (eventBindings && eventBindings.length) {
18493 const listeners = createHostListeners(eventBindings, name);
18494 createStatements.push(...listeners);
18495 }
18496 // Calculate the host property bindings
18497 const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan);
18498 const allOtherBindings = [];
18499 // We need to calculate the total amount of binding slots required by
18500 // all the instructions together before any value conversions happen.
18501 // Value conversions may require additional slots for interpolation and
18502 // bindings with pipes. These calculates happen after this block.
18503 let totalHostVarsCount = 0;
18504 bindings && bindings.forEach((binding) => {
18505 const stylingInputWasSet = styleBuilder.registerInputBasedOnName(binding.name, binding.expression, hostBindingSourceSpan);
18506 if (stylingInputWasSet) {
18507 totalHostVarsCount += MIN_STYLING_BINDING_SLOTS_REQUIRED;
18508 }
18509 else {
18510 allOtherBindings.push(binding);
18511 totalHostVarsCount++;
18512 }
18513 });
18514 let valueConverter;
18515 const getValueConverter = () => {
18516 if (!valueConverter) {
18517 const hostVarsCountFn = (numSlots) => {
18518 const originalVarsCount = totalHostVarsCount;
18519 totalHostVarsCount += numSlots;
18520 return originalVarsCount;
18521 };
18522 valueConverter = new ValueConverter(constantPool, () => error('Unexpected node'), // new nodes are illegal here
18523 hostVarsCountFn, () => error('Unexpected pipe')); // pipes are illegal here
18524 }
18525 return valueConverter;
18526 };
18527 const propertyBindings = [];
18528 const attributeBindings = [];
18529 const syntheticHostBindings = [];
18530 allOtherBindings.forEach((binding) => {
18531 // resolve literal arrays and literal objects
18532 const value = binding.expression.visit(getValueConverter());
18533 const bindingExpr = bindingFn(bindingContext, value);
18534 const { bindingName, instruction, isAttribute } = getBindingNameAndInstruction(binding);
18535 const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
18536 .filter(context => context !== SecurityContext.NONE);
18537 let sanitizerFn = null;
18538 if (securityContexts.length) {
18539 if (securityContexts.length === 2 &&
18540 securityContexts.indexOf(SecurityContext.URL) > -1 &&
18541 securityContexts.indexOf(SecurityContext.RESOURCE_URL) > -1) {
18542 // Special case for some URL attributes (such as "src" and "href") that may be a part
18543 // of different security contexts. In this case we use special santitization function and
18544 // select the actual sanitizer at runtime based on a tag name that is provided while
18545 // invoking sanitization function.
18546 sanitizerFn = importExpr(Identifiers$1.sanitizeUrlOrResourceUrl);
18547 }
18548 else {
18549 sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute);
18550 }
18551 }
18552 const instructionParams = [literal(bindingName), bindingExpr.currValExpr];
18553 if (sanitizerFn) {
18554 instructionParams.push(sanitizerFn);
18555 }
18556 updateStatements.push(...bindingExpr.stmts);
18557 if (instruction === Identifiers$1.hostProperty) {
18558 propertyBindings.push(instructionParams);
18559 }
18560 else if (instruction === Identifiers$1.attribute) {
18561 attributeBindings.push(instructionParams);
18562 }
18563 else if (instruction === Identifiers$1.syntheticHostProperty) {
18564 syntheticHostBindings.push(instructionParams);
18565 }
18566 else {
18567 updateStatements.push(importExpr(instruction).callFn(instructionParams).toStmt());
18568 }
18569 });
18570 if (propertyBindings.length > 0) {
18571 updateStatements.push(chainedInstruction(Identifiers$1.hostProperty, propertyBindings).toStmt());
18572 }
18573 if (attributeBindings.length > 0) {
18574 updateStatements.push(chainedInstruction(Identifiers$1.attribute, attributeBindings).toStmt());
18575 }
18576 if (syntheticHostBindings.length > 0) {
18577 updateStatements.push(chainedInstruction(Identifiers$1.syntheticHostProperty, syntheticHostBindings).toStmt());
18578 }
18579 // since we're dealing with directives/components and both have hostBinding
18580 // functions, we need to generate a special hostAttrs instruction that deals
18581 // with both the assignment of styling as well as static attributes to the host
18582 // element. The instruction below will instruct all initial styling (styling
18583 // that is inside of a host binding within a directive/component) to be attached
18584 // to the host element alongside any of the provided host attributes that were
18585 // collected earlier.
18586 const hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes);
18587 styleBuilder.assignHostAttrs(hostAttrs, definitionMap);
18588 if (styleBuilder.hasBindings) {
18589 // finally each binding that was registered in the statement above will need to be added to
18590 // the update block of a component/directive templateFn/hostBindingsFn so that the bindings
18591 // are evaluated and updated for the element.
18592 styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(instruction => {
18593 if (instruction.calls.length > 0) {
18594 const calls = [];
18595 instruction.calls.forEach(call => {
18596 // we subtract a value of `1` here because the binding slot was already allocated
18597 // at the top of this method when all the input bindings were counted.
18598 totalHostVarsCount +=
18599 Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
18600 calls.push(convertStylingCall(call, bindingContext, bindingFn));
18601 });
18602 updateStatements.push(chainedInstruction(instruction.reference, calls).toStmt());
18603 }
18604 });
18605 }
18606 if (totalHostVarsCount) {
18607 definitionMap.set('hostVars', literal(totalHostVarsCount));
18608 }
18609 if (createStatements.length > 0 || updateStatements.length > 0) {
18610 const hostBindingsFnName = name ? `${name}_HostBindings` : null;
18611 const statements = [];
18612 if (createStatements.length > 0) {
18613 statements.push(renderFlagCheckIfStmt(1 /* Create */, createStatements));
18614 }
18615 if (updateStatements.length > 0) {
18616 statements.push(renderFlagCheckIfStmt(2 /* Update */, updateStatements));
18617 }
18618 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], statements, INFERRED_TYPE, null, hostBindingsFnName);
18619 }
18620 return null;
18621 }
18622 function bindingFn(implicit, value) {
18623 return convertPropertyBinding(null, implicit, value, 'b', BindingForm.Expression, () => error('Unexpected interpolation'));
18624 }
18625 function convertStylingCall(call, bindingContext, bindingFn) {
18626 return call.params(value => bindingFn(bindingContext, value).currValExpr);
18627 }
18628 function getBindingNameAndInstruction(binding) {
18629 let bindingName = binding.name;
18630 let instruction;
18631 // Check to see if this is an attr binding or a property binding
18632 const attrMatches = bindingName.match(ATTR_REGEX);
18633 if (attrMatches) {
18634 bindingName = attrMatches[1];
18635 instruction = Identifiers$1.attribute;
18636 }
18637 else {
18638 if (binding.isAnimation) {
18639 bindingName = prepareSyntheticPropertyName(bindingName);
18640 // host bindings that have a synthetic property (e.g. @foo) should always be rendered
18641 // in the context of the component and not the parent. Therefore there is a special
18642 // compatibility instruction available for this purpose.
18643 instruction = Identifiers$1.syntheticHostProperty;
18644 }
18645 else {
18646 instruction = Identifiers$1.hostProperty;
18647 }
18648 }
18649 return { bindingName, instruction, isAttribute: !!attrMatches };
18650 }
18651 function createHostListeners(eventBindings, name) {
18652 const listeners = [];
18653 const syntheticListeners = [];
18654 const instructions = [];
18655 eventBindings.forEach(binding => {
18656 let bindingName = binding.name && sanitizeIdentifier(binding.name);
18657 const bindingFnName = binding.type === 1 /* Animation */ ?
18658 prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) :
18659 bindingName;
18660 const handlerName = name && bindingName ? `${name}_${bindingFnName}_HostBindingHandler` : null;
18661 const params = prepareEventListenerParameters(BoundEvent.fromParsedEvent(binding), handlerName);
18662 if (binding.type == 1 /* Animation */) {
18663 syntheticListeners.push(params);
18664 }
18665 else {
18666 listeners.push(params);
18667 }
18668 });
18669 if (syntheticListeners.length > 0) {
18670 instructions.push(chainedInstruction(Identifiers$1.syntheticHostListener, syntheticListeners).toStmt());
18671 }
18672 if (listeners.length > 0) {
18673 instructions.push(chainedInstruction(Identifiers$1.listener, listeners).toStmt());
18674 }
18675 return instructions;
18676 }
18677 function metadataAsSummary(meta) {
18678 // clang-format off
18679 return {
18680 // This is used by the BindingParser, which only deals with listeners and properties. There's no
18681 // need to pass attributes to it.
18682 hostAttributes: {},
18683 hostListeners: meta.listeners,
18684 hostProperties: meta.properties,
18685 };
18686 // clang-format on
18687 }
18688 const HOST_REG_EXP$1 = /^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/;
18689 function parseHostBindings(host) {
18690 const attributes = {};
18691 const listeners = {};
18692 const properties = {};
18693 const specialAttributes = {};
18694 for (const key of Object.keys(host)) {
18695 const value = host[key];
18696 const matches = key.match(HOST_REG_EXP$1);
18697 if (matches === null) {
18698 switch (key) {
18699 case 'class':
18700 if (typeof value !== 'string') {
18701 // TODO(alxhub): make this a diagnostic.
18702 throw new Error(`Class binding must be string`);
18703 }
18704 specialAttributes.classAttr = value;
18705 break;
18706 case 'style':
18707 if (typeof value !== 'string') {
18708 // TODO(alxhub): make this a diagnostic.
18709 throw new Error(`Style binding must be string`);
18710 }
18711 specialAttributes.styleAttr = value;
18712 break;
18713 default:
18714 if (typeof value === 'string') {
18715 attributes[key] = literal(value);
18716 }
18717 else {
18718 attributes[key] = value;
18719 }
18720 }
18721 }
18722 else if (matches[1 /* Binding */] != null) {
18723 if (typeof value !== 'string') {
18724 // TODO(alxhub): make this a diagnostic.
18725 throw new Error(`Property binding must be string`);
18726 }
18727 // synthetic properties (the ones that have a `@` as a prefix)
18728 // are still treated the same as regular properties. Therefore
18729 // there is no point in storing them in a separate map.
18730 properties[matches[1 /* Binding */]] = value;
18731 }
18732 else if (matches[2 /* Event */] != null) {
18733 if (typeof value !== 'string') {
18734 // TODO(alxhub): make this a diagnostic.
18735 throw new Error(`Event binding must be string`);
18736 }
18737 listeners[matches[2 /* Event */]] = value;
18738 }
18739 }
18740 return { attributes, listeners, properties, specialAttributes };
18741 }
18742 /**
18743 * Verifies host bindings and returns the list of errors (if any). Empty array indicates that a
18744 * given set of host bindings has no errors.
18745 *
18746 * @param bindings set of host bindings to verify.
18747 * @param sourceSpan source span where host bindings were defined.
18748 * @returns array of errors associated with a given set of host bindings.
18749 */
18750 function verifyHostBindings(bindings, sourceSpan) {
18751 const summary = metadataAsSummary(bindings);
18752 // TODO: abstract out host bindings verification logic and use it instead of
18753 // creating events and properties ASTs to detect errors (FW-996)
18754 const bindingParser = makeBindingParser();
18755 bindingParser.createDirectiveHostEventAsts(summary, sourceSpan);
18756 bindingParser.createBoundHostProperties(summary, sourceSpan);
18757 return bindingParser.errors;
18758 }
18759 function compileStyles(styles, selector, hostSelector) {
18760 const shadowCss = new ShadowCss();
18761 return styles.map(style => {
18762 return shadowCss.shimCssText(style, selector, hostSelector);
18763 });
18764 }
18765
18766 /**
18767 * @license
18768 * Copyright Google LLC All Rights Reserved.
18769 *
18770 * Use of this source code is governed by an MIT-style license that can be
18771 * found in the LICENSE file at https://angular.io/license
18772 */
18773 /**
18774 * An interface for retrieving documents by URL that the compiler uses
18775 * to load templates.
18776 */
18777 class ResourceLoader {
18778 get(url) {
18779 return '';
18780 }
18781 }
18782
18783 /**
18784 * @license
18785 * Copyright Google LLC All Rights Reserved.
18786 *
18787 * Use of this source code is governed by an MIT-style license that can be
18788 * found in the LICENSE file at https://angular.io/license
18789 */
18790 class CompilerFacadeImpl {
18791 constructor(jitEvaluator = new JitEvaluator()) {
18792 this.jitEvaluator = jitEvaluator;
18793 this.R3ResolvedDependencyType = R3ResolvedDependencyType;
18794 this.R3FactoryTarget = R3FactoryTarget;
18795 this.ResourceLoader = ResourceLoader;
18796 this.elementSchemaRegistry = new DomElementSchemaRegistry();
18797 }
18798 compilePipe(angularCoreEnv, sourceMapUrl, facade) {
18799 const metadata = {
18800 name: facade.name,
18801 type: wrapReference(facade.type),
18802 internalType: new WrappedNodeExpr(facade.type),
18803 typeArgumentCount: facade.typeArgumentCount,
18804 deps: convertR3DependencyMetadataArray(facade.deps),
18805 pipeName: facade.pipeName,
18806 pure: facade.pure,
18807 };
18808 const res = compilePipeFromMetadata(metadata);
18809 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
18810 }
18811 compilePipeDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
18812 const meta = convertDeclarePipeFacadeToMetadata(declaration);
18813 const res = compilePipeFromMetadata(meta);
18814 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
18815 }
18816 compileInjectable(angularCoreEnv, sourceMapUrl, facade) {
18817 const { expression, statements } = compileInjectable({
18818 name: facade.name,
18819 type: wrapReference(facade.type),
18820 internalType: new WrappedNodeExpr(facade.type),
18821 typeArgumentCount: facade.typeArgumentCount,
18822 providedIn: computeProvidedIn(facade.providedIn),
18823 useClass: wrapExpression(facade, USE_CLASS),
18824 useFactory: wrapExpression(facade, USE_FACTORY),
18825 useValue: wrapExpression(facade, USE_VALUE),
18826 useExisting: wrapExpression(facade, USE_EXISTING),
18827 userDeps: convertR3DependencyMetadataArray(facade.userDeps) || undefined,
18828 });
18829 return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
18830 }
18831 compileInjector(angularCoreEnv, sourceMapUrl, facade) {
18832 const meta = {
18833 name: facade.name,
18834 type: wrapReference(facade.type),
18835 internalType: new WrappedNodeExpr(facade.type),
18836 deps: convertR3DependencyMetadataArray(facade.deps),
18837 providers: new WrappedNodeExpr(facade.providers),
18838 imports: facade.imports.map(i => new WrappedNodeExpr(i)),
18839 };
18840 const res = compileInjector(meta);
18841 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
18842 }
18843 compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
18844 const meta = {
18845 type: wrapReference(facade.type),
18846 internalType: new WrappedNodeExpr(facade.type),
18847 adjacentType: new WrappedNodeExpr(facade.type),
18848 bootstrap: facade.bootstrap.map(wrapReference),
18849 declarations: facade.declarations.map(wrapReference),
18850 imports: facade.imports.map(wrapReference),
18851 exports: facade.exports.map(wrapReference),
18852 emitInline: true,
18853 containsForwardDecls: false,
18854 schemas: facade.schemas ? facade.schemas.map(wrapReference) : null,
18855 id: facade.id ? new WrappedNodeExpr(facade.id) : null,
18856 };
18857 const res = compileNgModule(meta);
18858 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
18859 }
18860 compileDirective(angularCoreEnv, sourceMapUrl, facade) {
18861 const meta = convertDirectiveFacadeToMetadata(facade);
18862 return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
18863 }
18864 compileDirectiveDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
18865 const typeSourceSpan = this.createParseSourceSpan('Directive', declaration.type.name, sourceMapUrl);
18866 const meta = convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan);
18867 return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
18868 }
18869 compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta) {
18870 const constantPool = new ConstantPool();
18871 const bindingParser = makeBindingParser();
18872 const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser);
18873 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
18874 }
18875 compileComponent(angularCoreEnv, sourceMapUrl, facade) {
18876 // Parse the template and check for errors.
18877 const { template, interpolation } = parseJitTemplate(facade.template, facade.name, sourceMapUrl, facade.preserveWhitespaces, facade.interpolation);
18878 // Compile the component metadata, including template, into an expression.
18879 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) :
18880 null, relativeContextFilePath: '', i18nUseExternalIds: true });
18881 const jitExpressionSourceMap = `ng:///${facade.name}.js`;
18882 return this.compileComponentFromMeta(angularCoreEnv, jitExpressionSourceMap, meta);
18883 }
18884 compileComponentDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
18885 const typeSourceSpan = this.createParseSourceSpan('Component', declaration.type.name, sourceMapUrl);
18886 const meta = convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl);
18887 return this.compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta);
18888 }
18889 compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta) {
18890 const constantPool = new ConstantPool();
18891 const bindingParser = makeBindingParser(meta.interpolation);
18892 const res = compileComponentFromMetadata(meta, constantPool, bindingParser);
18893 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
18894 }
18895 compileFactory(angularCoreEnv, sourceMapUrl, meta) {
18896 const factoryRes = compileFactoryFunction({
18897 name: meta.name,
18898 type: wrapReference(meta.type),
18899 internalType: new WrappedNodeExpr(meta.type),
18900 typeArgumentCount: meta.typeArgumentCount,
18901 deps: convertR3DependencyMetadataArray(meta.deps),
18902 injectFn: meta.injectFn === 'directiveInject' ? Identifiers.directiveInject :
18903 Identifiers.inject,
18904 target: meta.target,
18905 });
18906 return this.jitExpression(factoryRes.factory, angularCoreEnv, sourceMapUrl, factoryRes.statements);
18907 }
18908 createParseSourceSpan(kind, typeName, sourceUrl) {
18909 return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
18910 }
18911 /**
18912 * JIT compiles an expression and returns the result of executing that expression.
18913 *
18914 * @param def the definition which will be compiled and executed to get the value to patch
18915 * @param context an object map of @angular/core symbol names to symbols which will be available
18916 * in the context of the compiled expression
18917 * @param sourceUrl a URL to use for the source map of the compiled expression
18918 * @param preStatements a collection of statements that should be evaluated before the expression.
18919 */
18920 jitExpression(def, context, sourceUrl, preStatements) {
18921 // The ConstantPool may contain Statements which declare variables used in the final expression.
18922 // Therefore, its statements need to precede the actual JIT operation. The final statement is a
18923 // declaration of $def which is set to the expression being compiled.
18924 const statements = [
18925 ...preStatements,
18926 new DeclareVarStmt('$def', def, undefined, [StmtModifier.Exported]),
18927 ];
18928 const res = this.jitEvaluator.evaluateStatements(sourceUrl, statements, new R3JitReflector(context), /* enableSourceMaps */ true);
18929 return res['$def'];
18930 }
18931 }
18932 const USE_CLASS = Object.keys({ useClass: null })[0];
18933 const USE_FACTORY = Object.keys({ useFactory: null })[0];
18934 const USE_VALUE = Object.keys({ useValue: null })[0];
18935 const USE_EXISTING = Object.keys({ useExisting: null })[0];
18936 const wrapReference = function (value) {
18937 const wrapped = new WrappedNodeExpr(value);
18938 return { value: wrapped, type: wrapped };
18939 };
18940 function convertToR3QueryMetadata(facade) {
18941 return Object.assign(Object.assign({}, facade), { predicate: Array.isArray(facade.predicate) ? facade.predicate :
18942 new WrappedNodeExpr(facade.predicate), read: facade.read ? new WrappedNodeExpr(facade.read) : null, static: facade.static, emitDistinctChangesOnly: facade.emitDistinctChangesOnly });
18943 }
18944 function convertQueryDeclarationToMetadata(declaration) {
18945 var _a, _b, _c, _d;
18946 return {
18947 propertyName: declaration.propertyName,
18948 first: (_a = declaration.first) !== null && _a !== void 0 ? _a : false,
18949 predicate: Array.isArray(declaration.predicate) ? declaration.predicate :
18950 new WrappedNodeExpr(declaration.predicate),
18951 descendants: (_b = declaration.descendants) !== null && _b !== void 0 ? _b : false,
18952 read: declaration.read ? new WrappedNodeExpr(declaration.read) : null,
18953 static: (_c = declaration.static) !== null && _c !== void 0 ? _c : false,
18954 emitDistinctChangesOnly: (_d = declaration.emitDistinctChangesOnly) !== null && _d !== void 0 ? _d : true,
18955 };
18956 }
18957 function convertDirectiveFacadeToMetadata(facade) {
18958 const inputsFromMetadata = parseInputOutputs(facade.inputs || []);
18959 const outputsFromMetadata = parseInputOutputs(facade.outputs || []);
18960 const propMetadata = facade.propMetadata;
18961 const inputsFromType = {};
18962 const outputsFromType = {};
18963 for (const field in propMetadata) {
18964 if (propMetadata.hasOwnProperty(field)) {
18965 propMetadata[field].forEach(ann => {
18966 if (isInput(ann)) {
18967 inputsFromType[field] =
18968 ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field;
18969 }
18970 else if (isOutput(ann)) {
18971 outputsFromType[field] = ann.bindingPropertyName || field;
18972 }
18973 });
18974 }
18975 }
18976 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 });
18977 }
18978 function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
18979 var _a, _b, _c, _d, _e, _f, _g, _h;
18980 return {
18981 name: declaration.type.name,
18982 type: wrapReference(declaration.type),
18983 typeSourceSpan,
18984 internalType: new WrappedNodeExpr(declaration.type),
18985 selector: (_a = declaration.selector) !== null && _a !== void 0 ? _a : null,
18986 inputs: (_b = declaration.inputs) !== null && _b !== void 0 ? _b : {},
18987 outputs: (_c = declaration.outputs) !== null && _c !== void 0 ? _c : {},
18988 host: convertHostDeclarationToMetadata(declaration.host),
18989 queries: ((_d = declaration.queries) !== null && _d !== void 0 ? _d : []).map(convertQueryDeclarationToMetadata),
18990 viewQueries: ((_e = declaration.viewQueries) !== null && _e !== void 0 ? _e : []).map(convertQueryDeclarationToMetadata),
18991 providers: declaration.providers !== undefined ? new WrappedNodeExpr(declaration.providers) :
18992 null,
18993 exportAs: (_f = declaration.exportAs) !== null && _f !== void 0 ? _f : null,
18994 usesInheritance: (_g = declaration.usesInheritance) !== null && _g !== void 0 ? _g : false,
18995 lifecycle: { usesOnChanges: (_h = declaration.usesOnChanges) !== null && _h !== void 0 ? _h : false },
18996 deps: null,
18997 typeArgumentCount: 0,
18998 fullInheritance: false,
18999 };
19000 }
19001 function convertHostDeclarationToMetadata(host = {}) {
19002 var _a, _b, _c;
19003 return {
19004 attributes: convertOpaqueValuesToExpressions((_a = host.attributes) !== null && _a !== void 0 ? _a : {}),
19005 listeners: (_b = host.listeners) !== null && _b !== void 0 ? _b : {},
19006 properties: (_c = host.properties) !== null && _c !== void 0 ? _c : {},
19007 specialAttributes: {
19008 classAttr: host.classAttribute,
19009 styleAttr: host.styleAttribute,
19010 },
19011 };
19012 }
19013 function convertOpaqueValuesToExpressions(obj) {
19014 const result = {};
19015 for (const key of Object.keys(obj)) {
19016 result[key] = new WrappedNodeExpr(obj[key]);
19017 }
19018 return result;
19019 }
19020 function convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl) {
19021 var _a, _b, _c, _d, _e;
19022 const { template, interpolation } = parseJitTemplate(declaration.template, declaration.type.name, sourceMapUrl, (_a = declaration.preserveWhitespaces) !== null && _a !== void 0 ? _a : false, declaration.interpolation);
19023 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 ?
19024 new WrappedNodeExpr(declaration.viewProviders) :
19025 null, animations: declaration.animations !== undefined ? new WrappedNodeExpr(declaration.animations) :
19026 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 });
19027 }
19028 function convertUsedDirectiveDeclarationToMetadata(declaration) {
19029 var _a, _b, _c;
19030 return {
19031 selector: declaration.selector,
19032 type: new WrappedNodeExpr(declaration.type),
19033 inputs: (_a = declaration.inputs) !== null && _a !== void 0 ? _a : [],
19034 outputs: (_b = declaration.outputs) !== null && _b !== void 0 ? _b : [],
19035 exportAs: (_c = declaration.exportAs) !== null && _c !== void 0 ? _c : null,
19036 };
19037 }
19038 function convertUsedPipesToMetadata(declaredPipes) {
19039 const pipes = new Map();
19040 if (declaredPipes === undefined) {
19041 return pipes;
19042 }
19043 for (const pipeName of Object.keys(declaredPipes)) {
19044 const pipeType = declaredPipes[pipeName];
19045 pipes.set(pipeName, new WrappedNodeExpr(pipeType));
19046 }
19047 return pipes;
19048 }
19049 function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
19050 const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
19051 // Parse the template and check for errors.
19052 const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces: preserveWhitespaces, interpolationConfig });
19053 if (parsed.errors !== null) {
19054 const errors = parsed.errors.map(err => err.toString()).join(', ');
19055 throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
19056 }
19057 return { template: parsed, interpolation: interpolationConfig };
19058 }
19059 function wrapExpression(obj, property) {
19060 if (obj.hasOwnProperty(property)) {
19061 return new WrappedNodeExpr(obj[property]);
19062 }
19063 else {
19064 return undefined;
19065 }
19066 }
19067 function computeProvidedIn(providedIn) {
19068 if (providedIn == null || typeof providedIn === 'string') {
19069 return new LiteralExpr(providedIn);
19070 }
19071 else {
19072 return new WrappedNodeExpr(providedIn);
19073 }
19074 }
19075 function convertR3DependencyMetadata(facade) {
19076 let tokenExpr;
19077 if (facade.token === null) {
19078 tokenExpr = new LiteralExpr(null);
19079 }
19080 else if (facade.resolved === R3ResolvedDependencyType.Attribute) {
19081 tokenExpr = new LiteralExpr(facade.token);
19082 }
19083 else {
19084 tokenExpr = new WrappedNodeExpr(facade.token);
19085 }
19086 return {
19087 token: tokenExpr,
19088 attribute: null,
19089 resolved: facade.resolved,
19090 host: facade.host,
19091 optional: facade.optional,
19092 self: facade.self,
19093 skipSelf: facade.skipSelf,
19094 };
19095 }
19096 function convertR3DependencyMetadataArray(facades) {
19097 return facades == null ? null : facades.map(convertR3DependencyMetadata);
19098 }
19099 function extractHostBindings(propMetadata, sourceSpan, host) {
19100 // First parse the declarations from the metadata.
19101 const bindings = parseHostBindings(host || {});
19102 // After that check host bindings for errors
19103 const errors = verifyHostBindings(bindings, sourceSpan);
19104 if (errors.length) {
19105 throw new Error(errors.map((error) => error.msg).join('\n'));
19106 }
19107 // Next, loop over the properties of the object, looking for @HostBinding and @HostListener.
19108 for (const field in propMetadata) {
19109 if (propMetadata.hasOwnProperty(field)) {
19110 propMetadata[field].forEach(ann => {
19111 if (isHostBinding(ann)) {
19112 // Since this is a decorator, we know that the value is a class member. Always access it
19113 // through `this` so that further down the line it can't be confused for a literal value
19114 // (e.g. if there's a property called `true`).
19115 bindings.properties[ann.hostPropertyName || field] =
19116 getSafePropertyAccessString('this', field);
19117 }
19118 else if (isHostListener(ann)) {
19119 bindings.listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`;
19120 }
19121 });
19122 }
19123 }
19124 return bindings;
19125 }
19126 function isHostBinding(value) {
19127 return value.ngMetadataName === 'HostBinding';
19128 }
19129 function isHostListener(value) {
19130 return value.ngMetadataName === 'HostListener';
19131 }
19132 function isInput(value) {
19133 return value.ngMetadataName === 'Input';
19134 }
19135 function isOutput(value) {
19136 return value.ngMetadataName === 'Output';
19137 }
19138 function parseInputOutputs(values) {
19139 return values.reduce((map, value) => {
19140 const [field, property] = value.split(',').map(piece => piece.trim());
19141 map[field] = property || field;
19142 return map;
19143 }, {});
19144 }
19145 function convertDeclarePipeFacadeToMetadata(declaration) {
19146 var _a;
19147 return {
19148 name: declaration.type.name,
19149 type: wrapReference(declaration.type),
19150 internalType: new WrappedNodeExpr(declaration.type),
19151 typeArgumentCount: 0,
19152 pipeName: declaration.name,
19153 deps: null,
19154 pure: (_a = declaration.pure) !== null && _a !== void 0 ? _a : true,
19155 };
19156 }
19157 function publishFacade(global) {
19158 const ng = global.ng || (global.ng = {});
19159 ng.ɵcompilerFacade = new CompilerFacadeImpl();
19160 }
19161
19162 /**
19163 * @license
19164 * Copyright Google LLC All Rights Reserved.
19165 *
19166 * Use of this source code is governed by an MIT-style license that can be
19167 * found in the LICENSE file at https://angular.io/license
19168 */
19169 const VERSION$1 = new Version('11.2.4');
19170
19171 /**
19172 * @license
19173 * Copyright Google LLC All Rights Reserved.
19174 *
19175 * Use of this source code is governed by an MIT-style license that can be
19176 * found in the LICENSE file at https://angular.io/license
19177 */
19178 class CompilerConfig {
19179 constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, jitDevMode = false, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
19180 this.defaultEncapsulation = defaultEncapsulation;
19181 this.useJit = !!useJit;
19182 this.jitDevMode = !!jitDevMode;
19183 this.missingTranslation = missingTranslation;
19184 this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
19185 this.strictInjectionParameters = strictInjectionParameters === true;
19186 }
19187 }
19188 function preserveWhitespacesDefault(preserveWhitespacesOption, defaultSetting = false) {
19189 return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
19190 }
19191
19192 /**
19193 * @license
19194 * Copyright Google LLC All Rights Reserved.
19195 *
19196 * Use of this source code is governed by an MIT-style license that can be
19197 * found in the LICENSE file at https://angular.io/license
19198 */
19199 class DirectiveNormalizer {
19200 constructor(_resourceLoader, _urlResolver, _htmlParser, _config) {
19201 this._resourceLoader = _resourceLoader;
19202 this._urlResolver = _urlResolver;
19203 this._htmlParser = _htmlParser;
19204 this._config = _config;
19205 this._resourceLoaderCache = new Map();
19206 }
19207 clearCache() {
19208 this._resourceLoaderCache.clear();
19209 }
19210 clearCacheFor(normalizedDirective) {
19211 if (!normalizedDirective.isComponent) {
19212 return;
19213 }
19214 const template = normalizedDirective.template;
19215 this._resourceLoaderCache.delete(template.templateUrl);
19216 template.externalStylesheets.forEach((stylesheet) => {
19217 this._resourceLoaderCache.delete(stylesheet.moduleUrl);
19218 });
19219 }
19220 _fetch(url) {
19221 let result = this._resourceLoaderCache.get(url);
19222 if (!result) {
19223 result = this._resourceLoader.get(url);
19224 this._resourceLoaderCache.set(url, result);
19225 }
19226 return result;
19227 }
19228 normalizeTemplate(prenormData) {
19229 if (isDefined(prenormData.template)) {
19230 if (isDefined(prenormData.templateUrl)) {
19231 throw syntaxError(`'${stringify(prenormData
19232 .componentType)}' component cannot define both template and templateUrl`);
19233 }
19234 if (typeof prenormData.template !== 'string') {
19235 throw syntaxError(`The template specified for component ${stringify(prenormData.componentType)} is not a string`);
19236 }
19237 }
19238 else if (isDefined(prenormData.templateUrl)) {
19239 if (typeof prenormData.templateUrl !== 'string') {
19240 throw syntaxError(`The templateUrl specified for component ${stringify(prenormData.componentType)} is not a string`);
19241 }
19242 }
19243 else {
19244 throw syntaxError(`No template specified for component ${stringify(prenormData.componentType)}`);
19245 }
19246 if (isDefined(prenormData.preserveWhitespaces) &&
19247 typeof prenormData.preserveWhitespaces !== 'boolean') {
19248 throw syntaxError(`The preserveWhitespaces option for component ${stringify(prenormData.componentType)} must be a boolean`);
19249 }
19250 return SyncAsync.then(this._preParseTemplate(prenormData), (preparsedTemplate) => this._normalizeTemplateMetadata(prenormData, preparsedTemplate));
19251 }
19252 _preParseTemplate(prenomData) {
19253 let template;
19254 let templateUrl;
19255 if (prenomData.template != null) {
19256 template = prenomData.template;
19257 templateUrl = prenomData.moduleUrl;
19258 }
19259 else {
19260 templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl);
19261 template = this._fetch(templateUrl);
19262 }
19263 return SyncAsync.then(template, (template) => this._preparseLoadedTemplate(prenomData, template, templateUrl));
19264 }
19265 _preparseLoadedTemplate(prenormData, template, templateAbsUrl) {
19266 const isInline = !!prenormData.template;
19267 const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation);
19268 const templateUrl = templateSourceUrl({ reference: prenormData.ngModuleType }, { type: { reference: prenormData.componentType } }, { isInline, templateUrl: templateAbsUrl });
19269 const rootNodesAndErrors = this._htmlParser.parse(template, templateUrl, { tokenizeExpansionForms: true, interpolationConfig });
19270 if (rootNodesAndErrors.errors.length > 0) {
19271 const errorString = rootNodesAndErrors.errors.join('\n');
19272 throw syntaxError(`Template parse errors:\n${errorString}`);
19273 }
19274 const templateMetadataStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: prenormData.styles, moduleUrl: prenormData.moduleUrl }));
19275 const visitor = new TemplatePreparseVisitor();
19276 visitAll$1(visitor, rootNodesAndErrors.rootNodes);
19277 const templateStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl }));
19278 const styles = templateMetadataStyles.styles.concat(templateStyles.styles);
19279 const inlineStyleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
19280 const styleUrls = this
19281 ._normalizeStylesheet(new CompileStylesheetMetadata({ styleUrls: prenormData.styleUrls, moduleUrl: prenormData.moduleUrl }))
19282 .styleUrls;
19283 return {
19284 template,
19285 templateUrl: templateAbsUrl,
19286 isInline,
19287 htmlAst: rootNodesAndErrors,
19288 styles,
19289 inlineStyleUrls,
19290 styleUrls,
19291 ngContentSelectors: visitor.ngContentSelectors,
19292 };
19293 }
19294 _normalizeTemplateMetadata(prenormData, preparsedTemplate) {
19295 return SyncAsync.then(this._loadMissingExternalStylesheets(preparsedTemplate.styleUrls.concat(preparsedTemplate.inlineStyleUrls)), (externalStylesheets) => this._normalizeLoadedTemplateMetadata(prenormData, preparsedTemplate, externalStylesheets));
19296 }
19297 _normalizeLoadedTemplateMetadata(prenormData, preparsedTemplate, stylesheets) {
19298 // Algorithm:
19299 // - produce exactly 1 entry per original styleUrl in
19300 // CompileTemplateMetadata.externalStylesheets with all styles inlined
19301 // - inline all styles that are referenced by the template into CompileTemplateMetadata.styles.
19302 // Reason: be able to determine how many stylesheets there are even without loading
19303 // the template nor the stylesheets, so we can create a stub for TypeScript always synchronously
19304 // (as resource loading may be async)
19305 const styles = [...preparsedTemplate.styles];
19306 this._inlineStyles(preparsedTemplate.inlineStyleUrls, stylesheets, styles);
19307 const styleUrls = preparsedTemplate.styleUrls;
19308 const externalStylesheets = styleUrls.map(styleUrl => {
19309 const stylesheet = stylesheets.get(styleUrl);
19310 const styles = [...stylesheet.styles];
19311 this._inlineStyles(stylesheet.styleUrls, stylesheets, styles);
19312 return new CompileStylesheetMetadata({ moduleUrl: styleUrl, styles: styles });
19313 });
19314 let encapsulation = prenormData.encapsulation;
19315 if (encapsulation == null) {
19316 encapsulation = this._config.defaultEncapsulation;
19317 }
19318 if (encapsulation === ViewEncapsulation.Emulated && styles.length === 0 &&
19319 styleUrls.length === 0) {
19320 encapsulation = ViewEncapsulation.None;
19321 }
19322 return new CompileTemplateMetadata({
19323 encapsulation,
19324 template: preparsedTemplate.template,
19325 templateUrl: preparsedTemplate.templateUrl,
19326 htmlAst: preparsedTemplate.htmlAst,
19327 styles,
19328 styleUrls,
19329 ngContentSelectors: preparsedTemplate.ngContentSelectors,
19330 animations: prenormData.animations,
19331 interpolation: prenormData.interpolation,
19332 isInline: preparsedTemplate.isInline,
19333 externalStylesheets,
19334 preserveWhitespaces: preserveWhitespacesDefault(prenormData.preserveWhitespaces, this._config.preserveWhitespaces),
19335 });
19336 }
19337 _inlineStyles(styleUrls, stylesheets, targetStyles) {
19338 styleUrls.forEach(styleUrl => {
19339 const stylesheet = stylesheets.get(styleUrl);
19340 stylesheet.styles.forEach(style => targetStyles.push(style));
19341 this._inlineStyles(stylesheet.styleUrls, stylesheets, targetStyles);
19342 });
19343 }
19344 _loadMissingExternalStylesheets(styleUrls, loadedStylesheets = new Map()) {
19345 return SyncAsync.then(SyncAsync.all(styleUrls.filter((styleUrl) => !loadedStylesheets.has(styleUrl))
19346 .map(styleUrl => SyncAsync.then(this._fetch(styleUrl), (loadedStyle) => {
19347 const stylesheet = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: [loadedStyle], moduleUrl: styleUrl }));
19348 loadedStylesheets.set(styleUrl, stylesheet);
19349 return this._loadMissingExternalStylesheets(stylesheet.styleUrls, loadedStylesheets);
19350 }))), (_) => loadedStylesheets);
19351 }
19352 _normalizeStylesheet(stylesheet) {
19353 const moduleUrl = stylesheet.moduleUrl;
19354 const allStyleUrls = stylesheet.styleUrls.filter(isStyleUrlResolvable)
19355 .map(url => this._urlResolver.resolve(moduleUrl, url));
19356 const allStyles = stylesheet.styles.map(style => {
19357 const styleWithImports = extractStyleUrls(this._urlResolver, moduleUrl, style);
19358 allStyleUrls.push(...styleWithImports.styleUrls);
19359 return styleWithImports.style;
19360 });
19361 return new CompileStylesheetMetadata({ styles: allStyles, styleUrls: allStyleUrls, moduleUrl: moduleUrl });
19362 }
19363 }
19364 class TemplatePreparseVisitor {
19365 constructor() {
19366 this.ngContentSelectors = [];
19367 this.styles = [];
19368 this.styleUrls = [];
19369 this.ngNonBindableStackCount = 0;
19370 }
19371 visitElement(ast, context) {
19372 const preparsedElement = preparseElement(ast);
19373 switch (preparsedElement.type) {
19374 case PreparsedElementType.NG_CONTENT:
19375 if (this.ngNonBindableStackCount === 0) {
19376 this.ngContentSelectors.push(preparsedElement.selectAttr);
19377 }
19378 break;
19379 case PreparsedElementType.STYLE:
19380 let textContent = '';
19381 ast.children.forEach(child => {
19382 if (child instanceof Text$2) {
19383 textContent += child.value;
19384 }
19385 });
19386 this.styles.push(textContent);
19387 break;
19388 case PreparsedElementType.STYLESHEET:
19389 this.styleUrls.push(preparsedElement.hrefAttr);
19390 break;
19391 }
19392 if (preparsedElement.nonBindable) {
19393 this.ngNonBindableStackCount++;
19394 }
19395 visitAll$1(this, ast.children);
19396 if (preparsedElement.nonBindable) {
19397 this.ngNonBindableStackCount--;
19398 }
19399 return null;
19400 }
19401 visitExpansion(ast, context) {
19402 visitAll$1(this, ast.cases);
19403 }
19404 visitExpansionCase(ast, context) {
19405 visitAll$1(this, ast.expression);
19406 }
19407 visitComment(ast, context) {
19408 return null;
19409 }
19410 visitAttribute(ast, context) {
19411 return null;
19412 }
19413 visitText(ast, context) {
19414 return null;
19415 }
19416 }
19417
19418 /**
19419 * @license
19420 * Copyright Google LLC All Rights Reserved.
19421 *
19422 * Use of this source code is governed by an MIT-style license that can be
19423 * found in the LICENSE file at https://angular.io/license
19424 */
19425 const QUERY_METADATA_IDENTIFIERS = [
19426 createViewChild,
19427 createViewChildren,
19428 createContentChild,
19429 createContentChildren,
19430 ];
19431 /*
19432 * Resolve a `Type` for {@link Directive}.
19433 *
19434 * This interface can be overridden by the application developer to create custom behavior.
19435 *
19436 * See {@link Compiler}
19437 */
19438 class DirectiveResolver {
19439 constructor(_reflector) {
19440 this._reflector = _reflector;
19441 }
19442 isDirective(type) {
19443 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
19444 return typeMetadata && typeMetadata.some(isDirectiveMetadata);
19445 }
19446 resolve(type, throwIfNotFound = true) {
19447 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
19448 if (typeMetadata) {
19449 const metadata = findLast(typeMetadata, isDirectiveMetadata);
19450 if (metadata) {
19451 const propertyMetadata = this._reflector.propMetadata(type);
19452 const guards = this._reflector.guards(type);
19453 return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
19454 }
19455 }
19456 if (throwIfNotFound) {
19457 throw new Error(`No Directive annotation found on ${stringify(type)}`);
19458 }
19459 return null;
19460 }
19461 _mergeWithPropertyMetadata(dm, propertyMetadata, guards, directiveType) {
19462 const inputs = [];
19463 const outputs = [];
19464 const host = {};
19465 const queries = {};
19466 Object.keys(propertyMetadata).forEach((propName) => {
19467 const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
19468 if (input) {
19469 if (input.bindingPropertyName) {
19470 inputs.push(`${propName}: ${input.bindingPropertyName}`);
19471 }
19472 else {
19473 inputs.push(propName);
19474 }
19475 }
19476 const output = findLast(propertyMetadata[propName], (a) => createOutput.isTypeOf(a));
19477 if (output) {
19478 if (output.bindingPropertyName) {
19479 outputs.push(`${propName}: ${output.bindingPropertyName}`);
19480 }
19481 else {
19482 outputs.push(propName);
19483 }
19484 }
19485 const hostBindings = propertyMetadata[propName].filter(a => createHostBinding.isTypeOf(a));
19486 hostBindings.forEach(hostBinding => {
19487 if (hostBinding.hostPropertyName) {
19488 const startWith = hostBinding.hostPropertyName[0];
19489 if (startWith === '(') {
19490 throw new Error(`@HostBinding can not bind to events. Use @HostListener instead.`);
19491 }
19492 else if (startWith === '[') {
19493 throw new Error(`@HostBinding parameter should be a property name, 'class.<name>', or 'attr.<name>'.`);
19494 }
19495 host[`[${hostBinding.hostPropertyName}]`] = propName;
19496 }
19497 else {
19498 host[`[${propName}]`] = propName;
19499 }
19500 });
19501 const hostListeners = propertyMetadata[propName].filter(a => createHostListener.isTypeOf(a));
19502 hostListeners.forEach(hostListener => {
19503 const args = hostListener.args || [];
19504 host[`(${hostListener.eventName})`] = `${propName}(${args.join(',')})`;
19505 });
19506 const query = findLast(propertyMetadata[propName], (a) => QUERY_METADATA_IDENTIFIERS.some(i => i.isTypeOf(a)));
19507 if (query) {
19508 queries[propName] = query;
19509 }
19510 });
19511 return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
19512 }
19513 _extractPublicName(def) {
19514 return splitAtColon(def, [null, def])[1].trim();
19515 }
19516 _dedupeBindings(bindings) {
19517 const names = new Set();
19518 const publicNames = new Set();
19519 const reversedResult = [];
19520 // go last to first to allow later entries to overwrite previous entries
19521 for (let i = bindings.length - 1; i >= 0; i--) {
19522 const binding = bindings[i];
19523 const name = this._extractPublicName(binding);
19524 publicNames.add(name);
19525 if (!names.has(name)) {
19526 names.add(name);
19527 reversedResult.push(binding);
19528 }
19529 }
19530 return reversedResult.reverse();
19531 }
19532 _merge(directive, inputs, outputs, host, queries, guards, directiveType) {
19533 const mergedInputs = this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
19534 const mergedOutputs = this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
19535 const mergedHost = directive.host ? Object.assign(Object.assign({}, directive.host), host) : host;
19536 const mergedQueries = directive.queries ? Object.assign(Object.assign({}, directive.queries), queries) : queries;
19537 if (createComponent.isTypeOf(directive)) {
19538 const comp = directive;
19539 return createComponent({
19540 selector: comp.selector,
19541 inputs: mergedInputs,
19542 outputs: mergedOutputs,
19543 host: mergedHost,
19544 exportAs: comp.exportAs,
19545 moduleId: comp.moduleId,
19546 queries: mergedQueries,
19547 changeDetection: comp.changeDetection,
19548 providers: comp.providers,
19549 viewProviders: comp.viewProviders,
19550 entryComponents: comp.entryComponents,
19551 template: comp.template,
19552 templateUrl: comp.templateUrl,
19553 styles: comp.styles,
19554 styleUrls: comp.styleUrls,
19555 encapsulation: comp.encapsulation,
19556 animations: comp.animations,
19557 interpolation: comp.interpolation,
19558 preserveWhitespaces: directive.preserveWhitespaces,
19559 });
19560 }
19561 else {
19562 return createDirective({
19563 selector: directive.selector,
19564 inputs: mergedInputs,
19565 outputs: mergedOutputs,
19566 host: mergedHost,
19567 exportAs: directive.exportAs,
19568 queries: mergedQueries,
19569 providers: directive.providers,
19570 guards
19571 });
19572 }
19573 }
19574 }
19575 function isDirectiveMetadata(type) {
19576 return createDirective.isTypeOf(type) || createComponent.isTypeOf(type);
19577 }
19578 function findLast(arr, condition) {
19579 for (let i = arr.length - 1; i >= 0; i--) {
19580 if (condition(arr[i])) {
19581 return arr[i];
19582 }
19583 }
19584 return null;
19585 }
19586
19587 /**
19588 * @license
19589 * Copyright Google LLC All Rights Reserved.
19590 *
19591 * Use of this source code is governed by an MIT-style license that can be
19592 * found in the LICENSE file at https://angular.io/license
19593 */
19594 var _VisitorMode;
19595 (function (_VisitorMode) {
19596 _VisitorMode[_VisitorMode["Extract"] = 0] = "Extract";
19597 _VisitorMode[_VisitorMode["Merge"] = 1] = "Merge";
19598 })(_VisitorMode || (_VisitorMode = {}));
19599
19600 /**
19601 * @license
19602 * Copyright Google LLC All Rights Reserved.
19603 *
19604 * Use of this source code is governed by an MIT-style license that can be
19605 * found in the LICENSE file at https://angular.io/license
19606 */
19607 const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
19608 const GENERATED_FILE = /\.ngfactory\.|\.ngsummary\./;
19609 const JIT_SUMMARY_FILE = /\.ngsummary\./;
19610 const JIT_SUMMARY_NAME = /NgSummary$/;
19611 function ngfactoryFilePath(filePath, forceSourceFile = false) {
19612 const urlWithSuffix = splitTypescriptSuffix(filePath, forceSourceFile);
19613 return `${urlWithSuffix[0]}.ngfactory${normalizeGenFileSuffix(urlWithSuffix[1])}`;
19614 }
19615 function stripGeneratedFileSuffix(filePath) {
19616 return filePath.replace(GENERATED_FILE, '.');
19617 }
19618 function isGeneratedFile(filePath) {
19619 return GENERATED_FILE.test(filePath);
19620 }
19621 function splitTypescriptSuffix(path, forceSourceFile = false) {
19622 if (path.endsWith('.d.ts')) {
19623 return [path.slice(0, -5), forceSourceFile ? '.ts' : '.d.ts'];
19624 }
19625 const lastDot = path.lastIndexOf('.');
19626 if (lastDot !== -1) {
19627 return [path.substring(0, lastDot), path.substring(lastDot)];
19628 }
19629 return [path, ''];
19630 }
19631 function normalizeGenFileSuffix(srcFileSuffix) {
19632 return srcFileSuffix === '.tsx' ? '.ts' : srcFileSuffix;
19633 }
19634 function summaryFileName(fileName) {
19635 const fileNameWithoutSuffix = fileName.replace(STRIP_SRC_FILE_SUFFIXES, '');
19636 return `${fileNameWithoutSuffix}.ngsummary.json`;
19637 }
19638 function summaryForJitFileName(fileName, forceSourceFile = false) {
19639 const urlWithSuffix = splitTypescriptSuffix(stripGeneratedFileSuffix(fileName), forceSourceFile);
19640 return `${urlWithSuffix[0]}.ngsummary${urlWithSuffix[1]}`;
19641 }
19642 function stripSummaryForJitFileSuffix(filePath) {
19643 return filePath.replace(JIT_SUMMARY_FILE, '.');
19644 }
19645 function summaryForJitName(symbolName) {
19646 return `${symbolName}NgSummary`;
19647 }
19648 function stripSummaryForJitNameSuffix(symbolName) {
19649 return symbolName.replace(JIT_SUMMARY_NAME, '');
19650 }
19651
19652 /**
19653 * @license
19654 * Copyright Google LLC All Rights Reserved.
19655 *
19656 * Use of this source code is governed by an MIT-style license that can be
19657 * found in the LICENSE file at https://angular.io/license
19658 */
19659 var LifecycleHooks;
19660 (function (LifecycleHooks) {
19661 LifecycleHooks[LifecycleHooks["OnInit"] = 0] = "OnInit";
19662 LifecycleHooks[LifecycleHooks["OnDestroy"] = 1] = "OnDestroy";
19663 LifecycleHooks[LifecycleHooks["DoCheck"] = 2] = "DoCheck";
19664 LifecycleHooks[LifecycleHooks["OnChanges"] = 3] = "OnChanges";
19665 LifecycleHooks[LifecycleHooks["AfterContentInit"] = 4] = "AfterContentInit";
19666 LifecycleHooks[LifecycleHooks["AfterContentChecked"] = 5] = "AfterContentChecked";
19667 LifecycleHooks[LifecycleHooks["AfterViewInit"] = 6] = "AfterViewInit";
19668 LifecycleHooks[LifecycleHooks["AfterViewChecked"] = 7] = "AfterViewChecked";
19669 })(LifecycleHooks || (LifecycleHooks = {}));
19670 const LIFECYCLE_HOOKS_VALUES = [
19671 LifecycleHooks.OnInit, LifecycleHooks.OnDestroy, LifecycleHooks.DoCheck, LifecycleHooks.OnChanges,
19672 LifecycleHooks.AfterContentInit, LifecycleHooks.AfterContentChecked, LifecycleHooks.AfterViewInit,
19673 LifecycleHooks.AfterViewChecked
19674 ];
19675 function hasLifecycleHook(reflector, hook, token) {
19676 return reflector.hasLifecycleHook(token, getHookName(hook));
19677 }
19678 function getAllLifecycleHooks(reflector, token) {
19679 return LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(reflector, hook, token));
19680 }
19681 function getHookName(hook) {
19682 switch (hook) {
19683 case LifecycleHooks.OnInit:
19684 return 'ngOnInit';
19685 case LifecycleHooks.OnDestroy:
19686 return 'ngOnDestroy';
19687 case LifecycleHooks.DoCheck:
19688 return 'ngDoCheck';
19689 case LifecycleHooks.OnChanges:
19690 return 'ngOnChanges';
19691 case LifecycleHooks.AfterContentInit:
19692 return 'ngAfterContentInit';
19693 case LifecycleHooks.AfterContentChecked:
19694 return 'ngAfterContentChecked';
19695 case LifecycleHooks.AfterViewInit:
19696 return 'ngAfterViewInit';
19697 case LifecycleHooks.AfterViewChecked:
19698 return 'ngAfterViewChecked';
19699 default:
19700 // This default case is not needed by TypeScript compiler, as the switch is exhaustive.
19701 // However Closure Compiler does not understand that and reports an error in typed mode.
19702 // The `throw new Error` below works around the problem, and the unexpected: never variable
19703 // makes sure tsc still checks this code is unreachable.
19704 const unexpected = hook;
19705 throw new Error(`unexpected ${unexpected}`);
19706 }
19707 }
19708
19709 /**
19710 * @license
19711 * Copyright Google LLC All Rights Reserved.
19712 *
19713 * Use of this source code is governed by an MIT-style license that can be
19714 * found in the LICENSE file at https://angular.io/license
19715 */
19716 const ERROR_COMPONENT_TYPE = 'ngComponentType';
19717 // Design notes:
19718 // - don't lazily create metadata:
19719 // For some metadata, we need to do async work sometimes,
19720 // so the user has to kick off this loading.
19721 // But we want to report errors even when the async work is
19722 // not required to check that the user would have been able
19723 // to wait correctly.
19724 class CompileMetadataResolver {
19725 constructor(_config, _htmlParser, _ngModuleResolver, _directiveResolver, _pipeResolver, _summaryResolver, _schemaRegistry, _directiveNormalizer, _console, _staticSymbolCache, _reflector, _errorCollector) {
19726 this._config = _config;
19727 this._htmlParser = _htmlParser;
19728 this._ngModuleResolver = _ngModuleResolver;
19729 this._directiveResolver = _directiveResolver;
19730 this._pipeResolver = _pipeResolver;
19731 this._summaryResolver = _summaryResolver;
19732 this._schemaRegistry = _schemaRegistry;
19733 this._directiveNormalizer = _directiveNormalizer;
19734 this._console = _console;
19735 this._staticSymbolCache = _staticSymbolCache;
19736 this._reflector = _reflector;
19737 this._errorCollector = _errorCollector;
19738 this._nonNormalizedDirectiveCache = new Map();
19739 this._directiveCache = new Map();
19740 this._summaryCache = new Map();
19741 this._pipeCache = new Map();
19742 this._ngModuleCache = new Map();
19743 this._ngModuleOfTypes = new Map();
19744 this._shallowModuleCache = new Map();
19745 }
19746 getReflector() {
19747 return this._reflector;
19748 }
19749 clearCacheFor(type) {
19750 const dirMeta = this._directiveCache.get(type);
19751 this._directiveCache.delete(type);
19752 this._nonNormalizedDirectiveCache.delete(type);
19753 this._summaryCache.delete(type);
19754 this._pipeCache.delete(type);
19755 this._ngModuleOfTypes.delete(type);
19756 // Clear all of the NgModule as they contain transitive information!
19757 this._ngModuleCache.clear();
19758 if (dirMeta) {
19759 this._directiveNormalizer.clearCacheFor(dirMeta);
19760 }
19761 }
19762 clearCache() {
19763 this._directiveCache.clear();
19764 this._nonNormalizedDirectiveCache.clear();
19765 this._summaryCache.clear();
19766 this._pipeCache.clear();
19767 this._ngModuleCache.clear();
19768 this._ngModuleOfTypes.clear();
19769 this._directiveNormalizer.clearCache();
19770 }
19771 _createProxyClass(baseType, name) {
19772 let delegate = null;
19773 const proxyClass = function () {
19774 if (!delegate) {
19775 throw new Error(`Illegal state: Class ${name} for type ${stringify(baseType)} is not compiled yet!`);
19776 }
19777 return delegate.apply(this, arguments);
19778 };
19779 proxyClass.setDelegate = (d) => {
19780 delegate = d;
19781 proxyClass.prototype = d.prototype;
19782 };
19783 // Make stringify work correctly
19784 proxyClass.overriddenName = name;
19785 return proxyClass;
19786 }
19787 getGeneratedClass(dirType, name) {
19788 if (dirType instanceof StaticSymbol) {
19789 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), name);
19790 }
19791 else {
19792 return this._createProxyClass(dirType, name);
19793 }
19794 }
19795 getComponentViewClass(dirType) {
19796 return this.getGeneratedClass(dirType, viewClassName(dirType, 0));
19797 }
19798 getHostComponentViewClass(dirType) {
19799 return this.getGeneratedClass(dirType, hostViewClassName(dirType));
19800 }
19801 getHostComponentType(dirType) {
19802 const name = `${identifierName({ reference: dirType })}_Host`;
19803 if (dirType instanceof StaticSymbol) {
19804 return this._staticSymbolCache.get(dirType.filePath, name);
19805 }
19806 return this._createProxyClass(dirType, name);
19807 }
19808 getRendererType(dirType) {
19809 if (dirType instanceof StaticSymbol) {
19810 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), rendererTypeName(dirType));
19811 }
19812 else {
19813 // returning an object as proxy,
19814 // that we fill later during runtime compilation.
19815 return {};
19816 }
19817 }
19818 getComponentFactory(selector, dirType, inputs, outputs) {
19819 if (dirType instanceof StaticSymbol) {
19820 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), componentFactoryName(dirType));
19821 }
19822 else {
19823 const hostView = this.getHostComponentViewClass(dirType);
19824 // Note: ngContentSelectors will be filled later once the template is
19825 // loaded.
19826 const createComponentFactory = this._reflector.resolveExternalReference(Identifiers.createComponentFactory);
19827 return createComponentFactory(selector, dirType, hostView, inputs, outputs, []);
19828 }
19829 }
19830 initComponentFactory(factory, ngContentSelectors) {
19831 if (!(factory instanceof StaticSymbol)) {
19832 factory.ngContentSelectors.push(...ngContentSelectors);
19833 }
19834 }
19835 _loadSummary(type, kind) {
19836 let typeSummary = this._summaryCache.get(type);
19837 if (!typeSummary) {
19838 const summary = this._summaryResolver.resolveSummary(type);
19839 typeSummary = summary ? summary.type : null;
19840 this._summaryCache.set(type, typeSummary || null);
19841 }
19842 return typeSummary && typeSummary.summaryKind === kind ? typeSummary : null;
19843 }
19844 getHostComponentMetadata(compMeta, hostViewType) {
19845 const hostType = this.getHostComponentType(compMeta.type.reference);
19846 if (!hostViewType) {
19847 hostViewType = this.getHostComponentViewClass(hostType);
19848 }
19849 // Note: ! is ok here as this method should only be called with normalized directive
19850 // metadata, which always fills in the selector.
19851 const template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
19852 const templateUrl = '';
19853 const htmlAst = this._htmlParser.parse(template, templateUrl);
19854 return CompileDirectiveMetadata.create({
19855 isHost: true,
19856 type: { reference: hostType, diDeps: [], lifecycleHooks: [] },
19857 template: new CompileTemplateMetadata({
19858 encapsulation: ViewEncapsulation.None,
19859 template,
19860 templateUrl,
19861 htmlAst,
19862 styles: [],
19863 styleUrls: [],
19864 ngContentSelectors: [],
19865 animations: [],
19866 isInline: true,
19867 externalStylesheets: [],
19868 interpolation: null,
19869 preserveWhitespaces: false,
19870 }),
19871 exportAs: null,
19872 changeDetection: ChangeDetectionStrategy.Default,
19873 inputs: [],
19874 outputs: [],
19875 host: {},
19876 isComponent: true,
19877 selector: '*',
19878 providers: [],
19879 viewProviders: [],
19880 queries: [],
19881 guards: {},
19882 viewQueries: [],
19883 componentViewType: hostViewType,
19884 rendererType: { id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {} },
19885 entryComponents: [],
19886 componentFactory: null
19887 });
19888 }
19889 loadDirectiveMetadata(ngModuleType, directiveType, isSync) {
19890 if (this._directiveCache.has(directiveType)) {
19891 return null;
19892 }
19893 directiveType = resolveForwardRef(directiveType);
19894 const { annotation, metadata } = this.getNonNormalizedDirectiveMetadata(directiveType);
19895 const createDirectiveMetadata = (templateMetadata) => {
19896 const normalizedDirMeta = new CompileDirectiveMetadata({
19897 isHost: false,
19898 type: metadata.type,
19899 isComponent: metadata.isComponent,
19900 selector: metadata.selector,
19901 exportAs: metadata.exportAs,
19902 changeDetection: metadata.changeDetection,
19903 inputs: metadata.inputs,
19904 outputs: metadata.outputs,
19905 hostListeners: metadata.hostListeners,
19906 hostProperties: metadata.hostProperties,
19907 hostAttributes: metadata.hostAttributes,
19908 providers: metadata.providers,
19909 viewProviders: metadata.viewProviders,
19910 queries: metadata.queries,
19911 guards: metadata.guards,
19912 viewQueries: metadata.viewQueries,
19913 entryComponents: metadata.entryComponents,
19914 componentViewType: metadata.componentViewType,
19915 rendererType: metadata.rendererType,
19916 componentFactory: metadata.componentFactory,
19917 template: templateMetadata
19918 });
19919 if (templateMetadata) {
19920 this.initComponentFactory(metadata.componentFactory, templateMetadata.ngContentSelectors);
19921 }
19922 this._directiveCache.set(directiveType, normalizedDirMeta);
19923 this._summaryCache.set(directiveType, normalizedDirMeta.toSummary());
19924 return null;
19925 };
19926 if (metadata.isComponent) {
19927 const template = metadata.template;
19928 const templateMeta = this._directiveNormalizer.normalizeTemplate({
19929 ngModuleType,
19930 componentType: directiveType,
19931 moduleUrl: this._reflector.componentModuleUrl(directiveType, annotation),
19932 encapsulation: template.encapsulation,
19933 template: template.template,
19934 templateUrl: template.templateUrl,
19935 styles: template.styles,
19936 styleUrls: template.styleUrls,
19937 animations: template.animations,
19938 interpolation: template.interpolation,
19939 preserveWhitespaces: template.preserveWhitespaces
19940 });
19941 if (isPromise(templateMeta) && isSync) {
19942 this._reportError(componentStillLoadingError(directiveType), directiveType);
19943 return null;
19944 }
19945 return SyncAsync.then(templateMeta, createDirectiveMetadata);
19946 }
19947 else {
19948 // directive
19949 createDirectiveMetadata(null);
19950 return null;
19951 }
19952 }
19953 getNonNormalizedDirectiveMetadata(directiveType) {
19954 directiveType = resolveForwardRef(directiveType);
19955 if (!directiveType) {
19956 return null;
19957 }
19958 let cacheEntry = this._nonNormalizedDirectiveCache.get(directiveType);
19959 if (cacheEntry) {
19960 return cacheEntry;
19961 }
19962 const dirMeta = this._directiveResolver.resolve(directiveType, false);
19963 if (!dirMeta) {
19964 return null;
19965 }
19966 let nonNormalizedTemplateMetadata = undefined;
19967 if (createComponent.isTypeOf(dirMeta)) {
19968 // component
19969 const compMeta = dirMeta;
19970 assertArrayOfStrings('styles', compMeta.styles);
19971 assertArrayOfStrings('styleUrls', compMeta.styleUrls);
19972 assertInterpolationSymbols('interpolation', compMeta.interpolation);
19973 const animations = compMeta.animations;
19974 nonNormalizedTemplateMetadata = new CompileTemplateMetadata({
19975 encapsulation: noUndefined(compMeta.encapsulation),
19976 template: noUndefined(compMeta.template),
19977 templateUrl: noUndefined(compMeta.templateUrl),
19978 htmlAst: null,
19979 styles: compMeta.styles || [],
19980 styleUrls: compMeta.styleUrls || [],
19981 animations: animations || [],
19982 interpolation: noUndefined(compMeta.interpolation),
19983 isInline: !!compMeta.template,
19984 externalStylesheets: [],
19985 ngContentSelectors: [],
19986 preserveWhitespaces: noUndefined(dirMeta.preserveWhitespaces),
19987 });
19988 }
19989 let changeDetectionStrategy = null;
19990 let viewProviders = [];
19991 let entryComponentMetadata = [];
19992 let selector = dirMeta.selector;
19993 if (createComponent.isTypeOf(dirMeta)) {
19994 // Component
19995 const compMeta = dirMeta;
19996 changeDetectionStrategy = compMeta.changeDetection;
19997 if (compMeta.viewProviders) {
19998 viewProviders = this._getProvidersMetadata(compMeta.viewProviders, entryComponentMetadata, `viewProviders for "${stringifyType(directiveType)}"`, [], directiveType);
19999 }
20000 if (compMeta.entryComponents) {
20001 entryComponentMetadata = flattenAndDedupeArray(compMeta.entryComponents)
20002 .map((type) => this._getEntryComponentMetadata(type))
20003 .concat(entryComponentMetadata);
20004 }
20005 if (!selector) {
20006 selector = this._schemaRegistry.getDefaultComponentElementName();
20007 }
20008 }
20009 else {
20010 // Directive
20011 if (!selector) {
20012 selector = null;
20013 }
20014 }
20015 let providers = [];
20016 if (dirMeta.providers != null) {
20017 providers = this._getProvidersMetadata(dirMeta.providers, entryComponentMetadata, `providers for "${stringifyType(directiveType)}"`, [], directiveType);
20018 }
20019 let queries = [];
20020 let viewQueries = [];
20021 if (dirMeta.queries != null) {
20022 queries = this._getQueriesMetadata(dirMeta.queries, false, directiveType);
20023 viewQueries = this._getQueriesMetadata(dirMeta.queries, true, directiveType);
20024 }
20025 const metadata = CompileDirectiveMetadata.create({
20026 isHost: false,
20027 selector: selector,
20028 exportAs: noUndefined(dirMeta.exportAs),
20029 isComponent: !!nonNormalizedTemplateMetadata,
20030 type: this._getTypeMetadata(directiveType),
20031 template: nonNormalizedTemplateMetadata,
20032 changeDetection: changeDetectionStrategy,
20033 inputs: dirMeta.inputs || [],
20034 outputs: dirMeta.outputs || [],
20035 host: dirMeta.host || {},
20036 providers: providers || [],
20037 viewProviders: viewProviders || [],
20038 queries: queries || [],
20039 guards: dirMeta.guards || {},
20040 viewQueries: viewQueries || [],
20041 entryComponents: entryComponentMetadata,
20042 componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
20043 null,
20044 rendererType: nonNormalizedTemplateMetadata ? this.getRendererType(directiveType) : null,
20045 componentFactory: null
20046 });
20047 if (nonNormalizedTemplateMetadata) {
20048 metadata.componentFactory =
20049 this.getComponentFactory(selector, directiveType, metadata.inputs, metadata.outputs);
20050 }
20051 cacheEntry = { metadata, annotation: dirMeta };
20052 this._nonNormalizedDirectiveCache.set(directiveType, cacheEntry);
20053 return cacheEntry;
20054 }
20055 /**
20056 * Gets the metadata for the given directive.
20057 * This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
20058 */
20059 getDirectiveMetadata(directiveType) {
20060 const dirMeta = this._directiveCache.get(directiveType);
20061 if (!dirMeta) {
20062 this._reportError(syntaxError(`Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${stringifyType(directiveType)}.`), directiveType);
20063 }
20064 return dirMeta;
20065 }
20066 getDirectiveSummary(dirType) {
20067 const dirSummary = this._loadSummary(dirType, CompileSummaryKind.Directive);
20068 if (!dirSummary) {
20069 this._reportError(syntaxError(`Illegal state: Could not load the summary for directive ${stringifyType(dirType)}.`), dirType);
20070 }
20071 return dirSummary;
20072 }
20073 isDirective(type) {
20074 return !!this._loadSummary(type, CompileSummaryKind.Directive) ||
20075 this._directiveResolver.isDirective(type);
20076 }
20077 isAbstractDirective(type) {
20078 const summary = this._loadSummary(type, CompileSummaryKind.Directive);
20079 if (summary && !summary.isComponent) {
20080 return !summary.selector;
20081 }
20082 const meta = this._directiveResolver.resolve(type, false);
20083 if (meta && !createComponent.isTypeOf(meta)) {
20084 return !meta.selector;
20085 }
20086 return false;
20087 }
20088 isPipe(type) {
20089 return !!this._loadSummary(type, CompileSummaryKind.Pipe) ||
20090 this._pipeResolver.isPipe(type);
20091 }
20092 isNgModule(type) {
20093 return !!this._loadSummary(type, CompileSummaryKind.NgModule) ||
20094 this._ngModuleResolver.isNgModule(type);
20095 }
20096 getNgModuleSummary(moduleType, alreadyCollecting = null) {
20097 let moduleSummary = this._loadSummary(moduleType, CompileSummaryKind.NgModule);
20098 if (!moduleSummary) {
20099 const moduleMeta = this.getNgModuleMetadata(moduleType, false, alreadyCollecting);
20100 moduleSummary = moduleMeta ? moduleMeta.toSummary() : null;
20101 if (moduleSummary) {
20102 this._summaryCache.set(moduleType, moduleSummary);
20103 }
20104 }
20105 return moduleSummary;
20106 }
20107 /**
20108 * Loads the declared directives and pipes of an NgModule.
20109 */
20110 loadNgModuleDirectiveAndPipeMetadata(moduleType, isSync, throwIfNotFound = true) {
20111 const ngModule = this.getNgModuleMetadata(moduleType, throwIfNotFound);
20112 const loading = [];
20113 if (ngModule) {
20114 ngModule.declaredDirectives.forEach((id) => {
20115 const promise = this.loadDirectiveMetadata(moduleType, id.reference, isSync);
20116 if (promise) {
20117 loading.push(promise);
20118 }
20119 });
20120 ngModule.declaredPipes.forEach((id) => this._loadPipeMetadata(id.reference));
20121 }
20122 return Promise.all(loading);
20123 }
20124 getShallowModuleMetadata(moduleType) {
20125 let compileMeta = this._shallowModuleCache.get(moduleType);
20126 if (compileMeta) {
20127 return compileMeta;
20128 }
20129 const ngModuleMeta = findLast(this._reflector.shallowAnnotations(moduleType), createNgModule.isTypeOf);
20130 compileMeta = {
20131 type: this._getTypeMetadata(moduleType),
20132 rawExports: ngModuleMeta.exports,
20133 rawImports: ngModuleMeta.imports,
20134 rawProviders: ngModuleMeta.providers,
20135 };
20136 this._shallowModuleCache.set(moduleType, compileMeta);
20137 return compileMeta;
20138 }
20139 getNgModuleMetadata(moduleType, throwIfNotFound = true, alreadyCollecting = null) {
20140 moduleType = resolveForwardRef(moduleType);
20141 let compileMeta = this._ngModuleCache.get(moduleType);
20142 if (compileMeta) {
20143 return compileMeta;
20144 }
20145 const meta = this._ngModuleResolver.resolve(moduleType, throwIfNotFound);
20146 if (!meta) {
20147 return null;
20148 }
20149 const declaredDirectives = [];
20150 const exportedNonModuleIdentifiers = [];
20151 const declaredPipes = [];
20152 const importedModules = [];
20153 const exportedModules = [];
20154 const providers = [];
20155 const entryComponents = [];
20156 const bootstrapComponents = [];
20157 const schemas = [];
20158 if (meta.imports) {
20159 flattenAndDedupeArray(meta.imports).forEach((importedType) => {
20160 let importedModuleType = undefined;
20161 if (isValidType(importedType)) {
20162 importedModuleType = importedType;
20163 }
20164 else if (importedType && importedType.ngModule) {
20165 const moduleWithProviders = importedType;
20166 importedModuleType = moduleWithProviders.ngModule;
20167 if (moduleWithProviders.providers) {
20168 providers.push(...this._getProvidersMetadata(moduleWithProviders.providers, entryComponents, `provider for the NgModule '${stringifyType(importedModuleType)}'`, [], importedType));
20169 }
20170 }
20171 if (importedModuleType) {
20172 if (this._checkSelfImport(moduleType, importedModuleType))
20173 return;
20174 if (!alreadyCollecting)
20175 alreadyCollecting = new Set();
20176 if (alreadyCollecting.has(importedModuleType)) {
20177 this._reportError(syntaxError(`${this._getTypeDescriptor(importedModuleType)} '${stringifyType(importedType)}' is imported recursively by the module '${stringifyType(moduleType)}'.`), moduleType);
20178 return;
20179 }
20180 alreadyCollecting.add(importedModuleType);
20181 const importedModuleSummary = this.getNgModuleSummary(importedModuleType, alreadyCollecting);
20182 alreadyCollecting.delete(importedModuleType);
20183 if (!importedModuleSummary) {
20184 this._reportError(syntaxError(`Unexpected ${this._getTypeDescriptor(importedType)} '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'. Please add a @NgModule annotation.`), moduleType);
20185 return;
20186 }
20187 importedModules.push(importedModuleSummary);
20188 }
20189 else {
20190 this._reportError(syntaxError(`Unexpected value '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'`), moduleType);
20191 return;
20192 }
20193 });
20194 }
20195 if (meta.exports) {
20196 flattenAndDedupeArray(meta.exports).forEach((exportedType) => {
20197 if (!isValidType(exportedType)) {
20198 this._reportError(syntaxError(`Unexpected value '${stringifyType(exportedType)}' exported by the module '${stringifyType(moduleType)}'`), moduleType);
20199 return;
20200 }
20201 if (!alreadyCollecting)
20202 alreadyCollecting = new Set();
20203 if (alreadyCollecting.has(exportedType)) {
20204 this._reportError(syntaxError(`${this._getTypeDescriptor(exportedType)} '${stringify(exportedType)}' is exported recursively by the module '${stringifyType(moduleType)}'`), moduleType);
20205 return;
20206 }
20207 alreadyCollecting.add(exportedType);
20208 const exportedModuleSummary = this.getNgModuleSummary(exportedType, alreadyCollecting);
20209 alreadyCollecting.delete(exportedType);
20210 if (exportedModuleSummary) {
20211 exportedModules.push(exportedModuleSummary);
20212 }
20213 else {
20214 exportedNonModuleIdentifiers.push(this._getIdentifierMetadata(exportedType));
20215 }
20216 });
20217 }
20218 // Note: This will be modified later, so we rely on
20219 // getting a new instance every time!
20220 const transitiveModule = this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
20221 if (meta.declarations) {
20222 flattenAndDedupeArray(meta.declarations).forEach((declaredType) => {
20223 if (!isValidType(declaredType)) {
20224 this._reportError(syntaxError(`Unexpected value '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'`), moduleType);
20225 return;
20226 }
20227 const declaredIdentifier = this._getIdentifierMetadata(declaredType);
20228 if (this.isDirective(declaredType)) {
20229 if (this.isAbstractDirective(declaredType)) {
20230 this._reportError(syntaxError(`Directive ${stringifyType(declaredType)} has no selector, please add it!`), declaredType);
20231 }
20232 transitiveModule.addDirective(declaredIdentifier);
20233 declaredDirectives.push(declaredIdentifier);
20234 this._addTypeToModule(declaredType, moduleType);
20235 }
20236 else if (this.isPipe(declaredType)) {
20237 transitiveModule.addPipe(declaredIdentifier);
20238 transitiveModule.pipes.push(declaredIdentifier);
20239 declaredPipes.push(declaredIdentifier);
20240 this._addTypeToModule(declaredType, moduleType);
20241 }
20242 else {
20243 this._reportError(syntaxError(`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`), moduleType);
20244 return;
20245 }
20246 });
20247 }
20248 const exportedDirectives = [];
20249 const exportedPipes = [];
20250 exportedNonModuleIdentifiers.forEach((exportedId) => {
20251 if (transitiveModule.directivesSet.has(exportedId.reference)) {
20252 exportedDirectives.push(exportedId);
20253 transitiveModule.addExportedDirective(exportedId);
20254 }
20255 else if (transitiveModule.pipesSet.has(exportedId.reference)) {
20256 exportedPipes.push(exportedId);
20257 transitiveModule.addExportedPipe(exportedId);
20258 }
20259 else {
20260 this._reportError(syntaxError(`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringifyType(exportedId.reference)} from ${stringifyType(moduleType)} as it was neither declared nor imported!`), moduleType);
20261 return;
20262 }
20263 });
20264 // The providers of the module have to go last
20265 // so that they overwrite any other provider we already added.
20266 if (meta.providers) {
20267 providers.push(...this._getProvidersMetadata(meta.providers, entryComponents, `provider for the NgModule '${stringifyType(moduleType)}'`, [], moduleType));
20268 }
20269 if (meta.entryComponents) {
20270 entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
20271 .map(type => this._getEntryComponentMetadata(type)));
20272 }
20273 if (meta.bootstrap) {
20274 flattenAndDedupeArray(meta.bootstrap).forEach(type => {
20275 if (!isValidType(type)) {
20276 this._reportError(syntaxError(`Unexpected value '${stringifyType(type)}' used in the bootstrap property of module '${stringifyType(moduleType)}'`), moduleType);
20277 return;
20278 }
20279 bootstrapComponents.push(this._getIdentifierMetadata(type));
20280 });
20281 }
20282 entryComponents.push(...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference)));
20283 if (meta.schemas) {
20284 schemas.push(...flattenAndDedupeArray(meta.schemas));
20285 }
20286 compileMeta = new CompileNgModuleMetadata({
20287 type: this._getTypeMetadata(moduleType),
20288 providers,
20289 entryComponents,
20290 bootstrapComponents,
20291 schemas,
20292 declaredDirectives,
20293 exportedDirectives,
20294 declaredPipes,
20295 exportedPipes,
20296 importedModules,
20297 exportedModules,
20298 transitiveModule,
20299 id: meta.id || null,
20300 });
20301 entryComponents.forEach((id) => transitiveModule.addEntryComponent(id));
20302 providers.forEach((provider) => transitiveModule.addProvider(provider, compileMeta.type));
20303 transitiveModule.addModule(compileMeta.type);
20304 this._ngModuleCache.set(moduleType, compileMeta);
20305 return compileMeta;
20306 }
20307 _checkSelfImport(moduleType, importedModuleType) {
20308 if (moduleType === importedModuleType) {
20309 this._reportError(syntaxError(`'${stringifyType(moduleType)}' module can't import itself`), moduleType);
20310 return true;
20311 }
20312 return false;
20313 }
20314 _getTypeDescriptor(type) {
20315 if (isValidType(type)) {
20316 if (this.isDirective(type)) {
20317 return 'directive';
20318 }
20319 if (this.isPipe(type)) {
20320 return 'pipe';
20321 }
20322 if (this.isNgModule(type)) {
20323 return 'module';
20324 }
20325 }
20326 if (type.provide) {
20327 return 'provider';
20328 }
20329 return 'value';
20330 }
20331 _addTypeToModule(type, moduleType) {
20332 const oldModule = this._ngModuleOfTypes.get(type);
20333 if (oldModule && oldModule !== moduleType) {
20334 this._reportError(syntaxError(`Type ${stringifyType(type)} is part of the declarations of 2 modules: ${stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` +
20335 `Please consider moving ${stringifyType(type)} to a higher module that imports ${stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` +
20336 `You can also create a new NgModule that exports and includes ${stringifyType(type)} then import that NgModule in ${stringifyType(oldModule)} and ${stringifyType(moduleType)}.`), moduleType);
20337 return;
20338 }
20339 this._ngModuleOfTypes.set(type, moduleType);
20340 }
20341 _getTransitiveNgModuleMetadata(importedModules, exportedModules) {
20342 // collect `providers` / `entryComponents` from all imported and all exported modules
20343 const result = new TransitiveCompileNgModuleMetadata();
20344 const modulesByToken = new Map();
20345 importedModules.concat(exportedModules).forEach((modSummary) => {
20346 modSummary.modules.forEach((mod) => result.addModule(mod));
20347 modSummary.entryComponents.forEach((comp) => result.addEntryComponent(comp));
20348 const addedTokens = new Set();
20349 modSummary.providers.forEach((entry) => {
20350 const tokenRef = tokenReference(entry.provider.token);
20351 let prevModules = modulesByToken.get(tokenRef);
20352 if (!prevModules) {
20353 prevModules = new Set();
20354 modulesByToken.set(tokenRef, prevModules);
20355 }
20356 const moduleRef = entry.module.reference;
20357 // Note: the providers of one module may still contain multiple providers
20358 // per token (e.g. for multi providers), and we need to preserve these.
20359 if (addedTokens.has(tokenRef) || !prevModules.has(moduleRef)) {
20360 prevModules.add(moduleRef);
20361 addedTokens.add(tokenRef);
20362 result.addProvider(entry.provider, entry.module);
20363 }
20364 });
20365 });
20366 exportedModules.forEach((modSummary) => {
20367 modSummary.exportedDirectives.forEach((id) => result.addExportedDirective(id));
20368 modSummary.exportedPipes.forEach((id) => result.addExportedPipe(id));
20369 });
20370 importedModules.forEach((modSummary) => {
20371 modSummary.exportedDirectives.forEach((id) => result.addDirective(id));
20372 modSummary.exportedPipes.forEach((id) => result.addPipe(id));
20373 });
20374 return result;
20375 }
20376 _getIdentifierMetadata(type) {
20377 type = resolveForwardRef(type);
20378 return { reference: type };
20379 }
20380 isInjectable(type) {
20381 const annotations = this._reflector.tryAnnotations(type);
20382 return annotations.some(ann => createInjectable.isTypeOf(ann));
20383 }
20384 getInjectableSummary(type) {
20385 return {
20386 summaryKind: CompileSummaryKind.Injectable,
20387 type: this._getTypeMetadata(type, null, false)
20388 };
20389 }
20390 getInjectableMetadata(type, dependencies = null, throwOnUnknownDeps = true) {
20391 const typeSummary = this._loadSummary(type, CompileSummaryKind.Injectable);
20392 const typeMetadata = typeSummary ?
20393 typeSummary.type :
20394 this._getTypeMetadata(type, dependencies, throwOnUnknownDeps);
20395 const annotations = this._reflector.annotations(type).filter(ann => createInjectable.isTypeOf(ann));
20396 if (annotations.length === 0) {
20397 return null;
20398 }
20399 const meta = annotations[annotations.length - 1];
20400 return {
20401 symbol: type,
20402 type: typeMetadata,
20403 providedIn: meta.providedIn,
20404 useValue: meta.useValue,
20405 useClass: meta.useClass,
20406 useExisting: meta.useExisting,
20407 useFactory: meta.useFactory,
20408 deps: meta.deps,
20409 };
20410 }
20411 _getTypeMetadata(type, dependencies = null, throwOnUnknownDeps = true) {
20412 const identifier = this._getIdentifierMetadata(type);
20413 return {
20414 reference: identifier.reference,
20415 diDeps: this._getDependenciesMetadata(identifier.reference, dependencies, throwOnUnknownDeps),
20416 lifecycleHooks: getAllLifecycleHooks(this._reflector, identifier.reference),
20417 };
20418 }
20419 _getFactoryMetadata(factory, dependencies = null) {
20420 factory = resolveForwardRef(factory);
20421 return { reference: factory, diDeps: this._getDependenciesMetadata(factory, dependencies) };
20422 }
20423 /**
20424 * Gets the metadata for the given pipe.
20425 * This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
20426 */
20427 getPipeMetadata(pipeType) {
20428 const pipeMeta = this._pipeCache.get(pipeType);
20429 if (!pipeMeta) {
20430 this._reportError(syntaxError(`Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${stringifyType(pipeType)}.`), pipeType);
20431 }
20432 return pipeMeta || null;
20433 }
20434 getPipeSummary(pipeType) {
20435 const pipeSummary = this._loadSummary(pipeType, CompileSummaryKind.Pipe);
20436 if (!pipeSummary) {
20437 this._reportError(syntaxError(`Illegal state: Could not load the summary for pipe ${stringifyType(pipeType)}.`), pipeType);
20438 }
20439 return pipeSummary;
20440 }
20441 getOrLoadPipeMetadata(pipeType) {
20442 let pipeMeta = this._pipeCache.get(pipeType);
20443 if (!pipeMeta) {
20444 pipeMeta = this._loadPipeMetadata(pipeType);
20445 }
20446 return pipeMeta;
20447 }
20448 _loadPipeMetadata(pipeType) {
20449 pipeType = resolveForwardRef(pipeType);
20450 const pipeAnnotation = this._pipeResolver.resolve(pipeType);
20451 const pipeMeta = new CompilePipeMetadata({
20452 type: this._getTypeMetadata(pipeType),
20453 name: pipeAnnotation.name,
20454 pure: !!pipeAnnotation.pure
20455 });
20456 this._pipeCache.set(pipeType, pipeMeta);
20457 this._summaryCache.set(pipeType, pipeMeta.toSummary());
20458 return pipeMeta;
20459 }
20460 _getDependenciesMetadata(typeOrFunc, dependencies, throwOnUnknownDeps = true) {
20461 let hasUnknownDeps = false;
20462 const params = dependencies || this._reflector.parameters(typeOrFunc) || [];
20463 const dependenciesMetadata = params.map((param) => {
20464 let isAttribute = false;
20465 let isHost = false;
20466 let isSelf = false;
20467 let isSkipSelf = false;
20468 let isOptional = false;
20469 let token = null;
20470 if (Array.isArray(param)) {
20471 param.forEach((paramEntry) => {
20472 if (createHost.isTypeOf(paramEntry)) {
20473 isHost = true;
20474 }
20475 else if (createSelf.isTypeOf(paramEntry)) {
20476 isSelf = true;
20477 }
20478 else if (createSkipSelf.isTypeOf(paramEntry)) {
20479 isSkipSelf = true;
20480 }
20481 else if (createOptional.isTypeOf(paramEntry)) {
20482 isOptional = true;
20483 }
20484 else if (createAttribute.isTypeOf(paramEntry)) {
20485 isAttribute = true;
20486 token = paramEntry.attributeName;
20487 }
20488 else if (createInject.isTypeOf(paramEntry)) {
20489 token = paramEntry.token;
20490 }
20491 else if (createInjectionToken.isTypeOf(paramEntry) ||
20492 paramEntry instanceof StaticSymbol) {
20493 token = paramEntry;
20494 }
20495 else if (isValidType(paramEntry) && token == null) {
20496 token = paramEntry;
20497 }
20498 });
20499 }
20500 else {
20501 token = param;
20502 }
20503 if (token == null) {
20504 hasUnknownDeps = true;
20505 return {};
20506 }
20507 return {
20508 isAttribute,
20509 isHost,
20510 isSelf,
20511 isSkipSelf,
20512 isOptional,
20513 token: this._getTokenMetadata(token)
20514 };
20515 });
20516 if (hasUnknownDeps) {
20517 const depsTokens = dependenciesMetadata.map((dep) => dep.token ? stringifyType(dep.token) : '?').join(', ');
20518 const message = `Can't resolve all parameters for ${stringifyType(typeOrFunc)}: (${depsTokens}).`;
20519 if (throwOnUnknownDeps || this._config.strictInjectionParameters) {
20520 this._reportError(syntaxError(message), typeOrFunc);
20521 }
20522 }
20523 return dependenciesMetadata;
20524 }
20525 _getTokenMetadata(token) {
20526 token = resolveForwardRef(token);
20527 let compileToken;
20528 if (typeof token === 'string') {
20529 compileToken = { value: token };
20530 }
20531 else {
20532 compileToken = { identifier: { reference: token } };
20533 }
20534 return compileToken;
20535 }
20536 _getProvidersMetadata(providers, targetEntryComponents, debugInfo, compileProviders = [], type) {
20537 providers.forEach((provider, providerIdx) => {
20538 if (Array.isArray(provider)) {
20539 this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
20540 }
20541 else {
20542 provider = resolveForwardRef(provider);
20543 let providerMeta = undefined;
20544 if (provider && typeof provider === 'object' && provider.hasOwnProperty('provide')) {
20545 this._validateProvider(provider);
20546 providerMeta = new ProviderMeta(provider.provide, provider);
20547 }
20548 else if (isValidType(provider)) {
20549 providerMeta = new ProviderMeta(provider, { useClass: provider });
20550 }
20551 else if (provider === void 0) {
20552 this._reportError(syntaxError(`Encountered undefined provider! Usually this means you have a circular dependencies. This might be caused by using 'barrel' index.ts files.`));
20553 return;
20554 }
20555 else {
20556 const providersInfo = providers
20557 .reduce((soFar, seenProvider, seenProviderIdx) => {
20558 if (seenProviderIdx < providerIdx) {
20559 soFar.push(`${stringifyType(seenProvider)}`);
20560 }
20561 else if (seenProviderIdx == providerIdx) {
20562 soFar.push(`?${stringifyType(seenProvider)}?`);
20563 }
20564 else if (seenProviderIdx == providerIdx + 1) {
20565 soFar.push('...');
20566 }
20567 return soFar;
20568 }, [])
20569 .join(', ');
20570 this._reportError(syntaxError(`Invalid ${debugInfo ?
20571 debugInfo :
20572 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`), type);
20573 return;
20574 }
20575 if (providerMeta.token ===
20576 this._reflector.resolveExternalReference(Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS)) {
20577 targetEntryComponents.push(...this._getEntryComponentsFromProvider(providerMeta, type));
20578 }
20579 else {
20580 compileProviders.push(this.getProviderMetadata(providerMeta));
20581 }
20582 }
20583 });
20584 return compileProviders;
20585 }
20586 _validateProvider(provider) {
20587 if (provider.hasOwnProperty('useClass') && provider.useClass == null) {
20588 this._reportError(syntaxError(`Invalid provider for ${stringifyType(provider.provide)}. useClass cannot be ${provider.useClass}.
20589 Usually it happens when:
20590 1. There's a circular dependency (might be caused by using index.ts (barrel) files).
20591 2. Class was used before it was declared. Use forwardRef in this case.`));
20592 }
20593 }
20594 _getEntryComponentsFromProvider(provider, type) {
20595 const components = [];
20596 const collectedIdentifiers = [];
20597 if (provider.useFactory || provider.useExisting || provider.useClass) {
20598 this._reportError(syntaxError(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!`), type);
20599 return [];
20600 }
20601 if (!provider.multi) {
20602 this._reportError(syntaxError(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!`), type);
20603 return [];
20604 }
20605 extractIdentifiers(provider.useValue, collectedIdentifiers);
20606 collectedIdentifiers.forEach((identifier) => {
20607 const entry = this._getEntryComponentMetadata(identifier.reference, false);
20608 if (entry) {
20609 components.push(entry);
20610 }
20611 });
20612 return components;
20613 }
20614 _getEntryComponentMetadata(dirType, throwIfNotFound = true) {
20615 const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
20616 if (dirMeta && dirMeta.metadata.isComponent) {
20617 return { componentType: dirType, componentFactory: dirMeta.metadata.componentFactory };
20618 }
20619 const dirSummary = this._loadSummary(dirType, CompileSummaryKind.Directive);
20620 if (dirSummary && dirSummary.isComponent) {
20621 return { componentType: dirType, componentFactory: dirSummary.componentFactory };
20622 }
20623 if (throwIfNotFound) {
20624 throw syntaxError(`${dirType.name} cannot be used as an entry component.`);
20625 }
20626 return null;
20627 }
20628 _getInjectableTypeMetadata(type, dependencies = null) {
20629 const typeSummary = this._loadSummary(type, CompileSummaryKind.Injectable);
20630 if (typeSummary) {
20631 return typeSummary.type;
20632 }
20633 return this._getTypeMetadata(type, dependencies);
20634 }
20635 getProviderMetadata(provider) {
20636 let compileDeps = undefined;
20637 let compileTypeMetadata = null;
20638 let compileFactoryMetadata = null;
20639 let token = this._getTokenMetadata(provider.token);
20640 if (provider.useClass) {
20641 compileTypeMetadata =
20642 this._getInjectableTypeMetadata(provider.useClass, provider.dependencies);
20643 compileDeps = compileTypeMetadata.diDeps;
20644 if (provider.token === provider.useClass) {
20645 // use the compileTypeMetadata as it contains information about lifecycleHooks...
20646 token = { identifier: compileTypeMetadata };
20647 }
20648 }
20649 else if (provider.useFactory) {
20650 compileFactoryMetadata = this._getFactoryMetadata(provider.useFactory, provider.dependencies);
20651 compileDeps = compileFactoryMetadata.diDeps;
20652 }
20653 return {
20654 token: token,
20655 useClass: compileTypeMetadata,
20656 useValue: provider.useValue,
20657 useFactory: compileFactoryMetadata,
20658 useExisting: provider.useExisting ? this._getTokenMetadata(provider.useExisting) : undefined,
20659 deps: compileDeps,
20660 multi: provider.multi
20661 };
20662 }
20663 _getQueriesMetadata(queries, isViewQuery, directiveType) {
20664 const res = [];
20665 Object.keys(queries).forEach((propertyName) => {
20666 const query = queries[propertyName];
20667 if (query.isViewQuery === isViewQuery) {
20668 res.push(this._getQueryMetadata(query, propertyName, directiveType));
20669 }
20670 });
20671 return res;
20672 }
20673 _queryVarBindings(selector) {
20674 return selector.split(/\s*,\s*/);
20675 }
20676 _getQueryMetadata(q, propertyName, typeOrFunc) {
20677 let selectors;
20678 if (typeof q.selector === 'string') {
20679 selectors =
20680 this._queryVarBindings(q.selector).map(varName => this._getTokenMetadata(varName));
20681 }
20682 else {
20683 if (!q.selector) {
20684 this._reportError(syntaxError(`Can't construct a query for the property "${propertyName}" of "${stringifyType(typeOrFunc)}" since the query selector wasn't defined.`), typeOrFunc);
20685 selectors = [];
20686 }
20687 else {
20688 selectors = [this._getTokenMetadata(q.selector)];
20689 }
20690 }
20691 return {
20692 selectors,
20693 first: q.first,
20694 descendants: q.descendants,
20695 emitDistinctChangesOnly: q.emitDistinctChangesOnly,
20696 propertyName,
20697 read: q.read ? this._getTokenMetadata(q.read) : null,
20698 static: q.static
20699 };
20700 }
20701 _reportError(error, type, otherType) {
20702 if (this._errorCollector) {
20703 this._errorCollector(error, type);
20704 if (otherType) {
20705 this._errorCollector(error, otherType);
20706 }
20707 }
20708 else {
20709 throw error;
20710 }
20711 }
20712 }
20713 function flattenArray(tree, out = []) {
20714 if (tree) {
20715 for (let i = 0; i < tree.length; i++) {
20716 const item = resolveForwardRef(tree[i]);
20717 if (Array.isArray(item)) {
20718 flattenArray(item, out);
20719 }
20720 else {
20721 out.push(item);
20722 }
20723 }
20724 }
20725 return out;
20726 }
20727 function dedupeArray(array) {
20728 if (array) {
20729 return Array.from(new Set(array));
20730 }
20731 return [];
20732 }
20733 function flattenAndDedupeArray(tree) {
20734 return dedupeArray(flattenArray(tree));
20735 }
20736 function isValidType(value) {
20737 return (value instanceof StaticSymbol) || (value instanceof Type);
20738 }
20739 function extractIdentifiers(value, targetIdentifiers) {
20740 visitValue(value, new _CompileValueConverter(), targetIdentifiers);
20741 }
20742 class _CompileValueConverter extends ValueTransformer {
20743 visitOther(value, targetIdentifiers) {
20744 targetIdentifiers.push({ reference: value });
20745 }
20746 }
20747 function stringifyType(type) {
20748 if (type instanceof StaticSymbol) {
20749 return `${type.name} in ${type.filePath}`;
20750 }
20751 else {
20752 return stringify(type);
20753 }
20754 }
20755 /**
20756 * Indicates that a component is still being loaded in a synchronous compile.
20757 */
20758 function componentStillLoadingError(compType) {
20759 const error = Error(`Can't compile synchronously as ${stringify(compType)} is still being loaded!`);
20760 error[ERROR_COMPONENT_TYPE] = compType;
20761 return error;
20762 }
20763
20764 /**
20765 * @license
20766 * Copyright Google LLC All Rights Reserved.
20767 *
20768 * Use of this source code is governed by an MIT-style license that can be
20769 * found in the LICENSE file at https://angular.io/license
20770 */
20771 const LOG_VAR = variable('_l');
20772
20773 /**
20774 * @license
20775 * Copyright Google LLC All Rights Reserved.
20776 *
20777 * Use of this source code is governed by an MIT-style license that can be
20778 * found in the LICENSE file at https://angular.io/license
20779 */
20780 /**
20781 * Resolves types to {@link NgModule}.
20782 */
20783 class NgModuleResolver {
20784 constructor(_reflector) {
20785 this._reflector = _reflector;
20786 }
20787 isNgModule(type) {
20788 return this._reflector.annotations(type).some(createNgModule.isTypeOf);
20789 }
20790 resolve(type, throwIfNotFound = true) {
20791 const ngModuleMeta = findLast(this._reflector.annotations(type), createNgModule.isTypeOf);
20792 if (ngModuleMeta) {
20793 return ngModuleMeta;
20794 }
20795 else {
20796 if (throwIfNotFound) {
20797 throw new Error(`No NgModule metadata found for '${stringify(type)}'.`);
20798 }
20799 return null;
20800 }
20801 }
20802 }
20803
20804 /**
20805 * @license
20806 * Copyright Google LLC All Rights Reserved.
20807 *
20808 * Use of this source code is governed by an MIT-style license that can be
20809 * found in the LICENSE file at https://angular.io/license
20810 */
20811 /**
20812 * Resolve a `Type` for {@link Pipe}.
20813 *
20814 * This interface can be overridden by the application developer to create custom behavior.
20815 *
20816 * See {@link Compiler}
20817 */
20818 class PipeResolver {
20819 constructor(_reflector) {
20820 this._reflector = _reflector;
20821 }
20822 isPipe(type) {
20823 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
20824 return typeMetadata && typeMetadata.some(createPipe.isTypeOf);
20825 }
20826 /**
20827 * Return {@link Pipe} for a given `Type`.
20828 */
20829 resolve(type, throwIfNotFound = true) {
20830 const metas = this._reflector.annotations(resolveForwardRef(type));
20831 if (metas) {
20832 const annotation = findLast(metas, createPipe.isTypeOf);
20833 if (annotation) {
20834 return annotation;
20835 }
20836 }
20837 if (throwIfNotFound) {
20838 throw new Error(`No Pipe decorator found on ${stringify(type)}`);
20839 }
20840 return null;
20841 }
20842 }
20843
20844 /**
20845 * @license
20846 * Copyright Google LLC All Rights Reserved.
20847 *
20848 * Use of this source code is governed by an MIT-style license that can be
20849 * found in the LICENSE file at https://angular.io/license
20850 */
20851 const LOG_VAR$1 = variable('_l');
20852 const VIEW_VAR = variable('_v');
20853 const CHECK_VAR = variable('_ck');
20854 const COMP_VAR = variable('_co');
20855 const EVENT_NAME_VAR = variable('en');
20856 const ALLOW_DEFAULT_VAR = variable(`ad`);
20857
20858 /**
20859 * @license
20860 * Copyright Google LLC All Rights Reserved.
20861 *
20862 * Use of this source code is governed by an MIT-style license that can be
20863 * found in the LICENSE file at https://angular.io/license
20864 */
20865 const TS = /^(?!.*\.d\.ts$).*\.ts$/;
20866 class ResolvedStaticSymbol {
20867 constructor(symbol, metadata) {
20868 this.symbol = symbol;
20869 this.metadata = metadata;
20870 }
20871 }
20872 const SUPPORTED_SCHEMA_VERSION = 4;
20873 /**
20874 * This class is responsible for loading metadata per symbol,
20875 * and normalizing references between symbols.
20876 *
20877 * Internally, it only uses symbols without members,
20878 * and deduces the values for symbols with members based
20879 * on these symbols.
20880 */
20881 class StaticSymbolResolver {
20882 constructor(host, staticSymbolCache, summaryResolver, errorRecorder) {
20883 this.host = host;
20884 this.staticSymbolCache = staticSymbolCache;
20885 this.summaryResolver = summaryResolver;
20886 this.errorRecorder = errorRecorder;
20887 this.metadataCache = new Map();
20888 // Note: this will only contain StaticSymbols without members!
20889 this.resolvedSymbols = new Map();
20890 // Note: this will only contain StaticSymbols without members!
20891 this.importAs = new Map();
20892 this.symbolResourcePaths = new Map();
20893 this.symbolFromFile = new Map();
20894 this.knownFileNameToModuleNames = new Map();
20895 }
20896 resolveSymbol(staticSymbol) {
20897 if (staticSymbol.members.length > 0) {
20898 return this._resolveSymbolMembers(staticSymbol);
20899 }
20900 // Note: always ask for a summary first,
20901 // as we might have read shallow metadata via a .d.ts file
20902 // for the symbol.
20903 const resultFromSummary = this._resolveSymbolFromSummary(staticSymbol);
20904 if (resultFromSummary) {
20905 return resultFromSummary;
20906 }
20907 const resultFromCache = this.resolvedSymbols.get(staticSymbol);
20908 if (resultFromCache) {
20909 return resultFromCache;
20910 }
20911 // Note: Some users use libraries that were not compiled with ngc, i.e. they don't
20912 // have summaries, only .d.ts files. So we always need to check both, the summary
20913 // and metadata.
20914 this._createSymbolsOf(staticSymbol.filePath);
20915 return this.resolvedSymbols.get(staticSymbol);
20916 }
20917 /**
20918 * getImportAs produces a symbol that can be used to import the given symbol.
20919 * The import might be different than the symbol if the symbol is exported from
20920 * a library with a summary; in which case we want to import the symbol from the
20921 * ngfactory re-export instead of directly to avoid introducing a direct dependency
20922 * on an otherwise indirect dependency.
20923 *
20924 * @param staticSymbol the symbol for which to generate a import symbol
20925 */
20926 getImportAs(staticSymbol, useSummaries = true) {
20927 if (staticSymbol.members.length) {
20928 const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
20929 const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
20930 return baseImportAs ?
20931 this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
20932 null;
20933 }
20934 const summarizedFileName = stripSummaryForJitFileSuffix(staticSymbol.filePath);
20935 if (summarizedFileName !== staticSymbol.filePath) {
20936 const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
20937 const baseSymbol = this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
20938 const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
20939 return baseImportAs ? this.getStaticSymbol(summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name), baseSymbol.members) :
20940 null;
20941 }
20942 let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
20943 if (!result) {
20944 result = this.importAs.get(staticSymbol);
20945 }
20946 return result;
20947 }
20948 /**
20949 * getResourcePath produces the path to the original location of the symbol and should
20950 * be used to determine the relative location of resource references recorded in
20951 * symbol metadata.
20952 */
20953 getResourcePath(staticSymbol) {
20954 return this.symbolResourcePaths.get(staticSymbol) || staticSymbol.filePath;
20955 }
20956 /**
20957 * getTypeArity returns the number of generic type parameters the given symbol
20958 * has. If the symbol is not a type the result is null.
20959 */
20960 getTypeArity(staticSymbol) {
20961 // If the file is a factory/ngsummary file, don't resolve the symbol as doing so would
20962 // cause the metadata for an factory/ngsummary file to be loaded which doesn't exist.
20963 // All references to generated classes must include the correct arity whenever
20964 // generating code.
20965 if (isGeneratedFile(staticSymbol.filePath)) {
20966 return null;
20967 }
20968 let resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(staticSymbol));
20969 while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
20970 resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(resolvedSymbol.metadata));
20971 }
20972 return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
20973 }
20974 getKnownModuleName(filePath) {
20975 return this.knownFileNameToModuleNames.get(filePath) || null;
20976 }
20977 recordImportAs(sourceSymbol, targetSymbol) {
20978 sourceSymbol.assertNoMembers();
20979 targetSymbol.assertNoMembers();
20980 this.importAs.set(sourceSymbol, targetSymbol);
20981 }
20982 recordModuleNameForFileName(fileName, moduleName) {
20983 this.knownFileNameToModuleNames.set(fileName, moduleName);
20984 }
20985 /**
20986 * Invalidate all information derived from the given file and return the
20987 * static symbols contained in the file.
20988 *
20989 * @param fileName the file to invalidate
20990 */
20991 invalidateFile(fileName) {
20992 this.metadataCache.delete(fileName);
20993 const symbols = this.symbolFromFile.get(fileName);
20994 if (!symbols) {
20995 return [];
20996 }
20997 this.symbolFromFile.delete(fileName);
20998 for (const symbol of symbols) {
20999 this.resolvedSymbols.delete(symbol);
21000 this.importAs.delete(symbol);
21001 this.symbolResourcePaths.delete(symbol);
21002 }
21003 return symbols;
21004 }
21005 /** @internal */
21006 ignoreErrorsFor(cb) {
21007 const recorder = this.errorRecorder;
21008 this.errorRecorder = () => { };
21009 try {
21010 return cb();
21011 }
21012 finally {
21013 this.errorRecorder = recorder;
21014 }
21015 }
21016 _resolveSymbolMembers(staticSymbol) {
21017 const members = staticSymbol.members;
21018 const baseResolvedSymbol = this.resolveSymbol(this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name));
21019 if (!baseResolvedSymbol) {
21020 return null;
21021 }
21022 let baseMetadata = unwrapResolvedMetadata(baseResolvedSymbol.metadata);
21023 if (baseMetadata instanceof StaticSymbol) {
21024 return new ResolvedStaticSymbol(staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
21025 }
21026 else if (baseMetadata && baseMetadata.__symbolic === 'class') {
21027 if (baseMetadata.statics && members.length === 1) {
21028 return new ResolvedStaticSymbol(staticSymbol, baseMetadata.statics[members[0]]);
21029 }
21030 }
21031 else {
21032 let value = baseMetadata;
21033 for (let i = 0; i < members.length && value; i++) {
21034 value = value[members[i]];
21035 }
21036 return new ResolvedStaticSymbol(staticSymbol, value);
21037 }
21038 return null;
21039 }
21040 _resolveSymbolFromSummary(staticSymbol) {
21041 const summary = this.summaryResolver.resolveSummary(staticSymbol);
21042 return summary ? new ResolvedStaticSymbol(staticSymbol, summary.metadata) : null;
21043 }
21044 /**
21045 * getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
21046 * All types passed to the StaticResolver should be pseudo-types returned by this method.
21047 *
21048 * @param declarationFile the absolute path of the file where the symbol is declared
21049 * @param name the name of the type.
21050 * @param members a symbol for a static member of the named type
21051 */
21052 getStaticSymbol(declarationFile, name, members) {
21053 return this.staticSymbolCache.get(declarationFile, name, members);
21054 }
21055 /**
21056 * hasDecorators checks a file's metadata for the presence of decorators without evaluating the
21057 * metadata.
21058 *
21059 * @param filePath the absolute path to examine for decorators.
21060 * @returns true if any class in the file has a decorator.
21061 */
21062 hasDecorators(filePath) {
21063 const metadata = this.getModuleMetadata(filePath);
21064 if (metadata['metadata']) {
21065 return Object.keys(metadata['metadata']).some((metadataKey) => {
21066 const entry = metadata['metadata'][metadataKey];
21067 return entry && entry.__symbolic === 'class' && entry.decorators;
21068 });
21069 }
21070 return false;
21071 }
21072 getSymbolsOf(filePath) {
21073 const summarySymbols = this.summaryResolver.getSymbolsOf(filePath);
21074 if (summarySymbols) {
21075 return summarySymbols;
21076 }
21077 // Note: Some users use libraries that were not compiled with ngc, i.e. they don't
21078 // have summaries, only .d.ts files, but `summaryResolver.isLibraryFile` returns true.
21079 this._createSymbolsOf(filePath);
21080 return this.symbolFromFile.get(filePath) || [];
21081 }
21082 _createSymbolsOf(filePath) {
21083 if (this.symbolFromFile.has(filePath)) {
21084 return;
21085 }
21086 const resolvedSymbols = [];
21087 const metadata = this.getModuleMetadata(filePath);
21088 if (metadata['importAs']) {
21089 // Index bundle indices should use the importAs module name defined
21090 // in the bundle.
21091 this.knownFileNameToModuleNames.set(filePath, metadata['importAs']);
21092 }
21093 // handle the symbols in one of the re-export location
21094 if (metadata['exports']) {
21095 for (const moduleExport of metadata['exports']) {
21096 // handle the symbols in the list of explicitly re-exported symbols.
21097 if (moduleExport.export) {
21098 moduleExport.export.forEach((exportSymbol) => {
21099 let symbolName;
21100 if (typeof exportSymbol === 'string') {
21101 symbolName = exportSymbol;
21102 }
21103 else {
21104 symbolName = exportSymbol.as;
21105 }
21106 symbolName = unescapeIdentifier(symbolName);
21107 let symName = symbolName;
21108 if (typeof exportSymbol !== 'string') {
21109 symName = unescapeIdentifier(exportSymbol.name);
21110 }
21111 const resolvedModule = this.resolveModule(moduleExport.from, filePath);
21112 if (resolvedModule) {
21113 const targetSymbol = this.getStaticSymbol(resolvedModule, symName);
21114 const sourceSymbol = this.getStaticSymbol(filePath, symbolName);
21115 resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
21116 }
21117 });
21118 }
21119 else {
21120 // Handle the symbols loaded by 'export *' directives.
21121 const resolvedModule = this.resolveModule(moduleExport.from, filePath);
21122 if (resolvedModule && resolvedModule !== filePath) {
21123 const nestedExports = this.getSymbolsOf(resolvedModule);
21124 nestedExports.forEach((targetSymbol) => {
21125 const sourceSymbol = this.getStaticSymbol(filePath, targetSymbol.name);
21126 resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
21127 });
21128 }
21129 }
21130 }
21131 }
21132 // handle the actual metadata. Has to be after the exports
21133 // as there might be collisions in the names, and we want the symbols
21134 // of the current module to win ofter reexports.
21135 if (metadata['metadata']) {
21136 // handle direct declarations of the symbol
21137 const topLevelSymbolNames = new Set(Object.keys(metadata['metadata']).map(unescapeIdentifier));
21138 const origins = metadata['origins'] || {};
21139 Object.keys(metadata['metadata']).forEach((metadataKey) => {
21140 const symbolMeta = metadata['metadata'][metadataKey];
21141 const name = unescapeIdentifier(metadataKey);
21142 const symbol = this.getStaticSymbol(filePath, name);
21143 const origin = origins.hasOwnProperty(metadataKey) && origins[metadataKey];
21144 if (origin) {
21145 // If the symbol is from a bundled index, use the declaration location of the
21146 // symbol so relative references (such as './my.html') will be calculated
21147 // correctly.
21148 const originFilePath = this.resolveModule(origin, filePath);
21149 if (!originFilePath) {
21150 this.reportError(new Error(`Couldn't resolve original symbol for ${origin} from ${this.host.getOutputName(filePath)}`));
21151 }
21152 else {
21153 this.symbolResourcePaths.set(symbol, originFilePath);
21154 }
21155 }
21156 resolvedSymbols.push(this.createResolvedSymbol(symbol, filePath, topLevelSymbolNames, symbolMeta));
21157 });
21158 }
21159 const uniqueSymbols = new Set();
21160 for (const resolvedSymbol of resolvedSymbols) {
21161 this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol);
21162 uniqueSymbols.add(resolvedSymbol.symbol);
21163 }
21164 this.symbolFromFile.set(filePath, Array.from(uniqueSymbols));
21165 }
21166 createResolvedSymbol(sourceSymbol, topLevelPath, topLevelSymbolNames, metadata) {
21167 // For classes that don't have Angular summaries / metadata,
21168 // we only keep their arity, but nothing else
21169 // (e.g. their constructor parameters).
21170 // We do this to prevent introducing deep imports
21171 // as we didn't generate .ngfactory.ts files with proper reexports.
21172 const isTsFile = TS.test(sourceSymbol.filePath);
21173 if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) && !isTsFile && metadata &&
21174 metadata['__symbolic'] === 'class') {
21175 const transformedMeta = { __symbolic: 'class', arity: metadata.arity };
21176 return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
21177 }
21178 let _originalFileMemo;
21179 const getOriginalName = () => {
21180 if (!_originalFileMemo) {
21181 // Guess what the original file name is from the reference. If it has a `.d.ts` extension
21182 // replace it with `.ts`. If it already has `.ts` just leave it in place. If it doesn't have
21183 // .ts or .d.ts, append `.ts'. Also, if it is in `node_modules`, trim the `node_module`
21184 // location as it is not important to finding the file.
21185 _originalFileMemo =
21186 this.host.getOutputName(topLevelPath.replace(/((\.ts)|(\.d\.ts)|)$/, '.ts')
21187 .replace(/^.*node_modules[/\\]/, ''));
21188 }
21189 return _originalFileMemo;
21190 };
21191 const self = this;
21192 class ReferenceTransformer extends ValueTransformer {
21193 visitStringMap(map, functionParams) {
21194 const symbolic = map['__symbolic'];
21195 if (symbolic === 'function') {
21196 const oldLen = functionParams.length;
21197 functionParams.push(...(map['parameters'] || []));
21198 const result = super.visitStringMap(map, functionParams);
21199 functionParams.length = oldLen;
21200 return result;
21201 }
21202 else if (symbolic === 'reference') {
21203 const module = map['module'];
21204 const name = map['name'] ? unescapeIdentifier(map['name']) : map['name'];
21205 if (!name) {
21206 return null;
21207 }
21208 let filePath;
21209 if (module) {
21210 filePath = self.resolveModule(module, sourceSymbol.filePath);
21211 if (!filePath) {
21212 return {
21213 __symbolic: 'error',
21214 message: `Could not resolve ${module} relative to ${self.host.getMetadataFor(sourceSymbol.filePath)}.`,
21215 line: map['line'],
21216 character: map['character'],
21217 fileName: getOriginalName()
21218 };
21219 }
21220 return {
21221 __symbolic: 'resolved',
21222 symbol: self.getStaticSymbol(filePath, name),
21223 line: map['line'],
21224 character: map['character'],
21225 fileName: getOriginalName()
21226 };
21227 }
21228 else if (functionParams.indexOf(name) >= 0) {
21229 // reference to a function parameter
21230 return { __symbolic: 'reference', name: name };
21231 }
21232 else {
21233 if (topLevelSymbolNames.has(name)) {
21234 return self.getStaticSymbol(topLevelPath, name);
21235 }
21236 }
21237 }
21238 else if (symbolic === 'error') {
21239 return Object.assign(Object.assign({}, map), { fileName: getOriginalName() });
21240 }
21241 else {
21242 return super.visitStringMap(map, functionParams);
21243 }
21244 }
21245 }
21246 const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
21247 let unwrappedTransformedMeta = unwrapResolvedMetadata(transformedMeta);
21248 if (unwrappedTransformedMeta instanceof StaticSymbol) {
21249 return this.createExport(sourceSymbol, unwrappedTransformedMeta);
21250 }
21251 return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
21252 }
21253 createExport(sourceSymbol, targetSymbol) {
21254 sourceSymbol.assertNoMembers();
21255 targetSymbol.assertNoMembers();
21256 if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) &&
21257 this.summaryResolver.isLibraryFile(targetSymbol.filePath)) {
21258 // This case is for an ng library importing symbols from a plain ts library
21259 // transitively.
21260 // Note: We rely on the fact that we discover symbols in the direction
21261 // from source files to library files
21262 this.importAs.set(targetSymbol, this.getImportAs(sourceSymbol) || sourceSymbol);
21263 }
21264 return new ResolvedStaticSymbol(sourceSymbol, targetSymbol);
21265 }
21266 reportError(error, context, path) {
21267 if (this.errorRecorder) {
21268 this.errorRecorder(error, (context && context.filePath) || path);
21269 }
21270 else {
21271 throw error;
21272 }
21273 }
21274 /**
21275 * @param module an absolute path to a module file.
21276 */
21277 getModuleMetadata(module) {
21278 let moduleMetadata = this.metadataCache.get(module);
21279 if (!moduleMetadata) {
21280 const moduleMetadatas = this.host.getMetadataFor(module);
21281 if (moduleMetadatas) {
21282 let maxVersion = -1;
21283 moduleMetadatas.forEach((md) => {
21284 if (md && md['version'] > maxVersion) {
21285 maxVersion = md['version'];
21286 moduleMetadata = md;
21287 }
21288 });
21289 }
21290 if (!moduleMetadata) {
21291 moduleMetadata =
21292 { __symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {} };
21293 }
21294 if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
21295 const errorMessage = moduleMetadata['version'] == 2 ?
21296 `Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` :
21297 `Metadata version mismatch for module ${this.host.getOutputName(module)}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
21298 this.reportError(new Error(errorMessage));
21299 }
21300 this.metadataCache.set(module, moduleMetadata);
21301 }
21302 return moduleMetadata;
21303 }
21304 getSymbolByModule(module, symbolName, containingFile) {
21305 const filePath = this.resolveModule(module, containingFile);
21306 if (!filePath) {
21307 this.reportError(new Error(`Could not resolve module ${module}${containingFile ? ' relative to ' + this.host.getOutputName(containingFile) : ''}`));
21308 return this.getStaticSymbol(`ERROR:${module}`, symbolName);
21309 }
21310 return this.getStaticSymbol(filePath, symbolName);
21311 }
21312 resolveModule(module, containingFile) {
21313 try {
21314 return this.host.moduleNameToFileName(module, containingFile);
21315 }
21316 catch (e) {
21317 console.error(`Could not resolve module '${module}' relative to file ${containingFile}`);
21318 this.reportError(e, undefined, containingFile);
21319 }
21320 return null;
21321 }
21322 }
21323 // Remove extra underscore from escaped identifier.
21324 // See https://github.com/Microsoft/TypeScript/blob/master/src/compiler/utilities.ts
21325 function unescapeIdentifier(identifier) {
21326 return identifier.startsWith('___') ? identifier.substr(1) : identifier;
21327 }
21328 function unwrapResolvedMetadata(metadata) {
21329 if (metadata && metadata.__symbolic === 'resolved') {
21330 return metadata.symbol;
21331 }
21332 return metadata;
21333 }
21334
21335 /**
21336 * @license
21337 * Copyright Google LLC All Rights Reserved.
21338 *
21339 * Use of this source code is governed by an MIT-style license that can be
21340 * found in the LICENSE file at https://angular.io/license
21341 */
21342 function deserializeSummaries(symbolCache, summaryResolver, libraryFileName, json) {
21343 const deserializer = new FromJsonDeserializer(symbolCache, summaryResolver);
21344 return deserializer.deserialize(libraryFileName, json);
21345 }
21346 class FromJsonDeserializer extends ValueTransformer {
21347 constructor(symbolCache, summaryResolver) {
21348 super();
21349 this.symbolCache = symbolCache;
21350 this.summaryResolver = summaryResolver;
21351 }
21352 deserialize(libraryFileName, json) {
21353 const data = JSON.parse(json);
21354 const allImportAs = [];
21355 this.symbols = data.symbols.map((serializedSymbol) => this.symbolCache.get(this.summaryResolver.fromSummaryFileName(serializedSymbol.filePath, libraryFileName), serializedSymbol.name));
21356 data.symbols.forEach((serializedSymbol, index) => {
21357 const symbol = this.symbols[index];
21358 const importAs = serializedSymbol.importAs;
21359 if (typeof importAs === 'number') {
21360 allImportAs.push({ symbol, importAs: this.symbols[importAs] });
21361 }
21362 else if (typeof importAs === 'string') {
21363 allImportAs.push({ symbol, importAs: this.symbolCache.get(ngfactoryFilePath(libraryFileName), importAs) });
21364 }
21365 });
21366 const summaries = visitValue(data.summaries, this, null);
21367 return { moduleName: data.moduleName, summaries, importAs: allImportAs };
21368 }
21369 visitStringMap(map, context) {
21370 if ('__symbol' in map) {
21371 const baseSymbol = this.symbols[map['__symbol']];
21372 const members = map['members'];
21373 return members.length ? this.symbolCache.get(baseSymbol.filePath, baseSymbol.name, members) :
21374 baseSymbol;
21375 }
21376 else {
21377 return super.visitStringMap(map, context);
21378 }
21379 }
21380 }
21381
21382 /**
21383 * @license
21384 * Copyright Google LLC All Rights Reserved.
21385 *
21386 * Use of this source code is governed by an MIT-style license that can be
21387 * found in the LICENSE file at https://angular.io/license
21388 */
21389 function analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver) {
21390 const files = _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver);
21391 return mergeAnalyzedFiles(files);
21392 }
21393 // Analyzes all of the program files,
21394 // including files that are not part of the program
21395 // but are referenced by an NgModule.
21396 function _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver) {
21397 const seenFiles = new Set();
21398 const files = [];
21399 const visitFile = (fileName) => {
21400 if (seenFiles.has(fileName) || !host.isSourceFile(fileName)) {
21401 return false;
21402 }
21403 seenFiles.add(fileName);
21404 const analyzedFile = analyzeFile(host, staticSymbolResolver, metadataResolver, fileName);
21405 files.push(analyzedFile);
21406 analyzedFile.ngModules.forEach(ngModule => {
21407 ngModule.transitiveModule.modules.forEach(modMeta => visitFile(modMeta.reference.filePath));
21408 });
21409 };
21410 fileNames.forEach((fileName) => visitFile(fileName));
21411 return files;
21412 }
21413 function analyzeFile(host, staticSymbolResolver, metadataResolver, fileName) {
21414 const abstractDirectives = [];
21415 const directives = [];
21416 const pipes = [];
21417 const injectables = [];
21418 const ngModules = [];
21419 const hasDecorators = staticSymbolResolver.hasDecorators(fileName);
21420 let exportsNonSourceFiles = false;
21421 const isDeclarationFile = fileName.endsWith('.d.ts');
21422 // Don't analyze .d.ts files that have no decorators as a shortcut
21423 // to speed up the analysis. This prevents us from
21424 // resolving the references in these files.
21425 // Note: exportsNonSourceFiles is only needed when compiling with summaries,
21426 // which is not the case when .d.ts files are treated as input files.
21427 if (!isDeclarationFile || hasDecorators) {
21428 staticSymbolResolver.getSymbolsOf(fileName).forEach((symbol) => {
21429 const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
21430 const symbolMeta = resolvedSymbol.metadata;
21431 if (!symbolMeta || symbolMeta.__symbolic === 'error') {
21432 return;
21433 }
21434 let isNgSymbol = false;
21435 if (symbolMeta.__symbolic === 'class') {
21436 if (metadataResolver.isDirective(symbol)) {
21437 isNgSymbol = true;
21438 // This directive either has a selector or doesn't. Selector-less directives get tracked
21439 // in abstractDirectives, not directives. The compiler doesn't deal with selector-less
21440 // directives at all, really, other than to persist their metadata. This is done so that
21441 // apps will have an easier time migrating to Ivy, which requires the selector-less
21442 // annotations to be applied.
21443 if (!metadataResolver.isAbstractDirective(symbol)) {
21444 // The directive is an ordinary directive.
21445 directives.push(symbol);
21446 }
21447 else {
21448 // The directive has no selector and is an "abstract" directive, so track it
21449 // accordingly.
21450 abstractDirectives.push(symbol);
21451 }
21452 }
21453 else if (metadataResolver.isPipe(symbol)) {
21454 isNgSymbol = true;
21455 pipes.push(symbol);
21456 }
21457 else if (metadataResolver.isNgModule(symbol)) {
21458 const ngModule = metadataResolver.getNgModuleMetadata(symbol, false);
21459 if (ngModule) {
21460 isNgSymbol = true;
21461 ngModules.push(ngModule);
21462 }
21463 }
21464 else if (metadataResolver.isInjectable(symbol)) {
21465 isNgSymbol = true;
21466 const injectable = metadataResolver.getInjectableMetadata(symbol, null, false);
21467 if (injectable) {
21468 injectables.push(injectable);
21469 }
21470 }
21471 }
21472 if (!isNgSymbol) {
21473 exportsNonSourceFiles =
21474 exportsNonSourceFiles || isValueExportingNonSourceFile(host, symbolMeta);
21475 }
21476 });
21477 }
21478 return {
21479 fileName,
21480 directives,
21481 abstractDirectives,
21482 pipes,
21483 ngModules,
21484 injectables,
21485 exportsNonSourceFiles,
21486 };
21487 }
21488 function isValueExportingNonSourceFile(host, metadata) {
21489 let exportsNonSourceFiles = false;
21490 class Visitor {
21491 visitArray(arr, context) {
21492 arr.forEach(v => visitValue(v, this, context));
21493 }
21494 visitStringMap(map, context) {
21495 Object.keys(map).forEach((key) => visitValue(map[key], this, context));
21496 }
21497 visitPrimitive(value, context) { }
21498 visitOther(value, context) {
21499 if (value instanceof StaticSymbol && !host.isSourceFile(value.filePath)) {
21500 exportsNonSourceFiles = true;
21501 }
21502 }
21503 }
21504 visitValue(metadata, new Visitor(), null);
21505 return exportsNonSourceFiles;
21506 }
21507 function mergeAnalyzedFiles(analyzedFiles) {
21508 const allNgModules = [];
21509 const ngModuleByPipeOrDirective = new Map();
21510 const allPipesAndDirectives = new Set();
21511 analyzedFiles.forEach(af => {
21512 af.ngModules.forEach(ngModule => {
21513 allNgModules.push(ngModule);
21514 ngModule.declaredDirectives.forEach(d => ngModuleByPipeOrDirective.set(d.reference, ngModule));
21515 ngModule.declaredPipes.forEach(p => ngModuleByPipeOrDirective.set(p.reference, ngModule));
21516 });
21517 af.directives.forEach(d => allPipesAndDirectives.add(d));
21518 af.pipes.forEach(p => allPipesAndDirectives.add(p));
21519 });
21520 const symbolsMissingModule = [];
21521 allPipesAndDirectives.forEach(ref => {
21522 if (!ngModuleByPipeOrDirective.has(ref)) {
21523 symbolsMissingModule.push(ref);
21524 }
21525 });
21526 return {
21527 ngModules: allNgModules,
21528 ngModuleByPipeOrDirective,
21529 symbolsMissingModule,
21530 files: analyzedFiles
21531 };
21532 }
21533
21534 /**
21535 * @license
21536 * Copyright Google LLC All Rights Reserved.
21537 *
21538 * Use of this source code is governed by an MIT-style license that can be
21539 * found in the LICENSE file at https://angular.io/license
21540 */
21541 const FORMATTED_MESSAGE = 'ngFormattedMessage';
21542 function indentStr(level) {
21543 if (level <= 0)
21544 return '';
21545 if (level < 6)
21546 return ['', ' ', ' ', ' ', ' ', ' '][level];
21547 const half = indentStr(Math.floor(level / 2));
21548 return half + half + (level % 2 === 1 ? ' ' : '');
21549 }
21550 function formatChain(chain, indent = 0) {
21551 if (!chain)
21552 return '';
21553 const position = chain.position ?
21554 `${chain.position.fileName}(${chain.position.line + 1},${chain.position.column + 1})` :
21555 '';
21556 const prefix = position && indent === 0 ? `${position}: ` : '';
21557 const postfix = position && indent !== 0 ? ` at ${position}` : '';
21558 let message = `${prefix}${chain.message}${postfix}`;
21559 if (chain.next) {
21560 for (const kid of chain.next) {
21561 message += '\n' + formatChain(kid, indent + 2);
21562 }
21563 }
21564 return `${indentStr(indent)}${message}`;
21565 }
21566 function formattedError(chain) {
21567 const message = formatChain(chain) + '.';
21568 const error = syntaxError(message);
21569 error[FORMATTED_MESSAGE] = true;
21570 error.chain = chain;
21571 error.position = chain.position;
21572 return error;
21573 }
21574 function isFormattedError(error) {
21575 return !!error[FORMATTED_MESSAGE];
21576 }
21577
21578 /**
21579 * @license
21580 * Copyright Google LLC All Rights Reserved.
21581 *
21582 * Use of this source code is governed by an MIT-style license that can be
21583 * found in the LICENSE file at https://angular.io/license
21584 */
21585 const ANGULAR_CORE = '@angular/core';
21586 const ANGULAR_ROUTER = '@angular/router';
21587 const HIDDEN_KEY = /^\$.*\$$/;
21588 const IGNORE = {
21589 __symbolic: 'ignore'
21590 };
21591 const USE_VALUE$1 = 'useValue';
21592 const PROVIDE = 'provide';
21593 const REFERENCE_SET = new Set([USE_VALUE$1, 'useFactory', 'data', 'id', 'loadChildren']);
21594 const TYPEGUARD_POSTFIX = 'TypeGuard';
21595 const USE_IF = 'UseIf';
21596 function shouldIgnore(value) {
21597 return value && value.__symbolic == 'ignore';
21598 }
21599 /**
21600 * A static reflector implements enough of the Reflector API that is necessary to compile
21601 * templates statically.
21602 */
21603 class StaticReflector {
21604 constructor(summaryResolver, symbolResolver, knownMetadataClasses = [], knownMetadataFunctions = [], errorRecorder) {
21605 this.summaryResolver = summaryResolver;
21606 this.symbolResolver = symbolResolver;
21607 this.errorRecorder = errorRecorder;
21608 this.annotationCache = new Map();
21609 this.shallowAnnotationCache = new Map();
21610 this.propertyCache = new Map();
21611 this.parameterCache = new Map();
21612 this.methodCache = new Map();
21613 this.staticCache = new Map();
21614 this.conversionMap = new Map();
21615 this.resolvedExternalReferences = new Map();
21616 this.annotationForParentClassWithSummaryKind = new Map();
21617 this.initializeConversionMap();
21618 knownMetadataClasses.forEach((kc) => this._registerDecoratorOrConstructor(this.getStaticSymbol(kc.filePath, kc.name), kc.ctor));
21619 knownMetadataFunctions.forEach((kf) => this._registerFunction(this.getStaticSymbol(kf.filePath, kf.name), kf.fn));
21620 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Directive, [createDirective, createComponent]);
21621 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Pipe, [createPipe]);
21622 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.NgModule, [createNgModule]);
21623 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Injectable, [createInjectable, createPipe, createDirective, createComponent, createNgModule]);
21624 }
21625 componentModuleUrl(typeOrFunc) {
21626 const staticSymbol = this.findSymbolDeclaration(typeOrFunc);
21627 return this.symbolResolver.getResourcePath(staticSymbol);
21628 }
21629 /**
21630 * Invalidate the specified `symbols` on program change.
21631 * @param symbols
21632 */
21633 invalidateSymbols(symbols) {
21634 for (const symbol of symbols) {
21635 this.annotationCache.delete(symbol);
21636 this.shallowAnnotationCache.delete(symbol);
21637 this.propertyCache.delete(symbol);
21638 this.parameterCache.delete(symbol);
21639 this.methodCache.delete(symbol);
21640 this.staticCache.delete(symbol);
21641 this.conversionMap.delete(symbol);
21642 }
21643 }
21644 resolveExternalReference(ref, containingFile) {
21645 let key = undefined;
21646 if (!containingFile) {
21647 key = `${ref.moduleName}:${ref.name}`;
21648 const declarationSymbol = this.resolvedExternalReferences.get(key);
21649 if (declarationSymbol)
21650 return declarationSymbol;
21651 }
21652 const refSymbol = this.symbolResolver.getSymbolByModule(ref.moduleName, ref.name, containingFile);
21653 const declarationSymbol = this.findSymbolDeclaration(refSymbol);
21654 if (!containingFile) {
21655 this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName);
21656 this.symbolResolver.recordImportAs(declarationSymbol, refSymbol);
21657 }
21658 if (key) {
21659 this.resolvedExternalReferences.set(key, declarationSymbol);
21660 }
21661 return declarationSymbol;
21662 }
21663 findDeclaration(moduleUrl, name, containingFile) {
21664 return this.findSymbolDeclaration(this.symbolResolver.getSymbolByModule(moduleUrl, name, containingFile));
21665 }
21666 tryFindDeclaration(moduleUrl, name, containingFile) {
21667 return this.symbolResolver.ignoreErrorsFor(() => this.findDeclaration(moduleUrl, name, containingFile));
21668 }
21669 findSymbolDeclaration(symbol) {
21670 const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
21671 if (resolvedSymbol) {
21672 let resolvedMetadata = resolvedSymbol.metadata;
21673 if (resolvedMetadata && resolvedMetadata.__symbolic === 'resolved') {
21674 resolvedMetadata = resolvedMetadata.symbol;
21675 }
21676 if (resolvedMetadata instanceof StaticSymbol) {
21677 return this.findSymbolDeclaration(resolvedSymbol.metadata);
21678 }
21679 }
21680 return symbol;
21681 }
21682 tryAnnotations(type) {
21683 const originalRecorder = this.errorRecorder;
21684 this.errorRecorder = (error, fileName) => { };
21685 try {
21686 return this.annotations(type);
21687 }
21688 finally {
21689 this.errorRecorder = originalRecorder;
21690 }
21691 }
21692 annotations(type) {
21693 return this._annotations(type, (type, decorators) => this.simplify(type, decorators), this.annotationCache);
21694 }
21695 shallowAnnotations(type) {
21696 return this._annotations(type, (type, decorators) => this.simplify(type, decorators, true), this.shallowAnnotationCache);
21697 }
21698 _annotations(type, simplify, annotationCache) {
21699 let annotations = annotationCache.get(type);
21700 if (!annotations) {
21701 annotations = [];
21702 const classMetadata = this.getTypeMetadata(type);
21703 const parentType = this.findParentType(type, classMetadata);
21704 if (parentType) {
21705 const parentAnnotations = this.annotations(parentType);
21706 annotations.push(...parentAnnotations);
21707 }
21708 let ownAnnotations = [];
21709 if (classMetadata['decorators']) {
21710 ownAnnotations = simplify(type, classMetadata['decorators']);
21711 if (ownAnnotations) {
21712 annotations.push(...ownAnnotations);
21713 }
21714 }
21715 if (parentType && !this.summaryResolver.isLibraryFile(type.filePath) &&
21716 this.summaryResolver.isLibraryFile(parentType.filePath)) {
21717 const summary = this.summaryResolver.resolveSummary(parentType);
21718 if (summary && summary.type) {
21719 const requiredAnnotationTypes = this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind);
21720 const typeHasRequiredAnnotation = requiredAnnotationTypes.some((requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
21721 if (!typeHasRequiredAnnotation) {
21722 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`,
21723 /* summary */ undefined, `Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName)
21724 .join(' or ')} decorator to the class`), type), type);
21725 }
21726 }
21727 }
21728 annotationCache.set(type, annotations.filter(ann => !!ann));
21729 }
21730 return annotations;
21731 }
21732 propMetadata(type) {
21733 let propMetadata = this.propertyCache.get(type);
21734 if (!propMetadata) {
21735 const classMetadata = this.getTypeMetadata(type);
21736 propMetadata = {};
21737 const parentType = this.findParentType(type, classMetadata);
21738 if (parentType) {
21739 const parentPropMetadata = this.propMetadata(parentType);
21740 Object.keys(parentPropMetadata).forEach((parentProp) => {
21741 propMetadata[parentProp] = parentPropMetadata[parentProp];
21742 });
21743 }
21744 const members = classMetadata['members'] || {};
21745 Object.keys(members).forEach((propName) => {
21746 const propData = members[propName];
21747 const prop = propData
21748 .find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method');
21749 const decorators = [];
21750 // hasOwnProperty() is used here to make sure we do not look up methods
21751 // on `Object.prototype`.
21752 if (propMetadata === null || propMetadata === void 0 ? void 0 : propMetadata.hasOwnProperty(propName)) {
21753 decorators.push(...propMetadata[propName]);
21754 }
21755 propMetadata[propName] = decorators;
21756 if (prop && prop['decorators']) {
21757 decorators.push(...this.simplify(type, prop['decorators']));
21758 }
21759 });
21760 this.propertyCache.set(type, propMetadata);
21761 }
21762 return propMetadata;
21763 }
21764 parameters(type) {
21765 if (!(type instanceof StaticSymbol)) {
21766 this.reportError(new Error(`parameters received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
21767 return [];
21768 }
21769 try {
21770 let parameters = this.parameterCache.get(type);
21771 if (!parameters) {
21772 const classMetadata = this.getTypeMetadata(type);
21773 const parentType = this.findParentType(type, classMetadata);
21774 const members = classMetadata ? classMetadata['members'] : null;
21775 const ctorData = members ? members['__ctor__'] : null;
21776 if (ctorData) {
21777 const ctor = ctorData.find(a => a['__symbolic'] == 'constructor');
21778 const rawParameterTypes = ctor['parameters'] || [];
21779 const parameterDecorators = this.simplify(type, ctor['parameterDecorators'] || []);
21780 parameters = [];
21781 rawParameterTypes.forEach((rawParamType, index) => {
21782 const nestedResult = [];
21783 const paramType = this.trySimplify(type, rawParamType);
21784 if (paramType)
21785 nestedResult.push(paramType);
21786 const decorators = parameterDecorators ? parameterDecorators[index] : null;
21787 if (decorators) {
21788 nestedResult.push(...decorators);
21789 }
21790 parameters.push(nestedResult);
21791 });
21792 }
21793 else if (parentType) {
21794 parameters = this.parameters(parentType);
21795 }
21796 if (!parameters) {
21797 parameters = [];
21798 }
21799 this.parameterCache.set(type, parameters);
21800 }
21801 return parameters;
21802 }
21803 catch (e) {
21804 console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
21805 throw e;
21806 }
21807 }
21808 _methodNames(type) {
21809 let methodNames = this.methodCache.get(type);
21810 if (!methodNames) {
21811 const classMetadata = this.getTypeMetadata(type);
21812 methodNames = {};
21813 const parentType = this.findParentType(type, classMetadata);
21814 if (parentType) {
21815 const parentMethodNames = this._methodNames(parentType);
21816 Object.keys(parentMethodNames).forEach((parentProp) => {
21817 methodNames[parentProp] = parentMethodNames[parentProp];
21818 });
21819 }
21820 const members = classMetadata['members'] || {};
21821 Object.keys(members).forEach((propName) => {
21822 const propData = members[propName];
21823 const isMethod = propData.some(a => a['__symbolic'] == 'method');
21824 methodNames[propName] = methodNames[propName] || isMethod;
21825 });
21826 this.methodCache.set(type, methodNames);
21827 }
21828 return methodNames;
21829 }
21830 _staticMembers(type) {
21831 let staticMembers = this.staticCache.get(type);
21832 if (!staticMembers) {
21833 const classMetadata = this.getTypeMetadata(type);
21834 const staticMemberData = classMetadata['statics'] || {};
21835 staticMembers = Object.keys(staticMemberData);
21836 this.staticCache.set(type, staticMembers);
21837 }
21838 return staticMembers;
21839 }
21840 findParentType(type, classMetadata) {
21841 const parentType = this.trySimplify(type, classMetadata['extends']);
21842 if (parentType instanceof StaticSymbol) {
21843 return parentType;
21844 }
21845 }
21846 hasLifecycleHook(type, lcProperty) {
21847 if (!(type instanceof StaticSymbol)) {
21848 this.reportError(new Error(`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
21849 }
21850 try {
21851 return !!this._methodNames(type)[lcProperty];
21852 }
21853 catch (e) {
21854 console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
21855 throw e;
21856 }
21857 }
21858 guards(type) {
21859 if (!(type instanceof StaticSymbol)) {
21860 this.reportError(new Error(`guards received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
21861 return {};
21862 }
21863 const staticMembers = this._staticMembers(type);
21864 const result = {};
21865 for (let name of staticMembers) {
21866 if (name.endsWith(TYPEGUARD_POSTFIX)) {
21867 let property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
21868 let value;
21869 if (property.endsWith(USE_IF)) {
21870 property = name.substr(0, property.length - USE_IF.length);
21871 value = USE_IF;
21872 }
21873 else {
21874 value = this.getStaticSymbol(type.filePath, type.name, [name]);
21875 }
21876 result[property] = value;
21877 }
21878 }
21879 return result;
21880 }
21881 _registerDecoratorOrConstructor(type, ctor) {
21882 this.conversionMap.set(type, (context, args) => new ctor(...args));
21883 }
21884 _registerFunction(type, fn) {
21885 this.conversionMap.set(type, (context, args) => fn.apply(undefined, args));
21886 }
21887 initializeConversionMap() {
21888 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Injectable'), createInjectable);
21889 this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');
21890 this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');
21891 this.ROUTES = this.tryFindDeclaration(ANGULAR_ROUTER, 'ROUTES');
21892 this.ANALYZE_FOR_ENTRY_COMPONENTS =
21893 this.findDeclaration(ANGULAR_CORE, 'ANALYZE_FOR_ENTRY_COMPONENTS');
21894 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
21895 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
21896 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
21897 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Inject'), createInject);
21898 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
21899 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Attribute'), createAttribute);
21900 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChild'), createContentChild);
21901 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), createContentChildren);
21902 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChild'), createViewChild);
21903 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), createViewChildren);
21904 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), createInput);
21905 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Output'), createOutput);
21906 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), createPipe);
21907 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostBinding'), createHostBinding);
21908 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostListener'), createHostListener);
21909 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Directive'), createDirective);
21910 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Component'), createComponent);
21911 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'NgModule'), createNgModule);
21912 // Note: Some metadata classes can be used directly with Provider.deps.
21913 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
21914 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
21915 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
21916 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
21917 }
21918 /**
21919 * getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
21920 * All types passed to the StaticResolver should be pseudo-types returned by this method.
21921 *
21922 * @param declarationFile the absolute path of the file where the symbol is declared
21923 * @param name the name of the type.
21924 */
21925 getStaticSymbol(declarationFile, name, members) {
21926 return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
21927 }
21928 /**
21929 * Simplify but discard any errors
21930 */
21931 trySimplify(context, value) {
21932 const originalRecorder = this.errorRecorder;
21933 this.errorRecorder = (error, fileName) => { };
21934 const result = this.simplify(context, value);
21935 this.errorRecorder = originalRecorder;
21936 return result;
21937 }
21938 /** @internal */
21939 simplify(context, value, lazy = false) {
21940 const self = this;
21941 let scope = BindingScope$1.empty;
21942 const calling = new Map();
21943 function simplifyInContext(context, value, depth, references) {
21944 function resolveReferenceValue(staticSymbol) {
21945 const resolvedSymbol = self.symbolResolver.resolveSymbol(staticSymbol);
21946 return resolvedSymbol ? resolvedSymbol.metadata : null;
21947 }
21948 function simplifyEagerly(value) {
21949 return simplifyInContext(context, value, depth, 0);
21950 }
21951 function simplifyLazily(value) {
21952 return simplifyInContext(context, value, depth, references + 1);
21953 }
21954 function simplifyNested(nestedContext, value) {
21955 if (nestedContext === context) {
21956 // If the context hasn't changed let the exception propagate unmodified.
21957 return simplifyInContext(nestedContext, value, depth + 1, references);
21958 }
21959 try {
21960 return simplifyInContext(nestedContext, value, depth + 1, references);
21961 }
21962 catch (e) {
21963 if (isMetadataError(e)) {
21964 // Propagate the message text up but add a message to the chain that explains how we got
21965 // here.
21966 // e.chain implies e.symbol
21967 const summaryMsg = e.chain ? 'references \'' + e.symbol.name + '\'' : errorSummary(e);
21968 const summary = `'${nestedContext.name}' ${summaryMsg}`;
21969 const chain = { message: summary, position: e.position, next: e.chain };
21970 // TODO(chuckj): retrieve the position information indirectly from the collectors node
21971 // map if the metadata is from a .ts file.
21972 self.error({
21973 message: e.message,
21974 advise: e.advise,
21975 context: e.context,
21976 chain,
21977 symbol: nestedContext
21978 }, context);
21979 }
21980 else {
21981 // It is probably an internal error.
21982 throw e;
21983 }
21984 }
21985 }
21986 function simplifyCall(functionSymbol, targetFunction, args, targetExpression) {
21987 if (targetFunction && targetFunction['__symbolic'] == 'function') {
21988 if (calling.get(functionSymbol)) {
21989 self.error({
21990 message: 'Recursion is not supported',
21991 summary: `called '${functionSymbol.name}' recursively`,
21992 value: targetFunction
21993 }, functionSymbol);
21994 }
21995 try {
21996 const value = targetFunction['value'];
21997 if (value && (depth != 0 || value.__symbolic != 'error')) {
21998 const parameters = targetFunction['parameters'];
21999 const defaults = targetFunction.defaults;
22000 args = args.map(arg => simplifyNested(context, arg))
22001 .map(arg => shouldIgnore(arg) ? undefined : arg);
22002 if (defaults && defaults.length > args.length) {
22003 args.push(...defaults.slice(args.length).map((value) => simplify(value)));
22004 }
22005 calling.set(functionSymbol, true);
22006 const functionScope = BindingScope$1.build();
22007 for (let i = 0; i < parameters.length; i++) {
22008 functionScope.define(parameters[i], args[i]);
22009 }
22010 const oldScope = scope;
22011 let result;
22012 try {
22013 scope = functionScope.done();
22014 result = simplifyNested(functionSymbol, value);
22015 }
22016 finally {
22017 scope = oldScope;
22018 }
22019 return result;
22020 }
22021 }
22022 finally {
22023 calling.delete(functionSymbol);
22024 }
22025 }
22026 if (depth === 0) {
22027 // If depth is 0 we are evaluating the top level expression that is describing element
22028 // decorator. In this case, it is a decorator we don't understand, such as a custom
22029 // non-angular decorator, and we should just ignore it.
22030 return IGNORE;
22031 }
22032 let position = undefined;
22033 if (targetExpression && targetExpression.__symbolic == 'resolved') {
22034 const line = targetExpression.line;
22035 const character = targetExpression.character;
22036 const fileName = targetExpression.fileName;
22037 if (fileName != null && line != null && character != null) {
22038 position = { fileName, line, column: character };
22039 }
22040 }
22041 self.error({
22042 message: FUNCTION_CALL_NOT_SUPPORTED,
22043 context: functionSymbol,
22044 value: targetFunction,
22045 position
22046 }, context);
22047 }
22048 function simplify(expression) {
22049 if (isPrimitive(expression)) {
22050 return expression;
22051 }
22052 if (Array.isArray(expression)) {
22053 const result = [];
22054 for (const item of expression) {
22055 // Check for a spread expression
22056 if (item && item.__symbolic === 'spread') {
22057 // We call with references as 0 because we require the actual value and cannot
22058 // tolerate a reference here.
22059 const spreadArray = simplifyEagerly(item.expression);
22060 if (Array.isArray(spreadArray)) {
22061 for (const spreadItem of spreadArray) {
22062 result.push(spreadItem);
22063 }
22064 continue;
22065 }
22066 }
22067 const value = simplify(item);
22068 if (shouldIgnore(value)) {
22069 continue;
22070 }
22071 result.push(value);
22072 }
22073 return result;
22074 }
22075 if (expression instanceof StaticSymbol) {
22076 // Stop simplification at builtin symbols or if we are in a reference context and
22077 // the symbol doesn't have members.
22078 if (expression === self.injectionToken || self.conversionMap.has(expression) ||
22079 (references > 0 && !expression.members.length)) {
22080 return expression;
22081 }
22082 else {
22083 const staticSymbol = expression;
22084 const declarationValue = resolveReferenceValue(staticSymbol);
22085 if (declarationValue != null) {
22086 return simplifyNested(staticSymbol, declarationValue);
22087 }
22088 else {
22089 return staticSymbol;
22090 }
22091 }
22092 }
22093 if (expression) {
22094 if (expression['__symbolic']) {
22095 let staticSymbol;
22096 switch (expression['__symbolic']) {
22097 case 'binop':
22098 let left = simplify(expression['left']);
22099 if (shouldIgnore(left))
22100 return left;
22101 let right = simplify(expression['right']);
22102 if (shouldIgnore(right))
22103 return right;
22104 switch (expression['operator']) {
22105 case '&&':
22106 return left && right;
22107 case '||':
22108 return left || right;
22109 case '|':
22110 return left | right;
22111 case '^':
22112 return left ^ right;
22113 case '&':
22114 return left & right;
22115 case '==':
22116 return left == right;
22117 case '!=':
22118 return left != right;
22119 case '===':
22120 return left === right;
22121 case '!==':
22122 return left !== right;
22123 case '<':
22124 return left < right;
22125 case '>':
22126 return left > right;
22127 case '<=':
22128 return left <= right;
22129 case '>=':
22130 return left >= right;
22131 case '<<':
22132 return left << right;
22133 case '>>':
22134 return left >> right;
22135 case '+':
22136 return left + right;
22137 case '-':
22138 return left - right;
22139 case '*':
22140 return left * right;
22141 case '/':
22142 return left / right;
22143 case '%':
22144 return left % right;
22145 }
22146 return null;
22147 case 'if':
22148 let condition = simplify(expression['condition']);
22149 return condition ? simplify(expression['thenExpression']) :
22150 simplify(expression['elseExpression']);
22151 case 'pre':
22152 let operand = simplify(expression['operand']);
22153 if (shouldIgnore(operand))
22154 return operand;
22155 switch (expression['operator']) {
22156 case '+':
22157 return operand;
22158 case '-':
22159 return -operand;
22160 case '!':
22161 return !operand;
22162 case '~':
22163 return ~operand;
22164 }
22165 return null;
22166 case 'index':
22167 let indexTarget = simplifyEagerly(expression['expression']);
22168 let index = simplifyEagerly(expression['index']);
22169 if (indexTarget && isPrimitive(index))
22170 return indexTarget[index];
22171 return null;
22172 case 'select':
22173 const member = expression['member'];
22174 let selectContext = context;
22175 let selectTarget = simplify(expression['expression']);
22176 if (selectTarget instanceof StaticSymbol) {
22177 const members = selectTarget.members.concat(member);
22178 selectContext =
22179 self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
22180 const declarationValue = resolveReferenceValue(selectContext);
22181 if (declarationValue != null) {
22182 return simplifyNested(selectContext, declarationValue);
22183 }
22184 else {
22185 return selectContext;
22186 }
22187 }
22188 if (selectTarget && isPrimitive(member))
22189 return simplifyNested(selectContext, selectTarget[member]);
22190 return null;
22191 case 'reference':
22192 // Note: This only has to deal with variable references, as symbol references have
22193 // been converted into 'resolved'
22194 // in the StaticSymbolResolver.
22195 const name = expression['name'];
22196 const localValue = scope.resolve(name);
22197 if (localValue != BindingScope$1.missing) {
22198 return localValue;
22199 }
22200 break;
22201 case 'resolved':
22202 try {
22203 return simplify(expression.symbol);
22204 }
22205 catch (e) {
22206 // If an error is reported evaluating the symbol record the position of the
22207 // reference in the error so it can
22208 // be reported in the error message generated from the exception.
22209 if (isMetadataError(e) && expression.fileName != null &&
22210 expression.line != null && expression.character != null) {
22211 e.position = {
22212 fileName: expression.fileName,
22213 line: expression.line,
22214 column: expression.character
22215 };
22216 }
22217 throw e;
22218 }
22219 case 'class':
22220 return context;
22221 case 'function':
22222 return context;
22223 case 'new':
22224 case 'call':
22225 // Determine if the function is a built-in conversion
22226 staticSymbol = simplifyInContext(context, expression['expression'], depth + 1, /* references */ 0);
22227 if (staticSymbol instanceof StaticSymbol) {
22228 if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {
22229 // if somebody calls new InjectionToken, don't create an InjectionToken,
22230 // but rather return the symbol to which the InjectionToken is assigned to.
22231 // OpaqueToken is supported too as it is required by the language service to
22232 // support v4 and prior versions of Angular.
22233 return context;
22234 }
22235 const argExpressions = expression['arguments'] || [];
22236 let converter = self.conversionMap.get(staticSymbol);
22237 if (converter) {
22238 const args = argExpressions.map(arg => simplifyNested(context, arg))
22239 .map(arg => shouldIgnore(arg) ? undefined : arg);
22240 return converter(context, args);
22241 }
22242 else {
22243 // Determine if the function is one we can simplify.
22244 const targetFunction = resolveReferenceValue(staticSymbol);
22245 return simplifyCall(staticSymbol, targetFunction, argExpressions, expression['expression']);
22246 }
22247 }
22248 return IGNORE;
22249 case 'error':
22250 let message = expression.message;
22251 if (expression['line'] != null) {
22252 self.error({
22253 message,
22254 context: expression.context,
22255 value: expression,
22256 position: {
22257 fileName: expression['fileName'],
22258 line: expression['line'],
22259 column: expression['character']
22260 }
22261 }, context);
22262 }
22263 else {
22264 self.error({ message, context: expression.context }, context);
22265 }
22266 return IGNORE;
22267 case 'ignore':
22268 return expression;
22269 }
22270 return null;
22271 }
22272 return mapStringMap(expression, (value, name) => {
22273 if (REFERENCE_SET.has(name)) {
22274 if (name === USE_VALUE$1 && PROVIDE in expression) {
22275 // If this is a provider expression, check for special tokens that need the value
22276 // during analysis.
22277 const provide = simplify(expression.provide);
22278 if (provide === self.ROUTES || provide == self.ANALYZE_FOR_ENTRY_COMPONENTS) {
22279 return simplify(value);
22280 }
22281 }
22282 return simplifyLazily(value);
22283 }
22284 return simplify(value);
22285 });
22286 }
22287 return IGNORE;
22288 }
22289 return simplify(value);
22290 }
22291 let result;
22292 try {
22293 result = simplifyInContext(context, value, 0, lazy ? 1 : 0);
22294 }
22295 catch (e) {
22296 if (this.errorRecorder) {
22297 this.reportError(e, context);
22298 }
22299 else {
22300 throw formatMetadataError(e, context);
22301 }
22302 }
22303 if (shouldIgnore(result)) {
22304 return undefined;
22305 }
22306 return result;
22307 }
22308 getTypeMetadata(type) {
22309 const resolvedSymbol = this.symbolResolver.resolveSymbol(type);
22310 return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
22311 { __symbolic: 'class' };
22312 }
22313 reportError(error, context, path) {
22314 if (this.errorRecorder) {
22315 this.errorRecorder(formatMetadataError(error, context), (context && context.filePath) || path);
22316 }
22317 else {
22318 throw error;
22319 }
22320 }
22321 error({ message, summary, advise, position, context, value, symbol, chain }, reportingContext) {
22322 this.reportError(metadataError(message, summary, advise, position, symbol, context, chain), reportingContext);
22323 }
22324 }
22325 const METADATA_ERROR = 'ngMetadataError';
22326 function metadataError(message, summary, advise, position, symbol, context, chain) {
22327 const error = syntaxError(message);
22328 error[METADATA_ERROR] = true;
22329 if (advise)
22330 error.advise = advise;
22331 if (position)
22332 error.position = position;
22333 if (summary)
22334 error.summary = summary;
22335 if (context)
22336 error.context = context;
22337 if (chain)
22338 error.chain = chain;
22339 if (symbol)
22340 error.symbol = symbol;
22341 return error;
22342 }
22343 function isMetadataError(error) {
22344 return !!error[METADATA_ERROR];
22345 }
22346 const REFERENCE_TO_NONEXPORTED_CLASS = 'Reference to non-exported class';
22347 const VARIABLE_NOT_INITIALIZED = 'Variable not initialized';
22348 const DESTRUCTURE_NOT_SUPPORTED = 'Destructuring not supported';
22349 const COULD_NOT_RESOLVE_TYPE = 'Could not resolve type';
22350 const FUNCTION_CALL_NOT_SUPPORTED = 'Function call not supported';
22351 const REFERENCE_TO_LOCAL_SYMBOL = 'Reference to a local symbol';
22352 const LAMBDA_NOT_SUPPORTED = 'Lambda not supported';
22353 function expandedMessage(message, context) {
22354 switch (message) {
22355 case REFERENCE_TO_NONEXPORTED_CLASS:
22356 if (context && context.className) {
22357 return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`;
22358 }
22359 break;
22360 case VARIABLE_NOT_INITIALIZED:
22361 return 'Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler';
22362 case DESTRUCTURE_NOT_SUPPORTED:
22363 return 'Referencing an exported destructured variable or constant is not supported in decorators and this value is needed by the template compiler';
22364 case COULD_NOT_RESOLVE_TYPE:
22365 if (context && context.typeName) {
22366 return `Could not resolve type ${context.typeName}`;
22367 }
22368 break;
22369 case FUNCTION_CALL_NOT_SUPPORTED:
22370 if (context && context.name) {
22371 return `Function calls are not supported in decorators but '${context.name}' was called`;
22372 }
22373 return 'Function calls are not supported in decorators';
22374 case REFERENCE_TO_LOCAL_SYMBOL:
22375 if (context && context.name) {
22376 return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`;
22377 }
22378 break;
22379 case LAMBDA_NOT_SUPPORTED:
22380 return `Function expressions are not supported in decorators`;
22381 }
22382 return message;
22383 }
22384 function messageAdvise(message, context) {
22385 switch (message) {
22386 case REFERENCE_TO_NONEXPORTED_CLASS:
22387 if (context && context.className) {
22388 return `Consider exporting '${context.className}'`;
22389 }
22390 break;
22391 case DESTRUCTURE_NOT_SUPPORTED:
22392 return 'Consider simplifying to avoid destructuring';
22393 case REFERENCE_TO_LOCAL_SYMBOL:
22394 if (context && context.name) {
22395 return `Consider exporting '${context.name}'`;
22396 }
22397 break;
22398 case LAMBDA_NOT_SUPPORTED:
22399 return `Consider changing the function expression into an exported function`;
22400 }
22401 return undefined;
22402 }
22403 function errorSummary(error) {
22404 if (error.summary) {
22405 return error.summary;
22406 }
22407 switch (error.message) {
22408 case REFERENCE_TO_NONEXPORTED_CLASS:
22409 if (error.context && error.context.className) {
22410 return `references non-exported class ${error.context.className}`;
22411 }
22412 break;
22413 case VARIABLE_NOT_INITIALIZED:
22414 return 'is not initialized';
22415 case DESTRUCTURE_NOT_SUPPORTED:
22416 return 'is a destructured variable';
22417 case COULD_NOT_RESOLVE_TYPE:
22418 return 'could not be resolved';
22419 case FUNCTION_CALL_NOT_SUPPORTED:
22420 if (error.context && error.context.name) {
22421 return `calls '${error.context.name}'`;
22422 }
22423 return `calls a function`;
22424 case REFERENCE_TO_LOCAL_SYMBOL:
22425 if (error.context && error.context.name) {
22426 return `references local variable ${error.context.name}`;
22427 }
22428 return `references a local variable`;
22429 }
22430 return 'contains the error';
22431 }
22432 function mapStringMap(input, transform) {
22433 if (!input)
22434 return {};
22435 const result = {};
22436 Object.keys(input).forEach((key) => {
22437 const value = transform(input[key], key);
22438 if (!shouldIgnore(value)) {
22439 if (HIDDEN_KEY.test(key)) {
22440 Object.defineProperty(result, key, { enumerable: false, configurable: true, value: value });
22441 }
22442 else {
22443 result[key] = value;
22444 }
22445 }
22446 });
22447 return result;
22448 }
22449 function isPrimitive(o) {
22450 return o === null || (typeof o !== 'function' && typeof o !== 'object');
22451 }
22452 class BindingScope$1 {
22453 static build() {
22454 const current = new Map();
22455 return {
22456 define: function (name, value) {
22457 current.set(name, value);
22458 return this;
22459 },
22460 done: function () {
22461 return current.size > 0 ? new PopulatedScope(current) : BindingScope$1.empty;
22462 }
22463 };
22464 }
22465 }
22466 BindingScope$1.missing = {};
22467 BindingScope$1.empty = { resolve: name => BindingScope$1.missing };
22468 class PopulatedScope extends BindingScope$1 {
22469 constructor(bindings) {
22470 super();
22471 this.bindings = bindings;
22472 }
22473 resolve(name) {
22474 return this.bindings.has(name) ? this.bindings.get(name) : BindingScope$1.missing;
22475 }
22476 }
22477 function formatMetadataMessageChain(chain, advise) {
22478 const expanded = expandedMessage(chain.message, chain.context);
22479 const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : '';
22480 const message = `${expanded}${nesting}`;
22481 const position = chain.position;
22482 const next = chain.next ?
22483 formatMetadataMessageChain(chain.next, advise) :
22484 advise ? { message: advise } : undefined;
22485 return { message, position, next: next ? [next] : undefined };
22486 }
22487 function formatMetadataError(e, context) {
22488 if (isMetadataError(e)) {
22489 // Produce a formatted version of the and leaving enough information in the original error
22490 // to recover the formatting information to eventually produce a diagnostic error message.
22491 const position = e.position;
22492 const chain = {
22493 message: `Error during template compile of '${context.name}'`,
22494 position: position,
22495 next: { message: e.message, next: e.chain, context: e.context, symbol: e.symbol }
22496 };
22497 const advise = e.advise || messageAdvise(e.message, e.context);
22498 return formattedError(formatMetadataMessageChain(chain, advise));
22499 }
22500 return e;
22501 }
22502
22503 /**
22504 * @license
22505 * Copyright Google LLC All Rights Reserved.
22506 *
22507 * Use of this source code is governed by an MIT-style license that can be
22508 * found in the LICENSE file at https://angular.io/license
22509 */
22510 class AotSummaryResolver {
22511 constructor(host, staticSymbolCache) {
22512 this.host = host;
22513 this.staticSymbolCache = staticSymbolCache;
22514 // Note: this will only contain StaticSymbols without members!
22515 this.summaryCache = new Map();
22516 this.loadedFilePaths = new Map();
22517 // Note: this will only contain StaticSymbols without members!
22518 this.importAs = new Map();
22519 this.knownFileNameToModuleNames = new Map();
22520 }
22521 isLibraryFile(filePath) {
22522 // Note: We need to strip the .ngfactory. file path,
22523 // so this method also works for generated files
22524 // (for which host.isSourceFile will always return false).
22525 return !this.host.isSourceFile(stripGeneratedFileSuffix(filePath));
22526 }
22527 toSummaryFileName(filePath, referringSrcFileName) {
22528 return this.host.toSummaryFileName(filePath, referringSrcFileName);
22529 }
22530 fromSummaryFileName(fileName, referringLibFileName) {
22531 return this.host.fromSummaryFileName(fileName, referringLibFileName);
22532 }
22533 resolveSummary(staticSymbol) {
22534 const rootSymbol = staticSymbol.members.length ?
22535 this.staticSymbolCache.get(staticSymbol.filePath, staticSymbol.name) :
22536 staticSymbol;
22537 let summary = this.summaryCache.get(rootSymbol);
22538 if (!summary) {
22539 this._loadSummaryFile(staticSymbol.filePath);
22540 summary = this.summaryCache.get(staticSymbol);
22541 }
22542 return (rootSymbol === staticSymbol && summary) || null;
22543 }
22544 getSymbolsOf(filePath) {
22545 if (this._loadSummaryFile(filePath)) {
22546 return Array.from(this.summaryCache.keys()).filter((symbol) => symbol.filePath === filePath);
22547 }
22548 return null;
22549 }
22550 getImportAs(staticSymbol) {
22551 staticSymbol.assertNoMembers();
22552 return this.importAs.get(staticSymbol);
22553 }
22554 /**
22555 * Converts a file path to a module name that can be used as an `import`.
22556 */
22557 getKnownModuleName(importedFilePath) {
22558 return this.knownFileNameToModuleNames.get(importedFilePath) || null;
22559 }
22560 addSummary(summary) {
22561 this.summaryCache.set(summary.symbol, summary);
22562 }
22563 _loadSummaryFile(filePath) {
22564 let hasSummary = this.loadedFilePaths.get(filePath);
22565 if (hasSummary != null) {
22566 return hasSummary;
22567 }
22568 let json = null;
22569 if (this.isLibraryFile(filePath)) {
22570 const summaryFilePath = summaryFileName(filePath);
22571 try {
22572 json = this.host.loadSummary(summaryFilePath);
22573 }
22574 catch (e) {
22575 console.error(`Error loading summary file ${summaryFilePath}`);
22576 throw e;
22577 }
22578 }
22579 hasSummary = json != null;
22580 this.loadedFilePaths.set(filePath, hasSummary);
22581 if (json) {
22582 const { moduleName, summaries, importAs } = deserializeSummaries(this.staticSymbolCache, this, filePath, json);
22583 summaries.forEach((summary) => this.summaryCache.set(summary.symbol, summary));
22584 if (moduleName) {
22585 this.knownFileNameToModuleNames.set(filePath, moduleName);
22586 }
22587 importAs.forEach((importAs) => {
22588 this.importAs.set(importAs.symbol, importAs.importAs);
22589 });
22590 }
22591 return hasSummary;
22592 }
22593 }
22594
22595 class JitSummaryResolver {
22596 constructor() {
22597 this._summaries = new Map();
22598 }
22599 isLibraryFile() {
22600 return false;
22601 }
22602 toSummaryFileName(fileName) {
22603 return fileName;
22604 }
22605 fromSummaryFileName(fileName) {
22606 return fileName;
22607 }
22608 resolveSummary(reference) {
22609 return this._summaries.get(reference) || null;
22610 }
22611 getSymbolsOf() {
22612 return [];
22613 }
22614 getImportAs(reference) {
22615 return reference;
22616 }
22617 getKnownModuleName(fileName) {
22618 return null;
22619 }
22620 addSummary(summary) {
22621 this._summaries.set(summary.symbol, summary);
22622 }
22623 }
22624
22625 /**
22626 * @license
22627 * Copyright Google LLC All Rights Reserved.
22628 *
22629 * Use of this source code is governed by an MIT-style license that can be
22630 * found in the LICENSE file at https://angular.io/license
22631 */
22632 /**
22633 * The index of each URI component in the return value of goog.uri.utils.split.
22634 * @enum {number}
22635 */
22636 var _ComponentIndex;
22637 (function (_ComponentIndex) {
22638 _ComponentIndex[_ComponentIndex["Scheme"] = 1] = "Scheme";
22639 _ComponentIndex[_ComponentIndex["UserInfo"] = 2] = "UserInfo";
22640 _ComponentIndex[_ComponentIndex["Domain"] = 3] = "Domain";
22641 _ComponentIndex[_ComponentIndex["Port"] = 4] = "Port";
22642 _ComponentIndex[_ComponentIndex["Path"] = 5] = "Path";
22643 _ComponentIndex[_ComponentIndex["QueryData"] = 6] = "QueryData";
22644 _ComponentIndex[_ComponentIndex["Fragment"] = 7] = "Fragment";
22645 })(_ComponentIndex || (_ComponentIndex = {}));
22646
22647 /**
22648 * @license
22649 * Copyright Google LLC All Rights Reserved.
22650 *
22651 * Use of this source code is governed by an MIT-style license that can be
22652 * found in the LICENSE file at https://angular.io/license
22653 */
22654 // This file only reexports content of the `src` folder. Keep it that way.
22655 // This function call has a global side effects and publishes the compiler into global namespace for
22656 // the late binding of the Compiler to the @angular/core for jit compilation.
22657 publishFacade(_global);
22658
22659 /**
22660 * @license
22661 * Copyright Google LLC All Rights Reserved.
22662 *
22663 * Use of this source code is governed by an MIT-style license that can be
22664 * found in the LICENSE file at https://angular.io/license
22665 */
22666 /**
22667 * Matches an Angular attribute to a binding type. See `ATTR` for more details.
22668 *
22669 * This is adapted from packages/compiler/src/render3/r3_template_transform.ts
22670 * to allow empty binding names and match template attributes.
22671 */
22672 const BIND_NAME_REGEXP$2 = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@)|(\*))(.*))|\[\(([^\)]*)\)\]|\[([^\]]*)\]|\(([^\)]*)\))$/;
22673 /**
22674 * Represents possible Angular attribute bindings, as indices on a match of `BIND_NAME_REGEXP`.
22675 */
22676 var ATTR;
22677 (function (ATTR) {
22678 /** "bind-" */
22679 ATTR[ATTR["KW_BIND"] = 1] = "KW_BIND";
22680 /** "let-" */
22681 ATTR[ATTR["KW_LET"] = 2] = "KW_LET";
22682 /** "ref-/#" */
22683 ATTR[ATTR["KW_REF"] = 3] = "KW_REF";
22684 /** "on-" */
22685 ATTR[ATTR["KW_ON"] = 4] = "KW_ON";
22686 /** "bindon-" */
22687 ATTR[ATTR["KW_BINDON"] = 5] = "KW_BINDON";
22688 /** "@" */
22689 ATTR[ATTR["KW_AT"] = 6] = "KW_AT";
22690 /**
22691 * "*"
22692 * Microsyntax template starts with '*'. See https://angular.io/api/core/TemplateRef
22693 */
22694 ATTR[ATTR["KW_MICROSYNTAX"] = 7] = "KW_MICROSYNTAX";
22695 /** The identifier after "bind-", "let-", "ref-/#", "on-", "bindon-", "@", or "*" */
22696 ATTR[ATTR["IDENT_KW"] = 8] = "IDENT_KW";
22697 /** Identifier inside [()] */
22698 ATTR[ATTR["IDENT_BANANA_BOX"] = 9] = "IDENT_BANANA_BOX";
22699 /** Identifier inside [] */
22700 ATTR[ATTR["IDENT_PROPERTY"] = 10] = "IDENT_PROPERTY";
22701 /** Identifier inside () */
22702 ATTR[ATTR["IDENT_EVENT"] = 11] = "IDENT_EVENT";
22703 })(ATTR || (ATTR = {}));
22704 /**
22705 * Returns a descriptor for a given Angular attribute, or undefined if the attribute is
22706 * not an Angular attribute.
22707 */
22708 function getBindingDescriptor(attribute) {
22709 const bindParts = attribute.match(BIND_NAME_REGEXP$2);
22710 if (!bindParts)
22711 return;
22712 // The first match element is skipped because it matches the entire attribute text, including the
22713 // binding part.
22714 const kind = bindParts.findIndex((val, i) => i > 0 && val !== undefined);
22715 if (!(kind in ATTR)) {
22716 throw TypeError(`"${kind}" is not a valid Angular binding kind for "${attribute}"`);
22717 }
22718 return {
22719 kind,
22720 name: bindParts[ATTR.IDENT_KW],
22721 };
22722 }
22723
22724 /**
22725 * @license
22726 * Copyright Google LLC All Rights Reserved.
22727 *
22728 * Use of this source code is governed by an MIT-style license that can be
22729 * found in the LICENSE file at https://angular.io/license
22730 */
22731 const Diagnostic = {
22732 directive_not_in_module: {
22733 message: `%1 '%2' is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration.`,
22734 kind: 'Suggestion',
22735 },
22736 missing_template_and_templateurl: {
22737 message: `Component '%1' must have a template or templateUrl`,
22738 kind: 'Error',
22739 },
22740 both_template_and_templateurl: {
22741 message: `Component '%1' must not have both template and templateUrl`,
22742 kind: 'Error',
22743 },
22744 invalid_templateurl: {
22745 message: `URL does not point to a valid file`,
22746 kind: 'Error',
22747 },
22748 template_context_missing_member: {
22749 message: `The template context of '%1' does not define %2.\n` +
22750 `If the context type is a base type or 'any', consider refining it to a more specific type.`,
22751 kind: 'Suggestion',
22752 },
22753 callable_expression_expected_method_call: {
22754 message: 'Unexpected callable expression. Expected a method call',
22755 kind: 'Warning',
22756 },
22757 call_target_not_callable: {
22758 message: `Call target '%1' has non-callable type '%2'.`,
22759 kind: 'Error',
22760 },
22761 expression_might_be_null: {
22762 message: 'The expression might be null',
22763 kind: 'Error',
22764 },
22765 expected_a_number_type: {
22766 message: 'Expected a number type',
22767 kind: 'Error',
22768 },
22769 expected_a_string_or_number_type: {
22770 message: 'Expected operands to be a string or number type',
22771 kind: 'Error',
22772 },
22773 expected_operands_of_comparable_types_or_any: {
22774 message: 'Expected operands to be of comparable types or any',
22775 kind: 'Error',
22776 },
22777 unrecognized_operator: {
22778 message: 'Unrecognized operator %1',
22779 kind: 'Error',
22780 },
22781 unrecognized_primitive: {
22782 message: 'Unrecognized primitive %1',
22783 kind: 'Error',
22784 },
22785 no_pipe_found: {
22786 message: 'No pipe of name %1 found',
22787 kind: 'Error',
22788 },
22789 // TODO: Consider a better error message here.
22790 unable_to_resolve_compatible_call_signature: {
22791 message: 'Unable to resolve compatible call signature',
22792 kind: 'Error',
22793 },
22794 unable_to_resolve_signature: {
22795 message: 'Unable to resolve signature for call of %1',
22796 kind: 'Error',
22797 },
22798 could_not_resolve_type: {
22799 message: `Could not resolve the type of '%1'`,
22800 kind: 'Error',
22801 },
22802 identifier_not_callable: {
22803 message: `'%1' is not callable`,
22804 kind: 'Error',
22805 },
22806 identifier_possibly_undefined: {
22807 message: `'%1' is possibly undefined. Consider using the safe navigation operator (%2) or non-null assertion operator (%3).`,
22808 kind: 'Suggestion',
22809 },
22810 identifier_not_defined_in_app_context: {
22811 message: `Identifier '%1' is not defined. The component declaration, template variable declarations, and element references do not contain such a member`,
22812 kind: 'Error',
22813 },
22814 identifier_not_defined_on_receiver: {
22815 message: `Identifier '%1' is not defined. '%2' does not contain such a member`,
22816 kind: 'Error',
22817 },
22818 identifier_is_private: {
22819 message: `Identifier '%1' refers to a private member of %2`,
22820 kind: 'Warning',
22821 },
22822 };
22823 /**
22824 * Creates a language service diagnostic.
22825 * @param span location the diagnostic for
22826 * @param dm diagnostic message
22827 * @param formatArgs run-time arguments to format the diagnostic message with (see the messages in
22828 * the `Diagnostic` object for an example).
22829 * @returns a created diagnostic
22830 */
22831 function createDiagnostic(span, dm, ...formatArgs) {
22832 // Formats "%1 %2" with formatArgs ['a', 'b'] as "a b"
22833 const formattedMessage = dm.message.replace(/%(\d+)/g, (_, index) => formatArgs[+index - 1]);
22834 return {
22835 kind: ts.DiagnosticCategory[dm.kind],
22836 message: formattedMessage,
22837 span,
22838 };
22839 }
22840
22841 /**
22842 * @license
22843 * Copyright Google LLC All Rights Reserved.
22844 *
22845 * Use of this source code is governed by an MIT-style license that can be
22846 * found in the LICENSE file at https://angular.io/license
22847 */
22848 /**
22849 * An enumeration of basic types.
22850 *
22851 * @publicApi
22852 */
22853 var BuiltinType$1;
22854 (function (BuiltinType) {
22855 /**
22856 * The type is a type that can hold any other type.
22857 */
22858 BuiltinType[BuiltinType["Any"] = -1] = "Any";
22859 /** Unknown types are functionally identical to any. */
22860 BuiltinType[BuiltinType["Unknown"] = -1] = "Unknown";
22861 /**
22862 * The type of a string literal.
22863 */
22864 BuiltinType[BuiltinType["String"] = 1] = "String";
22865 /**
22866 * The type of a numeric literal.
22867 */
22868 BuiltinType[BuiltinType["Number"] = 2] = "Number";
22869 /**
22870 * The type of the `true` and `false` literals.
22871 */
22872 BuiltinType[BuiltinType["Boolean"] = 4] = "Boolean";
22873 /**
22874 * The type of the `undefined` literal.
22875 */
22876 BuiltinType[BuiltinType["Undefined"] = 8] = "Undefined";
22877 /**
22878 * the type of the `null` literal.
22879 */
22880 BuiltinType[BuiltinType["Null"] = 16] = "Null";
22881 /**
22882 * the type is an unbound type parameter.
22883 */
22884 BuiltinType[BuiltinType["Unbound"] = 32] = "Unbound";
22885 /**
22886 * Not a built-in type.
22887 */
22888 BuiltinType[BuiltinType["Other"] = 64] = "Other";
22889 BuiltinType[BuiltinType["Object"] = 128] = "Object";
22890 })(BuiltinType$1 || (BuiltinType$1 = {}));
22891
22892 /**
22893 * @license
22894 * Copyright Google LLC All Rights Reserved.
22895 *
22896 * Use of this source code is governed by an MIT-style license that can be
22897 * found in the LICENSE file at https://angular.io/license
22898 */
22899 function isParseSourceSpan(value) {
22900 return value && !!value.start;
22901 }
22902 function spanOf(span) {
22903 if (!span)
22904 return undefined;
22905 if (isParseSourceSpan(span)) {
22906 return { start: span.start.offset, end: span.end.offset };
22907 }
22908 else {
22909 if (span.endSourceSpan) {
22910 return { start: span.sourceSpan.start.offset, end: span.endSourceSpan.end.offset };
22911 }
22912 else if (span.children && span.children.length) {
22913 return {
22914 start: span.sourceSpan.start.offset,
22915 end: spanOf(span.children[span.children.length - 1]).end
22916 };
22917 }
22918 return { start: span.sourceSpan.start.offset, end: span.sourceSpan.end.offset };
22919 }
22920 }
22921 function inSpan(position, span, exclusive) {
22922 return span != null &&
22923 (exclusive ? position >= span.start && position < span.end :
22924 position >= span.start && position <= span.end);
22925 }
22926 function offsetSpan(span, amount) {
22927 return { start: span.start + amount, end: span.end + amount };
22928 }
22929 function isNarrower(spanA, spanB) {
22930 return spanA.start >= spanB.start && spanA.end <= spanB.end;
22931 }
22932 function isStructuralDirective(type) {
22933 var _a;
22934 for (const diDep of type.diDeps) {
22935 const diDepName = identifierName((_a = diDep.token) === null || _a === void 0 ? void 0 : _a.identifier);
22936 if (diDepName === Identifiers.TemplateRef.name ||
22937 diDepName === Identifiers.ViewContainerRef.name) {
22938 return true;
22939 }
22940 }
22941 return false;
22942 }
22943 function getSelectors(info) {
22944 const map = new Map();
22945 const results = [];
22946 for (const directive of info.directives) {
22947 const selectors = CssSelector.parse(directive.selector);
22948 for (const selector of selectors) {
22949 results.push(selector);
22950 map.set(selector, directive);
22951 }
22952 }
22953 return { selectors: results, map };
22954 }
22955 function diagnosticInfoFromTemplateInfo(info) {
22956 return {
22957 fileName: info.template.fileName,
22958 offset: info.template.span.start,
22959 query: info.template.query,
22960 members: info.template.members,
22961 htmlAst: info.htmlAst,
22962 templateAst: info.templateAst,
22963 source: info.template.source,
22964 };
22965 }
22966 function findTemplateAstAt(ast, position) {
22967 const path = [];
22968 const visitor = new class extends RecursiveTemplateAstVisitor {
22969 visit(ast) {
22970 let span = spanOf(ast);
22971 if (inSpan(position, span)) {
22972 const len = path.length;
22973 if (!len || isNarrower(span, spanOf(path[len - 1]))) {
22974 path.push(ast);
22975 }
22976 }
22977 else {
22978 // Returning a value here will result in the children being skipped.
22979 return true;
22980 }
22981 }
22982 visitEmbeddedTemplate(ast, context) {
22983 return this.visitChildren(context, visit => {
22984 // Ignore reference, variable and providers
22985 visit(ast.attrs);
22986 visit(ast.directives);
22987 visit(ast.children);
22988 });
22989 }
22990 visitElement(ast, context) {
22991 return this.visitChildren(context, visit => {
22992 // Ingnore providers
22993 visit(ast.attrs);
22994 visit(ast.inputs);
22995 visit(ast.outputs);
22996 visit(ast.references);
22997 visit(ast.directives);
22998 visit(ast.children);
22999 });
23000 }
23001 visitDirective(ast, context) {
23002 // Ignore the host properties of a directive
23003 const result = this.visitChildren(context, visit => {
23004 visit(ast.inputs);
23005 });
23006 // We never care about the diretive itself, just its inputs.
23007 if (path[path.length - 1] === ast) {
23008 path.pop();
23009 }
23010 return result;
23011 }
23012 };
23013 templateVisitAll(visitor, ast);
23014 return new AstPath(path, position);
23015 }
23016 /**
23017 * Find the tightest node at the specified `position` from the AST `nodes`, and
23018 * return the path to the node.
23019 * @param nodes HTML AST nodes
23020 * @param position
23021 */
23022 function getPathToNodeAtPosition(nodes, position) {
23023 const path = [];
23024 const visitor = new class extends RecursiveVisitor {
23025 visit(ast) {
23026 const span = spanOf(ast);
23027 if (inSpan(position, span)) {
23028 path.push(ast);
23029 }
23030 else {
23031 // Returning a truthy value here will skip all children and terminate
23032 // the visit.
23033 return true;
23034 }
23035 }
23036 };
23037 visitAll$1(visitor, nodes);
23038 return new AstPath(path, position);
23039 }
23040 /**
23041 * Inverts an object's key-value pairs.
23042 */
23043 function invertMap(obj) {
23044 const result = {};
23045 for (const name of Object.keys(obj)) {
23046 const v = obj[name];
23047 result[v] = name;
23048 }
23049 return result;
23050 }
23051 /**
23052 * Finds the directive member providing a template output binding, if one exists.
23053 * @param info aggregate template AST information
23054 * @param path narrowing
23055 */
23056 function findOutputBinding(binding, path, query) {
23057 const element = path.first(ElementAst);
23058 if (element) {
23059 for (const directive of element.directives) {
23060 const invertedOutputs = invertMap(directive.directive.outputs);
23061 const fieldName = invertedOutputs[binding.name];
23062 if (fieldName) {
23063 const classSymbol = query.getTypeSymbol(directive.directive.type.reference);
23064 if (classSymbol) {
23065 return classSymbol.members().get(fieldName);
23066 }
23067 }
23068 }
23069 }
23070 }
23071 /**
23072 * Returns an absolute path from the text in `node`. If the text is already
23073 * an absolute path, return it as is, otherwise join the path with the filename
23074 * of the source file.
23075 */
23076 function extractAbsoluteFilePath(node) {
23077 const url = node.text;
23078 return path.isAbsolute(url) ? url : path.join(path.dirname(node.getSourceFile().fileName), url);
23079 }
23080
23081 /**
23082 * @license
23083 * Copyright Google LLC All Rights Reserved.
23084 *
23085 * Use of this source code is governed by an MIT-style license that can be
23086 * found in the LICENSE file at https://angular.io/license
23087 */
23088 // AstType calculatetype of the ast given AST element.
23089 class AstType {
23090 constructor(scope, query, context, source) {
23091 this.scope = scope;
23092 this.query = query;
23093 this.context = context;
23094 this.source = source;
23095 this.diagnostics = [];
23096 }
23097 getType(ast) {
23098 return ast.visit(this);
23099 }
23100 getDiagnostics(ast) {
23101 const type = ast.visit(this);
23102 if (this.context.inEvent && type.callable) {
23103 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.callable_expression_expected_method_call));
23104 }
23105 return this.diagnostics;
23106 }
23107 visitUnary(ast) {
23108 // Visit the child to produce diagnostics.
23109 ast.expr.visit(this);
23110 // The unary plus and minus operator are always of type number.
23111 // https://github.com/Microsoft/TypeScript/blob/v1.8.10/doc/spec.md#4.18
23112 switch (ast.operator) {
23113 case '-':
23114 case '+':
23115 return this.query.getBuiltinType(BuiltinType$1.Number);
23116 }
23117 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unrecognized_operator, ast.operator));
23118 return this.anyType;
23119 }
23120 visitBinary(ast) {
23121 const getType = (ast, operation) => {
23122 const type = this.getType(ast);
23123 if (type.nullable) {
23124 switch (operation) {
23125 case '&&':
23126 case '||':
23127 case '==':
23128 case '!=':
23129 case '===':
23130 case '!==':
23131 // Nullable allowed.
23132 break;
23133 default:
23134 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.expression_might_be_null));
23135 break;
23136 }
23137 }
23138 return type;
23139 };
23140 const leftType = getType(ast.left, ast.operation);
23141 const rightType = getType(ast.right, ast.operation);
23142 const leftKind = this.query.getTypeKind(leftType);
23143 const rightKind = this.query.getTypeKind(rightType);
23144 // The following swtich implements operator typing similar to the
23145 // type production tables in the TypeScript specification.
23146 // https://github.com/Microsoft/TypeScript/blob/v1.8.10/doc/spec.md#4.19
23147 const operKind = leftKind << 8 | rightKind;
23148 switch (ast.operation) {
23149 case '*':
23150 case '/':
23151 case '%':
23152 case '-':
23153 case '<<':
23154 case '>>':
23155 case '>>>':
23156 case '&':
23157 case '^':
23158 case '|':
23159 switch (operKind) {
23160 case BuiltinType$1.Any << 8 | BuiltinType$1.Any:
23161 case BuiltinType$1.Number << 8 | BuiltinType$1.Any:
23162 case BuiltinType$1.Any << 8 | BuiltinType$1.Number:
23163 case BuiltinType$1.Number << 8 | BuiltinType$1.Number:
23164 return this.query.getBuiltinType(BuiltinType$1.Number);
23165 default:
23166 let errorAst = ast.left;
23167 switch (leftKind) {
23168 case BuiltinType$1.Any:
23169 case BuiltinType$1.Number:
23170 errorAst = ast.right;
23171 break;
23172 }
23173 this.diagnostics.push(createDiagnostic(errorAst.span, Diagnostic.expected_a_number_type));
23174 return this.anyType;
23175 }
23176 case '+':
23177 switch (operKind) {
23178 case BuiltinType$1.Any << 8 | BuiltinType$1.Any:
23179 case BuiltinType$1.Any << 8 | BuiltinType$1.Boolean:
23180 case BuiltinType$1.Any << 8 | BuiltinType$1.Number:
23181 case BuiltinType$1.Any << 8 | BuiltinType$1.Other:
23182 case BuiltinType$1.Boolean << 8 | BuiltinType$1.Any:
23183 case BuiltinType$1.Number << 8 | BuiltinType$1.Any:
23184 case BuiltinType$1.Other << 8 | BuiltinType$1.Any:
23185 return this.anyType;
23186 case BuiltinType$1.Any << 8 | BuiltinType$1.String:
23187 case BuiltinType$1.Boolean << 8 | BuiltinType$1.String:
23188 case BuiltinType$1.Number << 8 | BuiltinType$1.String:
23189 case BuiltinType$1.String << 8 | BuiltinType$1.Any:
23190 case BuiltinType$1.String << 8 | BuiltinType$1.Boolean:
23191 case BuiltinType$1.String << 8 | BuiltinType$1.Number:
23192 case BuiltinType$1.String << 8 | BuiltinType$1.String:
23193 case BuiltinType$1.String << 8 | BuiltinType$1.Other:
23194 case BuiltinType$1.Other << 8 | BuiltinType$1.String:
23195 return this.query.getBuiltinType(BuiltinType$1.String);
23196 case BuiltinType$1.Number << 8 | BuiltinType$1.Number:
23197 return this.query.getBuiltinType(BuiltinType$1.Number);
23198 case BuiltinType$1.Boolean << 8 | BuiltinType$1.Number:
23199 case BuiltinType$1.Other << 8 | BuiltinType$1.Number:
23200 this.diagnostics.push(createDiagnostic(ast.left.span, Diagnostic.expected_a_number_type));
23201 return this.anyType;
23202 case BuiltinType$1.Number << 8 | BuiltinType$1.Boolean:
23203 case BuiltinType$1.Number << 8 | BuiltinType$1.Other:
23204 this.diagnostics.push(createDiagnostic(ast.right.span, Diagnostic.expected_a_number_type));
23205 return this.anyType;
23206 default:
23207 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.expected_a_string_or_number_type));
23208 return this.anyType;
23209 }
23210 case '>':
23211 case '<':
23212 case '<=':
23213 case '>=':
23214 case '==':
23215 case '!=':
23216 case '===':
23217 case '!==':
23218 if (!(leftKind & rightKind) &&
23219 !((leftKind | rightKind) & (BuiltinType$1.Null | BuiltinType$1.Undefined))) {
23220 // Two values are comparable only if
23221 // - they have some type overlap, or
23222 // - at least one is not defined
23223 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.expected_operands_of_comparable_types_or_any));
23224 }
23225 return this.query.getBuiltinType(BuiltinType$1.Boolean);
23226 case '&&':
23227 return rightType;
23228 case '||':
23229 return this.query.getTypeUnion(leftType, rightType);
23230 }
23231 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unrecognized_operator, ast.operation));
23232 return this.anyType;
23233 }
23234 visitChain(ast) {
23235 // If we are producing diagnostics, visit the children
23236 for (const expr of ast.expressions) {
23237 expr.visit(this);
23238 }
23239 // The type of a chain is always undefined.
23240 return this.query.getBuiltinType(BuiltinType$1.Undefined);
23241 }
23242 visitConditional(ast) {
23243 // The type of a conditional is the union of the true and false conditions.
23244 ast.condition.visit(this);
23245 ast.trueExp.visit(this);
23246 ast.falseExp.visit(this);
23247 return this.query.getTypeUnion(this.getType(ast.trueExp), this.getType(ast.falseExp));
23248 }
23249 visitFunctionCall(ast) {
23250 // The type of a function call is the return type of the selected signature.
23251 // The signature is selected based on the types of the arguments. Angular doesn't
23252 // support contextual typing of arguments so this is simpler than TypeScript's
23253 // version.
23254 const args = ast.args.map(arg => this.getType(arg));
23255 const target = this.getType(ast.target);
23256 if (!target || !target.callable) {
23257 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.call_target_not_callable, this.sourceOf(ast.target), target.name));
23258 return this.anyType;
23259 }
23260 const signature = target.selectSignature(args);
23261 if (signature) {
23262 return signature.result;
23263 }
23264 // TODO: Consider a better error message here. See `typescript_symbols#selectSignature` for more
23265 // details.
23266 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unable_to_resolve_compatible_call_signature));
23267 return this.anyType;
23268 }
23269 visitImplicitReceiver(_ast) {
23270 const _this = this;
23271 // Return a pseudo-symbol for the implicit receiver.
23272 // The members of the implicit receiver are what is defined by the
23273 // scope passed into this class.
23274 return {
23275 name: '$implicit',
23276 kind: 'component',
23277 language: 'ng-template',
23278 type: undefined,
23279 container: undefined,
23280 callable: false,
23281 nullable: false,
23282 public: true,
23283 definition: undefined,
23284 documentation: [],
23285 members() {
23286 return _this.scope;
23287 },
23288 signatures() {
23289 return [];
23290 },
23291 selectSignature(_types) {
23292 return undefined;
23293 },
23294 indexed(_argument) {
23295 return undefined;
23296 },
23297 typeArguments() {
23298 return undefined;
23299 },
23300 };
23301 }
23302 visitThisReceiver(_ast) {
23303 return this.visitImplicitReceiver(_ast);
23304 }
23305 visitInterpolation(ast) {
23306 // If we are producing diagnostics, visit the children.
23307 for (const expr of ast.expressions) {
23308 expr.visit(this);
23309 }
23310 return this.undefinedType;
23311 }
23312 visitKeyedRead(ast) {
23313 const targetType = this.getType(ast.obj);
23314 const keyType = this.getType(ast.key);
23315 const result = targetType.indexed(keyType, ast.key instanceof LiteralPrimitive ? ast.key.value : undefined);
23316 return result || this.anyType;
23317 }
23318 visitKeyedWrite(ast) {
23319 // The write of a type is the type of the value being written.
23320 return this.getType(ast.value);
23321 }
23322 visitLiteralArray(ast) {
23323 // A type literal is an array type of the union of the elements
23324 return this.query.getArrayType(this.query.getTypeUnion(...ast.expressions.map(element => this.getType(element))));
23325 }
23326 visitLiteralMap(ast) {
23327 // If we are producing diagnostics, visit the children
23328 for (const value of ast.values) {
23329 value.visit(this);
23330 }
23331 // TODO: Return a composite type.
23332 return this.anyType;
23333 }
23334 visitLiteralPrimitive(ast) {
23335 // The type of a literal primitive depends on the value of the literal.
23336 switch (ast.value) {
23337 case true:
23338 case false:
23339 return this.query.getBuiltinType(BuiltinType$1.Boolean);
23340 case null:
23341 return this.query.getBuiltinType(BuiltinType$1.Null);
23342 case undefined:
23343 return this.query.getBuiltinType(BuiltinType$1.Undefined);
23344 default:
23345 switch (typeof ast.value) {
23346 case 'string':
23347 return this.query.getBuiltinType(BuiltinType$1.String);
23348 case 'number':
23349 return this.query.getBuiltinType(BuiltinType$1.Number);
23350 default:
23351 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unrecognized_primitive, typeof ast.value));
23352 return this.anyType;
23353 }
23354 }
23355 }
23356 visitMethodCall(ast) {
23357 return this.resolveMethodCall(this.getType(ast.receiver), ast);
23358 }
23359 visitPipe(ast) {
23360 // The type of a pipe node is the return type of the pipe's transform method. The table returned
23361 // by getPipes() is expected to contain symbols with the corresponding transform method type.
23362 const pipe = this.query.getPipes().get(ast.name);
23363 if (!pipe) {
23364 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.no_pipe_found, ast.name));
23365 return this.anyType;
23366 }
23367 const expType = this.getType(ast.exp);
23368 const signature = pipe.selectSignature([expType].concat(ast.args.map(arg => this.getType(arg))));
23369 if (!signature) {
23370 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unable_to_resolve_signature, ast.name));
23371 return this.anyType;
23372 }
23373 return signature.result;
23374 }
23375 visitPrefixNot(ast) {
23376 // If we are producing diagnostics, visit the children
23377 ast.expression.visit(this);
23378 // The type of a prefix ! is always boolean.
23379 return this.query.getBuiltinType(BuiltinType$1.Boolean);
23380 }
23381 visitNonNullAssert(ast) {
23382 const expressionType = this.getType(ast.expression);
23383 return this.query.getNonNullableType(expressionType);
23384 }
23385 visitPropertyRead(ast) {
23386 return this.resolvePropertyRead(this.getType(ast.receiver), ast);
23387 }
23388 visitPropertyWrite(ast) {
23389 // The type of a write is the type of the value being written.
23390 return this.getType(ast.value);
23391 }
23392 visitQuote(_ast) {
23393 // The type of a quoted expression is any.
23394 return this.query.getBuiltinType(BuiltinType$1.Any);
23395 }
23396 visitSafeMethodCall(ast) {
23397 return this.resolveMethodCall(this.query.getNonNullableType(this.getType(ast.receiver)), ast);
23398 }
23399 visitSafePropertyRead(ast) {
23400 return this.resolvePropertyRead(this.query.getNonNullableType(this.getType(ast.receiver)), ast);
23401 }
23402 /**
23403 * Gets the source of an expession AST.
23404 * The AST's sourceSpan is relative to the start of the template source code, which is contained
23405 * at this.source.
23406 */
23407 sourceOf(ast) {
23408 return this.source.substring(ast.sourceSpan.start, ast.sourceSpan.end);
23409 }
23410 get anyType() {
23411 let result = this._anyType;
23412 if (!result) {
23413 result = this._anyType = this.query.getBuiltinType(BuiltinType$1.Any);
23414 }
23415 return result;
23416 }
23417 get undefinedType() {
23418 let result = this._undefinedType;
23419 if (!result) {
23420 result = this._undefinedType = this.query.getBuiltinType(BuiltinType$1.Undefined);
23421 }
23422 return result;
23423 }
23424 resolveMethodCall(receiverType, ast) {
23425 if (this.isAny(receiverType)) {
23426 return this.anyType;
23427 }
23428 const methodType = this.resolvePropertyRead(receiverType, ast);
23429 if (!methodType) {
23430 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.could_not_resolve_type, ast.name));
23431 return this.anyType;
23432 }
23433 if (this.isAny(methodType)) {
23434 return this.anyType;
23435 }
23436 if (!methodType.callable) {
23437 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_not_callable, ast.name));
23438 return this.anyType;
23439 }
23440 const signature = methodType.selectSignature(ast.args.map(arg => this.getType(arg)));
23441 if (!signature) {
23442 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.unable_to_resolve_signature, ast.name));
23443 return this.anyType;
23444 }
23445 return signature.result;
23446 }
23447 resolvePropertyRead(receiverType, ast) {
23448 if (this.isAny(receiverType)) {
23449 return this.anyType;
23450 }
23451 // The type of a property read is the seelcted member's type.
23452 const member = receiverType.members().get(ast.name);
23453 if (!member) {
23454 if (receiverType.name === '$implicit') {
23455 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_not_defined_in_app_context, ast.name));
23456 }
23457 else if (receiverType.nullable && ast.receiver instanceof PropertyRead) {
23458 const receiver = ast.receiver.name;
23459 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_possibly_undefined, receiver, `${receiver}?.${ast.name}`, `${receiver}!.${ast.name}`));
23460 }
23461 else {
23462 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_not_defined_on_receiver, ast.name, receiverType.name));
23463 }
23464 return this.anyType;
23465 }
23466 if (!member.public) {
23467 const container = receiverType.name === '$implicit' ? 'the component' : `'${receiverType.name}'`;
23468 this.diagnostics.push(createDiagnostic(refinedSpan(ast), Diagnostic.identifier_is_private, ast.name, container));
23469 }
23470 return member.type;
23471 }
23472 isAny(symbol) {
23473 return !symbol || this.query.getTypeKind(symbol) === BuiltinType$1.Any ||
23474 (!!symbol.type && this.isAny(symbol.type));
23475 }
23476 }
23477 function refinedSpan(ast) {
23478 // nameSpan is an absolute span, but the spans returned by the expression visitor are expected to
23479 // be relative to the start of the expression.
23480 // TODO: migrate to only using absolute spans
23481 const absoluteOffset = ast.sourceSpan.start - ast.span.start;
23482 if (ast instanceof ASTWithName) {
23483 return offsetSpan(ast.nameSpan, -absoluteOffset);
23484 }
23485 return offsetSpan(ast.sourceSpan, -absoluteOffset);
23486 }
23487
23488 /**
23489 * @license
23490 * Copyright Google LLC All Rights Reserved.
23491 *
23492 * Use of this source code is governed by an MIT-style license that can be
23493 * found in the LICENSE file at https://angular.io/license
23494 */
23495 function getTemplateExpressionDiagnostics(info) {
23496 const visitor = new ExpressionDiagnosticsVisitor(info, (path) => getExpressionScope(info, path));
23497 templateVisitAll(visitor, info.templateAst);
23498 return visitor.diagnostics;
23499 }
23500 function getReferences(info) {
23501 const result = [];
23502 function processReferences(references) {
23503 for (const reference of references) {
23504 let type = undefined;
23505 if (reference.value) {
23506 type = info.query.getTypeSymbol(tokenReference(reference.value));
23507 }
23508 result.push({
23509 name: reference.name,
23510 kind: 'reference',
23511 type: type || info.query.getBuiltinType(BuiltinType$1.Any),
23512 get definition() {
23513 return getDefinitionOf(info, reference);
23514 }
23515 });
23516 }
23517 }
23518 const visitor = new class extends RecursiveTemplateAstVisitor {
23519 visitEmbeddedTemplate(ast, context) {
23520 super.visitEmbeddedTemplate(ast, context);
23521 processReferences(ast.references);
23522 }
23523 visitElement(ast, context) {
23524 super.visitElement(ast, context);
23525 processReferences(ast.references);
23526 }
23527 };
23528 templateVisitAll(visitor, info.templateAst);
23529 return result;
23530 }
23531 function getDefinitionOf(info, ast) {
23532 if (info.fileName) {
23533 const templateOffset = info.offset;
23534 return [{
23535 fileName: info.fileName,
23536 span: {
23537 start: ast.sourceSpan.start.offset + templateOffset,
23538 end: ast.sourceSpan.end.offset + templateOffset
23539 }
23540 }];
23541 }
23542 }
23543 /**
23544 * Resolve all variable declarations in a template by traversing the specified
23545 * `path`.
23546 * @param info
23547 * @param path template AST path
23548 */
23549 function getVarDeclarations(info, path) {
23550 const results = [];
23551 for (let current = path.head; current; current = path.childOf(current)) {
23552 if (!(current instanceof EmbeddedTemplateAst)) {
23553 continue;
23554 }
23555 for (const variable of current.variables) {
23556 let symbol = getVariableTypeFromDirectiveContext(variable.value, info.query, current);
23557 const kind = info.query.getTypeKind(symbol);
23558 if (kind === BuiltinType$1.Any || kind === BuiltinType$1.Unbound) {
23559 // For special cases such as ngFor and ngIf, the any type is not very useful.
23560 // We can do better by resolving the binding value.
23561 const symbolsInScope = info.query.mergeSymbolTable([
23562 info.members,
23563 // Since we are traversing the AST path from head to tail, any variables
23564 // that have been declared so far are also in scope.
23565 info.query.createSymbolTable(results),
23566 ]);
23567 symbol = refinedVariableType(variable.value, symbolsInScope, info, current);
23568 }
23569 results.push({
23570 name: variable.name,
23571 kind: 'variable',
23572 type: symbol,
23573 get definition() {
23574 return getDefinitionOf(info, variable);
23575 },
23576 });
23577 }
23578 }
23579 return results;
23580 }
23581 /**
23582 * Resolve the type for the variable in `templateElement` by finding the structural
23583 * directive which has the context member. Returns any when not found.
23584 * @param value variable value name
23585 * @param query type symbol query
23586 * @param templateElement
23587 */
23588 function getVariableTypeFromDirectiveContext(value, query, templateElement) {
23589 for (const { directive } of templateElement.directives) {
23590 const context = query.getTemplateContext(directive.type.reference);
23591 if (context) {
23592 const member = context.get(value);
23593 if (member && member.type) {
23594 return member.type;
23595 }
23596 }
23597 }
23598 return query.getBuiltinType(BuiltinType$1.Any);
23599 }
23600 /**
23601 * Resolve a more specific type for the variable in `templateElement` by inspecting
23602 * all variables that are in scope in the `mergedTable`. This function is a special
23603 * case for `ngFor` and `ngIf`. If resolution fails, return the `any` type.
23604 * @param value variable value name
23605 * @param mergedTable symbol table for all variables in scope
23606 * @param info available template information
23607 * @param templateElement
23608 */
23609 function refinedVariableType(value, mergedTable, info, templateElement) {
23610 if (value === '$implicit') {
23611 // Special case: ngFor directive
23612 const ngForDirective = templateElement.directives.find(d => {
23613 const name = identifierName(d.directive.type);
23614 return name == 'NgFor' || name == 'NgForOf';
23615 });
23616 if (ngForDirective) {
23617 const ngForOfBinding = ngForDirective.inputs.find(i => i.directiveName == 'ngForOf');
23618 if (ngForOfBinding) {
23619 // Check if there is a known type for the ngFor binding.
23620 const bindingType = new AstType(mergedTable, info.query, {}, info.source).getType(ngForOfBinding.value);
23621 if (bindingType) {
23622 const result = info.query.getElementType(bindingType);
23623 if (result) {
23624 return result;
23625 }
23626 }
23627 }
23628 }
23629 }
23630 if (value === 'ngIf' || value === '$implicit') {
23631 const ngIfDirective = templateElement.directives.find(d => identifierName(d.directive.type) === 'NgIf');
23632 if (ngIfDirective) {
23633 // Special case: ngIf directive. The NgIf structural directive owns a template context with
23634 // "$implicit" and "ngIf" members. These properties are typed as generics. Until the language
23635 // service uses an Ivy and TypecheckBlock backend, we cannot bind these values to a concrete
23636 // type without manual inference. To get the concrete type, look up the type of the "ngIf"
23637 // import on the NgIf directive bound to the template.
23638 //
23639 // See @angular/common/ng_if.ts for more information.
23640 const ngIfBinding = ngIfDirective.inputs.find(i => i.directiveName === 'ngIf');
23641 if (ngIfBinding) {
23642 // Check if there is a known type bound to the ngIf input.
23643 const bindingType = new AstType(mergedTable, info.query, {}, info.source).getType(ngIfBinding.value);
23644 if (bindingType) {
23645 return bindingType;
23646 }
23647 }
23648 }
23649 }
23650 // We can't do better, return any
23651 return info.query.getBuiltinType(BuiltinType$1.Any);
23652 }
23653 function getEventDeclaration(info, path) {
23654 const event = path.tail;
23655 if (!(event instanceof BoundEventAst)) {
23656 // No event available in this context.
23657 return;
23658 }
23659 const genericEvent = {
23660 name: '$event',
23661 kind: 'variable',
23662 type: info.query.getBuiltinType(BuiltinType$1.Any),
23663 };
23664 const outputSymbol = findOutputBinding(event, path, info.query);
23665 if (!outputSymbol) {
23666 // The `$event` variable doesn't belong to an output, so its type can't be refined.
23667 // TODO: type `$event` variables in bindings to DOM events.
23668 return genericEvent;
23669 }
23670 // The raw event type is wrapped in a generic, like EventEmitter<T> or Observable<T>.
23671 const ta = outputSymbol.typeArguments();
23672 if (!ta || ta.length !== 1)
23673 return genericEvent;
23674 const eventType = ta[0];
23675 return Object.assign(Object.assign({}, genericEvent), { type: eventType });
23676 }
23677 /**
23678 * Returns the symbols available in a particular scope of a template.
23679 * @param info parsed template information
23680 * @param path path of template nodes narrowing to the context the expression scope should be
23681 * derived for.
23682 */
23683 function getExpressionScope(info, path) {
23684 let result = info.members;
23685 const references = getReferences(info);
23686 const variables = getVarDeclarations(info, path);
23687 const event = getEventDeclaration(info, path);
23688 if (references.length || variables.length || event) {
23689 const referenceTable = info.query.createSymbolTable(references);
23690 const variableTable = info.query.createSymbolTable(variables);
23691 const eventsTable = info.query.createSymbolTable(event ? [event] : []);
23692 result = info.query.mergeSymbolTable([result, referenceTable, variableTable, eventsTable]);
23693 }
23694 return result;
23695 }
23696 class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor {
23697 constructor(info, getExpressionScope) {
23698 super();
23699 this.info = info;
23700 this.getExpressionScope = getExpressionScope;
23701 this.diagnostics = [];
23702 this.path = new AstPath([]);
23703 }
23704 visitDirective(ast, context) {
23705 // Override the default child visitor to ignore the host properties of a directive.
23706 if (ast.inputs && ast.inputs.length) {
23707 templateVisitAll(this, ast.inputs, context);
23708 }
23709 }
23710 visitBoundText(ast) {
23711 this.push(ast);
23712 this.diagnoseExpression(ast.value, ast.sourceSpan.start.offset, false);
23713 this.pop();
23714 }
23715 visitDirectiveProperty(ast) {
23716 this.push(ast);
23717 this.diagnoseExpression(ast.value, this.attributeValueLocation(ast), false);
23718 this.pop();
23719 }
23720 visitElementProperty(ast) {
23721 this.push(ast);
23722 this.diagnoseExpression(ast.value, this.attributeValueLocation(ast), false);
23723 this.pop();
23724 }
23725 visitEvent(ast) {
23726 this.push(ast);
23727 this.diagnoseExpression(ast.handler, this.attributeValueLocation(ast), true);
23728 this.pop();
23729 }
23730 visitVariable(ast) {
23731 const directive = this.directiveSummary;
23732 if (directive && ast.value) {
23733 const context = this.info.query.getTemplateContext(directive.type.reference);
23734 if (context && !context.has(ast.value)) {
23735 const missingMember = ast.value === '$implicit' ? 'an implicit value' : `a member called '${ast.value}'`;
23736 const span = this.absSpan(spanOf$1(ast.sourceSpan));
23737 this.diagnostics.push(createDiagnostic(span, Diagnostic.template_context_missing_member, directive.type.reference.name, missingMember));
23738 }
23739 }
23740 }
23741 visitElement(ast, context) {
23742 this.push(ast);
23743 super.visitElement(ast, context);
23744 this.pop();
23745 }
23746 visitEmbeddedTemplate(ast, context) {
23747 const previousDirectiveSummary = this.directiveSummary;
23748 this.push(ast);
23749 // Find directive that references this template
23750 this.directiveSummary =
23751 ast.directives.map(d => d.directive).find(d => hasTemplateReference(d.type));
23752 // Process children
23753 super.visitEmbeddedTemplate(ast, context);
23754 this.pop();
23755 this.directiveSummary = previousDirectiveSummary;
23756 }
23757 attributeValueLocation(ast) {
23758 const path = getPathToNodeAtPosition(this.info.htmlAst, ast.sourceSpan.start.offset);
23759 const last = path.tail;
23760 if (last instanceof Attribute && last.valueSpan) {
23761 return last.valueSpan.start.offset;
23762 }
23763 return ast.sourceSpan.start.offset;
23764 }
23765 diagnoseExpression(ast, offset, inEvent) {
23766 const scope = this.getExpressionScope(this.path, inEvent);
23767 const analyzer = new AstType(scope, this.info.query, { inEvent }, this.info.source);
23768 for (const diagnostic of analyzer.getDiagnostics(ast)) {
23769 diagnostic.span = this.absSpan(diagnostic.span, offset);
23770 this.diagnostics.push(diagnostic);
23771 }
23772 }
23773 push(ast) {
23774 this.path.push(ast);
23775 }
23776 pop() {
23777 this.path.pop();
23778 }
23779 absSpan(span, additionalOffset = 0) {
23780 return {
23781 start: span.start + this.info.offset + additionalOffset,
23782 end: span.end + this.info.offset + additionalOffset,
23783 };
23784 }
23785 }
23786 function hasTemplateReference(type) {
23787 if (type.diDeps) {
23788 for (let diDep of type.diDeps) {
23789 if (diDep.token && diDep.token.identifier &&
23790 identifierName(diDep.token.identifier) == 'TemplateRef')
23791 return true;
23792 }
23793 }
23794 return false;
23795 }
23796 function spanOf$1(sourceSpan) {
23797 return { start: sourceSpan.start.offset, end: sourceSpan.end.offset };
23798 }
23799
23800 /**
23801 * @license
23802 * Copyright Google LLC All Rights Reserved.
23803 *
23804 * Use of this source code is governed by an MIT-style license that can be
23805 * found in the LICENSE file at https://angular.io/license
23806 */
23807 /**
23808 * The type of Angular directive. Used for QuickInfo in template.
23809 */
23810 var DirectiveKind;
23811 (function (DirectiveKind) {
23812 DirectiveKind["COMPONENT"] = "component";
23813 DirectiveKind["DIRECTIVE"] = "directive";
23814 DirectiveKind["EVENT"] = "event";
23815 })(DirectiveKind || (DirectiveKind = {}));
23816 /**
23817 * ScriptElementKind for completion.
23818 */
23819 var CompletionKind;
23820 (function (CompletionKind) {
23821 CompletionKind["ANGULAR_ELEMENT"] = "angular element";
23822 CompletionKind["ATTRIBUTE"] = "attribute";
23823 CompletionKind["COMPONENT"] = "component";
23824 CompletionKind["ELEMENT"] = "element";
23825 CompletionKind["ENTITY"] = "entity";
23826 CompletionKind["HTML_ATTRIBUTE"] = "html attribute";
23827 CompletionKind["HTML_ELEMENT"] = "html element";
23828 CompletionKind["KEY"] = "key";
23829 CompletionKind["METHOD"] = "method";
23830 CompletionKind["PIPE"] = "pipe";
23831 CompletionKind["PROPERTY"] = "property";
23832 CompletionKind["REFERENCE"] = "reference";
23833 CompletionKind["TYPE"] = "type";
23834 CompletionKind["VARIABLE"] = "variable";
23835 })(CompletionKind || (CompletionKind = {}));
23836
23837 /**
23838 * @license
23839 * Copyright Google LLC All Rights Reserved.
23840 *
23841 * Use of this source code is governed by an MIT-style license that can be
23842 * found in the LICENSE file at https://angular.io/license
23843 */
23844 function findAstAt(ast, position, excludeEmpty = false) {
23845 const path = [];
23846 const visitor = new class extends RecursiveAstVisitor {
23847 visit(ast) {
23848 if ((!excludeEmpty || ast.sourceSpan.start < ast.sourceSpan.end) &&
23849 inSpan(position, ast.sourceSpan)) {
23850 const isNotNarrower = path.length && !isNarrower(ast.span, path[path.length - 1].span);
23851 if (!isNotNarrower) {
23852 path.push(ast);
23853 }
23854 ast.visit(this);
23855 }
23856 }
23857 };
23858 // We never care about the ASTWithSource node and its visit() method calls its ast's visit so
23859 // the visit() method above would never see it.
23860 if (ast instanceof ASTWithSource) {
23861 ast = ast.ast;
23862 }
23863 // `Interpolation` is useless here except the `expressions` of it.
23864 if (ast instanceof Interpolation) {
23865 ast = ast.expressions.filter((_ast) => inSpan(position, _ast.sourceSpan))[0];
23866 }
23867 if (ast) {
23868 visitor.visit(ast);
23869 }
23870 return new AstPath(path, position);
23871 }
23872 function getExpressionCompletions(scope, ast, position, templateInfo) {
23873 const path = findAstAt(ast, position);
23874 if (path.empty)
23875 return undefined;
23876 const tail = path.tail;
23877 let result = scope;
23878 function getType(ast) {
23879 return new AstType(scope, templateInfo.query, {}, templateInfo.source).getType(ast);
23880 }
23881 // If the completion request is in a not in a pipe or property access then the global scope
23882 // (that is the scope of the implicit receiver) is the right scope as the user is typing the
23883 // beginning of an expression.
23884 tail.visit({
23885 visitUnary(_ast) { },
23886 visitBinary(_ast) { },
23887 visitChain(_ast) { },
23888 visitConditional(_ast) { },
23889 visitFunctionCall(_ast) { },
23890 visitImplicitReceiver(_ast) { },
23891 visitThisReceiver(_ast) { },
23892 visitInterpolation(_ast) {
23893 result = undefined;
23894 },
23895 visitKeyedRead(_ast) { },
23896 visitKeyedWrite(_ast) { },
23897 visitLiteralArray(_ast) { },
23898 visitLiteralMap(_ast) { },
23899 visitLiteralPrimitive(ast) {
23900 // The type `LiteralPrimitive` include the `ERROR`, and it's wrapped as `string`.
23901 // packages/compiler/src/template_parser/binding_parser.ts#L308
23902 // So exclude the `ERROR` here.
23903 if (typeof ast.value === 'string' &&
23904 ast.value ===
23905 templateInfo.source.slice(ast.sourceSpan.start + 1, ast.sourceSpan.end - 1)) {
23906 result = undefined;
23907 }
23908 },
23909 visitMethodCall(_ast) { },
23910 visitPipe(ast) {
23911 if (position >= ast.exp.span.end &&
23912 (!ast.args || !ast.args.length || position < ast.args[0].span.start)) {
23913 // We are in a position a pipe name is expected.
23914 result = templateInfo.query.getPipes();
23915 }
23916 },
23917 visitPrefixNot(_ast) { },
23918 visitNonNullAssert(_ast) { },
23919 visitPropertyRead(ast) {
23920 const receiverType = getType(ast.receiver);
23921 result = receiverType ? receiverType.members() : scope;
23922 },
23923 visitPropertyWrite(ast) {
23924 const receiverType = getType(ast.receiver);
23925 result = receiverType ? receiverType.members() : scope;
23926 },
23927 visitQuote(_ast) {
23928 // For a quote, return the members of any (if there are any).
23929 result = templateInfo.query.getBuiltinType(BuiltinType$1.Any).members();
23930 },
23931 visitSafeMethodCall(ast) {
23932 const receiverType = getType(ast.receiver);
23933 result = receiverType ? receiverType.members() : scope;
23934 },
23935 visitSafePropertyRead(ast) {
23936 const receiverType = getType(ast.receiver);
23937 result = receiverType ? receiverType.members() : scope;
23938 },
23939 });
23940 return result && result.values();
23941 }
23942 /**
23943 * Retrieves the expression symbol at a particular position in a template.
23944 *
23945 * @param scope symbols in scope of the template
23946 * @param ast template AST
23947 * @param position absolute location in template to retrieve symbol at
23948 * @param query type symbol query for the template scope
23949 */
23950 function getExpressionSymbol(scope, ast, position, templateInfo) {
23951 const path = findAstAt(ast, position, /* excludeEmpty */ true);
23952 if (path.empty)
23953 return undefined;
23954 const tail = path.tail;
23955 function getType(ast) {
23956 return new AstType(scope, templateInfo.query, {}, templateInfo.source).getType(ast);
23957 }
23958 function spanFromName(ast) {
23959 // `nameSpan` is an absolute span, but the span expected by the result of this method is
23960 // relative to the start of the expression.
23961 // TODO(ayazhafiz): migrate to only using absolute spans
23962 const offset = ast.sourceSpan.start - ast.span.start;
23963 return {
23964 start: ast.nameSpan.start - offset,
23965 end: ast.nameSpan.end - offset,
23966 };
23967 }
23968 let symbol = undefined;
23969 let span = undefined;
23970 // If the completion request is in a not in a pipe or property access then the global scope
23971 // (that is the scope of the implicit receiver) is the right scope as the user is typing the
23972 // beginning of an expression.
23973 tail.visit({
23974 visitUnary(_ast) { },
23975 visitBinary(_ast) { },
23976 visitChain(_ast) { },
23977 visitConditional(_ast) { },
23978 visitFunctionCall(_ast) { },
23979 visitImplicitReceiver(_ast) { },
23980 visitThisReceiver(_ast) { },
23981 visitInterpolation(_ast) { },
23982 visitKeyedRead(_ast) { },
23983 visitKeyedWrite(_ast) { },
23984 visitLiteralArray(_ast) { },
23985 visitLiteralMap(_ast) { },
23986 visitLiteralPrimitive(_ast) { },
23987 visitMethodCall(ast) {
23988 const receiverType = getType(ast.receiver);
23989 symbol = receiverType && receiverType.members().get(ast.name);
23990 span = spanFromName(ast);
23991 },
23992 visitPipe(ast) {
23993 if (inSpan(position, ast.nameSpan, /* exclusive */ true)) {
23994 // We are in a position a pipe name is expected.
23995 const pipes = templateInfo.query.getPipes();
23996 symbol = pipes.get(ast.name);
23997 span = spanFromName(ast);
23998 }
23999 },
24000 visitPrefixNot(_ast) { },
24001 visitNonNullAssert(_ast) { },
24002 visitPropertyRead(ast) {
24003 const receiverType = getType(ast.receiver);
24004 symbol = receiverType && receiverType.members().get(ast.name);
24005 span = spanFromName(ast);
24006 },
24007 visitPropertyWrite(ast) {
24008 const receiverType = getType(ast.receiver);
24009 symbol = receiverType && receiverType.members().get(ast.name);
24010 span = spanFromName(ast);
24011 },
24012 visitQuote(_ast) { },
24013 visitSafeMethodCall(ast) {
24014 const receiverType = getType(ast.receiver);
24015 symbol = receiverType && receiverType.members().get(ast.name);
24016 span = spanFromName(ast);
24017 },
24018 visitSafePropertyRead(ast) {
24019 const receiverType = getType(ast.receiver);
24020 symbol = receiverType && receiverType.members().get(ast.name);
24021 span = spanFromName(ast);
24022 },
24023 });
24024 if (symbol && span) {
24025 return { symbol, span };
24026 }
24027 }
24028
24029 /**
24030 * @license
24031 * Copyright Google LLC All Rights Reserved.
24032 *
24033 * Use of this source code is governed by an MIT-style license that can be
24034 * found in the LICENSE file at https://angular.io/license
24035 */
24036 const values = [
24037 'ID',
24038 'CDATA',
24039 'NAME',
24040 ['ltr', 'rtl'],
24041 ['rect', 'circle', 'poly', 'default'],
24042 'NUMBER',
24043 ['nohref'],
24044 ['ismap'],
24045 ['declare'],
24046 ['DATA', 'REF', 'OBJECT'],
24047 ['GET', 'POST'],
24048 'IDREF',
24049 ['TEXT', 'PASSWORD', 'CHECKBOX', 'RADIO', 'SUBMIT', 'RESET', 'FILE', 'HIDDEN', 'IMAGE', 'BUTTON'],
24050 ['checked'],
24051 ['disabled'],
24052 ['readonly'],
24053 ['multiple'],
24054 ['selected'],
24055 ['button', 'submit', 'reset'],
24056 ['void', 'above', 'below', 'hsides', 'lhs', 'rhs', 'vsides', 'box', 'border'],
24057 ['none', 'groups', 'rows', 'cols', 'all'],
24058 ['left', 'center', 'right', 'justify', 'char'],
24059 ['top', 'middle', 'bottom', 'baseline'],
24060 'IDREFS',
24061 ['row', 'col', 'rowgroup', 'colgroup'],
24062 ['defer']
24063 ];
24064 const groups = [
24065 { id: 0 },
24066 {
24067 onclick: 1,
24068 ondblclick: 1,
24069 onmousedown: 1,
24070 onmouseup: 1,
24071 onmouseover: 1,
24072 onmousemove: 1,
24073 onmouseout: 1,
24074 onkeypress: 1,
24075 onkeydown: 1,
24076 onkeyup: 1
24077 },
24078 { lang: 2, dir: 3 },
24079 { onload: 1, onunload: 1 },
24080 { name: 1 },
24081 { href: 1 },
24082 { type: 1 },
24083 { alt: 1 },
24084 { tabindex: 5 },
24085 { media: 1 },
24086 { nohref: 6 },
24087 { usemap: 1 },
24088 { src: 1 },
24089 { onfocus: 1, onblur: 1 },
24090 { charset: 1 },
24091 { declare: 8, classid: 1, codebase: 1, data: 1, codetype: 1, archive: 1, standby: 1 },
24092 { title: 1 },
24093 { value: 1 },
24094 { cite: 1 },
24095 { datetime: 1 },
24096 { accept: 1 },
24097 { shape: 4, coords: 1 },
24098 { for: 11
24099 },
24100 { action: 1, method: 10, enctype: 1, onsubmit: 1, onreset: 1, 'accept-charset': 1 },
24101 { valuetype: 9 },
24102 { longdesc: 1 },
24103 { width: 1 },
24104 { disabled: 14 },
24105 { readonly: 15, onselect: 1 },
24106 { accesskey: 1 },
24107 { size: 5, multiple: 16 },
24108 { onchange: 1 },
24109 { label: 1 },
24110 { selected: 17 },
24111 { type: 12, checked: 13, size: 1, maxlength: 5 },
24112 { rows: 5, cols: 5 },
24113 { type: 18 },
24114 { height: 1 },
24115 { summary: 1, border: 1, frame: 19, rules: 20, cellspacing: 1, cellpadding: 1, datapagesize: 1 },
24116 { align: 21, char: 1, charoff: 1, valign: 22 },
24117 { span: 5 },
24118 { abbr: 1, axis: 1, headers: 23, scope: 24, rowspan: 5, colspan: 5 },
24119 { profile: 1 },
24120 { 'http-equiv': 2, name: 2, content: 1, scheme: 1 },
24121 { class: 1, style: 1 },
24122 { hreflang: 2, rel: 1, rev: 1 },
24123 { ismap: 7 },
24124 {
24125 defer: 25, event: 1, for: 1
24126 }
24127 ];
24128 const elements = {
24129 TT: [0, 1, 2, 16, 44],
24130 I: [0, 1, 2, 16, 44],
24131 B: [0, 1, 2, 16, 44],
24132 BIG: [0, 1, 2, 16, 44],
24133 SMALL: [0, 1, 2, 16, 44],
24134 EM: [0, 1, 2, 16, 44],
24135 STRONG: [0, 1, 2, 16, 44],
24136 DFN: [0, 1, 2, 16, 44],
24137 CODE: [0, 1, 2, 16, 44],
24138 SAMP: [0, 1, 2, 16, 44],
24139 KBD: [0, 1, 2, 16, 44],
24140 VAR: [0, 1, 2, 16, 44],
24141 CITE: [0, 1, 2, 16, 44],
24142 ABBR: [0, 1, 2, 16, 44],
24143 ACRONYM: [0, 1, 2, 16, 44],
24144 SUB: [0, 1, 2, 16, 44],
24145 SUP: [0, 1, 2, 16, 44],
24146 SPAN: [0, 1, 2, 16, 44],
24147 BDO: [0, 2, 16, 44],
24148 BR: [0, 16, 44],
24149 BODY: [0, 1, 2, 3, 16, 44],
24150 ADDRESS: [0, 1, 2, 16, 44],
24151 DIV: [0, 1, 2, 16, 44],
24152 A: [0, 1, 2, 4, 5, 6, 8, 13, 14, 16, 21, 29, 44, 45],
24153 MAP: [0, 1, 2, 4, 16, 44],
24154 AREA: [0, 1, 2, 5, 7, 8, 10, 13, 16, 21, 29, 44],
24155 LINK: [0, 1, 2, 5, 6, 9, 14, 16, 44, 45],
24156 IMG: [0, 1, 2, 4, 7, 11, 12, 16, 25, 26, 37, 44, 46],
24157 OBJECT: [0, 1, 2, 4, 6, 8, 11, 15, 16, 26, 37, 44],
24158 PARAM: [0, 4, 6, 17, 24],
24159 HR: [0, 1, 2, 16, 44],
24160 P: [0, 1, 2, 16, 44],
24161 H1: [0, 1, 2, 16, 44],
24162 H2: [0, 1, 2, 16, 44],
24163 H3: [0, 1, 2, 16, 44],
24164 H4: [0, 1, 2, 16, 44],
24165 H5: [0, 1, 2, 16, 44],
24166 H6: [0, 1, 2, 16, 44],
24167 PRE: [0, 1, 2, 16, 44],
24168 Q: [0, 1, 2, 16, 18, 44],
24169 BLOCKQUOTE: [0, 1, 2, 16, 18, 44],
24170 INS: [0, 1, 2, 16, 18, 19, 44],
24171 DEL: [0, 1, 2, 16, 18, 19, 44],
24172 DL: [0, 1, 2, 16, 44],
24173 DT: [0, 1, 2, 16, 44],
24174 DD: [0, 1, 2, 16, 44],
24175 OL: [0, 1, 2, 16, 44],
24176 UL: [0, 1, 2, 16, 44],
24177 LI: [0, 1, 2, 16, 44],
24178 FORM: [0, 1, 2, 4, 16, 20, 23, 44],
24179 LABEL: [0, 1, 2, 13, 16, 22, 29, 44],
24180 INPUT: [0, 1, 2, 4, 7, 8, 11, 12, 13, 16, 17, 20, 27, 28, 29, 31, 34, 44, 46],
24181 SELECT: [0, 1, 2, 4, 8, 13, 16, 27, 30, 31, 44],
24182 OPTGROUP: [0, 1, 2, 16, 27, 32, 44],
24183 OPTION: [0, 1, 2, 16, 17, 27, 32, 33, 44],
24184 TEXTAREA: [0, 1, 2, 4, 8, 13, 16, 27, 28, 29, 31, 35, 44],
24185 FIELDSET: [0, 1, 2, 16, 44],
24186 LEGEND: [0, 1, 2, 16, 29, 44],
24187 BUTTON: [0, 1, 2, 4, 8, 13, 16, 17, 27, 29, 36, 44],
24188 TABLE: [0, 1, 2, 16, 26, 38, 44],
24189 CAPTION: [0, 1, 2, 16, 44],
24190 COLGROUP: [0, 1, 2, 16, 26, 39, 40, 44],
24191 COL: [0, 1, 2, 16, 26, 39, 40, 44],
24192 THEAD: [0, 1, 2, 16, 39, 44],
24193 TBODY: [0, 1, 2, 16, 39, 44],
24194 TFOOT: [0, 1, 2, 16, 39, 44],
24195 TR: [0, 1, 2, 16, 39, 44],
24196 TH: [0, 1, 2, 16, 39, 41, 44],
24197 TD: [0, 1, 2, 16, 39, 41, 44],
24198 HEAD: [2, 42],
24199 TITLE: [2],
24200 BASE: [5],
24201 META: [2, 43],
24202 STYLE: [2, 6, 9, 16],
24203 SCRIPT: [6, 12, 14, 47],
24204 NOSCRIPT: [0, 1, 2, 16, 44],
24205 HTML: [2]
24206 };
24207 const defaultAttributes = [0, 1, 2, 4];
24208 function elementNames() {
24209 return Object.keys(elements).sort().map(v => v.toLowerCase());
24210 }
24211 function compose(indexes) {
24212 const result = {};
24213 if (indexes) {
24214 for (let index of indexes) {
24215 const group = groups[index];
24216 for (let name in group)
24217 if (group.hasOwnProperty(name))
24218 result[name] = values[group[name]];
24219 }
24220 }
24221 return result;
24222 }
24223 function attributeNames(element) {
24224 return Object.keys(compose(elements[element.toUpperCase()] || defaultAttributes)).sort();
24225 }
24226 // This section is describes the DOM property surface of a DOM element and is derivgulp formated
24227 // from
24228 // from the SCHEMA strings from the security context information. SCHEMA is copied here because
24229 // it would be an unnecessary risk to allow this array to be imported from the security context
24230 // schema registry.
24231 const SCHEMA$1 = [
24232 '[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop,slot' +
24233 /* added manually to avoid breaking changes */
24234 ',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored',
24235 '[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',
24236 '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',
24237 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume',
24238 ':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',
24239 ':svg:graphics^:svg:|',
24240 ':svg:animation^:svg:|*begin,*end,*repeat',
24241 ':svg:geometry^:svg:|',
24242 ':svg:componentTransferFunction^:svg:|',
24243 ':svg:gradient^:svg:|',
24244 ':svg:textContent^:svg:graphics|',
24245 ':svg:textPositioning^:svg:textContent|',
24246 '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',
24247 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username',
24248 'audio^media|',
24249 'br^[HTMLElement]|clear',
24250 'base^[HTMLElement]|href,target',
24251 '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',
24252 'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
24253 'canvas^[HTMLElement]|#height,#width',
24254 'content^[HTMLElement]|select',
24255 'dl^[HTMLElement]|!compact',
24256 'datalist^[HTMLElement]|',
24257 'details^[HTMLElement]|!open',
24258 'dialog^[HTMLElement]|!open,returnValue',
24259 'dir^[HTMLElement]|!compact',
24260 'div^[HTMLElement]|align',
24261 'embed^[HTMLElement]|align,height,name,src,type,width',
24262 'fieldset^[HTMLElement]|!disabled,name',
24263 'font^[HTMLElement]|color,face,size',
24264 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
24265 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
24266 'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
24267 'hr^[HTMLElement]|align,color,!noShade,size,width',
24268 'head^[HTMLElement]|',
24269 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align',
24270 'html^[HTMLElement]|version',
24271 'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width',
24272 'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width',
24273 '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',
24274 'li^[HTMLElement]|type,#value',
24275 'label^[HTMLElement]|htmlFor',
24276 'legend^[HTMLElement]|align',
24277 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type',
24278 'map^[HTMLElement]|name',
24279 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
24280 'menu^[HTMLElement]|!compact',
24281 'meta^[HTMLElement]|content,httpEquiv,name,scheme',
24282 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value',
24283 'ins,del^[HTMLElement]|cite,dateTime',
24284 'ol^[HTMLElement]|!compact,!reversed,#start,type',
24285 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
24286 'optgroup^[HTMLElement]|!disabled,label',
24287 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value',
24288 'output^[HTMLElement]|defaultValue,%htmlFor,name,value',
24289 'p^[HTMLElement]|align',
24290 'param^[HTMLElement]|name,type,value,valueType',
24291 'picture^[HTMLElement]|',
24292 'pre^[HTMLElement]|#width',
24293 'progress^[HTMLElement]|#max,#value',
24294 'q,blockquote,cite^[HTMLElement]|',
24295 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
24296 'select^[HTMLElement]|autocomplete,!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
24297 'shadow^[HTMLElement]|',
24298 'slot^[HTMLElement]|name',
24299 'source^[HTMLElement]|media,sizes,src,srcset,type',
24300 'span^[HTMLElement]|',
24301 'style^[HTMLElement]|!disabled,media,type',
24302 'caption^[HTMLElement]|align',
24303 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
24304 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width',
24305 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
24306 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign',
24307 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign',
24308 'template^[HTMLElement]|',
24309 'textarea^[HTMLElement]|autocapitalize,autocomplete,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
24310 'title^[HTMLElement]|text',
24311 'track^[HTMLElement]|!default,kind,label,src,srclang',
24312 'ul^[HTMLElement]|!compact,type',
24313 'unknown^[HTMLElement]|',
24314 'video^media|#height,poster,#width',
24315 ':svg:a^:svg:graphics|',
24316 ':svg:animate^:svg:animation|',
24317 ':svg:animateMotion^:svg:animation|',
24318 ':svg:animateTransform^:svg:animation|',
24319 ':svg:circle^:svg:geometry|',
24320 ':svg:clipPath^:svg:graphics|',
24321 ':svg:defs^:svg:graphics|',
24322 ':svg:desc^:svg:|',
24323 ':svg:discard^:svg:|',
24324 ':svg:ellipse^:svg:geometry|',
24325 ':svg:feBlend^:svg:|',
24326 ':svg:feColorMatrix^:svg:|',
24327 ':svg:feComponentTransfer^:svg:|',
24328 ':svg:feComposite^:svg:|',
24329 ':svg:feConvolveMatrix^:svg:|',
24330 ':svg:feDiffuseLighting^:svg:|',
24331 ':svg:feDisplacementMap^:svg:|',
24332 ':svg:feDistantLight^:svg:|',
24333 ':svg:feDropShadow^:svg:|',
24334 ':svg:feFlood^:svg:|',
24335 ':svg:feFuncA^:svg:componentTransferFunction|',
24336 ':svg:feFuncB^:svg:componentTransferFunction|',
24337 ':svg:feFuncG^:svg:componentTransferFunction|',
24338 ':svg:feFuncR^:svg:componentTransferFunction|',
24339 ':svg:feGaussianBlur^:svg:|',
24340 ':svg:feImage^:svg:|',
24341 ':svg:feMerge^:svg:|',
24342 ':svg:feMergeNode^:svg:|',
24343 ':svg:feMorphology^:svg:|',
24344 ':svg:feOffset^:svg:|',
24345 ':svg:fePointLight^:svg:|',
24346 ':svg:feSpecularLighting^:svg:|',
24347 ':svg:feSpotLight^:svg:|',
24348 ':svg:feTile^:svg:|',
24349 ':svg:feTurbulence^:svg:|',
24350 ':svg:filter^:svg:|',
24351 ':svg:foreignObject^:svg:graphics|',
24352 ':svg:g^:svg:graphics|',
24353 ':svg:image^:svg:graphics|',
24354 ':svg:line^:svg:geometry|',
24355 ':svg:linearGradient^:svg:gradient|',
24356 ':svg:mpath^:svg:|',
24357 ':svg:marker^:svg:|',
24358 ':svg:mask^:svg:|',
24359 ':svg:metadata^:svg:|',
24360 ':svg:path^:svg:geometry|',
24361 ':svg:pattern^:svg:|',
24362 ':svg:polygon^:svg:geometry|',
24363 ':svg:polyline^:svg:geometry|',
24364 ':svg:radialGradient^:svg:gradient|',
24365 ':svg:rect^:svg:geometry|',
24366 ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan',
24367 ':svg:script^:svg:|type',
24368 ':svg:set^:svg:animation|',
24369 ':svg:stop^:svg:|',
24370 ':svg:style^:svg:|!disabled,media,title,type',
24371 ':svg:switch^:svg:graphics|',
24372 ':svg:symbol^:svg:|',
24373 ':svg:tspan^:svg:textPositioning|',
24374 ':svg:text^:svg:textPositioning|',
24375 ':svg:textPath^:svg:textContent|',
24376 ':svg:title^:svg:|',
24377 ':svg:use^:svg:graphics|',
24378 ':svg:view^:svg:|#zoomAndPan',
24379 'data^[HTMLElement]|value',
24380 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name',
24381 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
24382 'summary^[HTMLElement]|',
24383 'time^[HTMLElement]|dateTime',
24384 ':svg:cursor^:svg:|',
24385 ];
24386 const EVENT = 'event';
24387 const BOOLEAN$1 = 'boolean';
24388 const NUMBER$1 = 'number';
24389 const STRING$1 = 'string';
24390 const OBJECT$1 = 'object';
24391 class SchemaInformation {
24392 constructor() {
24393 this.schema = {};
24394 SCHEMA$1.forEach(encodedType => {
24395 const parts = encodedType.split('|');
24396 const properties = parts[1].split(',');
24397 const typeParts = (parts[0] + '^').split('^');
24398 const typeName = typeParts[0];
24399 const type = {};
24400 typeName.split(',').forEach(tag => this.schema[tag.toLowerCase()] = type);
24401 const superName = typeParts[1];
24402 const superType = superName && this.schema[superName.toLowerCase()];
24403 if (superType) {
24404 for (const key in superType) {
24405 type[key] = superType[key];
24406 }
24407 }
24408 properties.forEach((property) => {
24409 if (property === '') ;
24410 else if (property.startsWith('*')) {
24411 type[property.substring(1)] = EVENT;
24412 }
24413 else if (property.startsWith('!')) {
24414 type[property.substring(1)] = BOOLEAN$1;
24415 }
24416 else if (property.startsWith('#')) {
24417 type[property.substring(1)] = NUMBER$1;
24418 }
24419 else if (property.startsWith('%')) {
24420 type[property.substring(1)] = OBJECT$1;
24421 }
24422 else {
24423 type[property] = STRING$1;
24424 }
24425 });
24426 });
24427 }
24428 allKnownElements() {
24429 return Object.keys(this.schema);
24430 }
24431 eventsOf(elementName) {
24432 const elementType = this.schema[elementName.toLowerCase()] || {};
24433 return Object.keys(elementType).filter(property => elementType[property] === EVENT);
24434 }
24435 propertiesOf(elementName) {
24436 const elementType = this.schema[elementName.toLowerCase()] || {};
24437 return Object.keys(elementType).filter(property => elementType[property] !== EVENT);
24438 }
24439 typeOf(elementName, property) {
24440 return (this.schema[elementName.toLowerCase()] || {})[property];
24441 }
24442 static get instance() {
24443 let result = SchemaInformation._instance;
24444 if (!result) {
24445 result = SchemaInformation._instance = new SchemaInformation();
24446 }
24447 return result;
24448 }
24449 }
24450 function eventNames(elementName) {
24451 return SchemaInformation.instance.eventsOf(elementName);
24452 }
24453 function propertyNames(elementName) {
24454 return SchemaInformation.instance.propertiesOf(elementName);
24455 }
24456
24457 /**
24458 * @license
24459 * Copyright Google LLC All Rights Reserved.
24460 *
24461 * Use of this source code is governed by an MIT-style license that can be
24462 * found in the LICENSE file at https://angular.io/license
24463 */
24464 const EMPTY_SYMBOL_TABLE = {
24465 size: 0,
24466 get: () => undefined,
24467 has: () => false,
24468 values: () => [],
24469 };
24470 /**
24471 * A factory function that returns a symbol table that contains all global symbols
24472 * available in an interpolation scope in a template.
24473 * This function creates the table the first time it is called, and return a cached
24474 * value for all subsequent calls.
24475 */
24476 const createGlobalSymbolTable = (function () {
24477 let GLOBAL_SYMBOL_TABLE;
24478 return function (query) {
24479 if (GLOBAL_SYMBOL_TABLE) {
24480 return GLOBAL_SYMBOL_TABLE;
24481 }
24482 GLOBAL_SYMBOL_TABLE = query.createSymbolTable([
24483 // The `$any()` method casts the type of an expression to `any`.
24484 // https://angular.io/guide/template-syntax#the-any-type-cast-function
24485 {
24486 name: '$any',
24487 kind: 'method',
24488 type: {
24489 name: '$any',
24490 kind: 'method',
24491 type: undefined,
24492 language: 'typescript',
24493 container: undefined,
24494 public: true,
24495 callable: true,
24496 definition: undefined,
24497 nullable: false,
24498 documentation: [{
24499 kind: 'text',
24500 text: 'function to cast an expression to the `any` type',
24501 }],
24502 members: () => EMPTY_SYMBOL_TABLE,
24503 signatures: () => [],
24504 selectSignature(args) {
24505 if (args.length !== 1) {
24506 return;
24507 }
24508 return {
24509 arguments: EMPTY_SYMBOL_TABLE,
24510 result: query.getBuiltinType(BuiltinType$1.Any),
24511 };
24512 },
24513 indexed: () => undefined,
24514 typeArguments: () => undefined,
24515 },
24516 },
24517 ]);
24518 return GLOBAL_SYMBOL_TABLE;
24519 };
24520 })();
24521
24522 /**
24523 * @license
24524 * Copyright Google LLC All Rights Reserved.
24525 *
24526 * Use of this source code is governed by an MIT-style license that can be
24527 * found in the LICENSE file at https://angular.io/license
24528 */
24529 // In TypeScript 2.1 these flags moved
24530 // These helpers work for both 2.0 and 2.1.
24531 const isPrivate = ts.ModifierFlags ?
24532 ((node) => !!(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Private)) :
24533 ((node) => !!(node.flags & ts.NodeFlags.Private));
24534 const isReferenceType = ts.ObjectFlags ?
24535 ((type) => !!(type.flags & ts.TypeFlags.Object &&
24536 type.objectFlags & ts.ObjectFlags.Reference)) :
24537 ((type) => !!(type.flags & ts.TypeFlags.Reference));
24538 function getSymbolQuery(program, checker, source, fetchPipes) {
24539 return new TypeScriptSymbolQuery(program, checker, source, fetchPipes);
24540 }
24541 function getClassMembersFromDeclaration(program, checker, source, declaration) {
24542 const type = checker.getTypeAtLocation(declaration);
24543 return new TypeWrapper(type, { node: source, program, checker }).members();
24544 }
24545 function getPipesTable(source, program, checker, pipes) {
24546 return new PipesTable(pipes, { program, checker, node: source });
24547 }
24548 class TypeScriptSymbolQuery {
24549 constructor(program, checker, source, fetchPipes) {
24550 this.program = program;
24551 this.checker = checker;
24552 this.source = source;
24553 this.fetchPipes = fetchPipes;
24554 this.typeCache = new Map();
24555 }
24556 getTypeKind(symbol) {
24557 const type = symbol instanceof TypeWrapper ? symbol.tsType : undefined;
24558 return typeKindOf(type);
24559 }
24560 getBuiltinType(kind) {
24561 let result = this.typeCache.get(kind);
24562 if (!result) {
24563 const type = getTsTypeFromBuiltinType(kind, {
24564 checker: this.checker,
24565 node: this.source,
24566 program: this.program,
24567 });
24568 result =
24569 new TypeWrapper(type, { program: this.program, checker: this.checker, node: this.source });
24570 this.typeCache.set(kind, result);
24571 }
24572 return result;
24573 }
24574 getTypeUnion(...types) {
24575 // No API exists so return any if the types are not all the same type.
24576 let result = undefined;
24577 if (types.length) {
24578 result = types[0];
24579 for (let i = 1; i < types.length; i++) {
24580 if (types[i] != result) {
24581 result = undefined;
24582 break;
24583 }
24584 }
24585 }
24586 return result || this.getBuiltinType(BuiltinType$1.Any);
24587 }
24588 getArrayType(_type) {
24589 return this.getBuiltinType(BuiltinType$1.Any);
24590 }
24591 getElementType(type) {
24592 if (type instanceof TypeWrapper) {
24593 const ty = type.tsType;
24594 const tyArgs = type.typeArguments();
24595 // TODO(ayazhafiz): Track https://github.com/microsoft/TypeScript/issues/37711 to expose
24596 // `isArrayLikeType` as a public method.
24597 if (!this.checker.isArrayLikeType(ty) || (tyArgs === null || tyArgs === void 0 ? void 0 : tyArgs.length) !== 1)
24598 return;
24599 return tyArgs[0];
24600 }
24601 }
24602 getNonNullableType(symbol) {
24603 if (symbol instanceof TypeWrapper && (typeof this.checker.getNonNullableType == 'function')) {
24604 const tsType = symbol.tsType;
24605 const nonNullableType = this.checker.getNonNullableType(tsType);
24606 if (nonNullableType != tsType) {
24607 return new TypeWrapper(nonNullableType, symbol.context);
24608 }
24609 else if (nonNullableType == tsType) {
24610 return symbol;
24611 }
24612 }
24613 return this.getBuiltinType(BuiltinType$1.Any);
24614 }
24615 getPipes() {
24616 let result = this.pipesCache;
24617 if (!result) {
24618 result = this.pipesCache = this.fetchPipes();
24619 }
24620 return result;
24621 }
24622 getTemplateContext(type) {
24623 const context = { node: this.source, program: this.program, checker: this.checker };
24624 const typeSymbol = findClassSymbolInContext(type, context);
24625 if (typeSymbol) {
24626 const contextType = this.getTemplateRefContextType(typeSymbol, context);
24627 if (contextType)
24628 return contextType.members();
24629 }
24630 }
24631 getTypeSymbol(type) {
24632 const context = { node: this.source, program: this.program, checker: this.checker };
24633 const typeSymbol = findClassSymbolInContext(type, context);
24634 return typeSymbol && new SymbolWrapper(typeSymbol, context);
24635 }
24636 createSymbolTable(symbols) {
24637 const result = new MapSymbolTable();
24638 result.addAll(symbols.map(s => new DeclaredSymbol(s)));
24639 return result;
24640 }
24641 mergeSymbolTable(symbolTables) {
24642 const result = new MapSymbolTable();
24643 for (const symbolTable of symbolTables) {
24644 result.addAll(symbolTable.values());
24645 }
24646 return result;
24647 }
24648 getSpanAt(line, column) {
24649 return spanAt(this.source, line, column);
24650 }
24651 getTemplateRefContextType(typeSymbol, context) {
24652 const type = this.checker.getTypeOfSymbolAtLocation(typeSymbol, this.source);
24653 const constructor = type.symbol && type.symbol.members &&
24654 getFromSymbolTable(type.symbol.members, '__constructor');
24655 if (constructor) {
24656 const constructorDeclaration = constructor.declarations[0];
24657 for (const parameter of constructorDeclaration.parameters) {
24658 const type = this.checker.getTypeAtLocation(parameter.type);
24659 if (type.symbol.name == 'TemplateRef' && isReferenceType(type)) {
24660 const typeWrapper = new TypeWrapper(type, context);
24661 const typeArguments = typeWrapper.typeArguments();
24662 if (typeArguments && typeArguments.length === 1) {
24663 return typeArguments[0];
24664 }
24665 }
24666 }
24667 }
24668 }
24669 }
24670 function typeCallable(type) {
24671 const signatures = type.getCallSignatures();
24672 return signatures && signatures.length != 0;
24673 }
24674 function signaturesOf(type, context) {
24675 return type.getCallSignatures().map(s => new SignatureWrapper(s, context));
24676 }
24677 function selectSignature(type, context, types) {
24678 // TODO: Do a better job of selecting the right signature. TypeScript does not currently support a
24679 // Type Relationship API (see https://github.com/angular/vscode-ng-language-service/issues/143).
24680 // Consider creating a TypeCheckBlock host in the language service that may also act as a
24681 // scratchpad for type comparisons.
24682 const signatures = type.getCallSignatures();
24683 const passedInTypes = types.map(type => {
24684 if (type instanceof TypeWrapper) {
24685 return type.tsType;
24686 }
24687 });
24688 // Try to select a matching signature in which all parameter types match.
24689 // Note that this is just a best-effort approach, because we're checking for
24690 // strict type equality rather than compatibility.
24691 // For example, if the signature contains a ReadonlyArray<number> and the
24692 // passed parameter type is an Array<number>, this will fail.
24693 function allParameterTypesMatch(signature) {
24694 const tc = context.checker;
24695 return signature.getParameters().every((parameter, i) => {
24696 const type = tc.getTypeOfSymbolAtLocation(parameter, parameter.valueDeclaration);
24697 return type === passedInTypes[i];
24698 });
24699 }
24700 const exactMatch = signatures.find(allParameterTypesMatch);
24701 if (exactMatch) {
24702 return new SignatureWrapper(exactMatch, context);
24703 }
24704 // If not, fallback to a naive selection
24705 return signatures.length ? new SignatureWrapper(signatures[0], context) : undefined;
24706 }
24707 class TypeWrapper {
24708 constructor(tsType, context) {
24709 this.tsType = tsType;
24710 this.context = context;
24711 this.kind = 'type';
24712 this.language = 'typescript';
24713 this.type = undefined;
24714 this.container = undefined;
24715 this.public = true;
24716 if (!tsType) {
24717 throw Error('Internal: null type');
24718 }
24719 }
24720 get name() {
24721 return this.context.checker.typeToString(this.tsType);
24722 }
24723 get callable() {
24724 return typeCallable(this.tsType);
24725 }
24726 get nullable() {
24727 return this.context.checker.getNonNullableType(this.tsType) != this.tsType;
24728 }
24729 get documentation() {
24730 const symbol = this.tsType.getSymbol();
24731 if (!symbol) {
24732 return [];
24733 }
24734 return symbol.getDocumentationComment(this.context.checker);
24735 }
24736 get definition() {
24737 const symbol = this.tsType.getSymbol();
24738 return symbol ? definitionFromTsSymbol(symbol) : undefined;
24739 }
24740 members() {
24741 // Should call getApparentProperties() instead of getProperties() because
24742 // the former includes properties on the base class whereas the latter does
24743 // not. This provides properties like .bind(), .call(), .apply(), etc for
24744 // functions.
24745 return new SymbolTableWrapper(this.tsType.getApparentProperties(), this.context, this.tsType);
24746 }
24747 signatures() {
24748 return signaturesOf(this.tsType, this.context);
24749 }
24750 selectSignature(types) {
24751 return selectSignature(this.tsType, this.context, types);
24752 }
24753 indexed(type, value) {
24754 if (!(type instanceof TypeWrapper))
24755 return;
24756 const typeKind = typeKindOf(type.tsType);
24757 switch (typeKind) {
24758 case BuiltinType$1.Number:
24759 const nType = this.tsType.getNumberIndexType();
24760 if (nType) {
24761 // get the right tuple type by value, like 'var t: [number, string];'
24762 if (nType.isUnion()) {
24763 // return undefined if array index out of bound.
24764 return nType.types[value] && new TypeWrapper(nType.types[value], this.context);
24765 }
24766 return new TypeWrapper(nType, this.context);
24767 }
24768 return undefined;
24769 case BuiltinType$1.String:
24770 const sType = this.tsType.getStringIndexType();
24771 return sType && new TypeWrapper(sType, this.context);
24772 }
24773 }
24774 typeArguments() {
24775 if (!isReferenceType(this.tsType))
24776 return;
24777 const typeReference = this.tsType;
24778 let typeArguments;
24779 typeArguments = this.context.checker.getTypeArguments(typeReference);
24780 if (!typeArguments)
24781 return undefined;
24782 return typeArguments.map(ta => new TypeWrapper(ta, this.context));
24783 }
24784 }
24785 // If stringIndexType a primitive type(e.g. 'string'), the Symbol is undefined;
24786 // and in AstType.resolvePropertyRead method, the Symbol.type should get the right type.
24787 class StringIndexTypeWrapper extends TypeWrapper {
24788 constructor() {
24789 super(...arguments);
24790 this.type = new TypeWrapper(this.tsType, this.context);
24791 }
24792 }
24793 class SymbolWrapper {
24794 constructor(symbol,
24795 /** TypeScript type context of the symbol. */
24796 context,
24797 /**
24798 * Type of the TypeScript symbol, if known. If not provided, the type of the symbol
24799 * will be determined dynamically; see `SymbolWrapper#tsType`.
24800 */
24801 _tsType) {
24802 this.context = context;
24803 this._tsType = _tsType;
24804 this.nullable = false;
24805 this.language = 'typescript';
24806 this.symbol = symbol && context && (symbol.flags & ts.SymbolFlags.Alias) ?
24807 context.checker.getAliasedSymbol(symbol) :
24808 symbol;
24809 }
24810 get name() {
24811 return this.symbol.name;
24812 }
24813 get kind() {
24814 return this.callable ? 'method' : 'property';
24815 }
24816 get type() {
24817 return new TypeWrapper(this.tsType, this.context);
24818 }
24819 get container() {
24820 return getContainerOf(this.symbol, this.context);
24821 }
24822 get public() {
24823 // Symbols that are not explicitly made private are public.
24824 return !isSymbolPrivate(this.symbol);
24825 }
24826 get callable() {
24827 return typeCallable(this.tsType);
24828 }
24829 get definition() {
24830 return definitionFromTsSymbol(this.symbol);
24831 }
24832 get documentation() {
24833 return this.symbol.getDocumentationComment(this.context.checker);
24834 }
24835 members() {
24836 if (!this._members) {
24837 if ((this.symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) != 0) {
24838 const declaredType = this.context.checker.getDeclaredTypeOfSymbol(this.symbol);
24839 const typeWrapper = new TypeWrapper(declaredType, this.context);
24840 this._members = typeWrapper.members();
24841 }
24842 else {
24843 this._members = new SymbolTableWrapper(this.symbol.members, this.context, this.tsType);
24844 }
24845 }
24846 return this._members;
24847 }
24848 signatures() {
24849 return signaturesOf(this.tsType, this.context);
24850 }
24851 selectSignature(types) {
24852 return selectSignature(this.tsType, this.context, types);
24853 }
24854 indexed(_argument) {
24855 return undefined;
24856 }
24857 typeArguments() {
24858 return this.type.typeArguments();
24859 }
24860 get tsType() {
24861 let type = this._tsType;
24862 if (!type) {
24863 type = this._tsType =
24864 this.context.checker.getTypeOfSymbolAtLocation(this.symbol, this.context.node);
24865 }
24866 return type;
24867 }
24868 }
24869 class DeclaredSymbol {
24870 constructor(declaration) {
24871 this.declaration = declaration;
24872 this.language = 'ng-template';
24873 this.nullable = false;
24874 this.public = true;
24875 }
24876 get name() {
24877 return this.declaration.name;
24878 }
24879 get kind() {
24880 return this.declaration.kind;
24881 }
24882 get container() {
24883 return undefined;
24884 }
24885 get type() {
24886 return this.declaration.type;
24887 }
24888 get callable() {
24889 return this.type.callable;
24890 }
24891 get definition() {
24892 return this.declaration.definition;
24893 }
24894 get documentation() {
24895 return this.declaration.type.documentation;
24896 }
24897 members() {
24898 return this.type.members();
24899 }
24900 signatures() {
24901 return this.type.signatures();
24902 }
24903 selectSignature(types) {
24904 return this.type.selectSignature(types);
24905 }
24906 typeArguments() {
24907 return this.type.typeArguments();
24908 }
24909 indexed(_argument) {
24910 return undefined;
24911 }
24912 }
24913 class SignatureWrapper {
24914 constructor(signature, context) {
24915 this.signature = signature;
24916 this.context = context;
24917 }
24918 get arguments() {
24919 return new SymbolTableWrapper(this.signature.getParameters(), this.context);
24920 }
24921 get result() {
24922 return new TypeWrapper(this.signature.getReturnType(), this.context);
24923 }
24924 }
24925 class SignatureResultOverride {
24926 constructor(signature, resultType) {
24927 this.signature = signature;
24928 this.resultType = resultType;
24929 }
24930 get arguments() {
24931 return this.signature.arguments;
24932 }
24933 get result() {
24934 return this.resultType;
24935 }
24936 }
24937 function toSymbolTableFactory(symbols) {
24938 // ∀ Typescript version >= 2.2, `SymbolTable` is implemented as an ES6 `Map`
24939 const result = new Map();
24940 for (const symbol of symbols) {
24941 result.set(symbol.name, symbol);
24942 }
24943 return result;
24944 }
24945 function toSymbols(symbolTable) {
24946 if (!symbolTable)
24947 return [];
24948 const table = symbolTable;
24949 if (typeof table.values === 'function') {
24950 return Array.from(table.values());
24951 }
24952 const result = [];
24953 const own = typeof table.hasOwnProperty === 'function' ?
24954 (name) => table.hasOwnProperty(name) :
24955 (name) => !!table[name];
24956 for (const name in table) {
24957 if (own(name)) {
24958 result.push(table[name]);
24959 }
24960 }
24961 return result;
24962 }
24963 class SymbolTableWrapper {
24964 /**
24965 * Creates a queryable table of symbols belonging to a TypeScript entity.
24966 * @param symbols symbols to query belonging to the entity
24967 * @param context program context
24968 * @param type original TypeScript type of entity owning the symbols, if known
24969 */
24970 constructor(symbols, context, type) {
24971 this.context = context;
24972 symbols = symbols || [];
24973 if (Array.isArray(symbols)) {
24974 this.symbols = symbols;
24975 this.symbolTable = toSymbolTableFactory(symbols);
24976 }
24977 else {
24978 this.symbols = toSymbols(symbols);
24979 this.symbolTable = symbols;
24980 }
24981 if (type) {
24982 this.stringIndexType = type.getStringIndexType();
24983 }
24984 }
24985 get size() {
24986 return this.symbols.length;
24987 }
24988 get(key) {
24989 const symbol = getFromSymbolTable(this.symbolTable, key);
24990 if (symbol) {
24991 return new SymbolWrapper(symbol, this.context);
24992 }
24993 if (this.stringIndexType) {
24994 // If the key does not exist as an explicit symbol on the type, it may be accessing a string
24995 // index signature using dot notation:
24996 //
24997 // const obj<T>: { [key: string]: T };
24998 // obj.stringIndex // equivalent to obj['stringIndex'];
24999 //
25000 // In this case, return the type indexed by an arbitrary string key.
25001 return new StringIndexTypeWrapper(this.stringIndexType, this.context);
25002 }
25003 return undefined;
25004 }
25005 has(key) {
25006 const table = this.symbolTable;
25007 return ((typeof table.has === 'function') ? table.has(key) : table[key] != null) ||
25008 this.stringIndexType !== undefined;
25009 }
25010 values() {
25011 return this.symbols.map(s => new SymbolWrapper(s, this.context));
25012 }
25013 }
25014 class MapSymbolTable {
25015 constructor() {
25016 this.map = new Map();
25017 this._values = [];
25018 }
25019 get size() {
25020 return this.map.size;
25021 }
25022 get(key) {
25023 return this.map.get(key);
25024 }
25025 add(symbol) {
25026 if (this.map.has(symbol.name)) {
25027 const previous = this.map.get(symbol.name);
25028 this._values[this._values.indexOf(previous)] = symbol;
25029 }
25030 this.map.set(symbol.name, symbol);
25031 this._values.push(symbol);
25032 }
25033 addAll(symbols) {
25034 for (const symbol of symbols) {
25035 this.add(symbol);
25036 }
25037 }
25038 has(key) {
25039 return this.map.has(key);
25040 }
25041 values() {
25042 // Switch to this.map.values once iterables are supported by the target language.
25043 return this._values;
25044 }
25045 }
25046 class PipesTable {
25047 constructor(pipes, context) {
25048 this.pipes = pipes;
25049 this.context = context;
25050 }
25051 get size() {
25052 return this.pipes.length;
25053 }
25054 get(key) {
25055 const pipe = this.pipes.find(pipe => pipe.name == key);
25056 if (pipe) {
25057 return new PipeSymbol(pipe, this.context);
25058 }
25059 }
25060 has(key) {
25061 return this.pipes.find(pipe => pipe.name == key) != null;
25062 }
25063 values() {
25064 return this.pipes.map(pipe => new PipeSymbol(pipe, this.context));
25065 }
25066 }
25067 // This matches .d.ts files that look like ".../<package-name>/<package-name>.d.ts",
25068 const INDEX_PATTERN = /[\\/]([^\\/]+)[\\/]\1\.d\.ts$/;
25069 class PipeSymbol {
25070 constructor(pipe, context) {
25071 this.pipe = pipe;
25072 this.context = context;
25073 this.kind = 'pipe';
25074 this.language = 'typescript';
25075 this.container = undefined;
25076 this.callable = true;
25077 this.nullable = false;
25078 this.public = true;
25079 }
25080 get name() {
25081 return this.pipe.name;
25082 }
25083 get type() {
25084 return new TypeWrapper(this.tsType, this.context);
25085 }
25086 get definition() {
25087 const symbol = this.tsType.getSymbol();
25088 return symbol ? definitionFromTsSymbol(symbol) : undefined;
25089 }
25090 get documentation() {
25091 const symbol = this.tsType.getSymbol();
25092 if (!symbol) {
25093 return [];
25094 }
25095 return symbol.getDocumentationComment(this.context.checker);
25096 }
25097 members() {
25098 return EmptyTable.instance;
25099 }
25100 signatures() {
25101 return signaturesOf(this.tsType, this.context);
25102 }
25103 selectSignature(types) {
25104 let signature = selectSignature(this.tsType, this.context, types);
25105 if (types.length > 0) {
25106 const parameterType = types[0];
25107 let resultType = undefined;
25108 switch (this.name) {
25109 case 'async':
25110 // Get type argument of 'Observable', 'Promise', or 'EventEmitter'.
25111 const tArgs = parameterType.typeArguments();
25112 if (tArgs && tArgs.length === 1) {
25113 resultType = tArgs[0];
25114 }
25115 break;
25116 case 'slice':
25117 resultType = parameterType;
25118 break;
25119 }
25120 if (resultType) {
25121 signature = new SignatureResultOverride(signature, resultType);
25122 }
25123 }
25124 return signature;
25125 }
25126 indexed(_argument) {
25127 return undefined;
25128 }
25129 typeArguments() {
25130 return this.type.typeArguments();
25131 }
25132 get tsType() {
25133 let type = this._tsType;
25134 if (!type) {
25135 const classSymbol = this.findClassSymbol(this.pipe.type.reference);
25136 if (classSymbol) {
25137 type = this._tsType = this.findTransformMethodType(classSymbol);
25138 }
25139 if (!type) {
25140 type = this._tsType = getTsTypeFromBuiltinType(BuiltinType$1.Any, this.context);
25141 }
25142 }
25143 return type;
25144 }
25145 findClassSymbol(type) {
25146 return findClassSymbolInContext(type, this.context);
25147 }
25148 findTransformMethodType(classSymbol) {
25149 const classType = this.context.checker.getDeclaredTypeOfSymbol(classSymbol);
25150 if (classType) {
25151 const transform = classType.getProperty('transform');
25152 if (transform) {
25153 return this.context.checker.getTypeOfSymbolAtLocation(transform, this.context.node);
25154 }
25155 }
25156 }
25157 }
25158 function findClassSymbolInContext(type, context) {
25159 let sourceFile = context.program.getSourceFile(type.filePath);
25160 if (!sourceFile) {
25161 // This handles a case where an <packageName>/index.d.ts and a <packageName>/<packageName>.d.ts
25162 // are in the same directory. If we are looking for <packageName>/<packageName> and didn't
25163 // find it, look for <packageName>/index.d.ts as the program might have found that instead.
25164 const p = type.filePath;
25165 const m = p.match(INDEX_PATTERN);
25166 if (m) {
25167 const indexVersion = path.join(path.dirname(p), 'index.d.ts');
25168 sourceFile = context.program.getSourceFile(indexVersion);
25169 }
25170 }
25171 if (sourceFile) {
25172 const moduleSymbol = sourceFile.module || sourceFile.symbol;
25173 const exports = context.checker.getExportsOfModule(moduleSymbol);
25174 return (exports || []).find(symbol => symbol.name == type.name);
25175 }
25176 }
25177 class EmptyTable {
25178 constructor() {
25179 this.size = 0;
25180 }
25181 get(_key) {
25182 return undefined;
25183 }
25184 has(_key) {
25185 return false;
25186 }
25187 values() {
25188 return [];
25189 }
25190 }
25191 EmptyTable.instance = new EmptyTable();
25192 function isSymbolPrivate(s) {
25193 return !!s.valueDeclaration && isPrivate(s.valueDeclaration);
25194 }
25195 function getTsTypeFromBuiltinType(builtinType, ctx) {
25196 let syntaxKind;
25197 switch (builtinType) {
25198 case BuiltinType$1.Any:
25199 syntaxKind = ts.SyntaxKind.AnyKeyword;
25200 break;
25201 case BuiltinType$1.Boolean:
25202 syntaxKind = ts.SyntaxKind.BooleanKeyword;
25203 break;
25204 case BuiltinType$1.Null:
25205 syntaxKind = ts.SyntaxKind.NullKeyword;
25206 break;
25207 case BuiltinType$1.Number:
25208 syntaxKind = ts.SyntaxKind.NumberKeyword;
25209 break;
25210 case BuiltinType$1.String:
25211 syntaxKind = ts.SyntaxKind.StringKeyword;
25212 break;
25213 case BuiltinType$1.Undefined:
25214 syntaxKind = ts.SyntaxKind.UndefinedKeyword;
25215 break;
25216 default:
25217 throw new Error(`Internal error, unhandled literal kind ${builtinType}:${BuiltinType$1[builtinType]}`);
25218 }
25219 const node = ts.createNode(syntaxKind);
25220 node.parent = ts.createEmptyStatement();
25221 return ctx.checker.getTypeAtLocation(node);
25222 }
25223 function spanAt(sourceFile, line, column) {
25224 if (line != null && column != null) {
25225 const position = ts.getPositionOfLineAndCharacter(sourceFile, line, column);
25226 const findChild = function findChild(node) {
25227 if (node.kind > ts.SyntaxKind.LastToken && node.pos <= position && node.end > position) {
25228 const betterNode = ts.forEachChild(node, findChild);
25229 return betterNode || node;
25230 }
25231 };
25232 const node = ts.forEachChild(sourceFile, findChild);
25233 if (node) {
25234 return { start: node.getStart(), end: node.getEnd() };
25235 }
25236 }
25237 }
25238 function definitionFromTsSymbol(symbol) {
25239 const declarations = symbol.declarations;
25240 if (declarations) {
25241 return declarations.map(declaration => {
25242 const sourceFile = declaration.getSourceFile();
25243 return {
25244 fileName: sourceFile.fileName,
25245 span: { start: declaration.getStart(), end: declaration.getEnd() }
25246 };
25247 });
25248 }
25249 }
25250 function parentDeclarationOf(node) {
25251 while (node) {
25252 switch (node.kind) {
25253 case ts.SyntaxKind.ClassDeclaration:
25254 case ts.SyntaxKind.InterfaceDeclaration:
25255 return node;
25256 case ts.SyntaxKind.SourceFile:
25257 return undefined;
25258 }
25259 node = node.parent;
25260 }
25261 }
25262 function getContainerOf(symbol, context) {
25263 if (symbol.getFlags() & ts.SymbolFlags.ClassMember && symbol.declarations) {
25264 for (const declaration of symbol.declarations) {
25265 const parent = parentDeclarationOf(declaration);
25266 if (parent) {
25267 const type = context.checker.getTypeAtLocation(parent);
25268 if (type) {
25269 return new TypeWrapper(type, context);
25270 }
25271 }
25272 }
25273 }
25274 }
25275 function typeKindOf(type) {
25276 if (type) {
25277 if (type.flags & ts.TypeFlags.Any) {
25278 return BuiltinType$1.Any;
25279 }
25280 else if (type.flags & (ts.TypeFlags.String | ts.TypeFlags.StringLike | ts.TypeFlags.StringLiteral)) {
25281 return BuiltinType$1.String;
25282 }
25283 else if (type.flags & (ts.TypeFlags.Number | ts.TypeFlags.NumberLike)) {
25284 return BuiltinType$1.Number;
25285 }
25286 else if (type.flags & ts.TypeFlags.Object) {
25287 return BuiltinType$1.Object;
25288 }
25289 else if (type.flags & (ts.TypeFlags.Undefined)) {
25290 return BuiltinType$1.Undefined;
25291 }
25292 else if (type.flags & (ts.TypeFlags.Null)) {
25293 return BuiltinType$1.Null;
25294 }
25295 else if (type.flags & ts.TypeFlags.Union) {
25296 const unionType = type;
25297 if (unionType.types.length === 0)
25298 return BuiltinType$1.Other;
25299 let ty = 0;
25300 for (const subType of unionType.types) {
25301 ty |= typeKindOf(subType);
25302 }
25303 return ty;
25304 }
25305 else if (type.flags & ts.TypeFlags.TypeParameter) {
25306 return BuiltinType$1.Unbound;
25307 }
25308 }
25309 return BuiltinType$1.Other;
25310 }
25311 function getFromSymbolTable(symbolTable, key) {
25312 const table = symbolTable;
25313 let symbol;
25314 if (typeof table.get === 'function') {
25315 // TS 2.2 uses a Map
25316 symbol = table.get(key);
25317 }
25318 else {
25319 // TS pre-2.2 uses an object
25320 symbol = table[key];
25321 }
25322 return symbol;
25323 }
25324
25325 /**
25326 * @license
25327 * Copyright Google LLC All Rights Reserved.
25328 *
25329 * Use of this source code is governed by an MIT-style license that can be
25330 * found in the LICENSE file at https://angular.io/license
25331 */
25332 /**
25333 * A base class to represent a template and which component class it is
25334 * associated with. A template source could answer basic questions about
25335 * top-level declarations of its class through the members() and query()
25336 * methods.
25337 */
25338 class BaseTemplate {
25339 constructor(host, classDeclNode, classSymbol) {
25340 this.host = host;
25341 this.classDeclNode = classDeclNode;
25342 this.classSymbol = classSymbol;
25343 this.program = host.program;
25344 }
25345 /**
25346 * Return the Angular StaticSymbol for the class that contains this template.
25347 */
25348 get type() {
25349 return this.classSymbol;
25350 }
25351 /**
25352 * Return a Map-like data structure that allows users to retrieve some or all
25353 * top-level declarations in the associated component class.
25354 */
25355 get members() {
25356 if (!this.membersTable) {
25357 const typeChecker = this.program.getTypeChecker();
25358 const sourceFile = this.classDeclNode.getSourceFile();
25359 this.membersTable = this.query.mergeSymbolTable([
25360 createGlobalSymbolTable(this.query),
25361 getClassMembersFromDeclaration(this.program, typeChecker, sourceFile, this.classDeclNode),
25362 ]);
25363 }
25364 return this.membersTable;
25365 }
25366 /**
25367 * Return an engine that provides more information about symbols in the
25368 * template.
25369 */
25370 get query() {
25371 if (!this.queryCache) {
25372 const program = this.program;
25373 const typeChecker = program.getTypeChecker();
25374 const sourceFile = this.classDeclNode.getSourceFile();
25375 this.queryCache = getSymbolQuery(program, typeChecker, sourceFile, () => {
25376 // Computing the ast is relatively expensive. Do it only when absolutely
25377 // necessary.
25378 // TODO: There is circular dependency here between TemplateSource and
25379 // TypeScriptHost. Consider refactoring the code to break this cycle.
25380 const ast = this.host.getTemplateAst(this);
25381 const pipes = (ast && ast.pipes) || [];
25382 return getPipesTable(sourceFile, program, typeChecker, pipes);
25383 });
25384 }
25385 return this.queryCache;
25386 }
25387 }
25388 /**
25389 * An InlineTemplate represents template defined in a TS file through the
25390 * `template` attribute in the decorator.
25391 */
25392 class InlineTemplate extends BaseTemplate {
25393 constructor(templateNode, classDeclNode, classSymbol, host) {
25394 super(host, classDeclNode, classSymbol);
25395 const sourceFile = templateNode.getSourceFile();
25396 if (sourceFile !== classDeclNode.getSourceFile()) {
25397 throw new Error(`Inline template and component class should belong to the same source file`);
25398 }
25399 this.fileName = sourceFile.fileName;
25400 // node.text returns the TS internal representation of the normalized text,
25401 // and all CR characters are stripped. node.getText() returns the raw text.
25402 this.source = templateNode.getText().slice(1, -1); // strip leading and trailing quotes
25403 this.span = {
25404 // TS string literal includes surrounding quotes in the start/end offsets.
25405 start: templateNode.getStart() + 1,
25406 end: templateNode.getEnd() - 1,
25407 };
25408 }
25409 }
25410 /**
25411 * An ExternalTemplate represents template defined in an external (most likely
25412 * HTML, but not necessarily) file through the `templateUrl` attribute in the
25413 * decorator.
25414 * Note that there is no ts.Node associated with the template because it's not
25415 * a TS file.
25416 */
25417 class ExternalTemplate extends BaseTemplate {
25418 constructor(source, fileName, classDeclNode, classSymbol, host) {
25419 super(host, classDeclNode, classSymbol);
25420 this.source = source;
25421 this.fileName = fileName;
25422 this.span = {
25423 start: 0,
25424 end: source.length,
25425 };
25426 }
25427 }
25428
25429 /**
25430 * @license
25431 * Copyright Google LLC All Rights Reserved.
25432 *
25433 * Use of this source code is governed by an MIT-style license that can be
25434 * found in the LICENSE file at https://angular.io/license
25435 */
25436 const HIDDEN_HTML_ELEMENTS = new Set(['html', 'script', 'noscript', 'base', 'body', 'title', 'head', 'link']);
25437 const HTML_ELEMENTS = elementNames().filter(name => !HIDDEN_HTML_ELEMENTS.has(name)).map(name => {
25438 return {
25439 name,
25440 kind: CompletionKind.HTML_ELEMENT,
25441 sortText: name,
25442 };
25443 });
25444 const ANGULAR_ELEMENTS = [
25445 {
25446 name: 'ng-container',
25447 kind: CompletionKind.ANGULAR_ELEMENT,
25448 sortText: 'ng-container',
25449 },
25450 {
25451 name: 'ng-content',
25452 kind: CompletionKind.ANGULAR_ELEMENT,
25453 sortText: 'ng-content',
25454 },
25455 {
25456 name: 'ng-template',
25457 kind: CompletionKind.ANGULAR_ELEMENT,
25458 sortText: 'ng-template',
25459 },
25460 ];
25461 function isIdentifierPart$1(code) {
25462 // Identifiers consist of alphanumeric characters, '_', or '$'.
25463 return isAsciiLetter(code) || isDigit(code) || code == $$ || code == $_;
25464 }
25465 /**
25466 * Gets the span of word in a template that surrounds `position`. If there is no word around
25467 * `position`, nothing is returned.
25468 */
25469 function getBoundedWordSpan(templateInfo, position, ast) {
25470 const { template } = templateInfo;
25471 const templateSrc = template.source;
25472 if (!templateSrc)
25473 return;
25474 if (ast instanceof Element$1) {
25475 // The HTML tag may include `-` (e.g. `app-root`),
25476 // so use the HtmlAst to get the span before ayazhafiz refactor the code.
25477 return {
25478 start: templateInfo.template.span.start + ast.startSourceSpan.start.offset + 1,
25479 length: ast.name.length
25480 };
25481 }
25482 // TODO(ayazhafiz): A solution based on word expansion will always be expensive compared to one
25483 // based on ASTs. Whatever penalty we incur is probably manageable for small-length (i.e. the
25484 // majority of) identifiers, but the current solution involes a number of branchings and we can't
25485 // control potentially very long identifiers. Consider moving to an AST-based solution once
25486 // existing difficulties with AST spans are more clearly resolved (see #31898 for discussion of
25487 // known problems, and #33091 for how they affect text replacement).
25488 //
25489 // `templatePosition` represents the right-bound location of a cursor in the template.
25490 // key.ent|ry
25491 // ^---- cursor, at position `r` is at.
25492 // A cursor is not itself a character in the template; it has a left (lower) and right (upper)
25493 // index bound that hugs the cursor itself.
25494 let templatePosition = position - template.span.start;
25495 // To perform word expansion, we want to determine the left and right indices that hug the cursor.
25496 // There are three cases here.
25497 let left, right;
25498 if (templatePosition === 0) {
25499 // 1. Case like
25500 // |rest of template
25501 // the cursor is at the start of the template, hugged only by the right side (0-index).
25502 left = right = 0;
25503 }
25504 else if (templatePosition === templateSrc.length) {
25505 // 2. Case like
25506 // rest of template|
25507 // the cursor is at the end of the template, hugged only by the left side (last-index).
25508 left = right = templateSrc.length - 1;
25509 }
25510 else {
25511 // 3. Case like
25512 // wo|rd
25513 // there is a clear left and right index.
25514 left = templatePosition - 1;
25515 right = templatePosition;
25516 }
25517 if (!isIdentifierPart$1(templateSrc.charCodeAt(left)) &&
25518 !isIdentifierPart$1(templateSrc.charCodeAt(right))) {
25519 // Case like
25520 // .|.
25521 // left ---^ ^--- right
25522 // There is no word here.
25523 return;
25524 }
25525 // Expand on the left and right side until a word boundary is hit. Back up one expansion on both
25526 // side to stay inside the word.
25527 while (left >= 0 && isIdentifierPart$1(templateSrc.charCodeAt(left)))
25528 --left;
25529 ++left;
25530 while (right < templateSrc.length && isIdentifierPart$1(templateSrc.charCodeAt(right)))
25531 ++right;
25532 --right;
25533 const absoluteStartPosition = position - (templatePosition - left);
25534 const length = right - left + 1;
25535 return { start: absoluteStartPosition, length };
25536 }
25537 function getTemplateCompletions(templateInfo, position) {
25538 const { htmlAst, template } = templateInfo;
25539 // Calculate the position relative to the start of the template. This is needed
25540 // because spans in HTML AST are relative. Inline template has non-zero start position.
25541 const templatePosition = position - template.span.start;
25542 const htmlPath = getPathToNodeAtPosition(htmlAst, templatePosition);
25543 const mostSpecific = htmlPath.tail;
25544 const visitor = new HtmlVisitor(templateInfo, htmlPath);
25545 const results = mostSpecific ?
25546 mostSpecific.visit(visitor, null /* context */) :
25547 elementCompletions(templateInfo);
25548 const replacementSpan = getBoundedWordSpan(templateInfo, position, mostSpecific);
25549 return results.map(entry => {
25550 return Object.assign(Object.assign({}, entry), { replacementSpan });
25551 });
25552 }
25553 class HtmlVisitor {
25554 constructor(templateInfo, htmlPath) {
25555 this.templateInfo = templateInfo;
25556 this.htmlPath = htmlPath;
25557 this.relativePosition = htmlPath.position;
25558 }
25559 // Note that every visitor method must explicitly specify return type because
25560 // Visitor returns `any` for all methods.
25561 visitElement(ast) {
25562 const startTagSpan = spanOf(ast.sourceSpan);
25563 const tagLen = ast.name.length;
25564 // + 1 for the opening angle bracket
25565 if (this.relativePosition <= startTagSpan.start + tagLen + 1) {
25566 // If we are in the tag then return the element completions.
25567 return elementCompletions(this.templateInfo);
25568 }
25569 if (this.relativePosition < startTagSpan.end) {
25570 // We are in the attribute section of the element (but not in an attribute).
25571 // Return the attribute completions.
25572 return attributeCompletionsForElement(this.templateInfo, ast.name);
25573 }
25574 return [];
25575 }
25576 visitAttribute(ast) {
25577 // An attribute consists of two parts, LHS="RHS".
25578 // Determine if completions are requested for LHS or RHS
25579 if (ast.valueSpan && inSpan(this.relativePosition, spanOf(ast.valueSpan))) {
25580 // RHS completion
25581 return attributeValueCompletions(this.templateInfo, this.htmlPath);
25582 }
25583 // LHS completion
25584 return attributeCompletions(this.templateInfo, this.htmlPath);
25585 }
25586 visitText() {
25587 var _a;
25588 const templatePath = findTemplateAstAt(this.templateInfo.templateAst, this.relativePosition);
25589 if (templatePath.tail instanceof BoundTextAst) {
25590 // If we know that this is an interpolation then do not try other scenarios.
25591 const visitor = new ExpressionVisitor(this.templateInfo, this.relativePosition, () => getExpressionScope(diagnosticInfoFromTemplateInfo(this.templateInfo), templatePath));
25592 (_a = templatePath.tail) === null || _a === void 0 ? void 0 : _a.visit(visitor, null);
25593 return visitor.results;
25594 }
25595 // TODO(kyliau): Not sure if this check is really needed since we don't have
25596 // any test cases for it.
25597 const element = this.htmlPath.first(Element$1);
25598 if (element &&
25599 getHtmlTagDefinition(element.name).getContentType() !== TagContentType.PARSABLE_DATA) {
25600 return [];
25601 }
25602 // This is to account for cases like <h1> <a> text | </h1> where the
25603 // closest element has no closing tag and thus is considered plain text.
25604 const results = voidElementAttributeCompletions(this.templateInfo, this.htmlPath);
25605 if (results.length) {
25606 return results;
25607 }
25608 return elementCompletions(this.templateInfo);
25609 }
25610 visitComment() {
25611 return [];
25612 }
25613 visitExpansion() {
25614 return [];
25615 }
25616 visitExpansionCase() {
25617 return [];
25618 }
25619 }
25620 function attributeCompletions(info, path) {
25621 const attr = path.tail;
25622 const elem = path.parentOf(attr);
25623 if (!(attr instanceof Attribute) || !(elem instanceof Element$1)) {
25624 return [];
25625 }
25626 // TODO: Consider parsing the attrinute name to a proper AST instead of
25627 // matching using regex. This is because the regexp would incorrectly identify
25628 // bind parts for cases like [()|]
25629 // ^ cursor is here
25630 const binding = getBindingDescriptor(attr.name);
25631 if (!binding) {
25632 // This is a normal HTML attribute, not an Angular attribute.
25633 return attributeCompletionsForElement(info, elem.name);
25634 }
25635 const results = [];
25636 const ngAttrs = angularAttributes(info, elem.name);
25637 switch (binding.kind) {
25638 case ATTR.KW_MICROSYNTAX:
25639 // template reference attribute: *attrName
25640 results.push(...ngAttrs.templateRefs);
25641 break;
25642 case ATTR.KW_BIND:
25643 case ATTR.IDENT_PROPERTY:
25644 // property binding via bind- or []
25645 results.push(...propertyNames(elem.name), ...ngAttrs.inputs);
25646 break;
25647 case ATTR.KW_ON:
25648 case ATTR.IDENT_EVENT:
25649 // event binding via on- or ()
25650 results.push(...eventNames(elem.name), ...ngAttrs.outputs);
25651 break;
25652 case ATTR.KW_BINDON:
25653 case ATTR.IDENT_BANANA_BOX:
25654 // banana-in-a-box binding via bindon- or [()]
25655 results.push(...ngAttrs.bananas);
25656 break;
25657 }
25658 return results.map(name => {
25659 return {
25660 name,
25661 kind: CompletionKind.ATTRIBUTE,
25662 sortText: name,
25663 };
25664 });
25665 }
25666 function attributeCompletionsForElement(info, elementName) {
25667 const results = [];
25668 if (info.template instanceof InlineTemplate) {
25669 // Provide HTML attributes completion only for inline templates
25670 for (const name of attributeNames(elementName)) {
25671 results.push({
25672 name,
25673 kind: CompletionKind.HTML_ATTRIBUTE,
25674 sortText: name,
25675 });
25676 }
25677 }
25678 // Add Angular attributes
25679 const ngAttrs = angularAttributes(info, elementName);
25680 for (const name of ngAttrs.others) {
25681 results.push({
25682 name,
25683 kind: CompletionKind.ATTRIBUTE,
25684 sortText: name,
25685 });
25686 }
25687 return results;
25688 }
25689 /**
25690 * Provide completions to the RHS of an attribute, which is of the form
25691 * LHS="RHS". The template path is computed from the specified `info` whereas
25692 * the context is determined from the specified `htmlPath`.
25693 * @param info Object that contains the template AST
25694 * @param htmlPath Path to the HTML node
25695 */
25696 function attributeValueCompletions(info, htmlPath) {
25697 // Find the corresponding Template AST path.
25698 const templatePath = findTemplateAstAt(info.templateAst, htmlPath.position);
25699 const visitor = new ExpressionVisitor(info, htmlPath.position, () => {
25700 const dinfo = diagnosticInfoFromTemplateInfo(info);
25701 return getExpressionScope(dinfo, templatePath);
25702 });
25703 if (templatePath.tail instanceof AttrAst ||
25704 templatePath.tail instanceof BoundElementPropertyAst ||
25705 templatePath.tail instanceof BoundEventAst) {
25706 templatePath.tail.visit(visitor, null);
25707 return visitor.results;
25708 }
25709 // In order to provide accurate attribute value completion, we need to know
25710 // what the LHS is, and construct the proper AST if it is missing.
25711 const htmlAttr = htmlPath.tail;
25712 const binding = getBindingDescriptor(htmlAttr.name);
25713 if (binding && binding.kind === ATTR.KW_REF) {
25714 let refAst;
25715 let elemAst;
25716 if (templatePath.tail instanceof ReferenceAst) {
25717 refAst = templatePath.tail;
25718 const parent = templatePath.parentOf(refAst);
25719 if (parent instanceof ElementAst) {
25720 elemAst = parent;
25721 }
25722 }
25723 else if (templatePath.tail instanceof ElementAst) {
25724 refAst = new ReferenceAst(htmlAttr.name, null, htmlAttr.value, htmlAttr.valueSpan);
25725 elemAst = templatePath.tail;
25726 }
25727 if (refAst && elemAst) {
25728 refAst.visit(visitor, elemAst);
25729 }
25730 }
25731 else {
25732 // HtmlAst contains the `Attribute` node, however the corresponding `AttrAst`
25733 // node is missing from the TemplateAst.
25734 const attrAst = new AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan);
25735 attrAst.visit(visitor, null);
25736 }
25737 return visitor.results;
25738 }
25739 function elementCompletions(info) {
25740 const results = [...ANGULAR_ELEMENTS];
25741 if (info.template instanceof InlineTemplate) {
25742 // Provide HTML elements completion only for inline templates
25743 results.push(...HTML_ELEMENTS);
25744 }
25745 // Collect the elements referenced by the selectors
25746 const components = new Set();
25747 for (const selector of getSelectors(info).selectors) {
25748 const name = selector.element;
25749 if (name && !components.has(name)) {
25750 components.add(name);
25751 results.push({
25752 name,
25753 kind: CompletionKind.COMPONENT,
25754 sortText: name,
25755 });
25756 }
25757 }
25758 return results;
25759 }
25760 // There is a special case of HTML where text that contains a unclosed tag is treated as
25761 // text. For exaple '<h1> Some <a text </h1>' produces a text nodes inside of the H1
25762 // element "Some <a text". We, however, want to treat this as if the user was requesting
25763 // the attributes of an "a" element, not requesting completion in the a text element. This
25764 // code checks for this case and returns element completions if it is detected or undefined
25765 // if it is not.
25766 function voidElementAttributeCompletions(info, path) {
25767 const tail = path.tail;
25768 if (tail instanceof Text$2) {
25769 const match = tail.value.match(/<(\w(\w|\d|-)*:)?(\w(\w|\d|-)*)\s/);
25770 // The position must be after the match, otherwise we are still in a place where elements
25771 // are expected (such as `<|a` or `<a|`; we only want attributes for `<a |` or after).
25772 if (match &&
25773 path.position >= (match.index || 0) + match[0].length + tail.sourceSpan.start.offset) {
25774 return attributeCompletionsForElement(info, match[3]);
25775 }
25776 }
25777 return [];
25778 }
25779 class ExpressionVisitor extends NullTemplateVisitor {
25780 constructor(info, position, getExpressionScope) {
25781 super();
25782 this.info = info;
25783 this.position = position;
25784 this.getExpressionScope = getExpressionScope;
25785 this.completions = new Map();
25786 }
25787 get results() {
25788 return Array.from(this.completions.values());
25789 }
25790 visitDirectiveProperty(ast) {
25791 this.processExpressionCompletions(ast.value);
25792 }
25793 visitElementProperty(ast) {
25794 this.processExpressionCompletions(ast.value);
25795 }
25796 visitEvent(ast) {
25797 this.processExpressionCompletions(ast.handler);
25798 }
25799 visitElement() {
25800 // no-op for now
25801 }
25802 visitAttr(ast) {
25803 const binding = getBindingDescriptor(ast.name);
25804 if (binding && binding.kind === ATTR.KW_MICROSYNTAX) {
25805 // This a template binding given by micro syntax expression.
25806 // First, verify the attribute consists of some binding we can give completions for.
25807 // The sourceSpan of AttrAst points to the RHS of the attribute
25808 const templateKey = binding.name;
25809 const templateValue = ast.sourceSpan.toString();
25810 const templateUrl = ast.sourceSpan.start.file.url;
25811 // TODO(kyliau): We are unable to determine the absolute offset of the key
25812 // but it is okay here, because we are only looking at the RHS of the attr
25813 const absKeyOffset = 0;
25814 const absValueOffset = ast.sourceSpan.start.offset;
25815 const { templateBindings } = this.info.expressionParser.parseTemplateBindings(templateKey, templateValue, templateUrl, absKeyOffset, absValueOffset);
25816 // Find the nearest template binding to the position.
25817 const lastBindingEnd = templateBindings.length > 0 &&
25818 templateBindings[templateBindings.length - 1].sourceSpan.end;
25819 const normalizedPositionToBinding = lastBindingEnd && this.position > lastBindingEnd ? lastBindingEnd : this.position;
25820 const templateBinding = templateBindings.find(b => inSpan(normalizedPositionToBinding, b.sourceSpan));
25821 if (!templateBinding) {
25822 return;
25823 }
25824 this.microSyntaxInAttributeValue(ast, templateBinding);
25825 }
25826 else {
25827 const expressionAst = this.info.expressionParser.parseBinding(ast.value, ast.sourceSpan.toString(), ast.sourceSpan.start.offset);
25828 this.processExpressionCompletions(expressionAst);
25829 }
25830 }
25831 visitReference(_ast, context) {
25832 context.directives.forEach(dir => {
25833 const { exportAs } = dir.directive;
25834 if (exportAs) {
25835 this.completions.set(exportAs, { name: exportAs, kind: CompletionKind.REFERENCE, sortText: exportAs });
25836 }
25837 });
25838 }
25839 visitBoundText(ast) {
25840 if (inSpan(this.position, ast.value.sourceSpan)) {
25841 const completions = getExpressionCompletions(this.getExpressionScope(), ast.value, this.position, this.info.template);
25842 if (completions) {
25843 this.addSymbolsToCompletions(completions);
25844 }
25845 }
25846 }
25847 processExpressionCompletions(value) {
25848 const symbols = getExpressionCompletions(this.getExpressionScope(), value, this.position, this.info.template);
25849 if (symbols) {
25850 this.addSymbolsToCompletions(symbols);
25851 }
25852 }
25853 addSymbolsToCompletions(symbols) {
25854 for (const s of symbols) {
25855 if (s.name.startsWith('__') || !s.public || this.completions.has(s.name)) {
25856 continue;
25857 }
25858 // The pipe method should not include parentheses.
25859 // e.g. {{ value_expression | slice : start [ : end ] }}
25860 const shouldInsertParentheses = s.callable && s.kind !== CompletionKind.PIPE;
25861 this.completions.set(s.name, {
25862 name: s.name,
25863 kind: s.kind,
25864 sortText: s.name,
25865 insertText: shouldInsertParentheses ? `${s.name}()` : s.name,
25866 });
25867 }
25868 }
25869 /**
25870 * This method handles the completions of attribute values for directives that
25871 * support the microsyntax format. Examples are *ngFor and *ngIf.
25872 * These directives allows declaration of "let" variables, adds context-specific
25873 * symbols like $implicit, index, count, among other behaviors.
25874 * For a complete description of such format, see
25875 * https://angular.io/guide/structural-directives#asterisk
25876 *
25877 * @param attr descriptor for attribute name and value pair
25878 * @param binding template binding for the expression in the attribute
25879 */
25880 microSyntaxInAttributeValue(attr, binding) {
25881 var _a;
25882 const key = attr.name.substring(1); // remove leading asterisk
25883 // Find the selector - eg ngFor, ngIf, etc
25884 const selectorInfo = getSelectors(this.info);
25885 const selector = selectorInfo.selectors.find(s => {
25886 // attributes are listed in (attribute, value) pairs
25887 for (let i = 0; i < s.attrs.length; i += 2) {
25888 if (s.attrs[i] === key) {
25889 return true;
25890 }
25891 }
25892 });
25893 if (!selector) {
25894 return;
25895 }
25896 const valueRelativePosition = this.position - attr.sourceSpan.start.offset;
25897 if (binding instanceof VariableBinding) {
25898 // TODO(kyliau): With expression sourceSpan we shouldn't have to search
25899 // the attribute value string anymore. Just check if position is in the
25900 // expression source span.
25901 const equalLocation = attr.value.indexOf('=');
25902 if (equalLocation > 0 && valueRelativePosition > equalLocation) {
25903 // We are after the '=' in a let clause. The valid values here are the members of the
25904 // template reference's type parameter.
25905 const directiveMetadata = selectorInfo.map.get(selector);
25906 if (directiveMetadata) {
25907 const contextTable = this.info.template.query.getTemplateContext(directiveMetadata.type.reference);
25908 if (contextTable) {
25909 // This adds symbols like $implicit, index, count, etc.
25910 this.addSymbolsToCompletions(contextTable.values());
25911 return;
25912 }
25913 }
25914 }
25915 }
25916 else if (binding instanceof ExpressionBinding) {
25917 if (inSpan(this.position, (_a = binding.value) === null || _a === void 0 ? void 0 : _a.ast.sourceSpan)) {
25918 this.processExpressionCompletions(binding.value.ast);
25919 return;
25920 }
25921 else if (!binding.value && this.position > binding.key.span.end) {
25922 // No expression is defined for the value of the key expression binding, but the cursor is
25923 // in a location where the expression would be defined. This can happen in a case like
25924 // let i of |
25925 // ^-- cursor
25926 // In this case, backfill the value to be an empty expression and retrieve completions.
25927 this.processExpressionCompletions(new EmptyExpr(new ParseSpan(valueRelativePosition, valueRelativePosition), new AbsoluteSourceSpan(this.position, this.position)));
25928 return;
25929 }
25930 }
25931 }
25932 }
25933 /**
25934 * Return all Angular-specific attributes for the element with `elementName`.
25935 * @param info
25936 * @param elementName
25937 */
25938 function angularAttributes(info, elementName) {
25939 const { selectors, map: selectorMap } = getSelectors(info);
25940 const templateRefs = new Set();
25941 const inputs = new Set();
25942 const outputs = new Set();
25943 const bananas = new Set();
25944 const others = new Set();
25945 for (const selector of selectors) {
25946 if (selector.element && selector.element !== elementName) {
25947 continue;
25948 }
25949 const summary = selectorMap.get(selector);
25950 const hasTemplateRef = isStructuralDirective(summary.type);
25951 // attributes are listed in (attribute, value) pairs
25952 for (let i = 0; i < selector.attrs.length; i += 2) {
25953 const attr = selector.attrs[i];
25954 if (hasTemplateRef) {
25955 templateRefs.add(attr);
25956 }
25957 else {
25958 others.add(attr);
25959 }
25960 }
25961 for (const input of Object.values(summary.inputs)) {
25962 inputs.add(input);
25963 }
25964 for (const output of Object.values(summary.outputs)) {
25965 outputs.add(output);
25966 }
25967 }
25968 for (const name of inputs) {
25969 // Add banana-in-a-box syntax
25970 // https://angular.io/guide/template-syntax#two-way-binding-
25971 if (outputs.has(`${name}Change`)) {
25972 bananas.add(name);
25973 }
25974 }
25975 return { templateRefs, inputs, outputs, bananas, others };
25976 }
25977
25978 /**
25979 * @license
25980 * Copyright Google LLC All Rights Reserved.
25981 *
25982 * Use of this source code is governed by an MIT-style license that can be
25983 * found in the LICENSE file at https://angular.io/license
25984 */
25985 /**
25986 * Traverses a template AST and locates symbol(s) at a specified position.
25987 * @param info template AST information set
25988 * @param position location to locate symbols at
25989 */
25990 function locateSymbols(info, position) {
25991 const templatePosition = position - info.template.span.start;
25992 // TODO: update `findTemplateAstAt` to use absolute positions.
25993 const path = findTemplateAstAt(info.templateAst, templatePosition);
25994 const attribute = findAttribute(info, position);
25995 if (!path.tail)
25996 return [];
25997 const narrowest = spanOf(path.tail);
25998 const toVisit = [];
25999 for (let node = path.tail; node && isNarrower(spanOf(node.sourceSpan), narrowest); node = path.parentOf(node)) {
26000 toVisit.push(node);
26001 }
26002 // For the structural directive, only care about the last template AST.
26003 if (attribute === null || attribute === void 0 ? void 0 : attribute.name.startsWith('*')) {
26004 toVisit.splice(0, toVisit.length - 1);
26005 }
26006 return toVisit.map(ast => locateSymbol(ast, path, info))
26007 .filter((sym) => sym !== undefined);
26008 }
26009 /**
26010 * Visits a template node and locates the symbol in that node at a path position.
26011 * @param ast template AST node to visit
26012 * @param path non-empty set of narrowing AST nodes at a position
26013 * @param info template AST information set
26014 */
26015 function locateSymbol(ast, path, info) {
26016 const templatePosition = path.position;
26017 const position = templatePosition + info.template.span.start;
26018 let symbol;
26019 let span;
26020 let staticSymbol;
26021 const attributeValueSymbol = (ast) => {
26022 const attribute = findAttribute(info, position);
26023 if (attribute) {
26024 if (inSpan(templatePosition, spanOf(attribute.valueSpan))) {
26025 let result;
26026 if (attribute.name.startsWith('*')) {
26027 result = getSymbolInMicrosyntax(info, path, attribute);
26028 }
26029 else {
26030 const dinfo = diagnosticInfoFromTemplateInfo(info);
26031 const scope = getExpressionScope(dinfo, path);
26032 result = getExpressionSymbol(scope, ast, templatePosition, info.template);
26033 }
26034 if (result) {
26035 symbol = result.symbol;
26036 span = offsetSpan(result.span, attribute.valueSpan.start.offset);
26037 }
26038 return true;
26039 }
26040 }
26041 return false;
26042 };
26043 ast.visit({
26044 visitNgContent(_ast) { },
26045 visitEmbeddedTemplate(_ast) { },
26046 visitElement(ast) {
26047 const component = ast.directives.find(d => d.directive.isComponent);
26048 if (component) {
26049 // Need to cast because 'reference' is typed as any
26050 staticSymbol = component.directive.type.reference;
26051 symbol = info.template.query.getTypeSymbol(staticSymbol);
26052 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.COMPONENT);
26053 span = spanOf(ast);
26054 }
26055 else {
26056 // Find a directive that matches the element name
26057 const directive = ast.directives.find(d => d.directive.selector != null && d.directive.selector.indexOf(ast.name) >= 0);
26058 if (directive) {
26059 // Need to cast because 'reference' is typed as any
26060 staticSymbol = directive.directive.type.reference;
26061 symbol = info.template.query.getTypeSymbol(staticSymbol);
26062 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE);
26063 span = spanOf(ast);
26064 }
26065 }
26066 },
26067 visitReference(ast) {
26068 symbol = ast.value && info.template.query.getTypeSymbol(tokenReference(ast.value));
26069 span = spanOf(ast);
26070 },
26071 visitVariable(_ast) { },
26072 visitEvent(ast) {
26073 if (!attributeValueSymbol(ast.handler)) {
26074 symbol = findOutputBinding(ast, path, info.template.query);
26075 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.EVENT);
26076 span = spanOf(ast);
26077 }
26078 },
26079 visitElementProperty(ast) {
26080 attributeValueSymbol(ast.value);
26081 },
26082 visitAttr(ast) {
26083 const element = path.first(ElementAst);
26084 if (!element)
26085 return;
26086 // Create a mapping of all directives applied to the element from their selectors.
26087 const matcher = new SelectorMatcher();
26088 for (const dir of element.directives) {
26089 if (!dir.directive.selector)
26090 continue;
26091 matcher.addSelectables(CssSelector.parse(dir.directive.selector), dir);
26092 }
26093 // See if this attribute matches the selector of any directive on the element.
26094 const attributeSelector = `[${ast.name}=${ast.value}]`;
26095 const parsedAttribute = CssSelector.parse(attributeSelector);
26096 if (!parsedAttribute.length)
26097 return;
26098 matcher.match(parsedAttribute[0], (_, { directive }) => {
26099 // Need to cast because 'reference' is typed as any
26100 staticSymbol = directive.type.reference;
26101 symbol = info.template.query.getTypeSymbol(staticSymbol);
26102 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE);
26103 span = spanOf(ast);
26104 });
26105 },
26106 visitBoundText(ast) {
26107 const expressionPosition = templatePosition - ast.sourceSpan.start.offset;
26108 if (inSpan(expressionPosition, ast.value.span)) {
26109 const dinfo = diagnosticInfoFromTemplateInfo(info);
26110 const scope = getExpressionScope(dinfo, path);
26111 const result = getExpressionSymbol(scope, ast.value, templatePosition, info.template);
26112 if (result) {
26113 symbol = result.symbol;
26114 span = offsetSpan(result.span, ast.sourceSpan.start.offset);
26115 }
26116 }
26117 },
26118 visitText(_ast) { },
26119 visitDirective(ast) {
26120 // Need to cast because 'reference' is typed as any
26121 staticSymbol = ast.directive.type.reference;
26122 symbol = info.template.query.getTypeSymbol(staticSymbol);
26123 span = spanOf(ast);
26124 },
26125 visitDirectiveProperty(ast) {
26126 if (!attributeValueSymbol(ast.value)) {
26127 const directive = findParentOfBinding(info.templateAst, ast, templatePosition);
26128 const attribute = findAttribute(info, position);
26129 if (directive && attribute) {
26130 if (attribute.name.startsWith('*')) {
26131 const compileTypeSummary = directive.directive;
26132 symbol = info.template.query.getTypeSymbol(compileTypeSummary.type.reference);
26133 symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE);
26134 // Use 'attribute.sourceSpan' instead of the directive's,
26135 // because the span of the directive is the whole opening tag of an element.
26136 span = spanOf(attribute.sourceSpan);
26137 }
26138 else {
26139 symbol = findInputBinding(info, ast.templateName, directive);
26140 span = spanOf(ast);
26141 }
26142 }
26143 }
26144 }
26145 }, null);
26146 if (symbol && span) {
26147 const { start, end } = offsetSpan(span, info.template.span.start);
26148 return {
26149 symbol,
26150 span: tss.createTextSpanFromBounds(start, end),
26151 staticSymbol,
26152 };
26153 }
26154 }
26155 // Get the symbol in microsyntax at template position.
26156 function getSymbolInMicrosyntax(info, path, attribute) {
26157 var _a;
26158 if (!attribute.valueSpan) {
26159 return;
26160 }
26161 const absValueOffset = attribute.valueSpan.start.offset;
26162 let result;
26163 const { templateBindings } = info.expressionParser.parseTemplateBindings(attribute.name, attribute.value, attribute.sourceSpan.toString(), attribute.sourceSpan.start.offset, attribute.valueSpan.start.offset);
26164 // Find the symbol that contains the position.
26165 for (const tb of templateBindings) {
26166 if (tb instanceof VariableBinding) {
26167 // TODO(kyliau): if binding is variable we should still look for the value
26168 // of the key. For example, "let i=index" => "index" should point to
26169 // NgForOfContext.index
26170 continue;
26171 }
26172 if (inSpan(path.position, (_a = tb.value) === null || _a === void 0 ? void 0 : _a.ast.sourceSpan)) {
26173 const dinfo = diagnosticInfoFromTemplateInfo(info);
26174 const scope = getExpressionScope(dinfo, path);
26175 result = getExpressionSymbol(scope, tb.value, path.position, info.template);
26176 }
26177 else if (inSpan(path.position, tb.sourceSpan)) {
26178 const template = path.first(EmbeddedTemplateAst);
26179 if (template) {
26180 // One element can only have one template binding.
26181 const directiveAst = template.directives[0];
26182 if (directiveAst) {
26183 const symbol = findInputBinding(info, tb.key.source.substring(1), directiveAst);
26184 if (symbol) {
26185 result = {
26186 symbol,
26187 // the span here has to be relative to the start of the template
26188 // value so deduct the absolute offset.
26189 // TODO(kyliau): Use absolute source span throughout completions.
26190 span: offsetSpan(tb.key.span, -absValueOffset),
26191 };
26192 }
26193 }
26194 }
26195 }
26196 }
26197 return result;
26198 }
26199 function findAttribute(info, position) {
26200 const templatePosition = position - info.template.span.start;
26201 const path = getPathToNodeAtPosition(info.htmlAst, templatePosition);
26202 return path.first(Attribute);
26203 }
26204 // TODO: remove this function after the path includes 'DirectiveAst'.
26205 // Find the directive that corresponds to the specified 'binding'
26206 // at the specified 'position' in the 'ast'.
26207 function findParentOfBinding(ast, binding, position) {
26208 let res;
26209 const visitor = new class extends RecursiveTemplateAstVisitor {
26210 visit(ast) {
26211 const span = spanOf(ast);
26212 if (!inSpan(position, span)) {
26213 // Returning a value here will result in the children being skipped.
26214 return true;
26215 }
26216 }
26217 visitEmbeddedTemplate(ast, context) {
26218 return this.visitChildren(context, visit => {
26219 visit(ast.directives);
26220 visit(ast.children);
26221 });
26222 }
26223 visitElement(ast, context) {
26224 return this.visitChildren(context, visit => {
26225 visit(ast.directives);
26226 visit(ast.children);
26227 });
26228 }
26229 visitDirective(ast) {
26230 const result = this.visitChildren(ast, visit => {
26231 visit(ast.inputs);
26232 });
26233 return result;
26234 }
26235 visitDirectiveProperty(ast, context) {
26236 if (ast === binding) {
26237 res = context;
26238 }
26239 }
26240 };
26241 templateVisitAll(visitor, ast);
26242 return res;
26243 }
26244 // Find the symbol of input binding in 'directiveAst' by 'name'.
26245 function findInputBinding(info, name, directiveAst) {
26246 const invertedInput = invertMap(directiveAst.directive.inputs);
26247 const fieldName = invertedInput[name];
26248 if (fieldName) {
26249 const classSymbol = info.template.query.getTypeSymbol(directiveAst.directive.type.reference);
26250 if (classSymbol) {
26251 return classSymbol.members().get(fieldName);
26252 }
26253 }
26254 }
26255 /**
26256 * Wrap a symbol and change its kind to component.
26257 */
26258 class OverrideKindSymbol {
26259 constructor(sym, kindOverride) {
26260 this.sym = sym;
26261 this.kind = kindOverride;
26262 }
26263 get name() {
26264 return this.sym.name;
26265 }
26266 get language() {
26267 return this.sym.language;
26268 }
26269 get type() {
26270 return this.sym.type;
26271 }
26272 get container() {
26273 return this.sym.container;
26274 }
26275 get public() {
26276 return this.sym.public;
26277 }
26278 get callable() {
26279 return this.sym.callable;
26280 }
26281 get nullable() {
26282 return this.sym.nullable;
26283 }
26284 get definition() {
26285 return this.sym.definition;
26286 }
26287 get documentation() {
26288 return this.sym.documentation;
26289 }
26290 members() {
26291 return this.sym.members();
26292 }
26293 signatures() {
26294 return this.sym.signatures();
26295 }
26296 selectSignature(types) {
26297 return this.sym.selectSignature(types);
26298 }
26299 indexed(argument) {
26300 return this.sym.indexed(argument);
26301 }
26302 typeArguments() {
26303 return this.sym.typeArguments();
26304 }
26305 }
26306
26307 /**
26308 * @license
26309 * Copyright Google LLC All Rights Reserved.
26310 *
26311 * Use of this source code is governed by an MIT-style license that can be
26312 * found in the LICENSE file at https://angular.io/license
26313 */
26314 /**
26315 * Return metadata about `node` if it looks like an Angular directive class.
26316 * In this case, potential matches are `@NgModule`, `@Component`, `@Directive`,
26317 * `@Pipe`, etc.
26318 * These class declarations all share some common attributes, namely their
26319 * decorator takes exactly one parameter and the parameter must be an object
26320 * literal.
26321 *
26322 * For example,
26323 * v---------- `decoratorId`
26324 * @NgModule({ <
26325 * declarations: [], < classDecln-al
26326 * }) <
26327 * class AppModule {} <
26328 * ^----- `classId`
26329 *
26330 * @param node Potential node that represents an Angular directive.
26331 */
26332 function getDirectiveClassLike(node) {
26333 if (!tss.isClassDeclaration(node) || !node.name || !node.decorators) {
26334 return;
26335 }
26336 for (const d of node.decorators) {
26337 const expr = d.expression;
26338 if (!tss.isCallExpression(expr) || expr.arguments.length !== 1 ||
26339 !tss.isIdentifier(expr.expression)) {
26340 continue;
26341 }
26342 const arg = expr.arguments[0];
26343 if (tss.isObjectLiteralExpression(arg)) {
26344 return {
26345 decoratorId: expr.expression,
26346 classId: node.name,
26347 };
26348 }
26349 }
26350 }
26351 /**
26352 * Finds the value of a property assignment that is nested in a TypeScript node and is of a certain
26353 * type T.
26354 *
26355 * @param startNode node to start searching for nested property assignment from
26356 * @param propName property assignment name
26357 * @param predicate function to verify that a node is of type T.
26358 * @return node property assignment value of type T, or undefined if none is found
26359 */
26360 function findPropertyValueOfType(startNode, propName, predicate) {
26361 if (tss.isPropertyAssignment(startNode) && startNode.name.getText() === propName) {
26362 const { initializer } = startNode;
26363 if (predicate(initializer))
26364 return initializer;
26365 }
26366 return startNode.forEachChild(c => findPropertyValueOfType(c, propName, predicate));
26367 }
26368 /**
26369 * Return the node that most tightly encompass the specified `position`.
26370 * @param node
26371 * @param position
26372 */
26373 function findTightestNode(node, position) {
26374 if (node.getStart() <= position && position < node.getEnd()) {
26375 return node.forEachChild(c => findTightestNode(c, position)) || node;
26376 }
26377 }
26378 /**
26379 * Returns a property assignment from the assignment value if the property name
26380 * matches the specified `key`, or `undefined` if there is no match.
26381 */
26382 function getPropertyAssignmentFromValue(value, key) {
26383 const propAssignment = value.parent;
26384 if (!propAssignment || !tss.isPropertyAssignment(propAssignment) ||
26385 propAssignment.name.getText() !== key) {
26386 return;
26387 }
26388 return propAssignment;
26389 }
26390 /**
26391 * Given a decorator property assignment, return the ClassDeclaration node that corresponds to the
26392 * directive class the property applies to.
26393 * If the property assignment is not on a class decorator, no declaration is returned.
26394 *
26395 * For example,
26396 *
26397 * @Component({
26398 * template: '<div></div>'
26399 * ^^^^^^^^^^^^^^^^^^^^^^^---- property assignment
26400 * })
26401 * class AppComponent {}
26402 * ^---- class declaration node
26403 *
26404 * @param propAsgnNode property assignment
26405 */
26406 function getClassDeclFromDecoratorProp(propAsgnNode) {
26407 if (!propAsgnNode.parent || !tss.isObjectLiteralExpression(propAsgnNode.parent)) {
26408 return;
26409 }
26410 const objLitExprNode = propAsgnNode.parent;
26411 if (!objLitExprNode.parent || !tss.isCallExpression(objLitExprNode.parent)) {
26412 return;
26413 }
26414 const callExprNode = objLitExprNode.parent;
26415 if (!callExprNode.parent || !tss.isDecorator(callExprNode.parent)) {
26416 return;
26417 }
26418 const decorator = callExprNode.parent;
26419 if (!decorator.parent || !tss.isClassDeclaration(decorator.parent)) {
26420 return;
26421 }
26422 const classDeclNode = decorator.parent;
26423 return classDeclNode;
26424 }
26425
26426 /**
26427 * @license
26428 * Copyright Google LLC All Rights Reserved.
26429 *
26430 * Use of this source code is governed by an MIT-style license that can be
26431 * found in the LICENSE file at https://angular.io/license
26432 */
26433 /**
26434 * Convert Angular Span to TypeScript TextSpan. Angular Span has 'start' and
26435 * 'end' whereas TS TextSpan has 'start' and 'length'.
26436 * @param span Angular Span
26437 */
26438 function ngSpanToTsTextSpan(span) {
26439 return {
26440 start: span.start,
26441 length: span.end - span.start,
26442 };
26443 }
26444 /**
26445 * Attempts to get the definition of a file whose URL is specified in a property assignment in a
26446 * directive decorator.
26447 * Currently applies to `templateUrl` and `styleUrls` properties.
26448 */
26449 function getUrlFromProperty(urlNode, tsLsHost) {
26450 // Get the property assignment node corresponding to the `templateUrl` or `styleUrls` assignment.
26451 // These assignments are specified differently; `templateUrl` is a string, and `styleUrls` is
26452 // an array of strings:
26453 // {
26454 // templateUrl: './template.ng.html',
26455 // styleUrls: ['./style.css', './other-style.css']
26456 // }
26457 // `templateUrl`'s property assignment can be found from the string literal node;
26458 // `styleUrls`'s property assignment can be found from the array (parent) node.
26459 //
26460 // First search for `templateUrl`.
26461 let asgn = getPropertyAssignmentFromValue(urlNode, 'templateUrl');
26462 if (!asgn) {
26463 // `templateUrl` assignment not found; search for `styleUrls` array assignment.
26464 asgn = getPropertyAssignmentFromValue(urlNode.parent, 'styleUrls');
26465 if (!asgn) {
26466 // Nothing found, bail.
26467 return;
26468 }
26469 }
26470 // If the property assignment is not a property of a class decorator, don't generate definitions
26471 // for it.
26472 if (!getClassDeclFromDecoratorProp(asgn)) {
26473 return;
26474 }
26475 // Extract url path specified by the url node, which is relative to the TypeScript source file
26476 // the url node is defined in.
26477 const url = extractAbsoluteFilePath(urlNode);
26478 // If the file does not exist, bail. It is possible that the TypeScript language service host
26479 // does not have a `fileExists` method, in which case optimistically assume the file exists.
26480 if (tsLsHost.fileExists && !tsLsHost.fileExists(url))
26481 return;
26482 const templateDefinitions = [{
26483 kind: ts.ScriptElementKind.externalModuleName,
26484 name: url,
26485 containerKind: ts.ScriptElementKind.unknown,
26486 containerName: '',
26487 // Reading the template is expensive, so don't provide a preview.
26488 textSpan: { start: 0, length: 0 },
26489 fileName: url,
26490 }];
26491 return {
26492 definitions: templateDefinitions,
26493 textSpan: {
26494 // Exclude opening and closing quotes in the url span.
26495 start: urlNode.getStart() + 1,
26496 length: urlNode.getWidth() - 2,
26497 },
26498 };
26499 }
26500 /**
26501 * Traverse the template AST and look for the symbol located at `position`, then
26502 * return its definition and span of bound text.
26503 * @param info
26504 * @param position
26505 */
26506 function getDefinitionAndBoundSpan(info, position) {
26507 const symbols = locateSymbols(info, position);
26508 if (!symbols.length) {
26509 return;
26510 }
26511 const seen = new Set();
26512 const definitions = [];
26513 for (const symbolInfo of symbols) {
26514 const { symbol } = symbolInfo;
26515 // symbol.definition is really the locations of the symbol. There could be
26516 // more than one. No meaningful info could be provided without any location.
26517 const { kind, name, container, definition: locations } = symbol;
26518 if (!locations || !locations.length) {
26519 continue;
26520 }
26521 const containerKind = container ? container.kind : ts.ScriptElementKind.unknown;
26522 const containerName = container ? container.name : '';
26523 for (const { fileName, span } of locations) {
26524 const textSpan = ngSpanToTsTextSpan(span);
26525 // In cases like two-way bindings, a request for the definitions of an expression may return
26526 // two of the same definition:
26527 // [(ngModel)]="prop"
26528 // ^^^^ -- one definition for the property binding, one for the event binding
26529 // To prune duplicate definitions, tag definitions with unique location signatures and ignore
26530 // definitions whose locations have already been seen.
26531 const signature = `${textSpan.start}:${textSpan.length}@${fileName}`;
26532 if (seen.has(signature))
26533 continue;
26534 definitions.push({
26535 kind: kind,
26536 name,
26537 containerKind,
26538 containerName,
26539 textSpan: ngSpanToTsTextSpan(span),
26540 fileName: fileName,
26541 });
26542 seen.add(signature);
26543 }
26544 }
26545 return {
26546 definitions,
26547 textSpan: symbols[0].span,
26548 };
26549 }
26550 /**
26551 * Gets an Angular-specific definition in a TypeScript source file.
26552 */
26553 function getTsDefinitionAndBoundSpan(sf, position, tsLsHost) {
26554 const node = findTightestNode(sf, position);
26555 if (!node)
26556 return;
26557 switch (node.kind) {
26558 case ts.SyntaxKind.StringLiteral:
26559 case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
26560 // Attempt to extract definition of a URL in a property assignment.
26561 return getUrlFromProperty(node, tsLsHost);
26562 default:
26563 return undefined;
26564 }
26565 }
26566
26567 /**
26568 * @license
26569 * Copyright Google LLC All Rights Reserved.
26570 *
26571 * Use of this source code is governed by an MIT-style license that can be
26572 * found in the LICENSE file at https://angular.io/license
26573 */
26574 /**
26575 * Return diagnostic information for the parsed AST of the template.
26576 * @param ast contains HTML and template AST
26577 */
26578 function getTemplateDiagnostics(ast) {
26579 const { parseErrors, templateAst, htmlAst, template } = ast;
26580 if (parseErrors && parseErrors.length) {
26581 return parseErrors.map(e => {
26582 return {
26583 kind: ts.DiagnosticCategory.Error,
26584 span: offsetSpan(spanOf(e.span), template.span.start),
26585 message: e.msg,
26586 };
26587 });
26588 }
26589 return getTemplateExpressionDiagnostics({
26590 templateAst: templateAst,
26591 htmlAst: htmlAst,
26592 offset: template.span.start,
26593 query: template.query,
26594 members: template.members,
26595 source: ast.template.source,
26596 });
26597 }
26598 /**
26599 * Performs a variety diagnostics on directive declarations.
26600 *
26601 * @param declarations Angular directive declarations
26602 * @param modules NgModules in the project
26603 * @param host TypeScript service host used to perform TypeScript queries
26604 * @return diagnosed errors, if any
26605 */
26606 function getDeclarationDiagnostics(declarations, modules, host) {
26607 const directives = new Set();
26608 for (const ngModule of modules.ngModules) {
26609 for (const directive of ngModule.declaredDirectives) {
26610 directives.add(directive.reference);
26611 }
26612 }
26613 const results = [];
26614 for (const declaration of declarations) {
26615 const { errors, metadata, type, declarationSpan } = declaration;
26616 const sf = host.getSourceFile(type.filePath);
26617 if (!sf) {
26618 host.error(`directive ${type.name} exists but has no source file`);
26619 return [];
26620 }
26621 // TypeScript identifier of the directive declaration annotation (e.g. "Component" or
26622 // "Directive") on a directive class.
26623 const directiveIdentifier = findTightestNode(sf, declarationSpan.start);
26624 if (!directiveIdentifier) {
26625 host.error(`directive ${type.name} exists but has no identifier`);
26626 return [];
26627 }
26628 for (const error of errors) {
26629 results.push({
26630 kind: ts.DiagnosticCategory.Error,
26631 message: error.message,
26632 span: error.span,
26633 });
26634 }
26635 if (!modules.ngModuleByPipeOrDirective.has(declaration.type)) {
26636 results.push(createDiagnostic(declarationSpan, Diagnostic.directive_not_in_module, metadata.isComponent ? 'Component' : 'Directive', type.name));
26637 }
26638 if (metadata.isComponent) {
26639 const { template, templateUrl, styleUrls } = metadata.template;
26640 if (template === null && !templateUrl) {
26641 results.push(createDiagnostic(declarationSpan, Diagnostic.missing_template_and_templateurl, type.name));
26642 }
26643 else if (templateUrl) {
26644 if (template) {
26645 results.push(createDiagnostic(declarationSpan, Diagnostic.both_template_and_templateurl, type.name));
26646 }
26647 // Find templateUrl value from the directive call expression, which is the parent of the
26648 // directive identifier.
26649 //
26650 // TODO: We should create an enum of the various properties a directive can have to use
26651 // instead of string literals. We can then perform a mass migration of all literal usages.
26652 const templateUrlNode = findPropertyValueOfType(directiveIdentifier.parent, 'templateUrl', ts.isLiteralExpression);
26653 if (!templateUrlNode) {
26654 host.error(`templateUrl ${templateUrl} exists but its TypeScript node doesn't`);
26655 return [];
26656 }
26657 results.push(...validateUrls([templateUrlNode], host.tsLsHost));
26658 }
26659 if (styleUrls.length > 0) {
26660 // Find styleUrls value from the directive call expression, which is the parent of the
26661 // directive identifier.
26662 const styleUrlsNode = findPropertyValueOfType(directiveIdentifier.parent, 'styleUrls', ts.isArrayLiteralExpression);
26663 if (!styleUrlsNode) {
26664 host.error(`styleUrls property exists but its TypeScript node doesn't'`);
26665 return [];
26666 }
26667 results.push(...validateUrls(styleUrlsNode.elements, host.tsLsHost));
26668 }
26669 }
26670 }
26671 return results;
26672 }
26673 /**
26674 * Checks that URLs on a directive point to a valid file.
26675 * Note that this diagnostic check may require a filesystem hit, and thus may be slower than other
26676 * checks.
26677 *
26678 * @param urls urls to check for validity
26679 * @param tsLsHost TS LS host used for querying filesystem information
26680 * @return diagnosed url errors, if any
26681 */
26682 function validateUrls(urls, tsLsHost) {
26683 if (!tsLsHost.fileExists) {
26684 return [];
26685 }
26686 const allErrors = [];
26687 // TODO(ayazhafiz): most of this logic can be unified with the logic in
26688 // definitions.ts#getUrlFromProperty. Create a utility function to be used by both.
26689 for (let i = 0; i < urls.length; ++i) {
26690 const urlNode = urls[i];
26691 if (!ts.isStringLiteralLike(urlNode)) {
26692 // If a non-string value is assigned to a URL node (like `templateUrl`), a type error will be
26693 // picked up by the TS Language Server.
26694 continue;
26695 }
26696 const url = extractAbsoluteFilePath(urlNode);
26697 if (tsLsHost.fileExists(url))
26698 continue;
26699 // Exclude opening and closing quotes in the url span.
26700 const urlSpan = { start: urlNode.getStart() + 1, end: urlNode.end - 1 };
26701 allErrors.push(createDiagnostic(urlSpan, Diagnostic.invalid_templateurl));
26702 }
26703 return allErrors;
26704 }
26705 /**
26706 * Return a recursive data structure that chains diagnostic messages.
26707 * @param chain
26708 */
26709 function chainDiagnostics(chain) {
26710 return {
26711 messageText: chain.message,
26712 category: ts.DiagnosticCategory.Error,
26713 code: 0,
26714 next: chain.next ? chain.next.map(chainDiagnostics) : undefined
26715 };
26716 }
26717 /**
26718 * Convert ng.Diagnostic to ts.Diagnostic.
26719 * @param d diagnostic
26720 * @param file
26721 */
26722 function ngDiagnosticToTsDiagnostic(d, file) {
26723 return {
26724 file,
26725 start: d.span.start,
26726 length: d.span.end - d.span.start,
26727 messageText: typeof d.message === 'string' ? d.message : chainDiagnostics(d.message),
26728 category: d.kind,
26729 code: 0,
26730 source: 'ng',
26731 };
26732 }
26733
26734 /**
26735 * @license
26736 * Copyright Google LLC All Rights Reserved.
26737 *
26738 * Use of this source code is governed by an MIT-style license that can be
26739 * found in the LICENSE file at https://angular.io/license
26740 */
26741 /**
26742 * Traverse the template AST and look for the symbol located at `position`, then
26743 * return the corresponding quick info.
26744 * @param info template AST
26745 * @param position location of the symbol
26746 * @param analyzedModules all NgModules in the program.
26747 */
26748 function getTemplateHover(info, position, analyzedModules) {
26749 var _a, _b;
26750 const symbolInfo = locateSymbols(info, position)[0];
26751 if (!symbolInfo) {
26752 return;
26753 }
26754 const { symbol, span, staticSymbol } = symbolInfo;
26755 // The container is either the symbol's container (for example, 'AppComponent'
26756 // is the container of the symbol 'title' in its template) or the NgModule
26757 // that the directive belongs to (the container of AppComponent is AppModule).
26758 let containerName = (_a = symbol.container) === null || _a === void 0 ? void 0 : _a.name;
26759 if (!containerName && staticSymbol) {
26760 // If there is a static symbol then the target is a directive.
26761 const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol);
26762 containerName = ngModule === null || ngModule === void 0 ? void 0 : ngModule.type.reference.name;
26763 }
26764 return createQuickInfo(symbol.name, symbol.kind, span, containerName, (_b = symbol.type) === null || _b === void 0 ? void 0 : _b.name, symbol.documentation);
26765 }
26766 /**
26767 * Get quick info for Angular semantic entities in TypeScript files, like Directives.
26768 * @param position location of the symbol in the source file
26769 * @param declarations All Directive-like declarations in the source file.
26770 * @param analyzedModules all NgModules in the program.
26771 */
26772 function getTsHover(position, declarations, analyzedModules) {
26773 for (const { declarationSpan, metadata } of declarations) {
26774 if (inSpan(position, declarationSpan)) {
26775 const staticSymbol = metadata.type.reference;
26776 const directiveName = staticSymbol.name;
26777 const kind = metadata.isComponent ? 'component' : 'directive';
26778 const textSpan = ts.createTextSpanFromBounds(declarationSpan.start, declarationSpan.end);
26779 const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol);
26780 const moduleName = ngModule === null || ngModule === void 0 ? void 0 : ngModule.type.reference.name;
26781 return createQuickInfo(directiveName, kind, textSpan, moduleName, ts.ScriptElementKind.classElement);
26782 }
26783 }
26784 }
26785 // Reverse mappings of enum would generate strings
26786 const ALIAS_NAME = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.aliasName];
26787 const SYMBOL_INTERFACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.interfaceName];
26788 const SYMBOL_PUNC = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.punctuation];
26789 const SYMBOL_SPACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.space];
26790 const SYMBOL_TEXT = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.text];
26791 /**
26792 * Construct a QuickInfo object taking into account its container and type.
26793 * @param name Name of the QuickInfo target
26794 * @param kind component, directive, pipe, etc.
26795 * @param textSpan span of the target
26796 * @param containerName either the Symbol's container or the NgModule that contains the directive
26797 * @param type user-friendly name of the type
26798 * @param documentation docstring or comment
26799 */
26800 function createQuickInfo(name, kind, textSpan, containerName, type, documentation) {
26801 const containerDisplayParts = containerName ?
26802 [
26803 { text: containerName, kind: SYMBOL_INTERFACE },
26804 { text: '.', kind: SYMBOL_PUNC },
26805 ] :
26806 [];
26807 const typeDisplayParts = type ?
26808 [
26809 { text: ':', kind: SYMBOL_PUNC },
26810 { text: ' ', kind: SYMBOL_SPACE },
26811 { text: type, kind: SYMBOL_INTERFACE },
26812 ] :
26813 [];
26814 return {
26815 kind: kind,
26816 kindModifiers: ts.ScriptElementKindModifier.none,
26817 textSpan: textSpan,
26818 displayParts: [
26819 { text: '(', kind: SYMBOL_PUNC },
26820 { text: kind, kind: SYMBOL_TEXT },
26821 { text: ')', kind: SYMBOL_PUNC },
26822 { text: ' ', kind: SYMBOL_SPACE },
26823 ...containerDisplayParts,
26824 { text: name, kind: SYMBOL_INTERFACE },
26825 ...typeDisplayParts,
26826 ],
26827 documentation,
26828 };
26829 }
26830
26831 /**
26832 * @license
26833 * Copyright Google LLC All Rights Reserved.
26834 *
26835 * Use of this source code is governed by an MIT-style license that can be
26836 * found in the LICENSE file at https://angular.io/license
26837 */
26838 /**
26839 * Create an instance of an Angular `LanguageService`.
26840 *
26841 * @publicApi
26842 */
26843 function createLanguageService(host) {
26844 return new LanguageServiceImpl(host);
26845 }
26846 class LanguageServiceImpl {
26847 constructor(host) {
26848 this.host = host;
26849 }
26850 getSemanticDiagnostics(fileName) {
26851 const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26852 const ngDiagnostics = [];
26853 const templates = this.host.getTemplates(fileName);
26854 for (const template of templates) {
26855 const ast = this.host.getTemplateAst(template);
26856 if (ast) {
26857 ngDiagnostics.push(...getTemplateDiagnostics(ast));
26858 }
26859 }
26860 const declarations = this.host.getDeclarations(fileName);
26861 ngDiagnostics.push(...getDeclarationDiagnostics(declarations, analyzedModules, this.host));
26862 const sourceFile = fileName.endsWith('.ts') ? this.host.getSourceFile(fileName) : undefined;
26863 const tsDiagnostics = ngDiagnostics.map(d => ngDiagnosticToTsDiagnostic(d, sourceFile));
26864 return [...tss.sortAndDeduplicateDiagnostics(tsDiagnostics)];
26865 }
26866 getCompletionsAtPosition(fileName, position, _options) {
26867 this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26868 const ast = this.host.getTemplateAstAtPosition(fileName, position);
26869 if (!ast) {
26870 return;
26871 }
26872 const results = getTemplateCompletions(ast, position);
26873 if (!results || !results.length) {
26874 return;
26875 }
26876 return {
26877 isGlobalCompletion: false,
26878 isMemberCompletion: false,
26879 isNewIdentifierLocation: false,
26880 // Cast CompletionEntry.kind from ng.CompletionKind to ts.ScriptElementKind
26881 entries: results,
26882 };
26883 }
26884 getDefinitionAndBoundSpan(fileName, position) {
26885 this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26886 const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
26887 if (templateInfo) {
26888 return getDefinitionAndBoundSpan(templateInfo, position);
26889 }
26890 // Attempt to get Angular-specific definitions in a TypeScript file, like templates defined
26891 // in a `templateUrl` property.
26892 if (fileName.endsWith('.ts')) {
26893 const sf = this.host.getSourceFile(fileName);
26894 if (sf) {
26895 return getTsDefinitionAndBoundSpan(sf, position, this.host.tsLsHost);
26896 }
26897 }
26898 }
26899 getQuickInfoAtPosition(fileName, position) {
26900 const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
26901 const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
26902 if (templateInfo) {
26903 return getTemplateHover(templateInfo, position, analyzedModules);
26904 }
26905 // Attempt to get Angular-specific hover information in a TypeScript file, the NgModule a
26906 // directive belongs to.
26907 const declarations = this.host.getDeclarations(fileName);
26908 return getTsHover(position, declarations, analyzedModules);
26909 }
26910 getReferencesAtPosition(fileName, position) {
26911 const defAndSpan = this.getDefinitionAndBoundSpan(fileName, position);
26912 if (!(defAndSpan === null || defAndSpan === void 0 ? void 0 : defAndSpan.definitions)) {
26913 return;
26914 }
26915 const { definitions } = defAndSpan;
26916 const tsDef = definitions.find(def => def.fileName.endsWith('.ts'));
26917 if (!tsDef) {
26918 return;
26919 }
26920 return this.host.tsLS.getReferencesAtPosition(tsDef.fileName, tsDef.textSpan.start);
26921 }
26922 }
26923
26924 /**
26925 * @license
26926 * Copyright Google LLC All Rights Reserved.
26927 *
26928 * Use of this source code is governed by an MIT-style license that can be
26929 * found in the LICENSE file at https://angular.io/license
26930 */
26931 function getClosureSafeProperty(objWithPropertyToExtract) {
26932 for (let key in objWithPropertyToExtract) {
26933 if (objWithPropertyToExtract[key] === getClosureSafeProperty) {
26934 return key;
26935 }
26936 }
26937 throw Error('Could not find renamed property on target object.');
26938 }
26939
26940 /**
26941 * @license
26942 * Copyright Google LLC All Rights Reserved.
26943 *
26944 * Use of this source code is governed by an MIT-style license that can be
26945 * found in the LICENSE file at https://angular.io/license
26946 */
26947 function stringify$1(token) {
26948 if (typeof token === 'string') {
26949 return token;
26950 }
26951 if (Array.isArray(token)) {
26952 return '[' + token.map(stringify$1).join(', ') + ']';
26953 }
26954 if (token == null) {
26955 return '' + token;
26956 }
26957 if (token.overriddenName) {
26958 return `${token.overriddenName}`;
26959 }
26960 if (token.name) {
26961 return `${token.name}`;
26962 }
26963 const res = token.toString();
26964 if (res == null) {
26965 return '' + res;
26966 }
26967 const newLineIndex = res.indexOf('\n');
26968 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
26969 }
26970 /**
26971 * Concatenates two strings with separator, allocating new strings only when necessary.
26972 *
26973 * @param before before string.
26974 * @param separator separator string.
26975 * @param after after string.
26976 * @returns concatenated string.
26977 */
26978 function concatStringsWithSpace(before, after) {
26979 return (before == null || before === '') ?
26980 (after === null ? '' : after) :
26981 ((after == null || after === '') ? before : before + ' ' + after);
26982 }
26983
26984 /**
26985 * @license
26986 * Copyright Google LLC All Rights Reserved.
26987 *
26988 * Use of this source code is governed by an MIT-style license that can be
26989 * found in the LICENSE file at https://angular.io/license
26990 */
26991 const __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty });
26992 /**
26993 * Allows to refer to references which are not yet defined.
26994 *
26995 * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
26996 * DI is declared, but not yet defined. It is also used when the `token` which we use when creating
26997 * a query is not yet defined.
26998 *
26999 * @usageNotes
27000 * ### Example
27001 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'}
27002 * @publicApi
27003 */
27004 function forwardRef(forwardRefFn) {
27005 forwardRefFn.__forward_ref__ = forwardRef;
27006 forwardRefFn.toString = function () {
27007 return stringify$1(this());
27008 };
27009 return forwardRefFn;
27010 }
27011 /**
27012 * Lazily retrieves the reference value from a forwardRef.
27013 *
27014 * Acts as the identity function when given a non-forward-ref value.
27015 *
27016 * @usageNotes
27017 * ### Example
27018 *
27019 * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'}
27020 *
27021 * @see `forwardRef`
27022 * @publicApi
27023 */
27024 function resolveForwardRef$1(type) {
27025 return isForwardRef(type) ? type() : type;
27026 }
27027 /** Checks whether a function is wrapped by a `forwardRef`. */
27028 function isForwardRef(fn) {
27029 return typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
27030 fn.__forward_ref__ === forwardRef;
27031 }
27032
27033 /**
27034 * @license
27035 * Copyright Google LLC All Rights Reserved.
27036 *
27037 * Use of this source code is governed by an MIT-style license that can be
27038 * found in the LICENSE file at https://angular.io/license
27039 */
27040 // Base URL for the error details page.
27041 // Keep this value in sync with a similar const in
27042 // `packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts`.
27043 const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors';
27044 class RuntimeError extends Error {
27045 constructor(code, message) {
27046 super(formatRuntimeError(code, message));
27047 this.code = code;
27048 }
27049 }
27050 // Contains a set of error messages that have details guides at angular.io.
27051 // Full list of available error guides can be found at https://angular.io/errors
27052 /* tslint:disable:no-toplevel-property-access */
27053 const RUNTIME_ERRORS_WITH_GUIDES = new Set([
27054 "100" /* EXPRESSION_CHANGED_AFTER_CHECKED */,
27055 "200" /* CYCLIC_DI_DEPENDENCY */,
27056 "201" /* PROVIDER_NOT_FOUND */,
27057 "300" /* MULTIPLE_COMPONENTS_MATCH */,
27058 "301" /* EXPORT_NOT_FOUND */,
27059 "302" /* PIPE_NOT_FOUND */,
27060 ]);
27061 /* tslint:enable:no-toplevel-property-access */
27062 /** Called to format a runtime error */
27063 function formatRuntimeError(code, message) {
27064 const fullCode = code ? `NG0${code}: ` : '';
27065 let errorMessage = `${fullCode}${message}`;
27066 // Some runtime errors are still thrown without `ngDevMode` (for example
27067 // `throwProviderNotFoundError`), so we add `ngDevMode` check here to avoid pulling
27068 // `RUNTIME_ERRORS_WITH_GUIDES` symbol into prod bundles.
27069 // TODO: revisit all instances where `RuntimeError` is thrown and see if `ngDevMode` can be added
27070 // there instead to tree-shake more devmode-only code (and eventually remove `ngDevMode` check
27071 // from this code).
27072 if (ngDevMode && RUNTIME_ERRORS_WITH_GUIDES.has(code)) {
27073 errorMessage = `${errorMessage}. Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/NG0${code}`;
27074 }
27075 return errorMessage;
27076 }
27077
27078 /**
27079 * @license
27080 * Copyright Google LLC All Rights Reserved.
27081 *
27082 * Use of this source code is governed by an MIT-style license that can be
27083 * found in the LICENSE file at https://angular.io/license
27084 */
27085 /**
27086 * Used for stringify render output in Ivy.
27087 * Important! This function is very performance-sensitive and we should
27088 * be extra careful not to introduce megamorphic reads in it.
27089 * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations.
27090 */
27091 function renderStringify(value) {
27092 if (typeof value === 'string')
27093 return value;
27094 if (value == null)
27095 return '';
27096 // Use `String` so that it invokes the `toString` method of the value. Note that this
27097 // appears to be faster than calling `value.toString` (see `render_stringify` benchmark).
27098 return String(value);
27099 }
27100 /**
27101 * Used to stringify a value so that it can be displayed in an error message.
27102 * Important! This function contains a megamorphic read and should only be
27103 * used for error messages.
27104 */
27105 function stringifyForError(value) {
27106 if (typeof value === 'function')
27107 return value.name || value.toString();
27108 if (typeof value === 'object' && value != null && typeof value.type === 'function') {
27109 return value.type.name || value.type.toString();
27110 }
27111 return renderStringify(value);
27112 }
27113
27114 /** Called when directives inject each other (creating a circular dependency) */
27115 function throwCyclicDependencyError(token, path) {
27116 const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
27117 throw new RuntimeError("200" /* CYCLIC_DI_DEPENDENCY */, `Circular dependency in DI detected for ${token}${depPath}`);
27118 }
27119 /** Throws an error when a token is not found in DI. */
27120 function throwProviderNotFoundError(token, injectorName) {
27121 const injectorDetails = injectorName ? ` in ${injectorName}` : '';
27122 throw new RuntimeError("201" /* PROVIDER_NOT_FOUND */, `No provider for ${stringifyForError(token)} found${injectorDetails}`);
27123 }
27124
27125 /**
27126 * @license
27127 * Copyright Google LLC All Rights Reserved.
27128 *
27129 * Use of this source code is governed by an MIT-style license that can be
27130 * found in the LICENSE file at https://angular.io/license
27131 */
27132 function assertNumber(actual, msg) {
27133 if (!(typeof actual === 'number')) {
27134 throwError(msg, typeof actual, 'number', '===');
27135 }
27136 }
27137 function assertString(actual, msg) {
27138 if (!(typeof actual === 'string')) {
27139 throwError(msg, actual === null ? 'null' : typeof actual, 'string', '===');
27140 }
27141 }
27142 function assertFunction(actual, msg) {
27143 if (!(typeof actual === 'function')) {
27144 throwError(msg, actual === null ? 'null' : typeof actual, 'function', '===');
27145 }
27146 }
27147 function assertEqual(actual, expected, msg) {
27148 if (!(actual == expected)) {
27149 throwError(msg, actual, expected, '==');
27150 }
27151 }
27152 function assertNotEqual(actual, expected, msg) {
27153 if (!(actual != expected)) {
27154 throwError(msg, actual, expected, '!=');
27155 }
27156 }
27157 function assertSame(actual, expected, msg) {
27158 if (!(actual === expected)) {
27159 throwError(msg, actual, expected, '===');
27160 }
27161 }
27162 function assertNotSame(actual, expected, msg) {
27163 if (!(actual !== expected)) {
27164 throwError(msg, actual, expected, '!==');
27165 }
27166 }
27167 function assertLessThan(actual, expected, msg) {
27168 if (!(actual < expected)) {
27169 throwError(msg, actual, expected, '<');
27170 }
27171 }
27172 function assertGreaterThan(actual, expected, msg) {
27173 if (!(actual > expected)) {
27174 throwError(msg, actual, expected, '>');
27175 }
27176 }
27177 function assertGreaterThanOrEqual(actual, expected, msg) {
27178 if (!(actual >= expected)) {
27179 throwError(msg, actual, expected, '>=');
27180 }
27181 }
27182 function assertDefined(actual, msg) {
27183 if (actual == null) {
27184 throwError(msg, actual, null, '!=');
27185 }
27186 }
27187 function throwError(msg, actual, expected, comparison) {
27188 throw new Error(`ASSERTION ERROR: ${msg}` +
27189 (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
27190 }
27191 function assertDomNode(node) {
27192 // If we're in a worker, `Node` will not be defined.
27193 if (!(typeof Node !== 'undefined' && node instanceof Node) &&
27194 !(typeof node === 'object' && node != null &&
27195 node.constructor.name === 'WebWorkerRenderNode')) {
27196 throwError(`The provided value must be an instance of a DOM Node but got ${stringify$1(node)}`);
27197 }
27198 }
27199 function assertIndexInRange(arr, index) {
27200 assertDefined(arr, 'Array must be defined.');
27201 const maxLen = arr.length;
27202 if (index < 0 || index >= maxLen) {
27203 throwError(`Index expected to be less than ${maxLen} but got ${index}`);
27204 }
27205 }
27206
27207 /**
27208 * @license
27209 * Copyright Google LLC All Rights Reserved.
27210 *
27211 * Use of this source code is governed by an MIT-style license that can be
27212 * found in the LICENSE file at https://angular.io/license
27213 */
27214 /**
27215 * Construct an `InjectableDef` which defines how a token will be constructed by the DI system, and
27216 * in which injectors (if any) it will be available.
27217 *
27218 * This should be assigned to a static `ɵprov` field on a type, which will then be an
27219 * `InjectableType`.
27220 *
27221 * Options:
27222 * * `providedIn` determines which injectors will include the injectable, by either associating it
27223 * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
27224 * provided in the `'root'` injector, which will be the application-level injector in most apps.
27225 * * `factory` gives the zero argument function which will create an instance of the injectable.
27226 * The factory can call `inject` to access the `Injector` and request injection of dependencies.
27227 *
27228 * @codeGenApi
27229 * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
27230 */
27231 function ɵɵdefineInjectable(opts) {
27232 return {
27233 token: opts.token,
27234 providedIn: opts.providedIn || null,
27235 factory: opts.factory,
27236 value: undefined,
27237 };
27238 }
27239 /**
27240 * Construct an `InjectorDef` which configures an injector.
27241 *
27242 * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
27243 * `InjectorType`.
27244 *
27245 * Options:
27246 *
27247 * * `factory`: an `InjectorType` is an instantiable type, so a zero argument `factory` function to
27248 * create the type must be provided. If that factory function needs to inject arguments, it can
27249 * use the `inject` function.
27250 * * `providers`: an optional array of providers to add to the injector. Each provider must
27251 * either have a factory or point to a type which has a `ɵprov` static property (the
27252 * type must be an `InjectableType`).
27253 * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
27254 * whose providers will also be added to the injector. Locally provided types will override
27255 * providers from imports.
27256 *
27257 * @codeGenApi
27258 */
27259 function ɵɵdefineInjector(options) {
27260 return {
27261 factory: options.factory,
27262 providers: options.providers || [],
27263 imports: options.imports || [],
27264 };
27265 }
27266 /**
27267 * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
27268 * inherited value.
27269 *
27270 * @param type A type which may have its own (non-inherited) `ɵprov`.
27271 */
27272 function getInjectableDef(type) {
27273 return getOwnDefinition(type, NG_PROV_DEF) || getOwnDefinition(type, NG_INJECTABLE_DEF);
27274 }
27275 /**
27276 * Return definition only if it is defined directly on `type` and is not inherited from a base
27277 * class of `type`.
27278 */
27279 function getOwnDefinition(type, field) {
27280 return type.hasOwnProperty(field) ? type[field] : null;
27281 }
27282 const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty });
27283 const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty });
27284 // We need to keep these around so we can read off old defs if new defs are unavailable
27285 const NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty });
27286 const NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty });
27287
27288 /**
27289 * @license
27290 * Copyright Google LLC All Rights Reserved.
27291 *
27292 * Use of this source code is governed by an MIT-style license that can be
27293 * found in the LICENSE file at https://angular.io/license
27294 */
27295 /**
27296 * Injection flags for DI.
27297 *
27298 * @publicApi
27299 */
27300 var InjectFlags;
27301 (function (InjectFlags) {
27302 // TODO(alxhub): make this 'const' (and remove `InternalInjectFlags` enum) when ngc no longer
27303 // writes exports of it into ngfactory files.
27304 /** Check self and check parent injector if needed */
27305 InjectFlags[InjectFlags["Default"] = 0] = "Default";
27306 /**
27307 * Specifies that an injector should retrieve a dependency from any injector until reaching the
27308 * host element of the current component. (Only used with Element Injector)
27309 */
27310 InjectFlags[InjectFlags["Host"] = 1] = "Host";
27311 /** Don't ascend to ancestors of the node requesting injection. */
27312 InjectFlags[InjectFlags["Self"] = 2] = "Self";
27313 /** Skip the node that is requesting injection. */
27314 InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf";
27315 /** Inject `defaultValue` instead if token not found. */
27316 InjectFlags[InjectFlags["Optional"] = 8] = "Optional";
27317 })(InjectFlags || (InjectFlags = {}));
27318
27319 /**
27320 * @license
27321 * Copyright Google LLC All Rights Reserved.
27322 *
27323 * Use of this source code is governed by an MIT-style license that can be
27324 * found in the LICENSE file at https://angular.io/license
27325 */
27326 /**
27327 * Current implementation of inject.
27328 *
27329 * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
27330 * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
27331 * way for two reasons:
27332 * 1. `Injector` should not depend on ivy logic.
27333 * 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
27334 */
27335 let _injectImplementation;
27336 function getInjectImplementation() {
27337 return _injectImplementation;
27338 }
27339 /**
27340 * Sets the current inject implementation.
27341 */
27342 function setInjectImplementation(impl) {
27343 const previous = _injectImplementation;
27344 _injectImplementation = impl;
27345 return previous;
27346 }
27347 /**
27348 * Injects `root` tokens in limp mode.
27349 *
27350 * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
27351 * `"root"`. This is known as the limp mode injection. In such case the value is stored in the
27352 * `InjectableDef`.
27353 */
27354 function injectRootLimpMode(token, notFoundValue, flags) {
27355 const injectableDef = getInjectableDef(token);
27356 if (injectableDef && injectableDef.providedIn == 'root') {
27357 return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
27358 injectableDef.value;
27359 }
27360 if (flags & InjectFlags.Optional)
27361 return null;
27362 if (notFoundValue !== undefined)
27363 return notFoundValue;
27364 throwProviderNotFoundError(stringify$1(token), 'Injector');
27365 }
27366
27367 /**
27368 * @license
27369 * Copyright Google LLC All Rights Reserved.
27370 *
27371 * Use of this source code is governed by an MIT-style license that can be
27372 * found in the LICENSE file at https://angular.io/license
27373 */
27374 /**
27375 * Convince closure compiler that the wrapped function has no side-effects.
27376 *
27377 * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to
27378 * allow us to execute a function but have closure compiler mark the call as no-side-effects.
27379 * It is important that the return value for the `noSideEffects` function be assigned
27380 * to something which is retained otherwise the call to `noSideEffects` will be removed by closure
27381 * compiler.
27382 */
27383 function noSideEffects(fn) {
27384 return { toString: fn }.toString();
27385 }
27386
27387 /**
27388 * @license
27389 * Copyright Google LLC All Rights Reserved.
27390 *
27391 * Use of this source code is governed by an MIT-style license that can be
27392 * found in the LICENSE file at https://angular.io/license
27393 */
27394 /**
27395 * The strategy that the default change detector uses to detect changes.
27396 * When set, takes effect the next time change detection is triggered.
27397 *
27398 * @see {@link ChangeDetectorRef#usage-notes Change detection usage}
27399 *
27400 * @publicApi
27401 */
27402 var ChangeDetectionStrategy$1;
27403 (function (ChangeDetectionStrategy) {
27404 /**
27405 * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated
27406 * until reactivated by setting the strategy to `Default` (`CheckAlways`).
27407 * Change detection can still be explicitly invoked.
27408 * This strategy applies to all child directives and cannot be overridden.
27409 */
27410 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
27411 /**
27412 * Use the default `CheckAlways` strategy, in which change detection is automatic until
27413 * explicitly deactivated.
27414 */
27415 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
27416 })(ChangeDetectionStrategy$1 || (ChangeDetectionStrategy$1 = {}));
27417 /**
27418 * Defines the possible states of the default change detector.
27419 * @see `ChangeDetectorRef`
27420 */
27421 var ChangeDetectorStatus;
27422 (function (ChangeDetectorStatus) {
27423 /**
27424 * A state in which, after calling `detectChanges()`, the change detector
27425 * state becomes `Checked`, and must be explicitly invoked or reactivated.
27426 */
27427 ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce";
27428 /**
27429 * A state in which change detection is skipped until the change detector mode
27430 * becomes `CheckOnce`.
27431 */
27432 ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked";
27433 /**
27434 * A state in which change detection continues automatically until explicitly
27435 * deactivated.
27436 */
27437 ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways";
27438 /**
27439 * A state in which a change detector sub tree is not a part of the main tree and
27440 * should be skipped.
27441 */
27442 ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached";
27443 /**
27444 * Indicates that the change detector encountered an error checking a binding
27445 * or calling a directive lifecycle method and is now in an inconsistent state. Change
27446 * detectors in this state do not detect changes.
27447 */
27448 ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored";
27449 /**
27450 * Indicates that the change detector has been destroyed.
27451 */
27452 ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed";
27453 })(ChangeDetectorStatus || (ChangeDetectorStatus = {}));
27454
27455 /**
27456 * @license
27457 * Copyright Google LLC All Rights Reserved.
27458 *
27459 * Use of this source code is governed by an MIT-style license that can be
27460 * found in the LICENSE file at https://angular.io/license
27461 */
27462 /**
27463 * Defines template and style encapsulation options available for Component's {@link Component}.
27464 *
27465 * See {@link Component#encapsulation encapsulation}.
27466 *
27467 * @usageNotes
27468 * ### Example
27469 *
27470 * {@example core/ts/metadata/encapsulation.ts region='longform'}
27471 *
27472 * @publicApi
27473 */
27474 var ViewEncapsulation$1;
27475 (function (ViewEncapsulation) {
27476 /**
27477 * Emulate `Native` scoping of styles by adding an attribute containing surrogate id to the Host
27478 * Element and pre-processing the style rules provided via {@link Component#styles styles} or
27479 * {@link Component#styleUrls styleUrls}, and adding the new Host Element attribute to all
27480 * selectors.
27481 *
27482 * This is the default option.
27483 */
27484 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
27485 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
27486 /**
27487 * Don't provide any template or style encapsulation.
27488 */
27489 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
27490 /**
27491 * Use Shadow DOM to encapsulate styles.
27492 *
27493 * For the DOM this means using modern [Shadow
27494 * DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) and
27495 * creating a ShadowRoot for Component's Host Element.
27496 */
27497 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
27498 })(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
27499
27500 /**
27501 * @license
27502 * Copyright Google LLC All Rights Reserved.
27503 *
27504 * Use of this source code is governed by an MIT-style license that can be
27505 * found in the LICENSE file at https://angular.io/license
27506 */
27507 const __globalThis = typeof globalThis !== 'undefined' && globalThis;
27508 const __window$1 = typeof window !== 'undefined' && window;
27509 const __self$1 = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
27510 self instanceof WorkerGlobalScope && self;
27511 const __global$1 = typeof global !== 'undefined' && global;
27512 // Always use __globalThis if available, which is the spec-defined global variable across all
27513 // environments, then fallback to __global first, because in Node tests both __global and
27514 // __window may be defined and _global should be __global in that case.
27515 const _global$1 = __globalThis || __global$1 || __window$1 || __self$1;
27516
27517 /**
27518 * @license
27519 * Copyright Google LLC All Rights Reserved.
27520 *
27521 * Use of this source code is governed by an MIT-style license that can be
27522 * found in the LICENSE file at https://angular.io/license
27523 */
27524 function ngDevModeResetPerfCounters() {
27525 const locationString = typeof location !== 'undefined' ? location.toString() : '';
27526 const newCounters = {
27527 namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1,
27528 firstCreatePass: 0,
27529 tNode: 0,
27530 tView: 0,
27531 rendererCreateTextNode: 0,
27532 rendererSetText: 0,
27533 rendererCreateElement: 0,
27534 rendererAddEventListener: 0,
27535 rendererSetAttribute: 0,
27536 rendererRemoveAttribute: 0,
27537 rendererSetProperty: 0,
27538 rendererSetClassName: 0,
27539 rendererAddClass: 0,
27540 rendererRemoveClass: 0,
27541 rendererSetStyle: 0,
27542 rendererRemoveStyle: 0,
27543 rendererDestroy: 0,
27544 rendererDestroyNode: 0,
27545 rendererMoveNode: 0,
27546 rendererRemoveNode: 0,
27547 rendererAppendChild: 0,
27548 rendererInsertBefore: 0,
27549 rendererCreateComment: 0,
27550 };
27551 // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
27552 const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
27553 _global$1['ngDevMode'] = allowNgDevModeTrue && newCounters;
27554 return newCounters;
27555 }
27556 /**
27557 * This function checks to see if the `ngDevMode` has been set. If yes,
27558 * then we honor it, otherwise we default to dev mode with additional checks.
27559 *
27560 * The idea is that unless we are doing production build where we explicitly
27561 * set `ngDevMode == false` we should be helping the developer by providing
27562 * as much early warning and errors as possible.
27563 *
27564 * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions
27565 * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode
27566 * is defined for the entire instruction set.
27567 *
27568 * When checking `ngDevMode` on toplevel, always init it before referencing it
27569 * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can
27570 * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595.
27571 *
27572 * Details on possible values for `ngDevMode` can be found on its docstring.
27573 *
27574 * NOTE:
27575 * - changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`.
27576 */
27577 function initNgDevMode() {
27578 // The below checks are to ensure that calling `initNgDevMode` multiple times does not
27579 // reset the counters.
27580 // If the `ngDevMode` is not an object, then it means we have not created the perf counters
27581 // yet.
27582 if (typeof ngDevMode === 'undefined' || ngDevMode) {
27583 if (typeof ngDevMode !== 'object') {
27584 ngDevModeResetPerfCounters();
27585 }
27586 return typeof ngDevMode !== 'undefined' && !!ngDevMode;
27587 }
27588 return false;
27589 }
27590
27591 /**
27592 * @license
27593 * Copyright Google LLC All Rights Reserved.
27594 *
27595 * Use of this source code is governed by an MIT-style license that can be
27596 * found in the LICENSE file at https://angular.io/license
27597 */
27598 /**
27599 * This file contains reuseable "empty" symbols that can be used as default return values
27600 * in different parts of the rendering code. Because the same symbols are returned, this
27601 * allows for identity checks against these values to be consistently used by the framework
27602 * code.
27603 */
27604 const EMPTY_OBJ = {};
27605 const EMPTY_ARRAY = [];
27606 // freezing the values prevents any code from accidentally inserting new values in
27607 if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
27608 // These property accesses can be ignored because ngDevMode will be set to false
27609 // when optimizing code and the whole if statement will be dropped.
27610 // tslint:disable-next-line:no-toplevel-property-access
27611 Object.freeze(EMPTY_OBJ);
27612 // tslint:disable-next-line:no-toplevel-property-access
27613 Object.freeze(EMPTY_ARRAY);
27614 }
27615
27616 /**
27617 * @license
27618 * Copyright Google LLC All Rights Reserved.
27619 *
27620 * Use of this source code is governed by an MIT-style license that can be
27621 * found in the LICENSE file at https://angular.io/license
27622 */
27623 const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty });
27624 const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty });
27625 const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty });
27626 const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty });
27627 const NG_LOC_ID_DEF = getClosureSafeProperty({ ɵloc: getClosureSafeProperty });
27628 const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty });
27629 /**
27630 * If a directive is diPublic, bloomAdd sets a property on the type with this constant as
27631 * the key and the directive's unique ID as the value. This allows us to map directives to their
27632 * bloom filter bit for DI.
27633 */
27634 // TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified.
27635 const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty });
27636
27637 /**
27638 * @license
27639 * Copyright Google LLC All Rights Reserved.
27640 *
27641 * Use of this source code is governed by an MIT-style license that can be
27642 * found in the LICENSE file at https://angular.io/license
27643 */
27644 /**
27645 * The following getter methods retrieve the definition from the type. Currently the retrieval
27646 * honors inheritance, but in the future we may change the rule to require that definitions are
27647 * explicit. This would require some sort of migration strategy.
27648 */
27649 function getComponentDef(type) {
27650 return type[NG_COMP_DEF] || null;
27651 }
27652
27653 /**
27654 * @license
27655 * Copyright Google LLC All Rights Reserved.
27656 *
27657 * Use of this source code is governed by an MIT-style license that can be
27658 * found in the LICENSE file at https://angular.io/license
27659 */
27660 // Below are constants for LView indices to help us look up LView members
27661 // without having to remember the specific indices.
27662 // Uglify will inline these when minifying so there shouldn't be a cost.
27663 const HOST = 0;
27664 const TVIEW = 1;
27665 const FLAGS = 2;
27666 const PARENT = 3;
27667 const NEXT = 4;
27668 const TRANSPLANTED_VIEWS_TO_REFRESH = 5;
27669 const T_HOST = 6;
27670 const CLEANUP = 7;
27671 const CONTEXT = 8;
27672 const INJECTOR = 9;
27673 const RENDERER_FACTORY = 10;
27674 const RENDERER = 11;
27675 const SANITIZER = 12;
27676 const CHILD_HEAD = 13;
27677 const CHILD_TAIL = 14;
27678 // FIXME(misko): Investigate if the three declarations aren't all same thing.
27679 const DECLARATION_VIEW = 15;
27680 const DECLARATION_COMPONENT_VIEW = 16;
27681 const DECLARATION_LCONTAINER = 17;
27682 const PREORDER_HOOK_FLAGS = 18;
27683 const QUERIES = 19;
27684 /**
27685 * Size of LView's header. Necessary to adjust for it when setting slots.
27686 *
27687 * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
27688 * instruction index into `LView` index. All other indexes should be in the `LView` index space and
27689 * there should be no need to refer to `HEADER_OFFSET` anywhere else.
27690 */
27691 const HEADER_OFFSET = 20;
27692 /**
27693 * Converts `TViewType` into human readable text.
27694 * Make sure this matches with `TViewType`
27695 */
27696 const TViewTypeAsString = [
27697 'Root',
27698 'Component',
27699 'Embedded',
27700 ];
27701
27702 /**
27703 * @license
27704 * Copyright Google LLC All Rights Reserved.
27705 *
27706 * Use of this source code is governed by an MIT-style license that can be
27707 * found in the LICENSE file at https://angular.io/license
27708 */
27709 /**
27710 * Special location which allows easy identification of type. If we have an array which was
27711 * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
27712 * `LContainer`.
27713 */
27714 const TYPE = 1;
27715 /**
27716 * Below are constants for LContainer indices to help us look up LContainer members
27717 * without having to remember the specific indices.
27718 * Uglify will inline these when minifying so there shouldn't be a cost.
27719 */
27720 /**
27721 * Flag to signify that this `LContainer` may have transplanted views which need to be change
27722 * detected. (see: `LView[DECLARATION_COMPONENT_VIEW])`.
27723 *
27724 * This flag, once set, is never unset for the `LContainer`. This means that when unset we can skip
27725 * a lot of work in `refreshEmbeddedViews`. But when set we still need to verify
27726 * that the `MOVED_VIEWS` are transplanted and on-push.
27727 */
27728 const HAS_TRANSPLANTED_VIEWS = 2;
27729 // PARENT, NEXT, TRANSPLANTED_VIEWS_TO_REFRESH are indices 3, 4, and 5
27730 // As we already have these constants in LView, we don't need to re-create them.
27731 // T_HOST is index 6
27732 // We already have this constants in LView, we don't need to re-create it.
27733 const NATIVE = 7;
27734 const VIEW_REFS = 8;
27735 const MOVED_VIEWS = 9;
27736 /**
27737 * Size of LContainer's header. Represents the index after which all views in the
27738 * container will be inserted. We need to keep a record of current views so we know
27739 * which views are already in the DOM (and don't need to be re-added) and so we can
27740 * remove views from the DOM when they are no longer required.
27741 */
27742 const CONTAINER_HEADER_OFFSET = 10;
27743
27744 /**
27745 * @license
27746 * Copyright Google LLC All Rights Reserved.
27747 *
27748 * Use of this source code is governed by an MIT-style license that can be
27749 * found in the LICENSE file at https://angular.io/license
27750 */
27751 /**
27752 * True if `value` is `LView`.
27753 * @param value wrapped value of `RNode`, `LView`, `LContainer`
27754 */
27755 function isLView(value) {
27756 return Array.isArray(value) && typeof value[TYPE] === 'object';
27757 }
27758 /**
27759 * True if `value` is `LContainer`.
27760 * @param value wrapped value of `RNode`, `LView`, `LContainer`
27761 */
27762 function isLContainer(value) {
27763 return Array.isArray(value) && value[TYPE] === true;
27764 }
27765 function isComponentHost(tNode) {
27766 return (tNode.flags & 2 /* isComponentHost */) === 2 /* isComponentHost */;
27767 }
27768 function isComponentDef(def) {
27769 return def.template !== null;
27770 }
27771 function isRootView(target) {
27772 return (target[FLAGS] & 512 /* IsRoot */) !== 0;
27773 }
27774
27775 /**
27776 * @license
27777 * Copyright Google LLC All Rights Reserved.
27778 *
27779 * Use of this source code is governed by an MIT-style license that can be
27780 * found in the LICENSE file at https://angular.io/license
27781 */
27782 // [Assert functions do not constraint type when they are guarded by a truthy
27783 // expression.](https://github.com/microsoft/TypeScript/issues/37295)
27784 function assertTNodeForLView(tNode, lView) {
27785 assertTNodeForTView(tNode, lView[TVIEW]);
27786 }
27787 function assertTNodeForTView(tNode, tView) {
27788 assertTNode(tNode);
27789 tNode.hasOwnProperty('tView_') &&
27790 assertEqual(tNode.tView_, tView, 'This TNode does not belong to this TView.');
27791 }
27792 function assertTNode(tNode) {
27793 assertDefined(tNode, 'TNode must be defined');
27794 if (!(tNode && typeof tNode === 'object' && tNode.hasOwnProperty('directiveStylingLast'))) {
27795 throwError('Not of type TNode, got: ' + tNode);
27796 }
27797 }
27798 function assertComponentType(actual, msg = 'Type passed in is not ComponentType, it does not have \'ɵcmp\' property.') {
27799 if (!getComponentDef(actual)) {
27800 throwError(msg);
27801 }
27802 }
27803 function assertLContainer(value) {
27804 assertDefined(value, 'LContainer must be defined');
27805 assertEqual(isLContainer(value), true, 'Expecting LContainer');
27806 }
27807 function assertLViewOrUndefined(value) {
27808 value && assertEqual(isLView(value), true, 'Expecting LView or undefined or null');
27809 }
27810 function assertLView(value) {
27811 assertDefined(value, 'LView must be defined');
27812 assertEqual(isLView(value), true, 'Expecting LView');
27813 }
27814 function assertFirstCreatePass(tView, errMessage) {
27815 assertEqual(tView.firstCreatePass, true, errMessage || 'Should only be called in first create pass.');
27816 }
27817 function assertFirstUpdatePass(tView, errMessage) {
27818 assertEqual(tView.firstUpdatePass, true, errMessage || 'Should only be called in first update pass.');
27819 }
27820 /**
27821 * This is a basic sanity check that an object is probably a directive def. DirectiveDef is
27822 * an interface, so we can't do a direct instanceof check.
27823 */
27824 function assertDirectiveDef(obj) {
27825 if (obj.type === undefined || obj.selectors == undefined || obj.inputs === undefined) {
27826 throwError(`Expected a DirectiveDef/ComponentDef and this object does not seem to have the expected shape.`);
27827 }
27828 }
27829 function assertIndexInDeclRange(lView, index) {
27830 const tView = lView[1];
27831 assertBetween(HEADER_OFFSET, tView.bindingStartIndex, index);
27832 }
27833 function assertIndexInExpandoRange(lView, index) {
27834 const tView = lView[1];
27835 assertBetween(tView.expandoStartIndex, lView.length, index);
27836 }
27837 function assertBetween(lower, upper, index) {
27838 if (!(lower <= index && index < upper)) {
27839 throwError(`Index out of range (expecting ${lower} <= ${index} < ${upper})`);
27840 }
27841 }
27842 function assertProjectionSlots(lView, errMessage) {
27843 assertDefined(lView[DECLARATION_COMPONENT_VIEW], 'Component views should exist.');
27844 assertDefined(lView[DECLARATION_COMPONENT_VIEW][T_HOST].projection, errMessage ||
27845 'Components with projection nodes (<ng-content>) must have projection slots defined.');
27846 }
27847 function assertParentView(lView, errMessage) {
27848 assertDefined(lView, errMessage || 'Component views should always have a parent view (component\'s host view)');
27849 }
27850 /**
27851 * This is a basic sanity check that the `injectorIndex` seems to point to what looks like a
27852 * NodeInjector data structure.
27853 *
27854 * @param lView `LView` which should be checked.
27855 * @param injectorIndex index into the `LView` where the `NodeInjector` is expected.
27856 */
27857 function assertNodeInjector(lView, injectorIndex) {
27858 assertIndexInExpandoRange(lView, injectorIndex);
27859 assertIndexInExpandoRange(lView, injectorIndex + 8 /* PARENT */);
27860 assertNumber(lView[injectorIndex + 0], 'injectorIndex should point to a bloom filter');
27861 assertNumber(lView[injectorIndex + 1], 'injectorIndex should point to a bloom filter');
27862 assertNumber(lView[injectorIndex + 2], 'injectorIndex should point to a bloom filter');
27863 assertNumber(lView[injectorIndex + 3], 'injectorIndex should point to a bloom filter');
27864 assertNumber(lView[injectorIndex + 4], 'injectorIndex should point to a bloom filter');
27865 assertNumber(lView[injectorIndex + 5], 'injectorIndex should point to a bloom filter');
27866 assertNumber(lView[injectorIndex + 6], 'injectorIndex should point to a bloom filter');
27867 assertNumber(lView[injectorIndex + 7], 'injectorIndex should point to a bloom filter');
27868 assertNumber(lView[injectorIndex + 8 /* PARENT */], 'injectorIndex should point to parent injector');
27869 }
27870
27871 /**
27872 * @license
27873 * Copyright Google LLC All Rights Reserved.
27874 *
27875 * Use of this source code is governed by an MIT-style license that can be
27876 * found in the LICENSE file at https://angular.io/license
27877 */
27878 function getFactoryDef(type, throwNotFound) {
27879 const hasFactoryDef = type.hasOwnProperty(NG_FACTORY_DEF);
27880 if (!hasFactoryDef && throwNotFound === true && ngDevMode) {
27881 throw new Error(`Type ${stringify$1(type)} does not have 'ɵfac' property.`);
27882 }
27883 return hasFactoryDef ? type[NG_FACTORY_DEF] : null;
27884 }
27885
27886 /**
27887 * @license
27888 * Copyright Google LLC All Rights Reserved.
27889 *
27890 * Use of this source code is governed by an MIT-style license that can be
27891 * found in the LICENSE file at https://angular.io/license
27892 */
27893 /**
27894 * Represents a basic change from a previous to a new value for a single
27895 * property on a directive instance. Passed as a value in a
27896 * {@link SimpleChanges} object to the `ngOnChanges` hook.
27897 *
27898 * @see `OnChanges`
27899 *
27900 * @publicApi
27901 */
27902 class SimpleChange {
27903 constructor(previousValue, currentValue, firstChange) {
27904 this.previousValue = previousValue;
27905 this.currentValue = currentValue;
27906 this.firstChange = firstChange;
27907 }
27908 /**
27909 * Check whether the new value is the first value assigned.
27910 */
27911 isFirstChange() {
27912 return this.firstChange;
27913 }
27914 }
27915
27916 /**
27917 * @license
27918 * Copyright Google LLC All Rights Reserved.
27919 *
27920 * Use of this source code is governed by an MIT-style license that can be
27921 * found in the LICENSE file at https://angular.io/license
27922 */
27923 function NgOnChangesFeatureImpl(definition) {
27924 if (definition.type.prototype.ngOnChanges) {
27925 definition.setInput = ngOnChangesSetInput;
27926 }
27927 return rememberChangeHistoryAndInvokeOnChangesHook;
27928 }
27929 /**
27930 * This is a synthetic lifecycle hook which gets inserted into `TView.preOrderHooks` to simulate
27931 * `ngOnChanges`.
27932 *
27933 * The hook reads the `NgSimpleChangesStore` data from the component instance and if changes are
27934 * found it invokes `ngOnChanges` on the component instance.
27935 *
27936 * @param this Component instance. Because this function gets inserted into `TView.preOrderHooks`,
27937 * it is guaranteed to be called with component instance.
27938 */
27939 function rememberChangeHistoryAndInvokeOnChangesHook() {
27940 const simpleChangesStore = getSimpleChangesStore(this);
27941 const current = simpleChangesStore === null || simpleChangesStore === void 0 ? void 0 : simpleChangesStore.current;
27942 if (current) {
27943 const previous = simpleChangesStore.previous;
27944 if (previous === EMPTY_OBJ) {
27945 simpleChangesStore.previous = current;
27946 }
27947 else {
27948 // New changes are copied to the previous store, so that we don't lose history for inputs
27949 // which were not changed this time
27950 for (let key in current) {
27951 previous[key] = current[key];
27952 }
27953 }
27954 simpleChangesStore.current = null;
27955 this.ngOnChanges(current);
27956 }
27957 }
27958 function ngOnChangesSetInput(instance, value, publicName, privateName) {
27959 const simpleChangesStore = getSimpleChangesStore(instance) ||
27960 setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
27961 const current = simpleChangesStore.current || (simpleChangesStore.current = {});
27962 const previous = simpleChangesStore.previous;
27963 const declaredName = this.declaredInputs[publicName];
27964 const previousChange = previous[declaredName];
27965 current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
27966 instance[privateName] = value;
27967 }
27968 const SIMPLE_CHANGES_STORE = '__ngSimpleChanges__';
27969 function getSimpleChangesStore(instance) {
27970 return instance[SIMPLE_CHANGES_STORE] || null;
27971 }
27972 function setSimpleChangesStore(instance, store) {
27973 return instance[SIMPLE_CHANGES_STORE] = store;
27974 }
27975
27976 /**
27977 * @license
27978 * Copyright Google LLC All Rights Reserved.
27979 *
27980 * Use of this source code is governed by an MIT-style license that can be
27981 * found in the LICENSE file at https://angular.io/license
27982 */
27983 const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
27984 const MATH_ML_NAMESPACE = 'http://www.w3.org/1998/MathML/';
27985
27986 /**
27987 * @license
27988 * Copyright Google LLC All Rights Reserved.
27989 *
27990 * Use of this source code is governed by an MIT-style license that can be
27991 * found in the LICENSE file at https://angular.io/license
27992 */
27993 /**
27994 * This property will be monkey-patched on elements, components and directives
27995 */
27996 const MONKEY_PATCH_KEY_NAME = '__ngContext__';
27997
27998 /**
27999 * @license
28000 * Copyright Google LLC All Rights Reserved.
28001 *
28002 * Use of this source code is governed by an MIT-style license that can be
28003 * found in the LICENSE file at https://angular.io/license
28004 */
28005 /**
28006 * Access the object that represents the `document` for this platform.
28007 *
28008 * Ivy calls this whenever it needs to access the `document` object.
28009 * For example to create the renderer or to do sanitization.
28010 */
28011 function getDocument() {
28012 if (typeof document !== 'undefined') {
28013 return document;
28014 }
28015 // No "document" can be found. This should only happen if we are running ivy outside Angular and
28016 // the current platform is not a browser. Since this is not a supported scenario at the moment
28017 // this should not happen in Angular apps.
28018 // Once we support running ivy outside of Angular we will need to publish `setDocument()` as a
28019 // public API. Meanwhile we just return `undefined` and let the application fail.
28020 return undefined;
28021 }
28022
28023 /**
28024 * @license
28025 * Copyright Google LLC All Rights Reserved.
28026 *
28027 * Use of this source code is governed by an MIT-style license that can be
28028 * found in the LICENSE file at https://angular.io/license
28029 */
28030 // TODO: cleanup once the code is merged in angular/angular
28031 var RendererStyleFlags3;
28032 (function (RendererStyleFlags3) {
28033 RendererStyleFlags3[RendererStyleFlags3["Important"] = 1] = "Important";
28034 RendererStyleFlags3[RendererStyleFlags3["DashCase"] = 2] = "DashCase";
28035 })(RendererStyleFlags3 || (RendererStyleFlags3 = {}));
28036 /** Returns whether the `renderer` is a `ProceduralRenderer3` */
28037 function isProceduralRenderer(renderer) {
28038 return !!(renderer.listen);
28039 }
28040 const ɵ0 = (hostElement, rendererType) => {
28041 return getDocument();
28042 };
28043 const domRendererFactory3 = {
28044 createRenderer: ɵ0
28045 };
28046
28047 /**
28048 * @license
28049 * Copyright Google LLC All Rights Reserved.
28050 *
28051 * Use of this source code is governed by an MIT-style license that can be
28052 * found in the LICENSE file at https://angular.io/license
28053 */
28054 /**
28055 * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
28056 * in same location in `LView`. This is because we don't want to pre-allocate space for it
28057 * because the storage is sparse. This file contains utilities for dealing with such data types.
28058 *
28059 * How do we know what is stored at a given location in `LView`.
28060 * - `Array.isArray(value) === false` => `RNode` (The normal storage value)
28061 * - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value.
28062 * - `typeof value[TYPE] === 'object'` => `LView`
28063 * - This happens when we have a component at a given location
28064 * - `typeof value[TYPE] === true` => `LContainer`
28065 * - This happens when we have `LContainer` binding at a given location.
28066 *
28067 *
28068 * NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.
28069 */
28070 /**
28071 * Returns `RNode`.
28072 * @param value wrapped value of `RNode`, `LView`, `LContainer`
28073 */
28074 function unwrapRNode(value) {
28075 while (Array.isArray(value)) {
28076 value = value[HOST];
28077 }
28078 return value;
28079 }
28080 /**
28081 * Retrieve an `RNode` for a given `TNode` and `LView`.
28082 *
28083 * This function guarantees in dev mode to retrieve a non-null `RNode`.
28084 *
28085 * @param tNode
28086 * @param lView
28087 */
28088 function getNativeByTNode(tNode, lView) {
28089 ngDevMode && assertTNodeForLView(tNode, lView);
28090 ngDevMode && assertIndexInRange(lView, tNode.index);
28091 const node = unwrapRNode(lView[tNode.index]);
28092 ngDevMode && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
28093 return node;
28094 }
28095 // fixme(misko): The return Type should be `TNode|null`
28096 function getTNode(tView, index) {
28097 ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
28098 ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode');
28099 const tNode = tView.data[index];
28100 ngDevMode && tNode !== null && assertTNode(tNode);
28101 return tNode;
28102 }
28103 function getComponentLViewByIndex(nodeIndex, hostView) {
28104 // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
28105 ngDevMode && assertIndexInRange(hostView, nodeIndex);
28106 const slotValue = hostView[nodeIndex];
28107 const lView = isLView(slotValue) ? slotValue : slotValue[HOST];
28108 return lView;
28109 }
28110 /**
28111 * Returns the monkey-patch value data present on the target (which could be
28112 * a component, directive or a DOM node).
28113 */
28114 function readPatchedData(target) {
28115 ngDevMode && assertDefined(target, 'Target expected');
28116 return target[MONKEY_PATCH_KEY_NAME] || null;
28117 }
28118 function readPatchedLView(target) {
28119 const value = readPatchedData(target);
28120 if (value) {
28121 return Array.isArray(value) ? value : value.lView;
28122 }
28123 return null;
28124 }
28125 /** Checks whether a given view is in creation mode */
28126 function isCreationMode(view) {
28127 return (view[FLAGS] & 4 /* CreationMode */) === 4 /* CreationMode */;
28128 }
28129 /**
28130 * Returns a boolean for whether the view is attached to the change detection tree.
28131 *
28132 * Note: This determines whether a view should be checked, not whether it's inserted
28133 * into a container. For that, you'll want `viewAttachedToContainer` below.
28134 */
28135 function viewAttachedToChangeDetector(view) {
28136 return (view[FLAGS] & 128 /* Attached */) === 128 /* Attached */;
28137 }
28138 /**
28139 * Resets the pre-order hook flags of the view.
28140 * @param lView the LView on which the flags are reset
28141 */
28142 function resetPreOrderHookFlags(lView) {
28143 lView[PREORDER_HOOK_FLAGS] = 0;
28144 }
28145 /**
28146 * Updates the `TRANSPLANTED_VIEWS_TO_REFRESH` counter on the `LContainer` as well as the parents
28147 * whose
28148 * 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
28149 * or
28150 * 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
28151 */
28152 function updateTransplantedViewCount(lContainer, amount) {
28153 lContainer[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
28154 let viewOrContainer = lContainer;
28155 let parent = lContainer[PARENT];
28156 while (parent !== null &&
28157 ((amount === 1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 1) ||
28158 (amount === -1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 0))) {
28159 parent[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
28160 viewOrContainer = parent;
28161 parent = parent[PARENT];
28162 }
28163 }
28164
28165 /**
28166 * @license
28167 * Copyright Google LLC All Rights Reserved.
28168 *
28169 * Use of this source code is governed by an MIT-style license that can be
28170 * found in the LICENSE file at https://angular.io/license
28171 */
28172 const instructionState = {
28173 lFrame: createLFrame(null),
28174 bindingsEnabled: true,
28175 isInCheckNoChangesMode: false,
28176 };
28177 /**
28178 * Return the current `LView`.
28179 */
28180 function getLView() {
28181 return instructionState.lFrame.lView;
28182 }
28183 /**
28184 * Return the current `TView`.
28185 */
28186 function getTView() {
28187 return instructionState.lFrame.tView;
28188 }
28189 function getCurrentTNode() {
28190 let currentTNode = getCurrentTNodePlaceholderOk();
28191 while (currentTNode !== null && currentTNode.type === 64 /* Placeholder */) {
28192 currentTNode = currentTNode.parent;
28193 }
28194 return currentTNode;
28195 }
28196 function getCurrentTNodePlaceholderOk() {
28197 return instructionState.lFrame.currentTNode;
28198 }
28199 function getCurrentParentTNode() {
28200 const lFrame = instructionState.lFrame;
28201 const currentTNode = lFrame.currentTNode;
28202 return lFrame.isParent ? currentTNode : currentTNode.parent;
28203 }
28204 function setCurrentTNode(tNode, isParent) {
28205 ngDevMode && tNode && assertTNodeForTView(tNode, instructionState.lFrame.tView);
28206 const lFrame = instructionState.lFrame;
28207 lFrame.currentTNode = tNode;
28208 lFrame.isParent = isParent;
28209 }
28210 function isCurrentTNodeParent() {
28211 return instructionState.lFrame.isParent;
28212 }
28213 function isInCheckNoChangesMode() {
28214 // TODO(misko): remove this from the LView since it is ngDevMode=true mode only.
28215 return instructionState.isInCheckNoChangesMode;
28216 }
28217 function setIsInCheckNoChangesMode(mode) {
28218 instructionState.isInCheckNoChangesMode = mode;
28219 }
28220 function setBindingIndex(value) {
28221 return instructionState.lFrame.bindingIndex = value;
28222 }
28223 function isInI18nBlock() {
28224 return instructionState.lFrame.inI18n;
28225 }
28226 /**
28227 * Set a new binding root index so that host template functions can execute.
28228 *
28229 * Bindings inside the host template are 0 index. But because we don't know ahead of time
28230 * how many host bindings we have we can't pre-compute them. For this reason they are all
28231 * 0 index and we just shift the root so that they match next available location in the LView.
28232 *
28233 * @param bindingRootIndex Root index for `hostBindings`
28234 * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive
28235 * whose `hostBindings` are being processed.
28236 */
28237 function setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex) {
28238 const lFrame = instructionState.lFrame;
28239 lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex;
28240 setCurrentDirectiveIndex(currentDirectiveIndex);
28241 }
28242 /**
28243 * Sets an index of a directive whose `hostBindings` are being processed.
28244 *
28245 * @param currentDirectiveIndex `TData` index where current directive instance can be found.
28246 */
28247 function setCurrentDirectiveIndex(currentDirectiveIndex) {
28248 instructionState.lFrame.currentDirectiveIndex = currentDirectiveIndex;
28249 }
28250 function setCurrentQueryIndex(value) {
28251 instructionState.lFrame.currentQueryIndex = value;
28252 }
28253 /**
28254 * Returns a `TNode` of the location where the current `LView` is declared at.
28255 *
28256 * @param lView an `LView` that we want to find parent `TNode` for.
28257 */
28258 function getDeclarationTNode(lView) {
28259 const tView = lView[TVIEW];
28260 // Return the declaration parent for embedded views
28261 if (tView.type === 2 /* Embedded */) {
28262 ngDevMode && assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
28263 return tView.declTNode;
28264 }
28265 // Components don't have `TView.declTNode` because each instance of component could be
28266 // inserted in different location, hence `TView.declTNode` is meaningless.
28267 // Falling back to `T_HOST` in case we cross component boundary.
28268 if (tView.type === 1 /* Component */) {
28269 return lView[T_HOST];
28270 }
28271 // Remaining TNode type is `TViewType.Root` which doesn't have a parent TNode.
28272 return null;
28273 }
28274 /**
28275 * This is a light weight version of the `enterView` which is needed by the DI system.
28276 *
28277 * @param lView `LView` location of the DI context.
28278 * @param tNode `TNode` for DI context
28279 * @param flags DI context flags. if `SkipSelf` flag is set than we walk up the declaration
28280 * tree from `tNode` until we find parent declared `TElementNode`.
28281 * @returns `true` if we have successfully entered DI associated with `tNode` (or with declared
28282 * `TNode` if `flags` has `SkipSelf`). Failing to enter DI implies that no associated
28283 * `NodeInjector` can be found and we should instead use `ModuleInjector`.
28284 * - If `true` than this call must be fallowed by `leaveDI`
28285 * - If `false` than this call failed and we should NOT call `leaveDI`
28286 */
28287 function enterDI(lView, tNode, flags) {
28288 ngDevMode && assertLViewOrUndefined(lView);
28289 if (flags & InjectFlags.SkipSelf) {
28290 ngDevMode && assertTNodeForTView(tNode, lView[TVIEW]);
28291 let parentTNode = tNode;
28292 let parentLView = lView;
28293 while (true) {
28294 ngDevMode && assertDefined(parentTNode, 'Parent TNode should be defined');
28295 parentTNode = parentTNode.parent;
28296 if (parentTNode === null && !(flags & InjectFlags.Host)) {
28297 parentTNode = getDeclarationTNode(parentLView);
28298 if (parentTNode === null)
28299 break;
28300 // In this case, a parent exists and is definitely an element. So it will definitely
28301 // have an existing lView as the declaration view, which is why we can assume it's defined.
28302 ngDevMode && assertDefined(parentLView, 'Parent LView should be defined');
28303 parentLView = parentLView[DECLARATION_VIEW];
28304 // In Ivy there are Comment nodes that correspond to ngIf and NgFor embedded directives
28305 // We want to skip those and look only at Elements and ElementContainers to ensure
28306 // we're looking at true parent nodes, and not content or other types.
28307 if (parentTNode.type & (2 /* Element */ | 8 /* ElementContainer */)) {
28308 break;
28309 }
28310 }
28311 else {
28312 break;
28313 }
28314 }
28315 if (parentTNode === null) {
28316 // If we failed to find a parent TNode this means that we should use module injector.
28317 return false;
28318 }
28319 else {
28320 tNode = parentTNode;
28321 lView = parentLView;
28322 }
28323 }
28324 ngDevMode && assertTNodeForLView(tNode, lView);
28325 const lFrame = instructionState.lFrame = allocLFrame();
28326 lFrame.currentTNode = tNode;
28327 lFrame.lView = lView;
28328 return true;
28329 }
28330 /**
28331 * Swap the current lView with a new lView.
28332 *
28333 * For performance reasons we store the lView in the top level of the module.
28334 * This way we minimize the number of properties to read. Whenever a new view
28335 * is entered we have to store the lView for later, and when the view is
28336 * exited the state has to be restored
28337 *
28338 * @param newView New lView to become active
28339 * @returns the previously active lView;
28340 */
28341 function enterView(newView) {
28342 ngDevMode && assertNotEqual(newView[0], newView[1], '????');
28343 ngDevMode && assertLViewOrUndefined(newView);
28344 const newLFrame = allocLFrame();
28345 if (ngDevMode) {
28346 assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
28347 assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
28348 assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
28349 assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
28350 assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
28351 assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
28352 assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
28353 assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
28354 assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
28355 }
28356 const tView = newView[TVIEW];
28357 instructionState.lFrame = newLFrame;
28358 ngDevMode && tView.firstChild && assertTNodeForTView(tView.firstChild, tView);
28359 newLFrame.currentTNode = tView.firstChild;
28360 newLFrame.lView = newView;
28361 newLFrame.tView = tView;
28362 newLFrame.contextLView = newView;
28363 newLFrame.bindingIndex = tView.bindingStartIndex;
28364 newLFrame.inI18n = false;
28365 }
28366 /**
28367 * Allocates next free LFrame. This function tries to reuse the `LFrame`s to lower memory pressure.
28368 */
28369 function allocLFrame() {
28370 const currentLFrame = instructionState.lFrame;
28371 const childLFrame = currentLFrame === null ? null : currentLFrame.child;
28372 const newLFrame = childLFrame === null ? createLFrame(currentLFrame) : childLFrame;
28373 return newLFrame;
28374 }
28375 function createLFrame(parent) {
28376 const lFrame = {
28377 currentTNode: null,
28378 isParent: true,
28379 lView: null,
28380 tView: null,
28381 selectedIndex: -1,
28382 contextLView: null,
28383 elementDepthCount: 0,
28384 currentNamespace: null,
28385 currentDirectiveIndex: -1,
28386 bindingRootIndex: -1,
28387 bindingIndex: -1,
28388 currentQueryIndex: 0,
28389 parent: parent,
28390 child: null,
28391 inI18n: false,
28392 };
28393 parent !== null && (parent.child = lFrame); // link the new LFrame for reuse.
28394 return lFrame;
28395 }
28396 /**
28397 * A lightweight version of leave which is used with DI.
28398 *
28399 * This function only resets `currentTNode` and `LView` as those are the only properties
28400 * used with DI (`enterDI()`).
28401 *
28402 * NOTE: This function is reexported as `leaveDI`. However `leaveDI` has return type of `void` where
28403 * as `leaveViewLight` has `LFrame`. This is so that `leaveViewLight` can be used in `leaveView`.
28404 */
28405 function leaveViewLight() {
28406 const oldLFrame = instructionState.lFrame;
28407 instructionState.lFrame = oldLFrame.parent;
28408 oldLFrame.currentTNode = null;
28409 oldLFrame.lView = null;
28410 return oldLFrame;
28411 }
28412 /**
28413 * This is a lightweight version of the `leaveView` which is needed by the DI system.
28414 *
28415 * NOTE: this function is an alias so that we can change the type of the function to have `void`
28416 * return type.
28417 */
28418 const leaveDI = leaveViewLight;
28419 /**
28420 * Leave the current `LView`
28421 *
28422 * This pops the `LFrame` with the associated `LView` from the stack.
28423 *
28424 * IMPORTANT: We must zero out the `LFrame` values here otherwise they will be retained. This is
28425 * because for performance reasons we don't release `LFrame` but rather keep it for next use.
28426 */
28427 function leaveView() {
28428 const oldLFrame = leaveViewLight();
28429 oldLFrame.isParent = true;
28430 oldLFrame.tView = null;
28431 oldLFrame.selectedIndex = -1;
28432 oldLFrame.contextLView = null;
28433 oldLFrame.elementDepthCount = 0;
28434 oldLFrame.currentDirectiveIndex = -1;
28435 oldLFrame.currentNamespace = null;
28436 oldLFrame.bindingRootIndex = -1;
28437 oldLFrame.bindingIndex = -1;
28438 oldLFrame.currentQueryIndex = 0;
28439 }
28440 /**
28441 * Gets the currently selected element index.
28442 *
28443 * Used with {@link property} instruction (and more in the future) to identify the index in the
28444 * current `LView` to act on.
28445 */
28446 function getSelectedIndex() {
28447 return instructionState.lFrame.selectedIndex;
28448 }
28449 /**
28450 * Sets the most recent index passed to {@link select}
28451 *
28452 * Used with {@link property} instruction (and more in the future) to identify the index in the
28453 * current `LView` to act on.
28454 *
28455 * (Note that if an "exit function" was set earlier (via `setElementExitFn()`) then that will be
28456 * run if and when the provided `index` value is different from the current selected index value.)
28457 */
28458 function setSelectedIndex(index) {
28459 ngDevMode && index !== -1 &&
28460 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
28461 ngDevMode &&
28462 assertLessThan(index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView');
28463 instructionState.lFrame.selectedIndex = index;
28464 }
28465
28466 /**
28467 * @license
28468 * Copyright Google LLC All Rights Reserved.
28469 *
28470 * Use of this source code is governed by an MIT-style license that can be
28471 * found in the LICENSE file at https://angular.io/license
28472 */
28473 /**
28474 * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`.
28475 *
28476 * Must be run *only* on the first template pass.
28477 *
28478 * Sets up the pre-order hooks on the provided `tView`,
28479 * see {@link HookData} for details about the data structure.
28480 *
28481 * @param directiveIndex The index of the directive in LView
28482 * @param directiveDef The definition containing the hooks to setup in tView
28483 * @param tView The current TView
28484 */
28485 function registerPreOrderHooks(directiveIndex, directiveDef, tView) {
28486 ngDevMode && assertFirstCreatePass(tView);
28487 const { ngOnChanges, ngOnInit, ngDoCheck } = directiveDef.type.prototype;
28488 if (ngOnChanges) {
28489 const wrappedOnChanges = NgOnChangesFeatureImpl(directiveDef);
28490 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, wrappedOnChanges);
28491 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = []))
28492 .push(directiveIndex, wrappedOnChanges);
28493 }
28494 if (ngOnInit) {
28495 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(0 - directiveIndex, ngOnInit);
28496 }
28497 if (ngDoCheck) {
28498 (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, ngDoCheck);
28499 (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, ngDoCheck);
28500 }
28501 }
28502 /**
28503 *
28504 * Loops through the directives on the provided `tNode` and queues hooks to be
28505 * run that are not initialization hooks.
28506 *
28507 * Should be executed during `elementEnd()` and similar to
28508 * preserve hook execution order. Content, view, and destroy hooks for projected
28509 * components and directives must be called *before* their hosts.
28510 *
28511 * Sets up the content, view, and destroy hooks on the provided `tView`,
28512 * see {@link HookData} for details about the data structure.
28513 *
28514 * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up
28515 * separately at `elementStart`.
28516 *
28517 * @param tView The current TView
28518 * @param tNode The TNode whose directives are to be searched for hooks to queue
28519 */
28520 function registerPostOrderHooks(tView, tNode) {
28521 ngDevMode && assertFirstCreatePass(tView);
28522 // It's necessary to loop through the directives at elementEnd() (rather than processing in
28523 // directiveCreate) so we can preserve the current hook order. Content, view, and destroy
28524 // hooks for projected components and directives must be called *before* their hosts.
28525 for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) {
28526 const directiveDef = tView.data[i];
28527 ngDevMode && assertDefined(directiveDef, 'Expecting DirectiveDef');
28528 const lifecycleHooks = directiveDef.type.prototype;
28529 const { ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked, ngOnDestroy } = lifecycleHooks;
28530 if (ngAfterContentInit) {
28531 (tView.contentHooks || (tView.contentHooks = [])).push(-i, ngAfterContentInit);
28532 }
28533 if (ngAfterContentChecked) {
28534 (tView.contentHooks || (tView.contentHooks = [])).push(i, ngAfterContentChecked);
28535 (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, ngAfterContentChecked);
28536 }
28537 if (ngAfterViewInit) {
28538 (tView.viewHooks || (tView.viewHooks = [])).push(-i, ngAfterViewInit);
28539 }
28540 if (ngAfterViewChecked) {
28541 (tView.viewHooks || (tView.viewHooks = [])).push(i, ngAfterViewChecked);
28542 (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, ngAfterViewChecked);
28543 }
28544 if (ngOnDestroy != null) {
28545 (tView.destroyHooks || (tView.destroyHooks = [])).push(i, ngOnDestroy);
28546 }
28547 }
28548 }
28549 /**
28550 * Executing hooks requires complex logic as we need to deal with 2 constraints.
28551 *
28552 * 1. Init hooks (ngOnInit, ngAfterContentInit, ngAfterViewInit) must all be executed once and only
28553 * once, across many change detection cycles. This must be true even if some hooks throw, or if
28554 * some recursively trigger a change detection cycle.
28555 * To solve that, it is required to track the state of the execution of these init hooks.
28556 * This is done by storing and maintaining flags in the view: the {@link InitPhaseState},
28557 * and the index within that phase. They can be seen as a cursor in the following structure:
28558 * [[onInit1, onInit2], [afterContentInit1], [afterViewInit1, afterViewInit2, afterViewInit3]]
28559 * They are are stored as flags in LView[FLAGS].
28560 *
28561 * 2. Pre-order hooks can be executed in batches, because of the select instruction.
28562 * To be able to pause and resume their execution, we also need some state about the hook's array
28563 * that is being processed:
28564 * - the index of the next hook to be executed
28565 * - the number of init hooks already found in the processed part of the array
28566 * They are are stored as flags in LView[PREORDER_HOOK_FLAGS].
28567 */
28568 /**
28569 * Executes pre-order check hooks ( OnChanges, DoChanges) given a view where all the init hooks were
28570 * executed once. This is a light version of executeInitAndCheckPreOrderHooks where we can skip read
28571 * / write of the init-hooks related flags.
28572 * @param lView The LView where hooks are defined
28573 * @param hooks Hooks to be run
28574 * @param nodeIndex 3 cases depending on the value:
28575 * - undefined: all hooks from the array should be executed (post-order case)
28576 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
28577 * flushing the remaining hooks)
28578 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
28579 * case, when executing select(number))
28580 */
28581 function executeCheckHooks(lView, hooks, nodeIndex) {
28582 callHooks(lView, hooks, 3 /* InitPhaseCompleted */, nodeIndex);
28583 }
28584 /**
28585 * Executes post-order init and check hooks (one of AfterContentInit, AfterContentChecked,
28586 * AfterViewInit, AfterViewChecked) given a view where there are pending init hooks to be executed.
28587 * @param lView The LView where hooks are defined
28588 * @param hooks Hooks to be run
28589 * @param initPhase A phase for which hooks should be run
28590 * @param nodeIndex 3 cases depending on the value:
28591 * - undefined: all hooks from the array should be executed (post-order case)
28592 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
28593 * flushing the remaining hooks)
28594 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
28595 * case, when executing select(number))
28596 */
28597 function executeInitAndCheckHooks(lView, hooks, initPhase, nodeIndex) {
28598 ngDevMode &&
28599 assertNotEqual(initPhase, 3 /* InitPhaseCompleted */, 'Init pre-order hooks should not be called more than once');
28600 if ((lView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhase) {
28601 callHooks(lView, hooks, initPhase, nodeIndex);
28602 }
28603 }
28604 function incrementInitPhaseFlags(lView, initPhase) {
28605 ngDevMode &&
28606 assertNotEqual(initPhase, 3 /* InitPhaseCompleted */, 'Init hooks phase should not be incremented after all init hooks have been run.');
28607 let flags = lView[FLAGS];
28608 if ((flags & 3 /* InitPhaseStateMask */) === initPhase) {
28609 flags &= 2047 /* IndexWithinInitPhaseReset */;
28610 flags += 1 /* InitPhaseStateIncrementer */;
28611 lView[FLAGS] = flags;
28612 }
28613 }
28614 /**
28615 * Calls lifecycle hooks with their contexts, skipping init hooks if it's not
28616 * the first LView pass
28617 *
28618 * @param currentView The current view
28619 * @param arr The array in which the hooks are found
28620 * @param initPhaseState the current state of the init phase
28621 * @param currentNodeIndex 3 cases depending on the value:
28622 * - undefined: all hooks from the array should be executed (post-order case)
28623 * - null: execute hooks only from the saved index until the end of the array (pre-order case, when
28624 * flushing the remaining hooks)
28625 * - number: execute hooks only from the saved index until that node index exclusive (pre-order
28626 * case, when executing select(number))
28627 */
28628 function callHooks(currentView, arr, initPhase, currentNodeIndex) {
28629 ngDevMode &&
28630 assertEqual(isInCheckNoChangesMode(), false, 'Hooks should never be run when in check no changes mode.');
28631 const startIndex = currentNodeIndex !== undefined ?
28632 (currentView[PREORDER_HOOK_FLAGS] & 65535 /* IndexOfTheNextPreOrderHookMaskMask */) :
28633 0;
28634 const nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1;
28635 const max = arr.length - 1; // Stop the loop at length - 1, because we look for the hook at i + 1
28636 let lastNodeIndexFound = 0;
28637 for (let i = startIndex; i < max; i++) {
28638 const hook = arr[i + 1];
28639 if (typeof hook === 'number') {
28640 lastNodeIndexFound = arr[i];
28641 if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) {
28642 break;
28643 }
28644 }
28645 else {
28646 const isInitHook = arr[i] < 0;
28647 if (isInitHook)
28648 currentView[PREORDER_HOOK_FLAGS] += 65536 /* NumberOfInitHooksCalledIncrementer */;
28649 if (lastNodeIndexFound < nodeIndexLimit || nodeIndexLimit == -1) {
28650 callHook(currentView, initPhase, arr, i);
28651 currentView[PREORDER_HOOK_FLAGS] =
28652 (currentView[PREORDER_HOOK_FLAGS] & 4294901760 /* NumberOfInitHooksCalledMask */) + i +
28653 2;
28654 }
28655 i++;
28656 }
28657 }
28658 }
28659 /**
28660 * Execute one hook against the current `LView`.
28661 *
28662 * @param currentView The current view
28663 * @param initPhaseState the current state of the init phase
28664 * @param arr The array in which the hooks are found
28665 * @param i The current index within the hook data array
28666 */
28667 function callHook(currentView, initPhase, arr, i) {
28668 const isInitHook = arr[i] < 0;
28669 const hook = arr[i + 1];
28670 const directiveIndex = isInitHook ? -arr[i] : arr[i];
28671 const directive = currentView[directiveIndex];
28672 if (isInitHook) {
28673 const indexWithintInitPhase = currentView[FLAGS] >> 11 /* IndexWithinInitPhaseShift */;
28674 // The init phase state must be always checked here as it may have been recursively updated.
28675 if (indexWithintInitPhase <
28676 (currentView[PREORDER_HOOK_FLAGS] >> 16 /* NumberOfInitHooksCalledShift */) &&
28677 (currentView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhase) {
28678 currentView[FLAGS] += 2048 /* IndexWithinInitPhaseIncrementer */;
28679 hook.call(directive);
28680 }
28681 }
28682 else {
28683 hook.call(directive);
28684 }
28685 }
28686
28687 /**
28688 * @license
28689 * Copyright Google LLC All Rights Reserved.
28690 *
28691 * Use of this source code is governed by an MIT-style license that can be
28692 * found in the LICENSE file at https://angular.io/license
28693 */
28694 const NO_PARENT_INJECTOR = -1;
28695 /**
28696 * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in
28697 * `TView.data`. This allows us to store information about the current node's tokens (which
28698 * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be
28699 * shared, so they live in `LView`).
28700 *
28701 * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter
28702 * determines whether a directive is available on the associated node or not. This prevents us
28703 * from searching the directives array at this level unless it's probable the directive is in it.
28704 *
28705 * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters.
28706 *
28707 * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed
28708 * using interfaces as they were previously. The start index of each `LInjector` and `TInjector`
28709 * will differ based on where it is flattened into the main array, so it's not possible to know
28710 * the indices ahead of time and save their types here. The interfaces are still included here
28711 * for documentation purposes.
28712 *
28713 * export interface LInjector extends Array<any> {
28714 *
28715 * // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
28716 * [0]: number;
28717 *
28718 * // Cumulative bloom for directive IDs 32-63
28719 * [1]: number;
28720 *
28721 * // Cumulative bloom for directive IDs 64-95
28722 * [2]: number;
28723 *
28724 * // Cumulative bloom for directive IDs 96-127
28725 * [3]: number;
28726 *
28727 * // Cumulative bloom for directive IDs 128-159
28728 * [4]: number;
28729 *
28730 * // Cumulative bloom for directive IDs 160 - 191
28731 * [5]: number;
28732 *
28733 * // Cumulative bloom for directive IDs 192 - 223
28734 * [6]: number;
28735 *
28736 * // Cumulative bloom for directive IDs 224 - 255
28737 * [7]: number;
28738 *
28739 * // We need to store a reference to the injector's parent so DI can keep looking up
28740 * // the injector tree until it finds the dependency it's looking for.
28741 * [PARENT_INJECTOR]: number;
28742 * }
28743 *
28744 * export interface TInjector extends Array<any> {
28745 *
28746 * // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE)
28747 * [0]: number;
28748 *
28749 * // Shared node bloom for directive IDs 32-63
28750 * [1]: number;
28751 *
28752 * // Shared node bloom for directive IDs 64-95
28753 * [2]: number;
28754 *
28755 * // Shared node bloom for directive IDs 96-127
28756 * [3]: number;
28757 *
28758 * // Shared node bloom for directive IDs 128-159
28759 * [4]: number;
28760 *
28761 * // Shared node bloom for directive IDs 160 - 191
28762 * [5]: number;
28763 *
28764 * // Shared node bloom for directive IDs 192 - 223
28765 * [6]: number;
28766 *
28767 * // Shared node bloom for directive IDs 224 - 255
28768 * [7]: number;
28769 *
28770 * // Necessary to find directive indices for a particular node.
28771 * [TNODE]: TElementNode|TElementContainerNode|TContainerNode;
28772 * }
28773 */
28774 /**
28775 * Factory for creating instances of injectors in the NodeInjector.
28776 *
28777 * This factory is complicated by the fact that it can resolve `multi` factories as well.
28778 *
28779 * NOTE: Some of the fields are optional which means that this class has two hidden classes.
28780 * - One without `multi` support (most common)
28781 * - One with `multi` values, (rare).
28782 *
28783 * Since VMs can cache up to 4 inline hidden classes this is OK.
28784 *
28785 * - Single factory: Only `resolving` and `factory` is defined.
28786 * - `providers` factory: `componentProviders` is a number and `index = -1`.
28787 * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`.
28788 */
28789 class NodeInjectorFactory {
28790 constructor(
28791 /**
28792 * Factory to invoke in order to create a new instance.
28793 */
28794 factory,
28795 /**
28796 * Set to `true` if the token is declared in `viewProviders` (or if it is component).
28797 */
28798 isViewProvider, injectImplementation) {
28799 this.factory = factory;
28800 /**
28801 * Marker set to true during factory invocation to see if we get into recursive loop.
28802 * Recursive loop causes an error to be displayed.
28803 */
28804 this.resolving = false;
28805 ngDevMode && assertDefined(factory, 'Factory not specified');
28806 ngDevMode && assertEqual(typeof factory, 'function', 'Expected factory function.');
28807 this.canSeeViewProviders = isViewProvider;
28808 this.injectImpl = injectImplementation;
28809 }
28810 }
28811 function isFactory(obj) {
28812 return obj instanceof NodeInjectorFactory;
28813 }
28814
28815 /**
28816 * Converts `TNodeType` into human readable text.
28817 * Make sure this matches with `TNodeType`
28818 */
28819 function toTNodeTypeAsString(tNodeType) {
28820 let text = '';
28821 (tNodeType & 1 /* Text */) && (text += '|Text');
28822 (tNodeType & 2 /* Element */) && (text += '|Element');
28823 (tNodeType & 4 /* Container */) && (text += '|Container');
28824 (tNodeType & 8 /* ElementContainer */) && (text += '|ElementContainer');
28825 (tNodeType & 16 /* Projection */) && (text += '|Projection');
28826 (tNodeType & 32 /* Icu */) && (text += '|IcuContainer');
28827 (tNodeType & 64 /* Placeholder */) && (text += '|Placeholder');
28828 return text.length > 0 ? text.substring(1) : text;
28829 }
28830
28831 /**
28832 * @license
28833 * Copyright Google LLC All Rights Reserved.
28834 *
28835 * Use of this source code is governed by an MIT-style license that can be
28836 * found in the LICENSE file at https://angular.io/license
28837 */
28838 function assertTNodeType(tNode, expectedTypes, message) {
28839 assertDefined(tNode, 'should be called with a TNode');
28840 if ((tNode.type & expectedTypes) === 0) {
28841 throwError(message ||
28842 `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
28843 }
28844 }
28845 function assertPureTNodeType(type) {
28846 if (!(type === 2 /* Element */ || //
28847 type === 1 /* Text */ || //
28848 type === 4 /* Container */ || //
28849 type === 8 /* ElementContainer */ || //
28850 type === 32 /* Icu */ || //
28851 type === 16 /* Projection */ || //
28852 type === 64 /* Placeholder */)) {
28853 throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
28854 }
28855 }
28856
28857 /**
28858 * Assigns all attribute values to the provided element via the inferred renderer.
28859 *
28860 * This function accepts two forms of attribute entries:
28861 *
28862 * default: (key, value):
28863 * attrs = [key1, value1, key2, value2]
28864 *
28865 * namespaced: (NAMESPACE_MARKER, uri, name, value)
28866 * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
28867 *
28868 * The `attrs` array can contain a mix of both the default and namespaced entries.
28869 * The "default" values are set without a marker, but if the function comes across
28870 * a marker value then it will attempt to set a namespaced value. If the marker is
28871 * not of a namespaced value then the function will quit and return the index value
28872 * where it stopped during the iteration of the attrs array.
28873 *
28874 * See [AttributeMarker] to understand what the namespace marker value is.
28875 *
28876 * Note that this instruction does not support assigning style and class values to
28877 * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
28878 * are applied to an element.
28879 * @param renderer The renderer to be used
28880 * @param native The element that the attributes will be assigned to
28881 * @param attrs The attribute array of values that will be assigned to the element
28882 * @returns the index value that was last accessed in the attributes array
28883 */
28884 function setUpAttributes(renderer, native, attrs) {
28885 const isProc = isProceduralRenderer(renderer);
28886 let i = 0;
28887 while (i < attrs.length) {
28888 const value = attrs[i];
28889 if (typeof value === 'number') {
28890 // only namespaces are supported. Other value types (such as style/class
28891 // entries) are not supported in this function.
28892 if (value !== 0 /* NamespaceURI */) {
28893 break;
28894 }
28895 // we just landed on the marker value ... therefore
28896 // we should skip to the next entry
28897 i++;
28898 const namespaceURI = attrs[i++];
28899 const attrName = attrs[i++];
28900 const attrVal = attrs[i++];
28901 ngDevMode && ngDevMode.rendererSetAttribute++;
28902 isProc ?
28903 renderer.setAttribute(native, attrName, attrVal, namespaceURI) :
28904 native.setAttributeNS(namespaceURI, attrName, attrVal);
28905 }
28906 else {
28907 // attrName is string;
28908 const attrName = value;
28909 const attrVal = attrs[++i];
28910 // Standard attributes
28911 ngDevMode && ngDevMode.rendererSetAttribute++;
28912 if (isAnimationProp(attrName)) {
28913 if (isProc) {
28914 renderer.setProperty(native, attrName, attrVal);
28915 }
28916 }
28917 else {
28918 isProc ?
28919 renderer.setAttribute(native, attrName, attrVal) :
28920 native.setAttribute(attrName, attrVal);
28921 }
28922 i++;
28923 }
28924 }
28925 // another piece of code may iterate over the same attributes array. Therefore
28926 // it may be helpful to return the exact spot where the attributes array exited
28927 // whether by running into an unsupported marker or if all the static values were
28928 // iterated over.
28929 return i;
28930 }
28931 function isAnimationProp(name) {
28932 // Perf note: accessing charCodeAt to check for the first character of a string is faster as
28933 // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
28934 // charCodeAt doesn't allocate memory to return a substring.
28935 return name.charCodeAt(0) === 64 /* AT_SIGN */;
28936 }
28937
28938 /**
28939 * @license
28940 * Copyright Google LLC All Rights Reserved.
28941 *
28942 * Use of this source code is governed by an MIT-style license that can be
28943 * found in the LICENSE file at https://angular.io/license
28944 */
28945 /// Parent Injector Utils ///////////////////////////////////////////////////////////////
28946 function hasParentInjector(parentLocation) {
28947 return parentLocation !== NO_PARENT_INJECTOR;
28948 }
28949 function getParentInjectorIndex(parentLocation) {
28950 ngDevMode && assertNumber(parentLocation, 'Number expected');
28951 ngDevMode && assertNotEqual(parentLocation, -1, 'Not a valid state.');
28952 const parentInjectorIndex = parentLocation & 32767 /* InjectorIndexMask */;
28953 ngDevMode &&
28954 assertGreaterThan(parentInjectorIndex, HEADER_OFFSET, 'Parent injector must be pointing past HEADER_OFFSET.');
28955 return parentLocation & 32767 /* InjectorIndexMask */;
28956 }
28957 function getParentInjectorViewOffset(parentLocation) {
28958 return parentLocation >> 16 /* ViewOffsetShift */;
28959 }
28960 /**
28961 * Unwraps a parent injector location number to find the view offset from the current injector,
28962 * then walks up the declaration view tree until the view is found that contains the parent
28963 * injector.
28964 *
28965 * @param location The location of the parent injector, which contains the view offset
28966 * @param startView The LView instance from which to start walking up the view tree
28967 * @returns The LView instance that contains the parent injector
28968 */
28969 function getParentInjectorView(location, startView) {
28970 let viewOffset = getParentInjectorViewOffset(location);
28971 let parentView = startView;
28972 // For most cases, the parent injector can be found on the host node (e.g. for component
28973 // or container), but we must keep the loop here to support the rarer case of deeply nested
28974 // <ng-template> tags or inline views, where the parent injector might live many views
28975 // above the child injector.
28976 while (viewOffset > 0) {
28977 parentView = parentView[DECLARATION_VIEW];
28978 viewOffset--;
28979 }
28980 return parentView;
28981 }
28982
28983 /**
28984 * @license
28985 * Copyright Google LLC All Rights Reserved.
28986 *
28987 * Use of this source code is governed by an MIT-style license that can be
28988 * found in the LICENSE file at https://angular.io/license
28989 */
28990 /**
28991 * Defines if the call to `inject` should include `viewProviders` in its resolution.
28992 *
28993 * This is set to true when we try to instantiate a component. This value is reset in
28994 * `getNodeInjectable` to a value which matches the declaration location of the token about to be
28995 * instantiated. This is done so that if we are injecting a token which was declared outside of
28996 * `viewProviders` we don't accidentally pull `viewProviders` in.
28997 *
28998 * Example:
28999 *
29000 * ```
29001 * @Injectable()
29002 * class MyService {
29003 * constructor(public value: String) {}
29004 * }
29005 *
29006 * @Component({
29007 * providers: [
29008 * MyService,
29009 * {provide: String, value: 'providers' }
29010 * ]
29011 * viewProviders: [
29012 * {provide: String, value: 'viewProviders'}
29013 * ]
29014 * })
29015 * class MyComponent {
29016 * constructor(myService: MyService, value: String) {
29017 * // We expect that Component can see into `viewProviders`.
29018 * expect(value).toEqual('viewProviders');
29019 * // `MyService` was not declared in `viewProviders` hence it can't see it.
29020 * expect(myService.value).toEqual('providers');
29021 * }
29022 * }
29023 *
29024 * ```
29025 */
29026 let includeViewProviders = true;
29027 function setIncludeViewProviders(v) {
29028 const oldValue = includeViewProviders;
29029 includeViewProviders = v;
29030 return oldValue;
29031 }
29032 /**
29033 * The number of slots in each bloom filter (used by DI). The larger this number, the fewer
29034 * directives that will share slots, and thus, the fewer false positives when checking for
29035 * the existence of a directive.
29036 */
29037 const BLOOM_SIZE = 256;
29038 const BLOOM_MASK = BLOOM_SIZE - 1;
29039 /**
29040 * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits,
29041 * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash
29042 * number.
29043 */
29044 const BLOOM_BUCKET_BITS = 5;
29045 /** Counter used to generate unique IDs for directives. */
29046 let nextNgElementId = 0;
29047 /**
29048 * Registers this directive as present in its node's injector by flipping the directive's
29049 * corresponding bit in the injector's bloom filter.
29050 *
29051 * @param injectorIndex The index of the node injector where this token should be registered
29052 * @param tView The TView for the injector's bloom filters
29053 * @param type The directive token to register
29054 */
29055 function bloomAdd(injectorIndex, tView, type) {
29056 ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
29057 let id;
29058 if (typeof type === 'string') {
29059 id = type.charCodeAt(0) || 0;
29060 }
29061 else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
29062 id = type[NG_ELEMENT_ID];
29063 }
29064 // Set a unique ID on the directive type, so if something tries to inject the directive,
29065 // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
29066 if (id == null) {
29067 id = type[NG_ELEMENT_ID] = nextNgElementId++;
29068 }
29069 // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
29070 // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
29071 const bloomHash = id & BLOOM_MASK;
29072 // Create a mask that targets the specific bit associated with the directive.
29073 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
29074 // to bit positions 0 - 31 in a 32 bit integer.
29075 const mask = 1 << bloomHash;
29076 // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`.
29077 // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask
29078 // should be written to.
29079 tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask;
29080 }
29081 /**
29082 * Creates (or gets an existing) injector for a given element or container.
29083 *
29084 * @param tNode for which an injector should be retrieved / created.
29085 * @param lView View where the node is stored
29086 * @returns Node injector
29087 */
29088 function getOrCreateNodeInjectorForNode(tNode, lView) {
29089 const existingInjectorIndex = getInjectorIndex(tNode, lView);
29090 if (existingInjectorIndex !== -1) {
29091 return existingInjectorIndex;
29092 }
29093 const tView = lView[TVIEW];
29094 if (tView.firstCreatePass) {
29095 tNode.injectorIndex = lView.length;
29096 insertBloom(tView.data, tNode); // foundation for node bloom
29097 insertBloom(lView, null); // foundation for cumulative bloom
29098 insertBloom(tView.blueprint, null);
29099 }
29100 const parentLoc = getParentInjectorLocation(tNode, lView);
29101 const injectorIndex = tNode.injectorIndex;
29102 // If a parent injector can't be found, its location is set to -1.
29103 // In that case, we don't need to set up a cumulative bloom
29104 if (hasParentInjector(parentLoc)) {
29105 const parentIndex = getParentInjectorIndex(parentLoc);
29106 const parentLView = getParentInjectorView(parentLoc, lView);
29107 const parentData = parentLView[TVIEW].data;
29108 // Creates a cumulative bloom filter that merges the parent's bloom filter
29109 // and its own cumulative bloom (which contains tokens for all ancestors)
29110 for (let i = 0; i < 8 /* BLOOM_SIZE */; i++) {
29111 lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
29112 }
29113 }
29114 lView[injectorIndex + 8 /* PARENT */] = parentLoc;
29115 return injectorIndex;
29116 }
29117 function insertBloom(arr, footer) {
29118 arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
29119 }
29120 function getInjectorIndex(tNode, lView) {
29121 if (tNode.injectorIndex === -1 ||
29122 // If the injector index is the same as its parent's injector index, then the index has been
29123 // copied down from the parent node. No injector has been created yet on this node.
29124 (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
29125 // After the first template pass, the injector index might exist but the parent values
29126 // might not have been calculated yet for this instance
29127 lView[tNode.injectorIndex + 8 /* PARENT */] === null) {
29128 return -1;
29129 }
29130 else {
29131 ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
29132 return tNode.injectorIndex;
29133 }
29134 }
29135 /**
29136 * Finds the index of the parent injector, with a view offset if applicable. Used to set the
29137 * parent injector initially.
29138 *
29139 * @returns Returns a number that is the combination of the number of LViews that we have to go up
29140 * to find the LView containing the parent inject AND the index of the injector within that LView.
29141 */
29142 function getParentInjectorLocation(tNode, lView) {
29143 if (tNode.parent && tNode.parent.injectorIndex !== -1) {
29144 // If we have a parent `TNode` and there is an injector associated with it we are done, because
29145 // the parent injector is within the current `LView`.
29146 return tNode.parent.injectorIndex; // ViewOffset is 0
29147 }
29148 // When parent injector location is computed it may be outside of the current view. (ie it could
29149 // be pointing to a declared parent location). This variable stores number of declaration parents
29150 // we need to walk up in order to find the parent injector location.
29151 let declarationViewOffset = 0;
29152 let parentTNode = null;
29153 let lViewCursor = lView;
29154 // The parent injector is not in the current `LView`. We will have to walk the declared parent
29155 // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
29156 // `NodeInjector`.
29157 while (lViewCursor !== null) {
29158 // First determine the `parentTNode` location. The parent pointer differs based on `TView.type`.
29159 const tView = lViewCursor[TVIEW];
29160 const tViewType = tView.type;
29161 if (tViewType === 2 /* Embedded */) {
29162 ngDevMode &&
29163 assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
29164 parentTNode = tView.declTNode;
29165 }
29166 else if (tViewType === 1 /* Component */) {
29167 // Components don't have `TView.declTNode` because each instance of component could be
29168 // inserted in different location, hence `TView.declTNode` is meaningless.
29169 parentTNode = lViewCursor[T_HOST];
29170 }
29171 else {
29172 ngDevMode && assertEqual(tView.type, 0 /* Root */, 'Root type expected');
29173 parentTNode = null;
29174 }
29175 if (parentTNode === null) {
29176 // If we have no parent, than we are done.
29177 return NO_PARENT_INJECTOR;
29178 }
29179 ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]);
29180 // Every iteration of the loop requires that we go to the declared parent.
29181 declarationViewOffset++;
29182 lViewCursor = lViewCursor[DECLARATION_VIEW];
29183 if (parentTNode.injectorIndex !== -1) {
29184 // We found a NodeInjector which points to something.
29185 return (parentTNode.injectorIndex |
29186 (declarationViewOffset << 16 /* ViewOffsetShift */));
29187 }
29188 }
29189 return NO_PARENT_INJECTOR;
29190 }
29191 /**
29192 * Makes a type or an injection token public to the DI system by adding it to an
29193 * injector's bloom filter.
29194 *
29195 * @param di The node injector in which a directive will be added
29196 * @param token The type or the injection token to be made public
29197 */
29198 function diPublicInInjector(injectorIndex, tView, token) {
29199 bloomAdd(injectorIndex, tView, token);
29200 }
29201 function notFoundValueOrThrow(notFoundValue, token, flags) {
29202 if (flags & InjectFlags.Optional) {
29203 return notFoundValue;
29204 }
29205 else {
29206 throwProviderNotFoundError(token, 'NodeInjector');
29207 }
29208 }
29209 /**
29210 * Returns the value associated to the given token from the ModuleInjector or throws exception
29211 *
29212 * @param lView The `LView` that contains the `tNode`
29213 * @param token The token to look for
29214 * @param flags Injection flags
29215 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
29216 * @returns the value from the injector or throws an exception
29217 */
29218 function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) {
29219 if (flags & InjectFlags.Optional && notFoundValue === undefined) {
29220 // This must be set or the NullInjector will throw for optional deps
29221 notFoundValue = null;
29222 }
29223 if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
29224 const moduleInjector = lView[INJECTOR];
29225 // switch to `injectInjectorOnly` implementation for module injector, since module injector
29226 // should not have access to Component/Directive DI scope (that may happen through
29227 // `directiveInject` implementation)
29228 const previousInjectImplementation = setInjectImplementation(undefined);
29229 try {
29230 if (moduleInjector) {
29231 return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
29232 }
29233 else {
29234 return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
29235 }
29236 }
29237 finally {
29238 setInjectImplementation(previousInjectImplementation);
29239 }
29240 }
29241 return notFoundValueOrThrow(notFoundValue, token, flags);
29242 }
29243 /**
29244 * Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
29245 *
29246 * Look for the injector providing the token by walking up the node injector tree and then
29247 * the module injector tree.
29248 *
29249 * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom
29250 * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`)
29251 *
29252 * @param tNode The Node where the search for the injector should start
29253 * @param lView The `LView` that contains the `tNode`
29254 * @param token The token to look for
29255 * @param flags Injection flags
29256 * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
29257 * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
29258 */
29259 function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) {
29260 if (tNode !== null) {
29261 const bloomHash = bloomHashBitOrFactory(token);
29262 // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
29263 // so just call the factory function to create it.
29264 if (typeof bloomHash === 'function') {
29265 if (!enterDI(lView, tNode, flags)) {
29266 // Failed to enter DI, try module injector instead. If a token is injected with the @Host
29267 // flag, the module injector is not searched for that token in Ivy.
29268 return (flags & InjectFlags.Host) ?
29269 notFoundValueOrThrow(notFoundValue, token, flags) :
29270 lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
29271 }
29272 try {
29273 const value = bloomHash();
29274 if (value == null && !(flags & InjectFlags.Optional)) {
29275 throwProviderNotFoundError(token);
29276 }
29277 else {
29278 return value;
29279 }
29280 }
29281 finally {
29282 leaveDI();
29283 }
29284 }
29285 else if (typeof bloomHash === 'number') {
29286 // A reference to the previous injector TView that was found while climbing the element
29287 // injector tree. This is used to know if viewProviders can be accessed on the current
29288 // injector.
29289 let previousTView = null;
29290 let injectorIndex = getInjectorIndex(tNode, lView);
29291 let parentLocation = NO_PARENT_INJECTOR;
29292 let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
29293 // If we should skip this injector, or if there is no injector on this node, start by
29294 // searching the parent injector.
29295 if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
29296 parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
29297 lView[injectorIndex + 8 /* PARENT */];
29298 if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
29299 injectorIndex = -1;
29300 }
29301 else {
29302 previousTView = lView[TVIEW];
29303 injectorIndex = getParentInjectorIndex(parentLocation);
29304 lView = getParentInjectorView(parentLocation, lView);
29305 }
29306 }
29307 // Traverse up the injector tree until we find a potential match or until we know there
29308 // *isn't* a match.
29309 while (injectorIndex !== -1) {
29310 ngDevMode && assertNodeInjector(lView, injectorIndex);
29311 // Check the current injector. If it matches, see if it contains token.
29312 const tView = lView[TVIEW];
29313 ngDevMode &&
29314 assertTNodeForLView(tView.data[injectorIndex + 8 /* TNODE */], lView);
29315 if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
29316 // At this point, we have an injector which *may* contain the token, so we step through
29317 // the providers and directives associated with the injector's corresponding node to get
29318 // the instance.
29319 const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode);
29320 if (instance !== NOT_FOUND) {
29321 return instance;
29322 }
29323 }
29324 parentLocation = lView[injectorIndex + 8 /* PARENT */];
29325 if (parentLocation !== NO_PARENT_INJECTOR &&
29326 shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* TNODE */] === hostTElementNode) &&
29327 bloomHasToken(bloomHash, injectorIndex, lView)) {
29328 // The def wasn't found anywhere on this node, so it was a false positive.
29329 // Traverse up the tree and continue searching.
29330 previousTView = tView;
29331 injectorIndex = getParentInjectorIndex(parentLocation);
29332 lView = getParentInjectorView(parentLocation, lView);
29333 }
29334 else {
29335 // If we should not search parent OR If the ancestor bloom filter value does not have the
29336 // bit corresponding to the directive we can give up on traversing up to find the specific
29337 // injector.
29338 injectorIndex = -1;
29339 }
29340 }
29341 }
29342 }
29343 return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
29344 }
29345 const NOT_FOUND = {};
29346 function createNodeInjector() {
29347 return new NodeInjector(getCurrentTNode(), getLView());
29348 }
29349 function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) {
29350 const currentTView = lView[TVIEW];
29351 const tNode = currentTView.data[injectorIndex + 8 /* TNODE */];
29352 // First, we need to determine if view providers can be accessed by the starting element.
29353 // There are two possibilities
29354 const canAccessViewProviders = previousTView == null ?
29355 // 1) This is the first invocation `previousTView == null` which means that we are at the
29356 // `TNode` of where injector is starting to look. In such a case the only time we are allowed
29357 // to look into the ViewProviders is if:
29358 // - we are on a component
29359 // - AND the injector set `includeViewProviders` to true (implying that the token can see
29360 // ViewProviders because it is the Component or a Service which itself was declared in
29361 // ViewProviders)
29362 (isComponentHost(tNode) && includeViewProviders) :
29363 // 2) `previousTView != null` which means that we are now walking across the parent nodes.
29364 // In such a case we are only allowed to look into the ViewProviders if:
29365 // - We just crossed from child View to Parent View `previousTView != currentTView`
29366 // - AND the parent TNode is an Element.
29367 // This means that we just came from the Component's View and therefore are allowed to see
29368 // into the ViewProviders.
29369 (previousTView != currentTView && ((tNode.type & 3 /* AnyRNode */) !== 0));
29370 // This special case happens when there is a @host on the inject and when we are searching
29371 // on the host element node.
29372 const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode;
29373 const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase);
29374 if (injectableIdx !== null) {
29375 return getNodeInjectable(lView, currentTView, injectableIdx, tNode);
29376 }
29377 else {
29378 return NOT_FOUND;
29379 }
29380 }
29381 /**
29382 * Searches for the given token among the node's directives and providers.
29383 *
29384 * @param tNode TNode on which directives are present.
29385 * @param tView The tView we are currently processing
29386 * @param token Provider token or type of a directive to look for.
29387 * @param canAccessViewProviders Whether view providers should be considered.
29388 * @param isHostSpecialCase Whether the host special case applies.
29389 * @returns Index of a found directive or provider, or null when none found.
29390 */
29391 function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) {
29392 const nodeProviderIndexes = tNode.providerIndexes;
29393 const tInjectables = tView.data;
29394 const injectablesStart = nodeProviderIndexes & 1048575 /* ProvidersStartIndexMask */;
29395 const directivesStart = tNode.directiveStart;
29396 const directiveEnd = tNode.directiveEnd;
29397 const cptViewProvidersCount = nodeProviderIndexes >> 20 /* CptViewProvidersCountShift */;
29398 const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount;
29399 // When the host special case applies, only the viewProviders and the component are visible
29400 const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd;
29401 for (let i = startingIndex; i < endIndex; i++) {
29402 const providerTokenOrDef = tInjectables[i];
29403 if (i < directivesStart && token === providerTokenOrDef ||
29404 i >= directivesStart && providerTokenOrDef.type === token) {
29405 return i;
29406 }
29407 }
29408 if (isHostSpecialCase) {
29409 const dirDef = tInjectables[directivesStart];
29410 if (dirDef && isComponentDef(dirDef) && dirDef.type === token) {
29411 return directivesStart;
29412 }
29413 }
29414 return null;
29415 }
29416 /**
29417 * Retrieve or instantiate the injectable from the `LView` at particular `index`.
29418 *
29419 * This function checks to see if the value has already been instantiated and if so returns the
29420 * cached `injectable`. Otherwise if it detects that the value is still a factory it
29421 * instantiates the `injectable` and caches the value.
29422 */
29423 function getNodeInjectable(lView, tView, index, tNode) {
29424 let value = lView[index];
29425 const tData = tView.data;
29426 if (isFactory(value)) {
29427 const factory = value;
29428 if (factory.resolving) {
29429 throwCyclicDependencyError(stringifyForError(tData[index]));
29430 }
29431 const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
29432 factory.resolving = true;
29433 const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
29434 const success = enterDI(lView, tNode, InjectFlags.Default);
29435 ngDevMode &&
29436 assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.');
29437 try {
29438 value = lView[index] = factory.factory(undefined, tData, lView, tNode);
29439 // This code path is hit for both directives and providers.
29440 // For perf reasons, we want to avoid searching for hooks on providers.
29441 // It does no harm to try (the hooks just won't exist), but the extra
29442 // checks are unnecessary and this is a hot path. So we check to see
29443 // if the index of the dependency is in the directive range for this
29444 // tNode. If it's not, we know it's a provider and skip hook registration.
29445 if (tView.firstCreatePass && index >= tNode.directiveStart) {
29446 ngDevMode && assertDirectiveDef(tData[index]);
29447 registerPreOrderHooks(index, tData[index], tView);
29448 }
29449 }
29450 finally {
29451 previousInjectImplementation !== null &&
29452 setInjectImplementation(previousInjectImplementation);
29453 setIncludeViewProviders(previousIncludeViewProviders);
29454 factory.resolving = false;
29455 leaveDI();
29456 }
29457 }
29458 return value;
29459 }
29460 /**
29461 * Returns the bit in an injector's bloom filter that should be used to determine whether or not
29462 * the directive might be provided by the injector.
29463 *
29464 * When a directive is public, it is added to the bloom filter and given a unique ID that can be
29465 * retrieved on the Type. When the directive isn't public or the token is not a directive `null`
29466 * is returned as the node injector can not possibly provide that token.
29467 *
29468 * @param token the injection token
29469 * @returns the matching bit to check in the bloom filter or `null` if the token is not known.
29470 * When the returned value is negative then it represents special values such as `Injector`.
29471 */
29472 function bloomHashBitOrFactory(token) {
29473 ngDevMode && assertDefined(token, 'token must be defined');
29474 if (typeof token === 'string') {
29475 return token.charCodeAt(0) || 0;
29476 }
29477 const tokenId =
29478 // First check with `hasOwnProperty` so we don't get an inherited ID.
29479 token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined;
29480 // Negative token IDs are used for special objects such as `Injector`
29481 if (typeof tokenId === 'number') {
29482 if (tokenId >= 0) {
29483 return tokenId & BLOOM_MASK;
29484 }
29485 else {
29486 ngDevMode &&
29487 assertEqual(tokenId, -1 /* Injector */, 'Expecting to get Special Injector Id');
29488 return createNodeInjector;
29489 }
29490 }
29491 else {
29492 return tokenId;
29493 }
29494 }
29495 function bloomHasToken(bloomHash, injectorIndex, injectorView) {
29496 // Create a mask that targets the specific bit associated with the directive we're looking for.
29497 // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
29498 // to bit positions 0 - 31 in a 32 bit integer.
29499 const mask = 1 << bloomHash;
29500 // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of
29501 // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset
29502 // that should be used.
29503 const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)];
29504 // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
29505 // this injector is a potential match.
29506 return !!(value & mask);
29507 }
29508 /** Returns true if flags prevent parent injector from being searched for tokens */
29509 function shouldSearchParent(flags, isFirstHostTNode) {
29510 return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode);
29511 }
29512 class NodeInjector {
29513 constructor(_tNode, _lView) {
29514 this._tNode = _tNode;
29515 this._lView = _lView;
29516 }
29517 get(token, notFoundValue) {
29518 return getOrCreateInjectable(this._tNode, this._lView, token, undefined, notFoundValue);
29519 }
29520 }
29521
29522 /**
29523 * @license
29524 * Copyright Google LLC All Rights Reserved.
29525 *
29526 * Use of this source code is governed by an MIT-style license that can be
29527 * found in the LICENSE file at https://angular.io/license
29528 */
29529 const ANNOTATIONS = '__annotations__';
29530 const PARAMETERS = '__parameters__';
29531 const PROP_METADATA = '__prop__metadata__';
29532 /**
29533 * @suppress {globalThis}
29534 */
29535 function makeDecorator(name, props, parentClass, additionalProcessing, typeFn) {
29536 return noSideEffects(() => {
29537 const metaCtor = makeMetadataCtor(props);
29538 function DecoratorFactory(...args) {
29539 if (this instanceof DecoratorFactory) {
29540 metaCtor.call(this, ...args);
29541 return this;
29542 }
29543 const annotationInstance = new DecoratorFactory(...args);
29544 return function TypeDecorator(cls) {
29545 if (typeFn)
29546 typeFn(cls, ...args);
29547 // Use of Object.defineProperty is important since it creates non-enumerable property which
29548 // prevents the property is copied during subclassing.
29549 const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
29550 cls[ANNOTATIONS] :
29551 Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
29552 annotations.push(annotationInstance);
29553 if (additionalProcessing)
29554 additionalProcessing(cls);
29555 return cls;
29556 };
29557 }
29558 if (parentClass) {
29559 DecoratorFactory.prototype = Object.create(parentClass.prototype);
29560 }
29561 DecoratorFactory.prototype.ngMetadataName = name;
29562 DecoratorFactory.annotationCls = DecoratorFactory;
29563 return DecoratorFactory;
29564 });
29565 }
29566 function makeMetadataCtor(props) {
29567 return function ctor(...args) {
29568 if (props) {
29569 const values = props(...args);
29570 for (const propName in values) {
29571 this[propName] = values[propName];
29572 }
29573 }
29574 };
29575 }
29576 function makeParamDecorator(name, props, parentClass) {
29577 return noSideEffects(() => {
29578 const metaCtor = makeMetadataCtor(props);
29579 function ParamDecoratorFactory(...args) {
29580 if (this instanceof ParamDecoratorFactory) {
29581 metaCtor.apply(this, args);
29582 return this;
29583 }
29584 const annotationInstance = new ParamDecoratorFactory(...args);
29585 ParamDecorator.annotation = annotationInstance;
29586 return ParamDecorator;
29587 function ParamDecorator(cls, unusedKey, index) {
29588 // Use of Object.defineProperty is important since it creates non-enumerable property which
29589 // prevents the property is copied during subclassing.
29590 const parameters = cls.hasOwnProperty(PARAMETERS) ?
29591 cls[PARAMETERS] :
29592 Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS];
29593 // there might be gaps if some in between parameters do not have annotations.
29594 // we pad with nulls.
29595 while (parameters.length <= index) {
29596 parameters.push(null);
29597 }
29598 (parameters[index] = parameters[index] || []).push(annotationInstance);
29599 return cls;
29600 }
29601 }
29602 if (parentClass) {
29603 ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
29604 }
29605 ParamDecoratorFactory.prototype.ngMetadataName = name;
29606 ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
29607 return ParamDecoratorFactory;
29608 });
29609 }
29610 function makePropDecorator(name, props, parentClass, additionalProcessing) {
29611 return noSideEffects(() => {
29612 const metaCtor = makeMetadataCtor(props);
29613 function PropDecoratorFactory(...args) {
29614 if (this instanceof PropDecoratorFactory) {
29615 metaCtor.apply(this, args);
29616 return this;
29617 }
29618 const decoratorInstance = new PropDecoratorFactory(...args);
29619 function PropDecorator(target, name) {
29620 const constructor = target.constructor;
29621 // Use of Object.defineProperty is important because it creates a non-enumerable property
29622 // which prevents the property from being copied during subclassing.
29623 const meta = constructor.hasOwnProperty(PROP_METADATA) ?
29624 constructor[PROP_METADATA] :
29625 Object.defineProperty(constructor, PROP_METADATA, { value: {} })[PROP_METADATA];
29626 meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
29627 meta[name].unshift(decoratorInstance);
29628 if (additionalProcessing)
29629 additionalProcessing(target, name, ...args);
29630 }
29631 return PropDecorator;
29632 }
29633 if (parentClass) {
29634 PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
29635 }
29636 PropDecoratorFactory.prototype.ngMetadataName = name;
29637 PropDecoratorFactory.annotationCls = PropDecoratorFactory;
29638 return PropDecoratorFactory;
29639 });
29640 }
29641
29642 /**
29643 * @license
29644 * Copyright Google LLC All Rights Reserved.
29645 *
29646 * Use of this source code is governed by an MIT-style license that can be
29647 * found in the LICENSE file at https://angular.io/license
29648 */
29649 function CREATE_ATTRIBUTE_DECORATOR__PRE_R3__() {
29650 return makeParamDecorator('Attribute', (attributeName) => ({ attributeName }));
29651 }
29652 const CREATE_ATTRIBUTE_DECORATOR_IMPL = CREATE_ATTRIBUTE_DECORATOR__PRE_R3__;
29653 /**
29654 * Attribute decorator and metadata.
29655 *
29656 * @Annotation
29657 * @publicApi
29658 */
29659 const Attribute$1 = CREATE_ATTRIBUTE_DECORATOR_IMPL();
29660
29661 /**
29662 * @license
29663 * Copyright Google LLC All Rights Reserved.
29664 *
29665 * Use of this source code is governed by an MIT-style license that can be
29666 * found in the LICENSE file at https://angular.io/license
29667 */
29668 /**
29669 * Creates a token that can be used in a DI Provider.
29670 *
29671 * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
29672 * runtime representation) such as when injecting an interface, callable type, array or
29673 * parameterized type.
29674 *
29675 * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
29676 * the `Injector`. This provides additional level of type safety.
29677 *
29678 * ```
29679 * interface MyInterface {...}
29680 * var myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
29681 * // myInterface is inferred to be MyInterface.
29682 * ```
29683 *
29684 * When creating an `InjectionToken`, you can optionally specify a factory function which returns
29685 * (possibly by creating) a default value of the parameterized type `T`. This sets up the
29686 * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
29687 * application's root injector. If the factory function, which takes zero arguments, needs to inject
29688 * dependencies, it can do so using the `inject` function. See below for an example.
29689 *
29690 * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
29691 * overrides the above behavior and marks the token as belonging to a particular `@NgModule`. As
29692 * mentioned above, `'root'` is the default value for `providedIn`.
29693 *
29694 * @usageNotes
29695 * ### Basic Example
29696 *
29697 * ### Plain InjectionToken
29698 *
29699 * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
29700 *
29701 * ### Tree-shakable InjectionToken
29702 *
29703 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
29704 *
29705 *
29706 * @publicApi
29707 */
29708 class InjectionToken {
29709 constructor(_desc, options) {
29710 this._desc = _desc;
29711 /** @internal */
29712 this.ngMetadataName = 'InjectionToken';
29713 this.ɵprov = undefined;
29714 if (typeof options == 'number') {
29715 (typeof ngDevMode === 'undefined' || ngDevMode) &&
29716 assertLessThan(options, 0, 'Only negative numbers are supported here');
29717 // This is a special hack to assign __NG_ELEMENT_ID__ to this instance.
29718 // See `InjectorMarkers`
29719 this.__NG_ELEMENT_ID__ = options;
29720 }
29721 else if (options !== undefined) {
29722 this.ɵprov = ɵɵdefineInjectable({
29723 token: this,
29724 providedIn: options.providedIn || 'root',
29725 factory: options.factory,
29726 });
29727 }
29728 }
29729 toString() {
29730 return `InjectionToken ${this._desc}`;
29731 }
29732 }
29733
29734 /**
29735 * @license
29736 * Copyright Google LLC All Rights Reserved.
29737 *
29738 * Use of this source code is governed by an MIT-style license that can be
29739 * found in the LICENSE file at https://angular.io/license
29740 */
29741 /**
29742 * A DI token that you can use to create a virtual [provider](guide/glossary#provider)
29743 * that will populate the `entryComponents` field of components and NgModules
29744 * based on its `useValue` property value.
29745 * All components that are referenced in the `useValue` value (either directly
29746 * or in a nested array or map) are added to the `entryComponents` property.
29747 *
29748 * @usageNotes
29749 *
29750 * The following example shows how the router can populate the `entryComponents`
29751 * field of an NgModule based on a router configuration that refers
29752 * to components.
29753 *
29754 * ```typescript
29755 * // helper function inside the router
29756 * function provideRoutes(routes) {
29757 * return [
29758 * {provide: ROUTES, useValue: routes},
29759 * {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: routes, multi: true}
29760 * ];
29761 * }
29762 *
29763 * // user code
29764 * let routes = [
29765 * {path: '/root', component: RootComp},
29766 * {path: '/teams', component: TeamsComp}
29767 * ];
29768 *
29769 * @NgModule({
29770 * providers: [provideRoutes(routes)]
29771 * })
29772 * class ModuleWithRoutes {}
29773 * ```
29774 *
29775 * @publicApi
29776 * @deprecated Since 9.0.0. With Ivy, this property is no longer necessary.
29777 */
29778 const ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForEntryComponents');
29779 // Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
29780 // explicitly set. This value will be changed to `true` in v12.
29781 // TODO(misko): switch the default in v12 to `true`. See: packages/compiler/src/core.ts
29782 const emitDistinctChangesOnlyDefaultValue$1 = false;
29783 /**
29784 * Base class for query metadata.
29785 *
29786 * @see `ContentChildren`.
29787 * @see `ContentChild`.
29788 * @see `ViewChildren`.
29789 * @see `ViewChild`.
29790 *
29791 * @publicApi
29792 */
29793 class Query {
29794 }
29795 const ɵ0$1 = (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue$1 }, data));
29796 /**
29797 * ContentChildren decorator and metadata.
29798 *
29799 *
29800 * @Annotation
29801 * @publicApi
29802 */
29803 const ContentChildren = makePropDecorator('ContentChildren', ɵ0$1, Query);
29804 const ɵ1 = (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data));
29805 /**
29806 * ContentChild decorator and metadata.
29807 *
29808 *
29809 * @Annotation
29810 *
29811 * @publicApi
29812 */
29813 const ContentChild = makePropDecorator('ContentChild', ɵ1, Query);
29814 const ɵ2 = (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue$1 }, data));
29815 /**
29816 * ViewChildren decorator and metadata.
29817 *
29818 * @Annotation
29819 * @publicApi
29820 */
29821 const ViewChildren = makePropDecorator('ViewChildren', ɵ2, Query);
29822 const ɵ3 = (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data));
29823 /**
29824 * ViewChild decorator and metadata.
29825 *
29826 * @Annotation
29827 * @publicApi
29828 */
29829 const ViewChild = makePropDecorator('ViewChild', ɵ3, Query);
29830
29831 /**
29832 * @license
29833 * Copyright Google LLC All Rights Reserved.
29834 *
29835 * Use of this source code is governed by an MIT-style license that can be
29836 * found in the LICENSE file at https://angular.io/license
29837 */
29838 var R3ResolvedDependencyType$1;
29839 (function (R3ResolvedDependencyType) {
29840 R3ResolvedDependencyType[R3ResolvedDependencyType["Token"] = 0] = "Token";
29841 R3ResolvedDependencyType[R3ResolvedDependencyType["Attribute"] = 1] = "Attribute";
29842 R3ResolvedDependencyType[R3ResolvedDependencyType["ChangeDetectorRef"] = 2] = "ChangeDetectorRef";
29843 R3ResolvedDependencyType[R3ResolvedDependencyType["Invalid"] = 3] = "Invalid";
29844 })(R3ResolvedDependencyType$1 || (R3ResolvedDependencyType$1 = {}));
29845 var R3FactoryTarget$1;
29846 (function (R3FactoryTarget) {
29847 R3FactoryTarget[R3FactoryTarget["Directive"] = 0] = "Directive";
29848 R3FactoryTarget[R3FactoryTarget["Component"] = 1] = "Component";
29849 R3FactoryTarget[R3FactoryTarget["Injectable"] = 2] = "Injectable";
29850 R3FactoryTarget[R3FactoryTarget["Pipe"] = 3] = "Pipe";
29851 R3FactoryTarget[R3FactoryTarget["NgModule"] = 4] = "NgModule";
29852 })(R3FactoryTarget$1 || (R3FactoryTarget$1 = {}));
29853 var ViewEncapsulation$2;
29854 (function (ViewEncapsulation) {
29855 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
29856 // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
29857 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
29858 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
29859 })(ViewEncapsulation$2 || (ViewEncapsulation$2 = {}));
29860
29861 /**
29862 * @license
29863 * Copyright Google LLC All Rights Reserved.
29864 *
29865 * Use of this source code is governed by an MIT-style license that can be
29866 * found in the LICENSE file at https://angular.io/license
29867 */
29868 /**
29869 * @description
29870 *
29871 * Represents a type that a Component or other object is instances of.
29872 *
29873 * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is represented by
29874 * the `MyCustomComponent` constructor function.
29875 *
29876 * @publicApi
29877 */
29878 const Type$2 = Function;
29879 function isType(v) {
29880 return typeof v === 'function';
29881 }
29882
29883 /**
29884 * @license
29885 * Copyright Google LLC All Rights Reserved.
29886 *
29887 * Use of this source code is governed by an MIT-style license that can be
29888 * found in the LICENSE file at https://angular.io/license
29889 */
29890 function removeFromArray(arr, index) {
29891 // perf: array.pop is faster than array.splice!
29892 if (index >= arr.length - 1) {
29893 return arr.pop();
29894 }
29895 else {
29896 return arr.splice(index, 1)[0];
29897 }
29898 }
29899 function newArray$1(size, value) {
29900 const list = [];
29901 for (let i = 0; i < size; i++) {
29902 list.push(value);
29903 }
29904 return list;
29905 }
29906
29907 /**
29908 * @license
29909 * Copyright Google LLC All Rights Reserved.
29910 *
29911 * Use of this source code is governed by an MIT-style license that can be
29912 * found in the LICENSE file at https://angular.io/license
29913 */
29914 /*
29915 * #########################
29916 * Attention: These Regular expressions have to hold even if the code is minified!
29917 * ##########################
29918 */
29919 /**
29920 * Regular expression that detects pass-through constructors for ES5 output. This Regex
29921 * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
29922 * it intends to capture the pattern where existing constructors have been downleveled from
29923 * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
29924 *
29925 * ```
29926 * function MyClass() {
29927 * var _this = _super.apply(this, arguments) || this;
29928 * ```
29929 *
29930 * ```
29931 * function MyClass() {
29932 * var _this = _super.apply(this, __spread(arguments)) || this;
29933 * ```
29934 *
29935 * More details can be found in: https://github.com/angular/angular/issues/38453.
29936 */
29937 const ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|[^()]+\(arguments\))\)/;
29938 /** Regular expression that detects ES2015 classes which extend from other classes. */
29939 const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
29940 /**
29941 * Regular expression that detects ES2015 classes which extend from other classes and
29942 * have an explicit constructor defined.
29943 */
29944 const ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
29945 /**
29946 * Regular expression that detects ES2015 classes which extend from other classes
29947 * and inherit a constructor.
29948 */
29949 const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/;
29950 /**
29951 * Determine whether a stringified type is a class which delegates its constructor
29952 * to its parent.
29953 *
29954 * This is not trivial since compiled code can actually contain a constructor function
29955 * even if the original source code did not. For instance, when the child class contains
29956 * an initialized instance property.
29957 */
29958 function isDelegateCtor(typeStr) {
29959 return ES5_DELEGATE_CTOR.test(typeStr) ||
29960 ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
29961 (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
29962 }
29963 class ReflectionCapabilities {
29964 constructor(reflect) {
29965 this._reflect = reflect || _global$1['Reflect'];
29966 }
29967 isReflectionEnabled() {
29968 return true;
29969 }
29970 factory(t) {
29971 return (...args) => new t(...args);
29972 }
29973 /** @internal */
29974 _zipTypesAndAnnotations(paramTypes, paramAnnotations) {
29975 let result;
29976 if (typeof paramTypes === 'undefined') {
29977 result = newArray$1(paramAnnotations.length);
29978 }
29979 else {
29980 result = newArray$1(paramTypes.length);
29981 }
29982 for (let i = 0; i < result.length; i++) {
29983 // TS outputs Object for parameters without types, while Traceur omits
29984 // the annotations. For now we preserve the Traceur behavior to aid
29985 // migration, but this can be revisited.
29986 if (typeof paramTypes === 'undefined') {
29987 result[i] = [];
29988 }
29989 else if (paramTypes[i] && paramTypes[i] != Object) {
29990 result[i] = [paramTypes[i]];
29991 }
29992 else {
29993 result[i] = [];
29994 }
29995 if (paramAnnotations && paramAnnotations[i] != null) {
29996 result[i] = result[i].concat(paramAnnotations[i]);
29997 }
29998 }
29999 return result;
30000 }
30001 _ownParameters(type, parentCtor) {
30002 const typeStr = type.toString();
30003 // If we have no decorators, we only have function.length as metadata.
30004 // In that case, to detect whether a child class declared an own constructor or not,
30005 // we need to look inside of that constructor to check whether it is
30006 // just calling the parent.
30007 // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
30008 // that sets 'design:paramtypes' to []
30009 // if a class inherits from another class but has no ctor declared itself.
30010 if (isDelegateCtor(typeStr)) {
30011 return null;
30012 }
30013 // Prefer the direct API.
30014 if (type.parameters && type.parameters !== parentCtor.parameters) {
30015 return type.parameters;
30016 }
30017 // API of tsickle for lowering decorators to properties on the class.
30018 const tsickleCtorParams = type.ctorParameters;
30019 if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
30020 // Newer tsickle uses a function closure
30021 // Retain the non-function case for compatibility with older tsickle
30022 const ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
30023 const paramTypes = ctorParameters.map((ctorParam) => ctorParam && ctorParam.type);
30024 const paramAnnotations = ctorParameters.map((ctorParam) => ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
30025 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
30026 }
30027 // API for metadata created by invoking the decorators.
30028 const paramAnnotations = type.hasOwnProperty(PARAMETERS) && type[PARAMETERS];
30029 const paramTypes = this._reflect && this._reflect.getOwnMetadata &&
30030 this._reflect.getOwnMetadata('design:paramtypes', type);
30031 if (paramTypes || paramAnnotations) {
30032 return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
30033 }
30034 // If a class has no decorators, at least create metadata
30035 // based on function.length.
30036 // Note: We know that this is a real constructor as we checked
30037 // the content of the constructor above.
30038 return newArray$1(type.length);
30039 }
30040 parameters(type) {
30041 // Note: only report metadata if we have at least one class decorator
30042 // to stay in sync with the static reflector.
30043 if (!isType(type)) {
30044 return [];
30045 }
30046 const parentCtor = getParentCtor(type);
30047 let parameters = this._ownParameters(type, parentCtor);
30048 if (!parameters && parentCtor !== Object) {
30049 parameters = this.parameters(parentCtor);
30050 }
30051 return parameters || [];
30052 }
30053 _ownAnnotations(typeOrFunc, parentCtor) {
30054 // Prefer the direct API.
30055 if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
30056 let annotations = typeOrFunc.annotations;
30057 if (typeof annotations === 'function' && annotations.annotations) {
30058 annotations = annotations.annotations;
30059 }
30060 return annotations;
30061 }
30062 // API of tsickle for lowering decorators to properties on the class.
30063 if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) {
30064 return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators);
30065 }
30066 // API for metadata created by invoking the decorators.
30067 if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
30068 return typeOrFunc[ANNOTATIONS];
30069 }
30070 return null;
30071 }
30072 annotations(typeOrFunc) {
30073 if (!isType(typeOrFunc)) {
30074 return [];
30075 }
30076 const parentCtor = getParentCtor(typeOrFunc);
30077 const ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
30078 const parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
30079 return parentAnnotations.concat(ownAnnotations);
30080 }
30081 _ownPropMetadata(typeOrFunc, parentCtor) {
30082 // Prefer the direct API.
30083 if (typeOrFunc.propMetadata &&
30084 typeOrFunc.propMetadata !== parentCtor.propMetadata) {
30085 let propMetadata = typeOrFunc.propMetadata;
30086 if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
30087 propMetadata = propMetadata.propMetadata;
30088 }
30089 return propMetadata;
30090 }
30091 // API of tsickle for lowering decorators to properties on the class.
30092 if (typeOrFunc.propDecorators &&
30093 typeOrFunc.propDecorators !== parentCtor.propDecorators) {
30094 const propDecorators = typeOrFunc.propDecorators;
30095 const propMetadata = {};
30096 Object.keys(propDecorators).forEach(prop => {
30097 propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
30098 });
30099 return propMetadata;
30100 }
30101 // API for metadata created by invoking the decorators.
30102 if (typeOrFunc.hasOwnProperty(PROP_METADATA)) {
30103 return typeOrFunc[PROP_METADATA];
30104 }
30105 return null;
30106 }
30107 propMetadata(typeOrFunc) {
30108 if (!isType(typeOrFunc)) {
30109 return {};
30110 }
30111 const parentCtor = getParentCtor(typeOrFunc);
30112 const propMetadata = {};
30113 if (parentCtor !== Object) {
30114 const parentPropMetadata = this.propMetadata(parentCtor);
30115 Object.keys(parentPropMetadata).forEach((propName) => {
30116 propMetadata[propName] = parentPropMetadata[propName];
30117 });
30118 }
30119 const ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
30120 if (ownPropMetadata) {
30121 Object.keys(ownPropMetadata).forEach((propName) => {
30122 const decorators = [];
30123 if (propMetadata.hasOwnProperty(propName)) {
30124 decorators.push(...propMetadata[propName]);
30125 }
30126 decorators.push(...ownPropMetadata[propName]);
30127 propMetadata[propName] = decorators;
30128 });
30129 }
30130 return propMetadata;
30131 }
30132 ownPropMetadata(typeOrFunc) {
30133 if (!isType(typeOrFunc)) {
30134 return {};
30135 }
30136 return this._ownPropMetadata(typeOrFunc, getParentCtor(typeOrFunc)) || {};
30137 }
30138 hasLifecycleHook(type, lcProperty) {
30139 return type instanceof Type$2 && lcProperty in type.prototype;
30140 }
30141 guards(type) {
30142 return {};
30143 }
30144 getter(name) {
30145 return new Function('o', 'return o.' + name + ';');
30146 }
30147 setter(name) {
30148 return new Function('o', 'v', 'return o.' + name + ' = v;');
30149 }
30150 method(name) {
30151 const functionBody = `if (!o.${name}) throw new Error('"${name}" is undefined');
30152 return o.${name}.apply(o, args);`;
30153 return new Function('o', 'args', functionBody);
30154 }
30155 // There is not a concept of import uri in Js, but this is useful in developing Dart applications.
30156 importUri(type) {
30157 // StaticSymbol
30158 if (typeof type === 'object' && type['filePath']) {
30159 return type['filePath'];
30160 }
30161 // Runtime type
30162 return `./${stringify$1(type)}`;
30163 }
30164 resourceUri(type) {
30165 return `./${stringify$1(type)}`;
30166 }
30167 resolveIdentifier(name, moduleUrl, members, runtime) {
30168 return runtime;
30169 }
30170 resolveEnum(enumIdentifier, name) {
30171 return enumIdentifier[name];
30172 }
30173 }
30174 function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
30175 if (!decoratorInvocations) {
30176 return [];
30177 }
30178 return decoratorInvocations.map(decoratorInvocation => {
30179 const decoratorType = decoratorInvocation.type;
30180 const annotationCls = decoratorType.annotationCls;
30181 const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
30182 return new annotationCls(...annotationArgs);
30183 });
30184 }
30185 function getParentCtor(ctor) {
30186 const parentProto = ctor.prototype ? Object.getPrototypeOf(ctor.prototype) : null;
30187 const parentCtor = parentProto ? parentProto.constructor : null;
30188 // Note: We always use `Object` as the null value
30189 // to simplify checking later on.
30190 return parentCtor || Object;
30191 }
30192
30193 /**
30194 * @license
30195 * Copyright Google LLC All Rights Reserved.
30196 *
30197 * Use of this source code is governed by an MIT-style license that can be
30198 * found in the LICENSE file at https://angular.io/license
30199 */
30200 const _THROW_IF_NOT_FOUND = {};
30201 const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
30202 /*
30203 * Name of a property (that we patch onto DI decorator), which is used as an annotation of which
30204 * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators
30205 * in the code, thus making them tree-shakable.
30206 */
30207 const DI_DECORATOR_FLAG = '__NG_DI_FLAG__';
30208 const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath';
30209 const NG_TOKEN_PATH = 'ngTokenPath';
30210 const NEW_LINE = /\n/gm;
30211 const NO_NEW_LINE = 'ɵ';
30212 const SOURCE = '__source';
30213 const ɵ0$2 = getClosureSafeProperty;
30214 const USE_VALUE$2 = getClosureSafeProperty({ provide: String, useValue: ɵ0$2 });
30215 /**
30216 * Current injector value used by `inject`.
30217 * - `undefined`: it is an error to call `inject`
30218 * - `null`: `inject` can be called but there is no injector (limp-mode).
30219 * - Injector instance: Use the injector for resolution.
30220 */
30221 let _currentInjector = undefined;
30222 function setCurrentInjector(injector) {
30223 const former = _currentInjector;
30224 _currentInjector = injector;
30225 return former;
30226 }
30227 function injectInjectorOnly(token, flags = InjectFlags.Default) {
30228 if (_currentInjector === undefined) {
30229 throw new Error(`inject() must be called from an injection context`);
30230 }
30231 else if (_currentInjector === null) {
30232 return injectRootLimpMode(token, undefined, flags);
30233 }
30234 else {
30235 return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
30236 }
30237 }
30238 function ɵɵinject(token, flags = InjectFlags.Default) {
30239 return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef$1(token), flags);
30240 }
30241 function injectArgs(types) {
30242 const args = [];
30243 for (let i = 0; i < types.length; i++) {
30244 const arg = resolveForwardRef$1(types[i]);
30245 if (Array.isArray(arg)) {
30246 if (arg.length === 0) {
30247 throw new Error('Arguments array must have arguments.');
30248 }
30249 let type = undefined;
30250 let flags = InjectFlags.Default;
30251 for (let j = 0; j < arg.length; j++) {
30252 const meta = arg[j];
30253 const flag = getInjectFlag(meta);
30254 if (typeof flag === 'number') {
30255 // Special case when we handle @Inject decorator.
30256 if (flag === -1 /* Inject */) {
30257 type = meta.token;
30258 }
30259 else {
30260 flags |= flag;
30261 }
30262 }
30263 else {
30264 type = meta;
30265 }
30266 }
30267 args.push(ɵɵinject(type, flags));
30268 }
30269 else {
30270 args.push(ɵɵinject(arg));
30271 }
30272 }
30273 return args;
30274 }
30275 /**
30276 * Attaches a given InjectFlag to a given decorator using monkey-patching.
30277 * Since DI decorators can be used in providers `deps` array (when provider is configured using
30278 * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we
30279 * attach the flag to make it available both as a static property and as a field on decorator
30280 * instance.
30281 *
30282 * @param decorator Provided DI decorator.
30283 * @param flag InjectFlag that should be applied.
30284 */
30285 function attachInjectFlag(decorator, flag) {
30286 decorator[DI_DECORATOR_FLAG] = flag;
30287 decorator.prototype[DI_DECORATOR_FLAG] = flag;
30288 return decorator;
30289 }
30290 /**
30291 * Reads monkey-patched property that contains InjectFlag attached to a decorator.
30292 *
30293 * @param token Token that may contain monkey-patched DI flags property.
30294 */
30295 function getInjectFlag(token) {
30296 return token[DI_DECORATOR_FLAG];
30297 }
30298 function catchInjectorError(e, token, injectorErrorName, source) {
30299 const tokenPath = e[NG_TEMP_TOKEN_PATH];
30300 if (token[SOURCE]) {
30301 tokenPath.unshift(token[SOURCE]);
30302 }
30303 e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source);
30304 e[NG_TOKEN_PATH] = tokenPath;
30305 e[NG_TEMP_TOKEN_PATH] = null;
30306 throw e;
30307 }
30308 function formatError(text, obj, injectorErrorName, source = null) {
30309 text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text;
30310 let context = stringify$1(obj);
30311 if (Array.isArray(obj)) {
30312 context = obj.map(stringify$1).join(' -> ');
30313 }
30314 else if (typeof obj === 'object') {
30315 let parts = [];
30316 for (let key in obj) {
30317 if (obj.hasOwnProperty(key)) {
30318 let value = obj[key];
30319 parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify$1(value)));
30320 }
30321 }
30322 context = `{${parts.join(', ')}}`;
30323 }
30324 return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
30325 }
30326
30327 /**
30328 * @license
30329 * Copyright Google LLC All Rights Reserved.
30330 *
30331 * Use of this source code is governed by an MIT-style license that can be
30332 * found in the LICENSE file at https://angular.io/license
30333 */
30334 const ɵ0$3 = (token) => ({ token });
30335 /**
30336 * Inject decorator and metadata.
30337 *
30338 * @Annotation
30339 * @publicApi
30340 */
30341 const Inject = attachInjectFlag(
30342 // Disable tslint because `DecoratorFlags` is a const enum which gets inlined.
30343 // tslint:disable-next-line: no-toplevel-property-access
30344 makeParamDecorator('Inject', ɵ0$3), -1 /* Inject */);
30345 /**
30346 * Optional decorator and metadata.
30347 *
30348 * @Annotation
30349 * @publicApi
30350 */
30351 const Optional =
30352 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30353 // tslint:disable-next-line: no-toplevel-property-access
30354 attachInjectFlag(makeParamDecorator('Optional'), 8 /* Optional */);
30355 /**
30356 * Self decorator and metadata.
30357 *
30358 * @Annotation
30359 * @publicApi
30360 */
30361 const Self =
30362 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30363 // tslint:disable-next-line: no-toplevel-property-access
30364 attachInjectFlag(makeParamDecorator('Self'), 2 /* Self */);
30365 /**
30366 * `SkipSelf` decorator and metadata.
30367 *
30368 * @Annotation
30369 * @publicApi
30370 */
30371 const SkipSelf =
30372 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30373 // tslint:disable-next-line: no-toplevel-property-access
30374 attachInjectFlag(makeParamDecorator('SkipSelf'), 4 /* SkipSelf */);
30375 /**
30376 * Host decorator and metadata.
30377 *
30378 * @Annotation
30379 * @publicApi
30380 */
30381 const Host =
30382 // Disable tslint because `InternalInjectFlags` is a const enum which gets inlined.
30383 // tslint:disable-next-line: no-toplevel-property-access
30384 attachInjectFlag(makeParamDecorator('Host'), 1 /* Host */);
30385
30386 /**
30387 * @license
30388 * Copyright Google LLC All Rights Reserved.
30389 *
30390 * Use of this source code is governed by an MIT-style license that can be
30391 * found in the LICENSE file at https://angular.io/license
30392 */
30393 /**
30394 * The Trusted Types policy, or null if Trusted Types are not
30395 * enabled/supported, or undefined if the policy has not been created yet.
30396 */
30397 let policy$1;
30398 /**
30399 * Returns the Trusted Types policy, or null if Trusted Types are not
30400 * enabled/supported. The first call to this function will create the policy.
30401 */
30402 function getPolicy$1() {
30403 if (policy$1 === undefined) {
30404 policy$1 = null;
30405 if (_global$1.trustedTypes) {
30406 try {
30407 policy$1 = _global$1.trustedTypes.createPolicy('angular', {
30408 createHTML: (s) => s,
30409 createScript: (s) => s,
30410 createScriptURL: (s) => s,
30411 });
30412 }
30413 catch (_a) {
30414 // trustedTypes.createPolicy throws if called with a name that is
30415 // already registered, even in report-only mode. Until the API changes,
30416 // catch the error not to break the applications functionally. In such
30417 // cases, the code will fall back to using strings.
30418 }
30419 }
30420 }
30421 return policy$1;
30422 }
30423 /**
30424 * Unsafely promote a string to a TrustedScript, falling back to strings when
30425 * Trusted Types are not available.
30426 * @security In particular, it must be assured that the provided string will
30427 * never cause an XSS vulnerability if used in a context that will be
30428 * interpreted and executed as a script by a browser, e.g. when calling eval.
30429 */
30430 function trustedScriptFromString$1(script) {
30431 var _a;
30432 return ((_a = getPolicy$1()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
30433 }
30434 /**
30435 * Unsafely call the Function constructor with the given string arguments. It
30436 * is only available in development mode, and should be stripped out of
30437 * production code.
30438 * @security This is a security-sensitive function; any use of this function
30439 * must go through security review. In particular, it must be assured that it
30440 * is only called from development code, as use in production code can lead to
30441 * XSS vulnerabilities.
30442 */
30443 function newTrustedFunctionForDev(...args) {
30444 if (typeof ngDevMode === 'undefined') {
30445 throw new Error('newTrustedFunctionForDev should never be called in production');
30446 }
30447 if (!_global$1.trustedTypes) {
30448 // In environments that don't support Trusted Types, fall back to the most
30449 // straightforward implementation:
30450 return new Function(...args);
30451 }
30452 // Chrome currently does not support passing TrustedScript to the Function
30453 // constructor. The following implements the workaround proposed on the page
30454 // below, where the Chromium bug is also referenced:
30455 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
30456 const fnArgs = args.slice(0, -1).join(',');
30457 const fnBody = args[args.length - 1];
30458 const body = `(function anonymous(${fnArgs}
30459) { ${fnBody}
30460})`;
30461 // Using eval directly confuses the compiler and prevents this module from
30462 // being stripped out of JS binaries even if not used. The global['eval']
30463 // indirection fixes that.
30464 const fn = _global$1['eval'](trustedScriptFromString$1(body));
30465 if (fn.bind === undefined) {
30466 // Workaround for a browser bug that only exists in Chrome 83, where passing
30467 // a TrustedScript to eval just returns the TrustedScript back without
30468 // evaluating it. In that case, fall back to the most straightforward
30469 // implementation:
30470 return new Function(...args);
30471 }
30472 // To completely mimic the behavior of calling "new Function", two more
30473 // things need to happen:
30474 // 1. Stringifying the resulting function should return its source code
30475 fn.toString = () => body;
30476 // 2. When calling the resulting function, `this` should refer to `global`
30477 return fn.bind(_global$1);
30478 // When Trusted Types support in Function constructors is widely available,
30479 // the implementation of this function can be simplified to:
30480 // return new Function(...args.map(a => trustedScriptFromString(a)));
30481 }
30482
30483 /**
30484 * @license
30485 * Copyright Google LLC All Rights Reserved.
30486 *
30487 * Use of this source code is governed by an MIT-style license that can be
30488 * found in the LICENSE file at https://angular.io/license
30489 */
30490 function tagSet(tags) {
30491 const res = {};
30492 for (const t of tags.split(','))
30493 res[t] = true;
30494 return res;
30495 }
30496 function merge(...sets) {
30497 const res = {};
30498 for (const s of sets) {
30499 for (const v in s) {
30500 if (s.hasOwnProperty(v))
30501 res[v] = true;
30502 }
30503 }
30504 return res;
30505 }
30506 // Good source of info about elements and attributes
30507 // https://html.spec.whatwg.org/#semantics
30508 // https://simon.html5.org/html-elements
30509 // Safe Void Elements - HTML5
30510 // https://html.spec.whatwg.org/#void-elements
30511 const VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr');
30512 // Elements that you can, intentionally, leave open (and which close themselves)
30513 // https://html.spec.whatwg.org/#optional-tags
30514 const OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr');
30515 const OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt');
30516 const OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS);
30517 // Safe Block Elements - HTML5
30518 const BLOCK_ELEMENTS = merge(OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet('address,article,' +
30519 'aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
30520 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul'));
30521 // Inline Elements - HTML5
30522 const INLINE_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet('a,abbr,acronym,audio,b,' +
30523 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' +
30524 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video'));
30525 const VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS);
30526 // Attributes that have href and hence need to be sanitized
30527 const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
30528 // Attributes that have special href set hence need to be sanitized
30529 const SRCSET_ATTRS = tagSet('srcset');
30530 const HTML_ATTRS = tagSet('abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' +
30531 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' +
30532 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' +
30533 'scope,scrolling,shape,size,sizes,span,srclang,start,summary,tabindex,target,title,translate,type,usemap,' +
30534 'valign,value,vspace,width');
30535 // Accessibility attributes as per WAI-ARIA 1.1 (W3C Working Draft 14 December 2018)
30536 const ARIA_ATTRS = tagSet('aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,' +
30537 'aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,' +
30538 'aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,' +
30539 'aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,' +
30540 'aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,' +
30541 'aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,' +
30542 'aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext');
30543 // NB: This currently consciously doesn't support SVG. SVG sanitization has had several security
30544 // issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via
30545 // innerHTML is required, SVG attributes should be added here.
30546 // NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those
30547 // can be sanitized, but they increase security surface area without a legitimate use case, so they
30548 // are left out here.
30549 const VALID_ATTRS = merge(URI_ATTRS, SRCSET_ATTRS, HTML_ATTRS, ARIA_ATTRS);
30550 // Elements whose content should not be traversed/preserved, if the elements themselves are invalid.
30551 //
30552 // Typically, `<invalid>Some content</invalid>` would traverse (and in this case preserve)
30553 // `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we
30554 // don't want to preserve the content, if the elements themselves are going to be removed.
30555 const SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template');
30556
30557 /**
30558 * @license
30559 * Copyright Google LLC All Rights Reserved.
30560 *
30561 * Use of this source code is governed by an MIT-style license that can be
30562 * found in the LICENSE file at https://angular.io/license
30563 */
30564 /**
30565 * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
30566 * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
30567 * handled.
30568 *
30569 * See DomSanitizer for more details on security in Angular applications.
30570 *
30571 * @publicApi
30572 */
30573 var SecurityContext$1;
30574 (function (SecurityContext) {
30575 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
30576 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
30577 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
30578 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
30579 SecurityContext[SecurityContext["URL"] = 4] = "URL";
30580 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
30581 })(SecurityContext$1 || (SecurityContext$1 = {}));
30582
30583 /**
30584 * @license
30585 * Copyright Google LLC All Rights Reserved.
30586 *
30587 * Use of this source code is governed by an MIT-style license that can be
30588 * found in the LICENSE file at https://angular.io/license
30589 */
30590 const ERROR_DEBUG_CONTEXT = 'ngDebugContext';
30591 const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
30592 const ERROR_LOGGER = 'ngErrorLogger';
30593 function wrappedError(message, originalError) {
30594 const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
30595 const error = Error(msg);
30596 error[ERROR_ORIGINAL_ERROR] = originalError;
30597 return error;
30598 }
30599
30600 /**
30601 * @license
30602 * Copyright Google LLC All Rights Reserved.
30603 *
30604 * Use of this source code is governed by an MIT-style license that can be
30605 * found in the LICENSE file at https://angular.io/license
30606 */
30607 function getDebugContext(error) {
30608 return error[ERROR_DEBUG_CONTEXT];
30609 }
30610 function getOriginalError(error) {
30611 return error[ERROR_ORIGINAL_ERROR];
30612 }
30613 function getErrorLogger(error) {
30614 return error[ERROR_LOGGER] || defaultErrorLogger;
30615 }
30616 function defaultErrorLogger(console, ...values) {
30617 console.error(...values);
30618 }
30619
30620 /**
30621 * @license
30622 * Copyright Google LLC All Rights Reserved.
30623 *
30624 * Use of this source code is governed by an MIT-style license that can be
30625 * found in the LICENSE file at https://angular.io/license
30626 */
30627 /**
30628 * Provides a hook for centralized exception handling.
30629 *
30630 * The default implementation of `ErrorHandler` prints error messages to the `console`. To
30631 * intercept error handling, write a custom exception handler that replaces this default as
30632 * appropriate for your app.
30633 *
30634 * @usageNotes
30635 * ### Example
30636 *
30637 * ```
30638 * class MyErrorHandler implements ErrorHandler {
30639 * handleError(error) {
30640 * // do something with the exception
30641 * }
30642 * }
30643 *
30644 * @NgModule({
30645 * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
30646 * })
30647 * class MyModule {}
30648 * ```
30649 *
30650 * @publicApi
30651 */
30652 class ErrorHandler {
30653 constructor() {
30654 /**
30655 * @internal
30656 */
30657 this._console = console;
30658 }
30659 handleError(error) {
30660 const originalError = this._findOriginalError(error);
30661 const context = this._findContext(error);
30662 // Note: Browser consoles show the place from where console.error was called.
30663 // We can use this to give users additional information about the error.
30664 const errorLogger = getErrorLogger(error);
30665 errorLogger(this._console, `ERROR`, error);
30666 if (originalError) {
30667 errorLogger(this._console, `ORIGINAL ERROR`, originalError);
30668 }
30669 if (context) {
30670 errorLogger(this._console, 'ERROR CONTEXT', context);
30671 }
30672 }
30673 /** @internal */
30674 _findContext(error) {
30675 if (error) {
30676 return getDebugContext(error) ? getDebugContext(error) :
30677 this._findContext(getOriginalError(error));
30678 }
30679 return null;
30680 }
30681 /** @internal */
30682 _findOriginalError(error) {
30683 let e = getOriginalError(error);
30684 while (e && getOriginalError(e)) {
30685 e = getOriginalError(e);
30686 }
30687 return e;
30688 }
30689 }
30690
30691 /**
30692 * @license
30693 * Copyright Google LLC All Rights Reserved.
30694 *
30695 * Use of this source code is governed by an MIT-style license that can be
30696 * found in the LICENSE file at https://angular.io/license
30697 */
30698 /**
30699 * THIS FILE CONTAINS CODE WHICH SHOULD BE TREE SHAKEN AND NEVER CALLED FROM PRODUCTION CODE!!!
30700 */
30701 /**
30702 * Creates an `Array` construction with a given name. This is useful when
30703 * looking for memory consumption to see what time of array it is.
30704 *
30705 *
30706 * @param name Name to give to the constructor
30707 * @returns A subclass of `Array` if possible. This can only be done in
30708 * environments which support `class` construct.
30709 */
30710 function createNamedArrayType(name) {
30711 // This should never be called in prod mode, so let's verify that is the case.
30712 if (ngDevMode) {
30713 try {
30714 // If this function were compromised the following could lead to arbitrary
30715 // script execution. We bless it with Trusted Types anyway since this
30716 // function is stripped out of production binaries.
30717 return (newTrustedFunctionForDev('Array', `return class ${name} extends Array{}`))(Array);
30718 }
30719 catch (e) {
30720 // If it does not work just give up and fall back to regular Array.
30721 return Array;
30722 }
30723 }
30724 else {
30725 throw new Error('Looks like we are in \'prod mode\', but we are creating a named Array type, which is wrong! Check your code');
30726 }
30727 }
30728
30729 /**
30730 * @license
30731 * Copyright Google LLC All Rights Reserved.
30732 *
30733 * Use of this source code is governed by an MIT-style license that can be
30734 * found in the LICENSE file at https://angular.io/license
30735 */
30736 /**
30737 * Assigns the given data to the given target (which could be a component,
30738 * directive or DOM node instance) using monkey-patching.
30739 */
30740 function attachPatchData(target, data) {
30741 target[MONKEY_PATCH_KEY_NAME] = data;
30742 }
30743
30744 /**
30745 * @license
30746 * Copyright Google LLC All Rights Reserved.
30747 *
30748 * Use of this source code is governed by an MIT-style license that can be
30749 * found in the LICENSE file at https://angular.io/license
30750 */
30751 const ɵ0$4 = () => (typeof requestAnimationFrame !== 'undefined' &&
30752 requestAnimationFrame || // browser only
30753 setTimeout // everything else
30754 )
30755 .bind(_global$1);
30756 const defaultScheduler = (ɵ0$4)();
30757
30758 /**
30759 * @license
30760 * Copyright Google LLC All Rights Reserved.
30761 *
30762 * Use of this source code is governed by an MIT-style license that can be
30763 * found in the LICENSE file at https://angular.io/license
30764 */
30765 /**
30766 * Flags for renderer-specific style modifiers.
30767 * @publicApi
30768 */
30769 var RendererStyleFlags2;
30770 (function (RendererStyleFlags2) {
30771 // TODO(misko): This needs to be refactored into a separate file so that it can be imported from
30772 // `node_manipulation.ts` Currently doing the import cause resolution order to change and fails
30773 // the tests. The work around is to have hard coded value in `node_manipulation.ts` for now.
30774 /**
30775 * Marks a style as important.
30776 */
30777 RendererStyleFlags2[RendererStyleFlags2["Important"] = 1] = "Important";
30778 /**
30779 * Marks a style as using dash case naming (this-is-dash-case).
30780 */
30781 RendererStyleFlags2[RendererStyleFlags2["DashCase"] = 2] = "DashCase";
30782 })(RendererStyleFlags2 || (RendererStyleFlags2 = {}));
30783
30784 /**
30785 * @license
30786 * Copyright Google LLC All Rights Reserved.
30787 *
30788 * Use of this source code is governed by an MIT-style license that can be
30789 * found in the LICENSE file at https://angular.io/license
30790 */
30791 let _icuContainerIterate;
30792 /**
30793 * Iterator which provides ability to visit all of the `TIcuContainerNode` root `RNode`s.
30794 */
30795 function icuContainerIterate(tIcuContainerNode, lView) {
30796 return _icuContainerIterate();
30797 }
30798
30799 /**
30800 * @license
30801 * Copyright Google LLC All Rights Reserved.
30802 *
30803 * Use of this source code is governed by an MIT-style license that can be
30804 * found in the LICENSE file at https://angular.io/license
30805 */
30806 /**
30807 * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of
30808 * that LContainer, which is an LView
30809 * @param lView the lView whose parent to get
30810 */
30811 function getLViewParent(lView) {
30812 ngDevMode && assertLView(lView);
30813 const parent = lView[PARENT];
30814 return isLContainer(parent) ? parent[PARENT] : parent;
30815 }
30816 /**
30817 * Gets the first `LContainer` in the LView or `null` if none exists.
30818 */
30819 function getFirstLContainer(lView) {
30820 return getNearestLContainer(lView[CHILD_HEAD]);
30821 }
30822 /**
30823 * Gets the next `LContainer` that is a sibling of the given container.
30824 */
30825 function getNextLContainer(container) {
30826 return getNearestLContainer(container[NEXT]);
30827 }
30828 function getNearestLContainer(viewOrContainer) {
30829 while (viewOrContainer !== null && !isLContainer(viewOrContainer)) {
30830 viewOrContainer = viewOrContainer[NEXT];
30831 }
30832 return viewOrContainer;
30833 }
30834
30835 /**
30836 * @license
30837 * Copyright Google LLC All Rights Reserved.
30838 *
30839 * Use of this source code is governed by an MIT-style license that can be
30840 * found in the LICENSE file at https://angular.io/license
30841 */
30842 /**
30843 * NOTE: for performance reasons, the possible actions are inlined within the function instead of
30844 * being passed as an argument.
30845 */
30846 function applyToElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
30847 // If this slot was allocated for a text node dynamically created by i18n, the text node itself
30848 // won't be created until i18nApply() in the update block, so this node should be skipped.
30849 // For more info, see "ICU expressions should work inside an ngTemplateOutlet inside an ngFor"
30850 // in `i18n_spec.ts`.
30851 if (lNodeToHandle != null) {
30852 let lContainer;
30853 let isComponent = false;
30854 // We are expecting an RNode, but in the case of a component or LContainer the `RNode` is
30855 // wrapped in an array which needs to be unwrapped. We need to know if it is a component and if
30856 // it has LContainer so that we can process all of those cases appropriately.
30857 if (isLContainer(lNodeToHandle)) {
30858 lContainer = lNodeToHandle;
30859 }
30860 else if (isLView(lNodeToHandle)) {
30861 isComponent = true;
30862 ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView');
30863 lNodeToHandle = lNodeToHandle[HOST];
30864 }
30865 const rNode = unwrapRNode(lNodeToHandle);
30866 ngDevMode && !isProceduralRenderer(renderer) && assertDomNode(rNode);
30867 if (action === 0 /* Create */ && parent !== null) {
30868 if (beforeNode == null) {
30869 nativeAppendChild(renderer, parent, rNode);
30870 }
30871 else {
30872 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
30873 }
30874 }
30875 else if (action === 1 /* Insert */ && parent !== null) {
30876 nativeInsertBefore(renderer, parent, rNode, beforeNode || null, true);
30877 }
30878 else if (action === 2 /* Detach */) {
30879 nativeRemoveNode(renderer, rNode, isComponent);
30880 }
30881 else if (action === 3 /* Destroy */) {
30882 ngDevMode && ngDevMode.rendererDestroyNode++;
30883 renderer.destroyNode(rNode);
30884 }
30885 if (lContainer != null) {
30886 applyContainer(renderer, action, lContainer, parent, beforeNode);
30887 }
30888 }
30889 }
30890 /**
30891 * Creates a native element from a tag name, using a renderer.
30892 * @param renderer A renderer to use
30893 * @param name the tag name
30894 * @param namespace Optional namespace for element.
30895 * @returns the element created
30896 */
30897 function createElementNode(renderer, name, namespace) {
30898 ngDevMode && ngDevMode.rendererCreateElement++;
30899 if (isProceduralRenderer(renderer)) {
30900 return renderer.createElement(name, namespace);
30901 }
30902 else {
30903 return namespace === null ? renderer.createElement(name) :
30904 renderer.createElementNS(namespace, name);
30905 }
30906 }
30907 /**
30908 * Removes all DOM elements associated with a view.
30909 *
30910 * Because some root nodes of the view may be containers, we sometimes need
30911 * to propagate deeply into the nested containers to remove all elements in the
30912 * views beneath it.
30913 *
30914 * @param tView The `TView' of the `LView` from which elements should be added or removed
30915 * @param lView The view from which elements should be added or removed
30916 */
30917 function removeViewFromContainer(tView, lView) {
30918 const renderer = lView[RENDERER];
30919 applyView(tView, lView, renderer, 2 /* Detach */, null, null);
30920 lView[HOST] = null;
30921 lView[T_HOST] = null;
30922 }
30923 /**
30924 * Detach a `LView` from the DOM by detaching its nodes.
30925 *
30926 * @param tView The `TView' of the `LView` to be detached
30927 * @param lView the `LView` to be detached.
30928 */
30929 function renderDetachView(tView, lView) {
30930 applyView(tView, lView, lView[RENDERER], 2 /* Detach */, null, null);
30931 }
30932 /**
30933 * Traverses down and up the tree of views and containers to remove listeners and
30934 * call onDestroy callbacks.
30935 *
30936 * Notes:
30937 * - Because it's used for onDestroy calls, it needs to be bottom-up.
30938 * - Must process containers instead of their views to avoid splicing
30939 * when views are destroyed and re-added.
30940 * - Using a while loop because it's faster than recursion
30941 * - Destroy only called on movement to sibling or movement to parent (laterally or up)
30942 *
30943 * @param rootView The view to destroy
30944 */
30945 function destroyViewTree(rootView) {
30946 // If the view has no children, we can clean it up and return early.
30947 let lViewOrLContainer = rootView[CHILD_HEAD];
30948 if (!lViewOrLContainer) {
30949 return cleanUpView(rootView[TVIEW], rootView);
30950 }
30951 while (lViewOrLContainer) {
30952 let next = null;
30953 if (isLView(lViewOrLContainer)) {
30954 // If LView, traverse down to child.
30955 next = lViewOrLContainer[CHILD_HEAD];
30956 }
30957 else {
30958 ngDevMode && assertLContainer(lViewOrLContainer);
30959 // If container, traverse down to its first LView.
30960 const firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET];
30961 if (firstView)
30962 next = firstView;
30963 }
30964 if (!next) {
30965 // Only clean up view when moving to the side or up, as destroy hooks
30966 // should be called in order from the bottom up.
30967 while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) {
30968 if (isLView(lViewOrLContainer)) {
30969 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
30970 }
30971 lViewOrLContainer = lViewOrLContainer[PARENT];
30972 }
30973 if (lViewOrLContainer === null)
30974 lViewOrLContainer = rootView;
30975 if (isLView(lViewOrLContainer)) {
30976 cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer);
30977 }
30978 next = lViewOrLContainer && lViewOrLContainer[NEXT];
30979 }
30980 lViewOrLContainer = next;
30981 }
30982 }
30983 function detachMovedView(declarationContainer, lView) {
30984 ngDevMode && assertLContainer(declarationContainer);
30985 ngDevMode &&
30986 assertDefined(declarationContainer[MOVED_VIEWS], 'A projected view should belong to a non-empty projected views collection');
30987 const movedViews = declarationContainer[MOVED_VIEWS];
30988 const declarationViewIndex = movedViews.indexOf(lView);
30989 const insertionLContainer = lView[PARENT];
30990 ngDevMode && assertLContainer(insertionLContainer);
30991 // If the view was marked for refresh but then detached before it was checked (where the flag
30992 // would be cleared and the counter decremented), we need to decrement the view counter here
30993 // instead.
30994 if (lView[FLAGS] & 1024 /* RefreshTransplantedView */) {
30995 lView[FLAGS] &= ~1024 /* RefreshTransplantedView */;
30996 updateTransplantedViewCount(insertionLContainer, -1);
30997 }
30998 movedViews.splice(declarationViewIndex, 1);
30999 }
31000 /**
31001 * Detaches a view from a container.
31002 *
31003 * This method removes the view from the container's array of active views. It also
31004 * removes the view's elements from the DOM.
31005 *
31006 * @param lContainer The container from which to detach a view
31007 * @param removeIndex The index of the view to detach
31008 * @returns Detached LView instance.
31009 */
31010 function detachView(lContainer, removeIndex) {
31011 if (lContainer.length <= CONTAINER_HEADER_OFFSET)
31012 return;
31013 const indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
31014 const viewToDetach = lContainer[indexInContainer];
31015 if (viewToDetach) {
31016 const declarationLContainer = viewToDetach[DECLARATION_LCONTAINER];
31017 if (declarationLContainer !== null && declarationLContainer !== lContainer) {
31018 detachMovedView(declarationLContainer, viewToDetach);
31019 }
31020 if (removeIndex > 0) {
31021 lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT];
31022 }
31023 const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
31024 removeViewFromContainer(viewToDetach[TVIEW], viewToDetach);
31025 // notify query that a view has been removed
31026 const lQueries = removedLView[QUERIES];
31027 if (lQueries !== null) {
31028 lQueries.detachView(removedLView[TVIEW]);
31029 }
31030 viewToDetach[PARENT] = null;
31031 viewToDetach[NEXT] = null;
31032 // Unsets the attached flag
31033 viewToDetach[FLAGS] &= ~128 /* Attached */;
31034 }
31035 return viewToDetach;
31036 }
31037 /**
31038 * A standalone function which destroys an LView,
31039 * conducting clean up (e.g. removing listeners, calling onDestroys).
31040 *
31041 * @param tView The `TView' of the `LView` to be destroyed
31042 * @param lView The view to be destroyed.
31043 */
31044 function destroyLView(tView, lView) {
31045 if (!(lView[FLAGS] & 256 /* Destroyed */)) {
31046 const renderer = lView[RENDERER];
31047 if (isProceduralRenderer(renderer) && renderer.destroyNode) {
31048 applyView(tView, lView, renderer, 3 /* Destroy */, null, null);
31049 }
31050 destroyViewTree(lView);
31051 }
31052 }
31053 /**
31054 * Calls onDestroys hooks for all directives and pipes in a given view and then removes all
31055 * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks
31056 * can be propagated to @Output listeners.
31057 *
31058 * @param tView `TView` for the `LView` to clean up.
31059 * @param lView The LView to clean up
31060 */
31061 function cleanUpView(tView, lView) {
31062 if (!(lView[FLAGS] & 256 /* Destroyed */)) {
31063 // Usually the Attached flag is removed when the view is detached from its parent, however
31064 // if it's a root view, the flag won't be unset hence why we're also removing on destroy.
31065 lView[FLAGS] &= ~128 /* Attached */;
31066 // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
31067 // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
31068 // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
31069 // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
31070 // really more of an "afterDestroy" hook if you think about it.
31071 lView[FLAGS] |= 256 /* Destroyed */;
31072 executeOnDestroys(tView, lView);
31073 processCleanups(tView, lView);
31074 // For component views only, the local renderer is destroyed at clean up time.
31075 if (lView[TVIEW].type === 1 /* Component */ && isProceduralRenderer(lView[RENDERER])) {
31076 ngDevMode && ngDevMode.rendererDestroy++;
31077 lView[RENDERER].destroy();
31078 }
31079 const declarationContainer = lView[DECLARATION_LCONTAINER];
31080 // we are dealing with an embedded view that is still inserted into a container
31081 if (declarationContainer !== null && isLContainer(lView[PARENT])) {
31082 // and this is a projected view
31083 if (declarationContainer !== lView[PARENT]) {
31084 detachMovedView(declarationContainer, lView);
31085 }
31086 // For embedded views still attached to a container: remove query result from this view.
31087 const lQueries = lView[QUERIES];
31088 if (lQueries !== null) {
31089 lQueries.detachView(tView);
31090 }
31091 }
31092 }
31093 }
31094 /** Removes listeners and unsubscribes from output subscriptions */
31095 function processCleanups(tView, lView) {
31096 const tCleanup = tView.cleanup;
31097 const lCleanup = lView[CLEANUP];
31098 // `LCleanup` contains both share information with `TCleanup` as well as instance specific
31099 // information appended at the end. We need to know where the end of the `TCleanup` information
31100 // is, and we track this with `lastLCleanupIndex`.
31101 let lastLCleanupIndex = -1;
31102 if (tCleanup !== null) {
31103 for (let i = 0; i < tCleanup.length - 1; i += 2) {
31104 if (typeof tCleanup[i] === 'string') {
31105 // This is a native DOM listener
31106 const idxOrTargetGetter = tCleanup[i + 1];
31107 const target = typeof idxOrTargetGetter === 'function' ?
31108 idxOrTargetGetter(lView) :
31109 unwrapRNode(lView[idxOrTargetGetter]);
31110 const listener = lCleanup[lastLCleanupIndex = tCleanup[i + 2]];
31111 const useCaptureOrSubIdx = tCleanup[i + 3];
31112 if (typeof useCaptureOrSubIdx === 'boolean') {
31113 // native DOM listener registered with Renderer3
31114 target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx);
31115 }
31116 else {
31117 if (useCaptureOrSubIdx >= 0) {
31118 // unregister
31119 lCleanup[lastLCleanupIndex = useCaptureOrSubIdx]();
31120 }
31121 else {
31122 // Subscription
31123 lCleanup[lastLCleanupIndex = -useCaptureOrSubIdx].unsubscribe();
31124 }
31125 }
31126 i += 2;
31127 }
31128 else {
31129 // This is a cleanup function that is grouped with the index of its context
31130 const context = lCleanup[lastLCleanupIndex = tCleanup[i + 1]];
31131 tCleanup[i].call(context);
31132 }
31133 }
31134 }
31135 if (lCleanup !== null) {
31136 for (let i = lastLCleanupIndex + 1; i < lCleanup.length; i++) {
31137 const instanceCleanupFn = lCleanup[i];
31138 ngDevMode && assertFunction(instanceCleanupFn, 'Expecting instance cleanup function.');
31139 instanceCleanupFn();
31140 }
31141 lView[CLEANUP] = null;
31142 }
31143 }
31144 /** Calls onDestroy hooks for this view */
31145 function executeOnDestroys(tView, lView) {
31146 let destroyHooks;
31147 if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
31148 for (let i = 0; i < destroyHooks.length; i += 2) {
31149 const context = lView[destroyHooks[i]];
31150 // Only call the destroy hook if the context has been requested.
31151 if (!(context instanceof NodeInjectorFactory)) {
31152 const toCall = destroyHooks[i + 1];
31153 if (Array.isArray(toCall)) {
31154 for (let j = 0; j < toCall.length; j += 2) {
31155 toCall[j + 1].call(context[toCall[j]]);
31156 }
31157 }
31158 else {
31159 toCall.call(context);
31160 }
31161 }
31162 }
31163 }
31164 }
31165 /**
31166 * Inserts a native node before another native node for a given parent using {@link Renderer3}.
31167 * This is a utility function that can be used when native nodes were determined - it abstracts an
31168 * actual renderer being used.
31169 */
31170 function nativeInsertBefore(renderer, parent, child, beforeNode, isMove) {
31171 ngDevMode && ngDevMode.rendererInsertBefore++;
31172 if (isProceduralRenderer(renderer)) {
31173 renderer.insertBefore(parent, child, beforeNode, isMove);
31174 }
31175 else {
31176 parent.insertBefore(child, beforeNode, isMove);
31177 }
31178 }
31179 function nativeAppendChild(renderer, parent, child) {
31180 ngDevMode && ngDevMode.rendererAppendChild++;
31181 ngDevMode && assertDefined(parent, 'parent node must be defined');
31182 if (isProceduralRenderer(renderer)) {
31183 renderer.appendChild(parent, child);
31184 }
31185 else {
31186 parent.appendChild(child);
31187 }
31188 }
31189 /** Removes a node from the DOM given its native parent. */
31190 function nativeRemoveChild(renderer, parent, child, isHostElement) {
31191 if (isProceduralRenderer(renderer)) {
31192 renderer.removeChild(parent, child, isHostElement);
31193 }
31194 else {
31195 parent.removeChild(child);
31196 }
31197 }
31198 /**
31199 * Returns a native parent of a given native node.
31200 */
31201 function nativeParentNode(renderer, node) {
31202 return (isProceduralRenderer(renderer) ? renderer.parentNode(node) : node.parentNode);
31203 }
31204 function getProjectionNodes(lView, tNode) {
31205 if (tNode !== null) {
31206 const componentView = lView[DECLARATION_COMPONENT_VIEW];
31207 const componentHost = componentView[T_HOST];
31208 const slotIdx = tNode.projection;
31209 ngDevMode && assertProjectionSlots(lView);
31210 return componentHost.projection[slotIdx];
31211 }
31212 return null;
31213 }
31214 /**
31215 * Removes a native node itself using a given renderer. To remove the node we are looking up its
31216 * parent from the native tree as not all platforms / browsers support the equivalent of
31217 * node.remove().
31218 *
31219 * @param renderer A renderer to be used
31220 * @param rNode The native node that should be removed
31221 * @param isHostElement A flag indicating if a node to be removed is a host of a component.
31222 */
31223 function nativeRemoveNode(renderer, rNode, isHostElement) {
31224 ngDevMode && ngDevMode.rendererRemoveNode++;
31225 const nativeParent = nativeParentNode(renderer, rNode);
31226 if (nativeParent) {
31227 nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
31228 }
31229 }
31230 /**
31231 * Performs the operation of `action` on the node. Typically this involves inserting or removing
31232 * nodes on the LView or projection boundary.
31233 */
31234 function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode, isProjection) {
31235 while (tNode != null) {
31236 ngDevMode && assertTNodeForLView(tNode, lView);
31237 ngDevMode &&
31238 assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */ | 16 /* Projection */ | 32 /* Icu */);
31239 const rawSlotValue = lView[tNode.index];
31240 const tNodeType = tNode.type;
31241 if (isProjection) {
31242 if (action === 0 /* Create */) {
31243 rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
31244 tNode.flags |= 4 /* isProjected */;
31245 }
31246 }
31247 if ((tNode.flags & 64 /* isDetached */) !== 64 /* isDetached */) {
31248 if (tNodeType & 8 /* ElementContainer */) {
31249 applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
31250 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
31251 }
31252 else if (tNodeType & 32 /* Icu */) {
31253 const nextRNode = icuContainerIterate();
31254 let rNode;
31255 while (rNode = nextRNode()) {
31256 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
31257 }
31258 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
31259 }
31260 else if (tNodeType & 16 /* Projection */) {
31261 applyProjectionRecursive(renderer, action, lView, tNode, parentRElement, beforeNode);
31262 }
31263 else {
31264 ngDevMode && assertTNodeType(tNode, 3 /* AnyRNode */ | 4 /* Container */);
31265 applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
31266 }
31267 }
31268 tNode = isProjection ? tNode.projectionNext : tNode.next;
31269 }
31270 }
31271 function applyView(tView, lView, renderer, action, parentRElement, beforeNode) {
31272 applyNodes(renderer, action, tView.firstChild, lView, parentRElement, beforeNode, false);
31273 }
31274 /**
31275 * `applyProjectionRecursive` performs operation on the projection specified by `action` (insert,
31276 * detach, destroy)
31277 *
31278 * Inserting a projection requires us to locate the projected nodes from the parent component. The
31279 * complication is that those nodes themselves could be re-projected from their parent component.
31280 *
31281 * @param renderer Render to use
31282 * @param action action to perform (insert, detach, destroy)
31283 * @param lView The LView which needs to be inserted, detached, destroyed.
31284 * @param tProjectionNode node to project
31285 * @param parentRElement parent DOM element for insertion/removal.
31286 * @param beforeNode Before which node the insertions should happen.
31287 */
31288 function applyProjectionRecursive(renderer, action, lView, tProjectionNode, parentRElement, beforeNode) {
31289 const componentLView = lView[DECLARATION_COMPONENT_VIEW];
31290 const componentNode = componentLView[T_HOST];
31291 ngDevMode &&
31292 assertEqual(typeof tProjectionNode.projection, 'number', 'expecting projection index');
31293 const nodeToProjectOrRNodes = componentNode.projection[tProjectionNode.projection];
31294 if (Array.isArray(nodeToProjectOrRNodes)) {
31295 // This should not exist, it is a bit of a hack. When we bootstrap a top level node and we
31296 // need to support passing projectable nodes, so we cheat and put them in the TNode
31297 // of the Host TView. (Yes we put instance info at the T Level). We can get away with it
31298 // because we know that that TView is not shared and therefore it will not be a problem.
31299 // This should be refactored and cleaned up.
31300 for (let i = 0; i < nodeToProjectOrRNodes.length; i++) {
31301 const rNode = nodeToProjectOrRNodes[i];
31302 applyToElementOrContainer(action, renderer, parentRElement, rNode, beforeNode);
31303 }
31304 }
31305 else {
31306 let nodeToProject = nodeToProjectOrRNodes;
31307 const projectedComponentLView = componentLView[PARENT];
31308 applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
31309 }
31310 }
31311 /**
31312 * `applyContainer` performs an operation on the container and its views as specified by
31313 * `action` (insert, detach, destroy)
31314 *
31315 * Inserting a Container is complicated by the fact that the container may have Views which
31316 * themselves have containers or projections.
31317 *
31318 * @param renderer Renderer to use
31319 * @param action action to perform (insert, detach, destroy)
31320 * @param lContainer The LContainer which needs to be inserted, detached, destroyed.
31321 * @param parentRElement parent DOM element for insertion/removal.
31322 * @param beforeNode Before which node the insertions should happen.
31323 */
31324 function applyContainer(renderer, action, lContainer, parentRElement, beforeNode) {
31325 ngDevMode && assertLContainer(lContainer);
31326 const anchor = lContainer[NATIVE]; // LContainer has its own before node.
31327 const native = unwrapRNode(lContainer);
31328 // An LContainer can be created dynamically on any node by injecting ViewContainerRef.
31329 // Asking for a ViewContainerRef on an element will result in a creation of a separate anchor
31330 // node (comment in the DOM) that will be different from the LContainer's host node. In this
31331 // particular case we need to execute action on 2 nodes:
31332 // - container's host node (this is done in the executeActionOnElementOrContainer)
31333 // - container's host node (this is done here)
31334 if (anchor !== native) {
31335 // This is very strange to me (Misko). I would expect that the native is same as anchor. I
31336 // don't see a reason why they should be different, but they are.
31337 //
31338 // If they are we need to process the second anchor as well.
31339 applyToElementOrContainer(action, renderer, parentRElement, anchor, beforeNode);
31340 }
31341 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
31342 const lView = lContainer[i];
31343 applyView(lView[TVIEW], lView, renderer, action, parentRElement, anchor);
31344 }
31345 }
31346 /**
31347 * Write `cssText` to `RElement`.
31348 *
31349 * This function does direct write without any reconciliation. Used for writing initial values, so
31350 * that static styling values do not pull in the style parser.
31351 *
31352 * @param renderer Renderer to use
31353 * @param element The element which needs to be updated.
31354 * @param newValue The new class list to write.
31355 */
31356 function writeDirectStyle(renderer, element, newValue) {
31357 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
31358 if (isProceduralRenderer(renderer)) {
31359 renderer.setAttribute(element, 'style', newValue);
31360 }
31361 else {
31362 element.style.cssText = newValue;
31363 }
31364 ngDevMode && ngDevMode.rendererSetStyle++;
31365 }
31366 /**
31367 * Write `className` to `RElement`.
31368 *
31369 * This function does direct write without any reconciliation. Used for writing initial values, so
31370 * that static styling values do not pull in the style parser.
31371 *
31372 * @param renderer Renderer to use
31373 * @param element The element which needs to be updated.
31374 * @param newValue The new class list to write.
31375 */
31376 function writeDirectClass(renderer, element, newValue) {
31377 ngDevMode && assertString(newValue, '\'newValue\' should be a string');
31378 if (isProceduralRenderer(renderer)) {
31379 if (newValue === '') {
31380 // There are tests in `google3` which expect `element.getAttribute('class')` to be `null`.
31381 renderer.removeAttribute(element, 'class');
31382 }
31383 else {
31384 renderer.setAttribute(element, 'class', newValue);
31385 }
31386 }
31387 else {
31388 element.className = newValue;
31389 }
31390 ngDevMode && ngDevMode.rendererSetClassName++;
31391 }
31392
31393 /**
31394 * @license
31395 * Copyright Google LLC All Rights Reserved.
31396 *
31397 * Use of this source code is governed by an MIT-style license that can be
31398 * found in the LICENSE file at https://angular.io/license
31399 */
31400 function isPositive(mode) {
31401 return (mode & 1 /* NOT */) === 0;
31402 }
31403 function maybeWrapInNotSelector(isNegativeMode, chunk) {
31404 return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
31405 }
31406 function stringifyCSSSelector(selector) {
31407 let result = selector[0];
31408 let i = 1;
31409 let mode = 2 /* ATTRIBUTE */;
31410 let currentChunk = '';
31411 let isNegativeMode = false;
31412 while (i < selector.length) {
31413 let valueOrMarker = selector[i];
31414 if (typeof valueOrMarker === 'string') {
31415 if (mode & 2 /* ATTRIBUTE */) {
31416 const attrValue = selector[++i];
31417 currentChunk +=
31418 '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
31419 }
31420 else if (mode & 8 /* CLASS */) {
31421 currentChunk += '.' + valueOrMarker;
31422 }
31423 else if (mode & 4 /* ELEMENT */) {
31424 currentChunk += ' ' + valueOrMarker;
31425 }
31426 }
31427 else {
31428 //
31429 // Append current chunk to the final result in case we come across SelectorFlag, which
31430 // indicates that the previous section of a selector is over. We need to accumulate content
31431 // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
31432 // ```
31433 // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
31434 // ```
31435 // should be transformed to `.classA :not(.classB .classC)`.
31436 //
31437 // Note: for negative selector part, we accumulate content between flags until we find the
31438 // next negative flag. This is needed to support a case where `:not()` rule contains more than
31439 // one chunk, e.g. the following selector:
31440 // ```
31441 // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
31442 // ```
31443 // should be stringified to `:not(p.foo) :not(.bar)`
31444 //
31445 if (currentChunk !== '' && !isPositive(valueOrMarker)) {
31446 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
31447 currentChunk = '';
31448 }
31449 mode = valueOrMarker;
31450 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
31451 // mode is maintained for remaining chunks of a selector.
31452 isNegativeMode = isNegativeMode || !isPositive(mode);
31453 }
31454 i++;
31455 }
31456 if (currentChunk !== '') {
31457 result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
31458 }
31459 return result;
31460 }
31461 /**
31462 * Generates string representation of CSS selector in parsed form.
31463 *
31464 * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
31465 * additional parsing at runtime (for example, for directive matching). However in some cases (for
31466 * example, while bootstrapping a component), a string version of the selector is required to query
31467 * for the host element on the page. This function takes the parsed form of a selector and returns
31468 * its string representation.
31469 *
31470 * @param selectorList selector in parsed form
31471 * @returns string representation of a given selector
31472 */
31473 function stringifyCSSSelectorList(selectorList) {
31474 return selectorList.map(stringifyCSSSelector).join(',');
31475 }
31476 /**
31477 * Extracts attributes and classes information from a given CSS selector.
31478 *
31479 * This function is used while creating a component dynamically. In this case, the host element
31480 * (that is created dynamically) should contain attributes and classes specified in component's CSS
31481 * selector.
31482 *
31483 * @param selector CSS selector in parsed form (in a form of array)
31484 * @returns object with `attrs` and `classes` fields that contain extracted information
31485 */
31486 function extractAttrsAndClassesFromSelector(selector) {
31487 const attrs = [];
31488 const classes = [];
31489 let i = 1;
31490 let mode = 2 /* ATTRIBUTE */;
31491 while (i < selector.length) {
31492 let valueOrMarker = selector[i];
31493 if (typeof valueOrMarker === 'string') {
31494 if (mode === 2 /* ATTRIBUTE */) {
31495 if (valueOrMarker !== '') {
31496 attrs.push(valueOrMarker, selector[++i]);
31497 }
31498 }
31499 else if (mode === 8 /* CLASS */) {
31500 classes.push(valueOrMarker);
31501 }
31502 }
31503 else {
31504 // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
31505 // mode is maintained for remaining chunks of a selector. Since attributes and classes are
31506 // extracted only for "positive" part of the selector, we can stop here.
31507 if (!isPositive(mode))
31508 break;
31509 mode = valueOrMarker;
31510 }
31511 i++;
31512 }
31513 return { attrs, classes };
31514 }
31515
31516 /**
31517 * @license
31518 * Copyright Google LLC All Rights Reserved.
31519 *
31520 * Use of this source code is governed by an MIT-style license that can be
31521 * found in the LICENSE file at https://angular.io/license
31522 */
31523 /** A special value which designates that a value has not changed. */
31524 const NO_CHANGE = (typeof ngDevMode === 'undefined' || ngDevMode) ? { __brand__: 'NO_CHANGE' } : {};
31525
31526 /**
31527 * @license
31528 * Copyright Google LLC All Rights Reserved.
31529 *
31530 * Use of this source code is governed by an MIT-style license that can be
31531 * found in the LICENSE file at https://angular.io/license
31532 */
31533 function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
31534 ngDevMode && assertIndexInDeclRange(lView, index);
31535 // Flush the initial hooks for elements in the view that have been added up to this point.
31536 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
31537 if (!checkNoChangesMode) {
31538 const hooksInitPhaseCompleted = (lView[FLAGS] & 3 /* InitPhaseStateMask */) === 3 /* InitPhaseCompleted */;
31539 if (hooksInitPhaseCompleted) {
31540 const preOrderCheckHooks = tView.preOrderCheckHooks;
31541 if (preOrderCheckHooks !== null) {
31542 executeCheckHooks(lView, preOrderCheckHooks, index);
31543 }
31544 }
31545 else {
31546 const preOrderHooks = tView.preOrderHooks;
31547 if (preOrderHooks !== null) {
31548 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* OnInitHooksToBeRun */, index);
31549 }
31550 }
31551 }
31552 // We must set the selected index *after* running the hooks, because hooks may have side-effects
31553 // that cause other template functions to run, thus updating the selected index, which is global
31554 // state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index
31555 // will be altered by the time we leave the `ɵɵadvance` instruction.
31556 setSelectedIndex(index);
31557 }
31558
31559 /**
31560 * @license
31561 * Copyright Google LLC All Rights Reserved.
31562 *
31563 * Use of this source code is governed by an MIT-style license that can be
31564 * found in the LICENSE file at https://angular.io/license
31565 */
31566 function getTStylingRangePrev(tStylingRange) {
31567 ngDevMode && assertNumber(tStylingRange, 'expected number');
31568 return (tStylingRange >> 17 /* PREV_SHIFT */) & 32767 /* UNSIGNED_MASK */;
31569 }
31570 function getTStylingRangePrevDuplicate(tStylingRange) {
31571 ngDevMode && assertNumber(tStylingRange, 'expected number');
31572 return (tStylingRange & 2 /* PREV_DUPLICATE */) ==
31573 2 /* PREV_DUPLICATE */;
31574 }
31575 function getTStylingRangeNext(tStylingRange) {
31576 ngDevMode && assertNumber(tStylingRange, 'expected number');
31577 return (tStylingRange & 131068 /* NEXT_MASK */) >> 2 /* NEXT_SHIFT */;
31578 }
31579 function getTStylingRangeNextDuplicate(tStylingRange) {
31580 ngDevMode && assertNumber(tStylingRange, 'expected number');
31581 return (tStylingRange & 1 /* NEXT_DUPLICATE */) ===
31582 1 /* NEXT_DUPLICATE */;
31583 }
31584
31585 /**
31586 * @license
31587 * Copyright Google LLC All Rights Reserved.
31588 *
31589 * Use of this source code is governed by an MIT-style license that can be
31590 * found in the LICENSE file at https://angular.io/license
31591 */
31592 /**
31593 * Patch a `debug` property on top of the existing object.
31594 *
31595 * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
31596 *
31597 * @param obj Object to patch
31598 * @param debug Value to patch
31599 */
31600 function attachDebugObject(obj, debug) {
31601 if (ngDevMode) {
31602 Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
31603 }
31604 else {
31605 throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
31606 }
31607 }
31608
31609 /**
31610 * @license
31611 * Copyright Google LLC All Rights Reserved.
31612 *
31613 * Use of this source code is governed by an MIT-style license that can be
31614 * found in the LICENSE file at https://angular.io/license
31615 */
31616 const NG_DEV_MODE = ((typeof ngDevMode === 'undefined' || !!ngDevMode) && initNgDevMode());
31617 /*
31618 * This file contains conditionally attached classes which provide human readable (debug) level
31619 * information for `LView`, `LContainer` and other internal data structures. These data structures
31620 * are stored internally as array which makes it very difficult during debugging to reason about the
31621 * current state of the system.
31622 *
31623 * Patching the array with extra property does change the array's hidden class' but it does not
31624 * change the cost of access, therefore this patching should not have significant if any impact in
31625 * `ngDevMode` mode. (see: https://jsperf.com/array-vs-monkey-patch-array)
31626 *
31627 * So instead of seeing:
31628 * ```
31629 * Array(30) [Object, 659, null, …]
31630 * ```
31631 *
31632 * You get to see:
31633 * ```
31634 * LViewDebug {
31635 * views: [...],
31636 * flags: {attached: true, ...}
31637 * nodes: [
31638 * {html: '<div id="123">', ..., nodes: [
31639 * {html: '<span>', ..., nodes: null}
31640 * ]}
31641 * ]
31642 * }
31643 * ```
31644 */
31645 let LVIEW_COMPONENT_CACHE;
31646 let LVIEW_EMBEDDED_CACHE;
31647 let LVIEW_ROOT;
31648 /**
31649 * This function clones a blueprint and creates LView.
31650 *
31651 * Simple slice will keep the same type, and we need it to be LView
31652 */
31653 function cloneToLViewFromTViewBlueprint(tView) {
31654 const debugTView = tView;
31655 const lView = getLViewToClone(debugTView.type, tView.template && tView.template.name);
31656 return lView.concat(tView.blueprint);
31657 }
31658 function getLViewToClone(type, name) {
31659 switch (type) {
31660 case 0 /* Root */:
31661 if (LVIEW_ROOT === undefined)
31662 LVIEW_ROOT = new (createNamedArrayType('LRootView'))();
31663 return LVIEW_ROOT;
31664 case 1 /* Component */:
31665 if (LVIEW_COMPONENT_CACHE === undefined)
31666 LVIEW_COMPONENT_CACHE = new Map();
31667 let componentArray = LVIEW_COMPONENT_CACHE.get(name);
31668 if (componentArray === undefined) {
31669 componentArray = new (createNamedArrayType('LComponentView' + nameSuffix(name)))();
31670 LVIEW_COMPONENT_CACHE.set(name, componentArray);
31671 }
31672 return componentArray;
31673 case 2 /* Embedded */:
31674 if (LVIEW_EMBEDDED_CACHE === undefined)
31675 LVIEW_EMBEDDED_CACHE = new Map();
31676 let embeddedArray = LVIEW_EMBEDDED_CACHE.get(name);
31677 if (embeddedArray === undefined) {
31678 embeddedArray = new (createNamedArrayType('LEmbeddedView' + nameSuffix(name)))();
31679 LVIEW_EMBEDDED_CACHE.set(name, embeddedArray);
31680 }
31681 return embeddedArray;
31682 }
31683 }
31684 function nameSuffix(text) {
31685 if (text == null)
31686 return '';
31687 const index = text.lastIndexOf('_Template');
31688 return '_' + (index === -1 ? text : text.substr(0, index));
31689 }
31690 /**
31691 * This class is a debug version of Object literal so that we can have constructor name show up
31692 * in
31693 * debug tools in ngDevMode.
31694 */
31695 const TViewConstructor = class TView {
31696 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) {
31697 this.type = type;
31698 this.blueprint = blueprint;
31699 this.template = template;
31700 this.queries = queries;
31701 this.viewQuery = viewQuery;
31702 this.declTNode = declTNode;
31703 this.data = data;
31704 this.bindingStartIndex = bindingStartIndex;
31705 this.expandoStartIndex = expandoStartIndex;
31706 this.hostBindingOpCodes = hostBindingOpCodes;
31707 this.firstCreatePass = firstCreatePass;
31708 this.firstUpdatePass = firstUpdatePass;
31709 this.staticViewQueries = staticViewQueries;
31710 this.staticContentQueries = staticContentQueries;
31711 this.preOrderHooks = preOrderHooks;
31712 this.preOrderCheckHooks = preOrderCheckHooks;
31713 this.contentHooks = contentHooks;
31714 this.contentCheckHooks = contentCheckHooks;
31715 this.viewHooks = viewHooks;
31716 this.viewCheckHooks = viewCheckHooks;
31717 this.destroyHooks = destroyHooks;
31718 this.cleanup = cleanup;
31719 this.contentQueries = contentQueries;
31720 this.components = components;
31721 this.directiveRegistry = directiveRegistry;
31722 this.pipeRegistry = pipeRegistry;
31723 this.firstChild = firstChild;
31724 this.schemas = schemas;
31725 this.consts = consts;
31726 this.incompleteFirstPass = incompleteFirstPass;
31727 this._decls = _decls;
31728 this._vars = _vars;
31729 }
31730 get template_() {
31731 const buf = [];
31732 processTNodeChildren(this.firstChild, buf);
31733 return buf.join('');
31734 }
31735 get type_() {
31736 return TViewTypeAsString[this.type] || `TViewType.?${this.type}?`;
31737 }
31738 };
31739 class TNode {
31740 constructor(tView_, //
31741 type, //
31742 index, //
31743 insertBeforeIndex, //
31744 injectorIndex, //
31745 directiveStart, //
31746 directiveEnd, //
31747 directiveStylingLast, //
31748 propertyBindings, //
31749 flags, //
31750 providerIndexes, //
31751 value, //
31752 attrs, //
31753 mergedAttrs, //
31754 localNames, //
31755 initialInputs, //
31756 inputs, //
31757 outputs, //
31758 tViews, //
31759 next, //
31760 projectionNext, //
31761 child, //
31762 parent, //
31763 projection, //
31764 styles, //
31765 stylesWithoutHost, //
31766 residualStyles, //
31767 classes, //
31768 classesWithoutHost, //
31769 residualClasses, //
31770 classBindings, //
31771 styleBindings) {
31772 this.tView_ = tView_;
31773 this.type = type;
31774 this.index = index;
31775 this.insertBeforeIndex = insertBeforeIndex;
31776 this.injectorIndex = injectorIndex;
31777 this.directiveStart = directiveStart;
31778 this.directiveEnd = directiveEnd;
31779 this.directiveStylingLast = directiveStylingLast;
31780 this.propertyBindings = propertyBindings;
31781 this.flags = flags;
31782 this.providerIndexes = providerIndexes;
31783 this.value = value;
31784 this.attrs = attrs;
31785 this.mergedAttrs = mergedAttrs;
31786 this.localNames = localNames;
31787 this.initialInputs = initialInputs;
31788 this.inputs = inputs;
31789 this.outputs = outputs;
31790 this.tViews = tViews;
31791 this.next = next;
31792 this.projectionNext = projectionNext;
31793 this.child = child;
31794 this.parent = parent;
31795 this.projection = projection;
31796 this.styles = styles;
31797 this.stylesWithoutHost = stylesWithoutHost;
31798 this.residualStyles = residualStyles;
31799 this.classes = classes;
31800 this.classesWithoutHost = classesWithoutHost;
31801 this.residualClasses = residualClasses;
31802 this.classBindings = classBindings;
31803 this.styleBindings = styleBindings;
31804 }
31805 /**
31806 * Return a human debug version of the set of `NodeInjector`s which will be consulted when
31807 * resolving tokens from this `TNode`.
31808 *
31809 * When debugging applications, it is often difficult to determine which `NodeInjector`s will be
31810 * consulted. This method shows a list of `DebugNode`s representing the `TNode`s which will be
31811 * consulted in order when resolving a token starting at this `TNode`.
31812 *
31813 * The original data is stored in `LView` and `TView` with a lot of offset indexes, and so it is
31814 * difficult to reason about.
31815 *
31816 * @param lView The `LView` instance for this `TNode`.
31817 */
31818 debugNodeInjectorPath(lView) {
31819 const path = [];
31820 let injectorIndex = getInjectorIndex(this, lView);
31821 if (injectorIndex === -1) {
31822 // Looks like the current `TNode` does not have `NodeInjector` associated with it => look for
31823 // parent NodeInjector.
31824 const parentLocation = getParentInjectorLocation(this, lView);
31825 if (parentLocation !== NO_PARENT_INJECTOR) {
31826 // We found a parent, so start searching from the parent location.
31827 injectorIndex = getParentInjectorIndex(parentLocation);
31828 lView = getParentInjectorView(parentLocation, lView);
31829 }
31830 }
31831 while (injectorIndex !== -1) {
31832 ngDevMode && assertNodeInjector(lView, injectorIndex);
31833 const tNode = lView[TVIEW].data[injectorIndex + 8 /* TNODE */];
31834 path.push(buildDebugNode(tNode, lView));
31835 const parentLocation = lView[injectorIndex + 8 /* PARENT */];
31836 if (parentLocation === NO_PARENT_INJECTOR) {
31837 injectorIndex = -1;
31838 }
31839 else {
31840 injectorIndex = getParentInjectorIndex(parentLocation);
31841 lView = getParentInjectorView(parentLocation, lView);
31842 }
31843 }
31844 return path;
31845 }
31846 get type_() {
31847 return toTNodeTypeAsString(this.type) || `TNodeType.?${this.type}?`;
31848 }
31849 get flags_() {
31850 const flags = [];
31851 if (this.flags & 16 /* hasClassInput */)
31852 flags.push('TNodeFlags.hasClassInput');
31853 if (this.flags & 8 /* hasContentQuery */)
31854 flags.push('TNodeFlags.hasContentQuery');
31855 if (this.flags & 32 /* hasStyleInput */)
31856 flags.push('TNodeFlags.hasStyleInput');
31857 if (this.flags & 128 /* hasHostBindings */)
31858 flags.push('TNodeFlags.hasHostBindings');
31859 if (this.flags & 2 /* isComponentHost */)
31860 flags.push('TNodeFlags.isComponentHost');
31861 if (this.flags & 1 /* isDirectiveHost */)
31862 flags.push('TNodeFlags.isDirectiveHost');
31863 if (this.flags & 64 /* isDetached */)
31864 flags.push('TNodeFlags.isDetached');
31865 if (this.flags & 4 /* isProjected */)
31866 flags.push('TNodeFlags.isProjected');
31867 return flags.join('|');
31868 }
31869 get template_() {
31870 if (this.type & 1 /* Text */)
31871 return this.value;
31872 const buf = [];
31873 const tagName = typeof this.value === 'string' && this.value || this.type_;
31874 buf.push('<', tagName);
31875 if (this.flags) {
31876 buf.push(' ', this.flags_);
31877 }
31878 if (this.attrs) {
31879 for (let i = 0; i < this.attrs.length;) {
31880 const attrName = this.attrs[i++];
31881 if (typeof attrName == 'number') {
31882 break;
31883 }
31884 const attrValue = this.attrs[i++];
31885 buf.push(' ', attrName, '="', attrValue, '"');
31886 }
31887 }
31888 buf.push('>');
31889 processTNodeChildren(this.child, buf);
31890 buf.push('</', tagName, '>');
31891 return buf.join('');
31892 }
31893 get styleBindings_() {
31894 return toDebugStyleBinding(this, false);
31895 }
31896 get classBindings_() {
31897 return toDebugStyleBinding(this, true);
31898 }
31899 get providerIndexStart_() {
31900 return this.providerIndexes & 1048575 /* ProvidersStartIndexMask */;
31901 }
31902 get providerIndexEnd_() {
31903 return this.providerIndexStart_ +
31904 (this.providerIndexes >>> 20 /* CptViewProvidersCountShift */);
31905 }
31906 }
31907 const TNodeDebug = TNode;
31908 function toDebugStyleBinding(tNode, isClassBased) {
31909 const tData = tNode.tView_.data;
31910 const bindings = [];
31911 const range = isClassBased ? tNode.classBindings : tNode.styleBindings;
31912 const prev = getTStylingRangePrev(range);
31913 const next = getTStylingRangeNext(range);
31914 let isTemplate = next !== 0;
31915 let cursor = isTemplate ? next : prev;
31916 while (cursor !== 0) {
31917 const itemKey = tData[cursor];
31918 const itemRange = tData[cursor + 1];
31919 bindings.unshift({
31920 key: itemKey,
31921 index: cursor,
31922 isTemplate: isTemplate,
31923 prevDuplicate: getTStylingRangePrevDuplicate(itemRange),
31924 nextDuplicate: getTStylingRangeNextDuplicate(itemRange),
31925 nextIndex: getTStylingRangeNext(itemRange),
31926 prevIndex: getTStylingRangePrev(itemRange),
31927 });
31928 if (cursor === prev)
31929 isTemplate = false;
31930 cursor = getTStylingRangePrev(itemRange);
31931 }
31932 bindings.push((isClassBased ? tNode.residualClasses : tNode.residualStyles) || null);
31933 return bindings;
31934 }
31935 function processTNodeChildren(tNode, buf) {
31936 while (tNode) {
31937 buf.push(tNode.template_);
31938 tNode = tNode.next;
31939 }
31940 }
31941 const TViewData = NG_DEV_MODE && createNamedArrayType('TViewData') || null;
31942 let TVIEWDATA_EMPTY; // can't initialize here or it will not be tree shaken, because
31943 // `LView` constructor could have side-effects.
31944 /**
31945 * This function clones a blueprint and creates TData.
31946 *
31947 * Simple slice will keep the same type, and we need it to be TData
31948 */
31949 function cloneToTViewData(list) {
31950 if (TVIEWDATA_EMPTY === undefined)
31951 TVIEWDATA_EMPTY = new TViewData();
31952 return TVIEWDATA_EMPTY.concat(list);
31953 }
31954 const LViewBlueprint = NG_DEV_MODE && createNamedArrayType('LViewBlueprint') || null;
31955 const MatchesArray = NG_DEV_MODE && createNamedArrayType('MatchesArray') || null;
31956 const TViewComponents = NG_DEV_MODE && createNamedArrayType('TViewComponents') || null;
31957 const TNodeLocalNames = NG_DEV_MODE && createNamedArrayType('TNodeLocalNames') || null;
31958 const TNodeInitialInputs = NG_DEV_MODE && createNamedArrayType('TNodeInitialInputs') || null;
31959 const TNodeInitialData = NG_DEV_MODE && createNamedArrayType('TNodeInitialData') || null;
31960 const LCleanup = NG_DEV_MODE && createNamedArrayType('LCleanup') || null;
31961 const TCleanup = NG_DEV_MODE && createNamedArrayType('TCleanup') || null;
31962 function attachLViewDebug(lView) {
31963 attachDebugObject(lView, new LViewDebug(lView));
31964 }
31965 function toDebug(obj) {
31966 if (obj) {
31967 const debug = obj.debug;
31968 assertDefined(debug, 'Object does not have a debug representation.');
31969 return debug;
31970 }
31971 else {
31972 return obj;
31973 }
31974 }
31975 /**
31976 * Use this method to unwrap a native element in `LView` and convert it into HTML for easier
31977 * reading.
31978 *
31979 * @param value possibly wrapped native DOM node.
31980 * @param includeChildren If `true` then the serialized HTML form will include child elements
31981 * (same
31982 * as `outerHTML`). If `false` then the serialized HTML form will only contain the element
31983 * itself
31984 * (will not serialize child elements).
31985 */
31986 function toHtml(value, includeChildren = false) {
31987 const node = unwrapRNode(value);
31988 if (node) {
31989 switch (node.nodeType) {
31990 case Node.TEXT_NODE:
31991 return node.textContent;
31992 case Node.COMMENT_NODE:
31993 return `<!--${node.textContent}-->`;
31994 case Node.ELEMENT_NODE:
31995 const outerHTML = node.outerHTML;
31996 if (includeChildren) {
31997 return outerHTML;
31998 }
31999 else {
32000 const innerHTML = '>' + node.innerHTML + '<';
32001 return (outerHTML.split(innerHTML)[0]) + '>';
32002 }
32003 }
32004 }
32005 return null;
32006 }
32007 class LViewDebug {
32008 constructor(_raw_lView) {
32009 this._raw_lView = _raw_lView;
32010 }
32011 /**
32012 * Flags associated with the `LView` unpacked into a more readable state.
32013 */
32014 get flags() {
32015 const flags = this._raw_lView[FLAGS];
32016 return {
32017 __raw__flags__: flags,
32018 initPhaseState: flags & 3 /* InitPhaseStateMask */,
32019 creationMode: !!(flags & 4 /* CreationMode */),
32020 firstViewPass: !!(flags & 8 /* FirstLViewPass */),
32021 checkAlways: !!(flags & 16 /* CheckAlways */),
32022 dirty: !!(flags & 64 /* Dirty */),
32023 attached: !!(flags & 128 /* Attached */),
32024 destroyed: !!(flags & 256 /* Destroyed */),
32025 isRoot: !!(flags & 512 /* IsRoot */),
32026 indexWithinInitPhase: flags >> 11 /* IndexWithinInitPhaseShift */,
32027 };
32028 }
32029 get parent() {
32030 return toDebug(this._raw_lView[PARENT]);
32031 }
32032 get hostHTML() {
32033 return toHtml(this._raw_lView[HOST], true);
32034 }
32035 get html() {
32036 return (this.nodes || []).map(mapToHTML).join('');
32037 }
32038 get context() {
32039 return this._raw_lView[CONTEXT];
32040 }
32041 /**
32042 * The tree of nodes associated with the current `LView`. The nodes have been normalized into
32043 * a tree structure with relevant details pulled out for readability.
32044 */
32045 get nodes() {
32046 const lView = this._raw_lView;
32047 const tNode = lView[TVIEW].firstChild;
32048 return toDebugNodes(tNode, lView);
32049 }
32050 get template() {
32051 return this.tView.template_;
32052 }
32053 get tView() {
32054 return this._raw_lView[TVIEW];
32055 }
32056 get cleanup() {
32057 return this._raw_lView[CLEANUP];
32058 }
32059 get injector() {
32060 return this._raw_lView[INJECTOR];
32061 }
32062 get rendererFactory() {
32063 return this._raw_lView[RENDERER_FACTORY];
32064 }
32065 get renderer() {
32066 return this._raw_lView[RENDERER];
32067 }
32068 get sanitizer() {
32069 return this._raw_lView[SANITIZER];
32070 }
32071 get childHead() {
32072 return toDebug(this._raw_lView[CHILD_HEAD]);
32073 }
32074 get next() {
32075 return toDebug(this._raw_lView[NEXT]);
32076 }
32077 get childTail() {
32078 return toDebug(this._raw_lView[CHILD_TAIL]);
32079 }
32080 get declarationView() {
32081 return toDebug(this._raw_lView[DECLARATION_VIEW]);
32082 }
32083 get queries() {
32084 return this._raw_lView[QUERIES];
32085 }
32086 get tHost() {
32087 return this._raw_lView[T_HOST];
32088 }
32089 get decls() {
32090 return toLViewRange(this.tView, this._raw_lView, HEADER_OFFSET, this.tView.bindingStartIndex);
32091 }
32092 get vars() {
32093 return toLViewRange(this.tView, this._raw_lView, this.tView.bindingStartIndex, this.tView.expandoStartIndex);
32094 }
32095 get expando() {
32096 return toLViewRange(this.tView, this._raw_lView, this.tView.expandoStartIndex, this._raw_lView.length);
32097 }
32098 /**
32099 * Normalized view of child views (and containers) attached at this location.
32100 */
32101 get childViews() {
32102 const childViews = [];
32103 let child = this.childHead;
32104 while (child) {
32105 childViews.push(child);
32106 child = child.next;
32107 }
32108 return childViews;
32109 }
32110 }
32111 function mapToHTML(node) {
32112 if (node.type === 'ElementContainer') {
32113 return (node.children || []).map(mapToHTML).join('');
32114 }
32115 else if (node.type === 'IcuContainer') {
32116 throw new Error('Not implemented');
32117 }
32118 else {
32119 return toHtml(node.native, true) || '';
32120 }
32121 }
32122 function toLViewRange(tView, lView, start, end) {
32123 let content = [];
32124 for (let index = start; index < end; index++) {
32125 content.push({ index: index, t: tView.data[index], l: lView[index] });
32126 }
32127 return { start: start, end: end, length: end - start, content: content };
32128 }
32129 /**
32130 * Turns a flat list of nodes into a tree by walking the associated `TNode` tree.
32131 *
32132 * @param tNode
32133 * @param lView
32134 */
32135 function toDebugNodes(tNode, lView) {
32136 if (tNode) {
32137 const debugNodes = [];
32138 let tNodeCursor = tNode;
32139 while (tNodeCursor) {
32140 debugNodes.push(buildDebugNode(tNodeCursor, lView));
32141 tNodeCursor = tNodeCursor.next;
32142 }
32143 return debugNodes;
32144 }
32145 else {
32146 return [];
32147 }
32148 }
32149 function buildDebugNode(tNode, lView) {
32150 const rawValue = lView[tNode.index];
32151 const native = unwrapRNode(rawValue);
32152 const factories = [];
32153 const instances = [];
32154 const tView = lView[TVIEW];
32155 for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
32156 const def = tView.data[i];
32157 factories.push(def.type);
32158 instances.push(lView[i]);
32159 }
32160 return {
32161 html: toHtml(native),
32162 type: toTNodeTypeAsString(tNode.type),
32163 tNode,
32164 native: native,
32165 children: toDebugNodes(tNode.child, lView),
32166 factories,
32167 instances,
32168 injector: buildNodeInjectorDebug(tNode, tView, lView),
32169 get injectorResolutionPath() {
32170 return tNode.debugNodeInjectorPath(lView);
32171 },
32172 };
32173 }
32174 function buildNodeInjectorDebug(tNode, tView, lView) {
32175 const viewProviders = [];
32176 for (let i = tNode.providerIndexStart_; i < tNode.providerIndexEnd_; i++) {
32177 viewProviders.push(tView.data[i]);
32178 }
32179 const providers = [];
32180 for (let i = tNode.providerIndexEnd_; i < tNode.directiveEnd; i++) {
32181 providers.push(tView.data[i]);
32182 }
32183 const nodeInjectorDebug = {
32184 bloom: toBloom(lView, tNode.injectorIndex),
32185 cumulativeBloom: toBloom(tView.data, tNode.injectorIndex),
32186 providers,
32187 viewProviders,
32188 parentInjectorIndex: lView[tNode.providerIndexStart_ - 1],
32189 };
32190 return nodeInjectorDebug;
32191 }
32192 /**
32193 * Convert a number at `idx` location in `array` into binary representation.
32194 *
32195 * @param array
32196 * @param idx
32197 */
32198 function binary(array, idx) {
32199 const value = array[idx];
32200 // If not a number we print 8 `?` to retain alignment but let user know that it was called on
32201 // wrong type.
32202 if (typeof value !== 'number')
32203 return '????????';
32204 // We prefix 0s so that we have constant length number
32205 const text = '00000000' + value.toString(2);
32206 return text.substring(text.length - 8);
32207 }
32208 /**
32209 * Convert a bloom filter at location `idx` in `array` into binary representation.
32210 *
32211 * @param array
32212 * @param idx
32213 */
32214 function toBloom(array, idx) {
32215 if (idx < 0) {
32216 return 'NO_NODE_INJECTOR';
32217 }
32218 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)}`;
32219 }
32220
32221 const ɵ0$5 = () => Promise.resolve(null);
32222 /**
32223 * A permanent marker promise which signifies that the current CD tree is
32224 * clean.
32225 */
32226 const _CLEAN_PROMISE = (ɵ0$5)();
32227 /**
32228 * Invoke `HostBindingsFunction`s for view.
32229 *
32230 * This methods executes `TView.hostBindingOpCodes`. It is used to execute the
32231 * `HostBindingsFunction`s associated with the current `LView`.
32232 *
32233 * @param tView Current `TView`.
32234 * @param lView Current `LView`.
32235 */
32236 function processHostBindingOpCodes(tView, lView) {
32237 const hostBindingOpCodes = tView.hostBindingOpCodes;
32238 if (hostBindingOpCodes === null)
32239 return;
32240 try {
32241 for (let i = 0; i < hostBindingOpCodes.length; i++) {
32242 const opCode = hostBindingOpCodes[i];
32243 if (opCode < 0) {
32244 // Negative numbers are element indexes.
32245 setSelectedIndex(~opCode);
32246 }
32247 else {
32248 // Positive numbers are NumberTuple which store bindingRootIndex and directiveIndex.
32249 const directiveIdx = opCode;
32250 const bindingRootIndx = hostBindingOpCodes[++i];
32251 const hostBindingFn = hostBindingOpCodes[++i];
32252 setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
32253 const context = lView[directiveIdx];
32254 hostBindingFn(2 /* Update */, context);
32255 }
32256 }
32257 }
32258 finally {
32259 setSelectedIndex(-1);
32260 }
32261 }
32262 /** Refreshes all content queries declared by directives in a given view */
32263 function refreshContentQueries(tView, lView) {
32264 const contentQueries = tView.contentQueries;
32265 if (contentQueries !== null) {
32266 for (let i = 0; i < contentQueries.length; i += 2) {
32267 const queryStartIdx = contentQueries[i];
32268 const directiveDefIdx = contentQueries[i + 1];
32269 if (directiveDefIdx !== -1) {
32270 const directiveDef = tView.data[directiveDefIdx];
32271 ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
32272 ngDevMode &&
32273 assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
32274 setCurrentQueryIndex(queryStartIdx);
32275 directiveDef.contentQueries(2 /* Update */, lView[directiveDefIdx], directiveDefIdx);
32276 }
32277 }
32278 }
32279 }
32280 /** Refreshes child components in the current view (update mode). */
32281 function refreshChildComponents(hostLView, components) {
32282 for (let i = 0; i < components.length; i++) {
32283 refreshComponent(hostLView, components[i]);
32284 }
32285 }
32286 /** Renders child components in the current view (creation mode). */
32287 function renderChildComponents(hostLView, components) {
32288 for (let i = 0; i < components.length; i++) {
32289 renderComponent(hostLView, components[i]);
32290 }
32291 }
32292 function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector) {
32293 const lView = ngDevMode ? cloneToLViewFromTViewBlueprint(tView) : tView.blueprint.slice();
32294 lView[HOST] = host;
32295 lView[FLAGS] = flags | 4 /* CreationMode */ | 128 /* Attached */ | 8 /* FirstLViewPass */;
32296 resetPreOrderHookFlags(lView);
32297 ngDevMode && tView.declTNode && parentLView && assertTNodeForLView(tView.declTNode, parentLView);
32298 lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
32299 lView[CONTEXT] = context;
32300 lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]);
32301 ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required');
32302 lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]);
32303 ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required');
32304 lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null;
32305 lView[INJECTOR] = injector || parentLView && parentLView[INJECTOR] || null;
32306 lView[T_HOST] = tHostNode;
32307 ngDevMode &&
32308 assertEqual(tView.type == 2 /* Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
32309 lView[DECLARATION_COMPONENT_VIEW] =
32310 tView.type == 2 /* Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
32311 ngDevMode && attachLViewDebug(lView);
32312 return lView;
32313 }
32314 function getOrCreateTNode(tView, index, type, name, attrs) {
32315 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
32316 // `view_engine_compatibility` for additional context.
32317 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
32318 // Keep this function short, so that the VM will inline it.
32319 ngDevMode && assertPureTNodeType(type);
32320 let tNode = tView.data[index];
32321 if (tNode === null) {
32322 tNode = createTNodeAtIndex(tView, index, type, name, attrs);
32323 if (isInI18nBlock()) {
32324 // If we are in i18n block then all elements should be pre declared through `Placeholder`
32325 // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
32326 // If the `TNode` was not pre-declared than it means it was not mentioned which means it was
32327 // removed, so we mark it as detached.
32328 tNode.flags |= 64 /* isDetached */;
32329 }
32330 }
32331 else if (tNode.type & 64 /* Placeholder */) {
32332 tNode.type = type;
32333 tNode.value = name;
32334 tNode.attrs = attrs;
32335 const parent = getCurrentParentTNode();
32336 tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex;
32337 ngDevMode && assertTNodeForTView(tNode, tView);
32338 ngDevMode && assertEqual(index, tNode.index, 'Expecting same index');
32339 }
32340 setCurrentTNode(tNode, true);
32341 return tNode;
32342 }
32343 function createTNodeAtIndex(tView, index, type, name, attrs) {
32344 const currentTNode = getCurrentTNodePlaceholderOk();
32345 const isParent = isCurrentTNodeParent();
32346 const parent = isParent ? currentTNode : currentTNode && currentTNode.parent;
32347 // Parents cannot cross component boundaries because components will be used in multiple places.
32348 const tNode = tView.data[index] =
32349 createTNode(tView, parent, type, index, name, attrs);
32350 // Assign a pointer to the first child node of a given view. The first node is not always the one
32351 // at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
32352 // the index 1 or more, so we can't just check node index.
32353 if (tView.firstChild === null) {
32354 tView.firstChild = tNode;
32355 }
32356 if (currentTNode !== null) {
32357 if (isParent) {
32358 // FIXME(misko): This logic looks unnecessarily complicated. Could we simplify?
32359 if (currentTNode.child == null && tNode.parent !== null) {
32360 // We are in the same view, which means we are adding content node to the parent view.
32361 currentTNode.child = tNode;
32362 }
32363 }
32364 else {
32365 if (currentTNode.next === null) {
32366 // In the case of i18n the `currentTNode` may already be linked, in which case we don't want
32367 // to break the links which i18n created.
32368 currentTNode.next = tNode;
32369 }
32370 }
32371 }
32372 return tNode;
32373 }
32374 /**
32375 * When elements are created dynamically after a view blueprint is created (e.g. through
32376 * i18nApply()), we need to adjust the blueprint for future
32377 * template passes.
32378 *
32379 * @param tView `TView` associated with `LView`
32380 * @param lView The `LView` containing the blueprint to adjust
32381 * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
32382 * @param initialValue Initial value to store in blueprint
32383 */
32384 function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
32385 if (numSlotsToAlloc === 0)
32386 return -1;
32387 if (ngDevMode) {
32388 assertFirstCreatePass(tView);
32389 assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
32390 assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
32391 assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
32392 assertFirstUpdatePass(tView);
32393 }
32394 const allocIdx = lView.length;
32395 for (let i = 0; i < numSlotsToAlloc; i++) {
32396 lView.push(initialValue);
32397 tView.blueprint.push(initialValue);
32398 tView.data.push(null);
32399 }
32400 return allocIdx;
32401 }
32402 //////////////////////////
32403 //// Render
32404 //////////////////////////
32405 /**
32406 * Processes a view in the creation mode. This includes a number of steps in a specific order:
32407 * - creating view query functions (if any);
32408 * - executing a template function in the creation mode;
32409 * - updating static queries (if any);
32410 * - creating child components defined in a given view.
32411 */
32412 function renderView(tView, lView, context) {
32413 ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
32414 enterView(lView);
32415 try {
32416 const viewQuery = tView.viewQuery;
32417 if (viewQuery !== null) {
32418 executeViewQueryFn(1 /* Create */, viewQuery, context);
32419 }
32420 // Execute a template associated with this view, if it exists. A template function might not be
32421 // defined for the root component views.
32422 const templateFn = tView.template;
32423 if (templateFn !== null) {
32424 executeTemplate(tView, lView, templateFn, 1 /* Create */, context);
32425 }
32426 // This needs to be set before children are processed to support recursive components.
32427 // This must be set to false immediately after the first creation run because in an
32428 // ngFor loop, all the views will be created together before update mode runs and turns
32429 // off firstCreatePass. If we don't set it here, instances will perform directive
32430 // matching, etc again and again.
32431 if (tView.firstCreatePass) {
32432 tView.firstCreatePass = false;
32433 }
32434 // We resolve content queries specifically marked as `static` in creation mode. Dynamic
32435 // content queries are resolved during change detection (i.e. update mode), after embedded
32436 // views are refreshed (see block above).
32437 if (tView.staticContentQueries) {
32438 refreshContentQueries(tView, lView);
32439 }
32440 // We must materialize query results before child components are processed
32441 // in case a child component has projected a container. The LContainer needs
32442 // to exist so the embedded views are properly attached by the container.
32443 if (tView.staticViewQueries) {
32444 executeViewQueryFn(2 /* Update */, tView.viewQuery, context);
32445 }
32446 // Render child component views.
32447 const components = tView.components;
32448 if (components !== null) {
32449 renderChildComponents(lView, components);
32450 }
32451 }
32452 catch (error) {
32453 // If we didn't manage to get past the first template pass due to
32454 // an error, mark the view as corrupted so we can try to recover.
32455 if (tView.firstCreatePass) {
32456 tView.incompleteFirstPass = true;
32457 }
32458 throw error;
32459 }
32460 finally {
32461 lView[FLAGS] &= ~4 /* CreationMode */;
32462 leaveView();
32463 }
32464 }
32465 /**
32466 * Processes a view in update mode. This includes a number of steps in a specific order:
32467 * - executing a template function in update mode;
32468 * - executing hooks;
32469 * - refreshing queries;
32470 * - setting host bindings;
32471 * - refreshing child (embedded and component) views.
32472 */
32473 function refreshView(tView, lView, templateFn, context) {
32474 ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
32475 const flags = lView[FLAGS];
32476 if ((flags & 256 /* Destroyed */) === 256 /* Destroyed */)
32477 return;
32478 enterView(lView);
32479 // Check no changes mode is a dev only mode used to verify that bindings have not changed
32480 // since they were assigned. We do not want to execute lifecycle hooks in that mode.
32481 const isInCheckNoChangesPass = isInCheckNoChangesMode();
32482 try {
32483 resetPreOrderHookFlags(lView);
32484 setBindingIndex(tView.bindingStartIndex);
32485 if (templateFn !== null) {
32486 executeTemplate(tView, lView, templateFn, 2 /* Update */, context);
32487 }
32488 const hooksInitPhaseCompleted = (flags & 3 /* InitPhaseStateMask */) === 3 /* InitPhaseCompleted */;
32489 // execute pre-order hooks (OnInit, OnChanges, DoCheck)
32490 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
32491 if (!isInCheckNoChangesPass) {
32492 if (hooksInitPhaseCompleted) {
32493 const preOrderCheckHooks = tView.preOrderCheckHooks;
32494 if (preOrderCheckHooks !== null) {
32495 executeCheckHooks(lView, preOrderCheckHooks, null);
32496 }
32497 }
32498 else {
32499 const preOrderHooks = tView.preOrderHooks;
32500 if (preOrderHooks !== null) {
32501 executeInitAndCheckHooks(lView, preOrderHooks, 0 /* OnInitHooksToBeRun */, null);
32502 }
32503 incrementInitPhaseFlags(lView, 0 /* OnInitHooksToBeRun */);
32504 }
32505 }
32506 // First mark transplanted views that are declared in this lView as needing a refresh at their
32507 // insertion points. This is needed to avoid the situation where the template is defined in this
32508 // `LView` but its declaration appears after the insertion component.
32509 markTransplantedViewsForRefresh(lView);
32510 refreshEmbeddedViews(lView);
32511 // Content query results must be refreshed before content hooks are called.
32512 if (tView.contentQueries !== null) {
32513 refreshContentQueries(tView, lView);
32514 }
32515 // execute content hooks (AfterContentInit, AfterContentChecked)
32516 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
32517 if (!isInCheckNoChangesPass) {
32518 if (hooksInitPhaseCompleted) {
32519 const contentCheckHooks = tView.contentCheckHooks;
32520 if (contentCheckHooks !== null) {
32521 executeCheckHooks(lView, contentCheckHooks);
32522 }
32523 }
32524 else {
32525 const contentHooks = tView.contentHooks;
32526 if (contentHooks !== null) {
32527 executeInitAndCheckHooks(lView, contentHooks, 1 /* AfterContentInitHooksToBeRun */);
32528 }
32529 incrementInitPhaseFlags(lView, 1 /* AfterContentInitHooksToBeRun */);
32530 }
32531 }
32532 processHostBindingOpCodes(tView, lView);
32533 // Refresh child component views.
32534 const components = tView.components;
32535 if (components !== null) {
32536 refreshChildComponents(lView, components);
32537 }
32538 // View queries must execute after refreshing child components because a template in this view
32539 // could be inserted in a child component. If the view query executes before child component
32540 // refresh, the template might not yet be inserted.
32541 const viewQuery = tView.viewQuery;
32542 if (viewQuery !== null) {
32543 executeViewQueryFn(2 /* Update */, viewQuery, context);
32544 }
32545 // execute view hooks (AfterViewInit, AfterViewChecked)
32546 // PERF WARNING: do NOT extract this to a separate function without running benchmarks
32547 if (!isInCheckNoChangesPass) {
32548 if (hooksInitPhaseCompleted) {
32549 const viewCheckHooks = tView.viewCheckHooks;
32550 if (viewCheckHooks !== null) {
32551 executeCheckHooks(lView, viewCheckHooks);
32552 }
32553 }
32554 else {
32555 const viewHooks = tView.viewHooks;
32556 if (viewHooks !== null) {
32557 executeInitAndCheckHooks(lView, viewHooks, 2 /* AfterViewInitHooksToBeRun */);
32558 }
32559 incrementInitPhaseFlags(lView, 2 /* AfterViewInitHooksToBeRun */);
32560 }
32561 }
32562 if (tView.firstUpdatePass === true) {
32563 // We need to make sure that we only flip the flag on successful `refreshView` only
32564 // Don't do this in `finally` block.
32565 // If we did this in `finally` block then an exception could block the execution of styling
32566 // instructions which in turn would be unable to insert themselves into the styling linked
32567 // list. The result of this would be that if the exception would not be throw on subsequent CD
32568 // the styling would be unable to process it data and reflect to the DOM.
32569 tView.firstUpdatePass = false;
32570 }
32571 // Do not reset the dirty state when running in check no changes mode. We don't want components
32572 // to behave differently depending on whether check no changes is enabled or not. For example:
32573 // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
32574 // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
32575 // no changes cycle, the component would be not be dirty for the next update pass. This would
32576 // be different in production mode where the component dirty state is not reset.
32577 if (!isInCheckNoChangesPass) {
32578 lView[FLAGS] &= ~(64 /* Dirty */ | 8 /* FirstLViewPass */);
32579 }
32580 if (lView[FLAGS] & 1024 /* RefreshTransplantedView */) {
32581 lView[FLAGS] &= ~1024 /* RefreshTransplantedView */;
32582 updateTransplantedViewCount(lView[PARENT], -1);
32583 }
32584 }
32585 finally {
32586 leaveView();
32587 }
32588 }
32589 function renderComponentOrTemplate(tView, lView, templateFn, context) {
32590 const rendererFactory = lView[RENDERER_FACTORY];
32591 const normalExecutionPath = !isInCheckNoChangesMode();
32592 const creationModeIsActive = isCreationMode(lView);
32593 try {
32594 if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) {
32595 rendererFactory.begin();
32596 }
32597 if (creationModeIsActive) {
32598 renderView(tView, lView, context);
32599 }
32600 refreshView(tView, lView, templateFn, context);
32601 }
32602 finally {
32603 if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) {
32604 rendererFactory.end();
32605 }
32606 }
32607 }
32608 function executeTemplate(tView, lView, templateFn, rf, context) {
32609 const prevSelectedIndex = getSelectedIndex();
32610 try {
32611 setSelectedIndex(-1);
32612 if (rf & 2 /* Update */ && lView.length > HEADER_OFFSET) {
32613 // When we're updating, inherently select 0 so we don't
32614 // have to generate that instruction for most update blocks.
32615 selectIndexInternal(tView, lView, HEADER_OFFSET, isInCheckNoChangesMode());
32616 }
32617 templateFn(rf, context);
32618 }
32619 finally {
32620 setSelectedIndex(prevSelectedIndex);
32621 }
32622 }
32623 /**
32624 * Gets TView from a template function or creates a new TView
32625 * if it doesn't already exist.
32626 *
32627 * @param def ComponentDef
32628 * @returns TView
32629 */
32630 function getOrCreateTComponentView(def) {
32631 const tView = def.tView;
32632 // Create a TView if there isn't one, or recreate it if the first create pass didn't
32633 // complete successfully since we can't know for sure whether it's in a usable shape.
32634 if (tView === null || tView.incompleteFirstPass) {
32635 // Declaration node here is null since this function is called when we dynamically create a
32636 // component and hence there is no declaration.
32637 const declTNode = null;
32638 return def.tView = createTView(1 /* Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
32639 }
32640 return tView;
32641 }
32642 /**
32643 * Creates a TView instance
32644 *
32645 * @param type Type of `TView`.
32646 * @param declTNode Declaration location of this `TView`.
32647 * @param templateFn Template function
32648 * @param decls The number of nodes, local refs, and pipes in this template
32649 * @param directives Registry of directives for this view
32650 * @param pipes Registry of pipes for this view
32651 * @param viewQuery View queries for this view
32652 * @param schemas Schemas for this view
32653 * @param consts Constants for this view
32654 */
32655 function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
32656 ngDevMode && ngDevMode.tView++;
32657 const bindingStartIndex = HEADER_OFFSET + decls;
32658 // This length does not yet contain host bindings from child directives because at this point,
32659 // we don't know which directives are active on this template. As soon as a directive is matched
32660 // that has a host binding, we will update the blueprint with that def's hostVars count.
32661 const initialViewLength = bindingStartIndex + vars;
32662 const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
32663 const consts = typeof constsOrFactory === 'function' ? constsOrFactory() : constsOrFactory;
32664 const tView = blueprint[TVIEW] = ngDevMode ?
32665 new TViewConstructor(type, // type: TViewType,
32666 blueprint, // blueprint: LView,
32667 templateFn, // template: ComponentTemplate<{}>|null,
32668 null, // queries: TQueries|null
32669 viewQuery, // viewQuery: ViewQueriesFunction<{}>|null,
32670 declTNode, // declTNode: TNode|null,
32671 cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData,
32672 bindingStartIndex, // bindingStartIndex: number,
32673 initialViewLength, // expandoStartIndex: number,
32674 null, // hostBindingOpCodes: HostBindingOpCodes,
32675 true, // firstCreatePass: boolean,
32676 true, // firstUpdatePass: boolean,
32677 false, // staticViewQueries: boolean,
32678 false, // staticContentQueries: boolean,
32679 null, // preOrderHooks: HookData|null,
32680 null, // preOrderCheckHooks: HookData|null,
32681 null, // contentHooks: HookData|null,
32682 null, // contentCheckHooks: HookData|null,
32683 null, // viewHooks: HookData|null,
32684 null, // viewCheckHooks: HookData|null,
32685 null, // destroyHooks: DestroyHookData|null,
32686 null, // cleanup: any[]|null,
32687 null, // contentQueries: number[]|null,
32688 null, // components: number[]|null,
32689 typeof directives === 'function' ? //
32690 directives() : //
32691 directives, // directiveRegistry: DirectiveDefList|null,
32692 typeof pipes === 'function' ? pipes() : pipes, // pipeRegistry: PipeDefList|null,
32693 null, // firstChild: TNode|null,
32694 schemas, // schemas: SchemaMetadata[]|null,
32695 consts, // consts: TConstants|null
32696 false, // incompleteFirstPass: boolean
32697 decls, // ngDevMode only: decls
32698 vars) :
32699 {
32700 type: type,
32701 blueprint: blueprint,
32702 template: templateFn,
32703 queries: null,
32704 viewQuery: viewQuery,
32705 declTNode: declTNode,
32706 data: blueprint.slice().fill(null, bindingStartIndex),
32707 bindingStartIndex: bindingStartIndex,
32708 expandoStartIndex: initialViewLength,
32709 hostBindingOpCodes: null,
32710 firstCreatePass: true,
32711 firstUpdatePass: true,
32712 staticViewQueries: false,
32713 staticContentQueries: false,
32714 preOrderHooks: null,
32715 preOrderCheckHooks: null,
32716 contentHooks: null,
32717 contentCheckHooks: null,
32718 viewHooks: null,
32719 viewCheckHooks: null,
32720 destroyHooks: null,
32721 cleanup: null,
32722 contentQueries: null,
32723 components: null,
32724 directiveRegistry: typeof directives === 'function' ? directives() : directives,
32725 pipeRegistry: typeof pipes === 'function' ? pipes() : pipes,
32726 firstChild: null,
32727 schemas: schemas,
32728 consts: consts,
32729 incompleteFirstPass: false
32730 };
32731 if (ngDevMode) {
32732 // For performance reasons it is important that the tView retains the same shape during runtime.
32733 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
32734 // prevent class transitions.
32735 Object.seal(tView);
32736 }
32737 return tView;
32738 }
32739 function createViewBlueprint(bindingStartIndex, initialViewLength) {
32740 const blueprint = ngDevMode ? new LViewBlueprint() : [];
32741 for (let i = 0; i < initialViewLength; i++) {
32742 blueprint.push(i < bindingStartIndex ? null : NO_CHANGE);
32743 }
32744 return blueprint;
32745 }
32746 function createError(text, token) {
32747 return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
32748 }
32749 function assertHostNodeExists(rElement, elementOrSelector) {
32750 if (!rElement) {
32751 if (typeof elementOrSelector === 'string') {
32752 throw createError('Host node with selector not found:', elementOrSelector);
32753 }
32754 else {
32755 throw createError('Host node is required:', elementOrSelector);
32756 }
32757 }
32758 }
32759 /**
32760 * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
32761 *
32762 * @param rendererFactory Factory function to create renderer instance.
32763 * @param elementOrSelector Render element or CSS selector to locate the element.
32764 * @param encapsulation View Encapsulation defined for component that requests host element.
32765 */
32766 function locateHostElement(renderer, elementOrSelector, encapsulation) {
32767 if (isProceduralRenderer(renderer)) {
32768 // When using native Shadow DOM, do not clear host element to allow native slot projection
32769 const preserveContent = encapsulation === ViewEncapsulation$1.ShadowDom;
32770 return renderer.selectRootElement(elementOrSelector, preserveContent);
32771 }
32772 let rElement = typeof elementOrSelector === 'string' ?
32773 renderer.querySelector(elementOrSelector) :
32774 elementOrSelector;
32775 ngDevMode && assertHostNodeExists(rElement, elementOrSelector);
32776 // Always clear host element's content when Renderer3 is in use. For procedural renderer case we
32777 // make it depend on whether ShadowDom encapsulation is used (in which case the content should be
32778 // preserved to allow native slot projection). ShadowDom encapsulation requires procedural
32779 // renderer, and procedural renderer case is handled above.
32780 rElement.textContent = '';
32781 return rElement;
32782 }
32783 /**
32784 * Saves context for this cleanup function in LView.cleanupInstances.
32785 *
32786 * On the first template pass, saves in TView:
32787 * - Cleanup function
32788 * - Index of context we just saved in LView.cleanupInstances
32789 *
32790 * This function can also be used to store instance specific cleanup fns. In that case the `context`
32791 * is `null` and the function is store in `LView` (rather than it `TView`).
32792 */
32793 function storeCleanupWithContext(tView, lView, context, cleanupFn) {
32794 const lCleanup = getOrCreateLViewCleanup(lView);
32795 if (context === null) {
32796 // If context is null that this is instance specific callback. These callbacks can only be
32797 // inserted after template shared instances. For this reason in ngDevMode we freeze the TView.
32798 if (ngDevMode) {
32799 Object.freeze(getOrCreateTViewCleanup(tView));
32800 }
32801 lCleanup.push(cleanupFn);
32802 }
32803 else {
32804 lCleanup.push(context);
32805 if (tView.firstCreatePass) {
32806 getOrCreateTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1);
32807 }
32808 }
32809 }
32810 function createTNode(tView, tParent, type, index, value, attrs) {
32811 ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
32812 // `view_engine_compatibility` for additional context.
32813 assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
32814 ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\'');
32815 ngDevMode && ngDevMode.tNode++;
32816 ngDevMode && tParent && assertTNodeForTView(tParent, tView);
32817 let injectorIndex = tParent ? tParent.injectorIndex : -1;
32818 const tNode = ngDevMode ?
32819 new TNodeDebug(tView, // tView_: TView
32820 type, // type: TNodeType
32821 index, // index: number
32822 null, // insertBeforeIndex: null|-1|number|number[]
32823 injectorIndex, // injectorIndex: number
32824 -1, // directiveStart: number
32825 -1, // directiveEnd: number
32826 -1, // directiveStylingLast: number
32827 null, // propertyBindings: number[]|null
32828 0, // flags: TNodeFlags
32829 0, // providerIndexes: TNodeProviderIndexes
32830 value, // value: string|null
32831 attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
32832 null, // mergedAttrs
32833 null, // localNames: (string|number)[]|null
32834 undefined, // initialInputs: (string[]|null)[]|null|undefined
32835 null, // inputs: PropertyAliases|null
32836 null, // outputs: PropertyAliases|null
32837 null, // tViews: ITView|ITView[]|null
32838 null, // next: ITNode|null
32839 null, // projectionNext: ITNode|null
32840 null, // child: ITNode|null
32841 tParent, // parent: TElementNode|TContainerNode|null
32842 null, // projection: number|(ITNode|RNode[])[]|null
32843 null, // styles: string|null
32844 null, // stylesWithoutHost: string|null
32845 undefined, // residualStyles: string|null
32846 null, // classes: string|null
32847 null, // classesWithoutHost: string|null
32848 undefined, // residualClasses: string|null
32849 0, // classBindings: TStylingRange;
32850 0) :
32851 {
32852 type,
32853 index,
32854 insertBeforeIndex: null,
32855 injectorIndex,
32856 directiveStart: -1,
32857 directiveEnd: -1,
32858 directiveStylingLast: -1,
32859 propertyBindings: null,
32860 flags: 0,
32861 providerIndexes: 0,
32862 value: value,
32863 attrs: attrs,
32864 mergedAttrs: null,
32865 localNames: null,
32866 initialInputs: undefined,
32867 inputs: null,
32868 outputs: null,
32869 tViews: null,
32870 next: null,
32871 projectionNext: null,
32872 child: null,
32873 parent: tParent,
32874 projection: null,
32875 styles: null,
32876 stylesWithoutHost: null,
32877 residualStyles: undefined,
32878 classes: null,
32879 classesWithoutHost: null,
32880 residualClasses: undefined,
32881 classBindings: 0,
32882 styleBindings: 0,
32883 };
32884 if (ngDevMode) {
32885 // For performance reasons it is important that the tNode retains the same shape during runtime.
32886 // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
32887 // prevent class transitions.
32888 Object.seal(tNode);
32889 }
32890 return tNode;
32891 }
32892 /**
32893 * Instantiate a root component.
32894 */
32895 function instantiateRootComponent(tView, lView, def) {
32896 const rootTNode = getCurrentTNode();
32897 if (tView.firstCreatePass) {
32898 if (def.providersResolver)
32899 def.providersResolver(def);
32900 const directiveIndex = allocExpando(tView, lView, 1, null);
32901 ngDevMode &&
32902 assertEqual(directiveIndex, rootTNode.directiveStart, 'Because this is a root component the allocated expando should match the TNode component.');
32903 configureViewWithDirective(tView, rootTNode, lView, directiveIndex, def);
32904 }
32905 const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart, rootTNode);
32906 attachPatchData(directive, lView);
32907 const native = getNativeByTNode(rootTNode, lView);
32908 if (native) {
32909 attachPatchData(native, lView);
32910 }
32911 return directive;
32912 }
32913 /**
32914 * Add `hostBindings` to the `TView.hostBindingOpCodes`.
32915 *
32916 * @param tView `TView` to which the `hostBindings` should be added.
32917 * @param tNode `TNode` the element which contains the directive
32918 * @param lView `LView` current `LView`
32919 * @param directiveIdx Directive index in view.
32920 * @param directiveVarsIdx Where will the directive's vars be stored
32921 * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
32922 */
32923 function registerHostBindingOpCodes(tView, tNode, lView, directiveIdx, directiveVarsIdx, def) {
32924 ngDevMode && assertFirstCreatePass(tView);
32925 const hostBindings = def.hostBindings;
32926 if (hostBindings) {
32927 let hostBindingOpCodes = tView.hostBindingOpCodes;
32928 if (hostBindingOpCodes === null) {
32929 hostBindingOpCodes = tView.hostBindingOpCodes = [];
32930 }
32931 const elementIndx = ~tNode.index;
32932 if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
32933 // Conditionally add select element so that we are more efficient in execution.
32934 // NOTE: this is strictly not necessary and it trades code size for runtime perf.
32935 // (We could just always add it.)
32936 hostBindingOpCodes.push(elementIndx);
32937 }
32938 hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
32939 }
32940 }
32941 /**
32942 * Returns the last selected element index in the `HostBindingOpCodes`
32943 *
32944 * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
32945 * if it changes. This method returns the last index (or '0' if not found.)
32946 *
32947 * Selected element index are only the ones which are negative.
32948 */
32949 function lastSelectedElementIdx(hostBindingOpCodes) {
32950 let i = hostBindingOpCodes.length;
32951 while (i > 0) {
32952 const value = hostBindingOpCodes[--i];
32953 if (typeof value === 'number' && value < 0) {
32954 return value;
32955 }
32956 }
32957 return 0;
32958 }
32959 /**
32960 * Invoke the host bindings in creation mode.
32961 *
32962 * @param def `DirectiveDef` which may contain the `hostBindings` function.
32963 * @param directive Instance of directive.
32964 */
32965 function invokeHostBindingsInCreationMode(def, directive) {
32966 if (def.hostBindings !== null) {
32967 def.hostBindings(1 /* Create */, directive);
32968 }
32969 }
32970 /**
32971 * Marks a given TNode as a component's host. This consists of:
32972 * - setting appropriate TNode flags;
32973 * - storing index of component's host element so it will be queued for view refresh during CD.
32974 */
32975 function markAsComponentHost(tView, hostTNode) {
32976 ngDevMode && assertFirstCreatePass(tView);
32977 hostTNode.flags |= 2 /* isComponentHost */;
32978 (tView.components || (tView.components = ngDevMode ? new TViewComponents() : []))
32979 .push(hostTNode.index);
32980 }
32981 /**
32982 * Initializes the flags on the current node, setting all indices to the initial index,
32983 * the directive count to 0, and adding the isComponent flag.
32984 * @param index the initial index
32985 */
32986 function initTNodeFlags(tNode, index, numberOfDirectives) {
32987 ngDevMode &&
32988 assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
32989 tNode.flags |= 1 /* isDirectiveHost */;
32990 // When the first directive is created on a node, save the index
32991 tNode.directiveStart = index;
32992 tNode.directiveEnd = index + numberOfDirectives;
32993 tNode.providerIndexes = index;
32994 }
32995 /**
32996 * Setup directive for instantiation.
32997 *
32998 * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
32999 * as `LView`. `TView` gets the `DirectiveDef`.
33000 *
33001 * @param tView `TView`
33002 * @param tNode `TNode`
33003 * @param lView `LView`
33004 * @param directiveIndex Index where the directive will be stored in the Expando.
33005 * @param def `DirectiveDef`
33006 */
33007 function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
33008 ngDevMode &&
33009 assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
33010 tView.data[directiveIndex] = def;
33011 const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
33012 const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null);
33013 tView.blueprint[directiveIndex] = nodeInjectorFactory;
33014 lView[directiveIndex] = nodeInjectorFactory;
33015 registerHostBindingOpCodes(tView, tNode, lView, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
33016 }
33017 //////////////////////////
33018 //// ViewContainer & View
33019 //////////////////////////
33020 // Not sure why I need to do `any` here but TS complains later.
33021 const LContainerArray = ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) &&
33022 createNamedArrayType('LContainer');
33023 /**
33024 * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
33025 * them by executing an associated template function.
33026 */
33027 function refreshEmbeddedViews(lView) {
33028 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
33029 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
33030 const embeddedLView = lContainer[i];
33031 const embeddedTView = embeddedLView[TVIEW];
33032 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
33033 if (viewAttachedToChangeDetector(embeddedLView)) {
33034 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
33035 }
33036 }
33037 }
33038 }
33039 /**
33040 * Mark transplanted views as needing to be refreshed at their insertion points.
33041 *
33042 * @param lView The `LView` that may have transplanted views.
33043 */
33044 function markTransplantedViewsForRefresh(lView) {
33045 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
33046 if (!lContainer[HAS_TRANSPLANTED_VIEWS])
33047 continue;
33048 const movedViews = lContainer[MOVED_VIEWS];
33049 ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
33050 for (let i = 0; i < movedViews.length; i++) {
33051 const movedLView = movedViews[i];
33052 const insertionLContainer = movedLView[PARENT];
33053 ngDevMode && assertLContainer(insertionLContainer);
33054 // We don't want to increment the counter if the moved LView was already marked for
33055 // refresh.
33056 if ((movedLView[FLAGS] & 1024 /* RefreshTransplantedView */) === 0) {
33057 updateTransplantedViewCount(insertionLContainer, 1);
33058 }
33059 // Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
33060 // those that aren't (declaration component === insertion component). In the latter case,
33061 // it's fine to add the flag, as we will clear it immediately in
33062 // `refreshEmbeddedViews` for the view currently being refreshed.
33063 movedLView[FLAGS] |= 1024 /* RefreshTransplantedView */;
33064 }
33065 }
33066 }
33067 /////////////
33068 /**
33069 * Refreshes components by entering the component view and processing its bindings, queries, etc.
33070 *
33071 * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
33072 */
33073 function refreshComponent(hostLView, componentHostIdx) {
33074 ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
33075 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
33076 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
33077 if (viewAttachedToChangeDetector(componentView)) {
33078 const tView = componentView[TVIEW];
33079 if (componentView[FLAGS] & (16 /* CheckAlways */ | 64 /* Dirty */)) {
33080 refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
33081 }
33082 else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
33083 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
33084 refreshContainsDirtyView(componentView);
33085 }
33086 }
33087 }
33088 /**
33089 * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
33090 * children or descendants of the given lView.
33091 *
33092 * @param lView The lView which contains descendant transplanted views that need to be refreshed.
33093 */
33094 function refreshContainsDirtyView(lView) {
33095 for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
33096 for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
33097 const embeddedLView = lContainer[i];
33098 if (embeddedLView[FLAGS] & 1024 /* RefreshTransplantedView */) {
33099 const embeddedTView = embeddedLView[TVIEW];
33100 ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
33101 refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
33102 }
33103 else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
33104 refreshContainsDirtyView(embeddedLView);
33105 }
33106 }
33107 }
33108 const tView = lView[TVIEW];
33109 // Refresh child component views.
33110 const components = tView.components;
33111 if (components !== null) {
33112 for (let i = 0; i < components.length; i++) {
33113 const componentView = getComponentLViewByIndex(components[i], lView);
33114 // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
33115 if (viewAttachedToChangeDetector(componentView) &&
33116 componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
33117 refreshContainsDirtyView(componentView);
33118 }
33119 }
33120 }
33121 }
33122 function renderComponent(hostLView, componentHostIdx) {
33123 ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
33124 const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
33125 const componentTView = componentView[TVIEW];
33126 syncViewWithBlueprint(componentTView, componentView);
33127 renderView(componentTView, componentView, componentView[CONTEXT]);
33128 }
33129 /**
33130 * Syncs an LView instance with its blueprint if they have gotten out of sync.
33131 *
33132 * Typically, blueprints and their view instances should always be in sync, so the loop here
33133 * will be skipped. However, consider this case of two components side-by-side:
33134 *
33135 * App template:
33136 * ```
33137 * <comp></comp>
33138 * <comp></comp>
33139 * ```
33140 *
33141 * The following will happen:
33142 * 1. App template begins processing.
33143 * 2. First <comp> is matched as a component and its LView is created.
33144 * 3. Second <comp> is matched as a component and its LView is created.
33145 * 4. App template completes processing, so it's time to check child templates.
33146 * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
33147 * 6. Second <comp> template is checked. Its blueprint has been updated by the first
33148 * <comp> template, but its LView was created before this update, so it is out of sync.
33149 *
33150 * Note that embedded views inside ngFor loops will never be out of sync because these views
33151 * are processed as soon as they are created.
33152 *
33153 * @param tView The `TView` that contains the blueprint for syncing
33154 * @param lView The view to sync
33155 */
33156 function syncViewWithBlueprint(tView, lView) {
33157 for (let i = lView.length; i < tView.blueprint.length; i++) {
33158 lView.push(tView.blueprint[i]);
33159 }
33160 }
33161 /**
33162 * Adds LView or LContainer to the end of the current view tree.
33163 *
33164 * This structure will be used to traverse through nested views to remove listeners
33165 * and call onDestroy callbacks.
33166 *
33167 * @param lView The view where LView or LContainer should be added
33168 * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header
33169 * @param lViewOrLContainer The LView or LContainer to add to the view tree
33170 * @returns The state passed in
33171 */
33172 function addToViewTree(lView, lViewOrLContainer) {
33173 // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
33174 // to the end of the queue, which means if the developer retrieves the LContainers from RNodes out
33175 // of order, the change detection will run out of order, as the act of retrieving the the
33176 // LContainer from the RNode is what adds it to the queue.
33177 if (lView[CHILD_HEAD]) {
33178 lView[CHILD_TAIL][NEXT] = lViewOrLContainer;
33179 }
33180 else {
33181 lView[CHILD_HEAD] = lViewOrLContainer;
33182 }
33183 lView[CHILD_TAIL] = lViewOrLContainer;
33184 return lViewOrLContainer;
33185 }
33186 ///////////////////////////////
33187 //// Change detection
33188 ///////////////////////////////
33189 /**
33190 * Marks current view and all ancestors dirty.
33191 *
33192 * Returns the root view because it is found as a byproduct of marking the view tree
33193 * dirty, and can be used by methods that consume markViewDirty() to easily schedule
33194 * change detection. Otherwise, such methods would need to traverse up the view tree
33195 * an additional time to get the root view and schedule a tick on it.
33196 *
33197 * @param lView The starting LView to mark dirty
33198 * @returns the root LView
33199 */
33200 function markViewDirty(lView) {
33201 while (lView) {
33202 lView[FLAGS] |= 64 /* Dirty */;
33203 const parent = getLViewParent(lView);
33204 // Stop traversing up as soon as you find a root view that wasn't attached to any container
33205 if (isRootView(lView) && !parent) {
33206 return lView;
33207 }
33208 // continue otherwise
33209 lView = parent;
33210 }
33211 return null;
33212 }
33213 function tickRootContext(rootContext) {
33214 for (let i = 0; i < rootContext.components.length; i++) {
33215 const rootComponent = rootContext.components[i];
33216 const lView = readPatchedLView(rootComponent);
33217 const tView = lView[TVIEW];
33218 renderComponentOrTemplate(tView, lView, tView.template, rootComponent);
33219 }
33220 }
33221 function detectChangesInternal(tView, lView, context) {
33222 const rendererFactory = lView[RENDERER_FACTORY];
33223 if (rendererFactory.begin)
33224 rendererFactory.begin();
33225 try {
33226 refreshView(tView, lView, tView.template, context);
33227 }
33228 catch (error) {
33229 handleError(lView, error);
33230 throw error;
33231 }
33232 finally {
33233 if (rendererFactory.end)
33234 rendererFactory.end();
33235 }
33236 }
33237 /**
33238 * Synchronously perform change detection on a root view and its components.
33239 *
33240 * @param lView The view which the change detection should be performed on.
33241 */
33242 function detectChangesInRootView(lView) {
33243 tickRootContext(lView[CONTEXT]);
33244 }
33245 function checkNoChangesInternal(tView, view, context) {
33246 setIsInCheckNoChangesMode(true);
33247 try {
33248 detectChangesInternal(tView, view, context);
33249 }
33250 finally {
33251 setIsInCheckNoChangesMode(false);
33252 }
33253 }
33254 /**
33255 * Checks the change detector on a root view and its components, and throws if any changes are
33256 * detected.
33257 *
33258 * This is used in development mode to verify that running change detection doesn't
33259 * introduce other changes.
33260 *
33261 * @param lView The view which the change detection should be checked on.
33262 */
33263 function checkNoChangesInRootView(lView) {
33264 setIsInCheckNoChangesMode(true);
33265 try {
33266 detectChangesInRootView(lView);
33267 }
33268 finally {
33269 setIsInCheckNoChangesMode(false);
33270 }
33271 }
33272 function executeViewQueryFn(flags, viewQueryFn, component) {
33273 ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
33274 setCurrentQueryIndex(0);
33275 viewQueryFn(flags, component);
33276 }
33277 const CLEAN_PROMISE = _CLEAN_PROMISE;
33278 function getOrCreateLViewCleanup(view) {
33279 // top level variables should not be exported for performance reasons (PERF_NOTES.md)
33280 return view[CLEANUP] || (view[CLEANUP] = ngDevMode ? new LCleanup() : []);
33281 }
33282 function getOrCreateTViewCleanup(tView) {
33283 return tView.cleanup || (tView.cleanup = ngDevMode ? new TCleanup() : []);
33284 }
33285 /** Handles an error thrown in an LView. */
33286 function handleError(lView, error) {
33287 const injector = lView[INJECTOR];
33288 const errorHandler = injector ? injector.get(ErrorHandler, null) : null;
33289 errorHandler && errorHandler.handleError(error);
33290 }
33291
33292 /**
33293 * @license
33294 * Copyright Google LLC All Rights Reserved.
33295 *
33296 * Use of this source code is governed by an MIT-style license that can be
33297 * found in the LICENSE file at https://angular.io/license
33298 */
33299 /**
33300 * Compute the static styling (class/style) from `TAttributes`.
33301 *
33302 * This function should be called during `firstCreatePass` only.
33303 *
33304 * @param tNode The `TNode` into which the styling information should be loaded.
33305 * @param attrs `TAttributes` containing the styling information.
33306 * @param writeToHost Where should the resulting static styles be written?
33307 * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
33308 * - `true` Write to `TNode.styles` / `TNode.classes`
33309 */
33310 function computeStaticStyling(tNode, attrs, writeToHost) {
33311 ngDevMode &&
33312 assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
33313 let styles = writeToHost ? tNode.styles : null;
33314 let classes = writeToHost ? tNode.classes : null;
33315 let mode = 0;
33316 if (attrs !== null) {
33317 for (let i = 0; i < attrs.length; i++) {
33318 const value = attrs[i];
33319 if (typeof value === 'number') {
33320 mode = value;
33321 }
33322 else if (mode == 1 /* Classes */) {
33323 classes = concatStringsWithSpace(classes, value);
33324 }
33325 else if (mode == 2 /* Styles */) {
33326 const style = value;
33327 const styleValue = attrs[++i];
33328 styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
33329 }
33330 }
33331 }
33332 writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
33333 writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
33334 }
33335
33336 /**
33337 * @license
33338 * Copyright Google LLC All Rights Reserved.
33339 *
33340 * Use of this source code is governed by an MIT-style license that can be
33341 * found in the LICENSE file at https://angular.io/license
33342 */
33343 /**
33344 * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors.
33345 *
33346 * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a
33347 * project.
33348 *
33349 * @publicApi
33350 */
33351 const INJECTOR$1 = new InjectionToken('INJECTOR',
33352 // Dissable tslint because this is const enum which gets inlined not top level prop access.
33353 // tslint:disable-next-line: no-toplevel-property-access
33354 -1 /* Injector */);
33355
33356 /**
33357 * @license
33358 * Copyright Google LLC All Rights Reserved.
33359 *
33360 * Use of this source code is governed by an MIT-style license that can be
33361 * found in the LICENSE file at https://angular.io/license
33362 */
33363 class NullInjector {
33364 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
33365 if (notFoundValue === THROW_IF_NOT_FOUND) {
33366 const error = new Error(`NullInjectorError: No provider for ${stringify$1(token)}!`);
33367 error.name = 'NullInjectorError';
33368 throw error;
33369 }
33370 return notFoundValue;
33371 }
33372 }
33373
33374 /**
33375 * @license
33376 * Copyright Google LLC All Rights Reserved.
33377 *
33378 * Use of this source code is governed by an MIT-style license that can be
33379 * found in the LICENSE file at https://angular.io/license
33380 */
33381 /**
33382 * An internal token whose presence in an injector indicates that the injector should treat itself
33383 * as a root scoped injector when processing requests for unknown tokens which may indicate
33384 * they are provided in the root scope.
33385 */
33386 const INJECTOR_SCOPE = new InjectionToken('Set Injector scope.');
33387
33388 /**
33389 * @license
33390 * Copyright Google LLC All Rights Reserved.
33391 *
33392 * Use of this source code is governed by an MIT-style license that can be
33393 * found in the LICENSE file at https://angular.io/license
33394 */
33395 function INJECTOR_IMPL__PRE_R3__(providers, parent, name) {
33396 return new StaticInjector(providers, parent, name);
33397 }
33398 const INJECTOR_IMPL = INJECTOR_IMPL__PRE_R3__;
33399 /**
33400 * Concrete injectors implement this interface. Injectors are configured
33401 * with [providers](guide/glossary#provider) that associate
33402 * dependencies of various types with [injection tokens](guide/glossary#di-token).
33403 *
33404 * @see ["DI Providers"](guide/dependency-injection-providers).
33405 * @see `StaticProvider`
33406 *
33407 * @usageNotes
33408 *
33409 * The following example creates a service injector instance.
33410 *
33411 * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
33412 *
33413 * ### Usage example
33414 *
33415 * {@example core/di/ts/injector_spec.ts region='Injector'}
33416 *
33417 * `Injector` returns itself when given `Injector` as a token:
33418 *
33419 * {@example core/di/ts/injector_spec.ts region='injectInjector'}
33420 *
33421 * @publicApi
33422 */
33423 class Injector {
33424 static create(options, parent) {
33425 if (Array.isArray(options)) {
33426 return INJECTOR_IMPL(options, parent, '');
33427 }
33428 else {
33429 return INJECTOR_IMPL(options.providers, options.parent, options.name || '');
33430 }
33431 }
33432 }
33433 Injector.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
33434 Injector.NULL = new NullInjector();
33435 /** @nocollapse */
33436 Injector.ɵprov = ɵɵdefineInjectable({
33437 token: Injector,
33438 providedIn: 'any',
33439 factory: () => ɵɵinject(INJECTOR$1),
33440 });
33441 /**
33442 * @internal
33443 * @nocollapse
33444 */
33445 Injector.__NG_ELEMENT_ID__ = -1 /* Injector */;
33446 const IDENT = function (value) {
33447 return value;
33448 };
33449 const EMPTY = [];
33450 const CIRCULAR = IDENT;
33451 const MULTI_PROVIDER_FN = function () {
33452 return Array.prototype.slice.call(arguments);
33453 };
33454 const NO_NEW_LINE$1 = 'ɵ';
33455 class StaticInjector {
33456 constructor(providers, parent = Injector.NULL, source = null) {
33457 this.parent = parent;
33458 this.source = source;
33459 const records = this._records = new Map();
33460 records.set(Injector, { token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false });
33461 records.set(INJECTOR$1, { token: INJECTOR$1, fn: IDENT, deps: EMPTY, value: this, useNew: false });
33462 this.scope = recursivelyProcessProviders(records, providers);
33463 }
33464 get(token, notFoundValue, flags = InjectFlags.Default) {
33465 const records = this._records;
33466 let record = records.get(token);
33467 if (record === undefined) {
33468 // This means we have never seen this record, see if it is tree shakable provider.
33469 const injectableDef = getInjectableDef(token);
33470 if (injectableDef) {
33471 const providedIn = injectableDef && injectableDef.providedIn;
33472 if (providedIn === 'any' || providedIn != null && providedIn === this.scope) {
33473 records.set(token, record = resolveProvider({ provide: token, useFactory: injectableDef.factory, deps: EMPTY }));
33474 }
33475 }
33476 if (record === undefined) {
33477 // Set record to null to make sure that we don't go through expensive lookup above again.
33478 records.set(token, null);
33479 }
33480 }
33481 let lastInjector = setCurrentInjector(this);
33482 try {
33483 return tryResolveToken(token, record, records, this.parent, notFoundValue, flags);
33484 }
33485 catch (e) {
33486 return catchInjectorError(e, token, 'StaticInjectorError', this.source);
33487 }
33488 finally {
33489 setCurrentInjector(lastInjector);
33490 }
33491 }
33492 toString() {
33493 const tokens = [], records = this._records;
33494 records.forEach((v, token) => tokens.push(stringify$1(token)));
33495 return `StaticInjector[${tokens.join(', ')}]`;
33496 }
33497 }
33498 function resolveProvider(provider) {
33499 const deps = computeDeps(provider);
33500 let fn = IDENT;
33501 let value = EMPTY;
33502 let useNew = false;
33503 let provide = resolveForwardRef$1(provider.provide);
33504 if (USE_VALUE$2 in provider) {
33505 // We need to use USE_VALUE in provider since provider.useValue could be defined as undefined.
33506 value = provider.useValue;
33507 }
33508 else if (provider.useFactory) {
33509 fn = provider.useFactory;
33510 }
33511 else if (provider.useExisting) ;
33512 else if (provider.useClass) {
33513 useNew = true;
33514 fn = resolveForwardRef$1(provider.useClass);
33515 }
33516 else if (typeof provide == 'function') {
33517 useNew = true;
33518 fn = provide;
33519 }
33520 else {
33521 throw staticError('StaticProvider does not have [useValue|useFactory|useExisting|useClass] or [provide] is not newable', provider);
33522 }
33523 return { deps, fn, useNew, value };
33524 }
33525 function multiProviderMixError(token) {
33526 return staticError('Cannot mix multi providers and regular providers', token);
33527 }
33528 function recursivelyProcessProviders(records, provider) {
33529 let scope = null;
33530 if (provider) {
33531 provider = resolveForwardRef$1(provider);
33532 if (Array.isArray(provider)) {
33533 // if we have an array recurse into the array
33534 for (let i = 0; i < provider.length; i++) {
33535 scope = recursivelyProcessProviders(records, provider[i]) || scope;
33536 }
33537 }
33538 else if (typeof provider === 'function') {
33539 // Functions were supported in ReflectiveInjector, but are not here. For safety give useful
33540 // error messages
33541 throw staticError('Function/Class not supported', provider);
33542 }
33543 else if (provider && typeof provider === 'object' && provider.provide) {
33544 // At this point we have what looks like a provider: {provide: ?, ....}
33545 let token = resolveForwardRef$1(provider.provide);
33546 const resolvedProvider = resolveProvider(provider);
33547 if (provider.multi === true) {
33548 // This is a multi provider.
33549 let multiProvider = records.get(token);
33550 if (multiProvider) {
33551 if (multiProvider.fn !== MULTI_PROVIDER_FN) {
33552 throw multiProviderMixError(token);
33553 }
33554 }
33555 else {
33556 // Create a placeholder factory which will look up the constituents of the multi provider.
33557 records.set(token, multiProvider = {
33558 token: provider.provide,
33559 deps: [],
33560 useNew: false,
33561 fn: MULTI_PROVIDER_FN,
33562 value: EMPTY
33563 });
33564 }
33565 // Treat the provider as the token.
33566 token = provider;
33567 multiProvider.deps.push({ token, options: 6 /* Default */ });
33568 }
33569 const record = records.get(token);
33570 if (record && record.fn == MULTI_PROVIDER_FN) {
33571 throw multiProviderMixError(token);
33572 }
33573 if (token === INJECTOR_SCOPE) {
33574 scope = resolvedProvider.value;
33575 }
33576 records.set(token, resolvedProvider);
33577 }
33578 else {
33579 throw staticError('Unexpected provider', provider);
33580 }
33581 }
33582 return scope;
33583 }
33584 function tryResolveToken(token, record, records, parent, notFoundValue, flags) {
33585 try {
33586 return resolveToken(token, record, records, parent, notFoundValue, flags);
33587 }
33588 catch (e) {
33589 // ensure that 'e' is of type Error.
33590 if (!(e instanceof Error)) {
33591 e = new Error(e);
33592 }
33593 const path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || [];
33594 path.unshift(token);
33595 if (record && record.value == CIRCULAR) {
33596 // Reset the Circular flag.
33597 record.value = EMPTY;
33598 }
33599 throw e;
33600 }
33601 }
33602 function resolveToken(token, record, records, parent, notFoundValue, flags) {
33603 let value;
33604 if (record && !(flags & InjectFlags.SkipSelf)) {
33605 // If we don't have a record, this implies that we don't own the provider hence don't know how
33606 // to resolve it.
33607 value = record.value;
33608 if (value == CIRCULAR) {
33609 throw Error(NO_NEW_LINE$1 + 'Circular dependency');
33610 }
33611 else if (value === EMPTY) {
33612 record.value = CIRCULAR;
33613 let obj = undefined;
33614 let useNew = record.useNew;
33615 let fn = record.fn;
33616 let depRecords = record.deps;
33617 let deps = EMPTY;
33618 if (depRecords.length) {
33619 deps = [];
33620 for (let i = 0; i < depRecords.length; i++) {
33621 const depRecord = depRecords[i];
33622 const options = depRecord.options;
33623 const childRecord = options & 2 /* CheckSelf */ ? records.get(depRecord.token) : undefined;
33624 deps.push(tryResolveToken(
33625 // Current Token to resolve
33626 depRecord.token,
33627 // A record which describes how to resolve the token.
33628 // If undefined, this means we don't have such a record
33629 childRecord,
33630 // Other records we know about.
33631 records,
33632 // If we don't know how to resolve dependency and we should not check parent for it,
33633 // than pass in Null injector.
33634 !childRecord && !(options & 4 /* CheckParent */) ? Injector.NULL : parent, options & 1 /* Optional */ ? null : Injector.THROW_IF_NOT_FOUND, InjectFlags.Default));
33635 }
33636 }
33637 record.value = value = useNew ? new fn(...deps) : fn.apply(obj, deps);
33638 }
33639 }
33640 else if (!(flags & InjectFlags.Self)) {
33641 value = parent.get(token, notFoundValue, InjectFlags.Default);
33642 }
33643 else if (!(flags & InjectFlags.Optional)) {
33644 value = Injector.NULL.get(token, notFoundValue);
33645 }
33646 else {
33647 value = Injector.NULL.get(token, typeof notFoundValue !== 'undefined' ? notFoundValue : null);
33648 }
33649 return value;
33650 }
33651 function computeDeps(provider) {
33652 let deps = EMPTY;
33653 const providerDeps = provider.deps;
33654 if (providerDeps && providerDeps.length) {
33655 deps = [];
33656 for (let i = 0; i < providerDeps.length; i++) {
33657 let options = 6 /* Default */;
33658 let token = resolveForwardRef$1(providerDeps[i]);
33659 if (Array.isArray(token)) {
33660 for (let j = 0, annotations = token; j < annotations.length; j++) {
33661 const annotation = annotations[j];
33662 if (annotation instanceof Optional || annotation == Optional) {
33663 options = options | 1 /* Optional */;
33664 }
33665 else if (annotation instanceof SkipSelf || annotation == SkipSelf) {
33666 options = options & ~2 /* CheckSelf */;
33667 }
33668 else if (annotation instanceof Self || annotation == Self) {
33669 options = options & ~4 /* CheckParent */;
33670 }
33671 else if (annotation instanceof Inject) {
33672 token = annotation.token;
33673 }
33674 else {
33675 token = resolveForwardRef$1(annotation);
33676 }
33677 }
33678 }
33679 deps.push({ token, options });
33680 }
33681 }
33682 else if (provider.useExisting) {
33683 const token = resolveForwardRef$1(provider.useExisting);
33684 deps = [{ token, options: 6 /* Default */ }];
33685 }
33686 else if (!providerDeps && !(USE_VALUE$2 in provider)) {
33687 // useValue & useExisting are the only ones which are exempt from deps all others need it.
33688 throw staticError('\'deps\' required', provider);
33689 }
33690 return deps;
33691 }
33692 function staticError(text, obj) {
33693 return new Error(formatError(text, obj, 'StaticInjectorError'));
33694 }
33695
33696 /**
33697 * @license
33698 * Copyright Google LLC All Rights Reserved.
33699 *
33700 * Use of this source code is governed by an MIT-style license that can be
33701 * found in the LICENSE file at https://angular.io/license
33702 */
33703 /**
33704 * Creates the root component view and the root component node.
33705 *
33706 * @param rNode Render host element.
33707 * @param def ComponentDef
33708 * @param rootView The parent view where the host node is stored
33709 * @param rendererFactory Factory to be used for creating child renderers.
33710 * @param hostRenderer The current renderer
33711 * @param sanitizer The sanitizer, if provided
33712 *
33713 * @returns Component view created
33714 */
33715 function createRootComponentView(rNode, def, rootView, rendererFactory, hostRenderer, sanitizer) {
33716 const tView = rootView[TVIEW];
33717 const index = HEADER_OFFSET;
33718 ngDevMode && assertIndexInRange(rootView, index);
33719 rootView[index] = rNode;
33720 // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
33721 // the same time we want to communicate the debug `TNode` that this is a special `TNode`
33722 // representing a host element.
33723 const tNode = getOrCreateTNode(tView, index, 2 /* Element */, '#host', null);
33724 const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
33725 if (mergedAttrs !== null) {
33726 computeStaticStyling(tNode, mergedAttrs, true);
33727 if (rNode !== null) {
33728 setUpAttributes(hostRenderer, rNode, mergedAttrs);
33729 if (tNode.classes !== null) {
33730 writeDirectClass(hostRenderer, rNode, tNode.classes);
33731 }
33732 if (tNode.styles !== null) {
33733 writeDirectStyle(hostRenderer, rNode, tNode.styles);
33734 }
33735 }
33736 }
33737 const viewRenderer = rendererFactory.createRenderer(rNode, def);
33738 const componentView = createLView(rootView, getOrCreateTComponentView(def), null, def.onPush ? 64 /* Dirty */ : 16 /* CheckAlways */, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null);
33739 if (tView.firstCreatePass) {
33740 diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, def.type);
33741 markAsComponentHost(tView, tNode);
33742 initTNodeFlags(tNode, rootView.length, 1);
33743 }
33744 addToViewTree(rootView, componentView);
33745 // Store component view at node index, with node as the HOST
33746 return rootView[index] = componentView;
33747 }
33748 /**
33749 * Creates a root component and sets it up with features and host bindings. Shared by
33750 * renderComponent() and ViewContainerRef.createComponent().
33751 */
33752 function createRootComponent(componentView, componentDef, rootLView, rootContext, hostFeatures) {
33753 const tView = rootLView[TVIEW];
33754 // Create directive instance with factory() and store at next index in viewData
33755 const component = instantiateRootComponent(tView, rootLView, componentDef);
33756 rootContext.components.push(component);
33757 componentView[CONTEXT] = component;
33758 hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
33759 // We want to generate an empty QueryList for root content queries for backwards
33760 // compatibility with ViewEngine.
33761 if (componentDef.contentQueries) {
33762 const tNode = getCurrentTNode();
33763 ngDevMode && assertDefined(tNode, 'TNode expected');
33764 componentDef.contentQueries(1 /* Create */, component, tNode.directiveStart);
33765 }
33766 const rootTNode = getCurrentTNode();
33767 ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
33768 if (tView.firstCreatePass &&
33769 (componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) {
33770 setSelectedIndex(rootTNode.index);
33771 const rootTView = rootLView[TVIEW];
33772 registerHostBindingOpCodes(rootTView, rootTNode, rootLView, rootTNode.directiveStart, rootTNode.directiveEnd, componentDef);
33773 invokeHostBindingsInCreationMode(componentDef, component);
33774 }
33775 return component;
33776 }
33777 function createRootContext(scheduler, playerHandler) {
33778 return {
33779 components: [],
33780 scheduler: scheduler || defaultScheduler,
33781 clean: CLEAN_PROMISE,
33782 playerHandler: playerHandler || null,
33783 flags: 0 /* Empty */
33784 };
33785 }
33786 /**
33787 * Used to enable lifecycle hooks on the root component.
33788 *
33789 * Include this feature when calling `renderComponent` if the root component
33790 * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't
33791 * be called properly.
33792 *
33793 * Example:
33794 *
33795 * ```
33796 * renderComponent(AppComponent, {hostFeatures: [LifecycleHooksFeature]});
33797 * ```
33798 */
33799 function LifecycleHooksFeature(component, def) {
33800 const lView = readPatchedLView(component);
33801 ngDevMode && assertDefined(lView, 'LView is required');
33802 const tView = lView[TVIEW];
33803 const tNode = getCurrentTNode();
33804 ngDevMode && assertDefined(tNode, 'TNode is required');
33805 registerPostOrderHooks(tView, tNode);
33806 }
33807
33808 /**
33809 * @license
33810 * Copyright Google LLC All Rights Reserved.
33811 *
33812 * Use of this source code is governed by an MIT-style license that can be
33813 * found in the LICENSE file at https://angular.io/license
33814 */
33815 let _symbolIterator = null;
33816 function getSymbolIterator() {
33817 if (!_symbolIterator) {
33818 const Symbol = _global$1['Symbol'];
33819 if (Symbol && Symbol.iterator) {
33820 _symbolIterator = Symbol.iterator;
33821 }
33822 else {
33823 // es6-shim specific logic
33824 const keys = Object.getOwnPropertyNames(Map.prototype);
33825 for (let i = 0; i < keys.length; ++i) {
33826 const key = keys[i];
33827 if (key !== 'entries' && key !== 'size' &&
33828 Map.prototype[key] === Map.prototype['entries']) {
33829 _symbolIterator = key;
33830 }
33831 }
33832 }
33833 }
33834 return _symbolIterator;
33835 }
33836
33837 /**
33838 * @license
33839 * Copyright Google LLC All Rights Reserved.
33840 *
33841 * Use of this source code is governed by an MIT-style license that can be
33842 * found in the LICENSE file at https://angular.io/license
33843 */
33844 function isListLikeIterable(obj) {
33845 if (!isJsObject(obj))
33846 return false;
33847 return Array.isArray(obj) ||
33848 (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
33849 getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop
33850 }
33851 function iterateListLike(obj, fn) {
33852 if (Array.isArray(obj)) {
33853 for (let i = 0; i < obj.length; i++) {
33854 fn(obj[i]);
33855 }
33856 }
33857 else {
33858 const iterator = obj[getSymbolIterator()]();
33859 let item;
33860 while (!((item = iterator.next()).done)) {
33861 fn(item.value);
33862 }
33863 }
33864 }
33865 function isJsObject(o) {
33866 return o !== null && (typeof o === 'function' || typeof o === 'object');
33867 }
33868
33869 /**
33870 * @license
33871 * Copyright Google LLC All Rights Reserved.
33872 *
33873 * Use of this source code is governed by an MIT-style license that can be
33874 * found in the LICENSE file at https://angular.io/license
33875 */
33876 const ɵ0$6 = getClosureSafeProperty;
33877 const USE_VALUE$3 = getClosureSafeProperty({ provide: String, useValue: ɵ0$6 });
33878
33879 /**
33880 * @license
33881 * Copyright Google LLC All Rights Reserved.
33882 *
33883 * Use of this source code is governed by an MIT-style license that can be
33884 * found in the LICENSE file at https://angular.io/license
33885 */
33886 const ɵ0$7 = getClosureSafeProperty;
33887 const USE_VALUE$4 = getClosureSafeProperty({ provide: String, useValue: ɵ0$7 });
33888 const EMPTY_ARRAY$1 = [];
33889 function convertInjectableProviderToFactory(type, provider) {
33890 if (!provider) {
33891 const reflectionCapabilities = new ReflectionCapabilities();
33892 const deps = reflectionCapabilities.parameters(type);
33893 // TODO - convert to flags.
33894 return () => new type(...injectArgs(deps));
33895 }
33896 if (USE_VALUE$4 in provider) {
33897 const valueProvider = provider;
33898 return () => valueProvider.useValue;
33899 }
33900 else if (provider.useExisting) {
33901 const existingProvider = provider;
33902 return () => ɵɵinject(resolveForwardRef$1(existingProvider.useExisting));
33903 }
33904 else if (provider.useFactory) {
33905 const factoryProvider = provider;
33906 return () => factoryProvider.useFactory(...injectArgs(factoryProvider.deps || EMPTY_ARRAY$1));
33907 }
33908 else if (provider.useClass) {
33909 const classProvider = provider;
33910 let deps = provider.deps;
33911 if (!deps) {
33912 const reflectionCapabilities = new ReflectionCapabilities();
33913 deps = reflectionCapabilities.parameters(type);
33914 }
33915 return () => new (resolveForwardRef$1(classProvider.useClass))(...injectArgs(deps));
33916 }
33917 else {
33918 let deps = provider.deps;
33919 if (!deps) {
33920 const reflectionCapabilities = new ReflectionCapabilities();
33921 deps = reflectionCapabilities.parameters(type);
33922 }
33923 return () => new type(...injectArgs(deps));
33924 }
33925 }
33926
33927 /**
33928 * @license
33929 * Copyright Google LLC All Rights Reserved.
33930 *
33931 * Use of this source code is governed by an MIT-style license that can be
33932 * found in the LICENSE file at https://angular.io/license
33933 */
33934 const ɵ0$8 = (type, meta) => SWITCH_COMPILE_INJECTABLE(type, meta);
33935 /**
33936 * Injectable decorator and metadata.
33937 *
33938 * @Annotation
33939 * @publicApi
33940 */
33941 const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, ɵ0$8);
33942 /**
33943 * Supports @Injectable() in JIT mode for Render2.
33944 */
33945 function render2CompileInjectable(injectableType, options) {
33946 if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) {
33947 injectableType.ɵprov = ɵɵdefineInjectable({
33948 token: injectableType,
33949 providedIn: options.providedIn,
33950 factory: convertInjectableProviderToFactory(injectableType, options),
33951 });
33952 }
33953 }
33954 const SWITCH_COMPILE_INJECTABLE__PRE_R3__ = render2CompileInjectable;
33955 const SWITCH_COMPILE_INJECTABLE = SWITCH_COMPILE_INJECTABLE__PRE_R3__;
33956
33957 /**
33958 * @license
33959 * Copyright Google LLC All Rights Reserved.
33960 *
33961 * Use of this source code is governed by an MIT-style license that can be
33962 * found in the LICENSE file at https://angular.io/license
33963 */
33964 function findFirstClosedCycle(keys) {
33965 const res = [];
33966 for (let i = 0; i < keys.length; ++i) {
33967 if (res.indexOf(keys[i]) > -1) {
33968 res.push(keys[i]);
33969 return res;
33970 }
33971 res.push(keys[i]);
33972 }
33973 return res;
33974 }
33975 function constructResolvingPath(keys) {
33976 if (keys.length > 1) {
33977 const reversed = findFirstClosedCycle(keys.slice().reverse());
33978 const tokenStrs = reversed.map(k => stringify$1(k.token));
33979 return ' (' + tokenStrs.join(' -> ') + ')';
33980 }
33981 return '';
33982 }
33983 function injectionError(injector, key, constructResolvingMessage, originalError) {
33984 const keys = [key];
33985 const errMsg = constructResolvingMessage(keys);
33986 const error = (originalError ? wrappedError(errMsg, originalError) : Error(errMsg));
33987 error.addKey = addKey;
33988 error.keys = keys;
33989 error.injectors = [injector];
33990 error.constructResolvingMessage = constructResolvingMessage;
33991 error[ERROR_ORIGINAL_ERROR] = originalError;
33992 return error;
33993 }
33994 function addKey(injector, key) {
33995 this.injectors.push(injector);
33996 this.keys.push(key);
33997 // Note: This updated message won't be reflected in the `.stack` property
33998 this.message = this.constructResolvingMessage(this.keys);
33999 }
34000 /**
34001 * Thrown when trying to retrieve a dependency by key from {@link Injector}, but the
34002 * {@link Injector} does not have a {@link Provider} for the given key.
34003 *
34004 * @usageNotes
34005 * ### Example
34006 *
34007 * ```typescript
34008 * class A {
34009 * constructor(b:B) {}
34010 * }
34011 *
34012 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
34013 * ```
34014 */
34015 function noProviderError(injector, key) {
34016 return injectionError(injector, key, function (keys) {
34017 const first = stringify$1(keys[0].token);
34018 return `No provider for ${first}!${constructResolvingPath(keys)}`;
34019 });
34020 }
34021 /**
34022 * Thrown when dependencies form a cycle.
34023 *
34024 * @usageNotes
34025 * ### Example
34026 *
34027 * ```typescript
34028 * var injector = Injector.resolveAndCreate([
34029 * {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]},
34030 * {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]}
34031 * ]);
34032 *
34033 * expect(() => injector.get("one")).toThrowError();
34034 * ```
34035 *
34036 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
34037 */
34038 function cyclicDependencyError(injector, key) {
34039 return injectionError(injector, key, function (keys) {
34040 return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
34041 });
34042 }
34043 /**
34044 * Thrown when a constructing type returns with an Error.
34045 *
34046 * The `InstantiationError` class contains the original error plus the dependency graph which caused
34047 * this object to be instantiated.
34048 *
34049 * @usageNotes
34050 * ### Example
34051 *
34052 * ```typescript
34053 * class A {
34054 * constructor() {
34055 * throw new Error('message');
34056 * }
34057 * }
34058 *
34059 * var injector = Injector.resolveAndCreate([A]);
34060
34061 * try {
34062 * injector.get(A);
34063 * } catch (e) {
34064 * expect(e instanceof InstantiationError).toBe(true);
34065 * expect(e.originalException.message).toEqual("message");
34066 * expect(e.originalStack).toBeDefined();
34067 * }
34068 * ```
34069 */
34070 function instantiationError(injector, originalException, originalStack, key) {
34071 return injectionError(injector, key, function (keys) {
34072 const first = stringify$1(keys[0].token);
34073 return `${originalException.message}: Error during instantiation of ${first}!${constructResolvingPath(keys)}.`;
34074 }, originalException);
34075 }
34076 /**
34077 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
34078 * creation.
34079 *
34080 * @usageNotes
34081 * ### Example
34082 *
34083 * ```typescript
34084 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
34085 * ```
34086 */
34087 function invalidProviderError(provider) {
34088 return Error(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
34089 }
34090 /**
34091 * Thrown when the class has no annotation information.
34092 *
34093 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
34094 * need to be injected into the constructor.
34095 *
34096 * @usageNotes
34097 * ### Example
34098 *
34099 * ```typescript
34100 * class A {
34101 * constructor(b) {}
34102 * }
34103 *
34104 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
34105 * ```
34106 *
34107 * This error is also thrown when the class not marked with {@link Injectable} has parameter types.
34108 *
34109 * ```typescript
34110 * class B {}
34111 *
34112 * class A {
34113 * constructor(b:B) {} // no information about the parameter types of A is available at runtime.
34114 * }
34115 *
34116 * expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
34117 * ```
34118 *
34119 */
34120 function noAnnotationError(typeOrFunc, params) {
34121 const signature = [];
34122 for (let i = 0, ii = params.length; i < ii; i++) {
34123 const parameter = params[i];
34124 if (!parameter || parameter.length == 0) {
34125 signature.push('?');
34126 }
34127 else {
34128 signature.push(parameter.map(stringify$1).join(' '));
34129 }
34130 }
34131 return Error('Cannot resolve all parameters for \'' + stringify$1(typeOrFunc) + '\'(' +
34132 signature.join(', ') + '). ' +
34133 'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
34134 stringify$1(typeOrFunc) + '\' is decorated with Injectable.');
34135 }
34136 /**
34137 * Thrown when getting an object by index.
34138 *
34139 * @usageNotes
34140 * ### Example
34141 *
34142 * ```typescript
34143 * class A {}
34144 *
34145 * var injector = Injector.resolveAndCreate([A]);
34146 *
34147 * expect(() => injector.getAt(100)).toThrowError();
34148 * ```
34149 *
34150 */
34151 function outOfBoundsError(index) {
34152 return Error(`Index ${index} is out-of-bounds.`);
34153 }
34154 // TODO: add a working example after alpha38 is released
34155 /**
34156 * Thrown when a multi provider and a regular provider are bound to the same token.
34157 *
34158 * @usageNotes
34159 * ### Example
34160 *
34161 * ```typescript
34162 * expect(() => Injector.resolveAndCreate([
34163 * { provide: "Strings", useValue: "string1", multi: true},
34164 * { provide: "Strings", useValue: "string2", multi: false}
34165 * ])).toThrowError();
34166 * ```
34167 */
34168 function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) {
34169 return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
34170 }
34171
34172 /**
34173 * @license
34174 * Copyright Google LLC All Rights Reserved.
34175 *
34176 * Use of this source code is governed by an MIT-style license that can be
34177 * found in the LICENSE file at https://angular.io/license
34178 */
34179 /**
34180 * A unique object used for retrieving items from the {@link ReflectiveInjector}.
34181 *
34182 * Keys have:
34183 * - a system-wide unique `id`.
34184 * - a `token`.
34185 *
34186 * `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
34187 * the
34188 * injector to store created objects in a more efficient way.
34189 *
34190 * `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
34191 * resolving
34192 * providers.
34193 *
34194 * @deprecated No replacement
34195 * @publicApi
34196 */
34197 class ReflectiveKey {
34198 /**
34199 * Private
34200 */
34201 constructor(token, id) {
34202 this.token = token;
34203 this.id = id;
34204 if (!token) {
34205 throw new Error('Token must be defined!');
34206 }
34207 this.displayName = stringify$1(this.token);
34208 }
34209 /**
34210 * Retrieves a `Key` for a token.
34211 */
34212 static get(token) {
34213 return _globalKeyRegistry.get(resolveForwardRef$1(token));
34214 }
34215 /**
34216 * @returns the number of keys registered in the system.
34217 */
34218 static get numberOfKeys() {
34219 return _globalKeyRegistry.numberOfKeys;
34220 }
34221 }
34222 class KeyRegistry {
34223 constructor() {
34224 this._allKeys = new Map();
34225 }
34226 get(token) {
34227 if (token instanceof ReflectiveKey)
34228 return token;
34229 if (this._allKeys.has(token)) {
34230 return this._allKeys.get(token);
34231 }
34232 const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
34233 this._allKeys.set(token, newKey);
34234 return newKey;
34235 }
34236 get numberOfKeys() {
34237 return this._allKeys.size;
34238 }
34239 }
34240 const _globalKeyRegistry = new KeyRegistry();
34241
34242 /**
34243 * @license
34244 * Copyright Google LLC All Rights Reserved.
34245 *
34246 * Use of this source code is governed by an MIT-style license that can be
34247 * found in the LICENSE file at https://angular.io/license
34248 */
34249 /**
34250 * Provides access to reflection data about symbols. Used internally by Angular
34251 * to power dependency injection and compilation.
34252 */
34253 class Reflector {
34254 constructor(reflectionCapabilities) {
34255 this.reflectionCapabilities = reflectionCapabilities;
34256 }
34257 updateCapabilities(caps) {
34258 this.reflectionCapabilities = caps;
34259 }
34260 factory(type) {
34261 return this.reflectionCapabilities.factory(type);
34262 }
34263 parameters(typeOrFunc) {
34264 return this.reflectionCapabilities.parameters(typeOrFunc);
34265 }
34266 annotations(typeOrFunc) {
34267 return this.reflectionCapabilities.annotations(typeOrFunc);
34268 }
34269 propMetadata(typeOrFunc) {
34270 return this.reflectionCapabilities.propMetadata(typeOrFunc);
34271 }
34272 hasLifecycleHook(type, lcProperty) {
34273 return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
34274 }
34275 getter(name) {
34276 return this.reflectionCapabilities.getter(name);
34277 }
34278 setter(name) {
34279 return this.reflectionCapabilities.setter(name);
34280 }
34281 method(name) {
34282 return this.reflectionCapabilities.method(name);
34283 }
34284 importUri(type) {
34285 return this.reflectionCapabilities.importUri(type);
34286 }
34287 resourceUri(type) {
34288 return this.reflectionCapabilities.resourceUri(type);
34289 }
34290 resolveIdentifier(name, moduleUrl, members, runtime) {
34291 return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime);
34292 }
34293 resolveEnum(identifier, name) {
34294 return this.reflectionCapabilities.resolveEnum(identifier, name);
34295 }
34296 }
34297
34298 /**
34299 * @license
34300 * Copyright Google LLC All Rights Reserved.
34301 *
34302 * Use of this source code is governed by an MIT-style license that can be
34303 * found in the LICENSE file at https://angular.io/license
34304 */
34305 /**
34306 * The {@link Reflector} used internally in Angular to access metadata
34307 * about symbols.
34308 */
34309 const reflector = new Reflector(new ReflectionCapabilities());
34310
34311 /**
34312 * @license
34313 * Copyright Google LLC All Rights Reserved.
34314 *
34315 * Use of this source code is governed by an MIT-style license that can be
34316 * found in the LICENSE file at https://angular.io/license
34317 */
34318 /**
34319 * `Dependency` is used by the framework to extend DI.
34320 * This is internal to Angular and should not be used directly.
34321 */
34322 class ReflectiveDependency {
34323 constructor(key, optional, visibility) {
34324 this.key = key;
34325 this.optional = optional;
34326 this.visibility = visibility;
34327 }
34328 static fromKey(key) {
34329 return new ReflectiveDependency(key, false, null);
34330 }
34331 }
34332 const _EMPTY_LIST = [];
34333 class ResolvedReflectiveProvider_ {
34334 constructor(key, resolvedFactories, multiProvider) {
34335 this.key = key;
34336 this.resolvedFactories = resolvedFactories;
34337 this.multiProvider = multiProvider;
34338 this.resolvedFactory = this.resolvedFactories[0];
34339 }
34340 }
34341 /**
34342 * An internal resolved representation of a factory function created by resolving `Provider`.
34343 * @publicApi
34344 */
34345 class ResolvedReflectiveFactory {
34346 constructor(
34347 /**
34348 * Factory function which can return an instance of an object represented by a key.
34349 */
34350 factory,
34351 /**
34352 * Arguments (dependencies) to the `factory` function.
34353 */
34354 dependencies) {
34355 this.factory = factory;
34356 this.dependencies = dependencies;
34357 }
34358 }
34359 /**
34360 * Resolve a single provider.
34361 */
34362 function resolveReflectiveFactory(provider) {
34363 let factoryFn;
34364 let resolvedDeps;
34365 if (provider.useClass) {
34366 const useClass = resolveForwardRef$1(provider.useClass);
34367 factoryFn = reflector.factory(useClass);
34368 resolvedDeps = _dependenciesFor(useClass);
34369 }
34370 else if (provider.useExisting) {
34371 factoryFn = (aliasInstance) => aliasInstance;
34372 resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
34373 }
34374 else if (provider.useFactory) {
34375 factoryFn = provider.useFactory;
34376 resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
34377 }
34378 else {
34379 factoryFn = () => provider.useValue;
34380 resolvedDeps = _EMPTY_LIST;
34381 }
34382 return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
34383 }
34384 /**
34385 * Converts the `Provider` into `ResolvedProvider`.
34386 *
34387 * `Injector` internally only uses `ResolvedProvider`, `Provider` contains convenience provider
34388 * syntax.
34389 */
34390 function resolveReflectiveProvider(provider) {
34391 return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false);
34392 }
34393 /**
34394 * Resolve a list of Providers.
34395 */
34396 function resolveReflectiveProviders(providers) {
34397 const normalized = _normalizeProviders(providers, []);
34398 const resolved = normalized.map(resolveReflectiveProvider);
34399 const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
34400 return Array.from(resolvedProviderMap.values());
34401 }
34402 /**
34403 * Merges a list of ResolvedProviders into a list where each key is contained exactly once and
34404 * multi providers have been merged.
34405 */
34406 function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) {
34407 for (let i = 0; i < providers.length; i++) {
34408 const provider = providers[i];
34409 const existing = normalizedProvidersMap.get(provider.key.id);
34410 if (existing) {
34411 if (provider.multiProvider !== existing.multiProvider) {
34412 throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
34413 }
34414 if (provider.multiProvider) {
34415 for (let j = 0; j < provider.resolvedFactories.length; j++) {
34416 existing.resolvedFactories.push(provider.resolvedFactories[j]);
34417 }
34418 }
34419 else {
34420 normalizedProvidersMap.set(provider.key.id, provider);
34421 }
34422 }
34423 else {
34424 let resolvedProvider;
34425 if (provider.multiProvider) {
34426 resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider);
34427 }
34428 else {
34429 resolvedProvider = provider;
34430 }
34431 normalizedProvidersMap.set(provider.key.id, resolvedProvider);
34432 }
34433 }
34434 return normalizedProvidersMap;
34435 }
34436 function _normalizeProviders(providers, res) {
34437 providers.forEach(b => {
34438 if (b instanceof Type$2) {
34439 res.push({ provide: b, useClass: b });
34440 }
34441 else if (b && typeof b == 'object' && b.provide !== undefined) {
34442 res.push(b);
34443 }
34444 else if (Array.isArray(b)) {
34445 _normalizeProviders(b, res);
34446 }
34447 else {
34448 throw invalidProviderError(b);
34449 }
34450 });
34451 return res;
34452 }
34453 function constructDependencies(typeOrFunc, dependencies) {
34454 if (!dependencies) {
34455 return _dependenciesFor(typeOrFunc);
34456 }
34457 else {
34458 const params = dependencies.map(t => [t]);
34459 return dependencies.map(t => _extractToken(typeOrFunc, t, params));
34460 }
34461 }
34462 function _dependenciesFor(typeOrFunc) {
34463 const params = reflector.parameters(typeOrFunc);
34464 if (!params)
34465 return [];
34466 if (params.some(p => p == null)) {
34467 throw noAnnotationError(typeOrFunc, params);
34468 }
34469 return params.map(p => _extractToken(typeOrFunc, p, params));
34470 }
34471 function _extractToken(typeOrFunc, metadata, params) {
34472 let token = null;
34473 let optional = false;
34474 if (!Array.isArray(metadata)) {
34475 if (metadata instanceof Inject) {
34476 return _createDependency(metadata.token, optional, null);
34477 }
34478 else {
34479 return _createDependency(metadata, optional, null);
34480 }
34481 }
34482 let visibility = null;
34483 for (let i = 0; i < metadata.length; ++i) {
34484 const paramMetadata = metadata[i];
34485 if (paramMetadata instanceof Type$2) {
34486 token = paramMetadata;
34487 }
34488 else if (paramMetadata instanceof Inject) {
34489 token = paramMetadata.token;
34490 }
34491 else if (paramMetadata instanceof Optional) {
34492 optional = true;
34493 }
34494 else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
34495 visibility = paramMetadata;
34496 }
34497 else if (paramMetadata instanceof InjectionToken) {
34498 token = paramMetadata;
34499 }
34500 }
34501 token = resolveForwardRef$1(token);
34502 if (token != null) {
34503 return _createDependency(token, optional, visibility);
34504 }
34505 else {
34506 throw noAnnotationError(typeOrFunc, params);
34507 }
34508 }
34509 function _createDependency(token, optional, visibility) {
34510 return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
34511 }
34512
34513 /**
34514 * @license
34515 * Copyright Google LLC All Rights Reserved.
34516 *
34517 * Use of this source code is governed by an MIT-style license that can be
34518 * found in the LICENSE file at https://angular.io/license
34519 */
34520 // Threshold for the dynamic version
34521 const UNDEFINED = {};
34522 /**
34523 * A ReflectiveDependency injection container used for instantiating objects and resolving
34524 * dependencies.
34525 *
34526 * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
34527 * constructor dependencies.
34528 *
34529 * In typical use, application code asks for the dependencies in the constructor and they are
34530 * resolved by the `Injector`.
34531 *
34532 * @usageNotes
34533 * ### Example
34534 *
34535 * The following example creates an `Injector` configured to create `Engine` and `Car`.
34536 *
34537 * ```typescript
34538 * @Injectable()
34539 * class Engine {
34540 * }
34541 *
34542 * @Injectable()
34543 * class Car {
34544 * constructor(public engine:Engine) {}
34545 * }
34546 *
34547 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
34548 * var car = injector.get(Car);
34549 * expect(car instanceof Car).toBe(true);
34550 * expect(car.engine instanceof Engine).toBe(true);
34551 * ```
34552 *
34553 * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
34554 * resolve all of the object's dependencies automatically.
34555 *
34556 * @deprecated from v5 - slow and brings in a lot of code, Use `Injector.create` instead.
34557 * @publicApi
34558 */
34559 class ReflectiveInjector {
34560 /**
34561 * Turns an array of provider definitions into an array of resolved providers.
34562 *
34563 * A resolution is a process of flattening multiple nested arrays and converting individual
34564 * providers into an array of `ResolvedReflectiveProvider`s.
34565 *
34566 * @usageNotes
34567 * ### Example
34568 *
34569 * ```typescript
34570 * @Injectable()
34571 * class Engine {
34572 * }
34573 *
34574 * @Injectable()
34575 * class Car {
34576 * constructor(public engine:Engine) {}
34577 * }
34578 *
34579 * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
34580 *
34581 * expect(providers.length).toEqual(2);
34582 *
34583 * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
34584 * expect(providers[0].key.displayName).toBe("Car");
34585 * expect(providers[0].dependencies.length).toEqual(1);
34586 * expect(providers[0].factory).toBeDefined();
34587 *
34588 * expect(providers[1].key.displayName).toBe("Engine");
34589 * });
34590 * ```
34591 *
34592 */
34593 static resolve(providers) {
34594 return resolveReflectiveProviders(providers);
34595 }
34596 /**
34597 * Resolves an array of providers and creates an injector from those providers.
34598 *
34599 * The passed-in providers can be an array of `Type`, `Provider`,
34600 * or a recursive array of more providers.
34601 *
34602 * @usageNotes
34603 * ### Example
34604 *
34605 * ```typescript
34606 * @Injectable()
34607 * class Engine {
34608 * }
34609 *
34610 * @Injectable()
34611 * class Car {
34612 * constructor(public engine:Engine) {}
34613 * }
34614 *
34615 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
34616 * expect(injector.get(Car) instanceof Car).toBe(true);
34617 * ```
34618 */
34619 static resolveAndCreate(providers, parent) {
34620 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
34621 return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
34622 }
34623 /**
34624 * Creates an injector from previously resolved providers.
34625 *
34626 * This API is the recommended way to construct injectors in performance-sensitive parts.
34627 *
34628 * @usageNotes
34629 * ### Example
34630 *
34631 * ```typescript
34632 * @Injectable()
34633 * class Engine {
34634 * }
34635 *
34636 * @Injectable()
34637 * class Car {
34638 * constructor(public engine:Engine) {}
34639 * }
34640 *
34641 * var providers = ReflectiveInjector.resolve([Car, Engine]);
34642 * var injector = ReflectiveInjector.fromResolvedProviders(providers);
34643 * expect(injector.get(Car) instanceof Car).toBe(true);
34644 * ```
34645 */
34646 static fromResolvedProviders(providers, parent) {
34647 return new ReflectiveInjector_(providers, parent);
34648 }
34649 }
34650 class ReflectiveInjector_ {
34651 /**
34652 * Private
34653 */
34654 constructor(_providers, _parent) {
34655 /** @internal */
34656 this._constructionCounter = 0;
34657 this._providers = _providers;
34658 this.parent = _parent || null;
34659 const len = _providers.length;
34660 this.keyIds = [];
34661 this.objs = [];
34662 for (let i = 0; i < len; i++) {
34663 this.keyIds[i] = _providers[i].key.id;
34664 this.objs[i] = UNDEFINED;
34665 }
34666 }
34667 get(token, notFoundValue = THROW_IF_NOT_FOUND) {
34668 return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
34669 }
34670 resolveAndCreateChild(providers) {
34671 const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
34672 return this.createChildFromResolved(ResolvedReflectiveProviders);
34673 }
34674 createChildFromResolved(providers) {
34675 const inj = new ReflectiveInjector_(providers);
34676 inj.parent = this;
34677 return inj;
34678 }
34679 resolveAndInstantiate(provider) {
34680 return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
34681 }
34682 instantiateResolved(provider) {
34683 return this._instantiateProvider(provider);
34684 }
34685 getProviderAtIndex(index) {
34686 if (index < 0 || index >= this._providers.length) {
34687 throw outOfBoundsError(index);
34688 }
34689 return this._providers[index];
34690 }
34691 /** @internal */
34692 _new(provider) {
34693 if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
34694 throw cyclicDependencyError(this, provider.key);
34695 }
34696 return this._instantiateProvider(provider);
34697 }
34698 _getMaxNumberOfObjects() {
34699 return this.objs.length;
34700 }
34701 _instantiateProvider(provider) {
34702 if (provider.multiProvider) {
34703 const res = [];
34704 for (let i = 0; i < provider.resolvedFactories.length; ++i) {
34705 res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
34706 }
34707 return res;
34708 }
34709 else {
34710 return this._instantiate(provider, provider.resolvedFactories[0]);
34711 }
34712 }
34713 _instantiate(provider, ResolvedReflectiveFactory) {
34714 const factory = ResolvedReflectiveFactory.factory;
34715 let deps;
34716 try {
34717 deps =
34718 ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
34719 }
34720 catch (e) {
34721 if (e.addKey) {
34722 e.addKey(this, provider.key);
34723 }
34724 throw e;
34725 }
34726 let obj;
34727 try {
34728 obj = factory(...deps);
34729 }
34730 catch (e) {
34731 throw instantiationError(this, e, e.stack, provider.key);
34732 }
34733 return obj;
34734 }
34735 _getByReflectiveDependency(dep) {
34736 return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
34737 }
34738 _getByKey(key, visibility, notFoundValue) {
34739 if (key === ReflectiveInjector_.INJECTOR_KEY) {
34740 return this;
34741 }
34742 if (visibility instanceof Self) {
34743 return this._getByKeySelf(key, notFoundValue);
34744 }
34745 else {
34746 return this._getByKeyDefault(key, notFoundValue, visibility);
34747 }
34748 }
34749 _getObjByKeyId(keyId) {
34750 for (let i = 0; i < this.keyIds.length; i++) {
34751 if (this.keyIds[i] === keyId) {
34752 if (this.objs[i] === UNDEFINED) {
34753 this.objs[i] = this._new(this._providers[i]);
34754 }
34755 return this.objs[i];
34756 }
34757 }
34758 return UNDEFINED;
34759 }
34760 /** @internal */
34761 _throwOrNull(key, notFoundValue) {
34762 if (notFoundValue !== THROW_IF_NOT_FOUND) {
34763 return notFoundValue;
34764 }
34765 else {
34766 throw noProviderError(this, key);
34767 }
34768 }
34769 /** @internal */
34770 _getByKeySelf(key, notFoundValue) {
34771 const obj = this._getObjByKeyId(key.id);
34772 return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
34773 }
34774 /** @internal */
34775 _getByKeyDefault(key, notFoundValue, visibility) {
34776 let inj;
34777 if (visibility instanceof SkipSelf) {
34778 inj = this.parent;
34779 }
34780 else {
34781 inj = this;
34782 }
34783 while (inj instanceof ReflectiveInjector_) {
34784 const inj_ = inj;
34785 const obj = inj_._getObjByKeyId(key.id);
34786 if (obj !== UNDEFINED)
34787 return obj;
34788 inj = inj_.parent;
34789 }
34790 if (inj !== null) {
34791 return inj.get(key.token, notFoundValue);
34792 }
34793 else {
34794 return this._throwOrNull(key, notFoundValue);
34795 }
34796 }
34797 get displayName() {
34798 const providers = _mapProviders(this, (b) => ' "' + b.key.displayName + '" ')
34799 .join(', ');
34800 return `ReflectiveInjector(providers: [${providers}])`;
34801 }
34802 toString() {
34803 return this.displayName;
34804 }
34805 }
34806 ReflectiveInjector_.INJECTOR_KEY = ReflectiveKey.get(Injector);
34807 function _mapProviders(injector, fn) {
34808 const res = [];
34809 for (let i = 0; i < injector._providers.length; ++i) {
34810 res[i] = fn(injector.getProviderAtIndex(i));
34811 }
34812 return res;
34813 }
34814
34815 /**
34816 * @license
34817 * Copyright Google LLC All Rights Reserved.
34818 *
34819 * Use of this source code is governed by an MIT-style license that can be
34820 * found in the LICENSE file at https://angular.io/license
34821 */
34822 /**
34823 * Determine if the argument is shaped like a Promise
34824 */
34825 function isPromise$1(obj) {
34826 // allow any Promise/A+ compliant thenable.
34827 // It's up to the caller to ensure that obj.then conforms to the spec
34828 return !!obj && typeof obj.then === 'function';
34829 }
34830
34831 /**
34832 * @license
34833 * Copyright Google LLC All Rights Reserved.
34834 *
34835 * Use of this source code is governed by an MIT-style license that can be
34836 * found in the LICENSE file at https://angular.io/license
34837 */
34838 /**
34839 * This file contains reuseable "empty" symbols that can be used as default return values
34840 * in different parts of the rendering code. Because the same symbols are returned, this
34841 * allows for identity checks against these values to be consistently used by the framework
34842 * code.
34843 */
34844 const EMPTY_OBJ$1 = {};
34845 const EMPTY_ARRAY$2 = [];
34846 // freezing the values prevents any code from accidentally inserting new values in
34847 if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) {
34848 // These property accesses can be ignored because ngDevMode will be set to false
34849 // when optimizing code and the whole if statement will be dropped.
34850 // tslint:disable-next-line:no-toplevel-property-access
34851 Object.freeze(EMPTY_OBJ$1);
34852 // tslint:disable-next-line:no-toplevel-property-access
34853 Object.freeze(EMPTY_ARRAY$2);
34854 }
34855
34856 /**
34857 * @license
34858 * Copyright Google LLC All Rights Reserved.
34859 *
34860 * Use of this source code is governed by an MIT-style license that can be
34861 * found in the LICENSE file at https://angular.io/license
34862 */
34863 /**
34864 * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
34865 */
34866 if (typeof ngI18nClosureMode === 'undefined') {
34867 // These property accesses can be ignored because ngI18nClosureMode will be set to false
34868 // when optimizing code and the whole if statement will be dropped.
34869 // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
34870 // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
34871 (function () {
34872 // tslint:disable-next-line:no-toplevel-property-access
34873 _global$1['ngI18nClosureMode'] =
34874 // TODO(FW-1250): validate that this actually, you know, works.
34875 // tslint:disable-next-line:no-toplevel-property-access
34876 typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
34877 })();
34878 }
34879
34880 /**
34881 * @license
34882 * Copyright Google LLC All Rights Reserved.
34883 *
34884 * Use of this source code is governed by an MIT-style license that can be
34885 * found in the LICENSE file at https://angular.io/license
34886 */
34887 /**
34888 * Index of each type of locale data from the locale data array
34889 */
34890 var LocaleDataIndex;
34891 (function (LocaleDataIndex) {
34892 LocaleDataIndex[LocaleDataIndex["LocaleId"] = 0] = "LocaleId";
34893 LocaleDataIndex[LocaleDataIndex["DayPeriodsFormat"] = 1] = "DayPeriodsFormat";
34894 LocaleDataIndex[LocaleDataIndex["DayPeriodsStandalone"] = 2] = "DayPeriodsStandalone";
34895 LocaleDataIndex[LocaleDataIndex["DaysFormat"] = 3] = "DaysFormat";
34896 LocaleDataIndex[LocaleDataIndex["DaysStandalone"] = 4] = "DaysStandalone";
34897 LocaleDataIndex[LocaleDataIndex["MonthsFormat"] = 5] = "MonthsFormat";
34898 LocaleDataIndex[LocaleDataIndex["MonthsStandalone"] = 6] = "MonthsStandalone";
34899 LocaleDataIndex[LocaleDataIndex["Eras"] = 7] = "Eras";
34900 LocaleDataIndex[LocaleDataIndex["FirstDayOfWeek"] = 8] = "FirstDayOfWeek";
34901 LocaleDataIndex[LocaleDataIndex["WeekendRange"] = 9] = "WeekendRange";
34902 LocaleDataIndex[LocaleDataIndex["DateFormat"] = 10] = "DateFormat";
34903 LocaleDataIndex[LocaleDataIndex["TimeFormat"] = 11] = "TimeFormat";
34904 LocaleDataIndex[LocaleDataIndex["DateTimeFormat"] = 12] = "DateTimeFormat";
34905 LocaleDataIndex[LocaleDataIndex["NumberSymbols"] = 13] = "NumberSymbols";
34906 LocaleDataIndex[LocaleDataIndex["NumberFormats"] = 14] = "NumberFormats";
34907 LocaleDataIndex[LocaleDataIndex["CurrencyCode"] = 15] = "CurrencyCode";
34908 LocaleDataIndex[LocaleDataIndex["CurrencySymbol"] = 16] = "CurrencySymbol";
34909 LocaleDataIndex[LocaleDataIndex["CurrencyName"] = 17] = "CurrencyName";
34910 LocaleDataIndex[LocaleDataIndex["Currencies"] = 18] = "Currencies";
34911 LocaleDataIndex[LocaleDataIndex["Directionality"] = 19] = "Directionality";
34912 LocaleDataIndex[LocaleDataIndex["PluralCase"] = 20] = "PluralCase";
34913 LocaleDataIndex[LocaleDataIndex["ExtraData"] = 21] = "ExtraData";
34914 })(LocaleDataIndex || (LocaleDataIndex = {}));
34915
34916 /**
34917 * @license
34918 * Copyright Google LLC All Rights Reserved.
34919 *
34920 * Use of this source code is governed by an MIT-style license that can be
34921 * found in the LICENSE file at https://angular.io/license
34922 */
34923 /**
34924 * The locale id that the application is using by default (for translations and ICU expressions).
34925 */
34926 const DEFAULT_LOCALE_ID = 'en-US';
34927 /**
34928 * USD currency code that the application uses by default for CurrencyPipe when no
34929 * DEFAULT_CURRENCY_CODE is provided.
34930 */
34931 const USD_CURRENCY_CODE = 'USD';
34932
34933 /**
34934 * @license
34935 * Copyright Google LLC All Rights Reserved.
34936 *
34937 * Use of this source code is governed by an MIT-style license that can be
34938 * found in the LICENSE file at https://angular.io/license
34939 */
34940 /**
34941 * See `I18nCreateOpCodes`
34942 */
34943 var I18nCreateOpCode;
34944 (function (I18nCreateOpCode) {
34945 /**
34946 * Number of bits to shift index so that it can be combined with the `APPEND_EAGERLY` and
34947 * `COMMENT`.
34948 */
34949 I18nCreateOpCode[I18nCreateOpCode["SHIFT"] = 2] = "SHIFT";
34950 /**
34951 * Should the node be appended to parent imedditatly after creation.
34952 */
34953 I18nCreateOpCode[I18nCreateOpCode["APPEND_EAGERLY"] = 1] = "APPEND_EAGERLY";
34954 /**
34955 * If set the node should be comment (rather than a text) node.
34956 */
34957 I18nCreateOpCode[I18nCreateOpCode["COMMENT"] = 2] = "COMMENT";
34958 })(I18nCreateOpCode || (I18nCreateOpCode = {}));
34959
34960 /**
34961 * @license
34962 * Copyright Google LLC All Rights Reserved.
34963 *
34964 * Use of this source code is governed by an MIT-style license that can be
34965 * found in the LICENSE file at https://angular.io/license
34966 */
34967 /**
34968 * The locale id that the application is currently using (for translations and ICU expressions).
34969 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
34970 * but is now defined as a global value.
34971 */
34972 let LOCALE_ID = DEFAULT_LOCALE_ID;
34973 /**
34974 * Sets the locale id that will be used for translations and ICU expressions.
34975 * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
34976 * but is now defined as a global value.
34977 *
34978 * @param localeId
34979 */
34980 function setLocaleId(localeId) {
34981 assertDefined(localeId, `Expected localeId to be defined`);
34982 if (typeof localeId === 'string') {
34983 LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
34984 }
34985 }
34986
34987 /**
34988 * @license
34989 * Copyright Google LLC All Rights Reserved.
34990 *
34991 * Use of this source code is governed by an MIT-style license that can be
34992 * found in the LICENSE file at https://angular.io/license
34993 */
34994 /**
34995 * Represents a component created by a `ComponentFactory`.
34996 * Provides access to the component instance and related objects,
34997 * and provides the means of destroying the instance.
34998 *
34999 * @publicApi
35000 */
35001 class ComponentRef {
35002 }
35003 /**
35004 * Base class for a factory that can create a component dynamically.
35005 * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
35006 * Use the resulting `ComponentFactory.create()` method to create a component of that type.
35007 *
35008 * @see [Dynamic Components](guide/dynamic-component-loader)
35009 *
35010 * @publicApi
35011 */
35012 class ComponentFactory {
35013 }
35014
35015 /**
35016 * @license
35017 * Copyright Google LLC All Rights Reserved.
35018 *
35019 * Use of this source code is governed by an MIT-style license that can be
35020 * found in the LICENSE file at https://angular.io/license
35021 */
35022 function noComponentFactoryError(component) {
35023 const error = Error(`No component factory found for ${stringify$1(component)}. Did you add it to @NgModule.entryComponents?`);
35024 error[ERROR_COMPONENT] = component;
35025 return error;
35026 }
35027 const ERROR_COMPONENT = 'ngComponent';
35028 class _NullComponentFactoryResolver {
35029 resolveComponentFactory(component) {
35030 throw noComponentFactoryError(component);
35031 }
35032 }
35033 /**
35034 * A simple registry that maps `Components` to generated `ComponentFactory` classes
35035 * that can be used to create instances of components.
35036 * Use to obtain the factory for a given component type,
35037 * then use the factory's `create()` method to create a component of that type.
35038 *
35039 * @see [Dynamic Components](guide/dynamic-component-loader)
35040 * @publicApi
35041 */
35042 class ComponentFactoryResolver {
35043 }
35044 ComponentFactoryResolver.NULL = new _NullComponentFactoryResolver();
35045 class ComponentFactoryBoundToModule extends ComponentFactory {
35046 constructor(factory, ngModule) {
35047 super();
35048 this.factory = factory;
35049 this.ngModule = ngModule;
35050 this.selector = factory.selector;
35051 this.componentType = factory.componentType;
35052 this.ngContentSelectors = factory.ngContentSelectors;
35053 this.inputs = factory.inputs;
35054 this.outputs = factory.outputs;
35055 }
35056 create(injector, projectableNodes, rootSelectorOrNode, ngModule) {
35057 return this.factory.create(injector, projectableNodes, rootSelectorOrNode, ngModule || this.ngModule);
35058 }
35059 }
35060
35061 /**
35062 * @license
35063 * Copyright Google LLC All Rights Reserved.
35064 *
35065 * Use of this source code is governed by an MIT-style license that can be
35066 * found in the LICENSE file at https://angular.io/license
35067 */
35068 function noop(...args) {
35069 // Do nothing.
35070 }
35071
35072 /**
35073 * @license
35074 * Copyright Google LLC All Rights Reserved.
35075 *
35076 * Use of this source code is governed by an MIT-style license that can be
35077 * found in the LICENSE file at https://angular.io/license
35078 */
35079 /**
35080 * Creates an ElementRef given a node.
35081 *
35082 * @param tNode The node for which you'd like an ElementRef
35083 * @param lView The view to which the node belongs
35084 * @returns The ElementRef instance to use
35085 */
35086 function createElementRef(tNode, lView) {
35087 return new ElementRef(getNativeByTNode(tNode, lView));
35088 }
35089 const SWITCH_ELEMENT_REF_FACTORY__PRE_R3__ = noop;
35090 const SWITCH_ELEMENT_REF_FACTORY = SWITCH_ELEMENT_REF_FACTORY__PRE_R3__;
35091 /**
35092 * A wrapper around a native element inside of a View.
35093 *
35094 * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
35095 * element.
35096 *
35097 * @security Permitting direct access to the DOM can make your application more vulnerable to
35098 * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
35099 * [Security Guide](https://g.co/ng/security).
35100 *
35101 * @publicApi
35102 */
35103 // Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
35104 // i.e. users have to ask for what they need. With that, we can build better analysis tools
35105 // and could do better codegen in the future.
35106 class ElementRef {
35107 constructor(nativeElement) {
35108 this.nativeElement = nativeElement;
35109 }
35110 }
35111 /**
35112 * @internal
35113 * @nocollapse
35114 */
35115 ElementRef.__NG_ELEMENT_ID__ = SWITCH_ELEMENT_REF_FACTORY;
35116
35117 /**
35118 * @license
35119 * Copyright Google LLC All Rights Reserved.
35120 *
35121 * Use of this source code is governed by an MIT-style license that can be
35122 * found in the LICENSE file at https://angular.io/license
35123 */
35124 const Renderer2Interceptor = new InjectionToken('Renderer2Interceptor');
35125 /**
35126 * Creates and initializes a custom renderer that implements the `Renderer2` base class.
35127 *
35128 * @publicApi
35129 */
35130 class RendererFactory2 {
35131 }
35132 /**
35133 * Extend this base class to implement custom rendering. By default, Angular
35134 * renders a template into DOM. You can use custom rendering to intercept
35135 * rendering calls, or to render to something other than DOM.
35136 *
35137 * Create your custom renderer using `RendererFactory2`.
35138 *
35139 * Use a custom renderer to bypass Angular's templating and
35140 * make custom UI changes that can't be expressed declaratively.
35141 * For example if you need to set a property or an attribute whose name is
35142 * not statically known, use the `setProperty()` or
35143 * `setAttribute()` method.
35144 *
35145 * @publicApi
35146 */
35147 class Renderer2 {
35148 }
35149 /**
35150 * @internal
35151 * @nocollapse
35152 */
35153 Renderer2.__NG_ELEMENT_ID__ = () => SWITCH_RENDERER2_FACTORY();
35154 const SWITCH_RENDERER2_FACTORY__PRE_R3__ = noop;
35155 const SWITCH_RENDERER2_FACTORY = SWITCH_RENDERER2_FACTORY__PRE_R3__;
35156
35157 /**
35158 * @license
35159 * Copyright Google LLC All Rights Reserved.
35160 *
35161 * Use of this source code is governed by an MIT-style license that can be
35162 * found in the LICENSE file at https://angular.io/license
35163 */
35164 /**
35165 * Sanitizer is used by the views to sanitize potentially dangerous values.
35166 *
35167 * @publicApi
35168 */
35169 class Sanitizer {
35170 }
35171 /** @nocollapse */
35172 Sanitizer.ɵprov = ɵɵdefineInjectable({
35173 token: Sanitizer,
35174 providedIn: 'root',
35175 factory: () => null,
35176 });
35177
35178 /**
35179 * @license
35180 * Copyright Google LLC All Rights Reserved.
35181 *
35182 * Use of this source code is governed by an MIT-style license that can be
35183 * found in the LICENSE file at https://angular.io/license
35184 */
35185 /**
35186 * @description Represents the version of Angular
35187 *
35188 * @publicApi
35189 */
35190 class Version$1 {
35191 constructor(full) {
35192 this.full = full;
35193 this.major = full.split('.')[0];
35194 this.minor = full.split('.')[1];
35195 this.patch = full.split('.').slice(2).join('.');
35196 }
35197 }
35198 /**
35199 * @publicApi
35200 */
35201 const VERSION$2 = new Version$1('11.2.4');
35202
35203 /**
35204 * @license
35205 * Copyright Google LLC All Rights Reserved.
35206 *
35207 * Use of this source code is governed by an MIT-style license that can be
35208 * found in the LICENSE file at https://angular.io/license
35209 */
35210 class DefaultIterableDifferFactory {
35211 constructor() { }
35212 supports(obj) {
35213 return isListLikeIterable(obj);
35214 }
35215 create(trackByFn) {
35216 return new DefaultIterableDiffer(trackByFn);
35217 }
35218 }
35219 const trackByIdentity = (index, item) => item;
35220 /**
35221 * @deprecated v4.0.0 - Should not be part of public API.
35222 * @publicApi
35223 */
35224 class DefaultIterableDiffer {
35225 constructor(trackByFn) {
35226 this.length = 0;
35227 // Keeps track of the used records at any point in time (during & across `_check()` calls)
35228 this._linkedRecords = null;
35229 // Keeps track of the removed records at any point in time during `_check()` calls.
35230 this._unlinkedRecords = null;
35231 this._previousItHead = null;
35232 this._itHead = null;
35233 this._itTail = null;
35234 this._additionsHead = null;
35235 this._additionsTail = null;
35236 this._movesHead = null;
35237 this._movesTail = null;
35238 this._removalsHead = null;
35239 this._removalsTail = null;
35240 // Keeps track of records where custom track by is the same, but item identity has changed
35241 this._identityChangesHead = null;
35242 this._identityChangesTail = null;
35243 this._trackByFn = trackByFn || trackByIdentity;
35244 }
35245 forEachItem(fn) {
35246 let record;
35247 for (record = this._itHead; record !== null; record = record._next) {
35248 fn(record);
35249 }
35250 }
35251 forEachOperation(fn) {
35252 let nextIt = this._itHead;
35253 let nextRemove = this._removalsHead;
35254 let addRemoveOffset = 0;
35255 let moveOffsets = null;
35256 while (nextIt || nextRemove) {
35257 // Figure out which is the next record to process
35258 // Order: remove, add, move
35259 const record = !nextRemove ||
35260 nextIt &&
35261 nextIt.currentIndex <
35262 getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
35263 nextIt :
35264 nextRemove;
35265 const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets);
35266 const currentIndex = record.currentIndex;
35267 // consume the item, and adjust the addRemoveOffset and update moveDistance if necessary
35268 if (record === nextRemove) {
35269 addRemoveOffset--;
35270 nextRemove = nextRemove._nextRemoved;
35271 }
35272 else {
35273 nextIt = nextIt._next;
35274 if (record.previousIndex == null) {
35275 addRemoveOffset++;
35276 }
35277 else {
35278 // INVARIANT: currentIndex < previousIndex
35279 if (!moveOffsets)
35280 moveOffsets = [];
35281 const localMovePreviousIndex = adjPreviousIndex - addRemoveOffset;
35282 const localCurrentIndex = currentIndex - addRemoveOffset;
35283 if (localMovePreviousIndex != localCurrentIndex) {
35284 for (let i = 0; i < localMovePreviousIndex; i++) {
35285 const offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0);
35286 const index = offset + i;
35287 if (localCurrentIndex <= index && index < localMovePreviousIndex) {
35288 moveOffsets[i] = offset + 1;
35289 }
35290 }
35291 const previousIndex = record.previousIndex;
35292 moveOffsets[previousIndex] = localCurrentIndex - localMovePreviousIndex;
35293 }
35294 }
35295 }
35296 if (adjPreviousIndex !== currentIndex) {
35297 fn(record, adjPreviousIndex, currentIndex);
35298 }
35299 }
35300 }
35301 forEachPreviousItem(fn) {
35302 let record;
35303 for (record = this._previousItHead; record !== null; record = record._nextPrevious) {
35304 fn(record);
35305 }
35306 }
35307 forEachAddedItem(fn) {
35308 let record;
35309 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
35310 fn(record);
35311 }
35312 }
35313 forEachMovedItem(fn) {
35314 let record;
35315 for (record = this._movesHead; record !== null; record = record._nextMoved) {
35316 fn(record);
35317 }
35318 }
35319 forEachRemovedItem(fn) {
35320 let record;
35321 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
35322 fn(record);
35323 }
35324 }
35325 forEachIdentityChange(fn) {
35326 let record;
35327 for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) {
35328 fn(record);
35329 }
35330 }
35331 diff(collection) {
35332 if (collection == null)
35333 collection = [];
35334 if (!isListLikeIterable(collection)) {
35335 throw new Error(`Error trying to diff '${stringify$1(collection)}'. Only arrays and iterables are allowed`);
35336 }
35337 if (this.check(collection)) {
35338 return this;
35339 }
35340 else {
35341 return null;
35342 }
35343 }
35344 onDestroy() { }
35345 check(collection) {
35346 this._reset();
35347 let record = this._itHead;
35348 let mayBeDirty = false;
35349 let index;
35350 let item;
35351 let itemTrackBy;
35352 if (Array.isArray(collection)) {
35353 this.length = collection.length;
35354 for (let index = 0; index < this.length; index++) {
35355 item = collection[index];
35356 itemTrackBy = this._trackByFn(index, item);
35357 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
35358 record = this._mismatch(record, item, itemTrackBy, index);
35359 mayBeDirty = true;
35360 }
35361 else {
35362 if (mayBeDirty) {
35363 // TODO(misko): can we limit this to duplicates only?
35364 record = this._verifyReinsertion(record, item, itemTrackBy, index);
35365 }
35366 if (!Object.is(record.item, item))
35367 this._addIdentityChange(record, item);
35368 }
35369 record = record._next;
35370 }
35371 }
35372 else {
35373 index = 0;
35374 iterateListLike(collection, (item) => {
35375 itemTrackBy = this._trackByFn(index, item);
35376 if (record === null || !Object.is(record.trackById, itemTrackBy)) {
35377 record = this._mismatch(record, item, itemTrackBy, index);
35378 mayBeDirty = true;
35379 }
35380 else {
35381 if (mayBeDirty) {
35382 // TODO(misko): can we limit this to duplicates only?
35383 record = this._verifyReinsertion(record, item, itemTrackBy, index);
35384 }
35385 if (!Object.is(record.item, item))
35386 this._addIdentityChange(record, item);
35387 }
35388 record = record._next;
35389 index++;
35390 });
35391 this.length = index;
35392 }
35393 this._truncate(record);
35394 this.collection = collection;
35395 return this.isDirty;
35396 }
35397 /* CollectionChanges is considered dirty if it has any additions, moves, removals, or identity
35398 * changes.
35399 */
35400 get isDirty() {
35401 return this._additionsHead !== null || this._movesHead !== null ||
35402 this._removalsHead !== null || this._identityChangesHead !== null;
35403 }
35404 /**
35405 * Reset the state of the change objects to show no changes. This means set previousKey to
35406 * currentKey, and clear all of the queues (additions, moves, removals).
35407 * Set the previousIndexes of moved and added items to their currentIndexes
35408 * Reset the list of additions, moves and removals
35409 *
35410 * @internal
35411 */
35412 _reset() {
35413 if (this.isDirty) {
35414 let record;
35415 for (record = this._previousItHead = this._itHead; record !== null; record = record._next) {
35416 record._nextPrevious = record._next;
35417 }
35418 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
35419 record.previousIndex = record.currentIndex;
35420 }
35421 this._additionsHead = this._additionsTail = null;
35422 for (record = this._movesHead; record !== null; record = record._nextMoved) {
35423 record.previousIndex = record.currentIndex;
35424 }
35425 this._movesHead = this._movesTail = null;
35426 this._removalsHead = this._removalsTail = null;
35427 this._identityChangesHead = this._identityChangesTail = null;
35428 // TODO(vicb): when assert gets supported
35429 // assert(!this.isDirty);
35430 }
35431 }
35432 /**
35433 * This is the core function which handles differences between collections.
35434 *
35435 * - `record` is the record which we saw at this position last time. If null then it is a new
35436 * item.
35437 * - `item` is the current item in the collection
35438 * - `index` is the position of the item in the collection
35439 *
35440 * @internal
35441 */
35442 _mismatch(record, item, itemTrackBy, index) {
35443 // The previous record after which we will append the current one.
35444 let previousRecord;
35445 if (record === null) {
35446 previousRecord = this._itTail;
35447 }
35448 else {
35449 previousRecord = record._prev;
35450 // Remove the record from the collection since we know it does not match the item.
35451 this._remove(record);
35452 }
35453 // See if we have evicted the item, which used to be at some anterior position of _itHead list.
35454 record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
35455 if (record !== null) {
35456 // It is an item which we have evicted earlier: reinsert it back into the list.
35457 // But first we need to check if identity changed, so we can update in view if necessary.
35458 if (!Object.is(record.item, item))
35459 this._addIdentityChange(record, item);
35460 this._reinsertAfter(record, previousRecord, index);
35461 }
35462 else {
35463 // Attempt to see if the item is at some posterior position of _itHead list.
35464 record = this._linkedRecords === null ? null : this._linkedRecords.get(itemTrackBy, index);
35465 if (record !== null) {
35466 // We have the item in _itHead at/after `index` position. We need to move it forward in the
35467 // collection.
35468 // But first we need to check if identity changed, so we can update in view if necessary.
35469 if (!Object.is(record.item, item))
35470 this._addIdentityChange(record, item);
35471 this._moveAfter(record, previousRecord, index);
35472 }
35473 else {
35474 // It is a new item: add it.
35475 record =
35476 this._addAfter(new IterableChangeRecord_(item, itemTrackBy), previousRecord, index);
35477 }
35478 }
35479 return record;
35480 }
35481 /**
35482 * This check is only needed if an array contains duplicates. (Short circuit of nothing dirty)
35483 *
35484 * Use case: `[a, a]` => `[b, a, a]`
35485 *
35486 * If we did not have this check then the insertion of `b` would:
35487 * 1) evict first `a`
35488 * 2) insert `b` at `0` index.
35489 * 3) leave `a` at index `1` as is. <-- this is wrong!
35490 * 3) reinsert `a` at index 2. <-- this is wrong!
35491 *
35492 * The correct behavior is:
35493 * 1) evict first `a`
35494 * 2) insert `b` at `0` index.
35495 * 3) reinsert `a` at index 1.
35496 * 3) move `a` at from `1` to `2`.
35497 *
35498 *
35499 * Double check that we have not evicted a duplicate item. We need to check if the item type may
35500 * have already been removed:
35501 * The insertion of b will evict the first 'a'. If we don't reinsert it now it will be reinserted
35502 * at the end. Which will show up as the two 'a's switching position. This is incorrect, since a
35503 * better way to think of it is as insert of 'b' rather then switch 'a' with 'b' and then add 'a'
35504 * at the end.
35505 *
35506 * @internal
35507 */
35508 _verifyReinsertion(record, item, itemTrackBy, index) {
35509 let reinsertRecord = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
35510 if (reinsertRecord !== null) {
35511 record = this._reinsertAfter(reinsertRecord, record._prev, index);
35512 }
35513 else if (record.currentIndex != index) {
35514 record.currentIndex = index;
35515 this._addToMoves(record, index);
35516 }
35517 return record;
35518 }
35519 /**
35520 * Get rid of any excess {@link IterableChangeRecord_}s from the previous collection
35521 *
35522 * - `record` The first excess {@link IterableChangeRecord_}.
35523 *
35524 * @internal
35525 */
35526 _truncate(record) {
35527 // Anything after that needs to be removed;
35528 while (record !== null) {
35529 const nextRecord = record._next;
35530 this._addToRemovals(this._unlink(record));
35531 record = nextRecord;
35532 }
35533 if (this._unlinkedRecords !== null) {
35534 this._unlinkedRecords.clear();
35535 }
35536 if (this._additionsTail !== null) {
35537 this._additionsTail._nextAdded = null;
35538 }
35539 if (this._movesTail !== null) {
35540 this._movesTail._nextMoved = null;
35541 }
35542 if (this._itTail !== null) {
35543 this._itTail._next = null;
35544 }
35545 if (this._removalsTail !== null) {
35546 this._removalsTail._nextRemoved = null;
35547 }
35548 if (this._identityChangesTail !== null) {
35549 this._identityChangesTail._nextIdentityChange = null;
35550 }
35551 }
35552 /** @internal */
35553 _reinsertAfter(record, prevRecord, index) {
35554 if (this._unlinkedRecords !== null) {
35555 this._unlinkedRecords.remove(record);
35556 }
35557 const prev = record._prevRemoved;
35558 const next = record._nextRemoved;
35559 if (prev === null) {
35560 this._removalsHead = next;
35561 }
35562 else {
35563 prev._nextRemoved = next;
35564 }
35565 if (next === null) {
35566 this._removalsTail = prev;
35567 }
35568 else {
35569 next._prevRemoved = prev;
35570 }
35571 this._insertAfter(record, prevRecord, index);
35572 this._addToMoves(record, index);
35573 return record;
35574 }
35575 /** @internal */
35576 _moveAfter(record, prevRecord, index) {
35577 this._unlink(record);
35578 this._insertAfter(record, prevRecord, index);
35579 this._addToMoves(record, index);
35580 return record;
35581 }
35582 /** @internal */
35583 _addAfter(record, prevRecord, index) {
35584 this._insertAfter(record, prevRecord, index);
35585 if (this._additionsTail === null) {
35586 // TODO(vicb):
35587 // assert(this._additionsHead === null);
35588 this._additionsTail = this._additionsHead = record;
35589 }
35590 else {
35591 // TODO(vicb):
35592 // assert(_additionsTail._nextAdded === null);
35593 // assert(record._nextAdded === null);
35594 this._additionsTail = this._additionsTail._nextAdded = record;
35595 }
35596 return record;
35597 }
35598 /** @internal */
35599 _insertAfter(record, prevRecord, index) {
35600 // TODO(vicb):
35601 // assert(record != prevRecord);
35602 // assert(record._next === null);
35603 // assert(record._prev === null);
35604 const next = prevRecord === null ? this._itHead : prevRecord._next;
35605 // TODO(vicb):
35606 // assert(next != record);
35607 // assert(prevRecord != record);
35608 record._next = next;
35609 record._prev = prevRecord;
35610 if (next === null) {
35611 this._itTail = record;
35612 }
35613 else {
35614 next._prev = record;
35615 }
35616 if (prevRecord === null) {
35617 this._itHead = record;
35618 }
35619 else {
35620 prevRecord._next = record;
35621 }
35622 if (this._linkedRecords === null) {
35623 this._linkedRecords = new _DuplicateMap();
35624 }
35625 this._linkedRecords.put(record);
35626 record.currentIndex = index;
35627 return record;
35628 }
35629 /** @internal */
35630 _remove(record) {
35631 return this._addToRemovals(this._unlink(record));
35632 }
35633 /** @internal */
35634 _unlink(record) {
35635 if (this._linkedRecords !== null) {
35636 this._linkedRecords.remove(record);
35637 }
35638 const prev = record._prev;
35639 const next = record._next;
35640 // TODO(vicb):
35641 // assert((record._prev = null) === null);
35642 // assert((record._next = null) === null);
35643 if (prev === null) {
35644 this._itHead = next;
35645 }
35646 else {
35647 prev._next = next;
35648 }
35649 if (next === null) {
35650 this._itTail = prev;
35651 }
35652 else {
35653 next._prev = prev;
35654 }
35655 return record;
35656 }
35657 /** @internal */
35658 _addToMoves(record, toIndex) {
35659 // TODO(vicb):
35660 // assert(record._nextMoved === null);
35661 if (record.previousIndex === toIndex) {
35662 return record;
35663 }
35664 if (this._movesTail === null) {
35665 // TODO(vicb):
35666 // assert(_movesHead === null);
35667 this._movesTail = this._movesHead = record;
35668 }
35669 else {
35670 // TODO(vicb):
35671 // assert(_movesTail._nextMoved === null);
35672 this._movesTail = this._movesTail._nextMoved = record;
35673 }
35674 return record;
35675 }
35676 _addToRemovals(record) {
35677 if (this._unlinkedRecords === null) {
35678 this._unlinkedRecords = new _DuplicateMap();
35679 }
35680 this._unlinkedRecords.put(record);
35681 record.currentIndex = null;
35682 record._nextRemoved = null;
35683 if (this._removalsTail === null) {
35684 // TODO(vicb):
35685 // assert(_removalsHead === null);
35686 this._removalsTail = this._removalsHead = record;
35687 record._prevRemoved = null;
35688 }
35689 else {
35690 // TODO(vicb):
35691 // assert(_removalsTail._nextRemoved === null);
35692 // assert(record._nextRemoved === null);
35693 record._prevRemoved = this._removalsTail;
35694 this._removalsTail = this._removalsTail._nextRemoved = record;
35695 }
35696 return record;
35697 }
35698 /** @internal */
35699 _addIdentityChange(record, item) {
35700 record.item = item;
35701 if (this._identityChangesTail === null) {
35702 this._identityChangesTail = this._identityChangesHead = record;
35703 }
35704 else {
35705 this._identityChangesTail = this._identityChangesTail._nextIdentityChange = record;
35706 }
35707 return record;
35708 }
35709 }
35710 class IterableChangeRecord_ {
35711 constructor(item, trackById) {
35712 this.item = item;
35713 this.trackById = trackById;
35714 this.currentIndex = null;
35715 this.previousIndex = null;
35716 /** @internal */
35717 this._nextPrevious = null;
35718 /** @internal */
35719 this._prev = null;
35720 /** @internal */
35721 this._next = null;
35722 /** @internal */
35723 this._prevDup = null;
35724 /** @internal */
35725 this._nextDup = null;
35726 /** @internal */
35727 this._prevRemoved = null;
35728 /** @internal */
35729 this._nextRemoved = null;
35730 /** @internal */
35731 this._nextAdded = null;
35732 /** @internal */
35733 this._nextMoved = null;
35734 /** @internal */
35735 this._nextIdentityChange = null;
35736 }
35737 }
35738 // A linked list of IterableChangeRecords with the same IterableChangeRecord_.item
35739 class _DuplicateItemRecordList {
35740 constructor() {
35741 /** @internal */
35742 this._head = null;
35743 /** @internal */
35744 this._tail = null;
35745 }
35746 /**
35747 * Append the record to the list of duplicates.
35748 *
35749 * Note: by design all records in the list of duplicates hold the same value in record.item.
35750 */
35751 add(record) {
35752 if (this._head === null) {
35753 this._head = this._tail = record;
35754 record._nextDup = null;
35755 record._prevDup = null;
35756 }
35757 else {
35758 // TODO(vicb):
35759 // assert(record.item == _head.item ||
35760 // record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN);
35761 this._tail._nextDup = record;
35762 record._prevDup = this._tail;
35763 record._nextDup = null;
35764 this._tail = record;
35765 }
35766 }
35767 // Returns a IterableChangeRecord_ having IterableChangeRecord_.trackById == trackById and
35768 // IterableChangeRecord_.currentIndex >= atOrAfterIndex
35769 get(trackById, atOrAfterIndex) {
35770 let record;
35771 for (record = this._head; record !== null; record = record._nextDup) {
35772 if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex) &&
35773 Object.is(record.trackById, trackById)) {
35774 return record;
35775 }
35776 }
35777 return null;
35778 }
35779 /**
35780 * Remove one {@link IterableChangeRecord_} from the list of duplicates.
35781 *
35782 * Returns whether the list of duplicates is empty.
35783 */
35784 remove(record) {
35785 // TODO(vicb):
35786 // assert(() {
35787 // // verify that the record being removed is in the list.
35788 // for (IterableChangeRecord_ cursor = _head; cursor != null; cursor = cursor._nextDup) {
35789 // if (identical(cursor, record)) return true;
35790 // }
35791 // return false;
35792 //});
35793 const prev = record._prevDup;
35794 const next = record._nextDup;
35795 if (prev === null) {
35796 this._head = next;
35797 }
35798 else {
35799 prev._nextDup = next;
35800 }
35801 if (next === null) {
35802 this._tail = prev;
35803 }
35804 else {
35805 next._prevDup = prev;
35806 }
35807 return this._head === null;
35808 }
35809 }
35810 class _DuplicateMap {
35811 constructor() {
35812 this.map = new Map();
35813 }
35814 put(record) {
35815 const key = record.trackById;
35816 let duplicates = this.map.get(key);
35817 if (!duplicates) {
35818 duplicates = new _DuplicateItemRecordList();
35819 this.map.set(key, duplicates);
35820 }
35821 duplicates.add(record);
35822 }
35823 /**
35824 * Retrieve the `value` using key. Because the IterableChangeRecord_ value may be one which we
35825 * have already iterated over, we use the `atOrAfterIndex` to pretend it is not there.
35826 *
35827 * Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we
35828 * have any more `a`s needs to return the second `a`.
35829 */
35830 get(trackById, atOrAfterIndex) {
35831 const key = trackById;
35832 const recordList = this.map.get(key);
35833 return recordList ? recordList.get(trackById, atOrAfterIndex) : null;
35834 }
35835 /**
35836 * Removes a {@link IterableChangeRecord_} from the list of duplicates.
35837 *
35838 * The list of duplicates also is removed from the map if it gets empty.
35839 */
35840 remove(record) {
35841 const key = record.trackById;
35842 const recordList = this.map.get(key);
35843 // Remove the list of duplicates when it gets empty
35844 if (recordList.remove(record)) {
35845 this.map.delete(key);
35846 }
35847 return record;
35848 }
35849 get isEmpty() {
35850 return this.map.size === 0;
35851 }
35852 clear() {
35853 this.map.clear();
35854 }
35855 }
35856 function getPreviousIndex(item, addRemoveOffset, moveOffsets) {
35857 const previousIndex = item.previousIndex;
35858 if (previousIndex === null)
35859 return previousIndex;
35860 let moveOffset = 0;
35861 if (moveOffsets && previousIndex < moveOffsets.length) {
35862 moveOffset = moveOffsets[previousIndex];
35863 }
35864 return previousIndex + addRemoveOffset + moveOffset;
35865 }
35866
35867 /**
35868 * @license
35869 * Copyright Google LLC All Rights Reserved.
35870 *
35871 * Use of this source code is governed by an MIT-style license that can be
35872 * found in the LICENSE file at https://angular.io/license
35873 */
35874 class DefaultKeyValueDifferFactory {
35875 constructor() { }
35876 supports(obj) {
35877 return obj instanceof Map || isJsObject(obj);
35878 }
35879 create() {
35880 return new DefaultKeyValueDiffer();
35881 }
35882 }
35883 class DefaultKeyValueDiffer {
35884 constructor() {
35885 this._records = new Map();
35886 this._mapHead = null;
35887 // _appendAfter is used in the check loop
35888 this._appendAfter = null;
35889 this._previousMapHead = null;
35890 this._changesHead = null;
35891 this._changesTail = null;
35892 this._additionsHead = null;
35893 this._additionsTail = null;
35894 this._removalsHead = null;
35895 this._removalsTail = null;
35896 }
35897 get isDirty() {
35898 return this._additionsHead !== null || this._changesHead !== null ||
35899 this._removalsHead !== null;
35900 }
35901 forEachItem(fn) {
35902 let record;
35903 for (record = this._mapHead; record !== null; record = record._next) {
35904 fn(record);
35905 }
35906 }
35907 forEachPreviousItem(fn) {
35908 let record;
35909 for (record = this._previousMapHead; record !== null; record = record._nextPrevious) {
35910 fn(record);
35911 }
35912 }
35913 forEachChangedItem(fn) {
35914 let record;
35915 for (record = this._changesHead; record !== null; record = record._nextChanged) {
35916 fn(record);
35917 }
35918 }
35919 forEachAddedItem(fn) {
35920 let record;
35921 for (record = this._additionsHead; record !== null; record = record._nextAdded) {
35922 fn(record);
35923 }
35924 }
35925 forEachRemovedItem(fn) {
35926 let record;
35927 for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
35928 fn(record);
35929 }
35930 }
35931 diff(map) {
35932 if (!map) {
35933 map = new Map();
35934 }
35935 else if (!(map instanceof Map || isJsObject(map))) {
35936 throw new Error(`Error trying to diff '${stringify$1(map)}'. Only maps and objects are allowed`);
35937 }
35938 return this.check(map) ? this : null;
35939 }
35940 onDestroy() { }
35941 /**
35942 * Check the current state of the map vs the previous.
35943 * The algorithm is optimised for when the keys do no change.
35944 */
35945 check(map) {
35946 this._reset();
35947 let insertBefore = this._mapHead;
35948 this._appendAfter = null;
35949 this._forEach(map, (value, key) => {
35950 if (insertBefore && insertBefore.key === key) {
35951 this._maybeAddToChanges(insertBefore, value);
35952 this._appendAfter = insertBefore;
35953 insertBefore = insertBefore._next;
35954 }
35955 else {
35956 const record = this._getOrCreateRecordForKey(key, value);
35957 insertBefore = this._insertBeforeOrAppend(insertBefore, record);
35958 }
35959 });
35960 // Items remaining at the end of the list have been deleted
35961 if (insertBefore) {
35962 if (insertBefore._prev) {
35963 insertBefore._prev._next = null;
35964 }
35965 this._removalsHead = insertBefore;
35966 for (let record = insertBefore; record !== null; record = record._nextRemoved) {
35967 if (record === this._mapHead) {
35968 this._mapHead = null;
35969 }
35970 this._records.delete(record.key);
35971 record._nextRemoved = record._next;
35972 record.previousValue = record.currentValue;
35973 record.currentValue = null;
35974 record._prev = null;
35975 record._next = null;
35976 }
35977 }
35978 // Make sure tails have no next records from previous runs
35979 if (this._changesTail)
35980 this._changesTail._nextChanged = null;
35981 if (this._additionsTail)
35982 this._additionsTail._nextAdded = null;
35983 return this.isDirty;
35984 }
35985 /**
35986 * Inserts a record before `before` or append at the end of the list when `before` is null.
35987 *
35988 * Notes:
35989 * - This method appends at `this._appendAfter`,
35990 * - This method updates `this._appendAfter`,
35991 * - The return value is the new value for the insertion pointer.
35992 */
35993 _insertBeforeOrAppend(before, record) {
35994 if (before) {
35995 const prev = before._prev;
35996 record._next = before;
35997 record._prev = prev;
35998 before._prev = record;
35999 if (prev) {
36000 prev._next = record;
36001 }
36002 if (before === this._mapHead) {
36003 this._mapHead = record;
36004 }
36005 this._appendAfter = before;
36006 return before;
36007 }
36008 if (this._appendAfter) {
36009 this._appendAfter._next = record;
36010 record._prev = this._appendAfter;
36011 }
36012 else {
36013 this._mapHead = record;
36014 }
36015 this._appendAfter = record;
36016 return null;
36017 }
36018 _getOrCreateRecordForKey(key, value) {
36019 if (this._records.has(key)) {
36020 const record = this._records.get(key);
36021 this._maybeAddToChanges(record, value);
36022 const prev = record._prev;
36023 const next = record._next;
36024 if (prev) {
36025 prev._next = next;
36026 }
36027 if (next) {
36028 next._prev = prev;
36029 }
36030 record._next = null;
36031 record._prev = null;
36032 return record;
36033 }
36034 const record = new KeyValueChangeRecord_(key);
36035 this._records.set(key, record);
36036 record.currentValue = value;
36037 this._addToAdditions(record);
36038 return record;
36039 }
36040 /** @internal */
36041 _reset() {
36042 if (this.isDirty) {
36043 let record;
36044 // let `_previousMapHead` contain the state of the map before the changes
36045 this._previousMapHead = this._mapHead;
36046 for (record = this._previousMapHead; record !== null; record = record._next) {
36047 record._nextPrevious = record._next;
36048 }
36049 // Update `record.previousValue` with the value of the item before the changes
36050 // We need to update all changed items (that's those which have been added and changed)
36051 for (record = this._changesHead; record !== null; record = record._nextChanged) {
36052 record.previousValue = record.currentValue;
36053 }
36054 for (record = this._additionsHead; record != null; record = record._nextAdded) {
36055 record.previousValue = record.currentValue;
36056 }
36057 this._changesHead = this._changesTail = null;
36058 this._additionsHead = this._additionsTail = null;
36059 this._removalsHead = null;
36060 }
36061 }
36062 // Add the record or a given key to the list of changes only when the value has actually changed
36063 _maybeAddToChanges(record, newValue) {
36064 if (!Object.is(newValue, record.currentValue)) {
36065 record.previousValue = record.currentValue;
36066 record.currentValue = newValue;
36067 this._addToChanges(record);
36068 }
36069 }
36070 _addToAdditions(record) {
36071 if (this._additionsHead === null) {
36072 this._additionsHead = this._additionsTail = record;
36073 }
36074 else {
36075 this._additionsTail._nextAdded = record;
36076 this._additionsTail = record;
36077 }
36078 }
36079 _addToChanges(record) {
36080 if (this._changesHead === null) {
36081 this._changesHead = this._changesTail = record;
36082 }
36083 else {
36084 this._changesTail._nextChanged = record;
36085 this._changesTail = record;
36086 }
36087 }
36088 /** @internal */
36089 _forEach(obj, fn) {
36090 if (obj instanceof Map) {
36091 obj.forEach(fn);
36092 }
36093 else {
36094 Object.keys(obj).forEach(k => fn(obj[k], k));
36095 }
36096 }
36097 }
36098 class KeyValueChangeRecord_ {
36099 constructor(key) {
36100 this.key = key;
36101 this.previousValue = null;
36102 this.currentValue = null;
36103 /** @internal */
36104 this._nextPrevious = null;
36105 /** @internal */
36106 this._next = null;
36107 /** @internal */
36108 this._prev = null;
36109 /** @internal */
36110 this._nextAdded = null;
36111 /** @internal */
36112 this._nextRemoved = null;
36113 /** @internal */
36114 this._nextChanged = null;
36115 }
36116 }
36117
36118 /**
36119 * @license
36120 * Copyright Google LLC All Rights Reserved.
36121 *
36122 * Use of this source code is governed by an MIT-style license that can be
36123 * found in the LICENSE file at https://angular.io/license
36124 */
36125 function defaultIterableDiffersFactory() {
36126 return new IterableDiffers([new DefaultIterableDifferFactory()]);
36127 }
36128 /**
36129 * A repository of different iterable diffing strategies used by NgFor, NgClass, and others.
36130 *
36131 * @publicApi
36132 */
36133 class IterableDiffers {
36134 constructor(factories) {
36135 this.factories = factories;
36136 }
36137 static create(factories, parent) {
36138 if (parent != null) {
36139 const copied = parent.factories.slice();
36140 factories = factories.concat(copied);
36141 }
36142 return new IterableDiffers(factories);
36143 }
36144 /**
36145 * Takes an array of {@link IterableDifferFactory} and returns a provider used to extend the
36146 * inherited {@link IterableDiffers} instance with the provided factories and return a new
36147 * {@link IterableDiffers} instance.
36148 *
36149 * @usageNotes
36150 * ### Example
36151 *
36152 * The following example shows how to extend an existing list of factories,
36153 * which will only be applied to the injector for this component and its children.
36154 * This step is all that's required to make a new {@link IterableDiffer} available.
36155 *
36156 * ```
36157 * @Component({
36158 * viewProviders: [
36159 * IterableDiffers.extend([new ImmutableListDiffer()])
36160 * ]
36161 * })
36162 * ```
36163 */
36164 static extend(factories) {
36165 return {
36166 provide: IterableDiffers,
36167 useFactory: (parent) => {
36168 // if parent is null, it means that we are in the root injector and we have just overridden
36169 // the default injection mechanism for IterableDiffers, in such a case just assume
36170 // `defaultIterableDiffersFactory`.
36171 return IterableDiffers.create(factories, parent || defaultIterableDiffersFactory());
36172 },
36173 // Dependency technically isn't optional, but we can provide a better error message this way.
36174 deps: [[IterableDiffers, new SkipSelf(), new Optional()]]
36175 };
36176 }
36177 find(iterable) {
36178 const factory = this.factories.find(f => f.supports(iterable));
36179 if (factory != null) {
36180 return factory;
36181 }
36182 else {
36183 throw new Error(`Cannot find a differ supporting object '${iterable}' of type '${getTypeNameForDebugging(iterable)}'`);
36184 }
36185 }
36186 }
36187 /** @nocollapse */
36188 IterableDiffers.ɵprov = ɵɵdefineInjectable({ token: IterableDiffers, providedIn: 'root', factory: defaultIterableDiffersFactory });
36189 function getTypeNameForDebugging(type) {
36190 return type['name'] || typeof type;
36191 }
36192
36193 /**
36194 * @license
36195 * Copyright Google LLC All Rights Reserved.
36196 *
36197 * Use of this source code is governed by an MIT-style license that can be
36198 * found in the LICENSE file at https://angular.io/license
36199 */
36200 function defaultKeyValueDiffersFactory() {
36201 return new KeyValueDiffers([new DefaultKeyValueDifferFactory()]);
36202 }
36203 /**
36204 * A repository of different Map diffing strategies used by NgClass, NgStyle, and others.
36205 *
36206 * @publicApi
36207 */
36208 class KeyValueDiffers {
36209 constructor(factories) {
36210 this.factories = factories;
36211 }
36212 static create(factories, parent) {
36213 if (parent) {
36214 const copied = parent.factories.slice();
36215 factories = factories.concat(copied);
36216 }
36217 return new KeyValueDiffers(factories);
36218 }
36219 /**
36220 * Takes an array of {@link KeyValueDifferFactory} and returns a provider used to extend the
36221 * inherited {@link KeyValueDiffers} instance with the provided factories and return a new
36222 * {@link KeyValueDiffers} instance.
36223 *
36224 * @usageNotes
36225 * ### Example
36226 *
36227 * The following example shows how to extend an existing list of factories,
36228 * which will only be applied to the injector for this component and its children.
36229 * This step is all that's required to make a new {@link KeyValueDiffer} available.
36230 *
36231 * ```
36232 * @Component({
36233 * viewProviders: [
36234 * KeyValueDiffers.extend([new ImmutableMapDiffer()])
36235 * ]
36236 * })
36237 * ```
36238 */
36239 static extend(factories) {
36240 return {
36241 provide: KeyValueDiffers,
36242 useFactory: (parent) => {
36243 // if parent is null, it means that we are in the root injector and we have just overridden
36244 // the default injection mechanism for KeyValueDiffers, in such a case just assume
36245 // `defaultKeyValueDiffersFactory`.
36246 return KeyValueDiffers.create(factories, parent || defaultKeyValueDiffersFactory());
36247 },
36248 // Dependency technically isn't optional, but we can provide a better error message this way.
36249 deps: [[KeyValueDiffers, new SkipSelf(), new Optional()]]
36250 };
36251 }
36252 find(kv) {
36253 const factory = this.factories.find(f => f.supports(kv));
36254 if (factory) {
36255 return factory;
36256 }
36257 throw new Error(`Cannot find a differ supporting object '${kv}'`);
36258 }
36259 }
36260 /** @nocollapse */
36261 KeyValueDiffers.ɵprov = ɵɵdefineInjectable({ token: KeyValueDiffers, providedIn: 'root', factory: defaultKeyValueDiffersFactory });
36262
36263 /**
36264 * @license
36265 * Copyright Google LLC All Rights Reserved.
36266 *
36267 * Use of this source code is governed by an MIT-style license that can be
36268 * found in the LICENSE file at https://angular.io/license
36269 */
36270 function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
36271 while (tNode !== null) {
36272 ngDevMode &&
36273 assertTNodeType(tNode, 3 /* AnyRNode */ | 12 /* AnyContainer */ | 16 /* Projection */ | 32 /* Icu */);
36274 const lNode = lView[tNode.index];
36275 if (lNode !== null) {
36276 result.push(unwrapRNode(lNode));
36277 }
36278 // A given lNode can represent either a native node or a LContainer (when it is a host of a
36279 // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
36280 // from the views in this container.
36281 if (isLContainer(lNode)) {
36282 for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
36283 const lViewInAContainer = lNode[i];
36284 const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
36285 if (lViewFirstChildTNode !== null) {
36286 collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
36287 }
36288 }
36289 }
36290 const tNodeType = tNode.type;
36291 if (tNodeType & 8 /* ElementContainer */) {
36292 collectNativeNodes(tView, lView, tNode.child, result);
36293 }
36294 else if (tNodeType & 32 /* Icu */) {
36295 const nextRNode = icuContainerIterate();
36296 let rNode;
36297 while (rNode = nextRNode()) {
36298 result.push(rNode);
36299 }
36300 }
36301 else if (tNodeType & 16 /* Projection */) {
36302 const nodesInSlot = getProjectionNodes(lView, tNode);
36303 if (Array.isArray(nodesInSlot)) {
36304 result.push(...nodesInSlot);
36305 }
36306 else {
36307 const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
36308 ngDevMode && assertParentView(parentView);
36309 collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
36310 }
36311 }
36312 tNode = isProjection ? tNode.projectionNext : tNode.next;
36313 }
36314 return result;
36315 }
36316
36317 /**
36318 * @license
36319 * Copyright Google LLC All Rights Reserved.
36320 *
36321 * Use of this source code is governed by an MIT-style license that can be
36322 * found in the LICENSE file at https://angular.io/license
36323 */
36324 class ViewRef {
36325 constructor(
36326 /**
36327 * This represents `LView` associated with the component when ViewRef is a ChangeDetectorRef.
36328 *
36329 * When ViewRef is created for a dynamic component, this also represents the `LView` for the
36330 * component.
36331 *
36332 * For a "regular" ViewRef created for an embedded view, this is the `LView` for the embedded
36333 * view.
36334 *
36335 * @internal
36336 */
36337 _lView,
36338 /**
36339 * This represents the `LView` associated with the point where `ChangeDetectorRef` was
36340 * requested.
36341 *
36342 * This may be different from `_lView` if the `_cdRefInjectingView` is an embedded view.
36343 */
36344 _cdRefInjectingView) {
36345 this._lView = _lView;
36346 this._cdRefInjectingView = _cdRefInjectingView;
36347 this._appRef = null;
36348 this._attachedToViewContainer = false;
36349 }
36350 get rootNodes() {
36351 const lView = this._lView;
36352 const tView = lView[TVIEW];
36353 return collectNativeNodes(tView, lView, tView.firstChild, []);
36354 }
36355 get context() {
36356 return this._lView[CONTEXT];
36357 }
36358 get destroyed() {
36359 return (this._lView[FLAGS] & 256 /* Destroyed */) === 256 /* Destroyed */;
36360 }
36361 destroy() {
36362 if (this._appRef) {
36363 this._appRef.detachView(this);
36364 }
36365 else if (this._attachedToViewContainer) {
36366 const parent = this._lView[PARENT];
36367 if (isLContainer(parent)) {
36368 const viewRefs = parent[VIEW_REFS];
36369 const index = viewRefs ? viewRefs.indexOf(this) : -1;
36370 if (index > -1) {
36371 ngDevMode &&
36372 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.');
36373 detachView(parent, index);
36374 removeFromArray(viewRefs, index);
36375 }
36376 }
36377 this._attachedToViewContainer = false;
36378 }
36379 destroyLView(this._lView[TVIEW], this._lView);
36380 }
36381 onDestroy(callback) {
36382 storeCleanupWithContext(this._lView[TVIEW], this._lView, null, callback);
36383 }
36384 /**
36385 * Marks a view and all of its ancestors dirty.
36386 *
36387 * It also triggers change detection by calling `scheduleTick` internally, which coalesces
36388 * multiple `markForCheck` calls to into one change detection run.
36389 *
36390 * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is
36391 * checked when it needs to be re-rendered but the two normal triggers haven't marked it
36392 * dirty (i.e. inputs haven't changed and events haven't fired in the view).
36393 *
36394 * <!-- TODO: Add a link to a chapter on OnPush components -->
36395 *
36396 * @usageNotes
36397 * ### Example
36398 *
36399 * ```typescript
36400 * @Component({
36401 * selector: 'my-app',
36402 * template: `Number of ticks: {{numberOfTicks}}`
36403 * changeDetection: ChangeDetectionStrategy.OnPush,
36404 * })
36405 * class AppComponent {
36406 * numberOfTicks = 0;
36407 *
36408 * constructor(private ref: ChangeDetectorRef) {
36409 * setInterval(() => {
36410 * this.numberOfTicks++;
36411 * // the following is required, otherwise the view will not be updated
36412 * this.ref.markForCheck();
36413 * }, 1000);
36414 * }
36415 * }
36416 * ```
36417 */
36418 markForCheck() {
36419 markViewDirty(this._cdRefInjectingView || this._lView);
36420 }
36421 /**
36422 * Detaches the view from the change detection tree.
36423 *
36424 * Detached views will not be checked during change detection runs until they are
36425 * re-attached, even if they are dirty. `detach` can be used in combination with
36426 * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change
36427 * detection checks.
36428 *
36429 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
36430 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
36431 *
36432 * @usageNotes
36433 * ### Example
36434 *
36435 * The following example defines a component with a large list of readonly data.
36436 * Imagine the data changes constantly, many times per second. For performance reasons,
36437 * we want to check and update the list every five seconds. We can do that by detaching
36438 * the component's change detector and doing a local check every five seconds.
36439 *
36440 * ```typescript
36441 * class DataProvider {
36442 * // in a real application the returned data will be different every time
36443 * get data() {
36444 * return [1,2,3,4,5];
36445 * }
36446 * }
36447 *
36448 * @Component({
36449 * selector: 'giant-list',
36450 * template: `
36451 * <li *ngFor="let d of dataProvider.data">Data {{d}}</li>
36452 * `,
36453 * })
36454 * class GiantList {
36455 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {
36456 * ref.detach();
36457 * setInterval(() => {
36458 * this.ref.detectChanges();
36459 * }, 5000);
36460 * }
36461 * }
36462 *
36463 * @Component({
36464 * selector: 'app',
36465 * providers: [DataProvider],
36466 * template: `
36467 * <giant-list><giant-list>
36468 * `,
36469 * })
36470 * class App {
36471 * }
36472 * ```
36473 */
36474 detach() {
36475 this._lView[FLAGS] &= ~128 /* Attached */;
36476 }
36477 /**
36478 * Re-attaches a view to the change detection tree.
36479 *
36480 * This can be used to re-attach views that were previously detached from the tree
36481 * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default.
36482 *
36483 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
36484 *
36485 * @usageNotes
36486 * ### Example
36487 *
36488 * The following example creates a component displaying `live` data. The component will detach
36489 * its change detector from the main change detector tree when the component's live property
36490 * is set to false.
36491 *
36492 * ```typescript
36493 * class DataProvider {
36494 * data = 1;
36495 *
36496 * constructor() {
36497 * setInterval(() => {
36498 * this.data = this.data * 2;
36499 * }, 500);
36500 * }
36501 * }
36502 *
36503 * @Component({
36504 * selector: 'live-data',
36505 * inputs: ['live'],
36506 * template: 'Data: {{dataProvider.data}}'
36507 * })
36508 * class LiveData {
36509 * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {}
36510 *
36511 * set live(value) {
36512 * if (value) {
36513 * this.ref.reattach();
36514 * } else {
36515 * this.ref.detach();
36516 * }
36517 * }
36518 * }
36519 *
36520 * @Component({
36521 * selector: 'my-app',
36522 * providers: [DataProvider],
36523 * template: `
36524 * Live Update: <input type="checkbox" [(ngModel)]="live">
36525 * <live-data [live]="live"><live-data>
36526 * `,
36527 * })
36528 * class AppComponent {
36529 * live = true;
36530 * }
36531 * ```
36532 */
36533 reattach() {
36534 this._lView[FLAGS] |= 128 /* Attached */;
36535 }
36536 /**
36537 * Checks the view and its children.
36538 *
36539 * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement
36540 * local change detection checks.
36541 *
36542 * <!-- TODO: Add a link to a chapter on detach/reattach/local digest -->
36543 * <!-- TODO: Add a live demo once ref.detectChanges is merged into master -->
36544 *
36545 * @usageNotes
36546 * ### Example
36547 *
36548 * The following example defines a component with a large list of readonly data.
36549 * Imagine, the data changes constantly, many times per second. For performance reasons,
36550 * we want to check and update the list every five seconds.
36551 *
36552 * We can do that by detaching the component's change detector and doing a local change detection
36553 * check every five seconds.
36554 *
36555 * See {@link ChangeDetectorRef#detach detach} for more information.
36556 */
36557 detectChanges() {
36558 detectChangesInternal(this._lView[TVIEW], this._lView, this.context);
36559 }
36560 /**
36561 * Checks the change detector and its children, and throws if any changes are detected.
36562 *
36563 * This is used in development mode to verify that running change detection doesn't
36564 * introduce other changes.
36565 */
36566 checkNoChanges() {
36567 checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
36568 }
36569 attachToViewContainerRef() {
36570 if (this._appRef) {
36571 throw new Error('This view is already attached directly to the ApplicationRef!');
36572 }
36573 this._attachedToViewContainer = true;
36574 }
36575 detachFromAppRef() {
36576 this._appRef = null;
36577 renderDetachView(this._lView[TVIEW], this._lView);
36578 }
36579 attachToAppRef(appRef) {
36580 if (this._attachedToViewContainer) {
36581 throw new Error('This view is already attached to a ViewContainer!');
36582 }
36583 this._appRef = appRef;
36584 }
36585 }
36586 /** @internal */
36587 class RootViewRef extends ViewRef {
36588 constructor(_view) {
36589 super(_view);
36590 this._view = _view;
36591 }
36592 detectChanges() {
36593 detectChangesInRootView(this._view);
36594 }
36595 checkNoChanges() {
36596 checkNoChangesInRootView(this._view);
36597 }
36598 get context() {
36599 return null;
36600 }
36601 }
36602
36603 /**
36604 * @license
36605 * Copyright Google LLC All Rights Reserved.
36606 *
36607 * Use of this source code is governed by an MIT-style license that can be
36608 * found in the LICENSE file at https://angular.io/license
36609 */
36610 const SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__ = noop;
36611 const SWITCH_CHANGE_DETECTOR_REF_FACTORY = SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__;
36612 /**
36613 * Base class that provides change detection functionality.
36614 * A change-detection tree collects all views that are to be checked for changes.
36615 * Use the methods to add and remove views from the tree, initiate change-detection,
36616 * and explicitly mark views as _dirty_, meaning that they have changed and need to be re-rendered.
36617 *
36618 * @see [Using change detection hooks](guide/lifecycle-hooks#using-change-detection-hooks)
36619 * @see [Defining custom change detection](guide/lifecycle-hooks#defining-custom-change-detection)
36620 *
36621 * @usageNotes
36622 *
36623 * The following examples demonstrate how to modify default change-detection behavior
36624 * to perform explicit detection when needed.
36625 *
36626 * ### Use `markForCheck()` with `CheckOnce` strategy
36627 *
36628 * The following example sets the `OnPush` change-detection strategy for a component
36629 * (`CheckOnce`, rather than the default `CheckAlways`), then forces a second check
36630 * after an interval. See [live demo](https://plnkr.co/edit/GC512b?p=preview).
36631 *
36632 * <code-example path="core/ts/change_detect/change-detection.ts"
36633 * region="mark-for-check"></code-example>
36634 *
36635 * ### Detach change detector to limit how often check occurs
36636 *
36637 * The following example defines a component with a large list of read-only data
36638 * that is expected to change constantly, many times per second.
36639 * To improve performance, we want to check and update the list
36640 * less often than the changes actually occur. To do that, we detach
36641 * the component's change detector and perform an explicit local check every five seconds.
36642 *
36643 * <code-example path="core/ts/change_detect/change-detection.ts" region="detach"></code-example>
36644 *
36645 *
36646 * ### Reattaching a detached component
36647 *
36648 * The following example creates a component displaying live data.
36649 * The component detaches its change detector from the main change detector tree
36650 * when the `live` property is set to false, and reattaches it when the property
36651 * becomes true.
36652 *
36653 * <code-example path="core/ts/change_detect/change-detection.ts" region="reattach"></code-example>
36654 *
36655 * @publicApi
36656 */
36657 class ChangeDetectorRef {
36658 }
36659 /**
36660 * @internal
36661 * @nocollapse
36662 */
36663 ChangeDetectorRef.__NG_ELEMENT_ID__ = SWITCH_CHANGE_DETECTOR_REF_FACTORY;
36664 /**
36665 * This marker is need so that the JIT compiler can correctly identify this class as special.
36666 *
36667 * @internal
36668 * @nocollapse
36669 */
36670 ChangeDetectorRef.__ChangeDetectorRef__ = true;
36671
36672 /**
36673 * @license
36674 * Copyright Google LLC All Rights Reserved.
36675 *
36676 * Use of this source code is governed by an MIT-style license that can be
36677 * found in the LICENSE file at https://angular.io/license
36678 */
36679 /**
36680 * Structural diffing for `Object`s and `Map`s.
36681 */
36682 const keyValDiff = [new DefaultKeyValueDifferFactory()];
36683 /**
36684 * Structural diffing for `Iterable` types such as `Array`s.
36685 */
36686 const iterableDiff = [new DefaultIterableDifferFactory()];
36687 const defaultIterableDiffers = new IterableDiffers(iterableDiff);
36688 const defaultKeyValueDiffers = new KeyValueDiffers(keyValDiff);
36689
36690 /**
36691 * @license
36692 * Copyright Google LLC All Rights Reserved.
36693 *
36694 * Use of this source code is governed by an MIT-style license that can be
36695 * found in the LICENSE file at https://angular.io/license
36696 */
36697 const SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__ = noop;
36698 const SWITCH_TEMPLATE_REF_FACTORY = SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__;
36699 /**
36700 * Represents an embedded template that can be used to instantiate embedded views.
36701 * To instantiate embedded views based on a template, use the `ViewContainerRef`
36702 * method `createEmbeddedView()`.
36703 *
36704 * Access a `TemplateRef` instance by placing a directive on an `<ng-template>`
36705 * element (or directive prefixed with `*`). The `TemplateRef` for the embedded view
36706 * is injected into the constructor of the directive,
36707 * using the `TemplateRef` token.
36708 *
36709 * You can also use a `Query` to find a `TemplateRef` associated with
36710 * a component or a directive.
36711 *
36712 * @see `ViewContainerRef`
36713 * @see [Navigate the Component Tree with DI](guide/dependency-injection-navtree)
36714 *
36715 * @publicApi
36716 */
36717 class TemplateRef {
36718 }
36719 /**
36720 * @internal
36721 * @nocollapse
36722 */
36723 TemplateRef.__NG_ELEMENT_ID__ = SWITCH_TEMPLATE_REF_FACTORY;
36724
36725 /**
36726 * @license
36727 * Copyright Google LLC All Rights Reserved.
36728 *
36729 * Use of this source code is governed by an MIT-style license that can be
36730 * found in the LICENSE file at https://angular.io/license
36731 */
36732 /**
36733 * Represents an instance of an `NgModule` created by an `NgModuleFactory`.
36734 * Provides access to the `NgModule` instance and related objects.
36735 *
36736 * @publicApi
36737 */
36738 class NgModuleRef {
36739 }
36740
36741 /**
36742 * @license
36743 * Copyright Google LLC All Rights Reserved.
36744 *
36745 * Use of this source code is governed by an MIT-style license that can be
36746 * found in the LICENSE file at https://angular.io/license
36747 */
36748 const SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__ = noop;
36749 const SWITCH_VIEW_CONTAINER_REF_FACTORY = SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__;
36750 /**
36751 * Represents a container where one or more views can be attached to a component.
36752 *
36753 * Can contain *host views* (created by instantiating a
36754 * component with the `createComponent()` method), and *embedded views*
36755 * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
36756 *
36757 * A view container instance can contain other view containers,
36758 * creating a [view hierarchy](guide/glossary#view-tree).
36759 *
36760 * @see `ComponentRef`
36761 * @see `EmbeddedViewRef`
36762 *
36763 * @publicApi
36764 */
36765 class ViewContainerRef {
36766 }
36767 /**
36768 * @internal
36769 * @nocollapse
36770 */
36771 ViewContainerRef.__NG_ELEMENT_ID__ = SWITCH_VIEW_CONTAINER_REF_FACTORY;
36772
36773 /**
36774 * @license
36775 * Copyright Google LLC All Rights Reserved.
36776 *
36777 * Use of this source code is governed by an MIT-style license that can be
36778 * found in the LICENSE file at https://angular.io/license
36779 */
36780 const _tokenKeyCache = new Map();
36781 function tokenKey(token) {
36782 let key = _tokenKeyCache.get(token);
36783 if (!key) {
36784 key = stringify$1(token) + '_' + _tokenKeyCache.size;
36785 _tokenKeyCache.set(token, key);
36786 }
36787 return key;
36788 }
36789
36790 /**
36791 * @license
36792 * Copyright Google LLC All Rights Reserved.
36793 *
36794 * Use of this source code is governed by an MIT-style license that can be
36795 * found in the LICENSE file at https://angular.io/license
36796 */
36797 const InjectorRefTokenKey = tokenKey(Injector);
36798 const INJECTORRefTokenKey = tokenKey(INJECTOR$1);
36799 const NgModuleRefTokenKey = tokenKey(NgModuleRef);
36800
36801 /**
36802 * @license
36803 * Copyright Google LLC All Rights Reserved.
36804 *
36805 * Use of this source code is governed by an MIT-style license that can be
36806 * found in the LICENSE file at https://angular.io/license
36807 */
36808 const Renderer2TokenKey = tokenKey(Renderer2);
36809 const ElementRefTokenKey = tokenKey(ElementRef);
36810 const ViewContainerRefTokenKey = tokenKey(ViewContainerRef);
36811 const TemplateRefTokenKey = tokenKey(TemplateRef);
36812 const ChangeDetectorRefTokenKey = tokenKey(ChangeDetectorRef);
36813 const InjectorRefTokenKey$1 = tokenKey(Injector);
36814 const INJECTORRefTokenKey$1 = tokenKey(INJECTOR$1);
36815 // This default value is when checking the hierarchy for a token.
36816 //
36817 // It means both:
36818 // - the token is not provided by the current injector,
36819 // - only the element injectors should be checked (ie do not check module injectors
36820 //
36821 // mod1
36822 // /
36823 // el1 mod2
36824 // \ /
36825 // el2
36826 //
36827 // When requesting el2.injector.get(token), we should check in the following order and return the
36828 // first found value:
36829 // - el2.injector.get(token, default)
36830 // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
36831 // - mod2.injector.get(token, default)
36832 const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
36833
36834 /**
36835 * @license
36836 * Copyright Google LLC All Rights Reserved.
36837 *
36838 * Use of this source code is governed by an MIT-style license that can be
36839 * found in the LICENSE file at https://angular.io/license
36840 */
36841 class ComponentFactoryResolver$1 extends ComponentFactoryResolver {
36842 /**
36843 * @param ngModule The NgModuleRef to which all resolved factories are bound.
36844 */
36845 constructor(ngModule) {
36846 super();
36847 this.ngModule = ngModule;
36848 }
36849 resolveComponentFactory(component) {
36850 ngDevMode && assertComponentType(component);
36851 const componentDef = getComponentDef(component);
36852 return new ComponentFactory$1(componentDef, this.ngModule);
36853 }
36854 }
36855 function toRefArray(map) {
36856 const array = [];
36857 for (let nonMinified in map) {
36858 if (map.hasOwnProperty(nonMinified)) {
36859 const minified = map[nonMinified];
36860 array.push({ propName: minified, templateName: nonMinified });
36861 }
36862 }
36863 return array;
36864 }
36865 function getNamespace(elementName) {
36866 const name = elementName.toLowerCase();
36867 return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null);
36868 }
36869 /**
36870 * A change detection scheduler token for {@link RootContext}. This token is the default value used
36871 * for the default `RootContext` found in the {@link ROOT_CONTEXT} token.
36872 */
36873 const SCHEDULER = new InjectionToken('SCHEDULER_TOKEN', {
36874 providedIn: 'root',
36875 factory: () => defaultScheduler,
36876 });
36877 function createChainedInjector(rootViewInjector, moduleInjector) {
36878 return {
36879 get: (token, notFoundValue, flags) => {
36880 const value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
36881 if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
36882 notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
36883 // Return the value from the root element injector when
36884 // - it provides it
36885 // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
36886 // - the module injector should not be checked
36887 // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR)
36888 return value;
36889 }
36890 return moduleInjector.get(token, notFoundValue, flags);
36891 }
36892 };
36893 }
36894 /**
36895 * Render3 implementation of {@link viewEngine_ComponentFactory}.
36896 */
36897 class ComponentFactory$1 extends ComponentFactory {
36898 /**
36899 * @param componentDef The component definition.
36900 * @param ngModule The NgModuleRef to which the factory is bound.
36901 */
36902 constructor(componentDef, ngModule) {
36903 super();
36904 this.componentDef = componentDef;
36905 this.ngModule = ngModule;
36906 this.componentType = componentDef.type;
36907 this.selector = stringifyCSSSelectorList(componentDef.selectors);
36908 this.ngContentSelectors =
36909 componentDef.ngContentSelectors ? componentDef.ngContentSelectors : [];
36910 this.isBoundToModule = !!ngModule;
36911 }
36912 get inputs() {
36913 return toRefArray(this.componentDef.inputs);
36914 }
36915 get outputs() {
36916 return toRefArray(this.componentDef.outputs);
36917 }
36918 create(injector, projectableNodes, rootSelectorOrNode, ngModule) {
36919 ngModule = ngModule || this.ngModule;
36920 const rootViewInjector = ngModule ? createChainedInjector(injector, ngModule.injector) : injector;
36921 const rendererFactory = rootViewInjector.get(RendererFactory2, domRendererFactory3);
36922 const sanitizer = rootViewInjector.get(Sanitizer, null);
36923 const hostRenderer = rendererFactory.createRenderer(null, this.componentDef);
36924 // Determine a tag name used for creating host elements when this component is created
36925 // dynamically. Default to 'div' if this component did not specify any tag name in its selector.
36926 const elementName = this.componentDef.selectors[0][0] || 'div';
36927 const hostRNode = rootSelectorOrNode ?
36928 locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) :
36929 createElementNode(rendererFactory.createRenderer(null, this.componentDef), elementName, getNamespace(elementName));
36930 const rootFlags = this.componentDef.onPush ? 64 /* Dirty */ | 512 /* IsRoot */ :
36931 16 /* CheckAlways */ | 512 /* IsRoot */;
36932 const rootContext = createRootContext();
36933 // Create the root view. Uses empty TView and ContentTemplate.
36934 const rootTView = createTView(0 /* Root */, null, null, 1, 0, null, null, null, null, null);
36935 const rootLView = createLView(null, rootTView, rootContext, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector);
36936 // rootView is the parent when bootstrapping
36937 // TODO(misko): it looks like we are entering view here but we don't really need to as
36938 // `renderView` does that. However as the code is written it is needed because
36939 // `createRootComponentView` and `createRootComponent` both read global state. Fixing those
36940 // issues would allow us to drop this.
36941 enterView(rootLView);
36942 let component;
36943 let tElementNode;
36944 try {
36945 const componentView = createRootComponentView(hostRNode, this.componentDef, rootLView, rendererFactory, hostRenderer);
36946 if (hostRNode) {
36947 if (rootSelectorOrNode) {
36948 setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION$2.full]);
36949 }
36950 else {
36951 // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
36952 // is not defined), also apply attributes and classes extracted from component selector.
36953 // Extract attributes and classes from the first selector only to match VE behavior.
36954 const { attrs, classes } = extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
36955 if (attrs) {
36956 setUpAttributes(hostRenderer, hostRNode, attrs);
36957 }
36958 if (classes && classes.length > 0) {
36959 writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
36960 }
36961 }
36962 }
36963 tElementNode = getTNode(rootTView, HEADER_OFFSET);
36964 if (projectableNodes !== undefined) {
36965 const projection = tElementNode.projection = [];
36966 for (let i = 0; i < this.ngContentSelectors.length; i++) {
36967 const nodesforSlot = projectableNodes[i];
36968 // Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
36969 // case). Here we do normalize passed data structure to be an array of arrays to avoid
36970 // complex checks down the line.
36971 // We also normalize the length of the passed in projectable nodes (to match the number of
36972 // <ng-container> slots defined by a component).
36973 projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
36974 }
36975 }
36976 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
36977 // executed here?
36978 // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
36979 component = createRootComponent(componentView, this.componentDef, rootLView, rootContext, [LifecycleHooksFeature]);
36980 renderView(rootTView, rootLView, null);
36981 }
36982 finally {
36983 leaveView();
36984 }
36985 return new ComponentRef$1(this.componentType, component, createElementRef(tElementNode, rootLView), rootLView, tElementNode);
36986 }
36987 }
36988 const componentFactoryResolver = new ComponentFactoryResolver$1();
36989 /**
36990 * Represents an instance of a Component created via a {@link ComponentFactory}.
36991 *
36992 * `ComponentRef` provides access to the Component Instance as well other objects related to this
36993 * Component Instance and allows you to destroy the Component Instance via the {@link #destroy}
36994 * method.
36995 *
36996 */
36997 class ComponentRef$1 extends ComponentRef {
36998 constructor(componentType, instance, location, _rootLView, _tNode) {
36999 super();
37000 this.location = location;
37001 this._rootLView = _rootLView;
37002 this._tNode = _tNode;
37003 this.instance = instance;
37004 this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView);
37005 this.componentType = componentType;
37006 }
37007 get injector() {
37008 return new NodeInjector(this._tNode, this._rootLView);
37009 }
37010 destroy() {
37011 this.hostView.destroy();
37012 }
37013 onDestroy(callback) {
37014 this.hostView.onDestroy(callback);
37015 }
37016 }
37017
37018 /*! *****************************************************************************
37019 Copyright (c) Microsoft Corporation. All rights reserved.
37020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use
37021 this file except in compliance with the License. You may obtain a copy of the
37022 License at http://www.apache.org/licenses/LICENSE-2.0
37023
37024 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
37025 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
37026 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
37027 MERCHANTABLITY OR NON-INFRINGEMENT.
37028
37029 See the Apache Version 2.0 License for specific language governing permissions
37030 and limitations under the License.
37031 ***************************************************************************** */
37032 /* global Reflect, Promise */
37033
37034 var extendStatics = function(d, b) {
37035 extendStatics = Object.setPrototypeOf ||
37036 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
37037 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
37038 return extendStatics(d, b);
37039 };
37040
37041 function __extends(d, b) {
37042 extendStatics(d, b);
37043 function __() { this.constructor = d; }
37044 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
37045 }
37046
37047 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37048 function isFunction(x) {
37049 return typeof x === 'function';
37050 }
37051
37052 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37053 var _enable_super_gross_mode_that_will_cause_bad_things = false;
37054 var config = {
37055 Promise: undefined,
37056 set useDeprecatedSynchronousErrorHandling(value) {
37057 if (value) {
37058 var error = /*@__PURE__*/ new Error();
37059 /*@__PURE__*/ console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n' + error.stack);
37060 }
37061 _enable_super_gross_mode_that_will_cause_bad_things = value;
37062 },
37063 get useDeprecatedSynchronousErrorHandling() {
37064 return _enable_super_gross_mode_that_will_cause_bad_things;
37065 },
37066 };
37067
37068 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37069 function hostReportError(err) {
37070 setTimeout(function () { throw err; }, 0);
37071 }
37072
37073 /** PURE_IMPORTS_START _config,_util_hostReportError PURE_IMPORTS_END */
37074 var empty = {
37075 closed: true,
37076 next: function (value) { },
37077 error: function (err) {
37078 if (config.useDeprecatedSynchronousErrorHandling) {
37079 throw err;
37080 }
37081 else {
37082 hostReportError(err);
37083 }
37084 },
37085 complete: function () { }
37086 };
37087
37088 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37089 var isArray = /*@__PURE__*/ (function () { return Array.isArray || (function (x) { return x && typeof x.length === 'number'; }); })();
37090
37091 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37092 function isObject(x) {
37093 return x !== null && typeof x === 'object';
37094 }
37095
37096 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37097 var UnsubscriptionErrorImpl = /*@__PURE__*/ (function () {
37098 function UnsubscriptionErrorImpl(errors) {
37099 Error.call(this);
37100 this.message = errors ?
37101 errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { return i + 1 + ") " + err.toString(); }).join('\n ') : '';
37102 this.name = 'UnsubscriptionError';
37103 this.errors = errors;
37104 return this;
37105 }
37106 UnsubscriptionErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
37107 return UnsubscriptionErrorImpl;
37108 })();
37109 var UnsubscriptionError = UnsubscriptionErrorImpl;
37110
37111 /** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_UnsubscriptionError PURE_IMPORTS_END */
37112 var Subscription = /*@__PURE__*/ (function () {
37113 function Subscription(unsubscribe) {
37114 this.closed = false;
37115 this._parentOrParents = null;
37116 this._subscriptions = null;
37117 if (unsubscribe) {
37118 this._unsubscribe = unsubscribe;
37119 }
37120 }
37121 Subscription.prototype.unsubscribe = function () {
37122 var errors;
37123 if (this.closed) {
37124 return;
37125 }
37126 var _a = this, _parentOrParents = _a._parentOrParents, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions;
37127 this.closed = true;
37128 this._parentOrParents = null;
37129 this._subscriptions = null;
37130 if (_parentOrParents instanceof Subscription) {
37131 _parentOrParents.remove(this);
37132 }
37133 else if (_parentOrParents !== null) {
37134 for (var index = 0; index < _parentOrParents.length; ++index) {
37135 var parent_1 = _parentOrParents[index];
37136 parent_1.remove(this);
37137 }
37138 }
37139 if (isFunction(_unsubscribe)) {
37140 try {
37141 _unsubscribe.call(this);
37142 }
37143 catch (e) {
37144 errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e];
37145 }
37146 }
37147 if (isArray(_subscriptions)) {
37148 var index = -1;
37149 var len = _subscriptions.length;
37150 while (++index < len) {
37151 var sub = _subscriptions[index];
37152 if (isObject(sub)) {
37153 try {
37154 sub.unsubscribe();
37155 }
37156 catch (e) {
37157 errors = errors || [];
37158 if (e instanceof UnsubscriptionError) {
37159 errors = errors.concat(flattenUnsubscriptionErrors(e.errors));
37160 }
37161 else {
37162 errors.push(e);
37163 }
37164 }
37165 }
37166 }
37167 }
37168 if (errors) {
37169 throw new UnsubscriptionError(errors);
37170 }
37171 };
37172 Subscription.prototype.add = function (teardown) {
37173 var subscription = teardown;
37174 if (!teardown) {
37175 return Subscription.EMPTY;
37176 }
37177 switch (typeof teardown) {
37178 case 'function':
37179 subscription = new Subscription(teardown);
37180 case 'object':
37181 if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') {
37182 return subscription;
37183 }
37184 else if (this.closed) {
37185 subscription.unsubscribe();
37186 return subscription;
37187 }
37188 else if (!(subscription instanceof Subscription)) {
37189 var tmp = subscription;
37190 subscription = new Subscription();
37191 subscription._subscriptions = [tmp];
37192 }
37193 break;
37194 default: {
37195 throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');
37196 }
37197 }
37198 var _parentOrParents = subscription._parentOrParents;
37199 if (_parentOrParents === null) {
37200 subscription._parentOrParents = this;
37201 }
37202 else if (_parentOrParents instanceof Subscription) {
37203 if (_parentOrParents === this) {
37204 return subscription;
37205 }
37206 subscription._parentOrParents = [_parentOrParents, this];
37207 }
37208 else if (_parentOrParents.indexOf(this) === -1) {
37209 _parentOrParents.push(this);
37210 }
37211 else {
37212 return subscription;
37213 }
37214 var subscriptions = this._subscriptions;
37215 if (subscriptions === null) {
37216 this._subscriptions = [subscription];
37217 }
37218 else {
37219 subscriptions.push(subscription);
37220 }
37221 return subscription;
37222 };
37223 Subscription.prototype.remove = function (subscription) {
37224 var subscriptions = this._subscriptions;
37225 if (subscriptions) {
37226 var subscriptionIndex = subscriptions.indexOf(subscription);
37227 if (subscriptionIndex !== -1) {
37228 subscriptions.splice(subscriptionIndex, 1);
37229 }
37230 }
37231 };
37232 Subscription.EMPTY = (function (empty) {
37233 empty.closed = true;
37234 return empty;
37235 }(new Subscription()));
37236 return Subscription;
37237 }());
37238 function flattenUnsubscriptionErrors(errors) {
37239 return errors.reduce(function (errs, err) { return errs.concat((err instanceof UnsubscriptionError) ? err.errors : err); }, []);
37240 }
37241
37242 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37243 var rxSubscriber = /*@__PURE__*/ (function () {
37244 return typeof Symbol === 'function'
37245 ? /*@__PURE__*/ Symbol('rxSubscriber')
37246 : '@@rxSubscriber_' + /*@__PURE__*/ Math.random();
37247 })();
37248
37249 /** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */
37250 var Subscriber = /*@__PURE__*/ (function (_super) {
37251 __extends(Subscriber, _super);
37252 function Subscriber(destinationOrNext, error, complete) {
37253 var _this = _super.call(this) || this;
37254 _this.syncErrorValue = null;
37255 _this.syncErrorThrown = false;
37256 _this.syncErrorThrowable = false;
37257 _this.isStopped = false;
37258 switch (arguments.length) {
37259 case 0:
37260 _this.destination = empty;
37261 break;
37262 case 1:
37263 if (!destinationOrNext) {
37264 _this.destination = empty;
37265 break;
37266 }
37267 if (typeof destinationOrNext === 'object') {
37268 if (destinationOrNext instanceof Subscriber) {
37269 _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable;
37270 _this.destination = destinationOrNext;
37271 destinationOrNext.add(_this);
37272 }
37273 else {
37274 _this.syncErrorThrowable = true;
37275 _this.destination = new SafeSubscriber(_this, destinationOrNext);
37276 }
37277 break;
37278 }
37279 default:
37280 _this.syncErrorThrowable = true;
37281 _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete);
37282 break;
37283 }
37284 return _this;
37285 }
37286 Subscriber.prototype[rxSubscriber] = function () { return this; };
37287 Subscriber.create = function (next, error, complete) {
37288 var subscriber = new Subscriber(next, error, complete);
37289 subscriber.syncErrorThrowable = false;
37290 return subscriber;
37291 };
37292 Subscriber.prototype.next = function (value) {
37293 if (!this.isStopped) {
37294 this._next(value);
37295 }
37296 };
37297 Subscriber.prototype.error = function (err) {
37298 if (!this.isStopped) {
37299 this.isStopped = true;
37300 this._error(err);
37301 }
37302 };
37303 Subscriber.prototype.complete = function () {
37304 if (!this.isStopped) {
37305 this.isStopped = true;
37306 this._complete();
37307 }
37308 };
37309 Subscriber.prototype.unsubscribe = function () {
37310 if (this.closed) {
37311 return;
37312 }
37313 this.isStopped = true;
37314 _super.prototype.unsubscribe.call(this);
37315 };
37316 Subscriber.prototype._next = function (value) {
37317 this.destination.next(value);
37318 };
37319 Subscriber.prototype._error = function (err) {
37320 this.destination.error(err);
37321 this.unsubscribe();
37322 };
37323 Subscriber.prototype._complete = function () {
37324 this.destination.complete();
37325 this.unsubscribe();
37326 };
37327 Subscriber.prototype._unsubscribeAndRecycle = function () {
37328 var _parentOrParents = this._parentOrParents;
37329 this._parentOrParents = null;
37330 this.unsubscribe();
37331 this.closed = false;
37332 this.isStopped = false;
37333 this._parentOrParents = _parentOrParents;
37334 return this;
37335 };
37336 return Subscriber;
37337 }(Subscription));
37338 var SafeSubscriber = /*@__PURE__*/ (function (_super) {
37339 __extends(SafeSubscriber, _super);
37340 function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) {
37341 var _this = _super.call(this) || this;
37342 _this._parentSubscriber = _parentSubscriber;
37343 var next;
37344 var context = _this;
37345 if (isFunction(observerOrNext)) {
37346 next = observerOrNext;
37347 }
37348 else if (observerOrNext) {
37349 next = observerOrNext.next;
37350 error = observerOrNext.error;
37351 complete = observerOrNext.complete;
37352 if (observerOrNext !== empty) {
37353 context = Object.create(observerOrNext);
37354 if (isFunction(context.unsubscribe)) {
37355 _this.add(context.unsubscribe.bind(context));
37356 }
37357 context.unsubscribe = _this.unsubscribe.bind(_this);
37358 }
37359 }
37360 _this._context = context;
37361 _this._next = next;
37362 _this._error = error;
37363 _this._complete = complete;
37364 return _this;
37365 }
37366 SafeSubscriber.prototype.next = function (value) {
37367 if (!this.isStopped && this._next) {
37368 var _parentSubscriber = this._parentSubscriber;
37369 if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
37370 this.__tryOrUnsub(this._next, value);
37371 }
37372 else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
37373 this.unsubscribe();
37374 }
37375 }
37376 };
37377 SafeSubscriber.prototype.error = function (err) {
37378 if (!this.isStopped) {
37379 var _parentSubscriber = this._parentSubscriber;
37380 var useDeprecatedSynchronousErrorHandling = config.useDeprecatedSynchronousErrorHandling;
37381 if (this._error) {
37382 if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
37383 this.__tryOrUnsub(this._error, err);
37384 this.unsubscribe();
37385 }
37386 else {
37387 this.__tryOrSetError(_parentSubscriber, this._error, err);
37388 this.unsubscribe();
37389 }
37390 }
37391 else if (!_parentSubscriber.syncErrorThrowable) {
37392 this.unsubscribe();
37393 if (useDeprecatedSynchronousErrorHandling) {
37394 throw err;
37395 }
37396 hostReportError(err);
37397 }
37398 else {
37399 if (useDeprecatedSynchronousErrorHandling) {
37400 _parentSubscriber.syncErrorValue = err;
37401 _parentSubscriber.syncErrorThrown = true;
37402 }
37403 else {
37404 hostReportError(err);
37405 }
37406 this.unsubscribe();
37407 }
37408 }
37409 };
37410 SafeSubscriber.prototype.complete = function () {
37411 var _this = this;
37412 if (!this.isStopped) {
37413 var _parentSubscriber = this._parentSubscriber;
37414 if (this._complete) {
37415 var wrappedComplete = function () { return _this._complete.call(_this._context); };
37416 if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
37417 this.__tryOrUnsub(wrappedComplete);
37418 this.unsubscribe();
37419 }
37420 else {
37421 this.__tryOrSetError(_parentSubscriber, wrappedComplete);
37422 this.unsubscribe();
37423 }
37424 }
37425 else {
37426 this.unsubscribe();
37427 }
37428 }
37429 };
37430 SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) {
37431 try {
37432 fn.call(this._context, value);
37433 }
37434 catch (err) {
37435 this.unsubscribe();
37436 if (config.useDeprecatedSynchronousErrorHandling) {
37437 throw err;
37438 }
37439 else {
37440 hostReportError(err);
37441 }
37442 }
37443 };
37444 SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) {
37445 if (!config.useDeprecatedSynchronousErrorHandling) {
37446 throw new Error('bad call');
37447 }
37448 try {
37449 fn.call(this._context, value);
37450 }
37451 catch (err) {
37452 if (config.useDeprecatedSynchronousErrorHandling) {
37453 parent.syncErrorValue = err;
37454 parent.syncErrorThrown = true;
37455 return true;
37456 }
37457 else {
37458 hostReportError(err);
37459 return true;
37460 }
37461 }
37462 return false;
37463 };
37464 SafeSubscriber.prototype._unsubscribe = function () {
37465 var _parentSubscriber = this._parentSubscriber;
37466 this._context = null;
37467 this._parentSubscriber = null;
37468 _parentSubscriber.unsubscribe();
37469 };
37470 return SafeSubscriber;
37471 }(Subscriber));
37472
37473 /** PURE_IMPORTS_START _Subscriber PURE_IMPORTS_END */
37474 function canReportError(observer) {
37475 while (observer) {
37476 var _a = observer, closed_1 = _a.closed, destination = _a.destination, isStopped = _a.isStopped;
37477 if (closed_1 || isStopped) {
37478 return false;
37479 }
37480 else if (destination && destination instanceof Subscriber) {
37481 observer = destination;
37482 }
37483 else {
37484 observer = null;
37485 }
37486 }
37487 return true;
37488 }
37489
37490 /** PURE_IMPORTS_START _Subscriber,_symbol_rxSubscriber,_Observer PURE_IMPORTS_END */
37491 function toSubscriber(nextOrObserver, error, complete) {
37492 if (nextOrObserver) {
37493 if (nextOrObserver instanceof Subscriber) {
37494 return nextOrObserver;
37495 }
37496 if (nextOrObserver[rxSubscriber]) {
37497 return nextOrObserver[rxSubscriber]();
37498 }
37499 }
37500 if (!nextOrObserver && !error && !complete) {
37501 return new Subscriber(empty);
37502 }
37503 return new Subscriber(nextOrObserver, error, complete);
37504 }
37505
37506 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37507 var observable = /*@__PURE__*/ (function () { return typeof Symbol === 'function' && Symbol.observable || '@@observable'; })();
37508
37509 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37510 function noop$1() { }
37511
37512 /** PURE_IMPORTS_START _noop PURE_IMPORTS_END */
37513 function pipeFromArray(fns) {
37514 if (!fns) {
37515 return noop$1;
37516 }
37517 if (fns.length === 1) {
37518 return fns[0];
37519 }
37520 return function piped(input) {
37521 return fns.reduce(function (prev, fn) { return fn(prev); }, input);
37522 };
37523 }
37524
37525 /** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */
37526 var Observable = /*@__PURE__*/ (function () {
37527 function Observable(subscribe) {
37528 this._isScalar = false;
37529 if (subscribe) {
37530 this._subscribe = subscribe;
37531 }
37532 }
37533 Observable.prototype.lift = function (operator) {
37534 var observable = new Observable();
37535 observable.source = this;
37536 observable.operator = operator;
37537 return observable;
37538 };
37539 Observable.prototype.subscribe = function (observerOrNext, error, complete) {
37540 var operator = this.operator;
37541 var sink = toSubscriber(observerOrNext, error, complete);
37542 if (operator) {
37543 sink.add(operator.call(sink, this.source));
37544 }
37545 else {
37546 sink.add(this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ?
37547 this._subscribe(sink) :
37548 this._trySubscribe(sink));
37549 }
37550 if (config.useDeprecatedSynchronousErrorHandling) {
37551 if (sink.syncErrorThrowable) {
37552 sink.syncErrorThrowable = false;
37553 if (sink.syncErrorThrown) {
37554 throw sink.syncErrorValue;
37555 }
37556 }
37557 }
37558 return sink;
37559 };
37560 Observable.prototype._trySubscribe = function (sink) {
37561 try {
37562 return this._subscribe(sink);
37563 }
37564 catch (err) {
37565 if (config.useDeprecatedSynchronousErrorHandling) {
37566 sink.syncErrorThrown = true;
37567 sink.syncErrorValue = err;
37568 }
37569 if (canReportError(sink)) {
37570 sink.error(err);
37571 }
37572 else {
37573 console.warn(err);
37574 }
37575 }
37576 };
37577 Observable.prototype.forEach = function (next, promiseCtor) {
37578 var _this = this;
37579 promiseCtor = getPromiseCtor(promiseCtor);
37580 return new promiseCtor(function (resolve, reject) {
37581 var subscription;
37582 subscription = _this.subscribe(function (value) {
37583 try {
37584 next(value);
37585 }
37586 catch (err) {
37587 reject(err);
37588 if (subscription) {
37589 subscription.unsubscribe();
37590 }
37591 }
37592 }, reject, resolve);
37593 });
37594 };
37595 Observable.prototype._subscribe = function (subscriber) {
37596 var source = this.source;
37597 return source && source.subscribe(subscriber);
37598 };
37599 Observable.prototype[observable] = function () {
37600 return this;
37601 };
37602 Observable.prototype.pipe = function () {
37603 var operations = [];
37604 for (var _i = 0; _i < arguments.length; _i++) {
37605 operations[_i] = arguments[_i];
37606 }
37607 if (operations.length === 0) {
37608 return this;
37609 }
37610 return pipeFromArray(operations)(this);
37611 };
37612 Observable.prototype.toPromise = function (promiseCtor) {
37613 var _this = this;
37614 promiseCtor = getPromiseCtor(promiseCtor);
37615 return new promiseCtor(function (resolve, reject) {
37616 var value;
37617 _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); });
37618 });
37619 };
37620 Observable.create = function (subscribe) {
37621 return new Observable(subscribe);
37622 };
37623 return Observable;
37624 }());
37625 function getPromiseCtor(promiseCtor) {
37626 if (!promiseCtor) {
37627 promiseCtor = Promise;
37628 }
37629 if (!promiseCtor) {
37630 throw new Error('no Promise impl found');
37631 }
37632 return promiseCtor;
37633 }
37634
37635 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37636 var ObjectUnsubscribedErrorImpl = /*@__PURE__*/ (function () {
37637 function ObjectUnsubscribedErrorImpl() {
37638 Error.call(this);
37639 this.message = 'object unsubscribed';
37640 this.name = 'ObjectUnsubscribedError';
37641 return this;
37642 }
37643 ObjectUnsubscribedErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
37644 return ObjectUnsubscribedErrorImpl;
37645 })();
37646 var ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl;
37647
37648 /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */
37649 var SubjectSubscription = /*@__PURE__*/ (function (_super) {
37650 __extends(SubjectSubscription, _super);
37651 function SubjectSubscription(subject, subscriber) {
37652 var _this = _super.call(this) || this;
37653 _this.subject = subject;
37654 _this.subscriber = subscriber;
37655 _this.closed = false;
37656 return _this;
37657 }
37658 SubjectSubscription.prototype.unsubscribe = function () {
37659 if (this.closed) {
37660 return;
37661 }
37662 this.closed = true;
37663 var subject = this.subject;
37664 var observers = subject.observers;
37665 this.subject = null;
37666 if (!observers || observers.length === 0 || subject.isStopped || subject.closed) {
37667 return;
37668 }
37669 var subscriberIndex = observers.indexOf(this.subscriber);
37670 if (subscriberIndex !== -1) {
37671 observers.splice(subscriberIndex, 1);
37672 }
37673 };
37674 return SubjectSubscription;
37675 }(Subscription));
37676
37677 /** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */
37678 var SubjectSubscriber = /*@__PURE__*/ (function (_super) {
37679 __extends(SubjectSubscriber, _super);
37680 function SubjectSubscriber(destination) {
37681 var _this = _super.call(this, destination) || this;
37682 _this.destination = destination;
37683 return _this;
37684 }
37685 return SubjectSubscriber;
37686 }(Subscriber));
37687 var Subject = /*@__PURE__*/ (function (_super) {
37688 __extends(Subject, _super);
37689 function Subject() {
37690 var _this = _super.call(this) || this;
37691 _this.observers = [];
37692 _this.closed = false;
37693 _this.isStopped = false;
37694 _this.hasError = false;
37695 _this.thrownError = null;
37696 return _this;
37697 }
37698 Subject.prototype[rxSubscriber] = function () {
37699 return new SubjectSubscriber(this);
37700 };
37701 Subject.prototype.lift = function (operator) {
37702 var subject = new AnonymousSubject(this, this);
37703 subject.operator = operator;
37704 return subject;
37705 };
37706 Subject.prototype.next = function (value) {
37707 if (this.closed) {
37708 throw new ObjectUnsubscribedError();
37709 }
37710 if (!this.isStopped) {
37711 var observers = this.observers;
37712 var len = observers.length;
37713 var copy = observers.slice();
37714 for (var i = 0; i < len; i++) {
37715 copy[i].next(value);
37716 }
37717 }
37718 };
37719 Subject.prototype.error = function (err) {
37720 if (this.closed) {
37721 throw new ObjectUnsubscribedError();
37722 }
37723 this.hasError = true;
37724 this.thrownError = err;
37725 this.isStopped = true;
37726 var observers = this.observers;
37727 var len = observers.length;
37728 var copy = observers.slice();
37729 for (var i = 0; i < len; i++) {
37730 copy[i].error(err);
37731 }
37732 this.observers.length = 0;
37733 };
37734 Subject.prototype.complete = function () {
37735 if (this.closed) {
37736 throw new ObjectUnsubscribedError();
37737 }
37738 this.isStopped = true;
37739 var observers = this.observers;
37740 var len = observers.length;
37741 var copy = observers.slice();
37742 for (var i = 0; i < len; i++) {
37743 copy[i].complete();
37744 }
37745 this.observers.length = 0;
37746 };
37747 Subject.prototype.unsubscribe = function () {
37748 this.isStopped = true;
37749 this.closed = true;
37750 this.observers = null;
37751 };
37752 Subject.prototype._trySubscribe = function (subscriber) {
37753 if (this.closed) {
37754 throw new ObjectUnsubscribedError();
37755 }
37756 else {
37757 return _super.prototype._trySubscribe.call(this, subscriber);
37758 }
37759 };
37760 Subject.prototype._subscribe = function (subscriber) {
37761 if (this.closed) {
37762 throw new ObjectUnsubscribedError();
37763 }
37764 else if (this.hasError) {
37765 subscriber.error(this.thrownError);
37766 return Subscription.EMPTY;
37767 }
37768 else if (this.isStopped) {
37769 subscriber.complete();
37770 return Subscription.EMPTY;
37771 }
37772 else {
37773 this.observers.push(subscriber);
37774 return new SubjectSubscription(this, subscriber);
37775 }
37776 };
37777 Subject.prototype.asObservable = function () {
37778 var observable = new Observable();
37779 observable.source = this;
37780 return observable;
37781 };
37782 Subject.create = function (destination, source) {
37783 return new AnonymousSubject(destination, source);
37784 };
37785 return Subject;
37786 }(Observable));
37787 var AnonymousSubject = /*@__PURE__*/ (function (_super) {
37788 __extends(AnonymousSubject, _super);
37789 function AnonymousSubject(destination, source) {
37790 var _this = _super.call(this) || this;
37791 _this.destination = destination;
37792 _this.source = source;
37793 return _this;
37794 }
37795 AnonymousSubject.prototype.next = function (value) {
37796 var destination = this.destination;
37797 if (destination && destination.next) {
37798 destination.next(value);
37799 }
37800 };
37801 AnonymousSubject.prototype.error = function (err) {
37802 var destination = this.destination;
37803 if (destination && destination.error) {
37804 this.destination.error(err);
37805 }
37806 };
37807 AnonymousSubject.prototype.complete = function () {
37808 var destination = this.destination;
37809 if (destination && destination.complete) {
37810 this.destination.complete();
37811 }
37812 };
37813 AnonymousSubject.prototype._subscribe = function (subscriber) {
37814 var source = this.source;
37815 if (source) {
37816 return this.source.subscribe(subscriber);
37817 }
37818 else {
37819 return Subscription.EMPTY;
37820 }
37821 };
37822 return AnonymousSubject;
37823 }(Subject));
37824
37825 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
37826 function refCount() {
37827 return function refCountOperatorFunction(source) {
37828 return source.lift(new RefCountOperator(source));
37829 };
37830 }
37831 var RefCountOperator = /*@__PURE__*/ (function () {
37832 function RefCountOperator(connectable) {
37833 this.connectable = connectable;
37834 }
37835 RefCountOperator.prototype.call = function (subscriber, source) {
37836 var connectable = this.connectable;
37837 connectable._refCount++;
37838 var refCounter = new RefCountSubscriber(subscriber, connectable);
37839 var subscription = source.subscribe(refCounter);
37840 if (!refCounter.closed) {
37841 refCounter.connection = connectable.connect();
37842 }
37843 return subscription;
37844 };
37845 return RefCountOperator;
37846 }());
37847 var RefCountSubscriber = /*@__PURE__*/ (function (_super) {
37848 __extends(RefCountSubscriber, _super);
37849 function RefCountSubscriber(destination, connectable) {
37850 var _this = _super.call(this, destination) || this;
37851 _this.connectable = connectable;
37852 return _this;
37853 }
37854 RefCountSubscriber.prototype._unsubscribe = function () {
37855 var connectable = this.connectable;
37856 if (!connectable) {
37857 this.connection = null;
37858 return;
37859 }
37860 this.connectable = null;
37861 var refCount = connectable._refCount;
37862 if (refCount <= 0) {
37863 this.connection = null;
37864 return;
37865 }
37866 connectable._refCount = refCount - 1;
37867 if (refCount > 1) {
37868 this.connection = null;
37869 return;
37870 }
37871 var connection = this.connection;
37872 var sharedConnection = connectable._connection;
37873 this.connection = null;
37874 if (sharedConnection && (!connection || sharedConnection === connection)) {
37875 sharedConnection.unsubscribe();
37876 }
37877 };
37878 return RefCountSubscriber;
37879 }(Subscriber));
37880
37881 /** PURE_IMPORTS_START tslib,_Subject,_Observable,_Subscriber,_Subscription,_operators_refCount PURE_IMPORTS_END */
37882 var ConnectableObservable = /*@__PURE__*/ (function (_super) {
37883 __extends(ConnectableObservable, _super);
37884 function ConnectableObservable(source, subjectFactory) {
37885 var _this = _super.call(this) || this;
37886 _this.source = source;
37887 _this.subjectFactory = subjectFactory;
37888 _this._refCount = 0;
37889 _this._isComplete = false;
37890 return _this;
37891 }
37892 ConnectableObservable.prototype._subscribe = function (subscriber) {
37893 return this.getSubject().subscribe(subscriber);
37894 };
37895 ConnectableObservable.prototype.getSubject = function () {
37896 var subject = this._subject;
37897 if (!subject || subject.isStopped) {
37898 this._subject = this.subjectFactory();
37899 }
37900 return this._subject;
37901 };
37902 ConnectableObservable.prototype.connect = function () {
37903 var connection = this._connection;
37904 if (!connection) {
37905 this._isComplete = false;
37906 connection = this._connection = new Subscription();
37907 connection.add(this.source
37908 .subscribe(new ConnectableSubscriber(this.getSubject(), this)));
37909 if (connection.closed) {
37910 this._connection = null;
37911 connection = Subscription.EMPTY;
37912 }
37913 }
37914 return connection;
37915 };
37916 ConnectableObservable.prototype.refCount = function () {
37917 return refCount()(this);
37918 };
37919 return ConnectableObservable;
37920 }(Observable));
37921 var connectableObservableDescriptor = /*@__PURE__*/ (function () {
37922 var connectableProto = ConnectableObservable.prototype;
37923 return {
37924 operator: { value: null },
37925 _refCount: { value: 0, writable: true },
37926 _subject: { value: null, writable: true },
37927 _connection: { value: null, writable: true },
37928 _subscribe: { value: connectableProto._subscribe },
37929 _isComplete: { value: connectableProto._isComplete, writable: true },
37930 getSubject: { value: connectableProto.getSubject },
37931 connect: { value: connectableProto.connect },
37932 refCount: { value: connectableProto.refCount }
37933 };
37934 })();
37935 var ConnectableSubscriber = /*@__PURE__*/ (function (_super) {
37936 __extends(ConnectableSubscriber, _super);
37937 function ConnectableSubscriber(destination, connectable) {
37938 var _this = _super.call(this, destination) || this;
37939 _this.connectable = connectable;
37940 return _this;
37941 }
37942 ConnectableSubscriber.prototype._error = function (err) {
37943 this._unsubscribe();
37944 _super.prototype._error.call(this, err);
37945 };
37946 ConnectableSubscriber.prototype._complete = function () {
37947 this.connectable._isComplete = true;
37948 this._unsubscribe();
37949 _super.prototype._complete.call(this);
37950 };
37951 ConnectableSubscriber.prototype._unsubscribe = function () {
37952 var connectable = this.connectable;
37953 if (connectable) {
37954 this.connectable = null;
37955 var connection = connectable._connection;
37956 connectable._refCount = 0;
37957 connectable._subject = null;
37958 connectable._connection = null;
37959 if (connection) {
37960 connection.unsubscribe();
37961 }
37962 }
37963 };
37964 return ConnectableSubscriber;
37965 }(SubjectSubscriber));
37966
37967 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37968 function isScheduler(value) {
37969 return value && typeof value.schedule === 'function';
37970 }
37971
37972 /** PURE_IMPORTS_START PURE_IMPORTS_END */
37973 var subscribeToArray = function (array) {
37974 return function (subscriber) {
37975 for (var i = 0, len = array.length; i < len && !subscriber.closed; i++) {
37976 subscriber.next(array[i]);
37977 }
37978 subscriber.complete();
37979 };
37980 };
37981
37982 /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */
37983 function scheduleArray(input, scheduler) {
37984 return new Observable(function (subscriber) {
37985 var sub = new Subscription();
37986 var i = 0;
37987 sub.add(scheduler.schedule(function () {
37988 if (i === input.length) {
37989 subscriber.complete();
37990 return;
37991 }
37992 subscriber.next(input[i++]);
37993 if (!subscriber.closed) {
37994 sub.add(this.schedule());
37995 }
37996 }));
37997 return sub;
37998 });
37999 }
38000
38001 /** PURE_IMPORTS_START _Observable,_util_subscribeToArray,_scheduled_scheduleArray PURE_IMPORTS_END */
38002 function fromArray(input, scheduler) {
38003 if (!scheduler) {
38004 return new Observable(subscribeToArray(input));
38005 }
38006 else {
38007 return scheduleArray(input, scheduler);
38008 }
38009 }
38010
38011 /** PURE_IMPORTS_START PURE_IMPORTS_END */
38012 function identity(x) {
38013 return x;
38014 }
38015
38016 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
38017 function map(project, thisArg) {
38018 return function mapOperation(source) {
38019 if (typeof project !== 'function') {
38020 throw new TypeError('argument is not a function. Are you looking for `mapTo()`?');
38021 }
38022 return source.lift(new MapOperator(project, thisArg));
38023 };
38024 }
38025 var MapOperator = /*@__PURE__*/ (function () {
38026 function MapOperator(project, thisArg) {
38027 this.project = project;
38028 this.thisArg = thisArg;
38029 }
38030 MapOperator.prototype.call = function (subscriber, source) {
38031 return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg));
38032 };
38033 return MapOperator;
38034 }());
38035 var MapSubscriber = /*@__PURE__*/ (function (_super) {
38036 __extends(MapSubscriber, _super);
38037 function MapSubscriber(destination, project, thisArg) {
38038 var _this = _super.call(this, destination) || this;
38039 _this.project = project;
38040 _this.count = 0;
38041 _this.thisArg = thisArg || _this;
38042 return _this;
38043 }
38044 MapSubscriber.prototype._next = function (value) {
38045 var result;
38046 try {
38047 result = this.project.call(this.thisArg, value, this.count++);
38048 }
38049 catch (err) {
38050 this.destination.error(err);
38051 return;
38052 }
38053 this.destination.next(result);
38054 };
38055 return MapSubscriber;
38056 }(Subscriber));
38057
38058 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
38059 var OuterSubscriber = /*@__PURE__*/ (function (_super) {
38060 __extends(OuterSubscriber, _super);
38061 function OuterSubscriber() {
38062 return _super !== null && _super.apply(this, arguments) || this;
38063 }
38064 OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) {
38065 this.destination.next(innerValue);
38066 };
38067 OuterSubscriber.prototype.notifyError = function (error, innerSub) {
38068 this.destination.error(error);
38069 };
38070 OuterSubscriber.prototype.notifyComplete = function (innerSub) {
38071 this.destination.complete();
38072 };
38073 return OuterSubscriber;
38074 }(Subscriber));
38075
38076 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
38077 var InnerSubscriber = /*@__PURE__*/ (function (_super) {
38078 __extends(InnerSubscriber, _super);
38079 function InnerSubscriber(parent, outerValue, outerIndex) {
38080 var _this = _super.call(this) || this;
38081 _this.parent = parent;
38082 _this.outerValue = outerValue;
38083 _this.outerIndex = outerIndex;
38084 _this.index = 0;
38085 return _this;
38086 }
38087 InnerSubscriber.prototype._next = function (value) {
38088 this.parent.notifyNext(this.outerValue, value, this.outerIndex, this.index++, this);
38089 };
38090 InnerSubscriber.prototype._error = function (error) {
38091 this.parent.notifyError(error, this);
38092 this.unsubscribe();
38093 };
38094 InnerSubscriber.prototype._complete = function () {
38095 this.parent.notifyComplete(this);
38096 this.unsubscribe();
38097 };
38098 return InnerSubscriber;
38099 }(Subscriber));
38100
38101 /** PURE_IMPORTS_START _hostReportError PURE_IMPORTS_END */
38102 var subscribeToPromise = function (promise) {
38103 return function (subscriber) {
38104 promise.then(function (value) {
38105 if (!subscriber.closed) {
38106 subscriber.next(value);
38107 subscriber.complete();
38108 }
38109 }, function (err) { return subscriber.error(err); })
38110 .then(null, hostReportError);
38111 return subscriber;
38112 };
38113 };
38114
38115 /** PURE_IMPORTS_START PURE_IMPORTS_END */
38116 function getSymbolIterator$1() {
38117 if (typeof Symbol !== 'function' || !Symbol.iterator) {
38118 return '@@iterator';
38119 }
38120 return Symbol.iterator;
38121 }
38122 var iterator = /*@__PURE__*/ getSymbolIterator$1();
38123
38124 /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */
38125 var subscribeToIterable = function (iterable) {
38126 return function (subscriber) {
38127 var iterator$1 = iterable[iterator]();
38128 do {
38129 var item = iterator$1.next();
38130 if (item.done) {
38131 subscriber.complete();
38132 break;
38133 }
38134 subscriber.next(item.value);
38135 if (subscriber.closed) {
38136 break;
38137 }
38138 } while (true);
38139 if (typeof iterator$1.return === 'function') {
38140 subscriber.add(function () {
38141 if (iterator$1.return) {
38142 iterator$1.return();
38143 }
38144 });
38145 }
38146 return subscriber;
38147 };
38148 };
38149
38150 /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */
38151 var subscribeToObservable = function (obj) {
38152 return function (subscriber) {
38153 var obs = obj[observable]();
38154 if (typeof obs.subscribe !== 'function') {
38155 throw new TypeError('Provided object does not correctly implement Symbol.observable');
38156 }
38157 else {
38158 return obs.subscribe(subscriber);
38159 }
38160 };
38161 };
38162
38163 /** PURE_IMPORTS_START PURE_IMPORTS_END */
38164 var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; });
38165
38166 /** PURE_IMPORTS_START PURE_IMPORTS_END */
38167 function isPromise$2(value) {
38168 return !!value && typeof value.subscribe !== 'function' && typeof value.then === 'function';
38169 }
38170
38171 /** PURE_IMPORTS_START _subscribeToArray,_subscribeToPromise,_subscribeToIterable,_subscribeToObservable,_isArrayLike,_isPromise,_isObject,_symbol_iterator,_symbol_observable PURE_IMPORTS_END */
38172 var subscribeTo = function (result) {
38173 if (!!result && typeof result[observable] === 'function') {
38174 return subscribeToObservable(result);
38175 }
38176 else if (isArrayLike(result)) {
38177 return subscribeToArray(result);
38178 }
38179 else if (isPromise$2(result)) {
38180 return subscribeToPromise(result);
38181 }
38182 else if (!!result && typeof result[iterator] === 'function') {
38183 return subscribeToIterable(result);
38184 }
38185 else {
38186 var value = isObject(result) ? 'an invalid object' : "'" + result + "'";
38187 var msg = "You provided " + value + " where a stream was expected."
38188 + ' You can provide an Observable, Promise, Array, or Iterable.';
38189 throw new TypeError(msg);
38190 }
38191 };
38192
38193 /** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo,_Observable PURE_IMPORTS_END */
38194 function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, innerSubscriber) {
38195 if (innerSubscriber === void 0) {
38196 innerSubscriber = new InnerSubscriber(outerSubscriber, outerValue, outerIndex);
38197 }
38198 if (innerSubscriber.closed) {
38199 return undefined;
38200 }
38201 if (result instanceof Observable) {
38202 return result.subscribe(innerSubscriber);
38203 }
38204 return subscribeTo(result)(innerSubscriber);
38205 }
38206
38207 /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_observable PURE_IMPORTS_END */
38208 function scheduleObservable(input, scheduler) {
38209 return new Observable(function (subscriber) {
38210 var sub = new Subscription();
38211 sub.add(scheduler.schedule(function () {
38212 var observable$1 = input[observable]();
38213 sub.add(observable$1.subscribe({
38214 next: function (value) { sub.add(scheduler.schedule(function () { return subscriber.next(value); })); },
38215 error: function (err) { sub.add(scheduler.schedule(function () { return subscriber.error(err); })); },
38216 complete: function () { sub.add(scheduler.schedule(function () { return subscriber.complete(); })); },
38217 }));
38218 }));
38219 return sub;
38220 });
38221 }
38222
38223 /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */
38224 function schedulePromise(input, scheduler) {
38225 return new Observable(function (subscriber) {
38226 var sub = new Subscription();
38227 sub.add(scheduler.schedule(function () {
38228 return input.then(function (value) {
38229 sub.add(scheduler.schedule(function () {
38230 subscriber.next(value);
38231 sub.add(scheduler.schedule(function () { return subscriber.complete(); }));
38232 }));
38233 }, function (err) {
38234 sub.add(scheduler.schedule(function () { return subscriber.error(err); }));
38235 });
38236 }));
38237 return sub;
38238 });
38239 }
38240
38241 /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_iterator PURE_IMPORTS_END */
38242 function scheduleIterable(input, scheduler) {
38243 if (!input) {
38244 throw new Error('Iterable cannot be null');
38245 }
38246 return new Observable(function (subscriber) {
38247 var sub = new Subscription();
38248 var iterator$1;
38249 sub.add(function () {
38250 if (iterator$1 && typeof iterator$1.return === 'function') {
38251 iterator$1.return();
38252 }
38253 });
38254 sub.add(scheduler.schedule(function () {
38255 iterator$1 = input[iterator]();
38256 sub.add(scheduler.schedule(function () {
38257 if (subscriber.closed) {
38258 return;
38259 }
38260 var value;
38261 var done;
38262 try {
38263 var result = iterator$1.next();
38264 value = result.value;
38265 done = result.done;
38266 }
38267 catch (err) {
38268 subscriber.error(err);
38269 return;
38270 }
38271 if (done) {
38272 subscriber.complete();
38273 }
38274 else {
38275 subscriber.next(value);
38276 this.schedule();
38277 }
38278 }));
38279 }));
38280 return sub;
38281 });
38282 }
38283
38284 /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */
38285 function isInteropObservable(input) {
38286 return input && typeof input[observable] === 'function';
38287 }
38288
38289 /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */
38290 function isIterable(input) {
38291 return input && typeof input[iterator] === 'function';
38292 }
38293
38294 /** PURE_IMPORTS_START _scheduleObservable,_schedulePromise,_scheduleArray,_scheduleIterable,_util_isInteropObservable,_util_isPromise,_util_isArrayLike,_util_isIterable PURE_IMPORTS_END */
38295 function scheduled(input, scheduler) {
38296 if (input != null) {
38297 if (isInteropObservable(input)) {
38298 return scheduleObservable(input, scheduler);
38299 }
38300 else if (isPromise$2(input)) {
38301 return schedulePromise(input, scheduler);
38302 }
38303 else if (isArrayLike(input)) {
38304 return scheduleArray(input, scheduler);
38305 }
38306 else if (isIterable(input) || typeof input === 'string') {
38307 return scheduleIterable(input, scheduler);
38308 }
38309 }
38310 throw new TypeError((input !== null && typeof input || input) + ' is not observable');
38311 }
38312
38313 /** PURE_IMPORTS_START _Observable,_util_subscribeTo,_scheduled_scheduled PURE_IMPORTS_END */
38314 function from(input, scheduler) {
38315 if (!scheduler) {
38316 if (input instanceof Observable) {
38317 return input;
38318 }
38319 return new Observable(subscribeTo(input));
38320 }
38321 else {
38322 return scheduled(input, scheduler);
38323 }
38324 }
38325
38326 /** PURE_IMPORTS_START tslib,_util_subscribeToResult,_OuterSubscriber,_InnerSubscriber,_map,_observable_from PURE_IMPORTS_END */
38327 function mergeMap(project, resultSelector, concurrent) {
38328 if (concurrent === void 0) {
38329 concurrent = Number.POSITIVE_INFINITY;
38330 }
38331 if (typeof resultSelector === 'function') {
38332 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)); };
38333 }
38334 else if (typeof resultSelector === 'number') {
38335 concurrent = resultSelector;
38336 }
38337 return function (source) { return source.lift(new MergeMapOperator(project, concurrent)); };
38338 }
38339 var MergeMapOperator = /*@__PURE__*/ (function () {
38340 function MergeMapOperator(project, concurrent) {
38341 if (concurrent === void 0) {
38342 concurrent = Number.POSITIVE_INFINITY;
38343 }
38344 this.project = project;
38345 this.concurrent = concurrent;
38346 }
38347 MergeMapOperator.prototype.call = function (observer, source) {
38348 return source.subscribe(new MergeMapSubscriber(observer, this.project, this.concurrent));
38349 };
38350 return MergeMapOperator;
38351 }());
38352 var MergeMapSubscriber = /*@__PURE__*/ (function (_super) {
38353 __extends(MergeMapSubscriber, _super);
38354 function MergeMapSubscriber(destination, project, concurrent) {
38355 if (concurrent === void 0) {
38356 concurrent = Number.POSITIVE_INFINITY;
38357 }
38358 var _this = _super.call(this, destination) || this;
38359 _this.project = project;
38360 _this.concurrent = concurrent;
38361 _this.hasCompleted = false;
38362 _this.buffer = [];
38363 _this.active = 0;
38364 _this.index = 0;
38365 return _this;
38366 }
38367 MergeMapSubscriber.prototype._next = function (value) {
38368 if (this.active < this.concurrent) {
38369 this._tryNext(value);
38370 }
38371 else {
38372 this.buffer.push(value);
38373 }
38374 };
38375 MergeMapSubscriber.prototype._tryNext = function (value) {
38376 var result;
38377 var index = this.index++;
38378 try {
38379 result = this.project(value, index);
38380 }
38381 catch (err) {
38382 this.destination.error(err);
38383 return;
38384 }
38385 this.active++;
38386 this._innerSub(result, value, index);
38387 };
38388 MergeMapSubscriber.prototype._innerSub = function (ish, value, index) {
38389 var innerSubscriber = new InnerSubscriber(this, value, index);
38390 var destination = this.destination;
38391 destination.add(innerSubscriber);
38392 var innerSubscription = subscribeToResult(this, ish, undefined, undefined, innerSubscriber);
38393 if (innerSubscription !== innerSubscriber) {
38394 destination.add(innerSubscription);
38395 }
38396 };
38397 MergeMapSubscriber.prototype._complete = function () {
38398 this.hasCompleted = true;
38399 if (this.active === 0 && this.buffer.length === 0) {
38400 this.destination.complete();
38401 }
38402 this.unsubscribe();
38403 };
38404 MergeMapSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) {
38405 this.destination.next(innerValue);
38406 };
38407 MergeMapSubscriber.prototype.notifyComplete = function (innerSub) {
38408 var buffer = this.buffer;
38409 this.remove(innerSub);
38410 this.active--;
38411 if (buffer.length > 0) {
38412 this._next(buffer.shift());
38413 }
38414 else if (this.active === 0 && this.hasCompleted) {
38415 this.destination.complete();
38416 }
38417 };
38418 return MergeMapSubscriber;
38419 }(OuterSubscriber));
38420
38421 /** PURE_IMPORTS_START _mergeMap,_util_identity PURE_IMPORTS_END */
38422 function mergeAll(concurrent) {
38423 if (concurrent === void 0) {
38424 concurrent = Number.POSITIVE_INFINITY;
38425 }
38426 return mergeMap(identity, concurrent);
38427 }
38428
38429 /** PURE_IMPORTS_START _Observable,_util_isScheduler,_operators_mergeAll,_fromArray PURE_IMPORTS_END */
38430 function merge$1() {
38431 var observables = [];
38432 for (var _i = 0; _i < arguments.length; _i++) {
38433 observables[_i] = arguments[_i];
38434 }
38435 var concurrent = Number.POSITIVE_INFINITY;
38436 var scheduler = null;
38437 var last = observables[observables.length - 1];
38438 if (isScheduler(last)) {
38439 scheduler = observables.pop();
38440 if (observables.length > 1 && typeof observables[observables.length - 1] === 'number') {
38441 concurrent = observables.pop();
38442 }
38443 }
38444 else if (typeof last === 'number') {
38445 concurrent = observables.pop();
38446 }
38447 if (scheduler === null && observables.length === 1 && observables[0] instanceof Observable) {
38448 return observables[0];
38449 }
38450 return mergeAll(concurrent)(fromArray(observables, scheduler));
38451 }
38452
38453 /**
38454 * @license
38455 * Copyright Google LLC All Rights Reserved.
38456 *
38457 * Use of this source code is governed by an MIT-style license that can be
38458 * found in the LICENSE file at https://angular.io/license
38459 */
38460 class EventEmitter_ extends Subject {
38461 constructor(isAsync = false) {
38462 super();
38463 this.__isAsync = isAsync;
38464 }
38465 emit(value) {
38466 super.next(value);
38467 }
38468 subscribe(observerOrNext, error, complete) {
38469 let schedulerFn;
38470 let errorFn = (err) => null;
38471 let completeFn = () => null;
38472 if (observerOrNext && typeof observerOrNext === 'object') {
38473 schedulerFn = this.__isAsync ? (value) => {
38474 setTimeout(() => observerOrNext.next(value));
38475 } : (value) => {
38476 observerOrNext.next(value);
38477 };
38478 if (observerOrNext.error) {
38479 errorFn = this.__isAsync ? (err) => {
38480 setTimeout(() => observerOrNext.error(err));
38481 } : (err) => {
38482 observerOrNext.error(err);
38483 };
38484 }
38485 if (observerOrNext.complete) {
38486 completeFn = this.__isAsync ? () => {
38487 setTimeout(() => observerOrNext.complete());
38488 } : () => {
38489 observerOrNext.complete();
38490 };
38491 }
38492 }
38493 else {
38494 schedulerFn = this.__isAsync ? (value) => {
38495 setTimeout(() => observerOrNext(value));
38496 } : (value) => {
38497 observerOrNext(value);
38498 };
38499 if (error) {
38500 errorFn = this.__isAsync ? (err) => {
38501 setTimeout(() => error(err));
38502 } : (err) => {
38503 error(err);
38504 };
38505 }
38506 if (complete) {
38507 completeFn = this.__isAsync ? () => {
38508 setTimeout(() => complete());
38509 } : () => {
38510 complete();
38511 };
38512 }
38513 }
38514 const sink = super.subscribe(schedulerFn, errorFn, completeFn);
38515 if (observerOrNext instanceof Subscription) {
38516 observerOrNext.add(sink);
38517 }
38518 return sink;
38519 }
38520 }
38521 /**
38522 * @publicApi
38523 */
38524 const EventEmitter = EventEmitter_;
38525
38526 /**
38527 * @license
38528 * Copyright Google LLC All Rights Reserved.
38529 *
38530 * Use of this source code is governed by an MIT-style license that can be
38531 * found in the LICENSE file at https://angular.io/license
38532 */
38533 const ɵ0$9 = (dir = {}) => dir, ɵ1$1 = (type, meta) => SWITCH_COMPILE_DIRECTIVE(type, meta);
38534 /**
38535 * Type of the Directive metadata.
38536 *
38537 * @publicApi
38538 */
38539 const Directive = makeDecorator('Directive', ɵ0$9, undefined, undefined, ɵ1$1);
38540 const ɵ2$1 = (c = {}) => (Object.assign({ changeDetection: ChangeDetectionStrategy$1.Default }, c)), ɵ3$1 = (type, meta) => SWITCH_COMPILE_COMPONENT(type, meta);
38541 /**
38542 * Component decorator and metadata.
38543 *
38544 * @Annotation
38545 * @publicApi
38546 */
38547 const Component = makeDecorator('Component', ɵ2$1, Directive, undefined, ɵ3$1);
38548 const ɵ4 = (p) => (Object.assign({ pure: true }, p)), ɵ5 = (type, meta) => SWITCH_COMPILE_PIPE(type, meta);
38549 /**
38550 * @Annotation
38551 * @publicApi
38552 */
38553 const Pipe = makeDecorator('Pipe', ɵ4, undefined, undefined, ɵ5);
38554 const ɵ6 = (bindingPropertyName) => ({ bindingPropertyName });
38555 /**
38556 * @Annotation
38557 * @publicApi
38558 */
38559 const Input = makePropDecorator('Input', ɵ6);
38560 const ɵ7 = (bindingPropertyName) => ({ bindingPropertyName });
38561 /**
38562 * @Annotation
38563 * @publicApi
38564 */
38565 const Output = makePropDecorator('Output', ɵ7);
38566 const ɵ8 = (hostPropertyName) => ({ hostPropertyName });
38567 /**
38568 * @Annotation
38569 * @publicApi
38570 */
38571 const HostBinding = makePropDecorator('HostBinding', ɵ8);
38572 const ɵ9 = (eventName, args) => ({ eventName, args });
38573 /**
38574 * Decorator that binds a DOM event to a host listener and supplies configuration metadata.
38575 * Angular invokes the supplied handler method when the host element emits the specified event,
38576 * and updates the bound element with the result.
38577 *
38578 * If the handler method returns false, applies `preventDefault` on the bound element.
38579 *
38580 * @usageNotes
38581 *
38582 * The following example declares a directive
38583 * that attaches a click listener to a button and counts clicks.
38584 *
38585 * ```ts
38586 * @Directive({selector: 'button[counting]'})
38587 * class CountClicks {
38588 * numberOfClicks = 0;
38589 *
38590 * @HostListener('click', ['$event.target'])
38591 * onClick(btn) {
38592 * console.log('button', btn, 'number of clicks:', this.numberOfClicks++);
38593 * }
38594 * }
38595 *
38596 * @Component({
38597 * selector: 'app',
38598 * template: '<button counting>Increment</button>',
38599 * })
38600 * class App {}
38601 *
38602 * ```
38603 *
38604 * The following example registers another DOM event handler that listens for key-press events.
38605 * ``` ts
38606 * import { HostListener, Component } from "@angular/core";
38607 *
38608 * @Component({
38609 * selector: 'app',
38610 * template: `<h1>Hello, you have pressed keys {{counter}} number of times!</h1> Press any key to
38611 * increment the counter.
38612 * <button (click)="resetCounter()">Reset Counter</button>`
38613 * })
38614 * class AppComponent {
38615 * counter = 0;
38616 * @HostListener('window:keydown', ['$event'])
38617 * handleKeyDown(event: KeyboardEvent) {
38618 * this.counter++;
38619 * }
38620 * resetCounter() {
38621 * this.counter = 0;
38622 * }
38623 * }
38624 * ```
38625 *
38626 * @Annotation
38627 * @publicApi
38628 */
38629 const HostListener = makePropDecorator('HostListener', ɵ9);
38630 const SWITCH_COMPILE_COMPONENT__PRE_R3__ = noop;
38631 const SWITCH_COMPILE_DIRECTIVE__PRE_R3__ = noop;
38632 const SWITCH_COMPILE_PIPE__PRE_R3__ = noop;
38633 const SWITCH_COMPILE_COMPONENT = SWITCH_COMPILE_COMPONENT__PRE_R3__;
38634 const SWITCH_COMPILE_DIRECTIVE = SWITCH_COMPILE_DIRECTIVE__PRE_R3__;
38635 const SWITCH_COMPILE_PIPE = SWITCH_COMPILE_PIPE__PRE_R3__;
38636
38637 /**
38638 * @license
38639 * Copyright Google LLC All Rights Reserved.
38640 *
38641 * Use of this source code is governed by an MIT-style license that can be
38642 * found in the LICENSE file at https://angular.io/license
38643 */
38644 const ɵ0$a = (ngModule) => ngModule, ɵ1$2 =
38645 /**
38646 * Decorator that marks the following class as an NgModule, and supplies
38647 * configuration metadata for it.
38648 *
38649 * * The `declarations` and `entryComponents` options configure the compiler
38650 * with information about what belongs to the NgModule.
38651 * * The `providers` options configures the NgModule's injector to provide
38652 * dependencies the NgModule members.
38653 * * The `imports` and `exports` options bring in members from other modules, and make
38654 * this module's members available to others.
38655 */
38656 (type, meta) => SWITCH_COMPILE_NGMODULE(type, meta);
38657 /**
38658 * @Annotation
38659 * @publicApi
38660 */
38661 const NgModule = makeDecorator('NgModule', ɵ0$a, undefined, undefined, ɵ1$2);
38662 function preR3NgModuleCompile(moduleType, metadata) {
38663 let imports = (metadata && metadata.imports) || [];
38664 if (metadata && metadata.exports) {
38665 imports = [...imports, metadata.exports];
38666 }
38667 moduleType.ɵinj = ɵɵdefineInjector({
38668 factory: convertInjectableProviderToFactory(moduleType, { useClass: moduleType }),
38669 providers: metadata && metadata.providers,
38670 imports: imports,
38671 });
38672 }
38673 const SWITCH_COMPILE_NGMODULE__PRE_R3__ = preR3NgModuleCompile;
38674 const SWITCH_COMPILE_NGMODULE = SWITCH_COMPILE_NGMODULE__PRE_R3__;
38675
38676 /** PURE_IMPORTS_START _observable_ConnectableObservable PURE_IMPORTS_END */
38677 function multicast(subjectOrSubjectFactory, selector) {
38678 return function multicastOperatorFunction(source) {
38679 var subjectFactory;
38680 if (typeof subjectOrSubjectFactory === 'function') {
38681 subjectFactory = subjectOrSubjectFactory;
38682 }
38683 else {
38684 subjectFactory = function subjectFactory() {
38685 return subjectOrSubjectFactory;
38686 };
38687 }
38688 if (typeof selector === 'function') {
38689 return source.lift(new MulticastOperator(subjectFactory, selector));
38690 }
38691 var connectable = Object.create(source, connectableObservableDescriptor);
38692 connectable.source = source;
38693 connectable.subjectFactory = subjectFactory;
38694 return connectable;
38695 };
38696 }
38697 var MulticastOperator = /*@__PURE__*/ (function () {
38698 function MulticastOperator(subjectFactory, selector) {
38699 this.subjectFactory = subjectFactory;
38700 this.selector = selector;
38701 }
38702 MulticastOperator.prototype.call = function (subscriber, source) {
38703 var selector = this.selector;
38704 var subject = this.subjectFactory();
38705 var subscription = selector(subject).subscribe(subscriber);
38706 subscription.add(source.subscribe(subject));
38707 return subscription;
38708 };
38709 return MulticastOperator;
38710 }());
38711
38712 /** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */
38713 function shareSubjectFactory() {
38714 return new Subject();
38715 }
38716 function share() {
38717 return function (source) { return refCount()(multicast(shareSubjectFactory)(source)); };
38718 }
38719
38720 /**
38721 * @license
38722 * Copyright Google LLC All Rights Reserved.
38723 *
38724 * Use of this source code is governed by an MIT-style license that can be
38725 * found in the LICENSE file at https://angular.io/license
38726 */
38727 /**
38728 * A [DI token](guide/glossary#di-token "DI token definition") that you can use to provide
38729 * one or more initialization functions.
38730 *
38731 * The provided functions are injected at application startup and executed during
38732 * app initialization. If any of these functions returns a Promise, initialization
38733 * does not complete until the Promise is resolved.
38734 *
38735 * You can, for example, create a factory function that loads language data
38736 * or an external configuration, and provide that function to the `APP_INITIALIZER` token.
38737 * The function is executed during the application bootstrap process,
38738 * and the needed data is available on startup.
38739 *
38740 * @see `ApplicationInitStatus`
38741 *
38742 * @publicApi
38743 */
38744 const APP_INITIALIZER = new InjectionToken('Application Initializer');
38745 /**
38746 * A class that reflects the state of running {@link APP_INITIALIZER} functions.
38747 *
38748 * @publicApi
38749 */
38750 class ApplicationInitStatus {
38751 constructor(appInits) {
38752 this.appInits = appInits;
38753 this.resolve = noop;
38754 this.reject = noop;
38755 this.initialized = false;
38756 this.done = false;
38757 this.donePromise = new Promise((res, rej) => {
38758 this.resolve = res;
38759 this.reject = rej;
38760 });
38761 }
38762 /** @internal */
38763 runInitializers() {
38764 if (this.initialized) {
38765 return;
38766 }
38767 const asyncInitPromises = [];
38768 const complete = () => {
38769 this.done = true;
38770 this.resolve();
38771 };
38772 if (this.appInits) {
38773 for (let i = 0; i < this.appInits.length; i++) {
38774 const initResult = this.appInits[i]();
38775 if (isPromise$1(initResult)) {
38776 asyncInitPromises.push(initResult);
38777 }
38778 }
38779 }
38780 Promise.all(asyncInitPromises)
38781 .then(() => {
38782 complete();
38783 })
38784 .catch(e => {
38785 this.reject(e);
38786 });
38787 if (asyncInitPromises.length === 0) {
38788 complete();
38789 }
38790 this.initialized = true;
38791 }
38792 }
38793 ApplicationInitStatus.decorators = [
38794 { type: Injectable }
38795 ];
38796 ApplicationInitStatus.ctorParameters = () => [
38797 { type: Array, decorators: [{ type: Inject, args: [APP_INITIALIZER,] }, { type: Optional }] }
38798 ];
38799
38800 /**
38801 * @license
38802 * Copyright Google LLC All Rights Reserved.
38803 *
38804 * Use of this source code is governed by an MIT-style license that can be
38805 * found in the LICENSE file at https://angular.io/license
38806 */
38807 /**
38808 * A [DI token](guide/glossary#di-token "DI token definition") representing a unique string ID, used
38809 * primarily for prefixing application attributes and CSS styles when
38810 * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used.
38811 *
38812 * BY default, the value is randomly generated and assigned to the application by Angular.
38813 * To provide a custom ID value, use a DI provider <!-- TODO: provider --> to configure
38814 * the root {@link Injector} that uses this token.
38815 *
38816 * @publicApi
38817 */
38818 const APP_ID = new InjectionToken('AppId');
38819 function _appIdRandomProviderFactory() {
38820 return `${_randomChar()}${_randomChar()}${_randomChar()}`;
38821 }
38822 /**
38823 * Providers that generate a random `APP_ID_TOKEN`.
38824 * @publicApi
38825 */
38826 const APP_ID_RANDOM_PROVIDER = {
38827 provide: APP_ID,
38828 useFactory: _appIdRandomProviderFactory,
38829 deps: [],
38830 };
38831 function _randomChar() {
38832 return String.fromCharCode(97 + Math.floor(Math.random() * 25));
38833 }
38834 /**
38835 * A function that is executed when a platform is initialized.
38836 * @publicApi
38837 */
38838 const PLATFORM_INITIALIZER = new InjectionToken('Platform Initializer');
38839 /**
38840 * A token that indicates an opaque platform ID.
38841 * @publicApi
38842 */
38843 const PLATFORM_ID = new InjectionToken('Platform ID');
38844 /**
38845 * A [DI token](guide/glossary#di-token "DI token definition") that provides a set of callbacks to
38846 * be called for every component that is bootstrapped.
38847 *
38848 * Each callback must take a `ComponentRef` instance and return nothing.
38849 *
38850 * `(componentRef: ComponentRef) => void`
38851 *
38852 * @publicApi
38853 */
38854 const APP_BOOTSTRAP_LISTENER = new InjectionToken('appBootstrapListener');
38855 /**
38856 * A [DI token](guide/glossary#di-token "DI token definition") that indicates the root directory of
38857 * the application
38858 * @publicApi
38859 */
38860 const PACKAGE_ROOT_URL = new InjectionToken('Application Packages Root URL');
38861
38862 /**
38863 * @license
38864 * Copyright Google LLC All Rights Reserved.
38865 *
38866 * Use of this source code is governed by an MIT-style license that can be
38867 * found in the LICENSE file at https://angular.io/license
38868 */
38869 class Console {
38870 log(message) {
38871 // tslint:disable-next-line:no-console
38872 console.log(message);
38873 }
38874 // Note: for reporting errors use `DOM.logError()` as it is platform specific
38875 warn(message) {
38876 // tslint:disable-next-line:no-console
38877 console.warn(message);
38878 }
38879 }
38880 Console.decorators = [
38881 { type: Injectable }
38882 ];
38883
38884 /**
38885 * @license
38886 * Copyright Google LLC All Rights Reserved.
38887 *
38888 * Use of this source code is governed by an MIT-style license that can be
38889 * found in the LICENSE file at https://angular.io/license
38890 */
38891 /**
38892 * Provide this token to set the locale of your application.
38893 * It is used for i18n extraction, by i18n pipes (DatePipe, I18nPluralPipe, CurrencyPipe,
38894 * DecimalPipe and PercentPipe) and by ICU expressions.
38895 *
38896 * See the [i18n guide](guide/i18n#setting-up-locale) for more information.
38897 *
38898 * @usageNotes
38899 * ### Example
38900 *
38901 * ```typescript
38902 * import { LOCALE_ID } from '@angular/core';
38903 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38904 * import { AppModule } from './app/app.module';
38905 *
38906 * platformBrowserDynamic().bootstrapModule(AppModule, {
38907 * providers: [{provide: LOCALE_ID, useValue: 'en-US' }]
38908 * });
38909 * ```
38910 *
38911 * @publicApi
38912 */
38913 const LOCALE_ID$1 = new InjectionToken('LocaleId');
38914 /**
38915 * Provide this token to set the default currency code your application uses for
38916 * CurrencyPipe when there is no currency code passed into it. This is only used by
38917 * CurrencyPipe and has no relation to locale currency. Defaults to USD if not configured.
38918 *
38919 * See the [i18n guide](guide/i18n#setting-up-locale) for more information.
38920 *
38921 * <div class="alert is-helpful">
38922 *
38923 * **Deprecation notice:**
38924 *
38925 * The default currency code is currently always `USD` but this is deprecated from v9.
38926 *
38927 * **In v10 the default currency code will be taken from the current locale.**
38928 *
38929 * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in
38930 * your application `NgModule`:
38931 *
38932 * ```ts
38933 * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
38934 * ```
38935 *
38936 * </div>
38937 *
38938 * @usageNotes
38939 * ### Example
38940 *
38941 * ```typescript
38942 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38943 * import { AppModule } from './app/app.module';
38944 *
38945 * platformBrowserDynamic().bootstrapModule(AppModule, {
38946 * providers: [{provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' }]
38947 * });
38948 * ```
38949 *
38950 * @publicApi
38951 */
38952 const DEFAULT_CURRENCY_CODE = new InjectionToken('DefaultCurrencyCode');
38953 /**
38954 * Use this token at bootstrap to provide the content of your translation file (`xtb`,
38955 * `xlf` or `xlf2`) when you want to translate your application in another language.
38956 *
38957 * See the [i18n guide](guide/i18n#merge) for more information.
38958 *
38959 * @usageNotes
38960 * ### Example
38961 *
38962 * ```typescript
38963 * import { TRANSLATIONS } from '@angular/core';
38964 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38965 * import { AppModule } from './app/app.module';
38966 *
38967 * // content of your translation file
38968 * const translations = '....';
38969 *
38970 * platformBrowserDynamic().bootstrapModule(AppModule, {
38971 * providers: [{provide: TRANSLATIONS, useValue: translations }]
38972 * });
38973 * ```
38974 *
38975 * @publicApi
38976 */
38977 const TRANSLATIONS = new InjectionToken('Translations');
38978 /**
38979 * Provide this token at bootstrap to set the format of your {@link TRANSLATIONS}: `xtb`,
38980 * `xlf` or `xlf2`.
38981 *
38982 * See the [i18n guide](guide/i18n#merge) for more information.
38983 *
38984 * @usageNotes
38985 * ### Example
38986 *
38987 * ```typescript
38988 * import { TRANSLATIONS_FORMAT } from '@angular/core';
38989 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
38990 * import { AppModule } from './app/app.module';
38991 *
38992 * platformBrowserDynamic().bootstrapModule(AppModule, {
38993 * providers: [{provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }]
38994 * });
38995 * ```
38996 *
38997 * @publicApi
38998 */
38999 const TRANSLATIONS_FORMAT = new InjectionToken('TranslationsFormat');
39000 /**
39001 * Use this enum at bootstrap as an option of `bootstrapModule` to define the strategy
39002 * that the compiler should use in case of missing translations:
39003 * - Error: throw if you have missing translations.
39004 * - Warning (default): show a warning in the console and/or shell.
39005 * - Ignore: do nothing.
39006 *
39007 * See the [i18n guide](guide/i18n#missing-translation) for more information.
39008 *
39009 * @usageNotes
39010 * ### Example
39011 * ```typescript
39012 * import { MissingTranslationStrategy } from '@angular/core';
39013 * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
39014 * import { AppModule } from './app/app.module';
39015 *
39016 * platformBrowserDynamic().bootstrapModule(AppModule, {
39017 * missingTranslation: MissingTranslationStrategy.Error
39018 * });
39019 * ```
39020 *
39021 * @publicApi
39022 */
39023 var MissingTranslationStrategy$1;
39024 (function (MissingTranslationStrategy) {
39025 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
39026 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
39027 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
39028 })(MissingTranslationStrategy$1 || (MissingTranslationStrategy$1 = {}));
39029
39030 /**
39031 * @license
39032 * Copyright Google LLC All Rights Reserved.
39033 *
39034 * Use of this source code is governed by an MIT-style license that can be
39035 * found in the LICENSE file at https://angular.io/license
39036 */
39037 const SWITCH_IVY_ENABLED__PRE_R3__ = false;
39038 const ivyEnabled = SWITCH_IVY_ENABLED__PRE_R3__;
39039
39040 /**
39041 * @license
39042 * Copyright Google LLC All Rights Reserved.
39043 *
39044 * Use of this source code is governed by an MIT-style license that can be
39045 * found in the LICENSE file at https://angular.io/license
39046 */
39047 function _throwError() {
39048 throw new Error(`Runtime compiler is not loaded`);
39049 }
39050 const Compiler_compileModuleSync__PRE_R3__ = _throwError;
39051 const Compiler_compileModuleSync = Compiler_compileModuleSync__PRE_R3__;
39052 const Compiler_compileModuleAsync__PRE_R3__ = _throwError;
39053 const Compiler_compileModuleAsync = Compiler_compileModuleAsync__PRE_R3__;
39054 const Compiler_compileModuleAndAllComponentsSync__PRE_R3__ = _throwError;
39055 const Compiler_compileModuleAndAllComponentsSync = Compiler_compileModuleAndAllComponentsSync__PRE_R3__;
39056 const Compiler_compileModuleAndAllComponentsAsync__PRE_R3__ = _throwError;
39057 const Compiler_compileModuleAndAllComponentsAsync = Compiler_compileModuleAndAllComponentsAsync__PRE_R3__;
39058 /**
39059 * Low-level service for running the angular compiler during runtime
39060 * to create {@link ComponentFactory}s, which
39061 * can later be used to create and render a Component instance.
39062 *
39063 * Each `@NgModule` provides an own `Compiler` to its injector,
39064 * that will use the directives/pipes of the ng module for compilation
39065 * of components.
39066 *
39067 * @publicApi
39068 */
39069 class Compiler {
39070 constructor() {
39071 /**
39072 * Compiles the given NgModule and all of its components. All templates of the components listed
39073 * in `entryComponents` have to be inlined.
39074 */
39075 this.compileModuleSync = Compiler_compileModuleSync;
39076 /**
39077 * Compiles the given NgModule and all of its components
39078 */
39079 this.compileModuleAsync = Compiler_compileModuleAsync;
39080 /**
39081 * Same as {@link #compileModuleSync} but also creates ComponentFactories for all components.
39082 */
39083 this.compileModuleAndAllComponentsSync = Compiler_compileModuleAndAllComponentsSync;
39084 /**
39085 * Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components.
39086 */
39087 this.compileModuleAndAllComponentsAsync = Compiler_compileModuleAndAllComponentsAsync;
39088 }
39089 /**
39090 * Clears all caches.
39091 */
39092 clearCache() { }
39093 /**
39094 * Clears the cache for the given component/ngModule.
39095 */
39096 clearCacheFor(type) { }
39097 /**
39098 * Returns the id for a given NgModule, if one is defined and known to the compiler.
39099 */
39100 getModuleId(moduleType) {
39101 return undefined;
39102 }
39103 }
39104 Compiler.decorators = [
39105 { type: Injectable }
39106 ];
39107 /**
39108 * Token to provide CompilerOptions in the platform injector.
39109 *
39110 * @publicApi
39111 */
39112 const COMPILER_OPTIONS = new InjectionToken('compilerOptions');
39113 /**
39114 * A factory for creating a Compiler
39115 *
39116 * @publicApi
39117 */
39118 class CompilerFactory {
39119 }
39120
39121 /**
39122 * @license
39123 * Copyright Google LLC All Rights Reserved.
39124 *
39125 * Use of this source code is governed by an MIT-style license that can be
39126 * found in the LICENSE file at https://angular.io/license
39127 */
39128 const promise = (() => Promise.resolve(0))();
39129 function scheduleMicroTask(fn) {
39130 if (typeof Zone === 'undefined') {
39131 // use promise to schedule microTask instead of use Zone
39132 promise.then(() => {
39133 fn && fn.apply(null, null);
39134 });
39135 }
39136 else {
39137 Zone.current.scheduleMicroTask('scheduleMicrotask', fn);
39138 }
39139 }
39140
39141 /**
39142 * @license
39143 * Copyright Google LLC All Rights Reserved.
39144 *
39145 * Use of this source code is governed by an MIT-style license that can be
39146 * found in the LICENSE file at https://angular.io/license
39147 */
39148 function getNativeRequestAnimationFrame() {
39149 let nativeRequestAnimationFrame = _global$1['requestAnimationFrame'];
39150 let nativeCancelAnimationFrame = _global$1['cancelAnimationFrame'];
39151 if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
39152 // use unpatched version of requestAnimationFrame(native delegate) if possible
39153 // to avoid another Change detection
39154 const unpatchedRequestAnimationFrame = nativeRequestAnimationFrame[Zone.__symbol__('OriginalDelegate')];
39155 if (unpatchedRequestAnimationFrame) {
39156 nativeRequestAnimationFrame = unpatchedRequestAnimationFrame;
39157 }
39158 const unpatchedCancelAnimationFrame = nativeCancelAnimationFrame[Zone.__symbol__('OriginalDelegate')];
39159 if (unpatchedCancelAnimationFrame) {
39160 nativeCancelAnimationFrame = unpatchedCancelAnimationFrame;
39161 }
39162 }
39163 return { nativeRequestAnimationFrame, nativeCancelAnimationFrame };
39164 }
39165
39166 /**
39167 * @license
39168 * Copyright Google LLC All Rights Reserved.
39169 *
39170 * Use of this source code is governed by an MIT-style license that can be
39171 * found in the LICENSE file at https://angular.io/license
39172 */
39173 /**
39174 * An injectable service for executing work inside or outside of the Angular zone.
39175 *
39176 * The most common use of this service is to optimize performance when starting a work consisting of
39177 * one or more asynchronous tasks that don't require UI updates or error handling to be handled by
39178 * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks
39179 * can reenter the Angular zone via {@link #run}.
39180 *
39181 * <!-- TODO: add/fix links to:
39182 * - docs explaining zones and the use of zones in Angular and change-detection
39183 * - link to runOutsideAngular/run (throughout this file!)
39184 * -->
39185 *
39186 * @usageNotes
39187 * ### Example
39188 *
39189 * ```
39190 * import {Component, NgZone} from '@angular/core';
39191 * import {NgIf} from '@angular/common';
39192 *
39193 * @Component({
39194 * selector: 'ng-zone-demo',
39195 * template: `
39196 * <h2>Demo: NgZone</h2>
39197 *
39198 * <p>Progress: {{progress}}%</p>
39199 * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
39200 *
39201 * <button (click)="processWithinAngularZone()">Process within Angular zone</button>
39202 * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
39203 * `,
39204 * })
39205 * export class NgZoneDemo {
39206 * progress: number = 0;
39207 * label: string;
39208 *
39209 * constructor(private _ngZone: NgZone) {}
39210 *
39211 * // Loop inside the Angular zone
39212 * // so the UI DOES refresh after each setTimeout cycle
39213 * processWithinAngularZone() {
39214 * this.label = 'inside';
39215 * this.progress = 0;
39216 * this._increaseProgress(() => console.log('Inside Done!'));
39217 * }
39218 *
39219 * // Loop outside of the Angular zone
39220 * // so the UI DOES NOT refresh after each setTimeout cycle
39221 * processOutsideOfAngularZone() {
39222 * this.label = 'outside';
39223 * this.progress = 0;
39224 * this._ngZone.runOutsideAngular(() => {
39225 * this._increaseProgress(() => {
39226 * // reenter the Angular zone and display done
39227 * this._ngZone.run(() => { console.log('Outside Done!'); });
39228 * });
39229 * });
39230 * }
39231 *
39232 * _increaseProgress(doneCallback: () => void) {
39233 * this.progress += 1;
39234 * console.log(`Current progress: ${this.progress}%`);
39235 *
39236 * if (this.progress < 100) {
39237 * window.setTimeout(() => this._increaseProgress(doneCallback), 10);
39238 * } else {
39239 * doneCallback();
39240 * }
39241 * }
39242 * }
39243 * ```
39244 *
39245 * @publicApi
39246 */
39247 class NgZone {
39248 constructor({ enableLongStackTrace = false, shouldCoalesceEventChangeDetection = false, shouldCoalesceRunChangeDetection = false }) {
39249 this.hasPendingMacrotasks = false;
39250 this.hasPendingMicrotasks = false;
39251 /**
39252 * Whether there are no outstanding microtasks or macrotasks.
39253 */
39254 this.isStable = true;
39255 /**
39256 * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
39257 */
39258 this.onUnstable = new EventEmitter(false);
39259 /**
39260 * Notifies when there is no more microtasks enqueued in the current VM Turn.
39261 * This is a hint for Angular to do change detection, which may enqueue more microtasks.
39262 * For this reason this event can fire multiple times per VM Turn.
39263 */
39264 this.onMicrotaskEmpty = new EventEmitter(false);
39265 /**
39266 * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
39267 * implies we are about to relinquish VM turn.
39268 * This event gets called just once.
39269 */
39270 this.onStable = new EventEmitter(false);
39271 /**
39272 * Notifies that an error has been delivered.
39273 */
39274 this.onError = new EventEmitter(false);
39275 if (typeof Zone == 'undefined') {
39276 throw new Error(`In this configuration Angular requires Zone.js`);
39277 }
39278 Zone.assertZonePatched();
39279 const self = this;
39280 self._nesting = 0;
39281 self._outer = self._inner = Zone.current;
39282 if (Zone['TaskTrackingZoneSpec']) {
39283 self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']);
39284 }
39285 if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) {
39286 self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']);
39287 }
39288 // if shouldCoalesceRunChangeDetection is true, all tasks including event tasks will be
39289 // coalesced, so shouldCoalesceEventChangeDetection option is not necessary and can be skipped.
39290 self.shouldCoalesceEventChangeDetection =
39291 !shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
39292 self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
39293 self.lastRequestAnimationFrameId = -1;
39294 self.nativeRequestAnimationFrame = getNativeRequestAnimationFrame().nativeRequestAnimationFrame;
39295 forkInnerZoneWithAngularBehavior(self);
39296 }
39297 static isInAngularZone() {
39298 return Zone.current.get('isAngularZone') === true;
39299 }
39300 static assertInAngularZone() {
39301 if (!NgZone.isInAngularZone()) {
39302 throw new Error('Expected to be in Angular Zone, but it is not!');
39303 }
39304 }
39305 static assertNotInAngularZone() {
39306 if (NgZone.isInAngularZone()) {
39307 throw new Error('Expected to not be in Angular Zone, but it is!');
39308 }
39309 }
39310 /**
39311 * Executes the `fn` function synchronously within the Angular zone and returns value returned by
39312 * the function.
39313 *
39314 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
39315 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
39316 *
39317 * Any future tasks or microtasks scheduled from within this function will continue executing from
39318 * within the Angular zone.
39319 *
39320 * If a synchronous error happens it will be rethrown and not reported via `onError`.
39321 */
39322 run(fn, applyThis, applyArgs) {
39323 return this._inner.run(fn, applyThis, applyArgs);
39324 }
39325 /**
39326 * Executes the `fn` function synchronously within the Angular zone as a task and returns value
39327 * returned by the function.
39328 *
39329 * Running functions via `run` allows you to reenter Angular zone from a task that was executed
39330 * outside of the Angular zone (typically started via {@link #runOutsideAngular}).
39331 *
39332 * Any future tasks or microtasks scheduled from within this function will continue executing from
39333 * within the Angular zone.
39334 *
39335 * If a synchronous error happens it will be rethrown and not reported via `onError`.
39336 */
39337 runTask(fn, applyThis, applyArgs, name) {
39338 const zone = this._inner;
39339 const task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop, noop);
39340 try {
39341 return zone.runTask(task, applyThis, applyArgs);
39342 }
39343 finally {
39344 zone.cancelTask(task);
39345 }
39346 }
39347 /**
39348 * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
39349 * rethrown.
39350 */
39351 runGuarded(fn, applyThis, applyArgs) {
39352 return this._inner.runGuarded(fn, applyThis, applyArgs);
39353 }
39354 /**
39355 * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
39356 * the function.
39357 *
39358 * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do
39359 * work that
39360 * doesn't trigger Angular change-detection or is subject to Angular's error handling.
39361 *
39362 * Any future tasks or microtasks scheduled from within this function will continue executing from
39363 * outside of the Angular zone.
39364 *
39365 * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
39366 */
39367 runOutsideAngular(fn) {
39368 return this._outer.run(fn);
39369 }
39370 }
39371 const EMPTY_PAYLOAD = {};
39372 function checkStable(zone) {
39373 if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
39374 try {
39375 zone._nesting++;
39376 zone.onMicrotaskEmpty.emit(null);
39377 }
39378 finally {
39379 zone._nesting--;
39380 if (!zone.hasPendingMicrotasks) {
39381 try {
39382 zone.runOutsideAngular(() => zone.onStable.emit(null));
39383 }
39384 finally {
39385 zone.isStable = true;
39386 }
39387 }
39388 }
39389 }
39390 }
39391 function delayChangeDetectionForEvents(zone) {
39392 if (zone.lastRequestAnimationFrameId !== -1) {
39393 return;
39394 }
39395 zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(_global$1, () => {
39396 // This is a work around for https://github.com/angular/angular/issues/36839.
39397 // The core issue is that when event coalescing is enabled it is possible for microtasks
39398 // to get flushed too early (As is the case with `Promise.then`) between the
39399 // coalescing eventTasks.
39400 //
39401 // To workaround this we schedule a "fake" eventTask before we process the
39402 // coalescing eventTasks. The benefit of this is that the "fake" container eventTask
39403 // will prevent the microtasks queue from getting drained in between the coalescing
39404 // eventTask execution.
39405 if (!zone.fakeTopEventTask) {
39406 zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
39407 zone.lastRequestAnimationFrameId = -1;
39408 updateMicroTaskStatus(zone);
39409 checkStable(zone);
39410 }, undefined, () => { }, () => { });
39411 }
39412 zone.fakeTopEventTask.invoke();
39413 });
39414 updateMicroTaskStatus(zone);
39415 }
39416 function forkInnerZoneWithAngularBehavior(zone) {
39417 const delayChangeDetectionForEventsDelegate = () => {
39418 delayChangeDetectionForEvents(zone);
39419 };
39420 zone._inner = zone._inner.fork({
39421 name: 'angular',
39422 properties: { 'isAngularZone': true },
39423 onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
39424 try {
39425 onEnter(zone);
39426 return delegate.invokeTask(target, task, applyThis, applyArgs);
39427 }
39428 finally {
39429 if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
39430 zone.shouldCoalesceRunChangeDetection) {
39431 delayChangeDetectionForEventsDelegate();
39432 }
39433 onLeave(zone);
39434 }
39435 },
39436 onInvoke: (delegate, current, target, callback, applyThis, applyArgs, source) => {
39437 try {
39438 onEnter(zone);
39439 return delegate.invoke(target, callback, applyThis, applyArgs, source);
39440 }
39441 finally {
39442 if (zone.shouldCoalesceRunChangeDetection) {
39443 delayChangeDetectionForEventsDelegate();
39444 }
39445 onLeave(zone);
39446 }
39447 },
39448 onHasTask: (delegate, current, target, hasTaskState) => {
39449 delegate.hasTask(target, hasTaskState);
39450 if (current === target) {
39451 // We are only interested in hasTask events which originate from our zone
39452 // (A child hasTask event is not interesting to us)
39453 if (hasTaskState.change == 'microTask') {
39454 zone._hasPendingMicrotasks = hasTaskState.microTask;
39455 updateMicroTaskStatus(zone);
39456 checkStable(zone);
39457 }
39458 else if (hasTaskState.change == 'macroTask') {
39459 zone.hasPendingMacrotasks = hasTaskState.macroTask;
39460 }
39461 }
39462 },
39463 onHandleError: (delegate, current, target, error) => {
39464 delegate.handleError(target, error);
39465 zone.runOutsideAngular(() => zone.onError.emit(error));
39466 return false;
39467 }
39468 });
39469 }
39470 function updateMicroTaskStatus(zone) {
39471 if (zone._hasPendingMicrotasks ||
39472 ((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
39473 zone.lastRequestAnimationFrameId !== -1)) {
39474 zone.hasPendingMicrotasks = true;
39475 }
39476 else {
39477 zone.hasPendingMicrotasks = false;
39478 }
39479 }
39480 function onEnter(zone) {
39481 zone._nesting++;
39482 if (zone.isStable) {
39483 zone.isStable = false;
39484 zone.onUnstable.emit(null);
39485 }
39486 }
39487 function onLeave(zone) {
39488 zone._nesting--;
39489 checkStable(zone);
39490 }
39491 /**
39492 * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls
39493 * to framework to perform rendering.
39494 */
39495 class NoopNgZone {
39496 constructor() {
39497 this.hasPendingMicrotasks = false;
39498 this.hasPendingMacrotasks = false;
39499 this.isStable = true;
39500 this.onUnstable = new EventEmitter();
39501 this.onMicrotaskEmpty = new EventEmitter();
39502 this.onStable = new EventEmitter();
39503 this.onError = new EventEmitter();
39504 }
39505 run(fn, applyThis, applyArgs) {
39506 return fn.apply(applyThis, applyArgs);
39507 }
39508 runGuarded(fn, applyThis, applyArgs) {
39509 return fn.apply(applyThis, applyArgs);
39510 }
39511 runOutsideAngular(fn) {
39512 return fn();
39513 }
39514 runTask(fn, applyThis, applyArgs, name) {
39515 return fn.apply(applyThis, applyArgs);
39516 }
39517 }
39518
39519 /**
39520 * @license
39521 * Copyright Google LLC All Rights Reserved.
39522 *
39523 * Use of this source code is governed by an MIT-style license that can be
39524 * found in the LICENSE file at https://angular.io/license
39525 */
39526 /**
39527 * The Testability service provides testing hooks that can be accessed from
39528 * the browser and by services such as Protractor. Each bootstrapped Angular
39529 * application on the page will have an instance of Testability.
39530 * @publicApi
39531 */
39532 class Testability {
39533 constructor(_ngZone) {
39534 this._ngZone = _ngZone;
39535 this._pendingCount = 0;
39536 this._isZoneStable = true;
39537 /**
39538 * Whether any work was done since the last 'whenStable' callback. This is
39539 * useful to detect if this could have potentially destabilized another
39540 * component while it is stabilizing.
39541 * @internal
39542 */
39543 this._didWork = false;
39544 this._callbacks = [];
39545 this.taskTrackingZone = null;
39546 this._watchAngularEvents();
39547 _ngZone.run(() => {
39548 this.taskTrackingZone =
39549 typeof Zone == 'undefined' ? null : Zone.current.get('TaskTrackingZone');
39550 });
39551 }
39552 _watchAngularEvents() {
39553 this._ngZone.onUnstable.subscribe({
39554 next: () => {
39555 this._didWork = true;
39556 this._isZoneStable = false;
39557 }
39558 });
39559 this._ngZone.runOutsideAngular(() => {
39560 this._ngZone.onStable.subscribe({
39561 next: () => {
39562 NgZone.assertNotInAngularZone();
39563 scheduleMicroTask(() => {
39564 this._isZoneStable = true;
39565 this._runCallbacksIfReady();
39566 });
39567 }
39568 });
39569 });
39570 }
39571 /**
39572 * Increases the number of pending request
39573 * @deprecated pending requests are now tracked with zones.
39574 */
39575 increasePendingRequestCount() {
39576 this._pendingCount += 1;
39577 this._didWork = true;
39578 return this._pendingCount;
39579 }
39580 /**
39581 * Decreases the number of pending request
39582 * @deprecated pending requests are now tracked with zones
39583 */
39584 decreasePendingRequestCount() {
39585 this._pendingCount -= 1;
39586 if (this._pendingCount < 0) {
39587 throw new Error('pending async requests below zero');
39588 }
39589 this._runCallbacksIfReady();
39590 return this._pendingCount;
39591 }
39592 /**
39593 * Whether an associated application is stable
39594 */
39595 isStable() {
39596 return this._isZoneStable && this._pendingCount === 0 && !this._ngZone.hasPendingMacrotasks;
39597 }
39598 _runCallbacksIfReady() {
39599 if (this.isStable()) {
39600 // Schedules the call backs in a new frame so that it is always async.
39601 scheduleMicroTask(() => {
39602 while (this._callbacks.length !== 0) {
39603 let cb = this._callbacks.pop();
39604 clearTimeout(cb.timeoutId);
39605 cb.doneCb(this._didWork);
39606 }
39607 this._didWork = false;
39608 });
39609 }
39610 else {
39611 // Still not stable, send updates.
39612 let pending = this.getPendingTasks();
39613 this._callbacks = this._callbacks.filter((cb) => {
39614 if (cb.updateCb && cb.updateCb(pending)) {
39615 clearTimeout(cb.timeoutId);
39616 return false;
39617 }
39618 return true;
39619 });
39620 this._didWork = true;
39621 }
39622 }
39623 getPendingTasks() {
39624 if (!this.taskTrackingZone) {
39625 return [];
39626 }
39627 // Copy the tasks data so that we don't leak tasks.
39628 return this.taskTrackingZone.macroTasks.map((t) => {
39629 return {
39630 source: t.source,
39631 // From TaskTrackingZone:
39632 // https://github.com/angular/zone.js/blob/master/lib/zone-spec/task-tracking.ts#L40
39633 creationLocation: t.creationLocation,
39634 data: t.data
39635 };
39636 });
39637 }
39638 addCallback(cb, timeout, updateCb) {
39639 let timeoutId = -1;
39640 if (timeout && timeout > 0) {
39641 timeoutId = setTimeout(() => {
39642 this._callbacks = this._callbacks.filter((cb) => cb.timeoutId !== timeoutId);
39643 cb(this._didWork, this.getPendingTasks());
39644 }, timeout);
39645 }
39646 this._callbacks.push({ doneCb: cb, timeoutId: timeoutId, updateCb: updateCb });
39647 }
39648 /**
39649 * Wait for the application to be stable with a timeout. If the timeout is reached before that
39650 * happens, the callback receives a list of the macro tasks that were pending, otherwise null.
39651 *
39652 * @param doneCb The callback to invoke when Angular is stable or the timeout expires
39653 * whichever comes first.
39654 * @param timeout Optional. The maximum time to wait for Angular to become stable. If not
39655 * specified, whenStable() will wait forever.
39656 * @param updateCb Optional. If specified, this callback will be invoked whenever the set of
39657 * pending macrotasks changes. If this callback returns true doneCb will not be invoked
39658 * and no further updates will be issued.
39659 */
39660 whenStable(doneCb, timeout, updateCb) {
39661 if (updateCb && !this.taskTrackingZone) {
39662 throw new Error('Task tracking zone is required when passing an update callback to ' +
39663 'whenStable(). Is "zone.js/dist/task-tracking.js" loaded?');
39664 }
39665 // These arguments are 'Function' above to keep the public API simple.
39666 this.addCallback(doneCb, timeout, updateCb);
39667 this._runCallbacksIfReady();
39668 }
39669 /**
39670 * Get the number of pending requests
39671 * @deprecated pending requests are now tracked with zones
39672 */
39673 getPendingRequestCount() {
39674 return this._pendingCount;
39675 }
39676 /**
39677 * Find providers by name
39678 * @param using The root element to search from
39679 * @param provider The name of binding variable
39680 * @param exactMatch Whether using exactMatch
39681 */
39682 findProviders(using, provider, exactMatch) {
39683 // TODO(juliemr): implement.
39684 return [];
39685 }
39686 }
39687 Testability.decorators = [
39688 { type: Injectable }
39689 ];
39690 Testability.ctorParameters = () => [
39691 { type: NgZone }
39692 ];
39693 /**
39694 * A global registry of {@link Testability} instances for specific elements.
39695 * @publicApi
39696 */
39697 class TestabilityRegistry {
39698 constructor() {
39699 /** @internal */
39700 this._applications = new Map();
39701 _testabilityGetter.addToWindow(this);
39702 }
39703 /**
39704 * Registers an application with a testability hook so that it can be tracked
39705 * @param token token of application, root element
39706 * @param testability Testability hook
39707 */
39708 registerApplication(token, testability) {
39709 this._applications.set(token, testability);
39710 }
39711 /**
39712 * Unregisters an application.
39713 * @param token token of application, root element
39714 */
39715 unregisterApplication(token) {
39716 this._applications.delete(token);
39717 }
39718 /**
39719 * Unregisters all applications
39720 */
39721 unregisterAllApplications() {
39722 this._applications.clear();
39723 }
39724 /**
39725 * Get a testability hook associated with the application
39726 * @param elem root element
39727 */
39728 getTestability(elem) {
39729 return this._applications.get(elem) || null;
39730 }
39731 /**
39732 * Get all registered testabilities
39733 */
39734 getAllTestabilities() {
39735 return Array.from(this._applications.values());
39736 }
39737 /**
39738 * Get all registered applications(root elements)
39739 */
39740 getAllRootElements() {
39741 return Array.from(this._applications.keys());
39742 }
39743 /**
39744 * Find testability of a node in the Tree
39745 * @param elem node
39746 * @param findInAncestors whether finding testability in ancestors if testability was not found in
39747 * current node
39748 */
39749 findTestabilityInTree(elem, findInAncestors = true) {
39750 return _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors);
39751 }
39752 }
39753 TestabilityRegistry.decorators = [
39754 { type: Injectable }
39755 ];
39756 TestabilityRegistry.ctorParameters = () => [];
39757 class _NoopGetTestability {
39758 addToWindow(registry) { }
39759 findTestabilityInTree(registry, elem, findInAncestors) {
39760 return null;
39761 }
39762 }
39763 let _testabilityGetter = new _NoopGetTestability();
39764
39765 /**
39766 * @license
39767 * Copyright Google LLC All Rights Reserved.
39768 *
39769 * Use of this source code is governed by an MIT-style license that can be
39770 * found in the LICENSE file at https://angular.io/license
39771 */
39772 /**
39773 * This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
39774 *
39775 * For more information on how to run and debug tests with either Ivy or View Engine (legacy),
39776 * please see [BAZEL.md](./docs/BAZEL.md).
39777 */
39778 let _devMode = true;
39779 /**
39780 * Returns whether Angular is in development mode. After called once,
39781 * the value is locked and won't change any more.
39782 *
39783 * By default, this is true, unless a user calls `enableProdMode` before calling this.
39784 *
39785 * @publicApi
39786 */
39787 function isDevMode() {
39788 return _devMode;
39789 }
39790
39791 /**
39792 * @license
39793 * Copyright Google LLC All Rights Reserved.
39794 *
39795 * Use of this source code is governed by an MIT-style license that can be
39796 * found in the LICENSE file at https://angular.io/license
39797 */
39798 let _platform;
39799 let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
39800 function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {
39801 const compilerFactory = injector.get(CompilerFactory);
39802 const compiler = compilerFactory.createCompiler([options]);
39803 return compiler.compileModuleAsync(moduleType);
39804 }
39805 let isBoundToModule = isBoundToModule__PRE_R3__;
39806 function isBoundToModule__PRE_R3__(cf) {
39807 return cf instanceof ComponentFactoryBoundToModule;
39808 }
39809 const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken');
39810 /**
39811 * Creates a platform.
39812 * Platforms must be created on launch using this function.
39813 *
39814 * @publicApi
39815 */
39816 function createPlatform(injector) {
39817 if (_platform && !_platform.destroyed &&
39818 !_platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
39819 throw new Error('There can be only one platform. Destroy the previous one to create a new one.');
39820 }
39821 _platform = injector.get(PlatformRef);
39822 const inits = injector.get(PLATFORM_INITIALIZER, null);
39823 if (inits)
39824 inits.forEach((init) => init());
39825 return _platform;
39826 }
39827 /**
39828 * Creates a factory for a platform. Can be used to provide or override `Providers` specific to
39829 * your application's runtime needs, such as `PLATFORM_INITIALIZER` and `PLATFORM_ID`.
39830 * @param parentPlatformFactory Another platform factory to modify. Allows you to compose factories
39831 * to build up configurations that might be required by different libraries or parts of the
39832 * application.
39833 * @param name Identifies the new platform factory.
39834 * @param providers A set of dependency providers for platforms created with the new factory.
39835 *
39836 * @publicApi
39837 */
39838 function createPlatformFactory(parentPlatformFactory, name, providers = []) {
39839 const desc = `Platform: ${name}`;
39840 const marker = new InjectionToken(desc);
39841 return (extraProviders = []) => {
39842 let platform = getPlatform();
39843 if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
39844 if (parentPlatformFactory) {
39845 parentPlatformFactory(providers.concat(extraProviders).concat({ provide: marker, useValue: true }));
39846 }
39847 else {
39848 const injectedProviders = providers.concat(extraProviders).concat({ provide: marker, useValue: true }, {
39849 provide: INJECTOR_SCOPE,
39850 useValue: 'platform'
39851 });
39852 createPlatform(Injector.create({ providers: injectedProviders, name: desc }));
39853 }
39854 }
39855 return assertPlatform(marker);
39856 };
39857 }
39858 /**
39859 * Checks that there is currently a platform that contains the given token as a provider.
39860 *
39861 * @publicApi
39862 */
39863 function assertPlatform(requiredToken) {
39864 const platform = getPlatform();
39865 if (!platform) {
39866 throw new Error('No platform exists!');
39867 }
39868 if (!platform.injector.get(requiredToken, null)) {
39869 throw new Error('A platform with a different configuration has been created. Please destroy it first.');
39870 }
39871 return platform;
39872 }
39873 /**
39874 * Returns the current platform.
39875 *
39876 * @publicApi
39877 */
39878 function getPlatform() {
39879 return _platform && !_platform.destroyed ? _platform : null;
39880 }
39881 /**
39882 * The Angular platform is the entry point for Angular on a web page.
39883 * Each page has exactly one platform. Services (such as reflection) which are common
39884 * to every Angular application running on the page are bound in its scope.
39885 * A page's platform is initialized implicitly when a platform is created using a platform
39886 * factory such as `PlatformBrowser`, or explicitly by calling the `createPlatform()` function.
39887 *
39888 * @publicApi
39889 */
39890 class PlatformRef {
39891 /** @internal */
39892 constructor(_injector) {
39893 this._injector = _injector;
39894 this._modules = [];
39895 this._destroyListeners = [];
39896 this._destroyed = false;
39897 }
39898 /**
39899 * Creates an instance of an `@NgModule` for the given platform for offline compilation.
39900 *
39901 * @usageNotes
39902 *
39903 * The following example creates the NgModule for a browser platform.
39904 *
39905 * ```typescript
39906 * my_module.ts:
39907 *
39908 * @NgModule({
39909 * imports: [BrowserModule]
39910 * })
39911 * class MyModule {}
39912 *
39913 * main.ts:
39914 * import {MyModuleNgFactory} from './my_module.ngfactory';
39915 * import {platformBrowser} from '@angular/platform-browser';
39916 *
39917 * let moduleRef = platformBrowser().bootstrapModuleFactory(MyModuleNgFactory);
39918 * ```
39919 */
39920 bootstrapModuleFactory(moduleFactory, options) {
39921 // Note: We need to create the NgZone _before_ we instantiate the module,
39922 // as instantiating the module creates some providers eagerly.
39923 // So we create a mini parent injector that just contains the new NgZone and
39924 // pass that as parent to the NgModuleFactory.
39925 const ngZoneOption = options ? options.ngZone : undefined;
39926 const ngZoneEventCoalescing = (options && options.ngZoneEventCoalescing) || false;
39927 const ngZoneRunCoalescing = (options && options.ngZoneRunCoalescing) || false;
39928 const ngZone = getNgZone(ngZoneOption, { ngZoneEventCoalescing, ngZoneRunCoalescing });
39929 const providers = [{ provide: NgZone, useValue: ngZone }];
39930 // Note: Create ngZoneInjector within ngZone.run so that all of the instantiated services are
39931 // created within the Angular zone
39932 // Do not try to replace ngZone.run with ApplicationRef#run because ApplicationRef would then be
39933 // created outside of the Angular zone.
39934 return ngZone.run(() => {
39935 const ngZoneInjector = Injector.create({ providers: providers, parent: this.injector, name: moduleFactory.moduleType.name });
39936 const moduleRef = moduleFactory.create(ngZoneInjector);
39937 const exceptionHandler = moduleRef.injector.get(ErrorHandler, null);
39938 if (!exceptionHandler) {
39939 throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
39940 }
39941 ngZone.runOutsideAngular(() => {
39942 const subscription = ngZone.onError.subscribe({
39943 next: (error) => {
39944 exceptionHandler.handleError(error);
39945 }
39946 });
39947 moduleRef.onDestroy(() => {
39948 remove(this._modules, moduleRef);
39949 subscription.unsubscribe();
39950 });
39951 });
39952 return _callAndReportToErrorHandler(exceptionHandler, ngZone, () => {
39953 const initStatus = moduleRef.injector.get(ApplicationInitStatus);
39954 initStatus.runInitializers();
39955 return initStatus.donePromise.then(() => {
39956 if (ivyEnabled) {
39957 // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy
39958 const localeId = moduleRef.injector.get(LOCALE_ID$1, DEFAULT_LOCALE_ID);
39959 setLocaleId(localeId || DEFAULT_LOCALE_ID);
39960 }
39961 this._moduleDoBootstrap(moduleRef);
39962 return moduleRef;
39963 });
39964 });
39965 });
39966 }
39967 /**
39968 * Creates an instance of an `@NgModule` for a given platform using the given runtime compiler.
39969 *
39970 * @usageNotes
39971 * ### Simple Example
39972 *
39973 * ```typescript
39974 * @NgModule({
39975 * imports: [BrowserModule]
39976 * })
39977 * class MyModule {}
39978 *
39979 * let moduleRef = platformBrowser().bootstrapModule(MyModule);
39980 * ```
39981 *
39982 */
39983 bootstrapModule(moduleType, compilerOptions = []) {
39984 const options = optionsReducer({}, compilerOptions);
39985 return compileNgModuleFactory(this.injector, options, moduleType)
39986 .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
39987 }
39988 _moduleDoBootstrap(moduleRef) {
39989 const appRef = moduleRef.injector.get(ApplicationRef);
39990 if (moduleRef._bootstrapComponents.length > 0) {
39991 moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
39992 }
39993 else if (moduleRef.instance.ngDoBootstrap) {
39994 moduleRef.instance.ngDoBootstrap(appRef);
39995 }
39996 else {
39997 throw new Error(`The module ${stringify$1(moduleRef.instance
39998 .constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
39999 `Please define one of these.`);
40000 }
40001 this._modules.push(moduleRef);
40002 }
40003 /**
40004 * Registers a listener to be called when the platform is destroyed.
40005 */
40006 onDestroy(callback) {
40007 this._destroyListeners.push(callback);
40008 }
40009 /**
40010 * Retrieves the platform {@link Injector}, which is the parent injector for
40011 * every Angular application on the page and provides singleton providers.
40012 */
40013 get injector() {
40014 return this._injector;
40015 }
40016 /**
40017 * Destroys the current Angular platform and all Angular applications on the page.
40018 * Destroys all modules and listeners registered with the platform.
40019 */
40020 destroy() {
40021 if (this._destroyed) {
40022 throw new Error('The platform has already been destroyed!');
40023 }
40024 this._modules.slice().forEach(module => module.destroy());
40025 this._destroyListeners.forEach(listener => listener());
40026 this._destroyed = true;
40027 }
40028 get destroyed() {
40029 return this._destroyed;
40030 }
40031 }
40032 PlatformRef.decorators = [
40033 { type: Injectable }
40034 ];
40035 PlatformRef.ctorParameters = () => [
40036 { type: Injector }
40037 ];
40038 function getNgZone(ngZoneOption, extra) {
40039 let ngZone;
40040 if (ngZoneOption === 'noop') {
40041 ngZone = new NoopNgZone();
40042 }
40043 else {
40044 ngZone = (ngZoneOption === 'zone.js' ? undefined : ngZoneOption) || new NgZone({
40045 enableLongStackTrace: isDevMode(),
40046 shouldCoalesceEventChangeDetection: !!(extra === null || extra === void 0 ? void 0 : extra.ngZoneEventCoalescing),
40047 shouldCoalesceRunChangeDetection: !!(extra === null || extra === void 0 ? void 0 : extra.ngZoneRunCoalescing)
40048 });
40049 }
40050 return ngZone;
40051 }
40052 function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
40053 try {
40054 const result = callback();
40055 if (isPromise$1(result)) {
40056 return result.catch((e) => {
40057 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
40058 // rethrow as the exception handler might not do it
40059 throw e;
40060 });
40061 }
40062 return result;
40063 }
40064 catch (e) {
40065 ngZone.runOutsideAngular(() => errorHandler.handleError(e));
40066 // rethrow as the exception handler might not do it
40067 throw e;
40068 }
40069 }
40070 function optionsReducer(dst, objs) {
40071 if (Array.isArray(objs)) {
40072 dst = objs.reduce(optionsReducer, dst);
40073 }
40074 else {
40075 dst = Object.assign(Object.assign({}, dst), objs);
40076 }
40077 return dst;
40078 }
40079 /**
40080 * A reference to an Angular application running on a page.
40081 *
40082 * @usageNotes
40083 *
40084 * {@a is-stable-examples}
40085 * ### isStable examples and caveats
40086 *
40087 * Note two important points about `isStable`, demonstrated in the examples below:
40088 * - the application will never be stable if you start any kind
40089 * of recurrent asynchronous task when the application starts
40090 * (for example for a polling process, started with a `setInterval`, a `setTimeout`
40091 * or using RxJS operators like `interval`);
40092 * - the `isStable` Observable runs outside of the Angular zone.
40093 *
40094 * Let's imagine that you start a recurrent task
40095 * (here incrementing a counter, using RxJS `interval`),
40096 * and at the same time subscribe to `isStable`.
40097 *
40098 * ```
40099 * constructor(appRef: ApplicationRef) {
40100 * appRef.isStable.pipe(
40101 * filter(stable => stable)
40102 * ).subscribe(() => console.log('App is stable now');
40103 * interval(1000).subscribe(counter => console.log(counter));
40104 * }
40105 * ```
40106 * In this example, `isStable` will never emit `true`,
40107 * and the trace "App is stable now" will never get logged.
40108 *
40109 * If you want to execute something when the app is stable,
40110 * you have to wait for the application to be stable
40111 * before starting your polling process.
40112 *
40113 * ```
40114 * constructor(appRef: ApplicationRef) {
40115 * appRef.isStable.pipe(
40116 * first(stable => stable),
40117 * tap(stable => console.log('App is stable now')),
40118 * switchMap(() => interval(1000))
40119 * ).subscribe(counter => console.log(counter));
40120 * }
40121 * ```
40122 * In this example, the trace "App is stable now" will be logged
40123 * and then the counter starts incrementing every second.
40124 *
40125 * Note also that this Observable runs outside of the Angular zone,
40126 * which means that the code in the subscription
40127 * to this Observable will not trigger the change detection.
40128 *
40129 * Let's imagine that instead of logging the counter value,
40130 * you update a field of your component
40131 * and display it in its template.
40132 *
40133 * ```
40134 * constructor(appRef: ApplicationRef) {
40135 * appRef.isStable.pipe(
40136 * first(stable => stable),
40137 * switchMap(() => interval(1000))
40138 * ).subscribe(counter => this.value = counter);
40139 * }
40140 * ```
40141 * As the `isStable` Observable runs outside the zone,
40142 * the `value` field will be updated properly,
40143 * but the template will not be refreshed!
40144 *
40145 * You'll have to manually trigger the change detection to update the template.
40146 *
40147 * ```
40148 * constructor(appRef: ApplicationRef, cd: ChangeDetectorRef) {
40149 * appRef.isStable.pipe(
40150 * first(stable => stable),
40151 * switchMap(() => interval(1000))
40152 * ).subscribe(counter => {
40153 * this.value = counter;
40154 * cd.detectChanges();
40155 * });
40156 * }
40157 * ```
40158 *
40159 * Or make the subscription callback run inside the zone.
40160 *
40161 * ```
40162 * constructor(appRef: ApplicationRef, zone: NgZone) {
40163 * appRef.isStable.pipe(
40164 * first(stable => stable),
40165 * switchMap(() => interval(1000))
40166 * ).subscribe(counter => zone.run(() => this.value = counter));
40167 * }
40168 * ```
40169 *
40170 * @publicApi
40171 */
40172 class ApplicationRef {
40173 /** @internal */
40174 constructor(_zone, _injector, _exceptionHandler, _componentFactoryResolver, _initStatus) {
40175 this._zone = _zone;
40176 this._injector = _injector;
40177 this._exceptionHandler = _exceptionHandler;
40178 this._componentFactoryResolver = _componentFactoryResolver;
40179 this._initStatus = _initStatus;
40180 /** @internal */
40181 this._bootstrapListeners = [];
40182 this._views = [];
40183 this._runningTick = false;
40184 this._stable = true;
40185 /**
40186 * Get a list of component types registered to this application.
40187 * This list is populated even before the component is created.
40188 */
40189 this.componentTypes = [];
40190 /**
40191 * Get a list of components registered to this application.
40192 */
40193 this.components = [];
40194 this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({
40195 next: () => {
40196 this._zone.run(() => {
40197 this.tick();
40198 });
40199 }
40200 });
40201 const isCurrentlyStable = new Observable((observer) => {
40202 this._stable = this._zone.isStable && !this._zone.hasPendingMacrotasks &&
40203 !this._zone.hasPendingMicrotasks;
40204 this._zone.runOutsideAngular(() => {
40205 observer.next(this._stable);
40206 observer.complete();
40207 });
40208 });
40209 const isStable = new Observable((observer) => {
40210 // Create the subscription to onStable outside the Angular Zone so that
40211 // the callback is run outside the Angular Zone.
40212 let stableSub;
40213 this._zone.runOutsideAngular(() => {
40214 stableSub = this._zone.onStable.subscribe(() => {
40215 NgZone.assertNotInAngularZone();
40216 // Check whether there are no pending macro/micro tasks in the next tick
40217 // to allow for NgZone to update the state.
40218 scheduleMicroTask(() => {
40219 if (!this._stable && !this._zone.hasPendingMacrotasks &&
40220 !this._zone.hasPendingMicrotasks) {
40221 this._stable = true;
40222 observer.next(true);
40223 }
40224 });
40225 });
40226 });
40227 const unstableSub = this._zone.onUnstable.subscribe(() => {
40228 NgZone.assertInAngularZone();
40229 if (this._stable) {
40230 this._stable = false;
40231 this._zone.runOutsideAngular(() => {
40232 observer.next(false);
40233 });
40234 }
40235 });
40236 return () => {
40237 stableSub.unsubscribe();
40238 unstableSub.unsubscribe();
40239 };
40240 });
40241 this.isStable =
40242 merge$1(isCurrentlyStable, isStable.pipe(share()));
40243 }
40244 /**
40245 * Bootstrap a new component at the root level of the application.
40246 *
40247 * @usageNotes
40248 * ### Bootstrap process
40249 *
40250 * When bootstrapping a new root component into an application, Angular mounts the
40251 * specified application component onto DOM elements identified by the componentType's
40252 * selector and kicks off automatic change detection to finish initializing the component.
40253 *
40254 * Optionally, a component can be mounted onto a DOM element that does not match the
40255 * componentType's selector.
40256 *
40257 * ### Example
40258 * {@example core/ts/platform/platform.ts region='longform'}
40259 */
40260 bootstrap(componentOrFactory, rootSelectorOrNode) {
40261 if (!this._initStatus.done) {
40262 throw new Error('Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
40263 }
40264 let componentFactory;
40265 if (componentOrFactory instanceof ComponentFactory) {
40266 componentFactory = componentOrFactory;
40267 }
40268 else {
40269 componentFactory =
40270 this._componentFactoryResolver.resolveComponentFactory(componentOrFactory);
40271 }
40272 this.componentTypes.push(componentFactory.componentType);
40273 // Create a factory associated with the current module if it's not bound to some other
40274 const ngModule = isBoundToModule(componentFactory) ? undefined : this._injector.get(NgModuleRef);
40275 const selectorOrNode = rootSelectorOrNode || componentFactory.selector;
40276 const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);
40277 const nativeElement = compRef.location.nativeElement;
40278 const testability = compRef.injector.get(Testability, null);
40279 const testabilityRegistry = testability && compRef.injector.get(TestabilityRegistry);
40280 if (testability && testabilityRegistry) {
40281 testabilityRegistry.registerApplication(nativeElement, testability);
40282 }
40283 compRef.onDestroy(() => {
40284 this.detachView(compRef.hostView);
40285 remove(this.components, compRef);
40286 if (testabilityRegistry) {
40287 testabilityRegistry.unregisterApplication(nativeElement);
40288 }
40289 });
40290 this._loadComponent(compRef);
40291 // Note that we have still left the `isDevMode()` condition in order to avoid
40292 // creating a breaking change for projects that still use the View Engine.
40293 if ((typeof ngDevMode === 'undefined' || ngDevMode) && isDevMode()) {
40294 const _console = this._injector.get(Console);
40295 _console.log(`Angular is running in development mode. Call enableProdMode() to enable production mode.`);
40296 }
40297 return compRef;
40298 }
40299 /**
40300 * Invoke this method to explicitly process change detection and its side-effects.
40301 *
40302 * In development mode, `tick()` also performs a second change detection cycle to ensure that no
40303 * further changes are detected. If additional changes are picked up during this second cycle,
40304 * bindings in the app have side-effects that cannot be resolved in a single change detection
40305 * pass.
40306 * In this case, Angular throws an error, since an Angular application can only have one change
40307 * detection pass during which all change detection must complete.
40308 */
40309 tick() {
40310 if (this._runningTick) {
40311 throw new Error('ApplicationRef.tick is called recursively');
40312 }
40313 try {
40314 this._runningTick = true;
40315 for (let view of this._views) {
40316 view.detectChanges();
40317 }
40318 // Note that we have still left the `isDevMode()` condition in order to avoid
40319 // creating a breaking change for projects that still use the View Engine.
40320 if ((typeof ngDevMode === 'undefined' || ngDevMode) && isDevMode()) {
40321 for (let view of this._views) {
40322 view.checkNoChanges();
40323 }
40324 }
40325 }
40326 catch (e) {
40327 // Attention: Don't rethrow as it could cancel subscriptions to Observables!
40328 this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));
40329 }
40330 finally {
40331 this._runningTick = false;
40332 }
40333 }
40334 /**
40335 * Attaches a view so that it will be dirty checked.
40336 * The view will be automatically detached when it is destroyed.
40337 * This will throw if the view is already attached to a ViewContainer.
40338 */
40339 attachView(viewRef) {
40340 const view = viewRef;
40341 this._views.push(view);
40342 view.attachToAppRef(this);
40343 }
40344 /**
40345 * Detaches a view from dirty checking again.
40346 */
40347 detachView(viewRef) {
40348 const view = viewRef;
40349 remove(this._views, view);
40350 view.detachFromAppRef();
40351 }
40352 _loadComponent(componentRef) {
40353 this.attachView(componentRef.hostView);
40354 this.tick();
40355 this.components.push(componentRef);
40356 // Get the listeners lazily to prevent DI cycles.
40357 const listeners = this._injector.get(APP_BOOTSTRAP_LISTENER, []).concat(this._bootstrapListeners);
40358 listeners.forEach((listener) => listener(componentRef));
40359 }
40360 /** @internal */
40361 ngOnDestroy() {
40362 this._views.slice().forEach((view) => view.destroy());
40363 this._onMicrotaskEmptySubscription.unsubscribe();
40364 }
40365 /**
40366 * Returns the number of attached views.
40367 */
40368 get viewCount() {
40369 return this._views.length;
40370 }
40371 }
40372 ApplicationRef.decorators = [
40373 { type: Injectable }
40374 ];
40375 ApplicationRef.ctorParameters = () => [
40376 { type: NgZone },
40377 { type: Injector },
40378 { type: ErrorHandler },
40379 { type: ComponentFactoryResolver },
40380 { type: ApplicationInitStatus }
40381 ];
40382 function remove(list, el) {
40383 const index = list.indexOf(el);
40384 if (index > -1) {
40385 list.splice(index, 1);
40386 }
40387 }
40388
40389 /**
40390 * @license
40391 * Copyright Google LLC All Rights Reserved.
40392 *
40393 * Use of this source code is governed by an MIT-style license that can be
40394 * found in the LICENSE file at https://angular.io/license
40395 */
40396 const _CORE_PLATFORM_PROVIDERS = [
40397 // Set a default platform name for platforms that don't set it explicitly.
40398 { provide: PLATFORM_ID, useValue: 'unknown' },
40399 { provide: PlatformRef, deps: [Injector] },
40400 { provide: TestabilityRegistry, deps: [] },
40401 { provide: Console, deps: [] },
40402 ];
40403 /**
40404 * This platform has to be included in any other platform
40405 *
40406 * @publicApi
40407 */
40408 const platformCore = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS);
40409
40410 /**
40411 * @license
40412 * Copyright Google LLC All Rights Reserved.
40413 *
40414 * Use of this source code is governed by an MIT-style license that can be
40415 * found in the LICENSE file at https://angular.io/license
40416 */
40417 function _iterableDiffersFactory() {
40418 return defaultIterableDiffers;
40419 }
40420 function _keyValueDiffersFactory() {
40421 return defaultKeyValueDiffers;
40422 }
40423 function _localeFactory(locale) {
40424 locale = locale || getGlobalLocale();
40425 return locale;
40426 }
40427 /**
40428 * Work out the locale from the potential global properties.
40429 *
40430 * * Closure Compiler: use `goog.LOCALE`.
40431 * * Ivy enabled: use `$localize.locale`
40432 */
40433 function getGlobalLocale() {
40434 if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
40435 typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
40436 // * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
40437 // * In order to preserve backwards compatibility, we use Angular default value over
40438 // Closure Compiler's one.
40439 return goog.LOCALE;
40440 }
40441 else {
40442 // KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
40443 // COMPILE-TIME INLINER.
40444 //
40445 // * During compile time inlining of translations the expression will be replaced
40446 // with a string literal that is the current locale. Other forms of this expression are not
40447 // guaranteed to be replaced.
40448 //
40449 // * During runtime translation evaluation, the developer is required to set `$localize.locale`
40450 // if required, or just to provide their own `LOCALE_ID` provider.
40451 return DEFAULT_LOCALE_ID;
40452 }
40453 }
40454 const ɵ0$b = USD_CURRENCY_CODE;
40455 /**
40456 * A built-in [dependency injection token](guide/glossary#di-token)
40457 * that is used to configure the root injector for bootstrapping.
40458 */
40459 const APPLICATION_MODULE_PROVIDERS = [
40460 {
40461 provide: ApplicationRef,
40462 useClass: ApplicationRef,
40463 deps: [NgZone, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus]
40464 },
40465 { provide: SCHEDULER, deps: [NgZone], useFactory: zoneSchedulerFactory },
40466 {
40467 provide: ApplicationInitStatus,
40468 useClass: ApplicationInitStatus,
40469 deps: [[new Optional(), APP_INITIALIZER]]
40470 },
40471 { provide: Compiler, useClass: Compiler, deps: [] },
40472 APP_ID_RANDOM_PROVIDER,
40473 { provide: IterableDiffers, useFactory: _iterableDiffersFactory, deps: [] },
40474 { provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory, deps: [] },
40475 {
40476 provide: LOCALE_ID$1,
40477 useFactory: _localeFactory,
40478 deps: [[new Inject(LOCALE_ID$1), new Optional(), new SkipSelf()]]
40479 },
40480 { provide: DEFAULT_CURRENCY_CODE, useValue: ɵ0$b },
40481 ];
40482 /**
40483 * Schedule work at next available slot.
40484 *
40485 * In Ivy this is just `requestAnimationFrame`. For compatibility reasons when bootstrapped
40486 * using `platformRef.bootstrap` we need to use `NgZone.onStable` as the scheduling mechanism.
40487 * This overrides the scheduling mechanism in Ivy to `NgZone.onStable`.
40488 *
40489 * @param ngZone NgZone to use for scheduling.
40490 */
40491 function zoneSchedulerFactory(ngZone) {
40492 let queue = [];
40493 ngZone.onStable.subscribe(() => {
40494 while (queue.length) {
40495 queue.pop()();
40496 }
40497 });
40498 return function (fn) {
40499 queue.push(fn);
40500 };
40501 }
40502
40503 /**
40504 * @license
40505 * Copyright Google LLC All Rights Reserved.
40506 *
40507 * Use of this source code is governed by an MIT-style license that can be
40508 * found in the LICENSE file at https://angular.io/license
40509 */
40510 var ViewAction;
40511 (function (ViewAction) {
40512 ViewAction[ViewAction["CreateViewNodes"] = 0] = "CreateViewNodes";
40513 ViewAction[ViewAction["CheckNoChanges"] = 1] = "CheckNoChanges";
40514 ViewAction[ViewAction["CheckNoChangesProjectedViews"] = 2] = "CheckNoChangesProjectedViews";
40515 ViewAction[ViewAction["CheckAndUpdate"] = 3] = "CheckAndUpdate";
40516 ViewAction[ViewAction["CheckAndUpdateProjectedViews"] = 4] = "CheckAndUpdateProjectedViews";
40517 ViewAction[ViewAction["Destroy"] = 5] = "Destroy";
40518 })(ViewAction || (ViewAction = {}));
40519
40520 /**
40521 * @license
40522 * Copyright Google LLC All Rights Reserved.
40523 *
40524 * Use of this source code is governed by an MIT-style license that can be
40525 * found in the LICENSE file at https://angular.io/license
40526 */
40527 var DebugAction;
40528 (function (DebugAction) {
40529 DebugAction[DebugAction["create"] = 0] = "create";
40530 DebugAction[DebugAction["detectChanges"] = 1] = "detectChanges";
40531 DebugAction[DebugAction["checkNoChanges"] = 2] = "checkNoChanges";
40532 DebugAction[DebugAction["destroy"] = 3] = "destroy";
40533 DebugAction[DebugAction["handleEvent"] = 4] = "handleEvent";
40534 })(DebugAction || (DebugAction = {}));
40535
40536 /**
40537 * @license
40538 * Copyright Google LLC All Rights Reserved.
40539 *
40540 * Use of this source code is governed by an MIT-style license that can be
40541 * found in the LICENSE file at https://angular.io/license
40542 */
40543 if (typeof ngDevMode !== 'undefined' && ngDevMode) {
40544 // This helper is to give a reasonable error message to people upgrading to v9 that have not yet
40545 // installed `@angular/localize` in their app.
40546 // tslint:disable-next-line: no-toplevel-property-access
40547 _global$1.$localize = _global$1.$localize || function () {
40548 throw new Error('It looks like your application or one of its dependencies is using i18n.\n' +
40549 'Angular 9 introduced a global `$localize()` function that needs to be loaded.\n' +
40550 'Please run `ng add @angular/localize` from the Angular CLI.\n' +
40551 '(For non-CLI projects, add `import \'@angular/localize/init\';` to your `polyfills.ts` file.\n' +
40552 'For server-side rendering applications add the import to your `main.server.ts` file.)');
40553 };
40554 }
40555
40556 /**
40557 * @license
40558 * Copyright Google LLC All Rights Reserved.
40559 *
40560 * Use of this source code is governed by an MIT-style license that can be
40561 * found in the LICENSE file at https://angular.io/license
40562 */
40563 // Metadata Schema
40564 // If you make a backwards incompatible change to the schema, increment the METADTA_VERSION number.
40565 // If you make a backwards compatible change to the metadata (such as adding an option field) then
40566 // leave METADATA_VERSION the same. If possible, supply as many versions of the metadata that can
40567 // represent the semantics of the file in an array. For example, when generating a version 2 file,
40568 // if version 1 can accurately represent the metadata, generate both version 1 and version 2 in
40569 // an array.
40570 const METADATA_VERSION = 4;
40571 function isClassMetadata(value) {
40572 return value && value.__symbolic === 'class';
40573 }
40574 function isMethodMetadata(value) {
40575 return value && (value.__symbolic === 'constructor' || value.__symbolic === 'method');
40576 }
40577 function isConstructorMetadata(value) {
40578 return value && value.__symbolic === 'constructor';
40579 }
40580 function isFunctionMetadata(value) {
40581 return value && value.__symbolic === 'function';
40582 }
40583 function isMetadataSymbolicExpression(value) {
40584 if (value) {
40585 switch (value.__symbolic) {
40586 case 'binary':
40587 case 'call':
40588 case 'index':
40589 case 'new':
40590 case 'pre':
40591 case 'reference':
40592 case 'select':
40593 case 'spread':
40594 case 'if':
40595 return true;
40596 }
40597 }
40598 return false;
40599 }
40600 function isMetadataGlobalReferenceExpression(value) {
40601 return value && value.name && !value.module && isMetadataSymbolicReferenceExpression(value);
40602 }
40603 function isMetadataModuleReferenceExpression(value) {
40604 return value && value.module && !value.name && !value.default &&
40605 isMetadataSymbolicReferenceExpression(value);
40606 }
40607 function isMetadataImportedSymbolReferenceExpression(value) {
40608 return value && value.module && !!value.name && isMetadataSymbolicReferenceExpression(value);
40609 }
40610 function isMetadataImportDefaultReference(value) {
40611 return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value);
40612 }
40613 function isMetadataSymbolicReferenceExpression(value) {
40614 return value && value.__symbolic === 'reference';
40615 }
40616 function isMetadataSymbolicSelectExpression(value) {
40617 return value && value.__symbolic === 'select';
40618 }
40619 function isMetadataSymbolicSpreadExpression(value) {
40620 return value && value.__symbolic === 'spread';
40621 }
40622 function isMetadataError$1(value) {
40623 return value && value.__symbolic === 'error';
40624 }
40625
40626 /**
40627 * @license
40628 * Copyright Google LLC All Rights Reserved.
40629 *
40630 * Use of this source code is governed by an MIT-style license that can be
40631 * found in the LICENSE file at https://angular.io/license
40632 */
40633 // In TypeScript 2.1 the spread element kind was renamed.
40634 const spreadElementSyntaxKind = ts.SyntaxKind.SpreadElement || ts.SyntaxKind.SpreadElementExpression;
40635 function isMethodCallOf(callExpression, memberName) {
40636 const expression = callExpression.expression;
40637 if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
40638 const propertyAccessExpression = expression;
40639 const name = propertyAccessExpression.name;
40640 if (name.kind == ts.SyntaxKind.Identifier) {
40641 return name.text === memberName;
40642 }
40643 }
40644 return false;
40645 }
40646 function isCallOf(callExpression, ident) {
40647 const expression = callExpression.expression;
40648 if (expression.kind === ts.SyntaxKind.Identifier) {
40649 const identifier = expression;
40650 return identifier.text === ident;
40651 }
40652 return false;
40653 }
40654 /* @internal */
40655 function recordMapEntry(entry, node, nodeMap, sourceFile) {
40656 if (!nodeMap.has(entry)) {
40657 nodeMap.set(entry, node);
40658 if (node &&
40659 (isMetadataImportedSymbolReferenceExpression(entry) ||
40660 isMetadataImportDefaultReference(entry)) &&
40661 entry.line == null) {
40662 const info = sourceInfo(node, sourceFile);
40663 if (info.line != null)
40664 entry.line = info.line;
40665 if (info.character != null)
40666 entry.character = info.character;
40667 }
40668 }
40669 return entry;
40670 }
40671 /**
40672 * ts.forEachChild stops iterating children when the callback return a truthy value.
40673 * This method inverts this to implement an `every` style iterator. It will return
40674 * true if every call to `cb` returns `true`.
40675 */
40676 function everyNodeChild(node, cb) {
40677 return !ts.forEachChild(node, node => !cb(node));
40678 }
40679 function isPrimitive$1(value) {
40680 return Object(value) !== value;
40681 }
40682 function isDefined$1(obj) {
40683 return obj !== undefined;
40684 }
40685 function getSourceFileOfNode(node) {
40686 while (node && node.kind != ts.SyntaxKind.SourceFile) {
40687 node = node.parent;
40688 }
40689 return node;
40690 }
40691 /* @internal */
40692 function sourceInfo(node, sourceFile) {
40693 if (node) {
40694 sourceFile = sourceFile || getSourceFileOfNode(node);
40695 if (sourceFile) {
40696 return ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
40697 }
40698 }
40699 return {};
40700 }
40701 /* @internal */
40702 function errorSymbol(message, node, context, sourceFile) {
40703 const result = Object.assign({ __symbolic: 'error', message }, sourceInfo(node, sourceFile));
40704 if (context) {
40705 result.context = context;
40706 }
40707 return result;
40708 }
40709 /**
40710 * Produce a symbolic representation of an expression folding values into their final value when
40711 * possible.
40712 */
40713 class Evaluator {
40714 constructor(symbols, nodeMap, options = {}, recordExport) {
40715 this.symbols = symbols;
40716 this.nodeMap = nodeMap;
40717 this.options = options;
40718 this.recordExport = recordExport;
40719 }
40720 nameOf(node) {
40721 if (node && node.kind == ts.SyntaxKind.Identifier) {
40722 return node.text;
40723 }
40724 const result = node && this.evaluateNode(node);
40725 if (isMetadataError$1(result) || typeof result === 'string') {
40726 return result;
40727 }
40728 else {
40729 return errorSymbol('Name expected', node, { received: (node && node.getText()) || '<missing>' });
40730 }
40731 }
40732 /**
40733 * Returns true if the expression represented by `node` can be folded into a literal expression.
40734 *
40735 * For example, a literal is always foldable. This means that literal expressions such as `1.2`
40736 * `"Some value"` `true` `false` are foldable.
40737 *
40738 * - An object literal is foldable if all the properties in the literal are foldable.
40739 * - An array literal is foldable if all the elements are foldable.
40740 * - A call is foldable if it is a call to a Array.prototype.concat or a call to CONST_EXPR.
40741 * - A property access is foldable if the object is foldable.
40742 * - A array index is foldable if index expression is foldable and the array is foldable.
40743 * - Binary operator expressions are foldable if the left and right expressions are foldable and
40744 * it is one of '+', '-', '*', '/', '%', '||', and '&&'.
40745 * - An identifier is foldable if a value can be found for its symbol in the evaluator symbol
40746 * table.
40747 */
40748 isFoldable(node) {
40749 return this.isFoldableWorker(node, new Map());
40750 }
40751 isFoldableWorker(node, folding) {
40752 if (node) {
40753 switch (node.kind) {
40754 case ts.SyntaxKind.ObjectLiteralExpression:
40755 return everyNodeChild(node, child => {
40756 if (child.kind === ts.SyntaxKind.PropertyAssignment) {
40757 const propertyAssignment = child;
40758 return this.isFoldableWorker(propertyAssignment.initializer, folding);
40759 }
40760 return false;
40761 });
40762 case ts.SyntaxKind.ArrayLiteralExpression:
40763 return everyNodeChild(node, child => this.isFoldableWorker(child, folding));
40764 case ts.SyntaxKind.CallExpression:
40765 const callExpression = node;
40766 // We can fold a <array>.concat(<v>).
40767 if (isMethodCallOf(callExpression, 'concat') &&
40768 arrayOrEmpty(callExpression.arguments).length === 1) {
40769 const arrayNode = callExpression.expression.expression;
40770 if (this.isFoldableWorker(arrayNode, folding) &&
40771 this.isFoldableWorker(callExpression.arguments[0], folding)) {
40772 // It needs to be an array.
40773 const arrayValue = this.evaluateNode(arrayNode);
40774 if (arrayValue && Array.isArray(arrayValue)) {
40775 return true;
40776 }
40777 }
40778 }
40779 // We can fold a call to CONST_EXPR
40780 if (isCallOf(callExpression, 'CONST_EXPR') &&
40781 arrayOrEmpty(callExpression.arguments).length === 1)
40782 return this.isFoldableWorker(callExpression.arguments[0], folding);
40783 return false;
40784 case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
40785 case ts.SyntaxKind.StringLiteral:
40786 case ts.SyntaxKind.NumericLiteral:
40787 case ts.SyntaxKind.NullKeyword:
40788 case ts.SyntaxKind.TrueKeyword:
40789 case ts.SyntaxKind.FalseKeyword:
40790 case ts.SyntaxKind.TemplateHead:
40791 case ts.SyntaxKind.TemplateMiddle:
40792 case ts.SyntaxKind.TemplateTail:
40793 return true;
40794 case ts.SyntaxKind.ParenthesizedExpression:
40795 const parenthesizedExpression = node;
40796 return this.isFoldableWorker(parenthesizedExpression.expression, folding);
40797 case ts.SyntaxKind.BinaryExpression:
40798 const binaryExpression = node;
40799 switch (binaryExpression.operatorToken.kind) {
40800 case ts.SyntaxKind.PlusToken:
40801 case ts.SyntaxKind.MinusToken:
40802 case ts.SyntaxKind.AsteriskToken:
40803 case ts.SyntaxKind.SlashToken:
40804 case ts.SyntaxKind.PercentToken:
40805 case ts.SyntaxKind.AmpersandAmpersandToken:
40806 case ts.SyntaxKind.BarBarToken:
40807 return this.isFoldableWorker(binaryExpression.left, folding) &&
40808 this.isFoldableWorker(binaryExpression.right, folding);
40809 default:
40810 return false;
40811 }
40812 case ts.SyntaxKind.PropertyAccessExpression:
40813 const propertyAccessExpression = node;
40814 return this.isFoldableWorker(propertyAccessExpression.expression, folding);
40815 case ts.SyntaxKind.ElementAccessExpression:
40816 const elementAccessExpression = node;
40817 return this.isFoldableWorker(elementAccessExpression.expression, folding) &&
40818 this.isFoldableWorker(elementAccessExpression.argumentExpression, folding);
40819 case ts.SyntaxKind.Identifier:
40820 let identifier = node;
40821 let reference = this.symbols.resolve(identifier.text);
40822 if (reference !== undefined && isPrimitive$1(reference)) {
40823 return true;
40824 }
40825 break;
40826 case ts.SyntaxKind.TemplateExpression:
40827 const templateExpression = node;
40828 return templateExpression.templateSpans.every(span => this.isFoldableWorker(span.expression, folding));
40829 }
40830 }
40831 return false;
40832 }
40833 /**
40834 * Produce a JSON serialiable object representing `node`. The foldable values in the expression
40835 * tree are folded. For example, a node representing `1 + 2` is folded into `3`.
40836 */
40837 evaluateNode(node, preferReference) {
40838 const t = this;
40839 let error;
40840 function recordEntry(entry, node) {
40841 if (t.options.substituteExpression) {
40842 const newEntry = t.options.substituteExpression(entry, node);
40843 if (t.recordExport && newEntry != entry && isMetadataGlobalReferenceExpression(newEntry)) {
40844 t.recordExport(newEntry.name, entry);
40845 }
40846 entry = newEntry;
40847 }
40848 return recordMapEntry(entry, node, t.nodeMap);
40849 }
40850 function isFoldableError(value) {
40851 return !t.options.verboseInvalidExpression && isMetadataError$1(value);
40852 }
40853 const resolveName = (name, preferReference) => {
40854 const reference = this.symbols.resolve(name, preferReference);
40855 if (reference === undefined) {
40856 // Encode as a global reference. StaticReflector will check the reference.
40857 return recordEntry({ __symbolic: 'reference', name }, node);
40858 }
40859 if (reference && isMetadataSymbolicReferenceExpression(reference)) {
40860 return recordEntry(Object.assign({}, reference), node);
40861 }
40862 return reference;
40863 };
40864 switch (node.kind) {
40865 case ts.SyntaxKind.ObjectLiteralExpression:
40866 let obj = {};
40867 let quoted = [];
40868 ts.forEachChild(node, child => {
40869 switch (child.kind) {
40870 case ts.SyntaxKind.ShorthandPropertyAssignment:
40871 case ts.SyntaxKind.PropertyAssignment:
40872 const assignment = child;
40873 if (assignment.name.kind == ts.SyntaxKind.StringLiteral) {
40874 const name = assignment.name.text;
40875 quoted.push(name);
40876 }
40877 const propertyName = this.nameOf(assignment.name);
40878 if (isFoldableError(propertyName)) {
40879 error = propertyName;
40880 return true;
40881 }
40882 const propertyValue = isPropertyAssignment(assignment) ?
40883 this.evaluateNode(assignment.initializer, /* preferReference */ true) :
40884 resolveName(propertyName, /* preferReference */ true);
40885 if (isFoldableError(propertyValue)) {
40886 error = propertyValue;
40887 return true; // Stop the forEachChild.
40888 }
40889 else {
40890 obj[propertyName] = isPropertyAssignment(assignment) ?
40891 recordEntry(propertyValue, assignment.initializer) :
40892 propertyValue;
40893 }
40894 }
40895 });
40896 if (error)
40897 return error;
40898 if (this.options.quotedNames && quoted.length) {
40899 obj['$quoted$'] = quoted;
40900 }
40901 return recordEntry(obj, node);
40902 case ts.SyntaxKind.ArrayLiteralExpression:
40903 let arr = [];
40904 ts.forEachChild(node, child => {
40905 const value = this.evaluateNode(child, /* preferReference */ true);
40906 // Check for error
40907 if (isFoldableError(value)) {
40908 error = value;
40909 return true; // Stop the forEachChild.
40910 }
40911 // Handle spread expressions
40912 if (isMetadataSymbolicSpreadExpression(value)) {
40913 if (Array.isArray(value.expression)) {
40914 for (const spreadValue of value.expression) {
40915 arr.push(spreadValue);
40916 }
40917 return;
40918 }
40919 }
40920 arr.push(value);
40921 });
40922 if (error)
40923 return error;
40924 return recordEntry(arr, node);
40925 case spreadElementSyntaxKind:
40926 let spreadExpression = this.evaluateNode(node.expression);
40927 return recordEntry({ __symbolic: 'spread', expression: spreadExpression }, node);
40928 case ts.SyntaxKind.CallExpression:
40929 const callExpression = node;
40930 if (isCallOf(callExpression, 'forwardRef') &&
40931 arrayOrEmpty(callExpression.arguments).length === 1) {
40932 const firstArgument = callExpression.arguments[0];
40933 if (firstArgument.kind == ts.SyntaxKind.ArrowFunction) {
40934 const arrowFunction = firstArgument;
40935 return recordEntry(this.evaluateNode(arrowFunction.body), node);
40936 }
40937 }
40938 const args = arrayOrEmpty(callExpression.arguments).map(arg => this.evaluateNode(arg));
40939 if (this.isFoldable(callExpression)) {
40940 if (isMethodCallOf(callExpression, 'concat')) {
40941 const arrayValue = this.evaluateNode(callExpression.expression.expression);
40942 if (isFoldableError(arrayValue))
40943 return arrayValue;
40944 return arrayValue.concat(args[0]);
40945 }
40946 }
40947 // Always fold a CONST_EXPR even if the argument is not foldable.
40948 if (isCallOf(callExpression, 'CONST_EXPR') &&
40949 arrayOrEmpty(callExpression.arguments).length === 1) {
40950 return recordEntry(args[0], node);
40951 }
40952 const expression = this.evaluateNode(callExpression.expression);
40953 if (isFoldableError(expression)) {
40954 return recordEntry(expression, node);
40955 }
40956 let result = { __symbolic: 'call', expression: expression };
40957 if (args && args.length) {
40958 result.arguments = args;
40959 }
40960 return recordEntry(result, node);
40961 case ts.SyntaxKind.NewExpression:
40962 const newExpression = node;
40963 const newArgs = arrayOrEmpty(newExpression.arguments).map(arg => this.evaluateNode(arg));
40964 const newTarget = this.evaluateNode(newExpression.expression);
40965 if (isMetadataError$1(newTarget)) {
40966 return recordEntry(newTarget, node);
40967 }
40968 const call = { __symbolic: 'new', expression: newTarget };
40969 if (newArgs.length) {
40970 call.arguments = newArgs;
40971 }
40972 return recordEntry(call, node);
40973 case ts.SyntaxKind.PropertyAccessExpression: {
40974 const propertyAccessExpression = node;
40975 const expression = this.evaluateNode(propertyAccessExpression.expression);
40976 if (isFoldableError(expression)) {
40977 return recordEntry(expression, node);
40978 }
40979 const member = this.nameOf(propertyAccessExpression.name);
40980 if (isFoldableError(member)) {
40981 return recordEntry(member, node);
40982 }
40983 if (expression && this.isFoldable(propertyAccessExpression.expression))
40984 return expression[member];
40985 if (isMetadataModuleReferenceExpression(expression)) {
40986 // A select into a module reference and be converted into a reference to the symbol
40987 // in the module
40988 return recordEntry({ __symbolic: 'reference', module: expression.module, name: member }, node);
40989 }
40990 return recordEntry({ __symbolic: 'select', expression, member }, node);
40991 }
40992 case ts.SyntaxKind.ElementAccessExpression: {
40993 const elementAccessExpression = node;
40994 const expression = this.evaluateNode(elementAccessExpression.expression);
40995 if (isFoldableError(expression)) {
40996 return recordEntry(expression, node);
40997 }
40998 if (!elementAccessExpression.argumentExpression) {
40999 return recordEntry(errorSymbol('Expression form not supported', node), node);
41000 }
41001 const index = this.evaluateNode(elementAccessExpression.argumentExpression);
41002 if (isFoldableError(expression)) {
41003 return recordEntry(expression, node);
41004 }
41005 if (this.isFoldable(elementAccessExpression.expression) &&
41006 this.isFoldable(elementAccessExpression.argumentExpression))
41007 return expression[index];
41008 return recordEntry({ __symbolic: 'index', expression, index }, node);
41009 }
41010 case ts.SyntaxKind.Identifier:
41011 const identifier = node;
41012 const name = identifier.text;
41013 return resolveName(name, preferReference);
41014 case ts.SyntaxKind.TypeReference:
41015 const typeReferenceNode = node;
41016 const typeNameNode = typeReferenceNode.typeName;
41017 const getReference = node => {
41018 if (typeNameNode.kind === ts.SyntaxKind.QualifiedName) {
41019 const qualifiedName = node;
41020 const left = this.evaluateNode(qualifiedName.left);
41021 if (isMetadataModuleReferenceExpression(left)) {
41022 return recordEntry({
41023 __symbolic: 'reference',
41024 module: left.module,
41025 name: qualifiedName.right.text
41026 }, node);
41027 }
41028 // Record a type reference to a declared type as a select.
41029 return { __symbolic: 'select', expression: left, member: qualifiedName.right.text };
41030 }
41031 else {
41032 const identifier = typeNameNode;
41033 const symbol = this.symbols.resolve(identifier.text);
41034 if (isFoldableError(symbol) || isMetadataSymbolicReferenceExpression(symbol)) {
41035 return recordEntry(symbol, node);
41036 }
41037 return recordEntry(errorSymbol('Could not resolve type', node, { typeName: identifier.text }), node);
41038 }
41039 };
41040 const typeReference = getReference(typeNameNode);
41041 if (isFoldableError(typeReference)) {
41042 return recordEntry(typeReference, node);
41043 }
41044 if (!isMetadataModuleReferenceExpression(typeReference) &&
41045 typeReferenceNode.typeArguments && typeReferenceNode.typeArguments.length) {
41046 const args = typeReferenceNode.typeArguments.map(element => this.evaluateNode(element));
41047 // TODO: Remove typecast when upgraded to 2.0 as it will be correctly inferred.
41048 // Some versions of 1.9 do not infer this correctly.
41049 typeReference.arguments = args;
41050 }
41051 return recordEntry(typeReference, node);
41052 case ts.SyntaxKind.UnionType:
41053 const unionType = node;
41054 // Remove null and undefined from the list of unions.
41055 const references = unionType.types
41056 .filter(n => n.kind !== ts.SyntaxKind.UndefinedKeyword &&
41057 !(ts.isLiteralTypeNode(n) && n.literal.kind === ts.SyntaxKind.NullKeyword))
41058 .map(n => this.evaluateNode(n));
41059 // The remmaining reference must be the same. If two have type arguments consider them
41060 // different even if the type arguments are the same.
41061 let candidate = null;
41062 for (let i = 0; i < references.length; i++) {
41063 const reference = references[i];
41064 if (isMetadataSymbolicReferenceExpression(reference)) {
41065 if (candidate) {
41066 if (reference.name == candidate.name &&
41067 reference.module == candidate.module && !reference.arguments) {
41068 candidate = reference;
41069 }
41070 }
41071 else {
41072 candidate = reference;
41073 }
41074 }
41075 else {
41076 return reference;
41077 }
41078 }
41079 if (candidate)
41080 return candidate;
41081 break;
41082 case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
41083 case ts.SyntaxKind.StringLiteral:
41084 case ts.SyntaxKind.TemplateHead:
41085 case ts.SyntaxKind.TemplateTail:
41086 case ts.SyntaxKind.TemplateMiddle:
41087 return node.text;
41088 case ts.SyntaxKind.NumericLiteral:
41089 return parseFloat(node.text);
41090 case ts.SyntaxKind.AnyKeyword:
41091 return recordEntry({ __symbolic: 'reference', name: 'any' }, node);
41092 case ts.SyntaxKind.StringKeyword:
41093 return recordEntry({ __symbolic: 'reference', name: 'string' }, node);
41094 case ts.SyntaxKind.NumberKeyword:
41095 return recordEntry({ __symbolic: 'reference', name: 'number' }, node);
41096 case ts.SyntaxKind.BooleanKeyword:
41097 return recordEntry({ __symbolic: 'reference', name: 'boolean' }, node);
41098 case ts.SyntaxKind.ArrayType:
41099 const arrayTypeNode = node;
41100 return recordEntry({
41101 __symbolic: 'reference',
41102 name: 'Array',
41103 arguments: [this.evaluateNode(arrayTypeNode.elementType)]
41104 }, node);
41105 case ts.SyntaxKind.NullKeyword:
41106 return null;
41107 case ts.SyntaxKind.TrueKeyword:
41108 return true;
41109 case ts.SyntaxKind.FalseKeyword:
41110 return false;
41111 case ts.SyntaxKind.ParenthesizedExpression:
41112 const parenthesizedExpression = node;
41113 return this.evaluateNode(parenthesizedExpression.expression);
41114 case ts.SyntaxKind.TypeAssertionExpression:
41115 const typeAssertion = node;
41116 return this.evaluateNode(typeAssertion.expression);
41117 case ts.SyntaxKind.PrefixUnaryExpression:
41118 const prefixUnaryExpression = node;
41119 const operand = this.evaluateNode(prefixUnaryExpression.operand);
41120 if (isDefined$1(operand) && isPrimitive$1(operand)) {
41121 switch (prefixUnaryExpression.operator) {
41122 case ts.SyntaxKind.PlusToken:
41123 return +operand;
41124 case ts.SyntaxKind.MinusToken:
41125 return -operand;
41126 case ts.SyntaxKind.TildeToken:
41127 return ~operand;
41128 case ts.SyntaxKind.ExclamationToken:
41129 return !operand;
41130 }
41131 }
41132 let operatorText;
41133 switch (prefixUnaryExpression.operator) {
41134 case ts.SyntaxKind.PlusToken:
41135 operatorText = '+';
41136 break;
41137 case ts.SyntaxKind.MinusToken:
41138 operatorText = '-';
41139 break;
41140 case ts.SyntaxKind.TildeToken:
41141 operatorText = '~';
41142 break;
41143 case ts.SyntaxKind.ExclamationToken:
41144 operatorText = '!';
41145 break;
41146 default:
41147 return undefined;
41148 }
41149 return recordEntry({ __symbolic: 'pre', operator: operatorText, operand: operand }, node);
41150 case ts.SyntaxKind.BinaryExpression:
41151 const binaryExpression = node;
41152 const left = this.evaluateNode(binaryExpression.left);
41153 const right = this.evaluateNode(binaryExpression.right);
41154 if (isDefined$1(left) && isDefined$1(right)) {
41155 if (isPrimitive$1(left) && isPrimitive$1(right))
41156 switch (binaryExpression.operatorToken.kind) {
41157 case ts.SyntaxKind.BarBarToken:
41158 return left || right;
41159 case ts.SyntaxKind.AmpersandAmpersandToken:
41160 return left && right;
41161 case ts.SyntaxKind.AmpersandToken:
41162 return left & right;
41163 case ts.SyntaxKind.BarToken:
41164 return left | right;
41165 case ts.SyntaxKind.CaretToken:
41166 return left ^ right;
41167 case ts.SyntaxKind.EqualsEqualsToken:
41168 return left == right;
41169 case ts.SyntaxKind.ExclamationEqualsToken:
41170 return left != right;
41171 case ts.SyntaxKind.EqualsEqualsEqualsToken:
41172 return left === right;
41173 case ts.SyntaxKind.ExclamationEqualsEqualsToken:
41174 return left !== right;
41175 case ts.SyntaxKind.LessThanToken:
41176 return left < right;
41177 case ts.SyntaxKind.GreaterThanToken:
41178 return left > right;
41179 case ts.SyntaxKind.LessThanEqualsToken:
41180 return left <= right;
41181 case ts.SyntaxKind.GreaterThanEqualsToken:
41182 return left >= right;
41183 case ts.SyntaxKind.LessThanLessThanToken:
41184 return left << right;
41185 case ts.SyntaxKind.GreaterThanGreaterThanToken:
41186 return left >> right;
41187 case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
41188 return left >>> right;
41189 case ts.SyntaxKind.PlusToken:
41190 return left + right;
41191 case ts.SyntaxKind.MinusToken:
41192 return left - right;
41193 case ts.SyntaxKind.AsteriskToken:
41194 return left * right;
41195 case ts.SyntaxKind.SlashToken:
41196 return left / right;
41197 case ts.SyntaxKind.PercentToken:
41198 return left % right;
41199 }
41200 return recordEntry({
41201 __symbolic: 'binop',
41202 operator: binaryExpression.operatorToken.getText(),
41203 left: left,
41204 right: right
41205 }, node);
41206 }
41207 break;
41208 case ts.SyntaxKind.ConditionalExpression:
41209 const conditionalExpression = node;
41210 const condition = this.evaluateNode(conditionalExpression.condition);
41211 const thenExpression = this.evaluateNode(conditionalExpression.whenTrue);
41212 const elseExpression = this.evaluateNode(conditionalExpression.whenFalse);
41213 if (isPrimitive$1(condition)) {
41214 return condition ? thenExpression : elseExpression;
41215 }
41216 return recordEntry({ __symbolic: 'if', condition, thenExpression, elseExpression }, node);
41217 case ts.SyntaxKind.FunctionExpression:
41218 case ts.SyntaxKind.ArrowFunction:
41219 return recordEntry(errorSymbol('Lambda not supported', node), node);
41220 case ts.SyntaxKind.TaggedTemplateExpression:
41221 return recordEntry(errorSymbol('Tagged template expressions are not supported in metadata', node), node);
41222 case ts.SyntaxKind.TemplateExpression:
41223 const templateExpression = node;
41224 if (this.isFoldable(node)) {
41225 return templateExpression.templateSpans.reduce((previous, current) => previous + this.evaluateNode(current.expression) +
41226 this.evaluateNode(current.literal), this.evaluateNode(templateExpression.head));
41227 }
41228 else {
41229 return templateExpression.templateSpans.reduce((previous, current) => {
41230 const expr = this.evaluateNode(current.expression);
41231 const literal = this.evaluateNode(current.literal);
41232 if (isFoldableError(expr))
41233 return expr;
41234 if (isFoldableError(literal))
41235 return literal;
41236 if (typeof previous === 'string' && typeof expr === 'string' &&
41237 typeof literal === 'string') {
41238 return previous + expr + literal;
41239 }
41240 let result = expr;
41241 if (previous !== '') {
41242 result = { __symbolic: 'binop', operator: '+', left: previous, right: expr };
41243 }
41244 if (literal != '') {
41245 result = { __symbolic: 'binop', operator: '+', left: result, right: literal };
41246 }
41247 return result;
41248 }, this.evaluateNode(templateExpression.head));
41249 }
41250 case ts.SyntaxKind.AsExpression:
41251 const asExpression = node;
41252 return this.evaluateNode(asExpression.expression);
41253 case ts.SyntaxKind.ClassExpression:
41254 return { __symbolic: 'class' };
41255 }
41256 return recordEntry(errorSymbol('Expression form not supported', node), node);
41257 }
41258 }
41259 function isPropertyAssignment(node) {
41260 return node.kind == ts.SyntaxKind.PropertyAssignment;
41261 }
41262 const empty$1 = ts.createNodeArray();
41263 function arrayOrEmpty(v) {
41264 return v || empty$1;
41265 }
41266
41267 /**
41268 * @license
41269 * Copyright Google LLC All Rights Reserved.
41270 *
41271 * Use of this source code is governed by an MIT-style license that can be
41272 * found in the LICENSE file at https://angular.io/license
41273 */
41274 class Symbols {
41275 constructor(sourceFile) {
41276 this.sourceFile = sourceFile;
41277 this.references = new Map();
41278 }
41279 resolve(name, preferReference) {
41280 return (preferReference && this.references.get(name)) || this.symbols.get(name);
41281 }
41282 define(name, value) {
41283 this.symbols.set(name, value);
41284 }
41285 defineReference(name, value) {
41286 this.references.set(name, value);
41287 }
41288 has(name) {
41289 return this.symbols.has(name);
41290 }
41291 get symbols() {
41292 let result = this._symbols;
41293 if (!result) {
41294 result = this._symbols = new Map();
41295 populateBuiltins(result);
41296 this.buildImports();
41297 }
41298 return result;
41299 }
41300 buildImports() {
41301 const symbols = this._symbols;
41302 // Collect the imported symbols into this.symbols
41303 const stripQuotes = (s) => s.replace(/^['"]|['"]$/g, '');
41304 const visit = (node) => {
41305 switch (node.kind) {
41306 case ts.SyntaxKind.ImportEqualsDeclaration:
41307 const importEqualsDeclaration = node;
41308 if (importEqualsDeclaration.moduleReference.kind ===
41309 ts.SyntaxKind.ExternalModuleReference) {
41310 const externalReference = importEqualsDeclaration.moduleReference;
41311 if (externalReference.expression) {
41312 // An `import <identifier> = require(<module-specifier>);
41313 if (!externalReference.expression.parent) {
41314 // The `parent` field of a node is set by the TypeScript binder (run as
41315 // part of the type checker). Setting it here allows us to call `getText()`
41316 // even if the `SourceFile` was not type checked (which looks for `SourceFile`
41317 // in the parent chain). This doesn't damage the node as the binder unconditionally
41318 // sets the parent.
41319 externalReference.expression.parent = externalReference;
41320 externalReference.parent = this.sourceFile;
41321 }
41322 const from = stripQuotes(externalReference.expression.getText());
41323 symbols.set(importEqualsDeclaration.name.text, { __symbolic: 'reference', module: from });
41324 break;
41325 }
41326 }
41327 symbols.set(importEqualsDeclaration.name.text, { __symbolic: 'error', message: `Unsupported import syntax` });
41328 break;
41329 case ts.SyntaxKind.ImportDeclaration:
41330 const importDecl = node;
41331 if (!importDecl.importClause) {
41332 // An `import <module-specifier>` clause which does not bring symbols into scope.
41333 break;
41334 }
41335 if (!importDecl.moduleSpecifier.parent) {
41336 // See note above in the `ImportEqualDeclaration` case.
41337 importDecl.moduleSpecifier.parent = importDecl;
41338 importDecl.parent = this.sourceFile;
41339 }
41340 const from = stripQuotes(importDecl.moduleSpecifier.getText());
41341 if (importDecl.importClause.name) {
41342 // An `import <identifier> form <module-specifier>` clause. Record the default symbol.
41343 symbols.set(importDecl.importClause.name.text, { __symbolic: 'reference', module: from, default: true });
41344 }
41345 const bindings = importDecl.importClause.namedBindings;
41346 if (bindings) {
41347 switch (bindings.kind) {
41348 case ts.SyntaxKind.NamedImports:
41349 // An `import { [<identifier> [, <identifier>] } from <module-specifier>` clause
41350 for (const binding of bindings.elements) {
41351 symbols.set(binding.name.text, {
41352 __symbolic: 'reference',
41353 module: from,
41354 name: binding.propertyName ? binding.propertyName.text : binding.name.text
41355 });
41356 }
41357 break;
41358 case ts.SyntaxKind.NamespaceImport:
41359 // An `input * as <identifier> from <module-specifier>` clause.
41360 symbols.set(bindings.name.text, { __symbolic: 'reference', module: from });
41361 break;
41362 }
41363 }
41364 break;
41365 }
41366 ts.forEachChild(node, visit);
41367 };
41368 if (this.sourceFile) {
41369 ts.forEachChild(this.sourceFile, visit);
41370 }
41371 }
41372 }
41373 function populateBuiltins(symbols) {
41374 // From lib.core.d.ts (all "define const")
41375 ['Object', 'Function', 'String', 'Number', 'Array', 'Boolean', 'Map', 'NaN', 'Infinity', 'Math',
41376 'Date', 'RegExp', 'Error', 'Error', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError',
41377 'TypeError', 'URIError', 'JSON', 'ArrayBuffer', 'DataView', 'Int8Array', 'Uint8Array',
41378 'Uint8ClampedArray', 'Uint16Array', 'Int16Array', 'Int32Array', 'Uint32Array', 'Float32Array',
41379 'Float64Array']
41380 .forEach(name => symbols.set(name, { __symbolic: 'reference', name }));
41381 }
41382
41383 /**
41384 * @license
41385 * Copyright Google LLC All Rights Reserved.
41386 *
41387 * Use of this source code is governed by an MIT-style license that can be
41388 * found in the LICENSE file at https://angular.io/license
41389 */
41390 const isStatic = (node) => ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static;
41391 /**
41392 * Collect decorator metadata from a TypeScript module.
41393 */
41394 class MetadataCollector {
41395 constructor(options = {}) {
41396 this.options = options;
41397 }
41398 /**
41399 * Returns a JSON.stringify friendly form describing the decorators of the exported classes from
41400 * the source file that is expected to correspond to a module.
41401 */
41402 getMetadata(sourceFile, strict = false, substituteExpression) {
41403 const locals = new Symbols(sourceFile);
41404 const nodeMap = new Map();
41405 const composedSubstituter = substituteExpression && this.options.substituteExpression ?
41406 (value, node) => this.options.substituteExpression(substituteExpression(value, node), node) :
41407 substituteExpression;
41408 const evaluatorOptions = substituteExpression ? Object.assign(Object.assign({}, this.options), { substituteExpression: composedSubstituter }) :
41409 this.options;
41410 let metadata;
41411 const evaluator = new Evaluator(locals, nodeMap, evaluatorOptions, (name, value) => {
41412 if (!metadata)
41413 metadata = {};
41414 metadata[name] = value;
41415 });
41416 let exports = undefined;
41417 function objFromDecorator(decoratorNode) {
41418 return evaluator.evaluateNode(decoratorNode.expression);
41419 }
41420 function recordEntry(entry, node) {
41421 if (composedSubstituter) {
41422 entry = composedSubstituter(entry, node);
41423 }
41424 return recordMapEntry(entry, node, nodeMap, sourceFile);
41425 }
41426 function errorSym(message, node, context) {
41427 return errorSymbol(message, node, context, sourceFile);
41428 }
41429 function maybeGetSimpleFunction(functionDeclaration) {
41430 if (functionDeclaration.name && functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
41431 const nameNode = functionDeclaration.name;
41432 const functionName = nameNode.text;
41433 const functionBody = functionDeclaration.body;
41434 if (functionBody && functionBody.statements.length == 1) {
41435 const statement = functionBody.statements[0];
41436 if (statement.kind === ts.SyntaxKind.ReturnStatement) {
41437 const returnStatement = statement;
41438 if (returnStatement.expression) {
41439 const func = {
41440 __symbolic: 'function',
41441 parameters: namesOf(functionDeclaration.parameters),
41442 value: evaluator.evaluateNode(returnStatement.expression)
41443 };
41444 if (functionDeclaration.parameters.some(p => p.initializer != null)) {
41445 func.defaults = functionDeclaration.parameters.map(p => p.initializer && evaluator.evaluateNode(p.initializer));
41446 }
41447 return recordEntry({ func, name: functionName }, functionDeclaration);
41448 }
41449 }
41450 }
41451 }
41452 }
41453 function classMetadataOf(classDeclaration) {
41454 const result = { __symbolic: 'class' };
41455 function getDecorators(decorators) {
41456 if (decorators && decorators.length)
41457 return decorators.map(decorator => objFromDecorator(decorator));
41458 return undefined;
41459 }
41460 function referenceFrom(node) {
41461 const result = evaluator.evaluateNode(node);
41462 if (isMetadataError$1(result) || isMetadataSymbolicReferenceExpression(result) ||
41463 isMetadataSymbolicSelectExpression(result)) {
41464 return result;
41465 }
41466 else {
41467 return errorSym('Symbol reference expected', node);
41468 }
41469 }
41470 // Add class parents
41471 if (classDeclaration.heritageClauses) {
41472 classDeclaration.heritageClauses.forEach((hc) => {
41473 if (hc.token === ts.SyntaxKind.ExtendsKeyword && hc.types) {
41474 hc.types.forEach(type => result.extends = referenceFrom(type.expression));
41475 }
41476 });
41477 }
41478 // Add arity if the type is generic
41479 const typeParameters = classDeclaration.typeParameters;
41480 if (typeParameters && typeParameters.length) {
41481 result.arity = typeParameters.length;
41482 }
41483 // Add class decorators
41484 if (classDeclaration.decorators) {
41485 result.decorators = getDecorators(classDeclaration.decorators);
41486 }
41487 // member decorators
41488 let members = null;
41489 function recordMember(name, metadata) {
41490 if (!members)
41491 members = {};
41492 const data = members.hasOwnProperty(name) ? members[name] : [];
41493 data.push(metadata);
41494 members[name] = data;
41495 }
41496 // static member
41497 let statics = null;
41498 function recordStaticMember(name, value) {
41499 if (!statics)
41500 statics = {};
41501 statics[name] = value;
41502 }
41503 for (const member of classDeclaration.members) {
41504 let isConstructor = false;
41505 switch (member.kind) {
41506 case ts.SyntaxKind.Constructor:
41507 case ts.SyntaxKind.MethodDeclaration:
41508 isConstructor = member.kind === ts.SyntaxKind.Constructor;
41509 const method = member;
41510 if (isStatic(method)) {
41511 const maybeFunc = maybeGetSimpleFunction(method);
41512 if (maybeFunc) {
41513 recordStaticMember(maybeFunc.name, maybeFunc.func);
41514 }
41515 continue;
41516 }
41517 const methodDecorators = getDecorators(method.decorators);
41518 const parameters = method.parameters;
41519 const parameterDecoratorData = [];
41520 const parametersData = [];
41521 let hasDecoratorData = false;
41522 let hasParameterData = false;
41523 for (const parameter of parameters) {
41524 const parameterData = getDecorators(parameter.decorators);
41525 parameterDecoratorData.push(parameterData);
41526 hasDecoratorData = hasDecoratorData || !!parameterData;
41527 if (isConstructor) {
41528 if (parameter.type) {
41529 parametersData.push(referenceFrom(parameter.type));
41530 }
41531 else {
41532 parametersData.push(null);
41533 }
41534 hasParameterData = true;
41535 }
41536 }
41537 const data = { __symbolic: isConstructor ? 'constructor' : 'method' };
41538 const name = isConstructor ? '__ctor__' : evaluator.nameOf(member.name);
41539 if (methodDecorators) {
41540 data.decorators = methodDecorators;
41541 }
41542 if (hasDecoratorData) {
41543 data.parameterDecorators = parameterDecoratorData;
41544 }
41545 if (hasParameterData) {
41546 data.parameters = parametersData;
41547 }
41548 if (!isMetadataError$1(name)) {
41549 recordMember(name, data);
41550 }
41551 break;
41552 case ts.SyntaxKind.PropertyDeclaration:
41553 case ts.SyntaxKind.GetAccessor:
41554 case ts.SyntaxKind.SetAccessor:
41555 const property = member;
41556 if (isStatic(property)) {
41557 const name = evaluator.nameOf(property.name);
41558 if (!isMetadataError$1(name) && !shouldIgnoreStaticMember(name)) {
41559 if (property.initializer) {
41560 const value = evaluator.evaluateNode(property.initializer);
41561 recordStaticMember(name, value);
41562 }
41563 else {
41564 recordStaticMember(name, errorSym('Variable not initialized', property.name));
41565 }
41566 }
41567 }
41568 const propertyDecorators = getDecorators(property.decorators);
41569 if (propertyDecorators) {
41570 const name = evaluator.nameOf(property.name);
41571 if (!isMetadataError$1(name)) {
41572 recordMember(name, { __symbolic: 'property', decorators: propertyDecorators });
41573 }
41574 }
41575 break;
41576 }
41577 }
41578 if (members) {
41579 result.members = members;
41580 }
41581 if (statics) {
41582 result.statics = statics;
41583 }
41584 return recordEntry(result, classDeclaration);
41585 }
41586 // Collect all exported symbols from an exports clause.
41587 const exportMap = new Map();
41588 ts.forEachChild(sourceFile, node => {
41589 switch (node.kind) {
41590 case ts.SyntaxKind.ExportDeclaration:
41591 const exportDeclaration = node;
41592 const { moduleSpecifier, exportClause } = exportDeclaration;
41593 if (!moduleSpecifier && exportClause && ts.isNamedExports(exportClause)) {
41594 // If there is a module specifier there is also an exportClause
41595 exportClause.elements.forEach(spec => {
41596 const exportedAs = spec.name.text;
41597 const name = (spec.propertyName || spec.name).text;
41598 exportMap.set(name, exportedAs);
41599 });
41600 }
41601 }
41602 });
41603 const isExport = (node) => sourceFile.isDeclarationFile ||
41604 ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export;
41605 const isExportedIdentifier = (identifier) => identifier && exportMap.has(identifier.text);
41606 const isExported = (node) => isExport(node) || isExportedIdentifier(node.name);
41607 const exportedIdentifierName = (identifier) => identifier && (exportMap.get(identifier.text) || identifier.text);
41608 const exportedName = (node) => exportedIdentifierName(node.name);
41609 // Pre-declare classes and functions
41610 ts.forEachChild(sourceFile, node => {
41611 switch (node.kind) {
41612 case ts.SyntaxKind.ClassDeclaration:
41613 const classDeclaration = node;
41614 if (classDeclaration.name) {
41615 const className = classDeclaration.name.text;
41616 if (isExported(classDeclaration)) {
41617 locals.define(className, { __symbolic: 'reference', name: exportedName(classDeclaration) });
41618 }
41619 else {
41620 locals.define(className, errorSym('Reference to non-exported class', node, { className }));
41621 }
41622 }
41623 break;
41624 case ts.SyntaxKind.InterfaceDeclaration:
41625 const interfaceDeclaration = node;
41626 if (interfaceDeclaration.name) {
41627 const interfaceName = interfaceDeclaration.name.text;
41628 // All references to interfaces should be converted to references to `any`.
41629 locals.define(interfaceName, { __symbolic: 'reference', name: 'any' });
41630 }
41631 break;
41632 case ts.SyntaxKind.FunctionDeclaration:
41633 const functionDeclaration = node;
41634 if (!isExported(functionDeclaration)) {
41635 // Report references to this function as an error.
41636 const nameNode = functionDeclaration.name;
41637 if (nameNode && nameNode.text) {
41638 locals.define(nameNode.text, errorSym('Reference to a non-exported function', nameNode, { name: nameNode.text }));
41639 }
41640 }
41641 break;
41642 }
41643 });
41644 ts.forEachChild(sourceFile, node => {
41645 switch (node.kind) {
41646 case ts.SyntaxKind.ExportDeclaration:
41647 // Record export declarations
41648 const exportDeclaration = node;
41649 const { moduleSpecifier, exportClause } = exportDeclaration;
41650 if (!moduleSpecifier) {
41651 // no module specifier -> export {propName as name};
41652 if (exportClause && ts.isNamedExports(exportClause)) {
41653 exportClause.elements.forEach(spec => {
41654 const name = spec.name.text;
41655 // If the symbol was not already exported, export a reference since it is a
41656 // reference to an import
41657 if (!metadata || !metadata[name]) {
41658 const propNode = spec.propertyName || spec.name;
41659 const value = evaluator.evaluateNode(propNode);
41660 if (!metadata)
41661 metadata = {};
41662 metadata[name] = recordEntry(value, node);
41663 }
41664 });
41665 }
41666 }
41667 if (moduleSpecifier && moduleSpecifier.kind == ts.SyntaxKind.StringLiteral) {
41668 // Ignore exports that don't have string literals as exports.
41669 // This is allowed by the syntax but will be flagged as an error by the type checker.
41670 const from = moduleSpecifier.text;
41671 const moduleExport = { from };
41672 if (exportClause && ts.isNamedExports(exportClause)) {
41673 moduleExport.export = exportClause.elements.map(spec => spec.propertyName ? { name: spec.propertyName.text, as: spec.name.text } :
41674 spec.name.text);
41675 }
41676 if (!exports)
41677 exports = [];
41678 exports.push(moduleExport);
41679 }
41680 break;
41681 case ts.SyntaxKind.ClassDeclaration:
41682 const classDeclaration = node;
41683 if (classDeclaration.name) {
41684 if (isExported(classDeclaration)) {
41685 const name = exportedName(classDeclaration);
41686 if (name) {
41687 if (!metadata)
41688 metadata = {};
41689 metadata[name] = classMetadataOf(classDeclaration);
41690 }
41691 }
41692 }
41693 // Otherwise don't record metadata for the class.
41694 break;
41695 case ts.SyntaxKind.TypeAliasDeclaration:
41696 const typeDeclaration = node;
41697 if (typeDeclaration.name && isExported(typeDeclaration)) {
41698 const name = exportedName(typeDeclaration);
41699 if (name) {
41700 if (!metadata)
41701 metadata = {};
41702 metadata[name] = { __symbolic: 'interface' };
41703 }
41704 }
41705 break;
41706 case ts.SyntaxKind.InterfaceDeclaration:
41707 const interfaceDeclaration = node;
41708 if (interfaceDeclaration.name && isExported(interfaceDeclaration)) {
41709 const name = exportedName(interfaceDeclaration);
41710 if (name) {
41711 if (!metadata)
41712 metadata = {};
41713 metadata[name] = { __symbolic: 'interface' };
41714 }
41715 }
41716 break;
41717 case ts.SyntaxKind.FunctionDeclaration:
41718 // Record functions that return a single value. Record the parameter
41719 // names substitution will be performed by the StaticReflector.
41720 const functionDeclaration = node;
41721 if (isExported(functionDeclaration) && functionDeclaration.name) {
41722 const name = exportedName(functionDeclaration);
41723 const maybeFunc = maybeGetSimpleFunction(functionDeclaration);
41724 if (name) {
41725 if (!metadata)
41726 metadata = {};
41727 // TODO(alxhub): The literal here is not valid FunctionMetadata.
41728 metadata[name] =
41729 maybeFunc ? recordEntry(maybeFunc.func, node) : { __symbolic: 'function' };
41730 }
41731 }
41732 break;
41733 case ts.SyntaxKind.EnumDeclaration:
41734 const enumDeclaration = node;
41735 if (isExported(enumDeclaration)) {
41736 const enumValueHolder = {};
41737 const enumName = exportedName(enumDeclaration);
41738 let nextDefaultValue = 0;
41739 let writtenMembers = 0;
41740 for (const member of enumDeclaration.members) {
41741 let enumValue;
41742 if (!member.initializer) {
41743 enumValue = nextDefaultValue;
41744 }
41745 else {
41746 enumValue = evaluator.evaluateNode(member.initializer);
41747 }
41748 let name = undefined;
41749 if (member.name.kind == ts.SyntaxKind.Identifier) {
41750 const identifier = member.name;
41751 name = identifier.text;
41752 enumValueHolder[name] = enumValue;
41753 writtenMembers++;
41754 }
41755 if (typeof enumValue === 'number') {
41756 nextDefaultValue = enumValue + 1;
41757 }
41758 else if (name) {
41759 // TODO(alxhub): 'left' here has a name propery which is not valid for
41760 // MetadataSymbolicSelectExpression.
41761 nextDefaultValue = {
41762 __symbolic: 'binary',
41763 operator: '+',
41764 left: {
41765 __symbolic: 'select',
41766 expression: recordEntry({ __symbolic: 'reference', name: enumName }, node),
41767 name
41768 },
41769 };
41770 }
41771 else {
41772 nextDefaultValue =
41773 recordEntry(errorSym('Unsupported enum member name', member.name), node);
41774 }
41775 }
41776 if (writtenMembers) {
41777 if (enumName) {
41778 if (!metadata)
41779 metadata = {};
41780 metadata[enumName] = recordEntry(enumValueHolder, node);
41781 }
41782 }
41783 }
41784 break;
41785 case ts.SyntaxKind.VariableStatement:
41786 const variableStatement = node;
41787 for (const variableDeclaration of variableStatement.declarationList.declarations) {
41788 if (variableDeclaration.name.kind == ts.SyntaxKind.Identifier) {
41789 const nameNode = variableDeclaration.name;
41790 let varValue;
41791 if (variableDeclaration.initializer) {
41792 varValue = evaluator.evaluateNode(variableDeclaration.initializer);
41793 }
41794 else {
41795 varValue = recordEntry(errorSym('Variable not initialized', nameNode), nameNode);
41796 }
41797 let exported = false;
41798 if (isExport(variableStatement) || isExport(variableDeclaration) ||
41799 isExportedIdentifier(nameNode)) {
41800 const name = exportedIdentifierName(nameNode);
41801 if (name) {
41802 if (!metadata)
41803 metadata = {};
41804 metadata[name] = recordEntry(varValue, node);
41805 }
41806 exported = true;
41807 }
41808 if (typeof varValue == 'string' || typeof varValue == 'number' ||
41809 typeof varValue == 'boolean') {
41810 locals.define(nameNode.text, varValue);
41811 if (exported) {
41812 locals.defineReference(nameNode.text, { __symbolic: 'reference', name: nameNode.text });
41813 }
41814 }
41815 else if (!exported) {
41816 if (varValue && !isMetadataError$1(varValue)) {
41817 locals.define(nameNode.text, recordEntry(varValue, node));
41818 }
41819 else {
41820 locals.define(nameNode.text, recordEntry(errorSym('Reference to a local symbol', nameNode, { name: nameNode.text }), node));
41821 }
41822 }
41823 }
41824 else {
41825 // Destructuring (or binding) declarations are not supported,
41826 // var {<identifier>[, <identifier>]+} = <expression>;
41827 // or
41828 // var [<identifier>[, <identifier}+] = <expression>;
41829 // are not supported.
41830 const report = (nameNode) => {
41831 switch (nameNode.kind) {
41832 case ts.SyntaxKind.Identifier:
41833 const name = nameNode;
41834 const varValue = errorSym('Destructuring not supported', name);
41835 locals.define(name.text, varValue);
41836 if (isExport(node)) {
41837 if (!metadata)
41838 metadata = {};
41839 metadata[name.text] = varValue;
41840 }
41841 break;
41842 case ts.SyntaxKind.BindingElement:
41843 const bindingElement = nameNode;
41844 report(bindingElement.name);
41845 break;
41846 case ts.SyntaxKind.ObjectBindingPattern:
41847 case ts.SyntaxKind.ArrayBindingPattern:
41848 const bindings = nameNode;
41849 bindings.elements.forEach(report);
41850 break;
41851 }
41852 };
41853 report(variableDeclaration.name);
41854 }
41855 }
41856 break;
41857 }
41858 });
41859 if (metadata || exports) {
41860 if (!metadata)
41861 metadata = {};
41862 else if (strict) {
41863 validateMetadata(sourceFile, nodeMap, metadata);
41864 }
41865 const result = {
41866 __symbolic: 'module',
41867 version: this.options.version || METADATA_VERSION,
41868 metadata
41869 };
41870 if (sourceFile.moduleName)
41871 result.importAs = sourceFile.moduleName;
41872 if (exports)
41873 result.exports = exports;
41874 return result;
41875 }
41876 }
41877 }
41878 // This will throw if the metadata entry given contains an error node.
41879 function validateMetadata(sourceFile, nodeMap, metadata) {
41880 let locals = new Set(['Array', 'Object', 'Set', 'Map', 'string', 'number', 'any']);
41881 function validateExpression(expression) {
41882 if (!expression) {
41883 return;
41884 }
41885 else if (Array.isArray(expression)) {
41886 expression.forEach(validateExpression);
41887 }
41888 else if (typeof expression === 'object' && !expression.hasOwnProperty('__symbolic')) {
41889 Object.getOwnPropertyNames(expression).forEach(v => validateExpression(expression[v]));
41890 }
41891 else if (isMetadataError$1(expression)) {
41892 reportError(expression);
41893 }
41894 else if (isMetadataGlobalReferenceExpression(expression)) {
41895 if (!locals.has(expression.name)) {
41896 const reference = metadata[expression.name];
41897 if (reference) {
41898 validateExpression(reference);
41899 }
41900 }
41901 }
41902 else if (isFunctionMetadata(expression)) {
41903 validateFunction(expression);
41904 }
41905 else if (isMetadataSymbolicExpression(expression)) {
41906 switch (expression.__symbolic) {
41907 case 'binary':
41908 const binaryExpression = expression;
41909 validateExpression(binaryExpression.left);
41910 validateExpression(binaryExpression.right);
41911 break;
41912 case 'call':
41913 case 'new':
41914 const callExpression = expression;
41915 validateExpression(callExpression.expression);
41916 if (callExpression.arguments)
41917 callExpression.arguments.forEach(validateExpression);
41918 break;
41919 case 'index':
41920 const indexExpression = expression;
41921 validateExpression(indexExpression.expression);
41922 validateExpression(indexExpression.index);
41923 break;
41924 case 'pre':
41925 const prefixExpression = expression;
41926 validateExpression(prefixExpression.operand);
41927 break;
41928 case 'select':
41929 const selectExpression = expression;
41930 validateExpression(selectExpression.expression);
41931 break;
41932 case 'spread':
41933 const spreadExpression = expression;
41934 validateExpression(spreadExpression.expression);
41935 break;
41936 case 'if':
41937 const ifExpression = expression;
41938 validateExpression(ifExpression.condition);
41939 validateExpression(ifExpression.elseExpression);
41940 validateExpression(ifExpression.thenExpression);
41941 break;
41942 }
41943 }
41944 }
41945 function validateMember(classData, member) {
41946 if (member.decorators) {
41947 member.decorators.forEach(validateExpression);
41948 }
41949 if (isMethodMetadata(member) && member.parameterDecorators) {
41950 member.parameterDecorators.forEach(validateExpression);
41951 }
41952 // Only validate parameters of classes for which we know that are used with our DI
41953 if (classData.decorators && isConstructorMetadata(member) && member.parameters) {
41954 member.parameters.forEach(validateExpression);
41955 }
41956 }
41957 function validateClass(classData) {
41958 if (classData.decorators) {
41959 classData.decorators.forEach(validateExpression);
41960 }
41961 if (classData.members) {
41962 Object.getOwnPropertyNames(classData.members)
41963 .forEach(name => classData.members[name].forEach((m) => validateMember(classData, m)));
41964 }
41965 if (classData.statics) {
41966 Object.getOwnPropertyNames(classData.statics).forEach(name => {
41967 const staticMember = classData.statics[name];
41968 if (isFunctionMetadata(staticMember)) {
41969 validateExpression(staticMember.value);
41970 }
41971 else {
41972 validateExpression(staticMember);
41973 }
41974 });
41975 }
41976 }
41977 function validateFunction(functionDeclaration) {
41978 if (functionDeclaration.value) {
41979 const oldLocals = locals;
41980 if (functionDeclaration.parameters) {
41981 locals = new Set(oldLocals.values());
41982 if (functionDeclaration.parameters)
41983 functionDeclaration.parameters.forEach(n => locals.add(n));
41984 }
41985 validateExpression(functionDeclaration.value);
41986 locals = oldLocals;
41987 }
41988 }
41989 function shouldReportNode(node) {
41990 if (node) {
41991 const nodeStart = node.getStart();
41992 return !(node.pos != nodeStart &&
41993 sourceFile.text.substring(node.pos, nodeStart).indexOf('@dynamic') >= 0);
41994 }
41995 return true;
41996 }
41997 function reportError(error) {
41998 const node = nodeMap.get(error);
41999 if (shouldReportNode(node)) {
42000 const lineInfo = error.line != undefined ? error.character != undefined ?
42001 `:${error.line + 1}:${error.character + 1}` :
42002 `:${error.line + 1}` :
42003 '';
42004 throw new Error(`${sourceFile.fileName}${lineInfo}: Metadata collected contains an error that will be reported at runtime: ${expandedMessage$1(error)}.\n ${JSON.stringify(error)}`);
42005 }
42006 }
42007 Object.getOwnPropertyNames(metadata).forEach(name => {
42008 const entry = metadata[name];
42009 try {
42010 if (isClassMetadata(entry)) {
42011 validateClass(entry);
42012 }
42013 }
42014 catch (e) {
42015 const node = nodeMap.get(entry);
42016 if (shouldReportNode(node)) {
42017 if (node) {
42018 const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
42019 throw new Error(`${sourceFile.fileName}:${line + 1}:${character + 1}: Error encountered in metadata generated for exported symbol '${name}': \n ${e.message}`);
42020 }
42021 throw new Error(`Error encountered in metadata generated for exported symbol ${name}: \n ${e.message}`);
42022 }
42023 }
42024 });
42025 }
42026 // Collect parameter names from a function.
42027 function namesOf(parameters) {
42028 const result = [];
42029 function addNamesOf(name) {
42030 if (name.kind == ts.SyntaxKind.Identifier) {
42031 const identifier = name;
42032 result.push(identifier.text);
42033 }
42034 else {
42035 const bindingPattern = name;
42036 for (const element of bindingPattern.elements) {
42037 const name = element.name;
42038 if (name) {
42039 addNamesOf(name);
42040 }
42041 }
42042 }
42043 }
42044 for (const parameter of parameters) {
42045 addNamesOf(parameter.name);
42046 }
42047 return result;
42048 }
42049 function shouldIgnoreStaticMember(memberName) {
42050 return memberName.startsWith('ngAcceptInputType_') || memberName.startsWith('ngTemplateGuard_');
42051 }
42052 function expandedMessage$1(error) {
42053 switch (error.message) {
42054 case 'Reference to non-exported class':
42055 if (error.context && error.context.className) {
42056 return `Reference to a non-exported class ${error.context.className}. Consider exporting the class`;
42057 }
42058 break;
42059 case 'Variable not initialized':
42060 return 'Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler';
42061 case 'Destructuring not supported':
42062 return 'Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring';
42063 case 'Could not resolve type':
42064 if (error.context && error.context.typeName) {
42065 return `Could not resolve type ${error.context.typeName}`;
42066 }
42067 break;
42068 case 'Function call not supported':
42069 let prefix = error.context && error.context.name ? `Calling function '${error.context.name}', f` : 'F';
42070 return prefix +
42071 'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
42072 case 'Reference to a local symbol':
42073 if (error.context && error.context.name) {
42074 return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
42075 }
42076 }
42077 return error.message;
42078 }
42079
42080 /**
42081 * @license
42082 * Copyright Google LLC All Rights Reserved.
42083 *
42084 * Use of this source code is governed by an MIT-style license that can be
42085 * found in the LICENSE file at https://angular.io/license
42086 */
42087 var EmitFlags;
42088 (function (EmitFlags) {
42089 EmitFlags[EmitFlags["DTS"] = 1] = "DTS";
42090 EmitFlags[EmitFlags["JS"] = 2] = "JS";
42091 EmitFlags[EmitFlags["Metadata"] = 4] = "Metadata";
42092 EmitFlags[EmitFlags["I18nBundle"] = 8] = "I18nBundle";
42093 EmitFlags[EmitFlags["Codegen"] = 16] = "Codegen";
42094 EmitFlags[EmitFlags["Default"] = 19] = "Default";
42095 EmitFlags[EmitFlags["All"] = 31] = "All";
42096 })(EmitFlags || (EmitFlags = {}));
42097
42098 /**
42099 * @license
42100 * Copyright Google LLC All Rights Reserved.
42101 *
42102 * Use of this source code is governed by an MIT-style license that can be
42103 * found in the LICENSE file at https://angular.io/license
42104 */
42105 const DTS = /\.d\.ts$/;
42106
42107 /**
42108 * @license
42109 * Copyright Google LLC All Rights Reserved.
42110 *
42111 * Use of this source code is governed by an MIT-style license that can be
42112 * found in the LICENSE file at https://angular.io/license
42113 */
42114 function createMetadataReaderCache() {
42115 const data = new Map();
42116 return { data };
42117 }
42118 function readMetadata(filePath, host, cache) {
42119 let metadatas = cache && cache.data.get(filePath);
42120 if (metadatas) {
42121 return metadatas;
42122 }
42123 if (host.fileExists(filePath)) {
42124 // If the file doesn't exists then we cannot return metadata for the file.
42125 // This will occur if the user referenced a declared module for which no file
42126 // exists for the module (i.e. jQuery or angularjs).
42127 if (DTS.test(filePath)) {
42128 metadatas = readMetadataFile(host, filePath);
42129 if (!metadatas) {
42130 // If there is a .d.ts file but no metadata file we need to produce a
42131 // metadata from the .d.ts file as metadata files capture reexports
42132 // (starting with v3).
42133 metadatas = [upgradeMetadataWithDtsData(host, { '__symbolic': 'module', 'version': 1, 'metadata': {} }, filePath)];
42134 }
42135 }
42136 else {
42137 const metadata = host.getSourceFileMetadata(filePath);
42138 metadatas = metadata ? [metadata] : [];
42139 }
42140 }
42141 if (cache && (!host.cacheMetadata || host.cacheMetadata(filePath))) {
42142 cache.data.set(filePath, metadatas);
42143 }
42144 return metadatas;
42145 }
42146 function readMetadataFile(host, dtsFilePath) {
42147 const metadataPath = dtsFilePath.replace(DTS, '.metadata.json');
42148 if (!host.fileExists(metadataPath)) {
42149 return undefined;
42150 }
42151 try {
42152 const metadataOrMetadatas = JSON.parse(host.readFile(metadataPath));
42153 const metadatas = metadataOrMetadatas ?
42154 (Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
42155 [];
42156 if (metadatas.length) {
42157 let maxMetadata = metadatas.reduce((p, c) => p.version > c.version ? p : c);
42158 if (maxMetadata.version < METADATA_VERSION) {
42159 metadatas.push(upgradeMetadataWithDtsData(host, maxMetadata, dtsFilePath));
42160 }
42161 }
42162 return metadatas;
42163 }
42164 catch (e) {
42165 console.error(`Failed to read JSON file ${metadataPath}`);
42166 throw e;
42167 }
42168 }
42169 function upgradeMetadataWithDtsData(host, oldMetadata, dtsFilePath) {
42170 // patch v1 to v3 by adding exports and the `extends` clause.
42171 // patch v3 to v4 by adding `interface` symbols for TypeAlias
42172 let newMetadata = {
42173 '__symbolic': 'module',
42174 'version': METADATA_VERSION,
42175 'metadata': Object.assign({}, oldMetadata.metadata),
42176 };
42177 if (oldMetadata.exports) {
42178 newMetadata.exports = oldMetadata.exports;
42179 }
42180 if (oldMetadata.importAs) {
42181 newMetadata.importAs = oldMetadata.importAs;
42182 }
42183 if (oldMetadata.origins) {
42184 newMetadata.origins = oldMetadata.origins;
42185 }
42186 const dtsMetadata = host.getSourceFileMetadata(dtsFilePath);
42187 if (dtsMetadata) {
42188 for (let prop in dtsMetadata.metadata) {
42189 if (!newMetadata.metadata[prop]) {
42190 newMetadata.metadata[prop] = dtsMetadata.metadata[prop];
42191 }
42192 }
42193 if (dtsMetadata['importAs'])
42194 newMetadata['importAs'] = dtsMetadata['importAs'];
42195 // Only copy exports from exports from metadata prior to version 3.
42196 // Starting with version 3 the collector began collecting exports and
42197 // this should be redundant. Also, with bundler will rewrite the exports
42198 // which will hoist the exports from modules referenced indirectly causing
42199 // the imports to be different than the .d.ts files and using the .d.ts file
42200 // exports would cause the StaticSymbolResolver to redirect symbols to the
42201 // incorrect location.
42202 if ((!oldMetadata.version || oldMetadata.version < 3) && dtsMetadata.exports) {
42203 newMetadata.exports = dtsMetadata.exports;
42204 }
42205 }
42206 return newMetadata;
42207 }
42208
42209 /**
42210 * @license
42211 * Copyright Google LLC All Rights Reserved.
42212 *
42213 * Use of this source code is governed by an MIT-style license that can be
42214 * found in the LICENSE file at https://angular.io/license
42215 */
42216 class ReflectorModuleModuleResolutionHost {
42217 constructor(tsLSHost, getProgram) {
42218 this.tsLSHost = tsLSHost;
42219 this.getProgram = getProgram;
42220 this.metadataCollector = new MetadataCollector({
42221 // Note: verboseInvalidExpressions is important so that
42222 // the collector will collect errors instead of throwing
42223 verboseInvalidExpression: true,
42224 });
42225 if (tsLSHost.directoryExists) {
42226 this.directoryExists = directoryName => tsLSHost.directoryExists(directoryName);
42227 }
42228 if (tsLSHost.realpath) {
42229 this.realpath = path => tsLSHost.realpath(path);
42230 }
42231 }
42232 fileExists(fileName) {
42233 // TypeScript resolution logic walks through the following sequence in order:
42234 // package.json (read "types" field) -> .ts -> .tsx -> .d.ts
42235 // For more info, see
42236 // https://www.typescriptlang.org/docs/handbook/module-resolution.html
42237 // For Angular specifically, we can skip .tsx lookup
42238 if (fileName.endsWith('.tsx')) {
42239 return false;
42240 }
42241 if (this.tsLSHost.fileExists) {
42242 return this.tsLSHost.fileExists(fileName);
42243 }
42244 return !!this.tsLSHost.getScriptSnapshot(fileName);
42245 }
42246 readFile(fileName) {
42247 // readFile() is used by TypeScript to read package.json during module
42248 // resolution, and it's used by Angular to read metadata.json during
42249 // metadata resolution.
42250 if (this.tsLSHost.readFile) {
42251 return this.tsLSHost.readFile(fileName);
42252 }
42253 // As a fallback, read the JSON files from the editor snapshot.
42254 const snapshot = this.tsLSHost.getScriptSnapshot(fileName);
42255 if (!snapshot) {
42256 // MetadataReaderHost readFile() declaration should be
42257 // `readFile(fileName: string): string | undefined`
42258 return undefined;
42259 }
42260 return snapshot.getText(0, snapshot.getLength());
42261 }
42262 getSourceFileMetadata(fileName) {
42263 const sf = this.getProgram().getSourceFile(fileName);
42264 return sf ? this.metadataCollector.getMetadata(sf) : undefined;
42265 }
42266 cacheMetadata(fileName) {
42267 // Don't cache the metadata for .ts files as they might change in the editor!
42268 return fileName.endsWith('.d.ts');
42269 }
42270 }
42271 class ReflectorHost {
42272 constructor(getProgram, tsLSHost) {
42273 this.tsLSHost = tsLSHost;
42274 this.metadataReaderCache = createMetadataReaderCache();
42275 // tsLSHost.getCurrentDirectory() returns the directory where tsconfig.json
42276 // is located. This is not the same as process.cwd() because the language
42277 // service host sets the "project root path" as its current directory.
42278 const currentDir = tsLSHost.getCurrentDirectory();
42279 this.fakeContainingPath = currentDir ? path.join(currentDir, 'fakeContainingFile.ts') : '';
42280 this.hostAdapter = new ReflectorModuleModuleResolutionHost(tsLSHost, getProgram);
42281 this.moduleResolutionCache = ts.createModuleResolutionCache(currentDir, s => s, // getCanonicalFileName
42282 tsLSHost.getCompilationSettings());
42283 }
42284 getMetadataFor(modulePath) {
42285 return readMetadata(modulePath, this.hostAdapter, this.metadataReaderCache);
42286 }
42287 moduleNameToFileName(moduleName, containingFile) {
42288 if (!containingFile) {
42289 if (moduleName.startsWith('.')) {
42290 throw new Error('Resolution of relative paths requires a containing file.');
42291 }
42292 if (!this.fakeContainingPath) {
42293 // If current directory is empty then the file must belong to an inferred
42294 // project (no tsconfig.json), in which case it's not possible to resolve
42295 // the module without the caller explicitly providing a containing file.
42296 throw new Error(`Could not resolve '${moduleName}' without a containing file.`);
42297 }
42298 containingFile = this.fakeContainingPath;
42299 }
42300 const compilerOptions = this.tsLSHost.getCompilationSettings();
42301 const resolved = ts.resolveModuleName(moduleName, containingFile, compilerOptions, this.hostAdapter, this.moduleResolutionCache)
42302 .resolvedModule;
42303 return resolved ? resolved.resolvedFileName : null;
42304 }
42305 getOutputName(filePath) {
42306 return filePath;
42307 }
42308 }
42309
42310 /**
42311 * @license
42312 * Copyright Google LLC All Rights Reserved.
42313 *
42314 * Use of this source code is governed by an MIT-style license that can be
42315 * found in the LICENSE file at https://angular.io/license
42316 */
42317 /**
42318 * The language service never needs the normalized versions of the metadata. To avoid parsing
42319 * the content and resolving references, return an empty file. This also allows normalizing
42320 * template that are syntatically incorrect which is required to provide completions in
42321 * syntactically incorrect templates.
42322 */
42323 class DummyHtmlParser extends HtmlParser {
42324 parse() {
42325 return new ParseTreeResult([], []);
42326 }
42327 }
42328 /**
42329 * Avoid loading resources in the language servcie by using a dummy loader.
42330 */
42331 class DummyResourceLoader extends ResourceLoader {
42332 get(_url) {
42333 return Promise.resolve('');
42334 }
42335 }
42336 /**
42337 * An implementation of a `LanguageServiceHost` for a TypeScript project.
42338 *
42339 * The `TypeScriptServiceHost` implements the Angular `LanguageServiceHost` using
42340 * the TypeScript language services.
42341 *
42342 * @publicApi
42343 */
42344 class TypeScriptServiceHost {
42345 constructor(tsLsHost, tsLS) {
42346 this.tsLsHost = tsLsHost;
42347 this.tsLS = tsLS;
42348 this.staticSymbolCache = new StaticSymbolCache();
42349 /**
42350 * Key of the `fileToComponent` map must be TS internal normalized path (path
42351 * separator must be `/`), value of the map is the StaticSymbol for the
42352 * Component class declaration.
42353 */
42354 this.fileToComponent = new Map();
42355 this.collectedErrors = new Map();
42356 this.fileVersions = new Map();
42357 this.lastProgram = undefined;
42358 this.analyzedModules = {
42359 files: [],
42360 ngModuleByPipeOrDirective: new Map(),
42361 ngModules: [],
42362 };
42363 this.summaryResolver = new AotSummaryResolver({
42364 loadSummary(_filePath) {
42365 return null;
42366 },
42367 isSourceFile(_sourceFilePath) {
42368 return true;
42369 },
42370 toSummaryFileName(sourceFilePath) {
42371 return sourceFilePath;
42372 },
42373 fromSummaryFileName(filePath) {
42374 return filePath;
42375 },
42376 }, this.staticSymbolCache);
42377 this.reflectorHost = new ReflectorHost(() => this.program, tsLsHost);
42378 this.staticSymbolResolver = new StaticSymbolResolver(this.reflectorHost, this.staticSymbolCache, this.summaryResolver, (e, filePath) => this.collectError(e, filePath));
42379 this.urlResolver = {
42380 resolve: (baseUrl, url) => {
42381 // In practice, `directoryExists` is always defined.
42382 // https://github.com/microsoft/TypeScript/blob/0b6c9254a850dd07056259d4eefca7721745af75/src/server/project.ts#L1608-L1614
42383 if (tsLsHost.directoryExists(baseUrl)) {
42384 return path.resolve(baseUrl, url);
42385 }
42386 return path.resolve(path.dirname(baseUrl), url);
42387 }
42388 };
42389 }
42390 /**
42391 * Return the singleton instance of the MetadataResolver.
42392 */
42393 get resolver() {
42394 if (this._resolver) {
42395 return this._resolver;
42396 }
42397 // StaticReflector keeps its own private caches that are not clearable.
42398 // We have no choice but to create a new instance to invalidate the caches.
42399 // TODO: Revisit this when language service gets rewritten for Ivy.
42400 const staticReflector = new StaticReflector(this.summaryResolver, this.staticSymbolResolver, [], // knownMetadataClasses
42401 [], // knownMetadataFunctions
42402 (e, filePath) => this.collectError(e, filePath));
42403 // Because static reflector above is changed, we need to create a new
42404 // resolver.
42405 const moduleResolver = new NgModuleResolver(staticReflector);
42406 const directiveResolver = new DirectiveResolver(staticReflector);
42407 const pipeResolver = new PipeResolver(staticReflector);
42408 const elementSchemaRegistry = new DomElementSchemaRegistry();
42409 const resourceLoader = new DummyResourceLoader();
42410 const htmlParser = new DummyHtmlParser();
42411 // This tracks the CompileConfig in codegen.ts. Currently these options
42412 // are hard-coded.
42413 const config = new CompilerConfig({
42414 defaultEncapsulation: ViewEncapsulation$1.Emulated,
42415 useJit: false,
42416 });
42417 const directiveNormalizer = new DirectiveNormalizer(resourceLoader, this.urlResolver, htmlParser, config);
42418 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));
42419 return this._resolver;
42420 }
42421 /**
42422 * Return the singleton instance of the StaticReflector hosted in the
42423 * MetadataResolver.
42424 */
42425 get reflector() {
42426 return this.resolver.getReflector();
42427 }
42428 /**
42429 * Return all known external templates.
42430 */
42431 getExternalTemplates() {
42432 return [...this.fileToComponent.keys()];
42433 }
42434 /**
42435 * Checks whether the program has changed and returns all analyzed modules.
42436 * If program has changed, invalidate all caches and update fileToComponent
42437 * and templateReferences.
42438 * In addition to returning information about NgModules, this method plays the
42439 * same role as 'synchronizeHostData' in tsserver.
42440 */
42441 getAnalyzedModules() {
42442 if (this.upToDate()) {
42443 return this.analyzedModules;
42444 }
42445 // Invalidate caches
42446 this.fileToComponent.clear();
42447 this.collectedErrors.clear();
42448 this.resolver.clearCache();
42449 const analyzeHost = {
42450 isSourceFile(_filePath) {
42451 return true;
42452 }
42453 };
42454 const programFiles = this.program.getSourceFiles().map(sf => sf.fileName);
42455 try {
42456 this.analyzedModules =
42457 analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver);
42458 }
42459 catch (e) {
42460 // Analyzing modules may throw; in that case, reuse the old modules.
42461 this.error(`Analyzing NgModules failed. ${e}`);
42462 return this.analyzedModules;
42463 }
42464 // update template references and fileToComponent
42465 for (const ngModule of this.analyzedModules.ngModules) {
42466 for (const directive of ngModule.declaredDirectives) {
42467 const { metadata } = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference);
42468 if (metadata.isComponent && metadata.template && metadata.template.templateUrl) {
42469 const templateName = this.urlResolver.resolve(this.reflector.componentModuleUrl(directive.reference), metadata.template.templateUrl);
42470 this.fileToComponent.set(tss.server.toNormalizedPath(templateName), directive.reference);
42471 }
42472 }
42473 }
42474 return this.analyzedModules;
42475 }
42476 /**
42477 * Checks whether the program has changed, and invalidate static symbols in
42478 * the source files that have changed.
42479 * Returns true if modules are up-to-date, false otherwise.
42480 * This should only be called by getAnalyzedModules().
42481 */
42482 upToDate() {
42483 const { lastProgram, program } = this;
42484 if (lastProgram === program) {
42485 return true;
42486 }
42487 this.lastProgram = program;
42488 // Even though the program has changed, it could be the case that none of
42489 // the source files have changed. If all source files remain the same, then
42490 // program is still up-to-date, and we should not invalidate caches.
42491 let filesAdded = 0;
42492 const filesChangedOrRemoved = [];
42493 // Check if any source files have been added / changed since last computation.
42494 const seen = new Set();
42495 const ANGULAR_CORE = '@angular/core';
42496 const corePath = this.reflectorHost.moduleNameToFileName(ANGULAR_CORE);
42497 for (const { fileName } of program.getSourceFiles()) {
42498 // If `@angular/core` is edited, the language service would have to be
42499 // restarted, so ignore changes to `@angular/core`.
42500 // When the StaticReflector is initialized at startup, it loads core
42501 // symbols from @angular/core by calling initializeConversionMap(). This
42502 // is only done once. If the file is invalidated, some of the core symbols
42503 // will be lost permanently.
42504 if (fileName === corePath) {
42505 continue;
42506 }
42507 seen.add(fileName);
42508 const version = this.tsLsHost.getScriptVersion(fileName);
42509 const lastVersion = this.fileVersions.get(fileName);
42510 if (lastVersion === undefined) {
42511 filesAdded++;
42512 this.fileVersions.set(fileName, version);
42513 }
42514 else if (version !== lastVersion) {
42515 filesChangedOrRemoved.push(fileName); // changed
42516 this.fileVersions.set(fileName, version);
42517 }
42518 }
42519 // Check if any source files have been removed since last computation.
42520 for (const [fileName] of this.fileVersions) {
42521 if (!seen.has(fileName)) {
42522 filesChangedOrRemoved.push(fileName); // removed
42523 // Because Maps are iterated in insertion order, it is safe to delete
42524 // entries from the same map while iterating.
42525 // See https://stackoverflow.com/questions/35940216 and
42526 // https://www.ecma-international.org/ecma-262/10.0/index.html#sec-map.prototype.foreach
42527 this.fileVersions.delete(fileName);
42528 }
42529 }
42530 for (const fileName of filesChangedOrRemoved) {
42531 const symbols = this.staticSymbolResolver.invalidateFile(fileName);
42532 this.reflector.invalidateSymbols(symbols);
42533 }
42534 // Program is up-to-date iff no files are added, changed, or removed.
42535 return filesAdded === 0 && filesChangedOrRemoved.length === 0;
42536 }
42537 /**
42538 * Find all templates in the specified `file`.
42539 * @param fileName TS or HTML file
42540 */
42541 getTemplates(fileName) {
42542 const results = [];
42543 if (fileName.endsWith('.ts')) {
42544 // Find every template string in the file
42545 const visit = (child) => {
42546 const template = this.getInternalTemplate(child);
42547 if (template) {
42548 results.push(template);
42549 }
42550 else {
42551 tss.forEachChild(child, visit);
42552 }
42553 };
42554 const sourceFile = this.getSourceFile(fileName);
42555 if (sourceFile) {
42556 tss.forEachChild(sourceFile, visit);
42557 }
42558 }
42559 else {
42560 const template = this.getExternalTemplate(fileName);
42561 if (template) {
42562 results.push(template);
42563 }
42564 }
42565 return results;
42566 }
42567 /**
42568 * Return metadata about all class declarations in the file that are Angular
42569 * directives. Potential matches are `@NgModule`, `@Component`, `@Directive`,
42570 * `@Pipes`, etc. class declarations.
42571 *
42572 * @param fileName TS file
42573 */
42574 getDeclarations(fileName) {
42575 if (!fileName.endsWith('.ts')) {
42576 return [];
42577 }
42578 const sourceFile = this.getSourceFile(fileName);
42579 if (!sourceFile) {
42580 return [];
42581 }
42582 const results = [];
42583 const visit = (child) => {
42584 const candidate = getDirectiveClassLike(child);
42585 if (candidate) {
42586 const { classId } = candidate;
42587 const declarationSpan = spanOf$2(classId);
42588 const className = classId.getText();
42589 const classSymbol = this.reflector.getStaticSymbol(sourceFile.fileName, className);
42590 // Ask the resolver to check if candidate is actually Angular directive
42591 if (!this.resolver.isDirective(classSymbol)) {
42592 return;
42593 }
42594 const data = this.resolver.getNonNormalizedDirectiveMetadata(classSymbol);
42595 if (!data) {
42596 return;
42597 }
42598 results.push({
42599 type: classSymbol,
42600 declarationSpan,
42601 metadata: data.metadata,
42602 errors: this.getCollectedErrors(declarationSpan, sourceFile),
42603 });
42604 }
42605 else {
42606 child.forEachChild(visit);
42607 }
42608 };
42609 tss.forEachChild(sourceFile, visit);
42610 return results;
42611 }
42612 getSourceFile(fileName) {
42613 if (!fileName.endsWith('.ts')) {
42614 throw new Error(`Non-TS source file requested: ${fileName}`);
42615 }
42616 return this.program.getSourceFile(fileName);
42617 }
42618 get program() {
42619 const program = this.tsLS.getProgram();
42620 if (!program) {
42621 // Program is very very unlikely to be undefined.
42622 throw new Error('No program in language service!');
42623 }
42624 return program;
42625 }
42626 /**
42627 * Return the TemplateSource if `node` is a template node.
42628 *
42629 * For example,
42630 *
42631 * @Component({
42632 * template: '<div></div>' <-- template node
42633 * })
42634 * class AppComponent {}
42635 * ^---- class declaration node
42636 *
42637 * @param node Potential template node
42638 */
42639 getInternalTemplate(node) {
42640 if (!tss.isStringLiteralLike(node)) {
42641 return;
42642 }
42643 const tmplAsgn = getPropertyAssignmentFromValue(node, 'template');
42644 if (!tmplAsgn) {
42645 return;
42646 }
42647 const classDecl = getClassDeclFromDecoratorProp(tmplAsgn);
42648 if (!classDecl || !classDecl.name) { // Does not handle anonymous class
42649 return;
42650 }
42651 const fileName = node.getSourceFile().fileName;
42652 const classSymbol = this.reflector.getStaticSymbol(fileName, classDecl.name.text);
42653 return new InlineTemplate(node, classDecl, classSymbol, this);
42654 }
42655 /**
42656 * Return the external template for `fileName`.
42657 * @param fileName HTML file
42658 */
42659 getExternalTemplate(fileName) {
42660 // First get the text for the template
42661 const snapshot = this.tsLsHost.getScriptSnapshot(fileName);
42662 if (!snapshot) {
42663 return;
42664 }
42665 const source = snapshot.getText(0, snapshot.getLength());
42666 // Next find the component class symbol
42667 const classSymbol = this.fileToComponent.get(tss.server.toNormalizedPath(fileName));
42668 if (!classSymbol) {
42669 return;
42670 }
42671 // Then use the class symbol to find the actual ts.ClassDeclaration node
42672 const sourceFile = this.getSourceFile(classSymbol.filePath);
42673 if (!sourceFile) {
42674 return;
42675 }
42676 // TODO: This only considers top-level class declarations in a source file.
42677 // This would not find a class declaration in a namespace, for example.
42678 const classDecl = sourceFile.forEachChild((child) => {
42679 if (tss.isClassDeclaration(child) && child.name && child.name.text === classSymbol.name) {
42680 return child;
42681 }
42682 });
42683 if (!classDecl) {
42684 return;
42685 }
42686 return new ExternalTemplate(source, fileName, classDecl, classSymbol, this);
42687 }
42688 collectError(error, filePath) {
42689 if (filePath) {
42690 let errors = this.collectedErrors.get(filePath);
42691 if (!errors) {
42692 errors = [];
42693 this.collectedErrors.set(filePath, errors);
42694 }
42695 errors.push(error);
42696 }
42697 }
42698 getCollectedErrors(defaultSpan, sourceFile) {
42699 const errors = this.collectedErrors.get(sourceFile.fileName);
42700 if (!errors) {
42701 return [];
42702 }
42703 // TODO: Add better typings for the errors
42704 return errors.map((e) => {
42705 const line = e.line || (e.position && e.position.line);
42706 const column = e.column || (e.position && e.position.column);
42707 const span = spanAt$1(sourceFile, line, column) || defaultSpan;
42708 if (isFormattedError(e)) {
42709 return errorToDiagnosticWithChain(e, span);
42710 }
42711 return { message: e.message, span };
42712 });
42713 }
42714 /**
42715 * Return the parsed template for the template at the specified `position`.
42716 * @param fileName TS or HTML file
42717 * @param position Position of the template in the TS file, otherwise ignored.
42718 */
42719 getTemplateAstAtPosition(fileName, position) {
42720 let template;
42721 if (fileName.endsWith('.ts')) {
42722 const sourceFile = this.getSourceFile(fileName);
42723 if (!sourceFile) {
42724 return;
42725 }
42726 // Find the node that most closely matches the position
42727 const node = findTightestNode(sourceFile, position);
42728 if (!node) {
42729 return;
42730 }
42731 template = this.getInternalTemplate(node);
42732 }
42733 else {
42734 template = this.getExternalTemplate(fileName);
42735 }
42736 if (!template) {
42737 return;
42738 }
42739 return this.getTemplateAst(template);
42740 }
42741 /**
42742 * Find the NgModule which the directive associated with the `classSymbol`
42743 * belongs to, then return its schema and transitive directives and pipes.
42744 * @param classSymbol Angular Symbol that defines a directive
42745 */
42746 getModuleMetadataForDirective(classSymbol) {
42747 const result = {
42748 directives: [],
42749 pipes: [],
42750 schemas: [],
42751 };
42752 // First find which NgModule the directive belongs to.
42753 const ngModule = this.analyzedModules.ngModuleByPipeOrDirective.get(classSymbol) ||
42754 findSuitableDefaultModule(this.analyzedModules);
42755 if (!ngModule) {
42756 return result;
42757 }
42758 // Then gather all transitive directives and pipes.
42759 const { directives, pipes } = ngModule.transitiveModule;
42760 for (const directive of directives) {
42761 const data = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference);
42762 if (data) {
42763 result.directives.push(data.metadata.toSummary());
42764 }
42765 }
42766 for (const pipe of pipes) {
42767 const metadata = this.resolver.getOrLoadPipeMetadata(pipe.reference);
42768 result.pipes.push(metadata.toSummary());
42769 }
42770 result.schemas.push(...ngModule.schemas);
42771 return result;
42772 }
42773 /**
42774 * Parse the `template` and return its AST, if any.
42775 * @param template template to be parsed
42776 */
42777 getTemplateAst(template) {
42778 const { type: classSymbol, fileName } = template;
42779 const data = this.resolver.getNonNormalizedDirectiveMetadata(classSymbol);
42780 if (!data) {
42781 return;
42782 }
42783 const htmlParser = new HtmlParser();
42784 const expressionParser = new Parser$1(new Lexer());
42785 const parser = new TemplateParser(new CompilerConfig(), this.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser, null, // console
42786 [] // tranforms
42787 );
42788 const htmlResult = htmlParser.parse(template.source, fileName, {
42789 tokenizeExpansionForms: true,
42790 preserveLineEndings: true,
42791 });
42792 const { directives, pipes, schemas } = this.getModuleMetadataForDirective(classSymbol);
42793 const parseResult = parser.tryParseHtml(htmlResult, data.metadata, directives, pipes, schemas);
42794 if (!parseResult.templateAst) {
42795 return;
42796 }
42797 return {
42798 htmlAst: htmlResult.rootNodes,
42799 templateAst: parseResult.templateAst,
42800 directive: data.metadata,
42801 directives,
42802 pipes,
42803 parseErrors: parseResult.errors,
42804 expressionParser,
42805 template,
42806 };
42807 }
42808 /**
42809 * Log the specified `msg` to file at INFO level. If logging is not enabled
42810 * this method is a no-op.
42811 * @param msg Log message
42812 */
42813 log(msg) {
42814 if (this.tsLsHost.log) {
42815 this.tsLsHost.log(msg);
42816 }
42817 }
42818 /**
42819 * Log the specified `msg` to file at ERROR level. If logging is not enabled
42820 * this method is a no-op.
42821 * @param msg error message
42822 */
42823 error(msg) {
42824 if (this.tsLsHost.error) {
42825 this.tsLsHost.error(msg);
42826 }
42827 }
42828 /**
42829 * Log debugging info to file at INFO level, only if verbose setting is turned
42830 * on. Otherwise, this method is a no-op.
42831 * @param msg debugging message
42832 */
42833 debug(msg) {
42834 const project = this.tsLsHost;
42835 if (!project.projectService) {
42836 // tsLsHost is not a Project
42837 return;
42838 }
42839 const { logger } = project.projectService;
42840 if (logger.hasLevel(tss.server.LogLevel.verbose)) {
42841 logger.info(msg);
42842 }
42843 }
42844 }
42845 function findSuitableDefaultModule(modules) {
42846 let result = undefined;
42847 let resultSize = 0;
42848 for (const module of modules.ngModules) {
42849 const moduleSize = module.transitiveModule.directives.length;
42850 if (moduleSize > resultSize) {
42851 result = module;
42852 resultSize = moduleSize;
42853 }
42854 }
42855 return result;
42856 }
42857 function spanOf$2(node) {
42858 return { start: node.getStart(), end: node.getEnd() };
42859 }
42860 function spanAt$1(sourceFile, line, column) {
42861 if (line != null && column != null) {
42862 const position = tss.getPositionOfLineAndCharacter(sourceFile, line, column);
42863 const findChild = function findChild(node) {
42864 if (node.kind > tss.SyntaxKind.LastToken && node.pos <= position && node.end > position) {
42865 const betterNode = tss.forEachChild(node, findChild);
42866 return betterNode || node;
42867 }
42868 };
42869 const node = tss.forEachChild(sourceFile, findChild);
42870 if (node) {
42871 return { start: node.getStart(), end: node.getEnd() };
42872 }
42873 }
42874 }
42875 function convertChain(chain) {
42876 return { message: chain.message, next: chain.next ? chain.next.map(convertChain) : undefined };
42877 }
42878 function errorToDiagnosticWithChain(error, span) {
42879 return { message: error.chain ? convertChain(error.chain) : error.message, span };
42880 }
42881
42882 /**
42883 * @license
42884 * Copyright Google LLC All Rights Reserved.
42885 *
42886 * Use of this source code is governed by an MIT-style license that can be
42887 * found in the LICENSE file at https://angular.io/license
42888 */
42889 // Use a WeakMap to keep track of Project to Host mapping so that when Project
42890 // is deleted Host could be garbage collected.
42891 const PROJECT_MAP = new WeakMap();
42892 /**
42893 * This function is called by tsserver to retrieve the external (non-TS) files
42894 * that should belong to the specified `project`. For Angular, these files are
42895 * external templates. This is called once when the project is loaded, then
42896 * every time when the program is updated.
42897 * @param project Project for which external files should be retrieved.
42898 */
42899 function getExternalFiles(project) {
42900 if (!project.hasRoots()) {
42901 // During project initialization where there is no root files yet we should
42902 // not do any work.
42903 return [];
42904 }
42905 const ngLsHost = PROJECT_MAP.get(project);
42906 if (ngLsHost === undefined) {
42907 return [];
42908 }
42909 ngLsHost.getAnalyzedModules();
42910 return ngLsHost.getExternalTemplates().filter(fileName => {
42911 // TODO(kyliau): Remove this when the following PR lands on the version of
42912 // TypeScript used in this repo.
42913 // https://github.com/microsoft/TypeScript/pull/41737
42914 return project.fileExists(fileName);
42915 });
42916 }
42917 function create(info) {
42918 const { languageService: tsLS, languageServiceHost: tsLSHost, config, project } = info;
42919 // This plugin could operate under two different modes:
42920 // 1. TS + Angular
42921 // Plugin augments TS language service to provide additional Angular
42922 // information. This only works with inline templates and is meant to be
42923 // used as a local plugin (configured via tsconfig.json)
42924 // 2. Angular only
42925 // Plugin only provides information on Angular templates, no TS info at all.
42926 // This effectively disables native TS features and is meant for internal
42927 // use only.
42928 const angularOnly = config ? config.angularOnly === true : false;
42929 const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS);
42930 const ngLS = createLanguageService(ngLSHost);
42931 PROJECT_MAP.set(project, ngLSHost);
42932 function getCompletionsAtPosition(fileName, position, options) {
42933 if (!angularOnly) {
42934 const results = tsLS.getCompletionsAtPosition(fileName, position, options);
42935 if (results && results.entries.length) {
42936 // If TS could answer the query, then return results immediately.
42937 return results;
42938 }
42939 }
42940 return ngLS.getCompletionsAtPosition(fileName, position, options);
42941 }
42942 function getQuickInfoAtPosition(fileName, position) {
42943 if (!angularOnly) {
42944 const result = tsLS.getQuickInfoAtPosition(fileName, position);
42945 if (result) {
42946 // If TS could answer the query, then return results immediately.
42947 return result;
42948 }
42949 }
42950 return ngLS.getQuickInfoAtPosition(fileName, position);
42951 }
42952 function getSemanticDiagnostics(fileName) {
42953 const results = [];
42954 if (!angularOnly) {
42955 results.push(...tsLS.getSemanticDiagnostics(fileName));
42956 }
42957 // For semantic diagnostics we need to combine both TS + Angular results
42958 results.push(...ngLS.getSemanticDiagnostics(fileName));
42959 return results;
42960 }
42961 function getDefinitionAtPosition(fileName, position) {
42962 if (!angularOnly) {
42963 const results = tsLS.getDefinitionAtPosition(fileName, position);
42964 if (results) {
42965 // If TS could answer the query, then return results immediately.
42966 return results;
42967 }
42968 }
42969 const result = ngLS.getDefinitionAndBoundSpan(fileName, position);
42970 if (!result || !result.definitions || !result.definitions.length) {
42971 return;
42972 }
42973 return result.definitions;
42974 }
42975 function getDefinitionAndBoundSpan(fileName, position) {
42976 if (!angularOnly) {
42977 const result = tsLS.getDefinitionAndBoundSpan(fileName, position);
42978 if (result) {
42979 // If TS could answer the query, then return results immediately.
42980 return result;
42981 }
42982 }
42983 return ngLS.getDefinitionAndBoundSpan(fileName, position);
42984 }
42985 function getTypeDefinitionAtPosition(fileName, position) {
42986 // Not implemented in VE Language Service
42987 return undefined;
42988 }
42989 function getReferencesAtPosition(fileName, position) {
42990 // Not implemented in VE Language Service
42991 return undefined;
42992 }
42993 function findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename) {
42994 // not implemented in VE Language Service
42995 return undefined;
42996 }
42997 function getTcb(fileName, position) {
42998 // Not implemented in VE Language Service
42999 return undefined;
43000 }
43001 return Object.assign(Object.assign({}, tsLS), {
43002 // Then override the methods supported by Angular language service
43003 getCompletionsAtPosition,
43004 getQuickInfoAtPosition,
43005 getSemanticDiagnostics,
43006 getDefinitionAtPosition,
43007 getDefinitionAndBoundSpan,
43008 getTypeDefinitionAtPosition,
43009 getReferencesAtPosition,
43010 findRenameLocations,
43011 getTcb });
43012 }
43013
43014 exports.create = create;
43015 exports.getExternalFiles = getExternalFiles;
43016 exports.isNgLanguageService = isNgLanguageService;
43017
43018 Object.defineProperty(exports, '__esModule', { value: true });
43019
43020});
43021//# sourceMappingURL=language-service.js.map