UNPKG

1.15 MBJavaScriptView Raw
1/**
2 * @license Angular v8.2.14
3 * (c) 2010-2019 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7/**
8 * @license
9 * Copyright Google Inc. All Rights Reserved.
10 *
11 * Use of this source code is governed by an MIT-style license that can be
12 * found in the LICENSE file at https://angular.io/license
13 */
14var TagContentType;
15(function (TagContentType) {
16 TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
17 TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
18 TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
19})(TagContentType || (TagContentType = {}));
20function splitNsName(elementName) {
21 if (elementName[0] != ':') {
22 return [null, elementName];
23 }
24 const colonIndex = elementName.indexOf(':', 1);
25 if (colonIndex == -1) {
26 throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
27 }
28 return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
29}
30// `<ng-container>` tags work the same regardless the namespace
31function isNgContainer(tagName) {
32 return splitNsName(tagName)[1] === 'ng-container';
33}
34// `<ng-content>` tags work the same regardless the namespace
35function isNgContent(tagName) {
36 return splitNsName(tagName)[1] === 'ng-content';
37}
38// `<ng-template>` tags work the same regardless the namespace
39function isNgTemplate(tagName) {
40 return splitNsName(tagName)[1] === 'ng-template';
41}
42function getNsPrefix(fullName) {
43 return fullName === null ? null : splitNsName(fullName)[0];
44}
45function mergeNsAndName(prefix, localName) {
46 return prefix ? `:${prefix}:${localName}` : localName;
47}
48// see http://www.w3.org/TR/html51/syntax.html#named-character-references
49// see https://html.spec.whatwg.org/multipage/entities.json
50// This list is not exhaustive to keep the compiler footprint low.
51// The `&#123;` / `&#x1ab;` syntax should be used when the named character reference does not
52// exist.
53const NAMED_ENTITIES = {
54 'Aacute': '\u00C1',
55 'aacute': '\u00E1',
56 'Acirc': '\u00C2',
57 'acirc': '\u00E2',
58 'acute': '\u00B4',
59 'AElig': '\u00C6',
60 'aelig': '\u00E6',
61 'Agrave': '\u00C0',
62 'agrave': '\u00E0',
63 'alefsym': '\u2135',
64 'Alpha': '\u0391',
65 'alpha': '\u03B1',
66 'amp': '&',
67 'and': '\u2227',
68 'ang': '\u2220',
69 'apos': '\u0027',
70 'Aring': '\u00C5',
71 'aring': '\u00E5',
72 'asymp': '\u2248',
73 'Atilde': '\u00C3',
74 'atilde': '\u00E3',
75 'Auml': '\u00C4',
76 'auml': '\u00E4',
77 'bdquo': '\u201E',
78 'Beta': '\u0392',
79 'beta': '\u03B2',
80 'brvbar': '\u00A6',
81 'bull': '\u2022',
82 'cap': '\u2229',
83 'Ccedil': '\u00C7',
84 'ccedil': '\u00E7',
85 'cedil': '\u00B8',
86 'cent': '\u00A2',
87 'Chi': '\u03A7',
88 'chi': '\u03C7',
89 'circ': '\u02C6',
90 'clubs': '\u2663',
91 'cong': '\u2245',
92 'copy': '\u00A9',
93 'crarr': '\u21B5',
94 'cup': '\u222A',
95 'curren': '\u00A4',
96 'dagger': '\u2020',
97 'Dagger': '\u2021',
98 'darr': '\u2193',
99 'dArr': '\u21D3',
100 'deg': '\u00B0',
101 'Delta': '\u0394',
102 'delta': '\u03B4',
103 'diams': '\u2666',
104 'divide': '\u00F7',
105 'Eacute': '\u00C9',
106 'eacute': '\u00E9',
107 'Ecirc': '\u00CA',
108 'ecirc': '\u00EA',
109 'Egrave': '\u00C8',
110 'egrave': '\u00E8',
111 'empty': '\u2205',
112 'emsp': '\u2003',
113 'ensp': '\u2002',
114 'Epsilon': '\u0395',
115 'epsilon': '\u03B5',
116 'equiv': '\u2261',
117 'Eta': '\u0397',
118 'eta': '\u03B7',
119 'ETH': '\u00D0',
120 'eth': '\u00F0',
121 'Euml': '\u00CB',
122 'euml': '\u00EB',
123 'euro': '\u20AC',
124 'exist': '\u2203',
125 'fnof': '\u0192',
126 'forall': '\u2200',
127 'frac12': '\u00BD',
128 'frac14': '\u00BC',
129 'frac34': '\u00BE',
130 'frasl': '\u2044',
131 'Gamma': '\u0393',
132 'gamma': '\u03B3',
133 'ge': '\u2265',
134 'gt': '>',
135 'harr': '\u2194',
136 'hArr': '\u21D4',
137 'hearts': '\u2665',
138 'hellip': '\u2026',
139 'Iacute': '\u00CD',
140 'iacute': '\u00ED',
141 'Icirc': '\u00CE',
142 'icirc': '\u00EE',
143 'iexcl': '\u00A1',
144 'Igrave': '\u00CC',
145 'igrave': '\u00EC',
146 'image': '\u2111',
147 'infin': '\u221E',
148 'int': '\u222B',
149 'Iota': '\u0399',
150 'iota': '\u03B9',
151 'iquest': '\u00BF',
152 'isin': '\u2208',
153 'Iuml': '\u00CF',
154 'iuml': '\u00EF',
155 'Kappa': '\u039A',
156 'kappa': '\u03BA',
157 'Lambda': '\u039B',
158 'lambda': '\u03BB',
159 'lang': '\u27E8',
160 'laquo': '\u00AB',
161 'larr': '\u2190',
162 'lArr': '\u21D0',
163 'lceil': '\u2308',
164 'ldquo': '\u201C',
165 'le': '\u2264',
166 'lfloor': '\u230A',
167 'lowast': '\u2217',
168 'loz': '\u25CA',
169 'lrm': '\u200E',
170 'lsaquo': '\u2039',
171 'lsquo': '\u2018',
172 'lt': '<',
173 'macr': '\u00AF',
174 'mdash': '\u2014',
175 'micro': '\u00B5',
176 'middot': '\u00B7',
177 'minus': '\u2212',
178 'Mu': '\u039C',
179 'mu': '\u03BC',
180 'nabla': '\u2207',
181 'nbsp': '\u00A0',
182 'ndash': '\u2013',
183 'ne': '\u2260',
184 'ni': '\u220B',
185 'not': '\u00AC',
186 'notin': '\u2209',
187 'nsub': '\u2284',
188 'Ntilde': '\u00D1',
189 'ntilde': '\u00F1',
190 'Nu': '\u039D',
191 'nu': '\u03BD',
192 'Oacute': '\u00D3',
193 'oacute': '\u00F3',
194 'Ocirc': '\u00D4',
195 'ocirc': '\u00F4',
196 'OElig': '\u0152',
197 'oelig': '\u0153',
198 'Ograve': '\u00D2',
199 'ograve': '\u00F2',
200 'oline': '\u203E',
201 'Omega': '\u03A9',
202 'omega': '\u03C9',
203 'Omicron': '\u039F',
204 'omicron': '\u03BF',
205 'oplus': '\u2295',
206 'or': '\u2228',
207 'ordf': '\u00AA',
208 'ordm': '\u00BA',
209 'Oslash': '\u00D8',
210 'oslash': '\u00F8',
211 'Otilde': '\u00D5',
212 'otilde': '\u00F5',
213 'otimes': '\u2297',
214 'Ouml': '\u00D6',
215 'ouml': '\u00F6',
216 'para': '\u00B6',
217 'permil': '\u2030',
218 'perp': '\u22A5',
219 'Phi': '\u03A6',
220 'phi': '\u03C6',
221 'Pi': '\u03A0',
222 'pi': '\u03C0',
223 'piv': '\u03D6',
224 'plusmn': '\u00B1',
225 'pound': '\u00A3',
226 'prime': '\u2032',
227 'Prime': '\u2033',
228 'prod': '\u220F',
229 'prop': '\u221D',
230 'Psi': '\u03A8',
231 'psi': '\u03C8',
232 'quot': '\u0022',
233 'radic': '\u221A',
234 'rang': '\u27E9',
235 'raquo': '\u00BB',
236 'rarr': '\u2192',
237 'rArr': '\u21D2',
238 'rceil': '\u2309',
239 'rdquo': '\u201D',
240 'real': '\u211C',
241 'reg': '\u00AE',
242 'rfloor': '\u230B',
243 'Rho': '\u03A1',
244 'rho': '\u03C1',
245 'rlm': '\u200F',
246 'rsaquo': '\u203A',
247 'rsquo': '\u2019',
248 'sbquo': '\u201A',
249 'Scaron': '\u0160',
250 'scaron': '\u0161',
251 'sdot': '\u22C5',
252 'sect': '\u00A7',
253 'shy': '\u00AD',
254 'Sigma': '\u03A3',
255 'sigma': '\u03C3',
256 'sigmaf': '\u03C2',
257 'sim': '\u223C',
258 'spades': '\u2660',
259 'sub': '\u2282',
260 'sube': '\u2286',
261 'sum': '\u2211',
262 'sup': '\u2283',
263 'sup1': '\u00B9',
264 'sup2': '\u00B2',
265 'sup3': '\u00B3',
266 'supe': '\u2287',
267 'szlig': '\u00DF',
268 'Tau': '\u03A4',
269 'tau': '\u03C4',
270 'there4': '\u2234',
271 'Theta': '\u0398',
272 'theta': '\u03B8',
273 'thetasym': '\u03D1',
274 'thinsp': '\u2009',
275 'THORN': '\u00DE',
276 'thorn': '\u00FE',
277 'tilde': '\u02DC',
278 'times': '\u00D7',
279 'trade': '\u2122',
280 'Uacute': '\u00DA',
281 'uacute': '\u00FA',
282 'uarr': '\u2191',
283 'uArr': '\u21D1',
284 'Ucirc': '\u00DB',
285 'ucirc': '\u00FB',
286 'Ugrave': '\u00D9',
287 'ugrave': '\u00F9',
288 'uml': '\u00A8',
289 'upsih': '\u03D2',
290 'Upsilon': '\u03A5',
291 'upsilon': '\u03C5',
292 'Uuml': '\u00DC',
293 'uuml': '\u00FC',
294 'weierp': '\u2118',
295 'Xi': '\u039E',
296 'xi': '\u03BE',
297 'Yacute': '\u00DD',
298 'yacute': '\u00FD',
299 'yen': '\u00A5',
300 'yuml': '\u00FF',
301 'Yuml': '\u0178',
302 'Zeta': '\u0396',
303 'zeta': '\u03B6',
304 'zwj': '\u200D',
305 'zwnj': '\u200C',
306};
307// The &ngsp; pseudo-entity is denoting a space. see:
308// https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart
309const NGSP_UNICODE = '\uE500';
310NAMED_ENTITIES['ngsp'] = NGSP_UNICODE;
311
312/**
313 * @license
314 * Copyright Google Inc. All Rights Reserved.
315 *
316 * Use of this source code is governed by an MIT-style license that can be
317 * found in the LICENSE file at https://angular.io/license
318 */
319class HtmlTagDefinition {
320 constructor({ closedByChildren, implicitNamespacePrefix, contentType = TagContentType.PARSABLE_DATA, closedByParent = false, isVoid = false, ignoreFirstLf = false } = {}) {
321 this.closedByChildren = {};
322 this.closedByParent = false;
323 this.canSelfClose = false;
324 if (closedByChildren && closedByChildren.length > 0) {
325 closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
326 }
327 this.isVoid = isVoid;
328 this.closedByParent = closedByParent || isVoid;
329 this.implicitNamespacePrefix = implicitNamespacePrefix || null;
330 this.contentType = contentType;
331 this.ignoreFirstLf = ignoreFirstLf;
332 }
333 isClosedByChild(name) {
334 return this.isVoid || name.toLowerCase() in this.closedByChildren;
335 }
336}
337let _DEFAULT_TAG_DEFINITION;
338// see http://www.w3.org/TR/html51/syntax.html#optional-tags
339// This implementation does not fully conform to the HTML5 spec.
340let TAG_DEFINITIONS;
341function getHtmlTagDefinition(tagName) {
342 if (!TAG_DEFINITIONS) {
343 _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
344 TAG_DEFINITIONS = {
345 'base': new HtmlTagDefinition({ isVoid: true }),
346 'meta': new HtmlTagDefinition({ isVoid: true }),
347 'area': new HtmlTagDefinition({ isVoid: true }),
348 'embed': new HtmlTagDefinition({ isVoid: true }),
349 'link': new HtmlTagDefinition({ isVoid: true }),
350 'img': new HtmlTagDefinition({ isVoid: true }),
351 'input': new HtmlTagDefinition({ isVoid: true }),
352 'param': new HtmlTagDefinition({ isVoid: true }),
353 'hr': new HtmlTagDefinition({ isVoid: true }),
354 'br': new HtmlTagDefinition({ isVoid: true }),
355 'source': new HtmlTagDefinition({ isVoid: true }),
356 'track': new HtmlTagDefinition({ isVoid: true }),
357 'wbr': new HtmlTagDefinition({ isVoid: true }),
358 'p': new HtmlTagDefinition({
359 closedByChildren: [
360 'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset',
361 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',
362 'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol',
363 'p', 'pre', 'section', 'table', 'ul'
364 ],
365 closedByParent: true
366 }),
367 'thead': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'] }),
368 'tbody': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'], closedByParent: true }),
369 'tfoot': new HtmlTagDefinition({ closedByChildren: ['tbody'], closedByParent: true }),
370 'tr': new HtmlTagDefinition({ closedByChildren: ['tr'], closedByParent: true }),
371 'td': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
372 'th': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
373 'col': new HtmlTagDefinition({ isVoid: true }),
374 'svg': new HtmlTagDefinition({ implicitNamespacePrefix: 'svg' }),
375 'math': new HtmlTagDefinition({ implicitNamespacePrefix: 'math' }),
376 'li': new HtmlTagDefinition({ closedByChildren: ['li'], closedByParent: true }),
377 'dt': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'] }),
378 'dd': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'], closedByParent: true }),
379 'rb': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
380 'rt': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
381 'rtc': new HtmlTagDefinition({ closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true }),
382 'rp': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
383 'optgroup': new HtmlTagDefinition({ closedByChildren: ['optgroup'], closedByParent: true }),
384 'option': new HtmlTagDefinition({ closedByChildren: ['option', 'optgroup'], closedByParent: true }),
385 'pre': new HtmlTagDefinition({ ignoreFirstLf: true }),
386 'listing': new HtmlTagDefinition({ ignoreFirstLf: true }),
387 'style': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }),
388 'script': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }),
389 'title': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT }),
390 'textarea': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }),
391 };
392 }
393 return TAG_DEFINITIONS[tagName.toLowerCase()] || _DEFAULT_TAG_DEFINITION;
394}
395
396/**
397 * @license
398 * Copyright Google Inc. All Rights Reserved.
399 *
400 * Use of this source code is governed by an MIT-style license that can be
401 * found in the LICENSE file at https://angular.io/license
402 */
403const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + //":not("
404 '([-\\w]+)|' + // "tag"
405 '(?:\\.([-\\w]+))|' + // ".class"
406 // "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range
407 '(?:\\[([-.\\w*]+)(?:=([\"\']?)([^\\]\"\']*)\\5)?\\])|' + // "[name]", "[name=value]",
408 // "[name="value"]",
409 // "[name='value']"
410 '(\\))|' + // ")"
411 '(\\s*,\\s*)', // ","
412'g');
413/**
414 * A css selector contains an element name,
415 * css classes and attribute/value pairs with the purpose
416 * of selecting subsets out of them.
417 */
418class CssSelector {
419 constructor() {
420 this.element = null;
421 this.classNames = [];
422 /**
423 * The selectors are encoded in pairs where:
424 * - even locations are attribute names
425 * - odd locations are attribute values.
426 *
427 * Example:
428 * Selector: `[key1=value1][key2]` would parse to:
429 * ```
430 * ['key1', 'value1', 'key2', '']
431 * ```
432 */
433 this.attrs = [];
434 this.notSelectors = [];
435 }
436 static parse(selector) {
437 const results = [];
438 const _addResult = (res, cssSel) => {
439 if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
440 cssSel.attrs.length == 0) {
441 cssSel.element = '*';
442 }
443 res.push(cssSel);
444 };
445 let cssSelector = new CssSelector();
446 let match;
447 let current = cssSelector;
448 let inNot = false;
449 _SELECTOR_REGEXP.lastIndex = 0;
450 while (match = _SELECTOR_REGEXP.exec(selector)) {
451 if (match[1]) {
452 if (inNot) {
453 throw new Error('Nesting :not is not allowed in a selector');
454 }
455 inNot = true;
456 current = new CssSelector();
457 cssSelector.notSelectors.push(current);
458 }
459 if (match[2]) {
460 current.setElement(match[2]);
461 }
462 if (match[3]) {
463 current.addClassName(match[3]);
464 }
465 if (match[4]) {
466 current.addAttribute(match[4], match[6]);
467 }
468 if (match[7]) {
469 inNot = false;
470 current = cssSelector;
471 }
472 if (match[8]) {
473 if (inNot) {
474 throw new Error('Multiple selectors in :not are not supported');
475 }
476 _addResult(results, cssSelector);
477 cssSelector = current = new CssSelector();
478 }
479 }
480 _addResult(results, cssSelector);
481 return results;
482 }
483 isElementSelector() {
484 return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 &&
485 this.notSelectors.length === 0;
486 }
487 hasElementSelector() { return !!this.element; }
488 setElement(element = null) { this.element = element; }
489 /** Gets a template string for an element that matches the selector. */
490 getMatchingElementTemplate() {
491 const tagName = this.element || 'div';
492 const classAttr = this.classNames.length > 0 ? ` class="${this.classNames.join(' ')}"` : '';
493 let attrs = '';
494 for (let i = 0; i < this.attrs.length; i += 2) {
495 const attrName = this.attrs[i];
496 const attrValue = this.attrs[i + 1] !== '' ? `="${this.attrs[i + 1]}"` : '';
497 attrs += ` ${attrName}${attrValue}`;
498 }
499 return getHtmlTagDefinition(tagName).isVoid ? `<${tagName}${classAttr}${attrs}/>` :
500 `<${tagName}${classAttr}${attrs}></${tagName}>`;
501 }
502 getAttrs() {
503 const result = [];
504 if (this.classNames.length > 0) {
505 result.push('class', this.classNames.join(' '));
506 }
507 return result.concat(this.attrs);
508 }
509 addAttribute(name, value = '') {
510 this.attrs.push(name, value && value.toLowerCase() || '');
511 }
512 addClassName(name) { this.classNames.push(name.toLowerCase()); }
513 toString() {
514 let res = this.element || '';
515 if (this.classNames) {
516 this.classNames.forEach(klass => res += `.${klass}`);
517 }
518 if (this.attrs) {
519 for (let i = 0; i < this.attrs.length; i += 2) {
520 const name = this.attrs[i];
521 const value = this.attrs[i + 1];
522 res += `[${name}${value ? '=' + value : ''}]`;
523 }
524 }
525 this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
526 return res;
527 }
528}
529/**
530 * Reads a list of CssSelectors and allows to calculate which ones
531 * are contained in a given CssSelector.
532 */
533class SelectorMatcher {
534 constructor() {
535 this._elementMap = new Map();
536 this._elementPartialMap = new Map();
537 this._classMap = new Map();
538 this._classPartialMap = new Map();
539 this._attrValueMap = new Map();
540 this._attrValuePartialMap = new Map();
541 this._listContexts = [];
542 }
543 static createNotMatcher(notSelectors) {
544 const notMatcher = new SelectorMatcher();
545 notMatcher.addSelectables(notSelectors, null);
546 return notMatcher;
547 }
548 addSelectables(cssSelectors, callbackCtxt) {
549 let listContext = null;
550 if (cssSelectors.length > 1) {
551 listContext = new SelectorListContext(cssSelectors);
552 this._listContexts.push(listContext);
553 }
554 for (let i = 0; i < cssSelectors.length; i++) {
555 this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
556 }
557 }
558 /**
559 * Add an object that can be found later on by calling `match`.
560 * @param cssSelector A css selector
561 * @param callbackCtxt An opaque object that will be given to the callback of the `match` function
562 */
563 _addSelectable(cssSelector, callbackCtxt, listContext) {
564 let matcher = this;
565 const element = cssSelector.element;
566 const classNames = cssSelector.classNames;
567 const attrs = cssSelector.attrs;
568 const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
569 if (element) {
570 const isTerminal = attrs.length === 0 && classNames.length === 0;
571 if (isTerminal) {
572 this._addTerminal(matcher._elementMap, element, selectable);
573 }
574 else {
575 matcher = this._addPartial(matcher._elementPartialMap, element);
576 }
577 }
578 if (classNames) {
579 for (let i = 0; i < classNames.length; i++) {
580 const isTerminal = attrs.length === 0 && i === classNames.length - 1;
581 const className = classNames[i];
582 if (isTerminal) {
583 this._addTerminal(matcher._classMap, className, selectable);
584 }
585 else {
586 matcher = this._addPartial(matcher._classPartialMap, className);
587 }
588 }
589 }
590 if (attrs) {
591 for (let i = 0; i < attrs.length; i += 2) {
592 const isTerminal = i === attrs.length - 2;
593 const name = attrs[i];
594 const value = attrs[i + 1];
595 if (isTerminal) {
596 const terminalMap = matcher._attrValueMap;
597 let terminalValuesMap = terminalMap.get(name);
598 if (!terminalValuesMap) {
599 terminalValuesMap = new Map();
600 terminalMap.set(name, terminalValuesMap);
601 }
602 this._addTerminal(terminalValuesMap, value, selectable);
603 }
604 else {
605 const partialMap = matcher._attrValuePartialMap;
606 let partialValuesMap = partialMap.get(name);
607 if (!partialValuesMap) {
608 partialValuesMap = new Map();
609 partialMap.set(name, partialValuesMap);
610 }
611 matcher = this._addPartial(partialValuesMap, value);
612 }
613 }
614 }
615 }
616 _addTerminal(map, name, selectable) {
617 let terminalList = map.get(name);
618 if (!terminalList) {
619 terminalList = [];
620 map.set(name, terminalList);
621 }
622 terminalList.push(selectable);
623 }
624 _addPartial(map, name) {
625 let matcher = map.get(name);
626 if (!matcher) {
627 matcher = new SelectorMatcher();
628 map.set(name, matcher);
629 }
630 return matcher;
631 }
632 /**
633 * Find the objects that have been added via `addSelectable`
634 * whose css selector is contained in the given css selector.
635 * @param cssSelector A css selector
636 * @param matchedCallback This callback will be called with the object handed into `addSelectable`
637 * @return boolean true if a match was found
638 */
639 match(cssSelector, matchedCallback) {
640 let result = false;
641 const element = cssSelector.element;
642 const classNames = cssSelector.classNames;
643 const attrs = cssSelector.attrs;
644 for (let i = 0; i < this._listContexts.length; i++) {
645 this._listContexts[i].alreadyMatched = false;
646 }
647 result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result;
648 result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
649 result;
650 if (classNames) {
651 for (let i = 0; i < classNames.length; i++) {
652 const className = classNames[i];
653 result =
654 this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
655 result =
656 this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) ||
657 result;
658 }
659 }
660 if (attrs) {
661 for (let i = 0; i < attrs.length; i += 2) {
662 const name = attrs[i];
663 const value = attrs[i + 1];
664 const terminalValuesMap = this._attrValueMap.get(name);
665 if (value) {
666 result =
667 this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
668 }
669 result =
670 this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
671 const partialValuesMap = this._attrValuePartialMap.get(name);
672 if (value) {
673 result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
674 }
675 result =
676 this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
677 }
678 }
679 return result;
680 }
681 /** @internal */
682 _matchTerminal(map, name, cssSelector, matchedCallback) {
683 if (!map || typeof name !== 'string') {
684 return false;
685 }
686 let selectables = map.get(name) || [];
687 const starSelectables = map.get('*');
688 if (starSelectables) {
689 selectables = selectables.concat(starSelectables);
690 }
691 if (selectables.length === 0) {
692 return false;
693 }
694 let selectable;
695 let result = false;
696 for (let i = 0; i < selectables.length; i++) {
697 selectable = selectables[i];
698 result = selectable.finalize(cssSelector, matchedCallback) || result;
699 }
700 return result;
701 }
702 /** @internal */
703 _matchPartial(map, name, cssSelector, matchedCallback) {
704 if (!map || typeof name !== 'string') {
705 return false;
706 }
707 const nestedSelector = map.get(name);
708 if (!nestedSelector) {
709 return false;
710 }
711 // TODO(perf): get rid of recursion and measure again
712 // TODO(perf): don't pass the whole selector into the recursion,
713 // but only the not processed parts
714 return nestedSelector.match(cssSelector, matchedCallback);
715 }
716}
717class SelectorListContext {
718 constructor(selectors) {
719 this.selectors = selectors;
720 this.alreadyMatched = false;
721 }
722}
723// Store context to pass back selector and context when a selector is matched
724class SelectorContext {
725 constructor(selector, cbContext, listContext) {
726 this.selector = selector;
727 this.cbContext = cbContext;
728 this.listContext = listContext;
729 this.notSelectors = selector.notSelectors;
730 }
731 finalize(cssSelector, callback) {
732 let result = true;
733 if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
734 const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
735 result = !notMatcher.match(cssSelector, null);
736 }
737 if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
738 if (this.listContext) {
739 this.listContext.alreadyMatched = true;
740 }
741 callback(this.selector, this.cbContext);
742 }
743 return result;
744 }
745}
746
747/**
748 * @license
749 * Copyright Google Inc. All Rights Reserved.
750 *
751 * Use of this source code is governed by an MIT-style license that can be
752 * found in the LICENSE file at https://angular.io/license
753 */
754const createInject = makeMetadataFactory('Inject', (token) => ({ token }));
755const createInjectionToken = makeMetadataFactory('InjectionToken', (desc) => ({ _desc: desc, ngInjectableDef: undefined }));
756const createAttribute = makeMetadataFactory('Attribute', (attributeName) => ({ attributeName }));
757const createContentChildren = makeMetadataFactory('ContentChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false }, data)));
758const createContentChild = makeMetadataFactory('ContentChild', (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data)));
759const createViewChildren = makeMetadataFactory('ViewChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true }, data)));
760const createViewChild = makeMetadataFactory('ViewChild', (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data)));
761const createDirective = makeMetadataFactory('Directive', (dir = {}) => dir);
762var ViewEncapsulation;
763(function (ViewEncapsulation) {
764 ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
765 ViewEncapsulation[ViewEncapsulation["Native"] = 1] = "Native";
766 ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
767 ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
768})(ViewEncapsulation || (ViewEncapsulation = {}));
769var ChangeDetectionStrategy;
770(function (ChangeDetectionStrategy) {
771 ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
772 ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
773})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
774const createComponent = makeMetadataFactory('Component', (c = {}) => (Object.assign({ changeDetection: ChangeDetectionStrategy.Default }, c)));
775const createPipe = makeMetadataFactory('Pipe', (p) => (Object.assign({ pure: true }, p)));
776const createInput = makeMetadataFactory('Input', (bindingPropertyName) => ({ bindingPropertyName }));
777const createOutput = makeMetadataFactory('Output', (bindingPropertyName) => ({ bindingPropertyName }));
778const createHostBinding = makeMetadataFactory('HostBinding', (hostPropertyName) => ({ hostPropertyName }));
779const createHostListener = makeMetadataFactory('HostListener', (eventName, args) => ({ eventName, args }));
780const createNgModule = makeMetadataFactory('NgModule', (ngModule) => ngModule);
781const createInjectable = makeMetadataFactory('Injectable', (injectable = {}) => injectable);
782const CUSTOM_ELEMENTS_SCHEMA = {
783 name: 'custom-elements'
784};
785const NO_ERRORS_SCHEMA = {
786 name: 'no-errors-schema'
787};
788const createOptional = makeMetadataFactory('Optional');
789const createSelf = makeMetadataFactory('Self');
790const createSkipSelf = makeMetadataFactory('SkipSelf');
791const createHost = makeMetadataFactory('Host');
792const Type = Function;
793var SecurityContext;
794(function (SecurityContext) {
795 SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
796 SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
797 SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
798 SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
799 SecurityContext[SecurityContext["URL"] = 4] = "URL";
800 SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
801})(SecurityContext || (SecurityContext = {}));
802var MissingTranslationStrategy;
803(function (MissingTranslationStrategy) {
804 MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
805 MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
806 MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
807})(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
808function makeMetadataFactory(name, props) {
809 // This must be declared as a function, not a fat arrow, so that ES2015 devmode produces code
810 // that works with the static_reflector.ts in the ViewEngine compiler.
811 // In particular, `_registerDecoratorOrConstructor` assumes that the value returned here can be
812 // new'ed.
813 function factory(...args) {
814 const values = props ? props(...args) : {};
815 return Object.assign({ ngMetadataName: name }, values);
816 }
817 factory.isTypeOf = (obj) => obj && obj.ngMetadataName === name;
818 factory.ngMetadataName = name;
819 return factory;
820}
821function parserSelectorToSimpleSelector(selector) {
822 const classes = selector.classNames && selector.classNames.length ?
823 [8 /* CLASS */, ...selector.classNames] :
824 [];
825 const elementName = selector.element && selector.element !== '*' ? selector.element : '';
826 return [elementName, ...selector.attrs, ...classes];
827}
828function parserSelectorToNegativeSelector(selector) {
829 const classes = selector.classNames && selector.classNames.length ?
830 [8 /* CLASS */, ...selector.classNames] :
831 [];
832 if (selector.element) {
833 return [
834 1 /* NOT */ | 4 /* ELEMENT */, selector.element, ...selector.attrs, ...classes
835 ];
836 }
837 else if (selector.attrs.length) {
838 return [1 /* NOT */ | 2 /* ATTRIBUTE */, ...selector.attrs, ...classes];
839 }
840 else {
841 return selector.classNames && selector.classNames.length ?
842 [1 /* NOT */ | 8 /* CLASS */, ...selector.classNames] :
843 [];
844 }
845}
846function parserSelectorToR3Selector(selector) {
847 const positive = parserSelectorToSimpleSelector(selector);
848 const negative = selector.notSelectors && selector.notSelectors.length ?
849 selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) :
850 [];
851 return positive.concat(...negative);
852}
853function parseSelectorToR3Selector(selector) {
854 return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
855}
856
857var core = /*#__PURE__*/Object.freeze({
858 createInject: createInject,
859 createInjectionToken: createInjectionToken,
860 createAttribute: createAttribute,
861 createContentChildren: createContentChildren,
862 createContentChild: createContentChild,
863 createViewChildren: createViewChildren,
864 createViewChild: createViewChild,
865 createDirective: createDirective,
866 get ViewEncapsulation () { return ViewEncapsulation; },
867 get ChangeDetectionStrategy () { return ChangeDetectionStrategy; },
868 createComponent: createComponent,
869 createPipe: createPipe,
870 createInput: createInput,
871 createOutput: createOutput,
872 createHostBinding: createHostBinding,
873 createHostListener: createHostListener,
874 createNgModule: createNgModule,
875 createInjectable: createInjectable,
876 CUSTOM_ELEMENTS_SCHEMA: CUSTOM_ELEMENTS_SCHEMA,
877 NO_ERRORS_SCHEMA: NO_ERRORS_SCHEMA,
878 createOptional: createOptional,
879 createSelf: createSelf,
880 createSkipSelf: createSkipSelf,
881 createHost: createHost,
882 Type: Type,
883 get SecurityContext () { return SecurityContext; },
884 get MissingTranslationStrategy () { return MissingTranslationStrategy; },
885 parseSelectorToR3Selector: parseSelectorToR3Selector
886});
887
888/**
889 * @license
890 * Copyright Google Inc. All Rights Reserved.
891 *
892 * Use of this source code is governed by an MIT-style license that can be
893 * found in the LICENSE file at https://angular.io/license
894 */
895//// Types
896var TypeModifier;
897(function (TypeModifier) {
898 TypeModifier[TypeModifier["Const"] = 0] = "Const";
899})(TypeModifier || (TypeModifier = {}));
900class Type$1 {
901 constructor(modifiers = null) {
902 this.modifiers = modifiers;
903 if (!modifiers) {
904 this.modifiers = [];
905 }
906 }
907 hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; }
908}
909var BuiltinTypeName;
910(function (BuiltinTypeName) {
911 BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic";
912 BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool";
913 BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String";
914 BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int";
915 BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number";
916 BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function";
917 BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred";
918 BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None";
919})(BuiltinTypeName || (BuiltinTypeName = {}));
920class BuiltinType extends Type$1 {
921 constructor(name, modifiers = null) {
922 super(modifiers);
923 this.name = name;
924 }
925 visitType(visitor, context) {
926 return visitor.visitBuiltinType(this, context);
927 }
928}
929class ExpressionType extends Type$1 {
930 constructor(value, modifiers = null, typeParams = null) {
931 super(modifiers);
932 this.value = value;
933 this.typeParams = typeParams;
934 }
935 visitType(visitor, context) {
936 return visitor.visitExpressionType(this, context);
937 }
938}
939class ArrayType extends Type$1 {
940 constructor(of, modifiers = null) {
941 super(modifiers);
942 this.of = of;
943 }
944 visitType(visitor, context) {
945 return visitor.visitArrayType(this, context);
946 }
947}
948class MapType extends Type$1 {
949 constructor(valueType, modifiers = null) {
950 super(modifiers);
951 this.valueType = valueType || null;
952 }
953 visitType(visitor, context) { return visitor.visitMapType(this, context); }
954}
955const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
956const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred);
957const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool);
958const INT_TYPE = new BuiltinType(BuiltinTypeName.Int);
959const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number);
960const STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
961const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
962const NONE_TYPE = new BuiltinType(BuiltinTypeName.None);
963///// Expressions
964var BinaryOperator;
965(function (BinaryOperator) {
966 BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals";
967 BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals";
968 BinaryOperator[BinaryOperator["Identical"] = 2] = "Identical";
969 BinaryOperator[BinaryOperator["NotIdentical"] = 3] = "NotIdentical";
970 BinaryOperator[BinaryOperator["Minus"] = 4] = "Minus";
971 BinaryOperator[BinaryOperator["Plus"] = 5] = "Plus";
972 BinaryOperator[BinaryOperator["Divide"] = 6] = "Divide";
973 BinaryOperator[BinaryOperator["Multiply"] = 7] = "Multiply";
974 BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo";
975 BinaryOperator[BinaryOperator["And"] = 9] = "And";
976 BinaryOperator[BinaryOperator["Or"] = 10] = "Or";
977 BinaryOperator[BinaryOperator["BitwiseAnd"] = 11] = "BitwiseAnd";
978 BinaryOperator[BinaryOperator["Lower"] = 12] = "Lower";
979 BinaryOperator[BinaryOperator["LowerEquals"] = 13] = "LowerEquals";
980 BinaryOperator[BinaryOperator["Bigger"] = 14] = "Bigger";
981 BinaryOperator[BinaryOperator["BiggerEquals"] = 15] = "BiggerEquals";
982})(BinaryOperator || (BinaryOperator = {}));
983function nullSafeIsEquivalent(base, other) {
984 if (base == null || other == null) {
985 return base == other;
986 }
987 return base.isEquivalent(other);
988}
989function areAllEquivalent(base, other) {
990 const len = base.length;
991 if (len !== other.length) {
992 return false;
993 }
994 for (let i = 0; i < len; i++) {
995 if (!base[i].isEquivalent(other[i])) {
996 return false;
997 }
998 }
999 return true;
1000}
1001class Expression {
1002 constructor(type, sourceSpan) {
1003 this.type = type || null;
1004 this.sourceSpan = sourceSpan || null;
1005 }
1006 prop(name, sourceSpan) {
1007 return new ReadPropExpr(this, name, null, sourceSpan);
1008 }
1009 key(index, type, sourceSpan) {
1010 return new ReadKeyExpr(this, index, type, sourceSpan);
1011 }
1012 callMethod(name, params, sourceSpan) {
1013 return new InvokeMethodExpr(this, name, params, null, sourceSpan);
1014 }
1015 callFn(params, sourceSpan) {
1016 return new InvokeFunctionExpr(this, params, null, sourceSpan);
1017 }
1018 instantiate(params, type, sourceSpan) {
1019 return new InstantiateExpr(this, params, type, sourceSpan);
1020 }
1021 conditional(trueCase, falseCase = null, sourceSpan) {
1022 return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan);
1023 }
1024 equals(rhs, sourceSpan) {
1025 return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan);
1026 }
1027 notEquals(rhs, sourceSpan) {
1028 return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan);
1029 }
1030 identical(rhs, sourceSpan) {
1031 return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan);
1032 }
1033 notIdentical(rhs, sourceSpan) {
1034 return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan);
1035 }
1036 minus(rhs, sourceSpan) {
1037 return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan);
1038 }
1039 plus(rhs, sourceSpan) {
1040 return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan);
1041 }
1042 divide(rhs, sourceSpan) {
1043 return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan);
1044 }
1045 multiply(rhs, sourceSpan) {
1046 return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan);
1047 }
1048 modulo(rhs, sourceSpan) {
1049 return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan);
1050 }
1051 and(rhs, sourceSpan) {
1052 return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan);
1053 }
1054 bitwiseAnd(rhs, sourceSpan, parens = true) {
1055 return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens);
1056 }
1057 or(rhs, sourceSpan) {
1058 return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan);
1059 }
1060 lower(rhs, sourceSpan) {
1061 return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan);
1062 }
1063 lowerEquals(rhs, sourceSpan) {
1064 return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan);
1065 }
1066 bigger(rhs, sourceSpan) {
1067 return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan);
1068 }
1069 biggerEquals(rhs, sourceSpan) {
1070 return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan);
1071 }
1072 isBlank(sourceSpan) {
1073 // Note: We use equals by purpose here to compare to null and undefined in JS.
1074 // We use the typed null to allow strictNullChecks to narrow types.
1075 return this.equals(TYPED_NULL_EXPR, sourceSpan);
1076 }
1077 cast(type, sourceSpan) {
1078 return new CastExpr(this, type, sourceSpan);
1079 }
1080 toStmt() { return new ExpressionStatement(this, null); }
1081}
1082var BuiltinVar;
1083(function (BuiltinVar) {
1084 BuiltinVar[BuiltinVar["This"] = 0] = "This";
1085 BuiltinVar[BuiltinVar["Super"] = 1] = "Super";
1086 BuiltinVar[BuiltinVar["CatchError"] = 2] = "CatchError";
1087 BuiltinVar[BuiltinVar["CatchStack"] = 3] = "CatchStack";
1088})(BuiltinVar || (BuiltinVar = {}));
1089class ReadVarExpr extends Expression {
1090 constructor(name, type, sourceSpan) {
1091 super(type, sourceSpan);
1092 if (typeof name === 'string') {
1093 this.name = name;
1094 this.builtin = null;
1095 }
1096 else {
1097 this.name = null;
1098 this.builtin = name;
1099 }
1100 }
1101 isEquivalent(e) {
1102 return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin;
1103 }
1104 isConstant() { return false; }
1105 visitExpression(visitor, context) {
1106 return visitor.visitReadVarExpr(this, context);
1107 }
1108 set(value) {
1109 if (!this.name) {
1110 throw new Error(`Built in variable ${this.builtin} can not be assigned to.`);
1111 }
1112 return new WriteVarExpr(this.name, value, null, this.sourceSpan);
1113 }
1114}
1115class TypeofExpr extends Expression {
1116 constructor(expr, type, sourceSpan) {
1117 super(type, sourceSpan);
1118 this.expr = expr;
1119 }
1120 visitExpression(visitor, context) {
1121 return visitor.visitTypeofExpr(this, context);
1122 }
1123 isEquivalent(e) {
1124 return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
1125 }
1126 isConstant() { return this.expr.isConstant(); }
1127}
1128class WrappedNodeExpr extends Expression {
1129 constructor(node, type, sourceSpan) {
1130 super(type, sourceSpan);
1131 this.node = node;
1132 }
1133 isEquivalent(e) {
1134 return e instanceof WrappedNodeExpr && this.node === e.node;
1135 }
1136 isConstant() { return false; }
1137 visitExpression(visitor, context) {
1138 return visitor.visitWrappedNodeExpr(this, context);
1139 }
1140}
1141class WriteVarExpr extends Expression {
1142 constructor(name, value, type, sourceSpan) {
1143 super(type || value.type, sourceSpan);
1144 this.name = name;
1145 this.value = value;
1146 }
1147 isEquivalent(e) {
1148 return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value);
1149 }
1150 isConstant() { return false; }
1151 visitExpression(visitor, context) {
1152 return visitor.visitWriteVarExpr(this, context);
1153 }
1154 toDeclStmt(type, modifiers) {
1155 return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
1156 }
1157 toConstDecl() { return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]); }
1158}
1159class WriteKeyExpr extends Expression {
1160 constructor(receiver, index, value, type, sourceSpan) {
1161 super(type || value.type, sourceSpan);
1162 this.receiver = receiver;
1163 this.index = index;
1164 this.value = value;
1165 }
1166 isEquivalent(e) {
1167 return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) &&
1168 this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value);
1169 }
1170 isConstant() { return false; }
1171 visitExpression(visitor, context) {
1172 return visitor.visitWriteKeyExpr(this, context);
1173 }
1174}
1175class WritePropExpr extends Expression {
1176 constructor(receiver, name, value, type, sourceSpan) {
1177 super(type || value.type, sourceSpan);
1178 this.receiver = receiver;
1179 this.name = name;
1180 this.value = value;
1181 }
1182 isEquivalent(e) {
1183 return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) &&
1184 this.name === e.name && this.value.isEquivalent(e.value);
1185 }
1186 isConstant() { return false; }
1187 visitExpression(visitor, context) {
1188 return visitor.visitWritePropExpr(this, context);
1189 }
1190}
1191var BuiltinMethod;
1192(function (BuiltinMethod) {
1193 BuiltinMethod[BuiltinMethod["ConcatArray"] = 0] = "ConcatArray";
1194 BuiltinMethod[BuiltinMethod["SubscribeObservable"] = 1] = "SubscribeObservable";
1195 BuiltinMethod[BuiltinMethod["Bind"] = 2] = "Bind";
1196})(BuiltinMethod || (BuiltinMethod = {}));
1197class InvokeMethodExpr extends Expression {
1198 constructor(receiver, method, args, type, sourceSpan) {
1199 super(type, sourceSpan);
1200 this.receiver = receiver;
1201 this.args = args;
1202 if (typeof method === 'string') {
1203 this.name = method;
1204 this.builtin = null;
1205 }
1206 else {
1207 this.name = null;
1208 this.builtin = method;
1209 }
1210 }
1211 isEquivalent(e) {
1212 return e instanceof InvokeMethodExpr && this.receiver.isEquivalent(e.receiver) &&
1213 this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args);
1214 }
1215 isConstant() { return false; }
1216 visitExpression(visitor, context) {
1217 return visitor.visitInvokeMethodExpr(this, context);
1218 }
1219}
1220class InvokeFunctionExpr extends Expression {
1221 constructor(fn, args, type, sourceSpan, pure = false) {
1222 super(type, sourceSpan);
1223 this.fn = fn;
1224 this.args = args;
1225 this.pure = pure;
1226 }
1227 isEquivalent(e) {
1228 return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) &&
1229 areAllEquivalent(this.args, e.args) && this.pure === e.pure;
1230 }
1231 isConstant() { return false; }
1232 visitExpression(visitor, context) {
1233 return visitor.visitInvokeFunctionExpr(this, context);
1234 }
1235}
1236class InstantiateExpr extends Expression {
1237 constructor(classExpr, args, type, sourceSpan) {
1238 super(type, sourceSpan);
1239 this.classExpr = classExpr;
1240 this.args = args;
1241 }
1242 isEquivalent(e) {
1243 return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) &&
1244 areAllEquivalent(this.args, e.args);
1245 }
1246 isConstant() { return false; }
1247 visitExpression(visitor, context) {
1248 return visitor.visitInstantiateExpr(this, context);
1249 }
1250}
1251class LiteralExpr extends Expression {
1252 constructor(value, type, sourceSpan) {
1253 super(type, sourceSpan);
1254 this.value = value;
1255 }
1256 isEquivalent(e) {
1257 return e instanceof LiteralExpr && this.value === e.value;
1258 }
1259 isConstant() { return true; }
1260 visitExpression(visitor, context) {
1261 return visitor.visitLiteralExpr(this, context);
1262 }
1263}
1264class ExternalExpr extends Expression {
1265 constructor(value, type, typeParams = null, sourceSpan) {
1266 super(type, sourceSpan);
1267 this.value = value;
1268 this.typeParams = typeParams;
1269 }
1270 isEquivalent(e) {
1271 return e instanceof ExternalExpr && this.value.name === e.value.name &&
1272 this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime;
1273 }
1274 isConstant() { return false; }
1275 visitExpression(visitor, context) {
1276 return visitor.visitExternalExpr(this, context);
1277 }
1278}
1279class ExternalReference {
1280 constructor(moduleName, name, runtime) {
1281 this.moduleName = moduleName;
1282 this.name = name;
1283 this.runtime = runtime;
1284 }
1285}
1286class ConditionalExpr extends Expression {
1287 constructor(condition, trueCase, falseCase = null, type, sourceSpan) {
1288 super(type || trueCase.type, sourceSpan);
1289 this.condition = condition;
1290 this.falseCase = falseCase;
1291 this.trueCase = trueCase;
1292 }
1293 isEquivalent(e) {
1294 return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) &&
1295 this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
1296 }
1297 isConstant() { return false; }
1298 visitExpression(visitor, context) {
1299 return visitor.visitConditionalExpr(this, context);
1300 }
1301}
1302class NotExpr extends Expression {
1303 constructor(condition, sourceSpan) {
1304 super(BOOL_TYPE, sourceSpan);
1305 this.condition = condition;
1306 }
1307 isEquivalent(e) {
1308 return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
1309 }
1310 isConstant() { return false; }
1311 visitExpression(visitor, context) {
1312 return visitor.visitNotExpr(this, context);
1313 }
1314}
1315class AssertNotNull extends Expression {
1316 constructor(condition, sourceSpan) {
1317 super(condition.type, sourceSpan);
1318 this.condition = condition;
1319 }
1320 isEquivalent(e) {
1321 return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition);
1322 }
1323 isConstant() { return false; }
1324 visitExpression(visitor, context) {
1325 return visitor.visitAssertNotNullExpr(this, context);
1326 }
1327}
1328class CastExpr extends Expression {
1329 constructor(value, type, sourceSpan) {
1330 super(type, sourceSpan);
1331 this.value = value;
1332 }
1333 isEquivalent(e) {
1334 return e instanceof CastExpr && this.value.isEquivalent(e.value);
1335 }
1336 isConstant() { return false; }
1337 visitExpression(visitor, context) {
1338 return visitor.visitCastExpr(this, context);
1339 }
1340}
1341class FnParam {
1342 constructor(name, type = null) {
1343 this.name = name;
1344 this.type = type;
1345 }
1346 isEquivalent(param) { return this.name === param.name; }
1347}
1348class FunctionExpr extends Expression {
1349 constructor(params, statements, type, sourceSpan, name) {
1350 super(type, sourceSpan);
1351 this.params = params;
1352 this.statements = statements;
1353 this.name = name;
1354 }
1355 isEquivalent(e) {
1356 return e instanceof FunctionExpr && areAllEquivalent(this.params, e.params) &&
1357 areAllEquivalent(this.statements, e.statements);
1358 }
1359 isConstant() { return false; }
1360 visitExpression(visitor, context) {
1361 return visitor.visitFunctionExpr(this, context);
1362 }
1363 toDeclStmt(name, modifiers = null) {
1364 return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan);
1365 }
1366}
1367class BinaryOperatorExpr extends Expression {
1368 constructor(operator, lhs, rhs, type, sourceSpan, parens = true) {
1369 super(type || lhs.type, sourceSpan);
1370 this.operator = operator;
1371 this.rhs = rhs;
1372 this.parens = parens;
1373 this.lhs = lhs;
1374 }
1375 isEquivalent(e) {
1376 return e instanceof BinaryOperatorExpr && this.operator === e.operator &&
1377 this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
1378 }
1379 isConstant() { return false; }
1380 visitExpression(visitor, context) {
1381 return visitor.visitBinaryOperatorExpr(this, context);
1382 }
1383}
1384class ReadPropExpr extends Expression {
1385 constructor(receiver, name, type, sourceSpan) {
1386 super(type, sourceSpan);
1387 this.receiver = receiver;
1388 this.name = name;
1389 }
1390 isEquivalent(e) {
1391 return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) &&
1392 this.name === e.name;
1393 }
1394 isConstant() { return false; }
1395 visitExpression(visitor, context) {
1396 return visitor.visitReadPropExpr(this, context);
1397 }
1398 set(value) {
1399 return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan);
1400 }
1401}
1402class ReadKeyExpr extends Expression {
1403 constructor(receiver, index, type, sourceSpan) {
1404 super(type, sourceSpan);
1405 this.receiver = receiver;
1406 this.index = index;
1407 }
1408 isEquivalent(e) {
1409 return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) &&
1410 this.index.isEquivalent(e.index);
1411 }
1412 isConstant() { return false; }
1413 visitExpression(visitor, context) {
1414 return visitor.visitReadKeyExpr(this, context);
1415 }
1416 set(value) {
1417 return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan);
1418 }
1419}
1420class LiteralArrayExpr extends Expression {
1421 constructor(entries, type, sourceSpan) {
1422 super(type, sourceSpan);
1423 this.entries = entries;
1424 }
1425 isConstant() { return this.entries.every(e => e.isConstant()); }
1426 isEquivalent(e) {
1427 return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
1428 }
1429 visitExpression(visitor, context) {
1430 return visitor.visitLiteralArrayExpr(this, context);
1431 }
1432}
1433class LiteralMapEntry {
1434 constructor(key, value, quoted) {
1435 this.key = key;
1436 this.value = value;
1437 this.quoted = quoted;
1438 }
1439 isEquivalent(e) {
1440 return this.key === e.key && this.value.isEquivalent(e.value);
1441 }
1442}
1443class LiteralMapExpr extends Expression {
1444 constructor(entries, type, sourceSpan) {
1445 super(type, sourceSpan);
1446 this.entries = entries;
1447 this.valueType = null;
1448 if (type) {
1449 this.valueType = type.valueType;
1450 }
1451 }
1452 isEquivalent(e) {
1453 return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
1454 }
1455 isConstant() { return this.entries.every(e => e.value.isConstant()); }
1456 visitExpression(visitor, context) {
1457 return visitor.visitLiteralMapExpr(this, context);
1458 }
1459}
1460class CommaExpr extends Expression {
1461 constructor(parts, sourceSpan) {
1462 super(parts[parts.length - 1].type, sourceSpan);
1463 this.parts = parts;
1464 }
1465 isEquivalent(e) {
1466 return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts);
1467 }
1468 isConstant() { return false; }
1469 visitExpression(visitor, context) {
1470 return visitor.visitCommaExpr(this, context);
1471 }
1472}
1473const THIS_EXPR = new ReadVarExpr(BuiltinVar.This, null, null);
1474const SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super, null, null);
1475const CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError, null, null);
1476const CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack, null, null);
1477const NULL_EXPR = new LiteralExpr(null, null, null);
1478const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
1479//// Statements
1480var StmtModifier;
1481(function (StmtModifier) {
1482 StmtModifier[StmtModifier["Final"] = 0] = "Final";
1483 StmtModifier[StmtModifier["Private"] = 1] = "Private";
1484 StmtModifier[StmtModifier["Exported"] = 2] = "Exported";
1485 StmtModifier[StmtModifier["Static"] = 3] = "Static";
1486})(StmtModifier || (StmtModifier = {}));
1487class Statement {
1488 constructor(modifiers, sourceSpan) {
1489 this.modifiers = modifiers || [];
1490 this.sourceSpan = sourceSpan || null;
1491 }
1492 hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; }
1493}
1494class DeclareVarStmt extends Statement {
1495 constructor(name, value, type, modifiers = null, sourceSpan) {
1496 super(modifiers, sourceSpan);
1497 this.name = name;
1498 this.value = value;
1499 this.type = type || (value && value.type) || null;
1500 }
1501 isEquivalent(stmt) {
1502 return stmt instanceof DeclareVarStmt && this.name === stmt.name &&
1503 (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value);
1504 }
1505 visitStatement(visitor, context) {
1506 return visitor.visitDeclareVarStmt(this, context);
1507 }
1508}
1509class DeclareFunctionStmt extends Statement {
1510 constructor(name, params, statements, type, modifiers = null, sourceSpan) {
1511 super(modifiers, sourceSpan);
1512 this.name = name;
1513 this.params = params;
1514 this.statements = statements;
1515 this.type = type || null;
1516 }
1517 isEquivalent(stmt) {
1518 return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) &&
1519 areAllEquivalent(this.statements, stmt.statements);
1520 }
1521 visitStatement(visitor, context) {
1522 return visitor.visitDeclareFunctionStmt(this, context);
1523 }
1524}
1525class ExpressionStatement extends Statement {
1526 constructor(expr, sourceSpan) {
1527 super(null, sourceSpan);
1528 this.expr = expr;
1529 }
1530 isEquivalent(stmt) {
1531 return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr);
1532 }
1533 visitStatement(visitor, context) {
1534 return visitor.visitExpressionStmt(this, context);
1535 }
1536}
1537class ReturnStatement extends Statement {
1538 constructor(value, sourceSpan) {
1539 super(null, sourceSpan);
1540 this.value = value;
1541 }
1542 isEquivalent(stmt) {
1543 return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value);
1544 }
1545 visitStatement(visitor, context) {
1546 return visitor.visitReturnStmt(this, context);
1547 }
1548}
1549class AbstractClassPart {
1550 constructor(type, modifiers) {
1551 this.modifiers = modifiers;
1552 if (!modifiers) {
1553 this.modifiers = [];
1554 }
1555 this.type = type || null;
1556 }
1557 hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; }
1558}
1559class ClassField extends AbstractClassPart {
1560 constructor(name, type, modifiers = null, initializer) {
1561 super(type, modifiers);
1562 this.name = name;
1563 this.initializer = initializer;
1564 }
1565 isEquivalent(f) { return this.name === f.name; }
1566}
1567class ClassMethod extends AbstractClassPart {
1568 constructor(name, params, body, type, modifiers = null) {
1569 super(type, modifiers);
1570 this.name = name;
1571 this.params = params;
1572 this.body = body;
1573 }
1574 isEquivalent(m) {
1575 return this.name === m.name && areAllEquivalent(this.body, m.body);
1576 }
1577}
1578class ClassGetter extends AbstractClassPart {
1579 constructor(name, body, type, modifiers = null) {
1580 super(type, modifiers);
1581 this.name = name;
1582 this.body = body;
1583 }
1584 isEquivalent(m) {
1585 return this.name === m.name && areAllEquivalent(this.body, m.body);
1586 }
1587}
1588class ClassStmt extends Statement {
1589 constructor(name, parent, fields, getters, constructorMethod, methods, modifiers = null, sourceSpan) {
1590 super(modifiers, sourceSpan);
1591 this.name = name;
1592 this.parent = parent;
1593 this.fields = fields;
1594 this.getters = getters;
1595 this.constructorMethod = constructorMethod;
1596 this.methods = methods;
1597 }
1598 isEquivalent(stmt) {
1599 return stmt instanceof ClassStmt && this.name === stmt.name &&
1600 nullSafeIsEquivalent(this.parent, stmt.parent) &&
1601 areAllEquivalent(this.fields, stmt.fields) &&
1602 areAllEquivalent(this.getters, stmt.getters) &&
1603 this.constructorMethod.isEquivalent(stmt.constructorMethod) &&
1604 areAllEquivalent(this.methods, stmt.methods);
1605 }
1606 visitStatement(visitor, context) {
1607 return visitor.visitDeclareClassStmt(this, context);
1608 }
1609}
1610class IfStmt extends Statement {
1611 constructor(condition, trueCase, falseCase = [], sourceSpan) {
1612 super(null, sourceSpan);
1613 this.condition = condition;
1614 this.trueCase = trueCase;
1615 this.falseCase = falseCase;
1616 }
1617 isEquivalent(stmt) {
1618 return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) &&
1619 areAllEquivalent(this.trueCase, stmt.trueCase) &&
1620 areAllEquivalent(this.falseCase, stmt.falseCase);
1621 }
1622 visitStatement(visitor, context) {
1623 return visitor.visitIfStmt(this, context);
1624 }
1625}
1626class CommentStmt extends Statement {
1627 constructor(comment, multiline = false, sourceSpan) {
1628 super(null, sourceSpan);
1629 this.comment = comment;
1630 this.multiline = multiline;
1631 }
1632 isEquivalent(stmt) { return stmt instanceof CommentStmt; }
1633 visitStatement(visitor, context) {
1634 return visitor.visitCommentStmt(this, context);
1635 }
1636}
1637class JSDocCommentStmt extends Statement {
1638 constructor(tags = [], sourceSpan) {
1639 super(null, sourceSpan);
1640 this.tags = tags;
1641 }
1642 isEquivalent(stmt) {
1643 return stmt instanceof JSDocCommentStmt && this.toString() === stmt.toString();
1644 }
1645 visitStatement(visitor, context) {
1646 return visitor.visitJSDocCommentStmt(this, context);
1647 }
1648 toString() { return serializeTags(this.tags); }
1649}
1650class TryCatchStmt extends Statement {
1651 constructor(bodyStmts, catchStmts, sourceSpan) {
1652 super(null, sourceSpan);
1653 this.bodyStmts = bodyStmts;
1654 this.catchStmts = catchStmts;
1655 }
1656 isEquivalent(stmt) {
1657 return stmt instanceof TryCatchStmt && areAllEquivalent(this.bodyStmts, stmt.bodyStmts) &&
1658 areAllEquivalent(this.catchStmts, stmt.catchStmts);
1659 }
1660 visitStatement(visitor, context) {
1661 return visitor.visitTryCatchStmt(this, context);
1662 }
1663}
1664class ThrowStmt extends Statement {
1665 constructor(error, sourceSpan) {
1666 super(null, sourceSpan);
1667 this.error = error;
1668 }
1669 isEquivalent(stmt) {
1670 return stmt instanceof TryCatchStmt && this.error.isEquivalent(stmt.error);
1671 }
1672 visitStatement(visitor, context) {
1673 return visitor.visitThrowStmt(this, context);
1674 }
1675}
1676class AstTransformer {
1677 transformExpr(expr, context) { return expr; }
1678 transformStmt(stmt, context) { return stmt; }
1679 visitReadVarExpr(ast, context) { return this.transformExpr(ast, context); }
1680 visitWrappedNodeExpr(ast, context) {
1681 return this.transformExpr(ast, context);
1682 }
1683 visitTypeofExpr(expr, context) {
1684 return this.transformExpr(new TypeofExpr(expr.expr.visitExpression(this, context), expr.type, expr.sourceSpan), context);
1685 }
1686 visitWriteVarExpr(expr, context) {
1687 return this.transformExpr(new WriteVarExpr(expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context);
1688 }
1689 visitWriteKeyExpr(expr, context) {
1690 return this.transformExpr(new WriteKeyExpr(expr.receiver.visitExpression(this, context), expr.index.visitExpression(this, context), expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context);
1691 }
1692 visitWritePropExpr(expr, context) {
1693 return this.transformExpr(new WritePropExpr(expr.receiver.visitExpression(this, context), expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context);
1694 }
1695 visitInvokeMethodExpr(ast, context) {
1696 const method = ast.builtin || ast.name;
1697 return this.transformExpr(new InvokeMethodExpr(ast.receiver.visitExpression(this, context), method, this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context);
1698 }
1699 visitInvokeFunctionExpr(ast, context) {
1700 return this.transformExpr(new InvokeFunctionExpr(ast.fn.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context);
1701 }
1702 visitInstantiateExpr(ast, context) {
1703 return this.transformExpr(new InstantiateExpr(ast.classExpr.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context);
1704 }
1705 visitLiteralExpr(ast, context) { return this.transformExpr(ast, context); }
1706 visitExternalExpr(ast, context) {
1707 return this.transformExpr(ast, context);
1708 }
1709 visitConditionalExpr(ast, context) {
1710 return this.transformExpr(new ConditionalExpr(ast.condition.visitExpression(this, context), ast.trueCase.visitExpression(this, context), ast.falseCase.visitExpression(this, context), ast.type, ast.sourceSpan), context);
1711 }
1712 visitNotExpr(ast, context) {
1713 return this.transformExpr(new NotExpr(ast.condition.visitExpression(this, context), ast.sourceSpan), context);
1714 }
1715 visitAssertNotNullExpr(ast, context) {
1716 return this.transformExpr(new AssertNotNull(ast.condition.visitExpression(this, context), ast.sourceSpan), context);
1717 }
1718 visitCastExpr(ast, context) {
1719 return this.transformExpr(new CastExpr(ast.value.visitExpression(this, context), ast.type, ast.sourceSpan), context);
1720 }
1721 visitFunctionExpr(ast, context) {
1722 return this.transformExpr(new FunctionExpr(ast.params, this.visitAllStatements(ast.statements, context), ast.type, ast.sourceSpan), context);
1723 }
1724 visitBinaryOperatorExpr(ast, context) {
1725 return this.transformExpr(new BinaryOperatorExpr(ast.operator, ast.lhs.visitExpression(this, context), ast.rhs.visitExpression(this, context), ast.type, ast.sourceSpan), context);
1726 }
1727 visitReadPropExpr(ast, context) {
1728 return this.transformExpr(new ReadPropExpr(ast.receiver.visitExpression(this, context), ast.name, ast.type, ast.sourceSpan), context);
1729 }
1730 visitReadKeyExpr(ast, context) {
1731 return this.transformExpr(new ReadKeyExpr(ast.receiver.visitExpression(this, context), ast.index.visitExpression(this, context), ast.type, ast.sourceSpan), context);
1732 }
1733 visitLiteralArrayExpr(ast, context) {
1734 return this.transformExpr(new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context), ast.type, ast.sourceSpan), context);
1735 }
1736 visitLiteralMapExpr(ast, context) {
1737 const entries = ast.entries.map((entry) => new LiteralMapEntry(entry.key, entry.value.visitExpression(this, context), entry.quoted));
1738 const mapType = new MapType(ast.valueType, null);
1739 return this.transformExpr(new LiteralMapExpr(entries, mapType, ast.sourceSpan), context);
1740 }
1741 visitCommaExpr(ast, context) {
1742 return this.transformExpr(new CommaExpr(this.visitAllExpressions(ast.parts, context), ast.sourceSpan), context);
1743 }
1744 visitAllExpressions(exprs, context) {
1745 return exprs.map(expr => expr.visitExpression(this, context));
1746 }
1747 visitDeclareVarStmt(stmt, context) {
1748 const value = stmt.value && stmt.value.visitExpression(this, context);
1749 return this.transformStmt(new DeclareVarStmt(stmt.name, value, stmt.type, stmt.modifiers, stmt.sourceSpan), context);
1750 }
1751 visitDeclareFunctionStmt(stmt, context) {
1752 return this.transformStmt(new DeclareFunctionStmt(stmt.name, stmt.params, this.visitAllStatements(stmt.statements, context), stmt.type, stmt.modifiers, stmt.sourceSpan), context);
1753 }
1754 visitExpressionStmt(stmt, context) {
1755 return this.transformStmt(new ExpressionStatement(stmt.expr.visitExpression(this, context), stmt.sourceSpan), context);
1756 }
1757 visitReturnStmt(stmt, context) {
1758 return this.transformStmt(new ReturnStatement(stmt.value.visitExpression(this, context), stmt.sourceSpan), context);
1759 }
1760 visitDeclareClassStmt(stmt, context) {
1761 const parent = stmt.parent.visitExpression(this, context);
1762 const getters = stmt.getters.map(getter => new ClassGetter(getter.name, this.visitAllStatements(getter.body, context), getter.type, getter.modifiers));
1763 const ctorMethod = stmt.constructorMethod &&
1764 new ClassMethod(stmt.constructorMethod.name, stmt.constructorMethod.params, this.visitAllStatements(stmt.constructorMethod.body, context), stmt.constructorMethod.type, stmt.constructorMethod.modifiers);
1765 const methods = stmt.methods.map(method => new ClassMethod(method.name, method.params, this.visitAllStatements(method.body, context), method.type, method.modifiers));
1766 return this.transformStmt(new ClassStmt(stmt.name, parent, stmt.fields, getters, ctorMethod, methods, stmt.modifiers, stmt.sourceSpan), context);
1767 }
1768 visitIfStmt(stmt, context) {
1769 return this.transformStmt(new IfStmt(stmt.condition.visitExpression(this, context), this.visitAllStatements(stmt.trueCase, context), this.visitAllStatements(stmt.falseCase, context), stmt.sourceSpan), context);
1770 }
1771 visitTryCatchStmt(stmt, context) {
1772 return this.transformStmt(new TryCatchStmt(this.visitAllStatements(stmt.bodyStmts, context), this.visitAllStatements(stmt.catchStmts, context), stmt.sourceSpan), context);
1773 }
1774 visitThrowStmt(stmt, context) {
1775 return this.transformStmt(new ThrowStmt(stmt.error.visitExpression(this, context), stmt.sourceSpan), context);
1776 }
1777 visitCommentStmt(stmt, context) {
1778 return this.transformStmt(stmt, context);
1779 }
1780 visitJSDocCommentStmt(stmt, context) {
1781 return this.transformStmt(stmt, context);
1782 }
1783 visitAllStatements(stmts, context) {
1784 return stmts.map(stmt => stmt.visitStatement(this, context));
1785 }
1786}
1787class RecursiveAstVisitor {
1788 visitType(ast, context) { return ast; }
1789 visitExpression(ast, context) {
1790 if (ast.type) {
1791 ast.type.visitType(this, context);
1792 }
1793 return ast;
1794 }
1795 visitBuiltinType(type, context) { return this.visitType(type, context); }
1796 visitExpressionType(type, context) {
1797 type.value.visitExpression(this, context);
1798 if (type.typeParams !== null) {
1799 type.typeParams.forEach(param => this.visitType(param, context));
1800 }
1801 return this.visitType(type, context);
1802 }
1803 visitArrayType(type, context) { return this.visitType(type, context); }
1804 visitMapType(type, context) { return this.visitType(type, context); }
1805 visitWrappedNodeExpr(ast, context) { return ast; }
1806 visitTypeofExpr(ast, context) { return this.visitExpression(ast, context); }
1807 visitReadVarExpr(ast, context) {
1808 return this.visitExpression(ast, context);
1809 }
1810 visitWriteVarExpr(ast, context) {
1811 ast.value.visitExpression(this, context);
1812 return this.visitExpression(ast, context);
1813 }
1814 visitWriteKeyExpr(ast, context) {
1815 ast.receiver.visitExpression(this, context);
1816 ast.index.visitExpression(this, context);
1817 ast.value.visitExpression(this, context);
1818 return this.visitExpression(ast, context);
1819 }
1820 visitWritePropExpr(ast, context) {
1821 ast.receiver.visitExpression(this, context);
1822 ast.value.visitExpression(this, context);
1823 return this.visitExpression(ast, context);
1824 }
1825 visitInvokeMethodExpr(ast, context) {
1826 ast.receiver.visitExpression(this, context);
1827 this.visitAllExpressions(ast.args, context);
1828 return this.visitExpression(ast, context);
1829 }
1830 visitInvokeFunctionExpr(ast, context) {
1831 ast.fn.visitExpression(this, context);
1832 this.visitAllExpressions(ast.args, context);
1833 return this.visitExpression(ast, context);
1834 }
1835 visitInstantiateExpr(ast, context) {
1836 ast.classExpr.visitExpression(this, context);
1837 this.visitAllExpressions(ast.args, context);
1838 return this.visitExpression(ast, context);
1839 }
1840 visitLiteralExpr(ast, context) {
1841 return this.visitExpression(ast, context);
1842 }
1843 visitExternalExpr(ast, context) {
1844 if (ast.typeParams) {
1845 ast.typeParams.forEach(type => type.visitType(this, context));
1846 }
1847 return this.visitExpression(ast, context);
1848 }
1849 visitConditionalExpr(ast, context) {
1850 ast.condition.visitExpression(this, context);
1851 ast.trueCase.visitExpression(this, context);
1852 ast.falseCase.visitExpression(this, context);
1853 return this.visitExpression(ast, context);
1854 }
1855 visitNotExpr(ast, context) {
1856 ast.condition.visitExpression(this, context);
1857 return this.visitExpression(ast, context);
1858 }
1859 visitAssertNotNullExpr(ast, context) {
1860 ast.condition.visitExpression(this, context);
1861 return this.visitExpression(ast, context);
1862 }
1863 visitCastExpr(ast, context) {
1864 ast.value.visitExpression(this, context);
1865 return this.visitExpression(ast, context);
1866 }
1867 visitFunctionExpr(ast, context) {
1868 this.visitAllStatements(ast.statements, context);
1869 return this.visitExpression(ast, context);
1870 }
1871 visitBinaryOperatorExpr(ast, context) {
1872 ast.lhs.visitExpression(this, context);
1873 ast.rhs.visitExpression(this, context);
1874 return this.visitExpression(ast, context);
1875 }
1876 visitReadPropExpr(ast, context) {
1877 ast.receiver.visitExpression(this, context);
1878 return this.visitExpression(ast, context);
1879 }
1880 visitReadKeyExpr(ast, context) {
1881 ast.receiver.visitExpression(this, context);
1882 ast.index.visitExpression(this, context);
1883 return this.visitExpression(ast, context);
1884 }
1885 visitLiteralArrayExpr(ast, context) {
1886 this.visitAllExpressions(ast.entries, context);
1887 return this.visitExpression(ast, context);
1888 }
1889 visitLiteralMapExpr(ast, context) {
1890 ast.entries.forEach((entry) => entry.value.visitExpression(this, context));
1891 return this.visitExpression(ast, context);
1892 }
1893 visitCommaExpr(ast, context) {
1894 this.visitAllExpressions(ast.parts, context);
1895 return this.visitExpression(ast, context);
1896 }
1897 visitAllExpressions(exprs, context) {
1898 exprs.forEach(expr => expr.visitExpression(this, context));
1899 }
1900 visitDeclareVarStmt(stmt, context) {
1901 if (stmt.value) {
1902 stmt.value.visitExpression(this, context);
1903 }
1904 if (stmt.type) {
1905 stmt.type.visitType(this, context);
1906 }
1907 return stmt;
1908 }
1909 visitDeclareFunctionStmt(stmt, context) {
1910 this.visitAllStatements(stmt.statements, context);
1911 if (stmt.type) {
1912 stmt.type.visitType(this, context);
1913 }
1914 return stmt;
1915 }
1916 visitExpressionStmt(stmt, context) {
1917 stmt.expr.visitExpression(this, context);
1918 return stmt;
1919 }
1920 visitReturnStmt(stmt, context) {
1921 stmt.value.visitExpression(this, context);
1922 return stmt;
1923 }
1924 visitDeclareClassStmt(stmt, context) {
1925 stmt.parent.visitExpression(this, context);
1926 stmt.getters.forEach(getter => this.visitAllStatements(getter.body, context));
1927 if (stmt.constructorMethod) {
1928 this.visitAllStatements(stmt.constructorMethod.body, context);
1929 }
1930 stmt.methods.forEach(method => this.visitAllStatements(method.body, context));
1931 return stmt;
1932 }
1933 visitIfStmt(stmt, context) {
1934 stmt.condition.visitExpression(this, context);
1935 this.visitAllStatements(stmt.trueCase, context);
1936 this.visitAllStatements(stmt.falseCase, context);
1937 return stmt;
1938 }
1939 visitTryCatchStmt(stmt, context) {
1940 this.visitAllStatements(stmt.bodyStmts, context);
1941 this.visitAllStatements(stmt.catchStmts, context);
1942 return stmt;
1943 }
1944 visitThrowStmt(stmt, context) {
1945 stmt.error.visitExpression(this, context);
1946 return stmt;
1947 }
1948 visitCommentStmt(stmt, context) { return stmt; }
1949 visitJSDocCommentStmt(stmt, context) { return stmt; }
1950 visitAllStatements(stmts, context) {
1951 stmts.forEach(stmt => stmt.visitStatement(this, context));
1952 }
1953}
1954function findReadVarNames(stmts) {
1955 const visitor = new _ReadVarVisitor();
1956 visitor.visitAllStatements(stmts, null);
1957 return visitor.varNames;
1958}
1959class _ReadVarVisitor extends RecursiveAstVisitor {
1960 constructor() {
1961 super(...arguments);
1962 this.varNames = new Set();
1963 }
1964 visitDeclareFunctionStmt(stmt, context) {
1965 // Don't descend into nested functions
1966 return stmt;
1967 }
1968 visitDeclareClassStmt(stmt, context) {
1969 // Don't descend into nested classes
1970 return stmt;
1971 }
1972 visitReadVarExpr(ast, context) {
1973 if (ast.name) {
1974 this.varNames.add(ast.name);
1975 }
1976 return null;
1977 }
1978}
1979function collectExternalReferences(stmts) {
1980 const visitor = new _FindExternalReferencesVisitor();
1981 visitor.visitAllStatements(stmts, null);
1982 return visitor.externalReferences;
1983}
1984class _FindExternalReferencesVisitor extends RecursiveAstVisitor {
1985 constructor() {
1986 super(...arguments);
1987 this.externalReferences = [];
1988 }
1989 visitExternalExpr(e, context) {
1990 this.externalReferences.push(e.value);
1991 return super.visitExternalExpr(e, context);
1992 }
1993}
1994function applySourceSpanToStatementIfNeeded(stmt, sourceSpan) {
1995 if (!sourceSpan) {
1996 return stmt;
1997 }
1998 const transformer = new _ApplySourceSpanTransformer(sourceSpan);
1999 return stmt.visitStatement(transformer, null);
2000}
2001function applySourceSpanToExpressionIfNeeded(expr, sourceSpan) {
2002 if (!sourceSpan) {
2003 return expr;
2004 }
2005 const transformer = new _ApplySourceSpanTransformer(sourceSpan);
2006 return expr.visitExpression(transformer, null);
2007}
2008class _ApplySourceSpanTransformer extends AstTransformer {
2009 constructor(sourceSpan) {
2010 super();
2011 this.sourceSpan = sourceSpan;
2012 }
2013 _clone(obj) {
2014 const clone = Object.create(obj.constructor.prototype);
2015 for (let prop of Object.keys(obj)) {
2016 clone[prop] = obj[prop];
2017 }
2018 return clone;
2019 }
2020 transformExpr(expr, context) {
2021 if (!expr.sourceSpan) {
2022 expr = this._clone(expr);
2023 expr.sourceSpan = this.sourceSpan;
2024 }
2025 return expr;
2026 }
2027 transformStmt(stmt, context) {
2028 if (!stmt.sourceSpan) {
2029 stmt = this._clone(stmt);
2030 stmt.sourceSpan = this.sourceSpan;
2031 }
2032 return stmt;
2033 }
2034}
2035function variable(name, type, sourceSpan) {
2036 return new ReadVarExpr(name, type, sourceSpan);
2037}
2038function importExpr(id, typeParams = null, sourceSpan) {
2039 return new ExternalExpr(id, null, typeParams, sourceSpan);
2040}
2041function importType(id, typeParams = null, typeModifiers = null) {
2042 return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
2043}
2044function expressionType(expr, typeModifiers = null, typeParams = null) {
2045 return new ExpressionType(expr, typeModifiers, typeParams);
2046}
2047function typeofExpr(expr) {
2048 return new TypeofExpr(expr);
2049}
2050function literalArr(values, type, sourceSpan) {
2051 return new LiteralArrayExpr(values, type, sourceSpan);
2052}
2053function literalMap(values, type = null) {
2054 return new LiteralMapExpr(values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null);
2055}
2056function not(expr, sourceSpan) {
2057 return new NotExpr(expr, sourceSpan);
2058}
2059function assertNotNull(expr, sourceSpan) {
2060 return new AssertNotNull(expr, sourceSpan);
2061}
2062function fn(params, body, type, sourceSpan, name) {
2063 return new FunctionExpr(params, body, type, sourceSpan, name);
2064}
2065function ifStmt(condition, thenClause, elseClause) {
2066 return new IfStmt(condition, thenClause, elseClause);
2067}
2068function literal(value, type, sourceSpan) {
2069 return new LiteralExpr(value, type, sourceSpan);
2070}
2071function isNull(exp) {
2072 return exp instanceof LiteralExpr && exp.value === null;
2073}
2074/*
2075 * Serializes a `Tag` into a string.
2076 * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`).
2077 */
2078function tagToString(tag) {
2079 let out = '';
2080 if (tag.tagName) {
2081 out += ` @${tag.tagName}`;
2082 }
2083 if (tag.text) {
2084 if (tag.text.match(/\/\*|\*\//)) {
2085 throw new Error('JSDoc text cannot contain "/*" and "*/"');
2086 }
2087 out += ' ' + tag.text.replace(/@/g, '\\@');
2088 }
2089 return out;
2090}
2091function serializeTags(tags) {
2092 if (tags.length === 0)
2093 return '';
2094 let out = '*\n';
2095 for (const tag of tags) {
2096 out += ' *';
2097 // If the tagToString is multi-line, insert " * " prefixes on subsequent lines.
2098 out += tagToString(tag).replace(/\n/g, '\n * ');
2099 out += '\n';
2100 }
2101 out += ' ';
2102 return out;
2103}
2104
2105/**
2106 * @license
2107 * Copyright Google Inc. All Rights Reserved.
2108 *
2109 * Use of this source code is governed by an MIT-style license that can be
2110 * found in the LICENSE file at https://angular.io/license
2111 */
2112const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
2113function dashCaseToCamelCase(input) {
2114 return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase());
2115}
2116function splitAtColon(input, defaultValues) {
2117 return _splitAt(input, ':', defaultValues);
2118}
2119function splitAtPeriod(input, defaultValues) {
2120 return _splitAt(input, '.', defaultValues);
2121}
2122function _splitAt(input, character, defaultValues) {
2123 const characterIndex = input.indexOf(character);
2124 if (characterIndex == -1)
2125 return defaultValues;
2126 return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()];
2127}
2128function visitValue(value, visitor, context) {
2129 if (Array.isArray(value)) {
2130 return visitor.visitArray(value, context);
2131 }
2132 if (isStrictStringMap(value)) {
2133 return visitor.visitStringMap(value, context);
2134 }
2135 if (value == null || typeof value == 'string' || typeof value == 'number' ||
2136 typeof value == 'boolean') {
2137 return visitor.visitPrimitive(value, context);
2138 }
2139 return visitor.visitOther(value, context);
2140}
2141function isDefined(val) {
2142 return val !== null && val !== undefined;
2143}
2144function noUndefined(val) {
2145 return val === undefined ? null : val;
2146}
2147class ValueTransformer {
2148 visitArray(arr, context) {
2149 return arr.map(value => visitValue(value, this, context));
2150 }
2151 visitStringMap(map, context) {
2152 const result = {};
2153 Object.keys(map).forEach(key => { result[key] = visitValue(map[key], this, context); });
2154 return result;
2155 }
2156 visitPrimitive(value, context) { return value; }
2157 visitOther(value, context) { return value; }
2158}
2159const SyncAsync = {
2160 assertSync: (value) => {
2161 if (isPromise(value)) {
2162 throw new Error(`Illegal state: value cannot be a promise`);
2163 }
2164 return value;
2165 },
2166 then: (value, cb) => { return isPromise(value) ? value.then(cb) : cb(value); },
2167 all: (syncAsyncValues) => {
2168 return syncAsyncValues.some(isPromise) ? Promise.all(syncAsyncValues) : syncAsyncValues;
2169 }
2170};
2171function error(msg) {
2172 throw new Error(`Internal Error: ${msg}`);
2173}
2174function syntaxError(msg, parseErrors) {
2175 const error = Error(msg);
2176 error[ERROR_SYNTAX_ERROR] = true;
2177 if (parseErrors)
2178 error[ERROR_PARSE_ERRORS] = parseErrors;
2179 return error;
2180}
2181const ERROR_SYNTAX_ERROR = 'ngSyntaxError';
2182const ERROR_PARSE_ERRORS = 'ngParseErrors';
2183function isSyntaxError(error) {
2184 return error[ERROR_SYNTAX_ERROR];
2185}
2186function getParseErrors(error) {
2187 return error[ERROR_PARSE_ERRORS] || [];
2188}
2189// Escape characters that have a special meaning in Regular Expressions
2190function escapeRegExp(s) {
2191 return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
2192}
2193const STRING_MAP_PROTO = Object.getPrototypeOf({});
2194function isStrictStringMap(obj) {
2195 return typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === STRING_MAP_PROTO;
2196}
2197function utf8Encode(str) {
2198 let encoded = '';
2199 for (let index = 0; index < str.length; index++) {
2200 let codePoint = str.charCodeAt(index);
2201 // decode surrogate
2202 // see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
2203 if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > (index + 1)) {
2204 const low = str.charCodeAt(index + 1);
2205 if (low >= 0xdc00 && low <= 0xdfff) {
2206 index++;
2207 codePoint = ((codePoint - 0xd800) << 10) + low - 0xdc00 + 0x10000;
2208 }
2209 }
2210 if (codePoint <= 0x7f) {
2211 encoded += String.fromCharCode(codePoint);
2212 }
2213 else if (codePoint <= 0x7ff) {
2214 encoded += String.fromCharCode(((codePoint >> 6) & 0x1F) | 0xc0, (codePoint & 0x3f) | 0x80);
2215 }
2216 else if (codePoint <= 0xffff) {
2217 encoded += String.fromCharCode((codePoint >> 12) | 0xe0, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80);
2218 }
2219 else if (codePoint <= 0x1fffff) {
2220 encoded += String.fromCharCode(((codePoint >> 18) & 0x07) | 0xf0, ((codePoint >> 12) & 0x3f) | 0x80, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80);
2221 }
2222 }
2223 return encoded;
2224}
2225function stringify(token) {
2226 if (typeof token === 'string') {
2227 return token;
2228 }
2229 if (token instanceof Array) {
2230 return '[' + token.map(stringify).join(', ') + ']';
2231 }
2232 if (token == null) {
2233 return '' + token;
2234 }
2235 if (token.overriddenName) {
2236 return `${token.overriddenName}`;
2237 }
2238 if (token.name) {
2239 return `${token.name}`;
2240 }
2241 if (!token.toString) {
2242 return 'object';
2243 }
2244 // WARNING: do not try to `JSON.stringify(token)` here
2245 // see https://github.com/angular/angular/issues/23440
2246 const res = token.toString();
2247 if (res == null) {
2248 return '' + res;
2249 }
2250 const newLineIndex = res.indexOf('\n');
2251 return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
2252}
2253/**
2254 * Lazily retrieves the reference value from a forwardRef.
2255 */
2256function resolveForwardRef(type) {
2257 if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__')) {
2258 return type();
2259 }
2260 else {
2261 return type;
2262 }
2263}
2264/**
2265 * Determine if the argument is shaped like a Promise
2266 */
2267function isPromise(obj) {
2268 // allow any Promise/A+ compliant thenable.
2269 // It's up to the caller to ensure that obj.then conforms to the spec
2270 return !!obj && typeof obj.then === 'function';
2271}
2272class Version {
2273 constructor(full) {
2274 this.full = full;
2275 const splits = full.split('.');
2276 this.major = splits[0];
2277 this.minor = splits[1];
2278 this.patch = splits.slice(2).join('.');
2279 }
2280}
2281const __window = typeof window !== 'undefined' && window;
2282const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
2283 self instanceof WorkerGlobalScope && self;
2284const __global = typeof global !== 'undefined' && global;
2285// Check __global first, because in Node tests both __global and __window may be defined and _global
2286// should be __global in that case.
2287const _global = __global || __window || __self;
2288
2289/**
2290 * @license
2291 * Copyright Google Inc. All Rights Reserved.
2292 *
2293 * Use of this source code is governed by an MIT-style license that can be
2294 * found in the LICENSE file at https://angular.io/license
2295 */
2296const CONSTANT_PREFIX = '_c';
2297/**
2298 * Context to use when producing a key.
2299 *
2300 * This ensures we see the constant not the reference variable when producing
2301 * a key.
2302 */
2303const KEY_CONTEXT = {};
2304/**
2305 * A node that is a place-holder that allows the node to be replaced when the actual
2306 * node is known.
2307 *
2308 * This allows the constant pool to change an expression from a direct reference to
2309 * a constant to a shared constant. It returns a fix-up node that is later allowed to
2310 * change the referenced expression.
2311 */
2312class FixupExpression extends Expression {
2313 constructor(resolved) {
2314 super(resolved.type);
2315 this.resolved = resolved;
2316 this.original = resolved;
2317 }
2318 visitExpression(visitor, context) {
2319 if (context === KEY_CONTEXT) {
2320 // When producing a key we want to traverse the constant not the
2321 // variable used to refer to it.
2322 return this.original.visitExpression(visitor, context);
2323 }
2324 else {
2325 return this.resolved.visitExpression(visitor, context);
2326 }
2327 }
2328 isEquivalent(e) {
2329 return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
2330 }
2331 isConstant() { return true; }
2332 fixup(expression) {
2333 this.resolved = expression;
2334 this.shared = true;
2335 }
2336}
2337/**
2338 * A constant pool allows a code emitter to share constant in an output context.
2339 *
2340 * The constant pool also supports sharing access to ivy definitions references.
2341 */
2342class ConstantPool {
2343 constructor() {
2344 this.statements = [];
2345 this.literals = new Map();
2346 this.literalFactories = new Map();
2347 this.injectorDefinitions = new Map();
2348 this.directiveDefinitions = new Map();
2349 this.componentDefinitions = new Map();
2350 this.pipeDefinitions = new Map();
2351 this.nextNameIndex = 0;
2352 }
2353 getConstLiteral(literal, forceShared) {
2354 if (literal instanceof LiteralExpr || literal instanceof FixupExpression) {
2355 // Do no put simple literals into the constant pool or try to produce a constant for a
2356 // reference to a constant.
2357 return literal;
2358 }
2359 const key = this.keyOf(literal);
2360 let fixup = this.literals.get(key);
2361 let newValue = false;
2362 if (!fixup) {
2363 fixup = new FixupExpression(literal);
2364 this.literals.set(key, fixup);
2365 newValue = true;
2366 }
2367 if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
2368 // Replace the expression with a variable
2369 const name = this.freshName();
2370 this.statements.push(variable(name).set(literal).toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]));
2371 fixup.fixup(variable(name));
2372 }
2373 return fixup;
2374 }
2375 getDefinition(type, kind, ctx, forceShared = false) {
2376 const definitions = this.definitionsOf(kind);
2377 let fixup = definitions.get(type);
2378 let newValue = false;
2379 if (!fixup) {
2380 const property = this.propertyNameOf(kind);
2381 fixup = new FixupExpression(ctx.importExpr(type).prop(property));
2382 definitions.set(type, fixup);
2383 newValue = true;
2384 }
2385 if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
2386 const name = this.freshName();
2387 this.statements.push(variable(name).set(fixup.resolved).toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]));
2388 fixup.fixup(variable(name));
2389 }
2390 return fixup;
2391 }
2392 getLiteralFactory(literal$1) {
2393 // Create a pure function that builds an array of a mix of constant and variable expressions
2394 if (literal$1 instanceof LiteralArrayExpr) {
2395 const argumentsForKey = literal$1.entries.map(e => e.isConstant() ? e : literal(null));
2396 const key = this.keyOf(literalArr(argumentsForKey));
2397 return this._getLiteralFactory(key, literal$1.entries, entries => literalArr(entries));
2398 }
2399 else {
2400 const expressionForKey = literalMap(literal$1.entries.map(e => ({
2401 key: e.key,
2402 value: e.value.isConstant() ? e.value : literal(null),
2403 quoted: e.quoted
2404 })));
2405 const key = this.keyOf(expressionForKey);
2406 return this._getLiteralFactory(key, literal$1.entries.map(e => e.value), entries => literalMap(entries.map((value, index) => ({
2407 key: literal$1.entries[index].key,
2408 value,
2409 quoted: literal$1.entries[index].quoted
2410 }))));
2411 }
2412 }
2413 _getLiteralFactory(key, values, resultMap) {
2414 let literalFactory = this.literalFactories.get(key);
2415 const literalFactoryArguments = values.filter((e => !e.isConstant()));
2416 if (!literalFactory) {
2417 const resultExpressions = values.map((e, index) => e.isConstant() ? this.getConstLiteral(e, true) : variable(`a${index}`));
2418 const parameters = resultExpressions.filter(isVariable).map(e => new FnParam(e.name, DYNAMIC_TYPE));
2419 const pureFunctionDeclaration = fn(parameters, [new ReturnStatement(resultMap(resultExpressions))], INFERRED_TYPE);
2420 const name = this.freshName();
2421 this.statements.push(variable(name).set(pureFunctionDeclaration).toDeclStmt(INFERRED_TYPE, [
2422 StmtModifier.Final
2423 ]));
2424 literalFactory = variable(name);
2425 this.literalFactories.set(key, literalFactory);
2426 }
2427 return { literalFactory, literalFactoryArguments };
2428 }
2429 /**
2430 * Produce a unique name.
2431 *
2432 * The name might be unique among different prefixes if any of the prefixes end in
2433 * a digit so the prefix should be a constant string (not based on user input) and
2434 * must not end in a digit.
2435 */
2436 uniqueName(prefix) { return `${prefix}${this.nextNameIndex++}`; }
2437 definitionsOf(kind) {
2438 switch (kind) {
2439 case 2 /* Component */:
2440 return this.componentDefinitions;
2441 case 1 /* Directive */:
2442 return this.directiveDefinitions;
2443 case 0 /* Injector */:
2444 return this.injectorDefinitions;
2445 case 3 /* Pipe */:
2446 return this.pipeDefinitions;
2447 }
2448 error(`Unknown definition kind ${kind}`);
2449 return this.componentDefinitions;
2450 }
2451 propertyNameOf(kind) {
2452 switch (kind) {
2453 case 2 /* Component */:
2454 return 'ngComponentDef';
2455 case 1 /* Directive */:
2456 return 'ngDirectiveDef';
2457 case 0 /* Injector */:
2458 return 'ngInjectorDef';
2459 case 3 /* Pipe */:
2460 return 'ngPipeDef';
2461 }
2462 error(`Unknown definition kind ${kind}`);
2463 return '<unknown>';
2464 }
2465 freshName() { return this.uniqueName(CONSTANT_PREFIX); }
2466 keyOf(expression) {
2467 return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT);
2468 }
2469}
2470/**
2471 * Visitor used to determine if 2 expressions are equivalent and can be shared in the
2472 * `ConstantPool`.
2473 *
2474 * When the id (string) generated by the visitor is equal, expressions are considered equivalent.
2475 */
2476class KeyVisitor {
2477 constructor() {
2478 this.visitWrappedNodeExpr = invalid;
2479 this.visitWriteVarExpr = invalid;
2480 this.visitWriteKeyExpr = invalid;
2481 this.visitWritePropExpr = invalid;
2482 this.visitInvokeMethodExpr = invalid;
2483 this.visitInvokeFunctionExpr = invalid;
2484 this.visitInstantiateExpr = invalid;
2485 this.visitConditionalExpr = invalid;
2486 this.visitNotExpr = invalid;
2487 this.visitAssertNotNullExpr = invalid;
2488 this.visitCastExpr = invalid;
2489 this.visitFunctionExpr = invalid;
2490 this.visitBinaryOperatorExpr = invalid;
2491 this.visitReadPropExpr = invalid;
2492 this.visitReadKeyExpr = invalid;
2493 this.visitCommaExpr = invalid;
2494 }
2495 visitLiteralExpr(ast) {
2496 return `${typeof ast.value === 'string' ? '"' + ast.value + '"' : ast.value}`;
2497 }
2498 visitLiteralArrayExpr(ast, context) {
2499 return `[${ast.entries.map(entry => entry.visitExpression(this, context)).join(',')}]`;
2500 }
2501 visitLiteralMapExpr(ast, context) {
2502 const mapKey = (entry) => {
2503 const quote = entry.quoted ? '"' : '';
2504 return `${quote}${entry.key}${quote}`;
2505 };
2506 const mapEntry = (entry) => `${mapKey(entry)}:${entry.value.visitExpression(this, context)}`;
2507 return `{${ast.entries.map(mapEntry).join(',')}`;
2508 }
2509 visitExternalExpr(ast) {
2510 return ast.value.moduleName ? `EX:${ast.value.moduleName}:${ast.value.name}` :
2511 `EX:${ast.value.runtime.name}`;
2512 }
2513 visitReadVarExpr(node) { return `VAR:${node.name}`; }
2514 visitTypeofExpr(node, context) {
2515 return `TYPEOF:${node.expr.visitExpression(this, context)}`;
2516 }
2517}
2518function invalid(arg) {
2519 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
2520}
2521function isVariable(e) {
2522 return e instanceof ReadVarExpr;
2523}
2524
2525/**
2526 * @license
2527 * Copyright Google Inc. All Rights Reserved.
2528 *
2529 * Use of this source code is governed by an MIT-style license that can be
2530 * found in the LICENSE file at https://angular.io/license
2531 */
2532const CORE = '@angular/core';
2533class Identifiers {
2534}
2535Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS = {
2536 name: 'ANALYZE_FOR_ENTRY_COMPONENTS',
2537 moduleName: CORE,
2538};
2539Identifiers.ElementRef = { name: 'ElementRef', moduleName: CORE };
2540Identifiers.NgModuleRef = { name: 'NgModuleRef', moduleName: CORE };
2541Identifiers.ViewContainerRef = { name: 'ViewContainerRef', moduleName: CORE };
2542Identifiers.ChangeDetectorRef = {
2543 name: 'ChangeDetectorRef',
2544 moduleName: CORE,
2545};
2546Identifiers.QueryList = { name: 'QueryList', moduleName: CORE };
2547Identifiers.TemplateRef = { name: 'TemplateRef', moduleName: CORE };
2548Identifiers.Renderer2 = { name: 'Renderer2', moduleName: CORE };
2549Identifiers.CodegenComponentFactoryResolver = {
2550 name: 'ɵCodegenComponentFactoryResolver',
2551 moduleName: CORE,
2552};
2553Identifiers.ComponentFactoryResolver = {
2554 name: 'ComponentFactoryResolver',
2555 moduleName: CORE,
2556};
2557Identifiers.ComponentFactory = { name: 'ComponentFactory', moduleName: CORE };
2558Identifiers.ComponentRef = { name: 'ComponentRef', moduleName: CORE };
2559Identifiers.NgModuleFactory = { name: 'NgModuleFactory', moduleName: CORE };
2560Identifiers.createModuleFactory = {
2561 name: 'ɵcmf',
2562 moduleName: CORE,
2563};
2564Identifiers.moduleDef = {
2565 name: 'ɵmod',
2566 moduleName: CORE,
2567};
2568Identifiers.moduleProviderDef = {
2569 name: 'ɵmpd',
2570 moduleName: CORE,
2571};
2572Identifiers.RegisterModuleFactoryFn = {
2573 name: 'ɵregisterModuleFactory',
2574 moduleName: CORE,
2575};
2576Identifiers.inject = { name: 'ɵɵinject', moduleName: CORE };
2577Identifiers.INJECTOR = { name: 'INJECTOR', moduleName: CORE };
2578Identifiers.Injector = { name: 'Injector', moduleName: CORE };
2579Identifiers.ɵɵdefineInjectable = { name: 'ɵɵdefineInjectable', moduleName: CORE };
2580Identifiers.InjectableDef = { name: 'ɵɵInjectableDef', moduleName: CORE };
2581Identifiers.ViewEncapsulation = {
2582 name: 'ViewEncapsulation',
2583 moduleName: CORE,
2584};
2585Identifiers.ChangeDetectionStrategy = {
2586 name: 'ChangeDetectionStrategy',
2587 moduleName: CORE,
2588};
2589Identifiers.SecurityContext = {
2590 name: 'SecurityContext',
2591 moduleName: CORE,
2592};
2593Identifiers.LOCALE_ID = { name: 'LOCALE_ID', moduleName: CORE };
2594Identifiers.TRANSLATIONS_FORMAT = {
2595 name: 'TRANSLATIONS_FORMAT',
2596 moduleName: CORE,
2597};
2598Identifiers.inlineInterpolate = {
2599 name: 'ɵinlineInterpolate',
2600 moduleName: CORE,
2601};
2602Identifiers.interpolate = { name: 'ɵinterpolate', moduleName: CORE };
2603Identifiers.EMPTY_ARRAY = { name: 'ɵEMPTY_ARRAY', moduleName: CORE };
2604Identifiers.EMPTY_MAP = { name: 'ɵEMPTY_MAP', moduleName: CORE };
2605Identifiers.Renderer = { name: 'Renderer', moduleName: CORE };
2606Identifiers.viewDef = { name: 'ɵvid', moduleName: CORE };
2607Identifiers.elementDef = { name: 'ɵeld', moduleName: CORE };
2608Identifiers.anchorDef = { name: 'ɵand', moduleName: CORE };
2609Identifiers.textDef = { name: 'ɵted', moduleName: CORE };
2610Identifiers.directiveDef = { name: 'ɵdid', moduleName: CORE };
2611Identifiers.providerDef = { name: 'ɵprd', moduleName: CORE };
2612Identifiers.queryDef = { name: 'ɵqud', moduleName: CORE };
2613Identifiers.pureArrayDef = { name: 'ɵpad', moduleName: CORE };
2614Identifiers.pureObjectDef = { name: 'ɵpod', moduleName: CORE };
2615Identifiers.purePipeDef = { name: 'ɵppd', moduleName: CORE };
2616Identifiers.pipeDef = { name: 'ɵpid', moduleName: CORE };
2617Identifiers.nodeValue = { name: 'ɵnov', moduleName: CORE };
2618Identifiers.ngContentDef = { name: 'ɵncd', moduleName: CORE };
2619Identifiers.unwrapValue = { name: 'ɵunv', moduleName: CORE };
2620Identifiers.createRendererType2 = { name: 'ɵcrt', moduleName: CORE };
2621// type only
2622Identifiers.RendererType2 = {
2623 name: 'RendererType2',
2624 moduleName: CORE,
2625};
2626// type only
2627Identifiers.ViewDefinition = {
2628 name: 'ɵViewDefinition',
2629 moduleName: CORE,
2630};
2631Identifiers.createComponentFactory = { name: 'ɵccf', moduleName: CORE };
2632Identifiers.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE };
2633function createTokenForReference(reference) {
2634 return { identifier: { reference: reference } };
2635}
2636function createTokenForExternalReference(reflector, reference) {
2637 return createTokenForReference(reflector.resolveExternalReference(reference));
2638}
2639
2640/**
2641 * @license
2642 * Copyright Google Inc. All Rights Reserved.
2643 *
2644 * Use of this source code is governed by an MIT-style license that can be
2645 * found in the LICENSE file at https://angular.io/license
2646 */
2647/**
2648 * A token representing the a reference to a static type.
2649 *
2650 * This token is unique for a filePath and name and can be used as a hash table key.
2651 */
2652class StaticSymbol {
2653 constructor(filePath, name, members) {
2654 this.filePath = filePath;
2655 this.name = name;
2656 this.members = members;
2657 }
2658 assertNoMembers() {
2659 if (this.members.length) {
2660 throw new Error(`Illegal state: symbol without members expected, but got ${JSON.stringify(this)}.`);
2661 }
2662 }
2663}
2664/**
2665 * A cache of static symbol used by the StaticReflector to return the same symbol for the
2666 * same symbol values.
2667 */
2668class StaticSymbolCache {
2669 constructor() {
2670 this.cache = new Map();
2671 }
2672 get(declarationFile, name, members) {
2673 members = members || [];
2674 const memberSuffix = members.length ? `.${members.join('.')}` : '';
2675 const key = `"${declarationFile}".${name}${memberSuffix}`;
2676 let result = this.cache.get(key);
2677 if (!result) {
2678 result = new StaticSymbol(declarationFile, name, members);
2679 this.cache.set(key, result);
2680 }
2681 return result;
2682 }
2683}
2684
2685/**
2686 * @license
2687 * Copyright Google Inc. All Rights Reserved.
2688 *
2689 * Use of this source code is governed by an MIT-style license that can be
2690 * found in the LICENSE file at https://angular.io/license
2691 */
2692// group 0: "[prop] or (event) or @trigger"
2693// group 1: "prop" from "[prop]"
2694// group 2: "event" from "(event)"
2695// group 3: "@trigger" from "@trigger"
2696const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/;
2697function sanitizeIdentifier(name) {
2698 return name.replace(/\W/g, '_');
2699}
2700let _anonymousTypeIndex = 0;
2701function identifierName(compileIdentifier) {
2702 if (!compileIdentifier || !compileIdentifier.reference) {
2703 return null;
2704 }
2705 const ref = compileIdentifier.reference;
2706 if (ref instanceof StaticSymbol) {
2707 return ref.name;
2708 }
2709 if (ref['__anonymousType']) {
2710 return ref['__anonymousType'];
2711 }
2712 let identifier = stringify(ref);
2713 if (identifier.indexOf('(') >= 0) {
2714 // case: anonymous functions!
2715 identifier = `anonymous_${_anonymousTypeIndex++}`;
2716 ref['__anonymousType'] = identifier;
2717 }
2718 else {
2719 identifier = sanitizeIdentifier(identifier);
2720 }
2721 return identifier;
2722}
2723function identifierModuleUrl(compileIdentifier) {
2724 const ref = compileIdentifier.reference;
2725 if (ref instanceof StaticSymbol) {
2726 return ref.filePath;
2727 }
2728 // Runtime type
2729 return `./${stringify(ref)}`;
2730}
2731function viewClassName(compType, embeddedTemplateIndex) {
2732 return `View_${identifierName({ reference: compType })}_${embeddedTemplateIndex}`;
2733}
2734function rendererTypeName(compType) {
2735 return `RenderType_${identifierName({ reference: compType })}`;
2736}
2737function hostViewClassName(compType) {
2738 return `HostView_${identifierName({ reference: compType })}`;
2739}
2740function componentFactoryName(compType) {
2741 return `${identifierName({ reference: compType })}NgFactory`;
2742}
2743var CompileSummaryKind;
2744(function (CompileSummaryKind) {
2745 CompileSummaryKind[CompileSummaryKind["Pipe"] = 0] = "Pipe";
2746 CompileSummaryKind[CompileSummaryKind["Directive"] = 1] = "Directive";
2747 CompileSummaryKind[CompileSummaryKind["NgModule"] = 2] = "NgModule";
2748 CompileSummaryKind[CompileSummaryKind["Injectable"] = 3] = "Injectable";
2749})(CompileSummaryKind || (CompileSummaryKind = {}));
2750function tokenName(token) {
2751 return token.value != null ? sanitizeIdentifier(token.value) : identifierName(token.identifier);
2752}
2753function tokenReference(token) {
2754 if (token.identifier != null) {
2755 return token.identifier.reference;
2756 }
2757 else {
2758 return token.value;
2759 }
2760}
2761/**
2762 * Metadata about a stylesheet
2763 */
2764class CompileStylesheetMetadata {
2765 constructor({ moduleUrl, styles, styleUrls } = {}) {
2766 this.moduleUrl = moduleUrl || null;
2767 this.styles = _normalizeArray(styles);
2768 this.styleUrls = _normalizeArray(styleUrls);
2769 }
2770}
2771/**
2772 * Metadata regarding compilation of a template.
2773 */
2774class CompileTemplateMetadata {
2775 constructor({ encapsulation, template, templateUrl, htmlAst, styles, styleUrls, externalStylesheets, animations, ngContentSelectors, interpolation, isInline, preserveWhitespaces }) {
2776 this.encapsulation = encapsulation;
2777 this.template = template;
2778 this.templateUrl = templateUrl;
2779 this.htmlAst = htmlAst;
2780 this.styles = _normalizeArray(styles);
2781 this.styleUrls = _normalizeArray(styleUrls);
2782 this.externalStylesheets = _normalizeArray(externalStylesheets);
2783 this.animations = animations ? flatten(animations) : [];
2784 this.ngContentSelectors = ngContentSelectors || [];
2785 if (interpolation && interpolation.length != 2) {
2786 throw new Error(`'interpolation' should have a start and an end symbol.`);
2787 }
2788 this.interpolation = interpolation;
2789 this.isInline = isInline;
2790 this.preserveWhitespaces = preserveWhitespaces;
2791 }
2792 toSummary() {
2793 return {
2794 ngContentSelectors: this.ngContentSelectors,
2795 encapsulation: this.encapsulation,
2796 styles: this.styles,
2797 animations: this.animations
2798 };
2799 }
2800}
2801/**
2802 * Metadata regarding compilation of a directive.
2803 */
2804class CompileDirectiveMetadata {
2805 static create({ isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host, providers, viewProviders, queries, guards, viewQueries, entryComponents, template, componentViewType, rendererType, componentFactory }) {
2806 const hostListeners = {};
2807 const hostProperties = {};
2808 const hostAttributes = {};
2809 if (host != null) {
2810 Object.keys(host).forEach(key => {
2811 const value = host[key];
2812 const matches = key.match(HOST_REG_EXP);
2813 if (matches === null) {
2814 hostAttributes[key] = value;
2815 }
2816 else if (matches[1] != null) {
2817 hostProperties[matches[1]] = value;
2818 }
2819 else if (matches[2] != null) {
2820 hostListeners[matches[2]] = value;
2821 }
2822 });
2823 }
2824 const inputsMap = {};
2825 if (inputs != null) {
2826 inputs.forEach((bindConfig) => {
2827 // canonical syntax: `dirProp: elProp`
2828 // if there is no `:`, use dirProp = elProp
2829 const parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
2830 inputsMap[parts[0]] = parts[1];
2831 });
2832 }
2833 const outputsMap = {};
2834 if (outputs != null) {
2835 outputs.forEach((bindConfig) => {
2836 // canonical syntax: `dirProp: elProp`
2837 // if there is no `:`, use dirProp = elProp
2838 const parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
2839 outputsMap[parts[0]] = parts[1];
2840 });
2841 }
2842 return new CompileDirectiveMetadata({
2843 isHost,
2844 type,
2845 isComponent: !!isComponent, selector, exportAs, changeDetection,
2846 inputs: inputsMap,
2847 outputs: outputsMap,
2848 hostListeners,
2849 hostProperties,
2850 hostAttributes,
2851 providers,
2852 viewProviders,
2853 queries,
2854 guards,
2855 viewQueries,
2856 entryComponents,
2857 template,
2858 componentViewType,
2859 rendererType,
2860 componentFactory,
2861 });
2862 }
2863 constructor({ isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, hostListeners, hostProperties, hostAttributes, providers, viewProviders, queries, guards, viewQueries, entryComponents, template, componentViewType, rendererType, componentFactory }) {
2864 this.isHost = !!isHost;
2865 this.type = type;
2866 this.isComponent = isComponent;
2867 this.selector = selector;
2868 this.exportAs = exportAs;
2869 this.changeDetection = changeDetection;
2870 this.inputs = inputs;
2871 this.outputs = outputs;
2872 this.hostListeners = hostListeners;
2873 this.hostProperties = hostProperties;
2874 this.hostAttributes = hostAttributes;
2875 this.providers = _normalizeArray(providers);
2876 this.viewProviders = _normalizeArray(viewProviders);
2877 this.queries = _normalizeArray(queries);
2878 this.guards = guards;
2879 this.viewQueries = _normalizeArray(viewQueries);
2880 this.entryComponents = _normalizeArray(entryComponents);
2881 this.template = template;
2882 this.componentViewType = componentViewType;
2883 this.rendererType = rendererType;
2884 this.componentFactory = componentFactory;
2885 }
2886 toSummary() {
2887 return {
2888 summaryKind: CompileSummaryKind.Directive,
2889 type: this.type,
2890 isComponent: this.isComponent,
2891 selector: this.selector,
2892 exportAs: this.exportAs,
2893 inputs: this.inputs,
2894 outputs: this.outputs,
2895 hostListeners: this.hostListeners,
2896 hostProperties: this.hostProperties,
2897 hostAttributes: this.hostAttributes,
2898 providers: this.providers,
2899 viewProviders: this.viewProviders,
2900 queries: this.queries,
2901 guards: this.guards,
2902 viewQueries: this.viewQueries,
2903 entryComponents: this.entryComponents,
2904 changeDetection: this.changeDetection,
2905 template: this.template && this.template.toSummary(),
2906 componentViewType: this.componentViewType,
2907 rendererType: this.rendererType,
2908 componentFactory: this.componentFactory
2909 };
2910 }
2911}
2912class CompilePipeMetadata {
2913 constructor({ type, name, pure }) {
2914 this.type = type;
2915 this.name = name;
2916 this.pure = !!pure;
2917 }
2918 toSummary() {
2919 return {
2920 summaryKind: CompileSummaryKind.Pipe,
2921 type: this.type,
2922 name: this.name,
2923 pure: this.pure
2924 };
2925 }
2926}
2927class CompileShallowModuleMetadata {
2928}
2929/**
2930 * Metadata regarding compilation of a module.
2931 */
2932class CompileNgModuleMetadata {
2933 constructor({ type, providers, declaredDirectives, exportedDirectives, declaredPipes, exportedPipes, entryComponents, bootstrapComponents, importedModules, exportedModules, schemas, transitiveModule, id }) {
2934 this.type = type || null;
2935 this.declaredDirectives = _normalizeArray(declaredDirectives);
2936 this.exportedDirectives = _normalizeArray(exportedDirectives);
2937 this.declaredPipes = _normalizeArray(declaredPipes);
2938 this.exportedPipes = _normalizeArray(exportedPipes);
2939 this.providers = _normalizeArray(providers);
2940 this.entryComponents = _normalizeArray(entryComponents);
2941 this.bootstrapComponents = _normalizeArray(bootstrapComponents);
2942 this.importedModules = _normalizeArray(importedModules);
2943 this.exportedModules = _normalizeArray(exportedModules);
2944 this.schemas = _normalizeArray(schemas);
2945 this.id = id || null;
2946 this.transitiveModule = transitiveModule || null;
2947 }
2948 toSummary() {
2949 const module = this.transitiveModule;
2950 return {
2951 summaryKind: CompileSummaryKind.NgModule,
2952 type: this.type,
2953 entryComponents: module.entryComponents,
2954 providers: module.providers,
2955 modules: module.modules,
2956 exportedDirectives: module.exportedDirectives,
2957 exportedPipes: module.exportedPipes
2958 };
2959 }
2960}
2961class TransitiveCompileNgModuleMetadata {
2962 constructor() {
2963 this.directivesSet = new Set();
2964 this.directives = [];
2965 this.exportedDirectivesSet = new Set();
2966 this.exportedDirectives = [];
2967 this.pipesSet = new Set();
2968 this.pipes = [];
2969 this.exportedPipesSet = new Set();
2970 this.exportedPipes = [];
2971 this.modulesSet = new Set();
2972 this.modules = [];
2973 this.entryComponentsSet = new Set();
2974 this.entryComponents = [];
2975 this.providers = [];
2976 }
2977 addProvider(provider, module) {
2978 this.providers.push({ provider: provider, module: module });
2979 }
2980 addDirective(id) {
2981 if (!this.directivesSet.has(id.reference)) {
2982 this.directivesSet.add(id.reference);
2983 this.directives.push(id);
2984 }
2985 }
2986 addExportedDirective(id) {
2987 if (!this.exportedDirectivesSet.has(id.reference)) {
2988 this.exportedDirectivesSet.add(id.reference);
2989 this.exportedDirectives.push(id);
2990 }
2991 }
2992 addPipe(id) {
2993 if (!this.pipesSet.has(id.reference)) {
2994 this.pipesSet.add(id.reference);
2995 this.pipes.push(id);
2996 }
2997 }
2998 addExportedPipe(id) {
2999 if (!this.exportedPipesSet.has(id.reference)) {
3000 this.exportedPipesSet.add(id.reference);
3001 this.exportedPipes.push(id);
3002 }
3003 }
3004 addModule(id) {
3005 if (!this.modulesSet.has(id.reference)) {
3006 this.modulesSet.add(id.reference);
3007 this.modules.push(id);
3008 }
3009 }
3010 addEntryComponent(ec) {
3011 if (!this.entryComponentsSet.has(ec.componentType)) {
3012 this.entryComponentsSet.add(ec.componentType);
3013 this.entryComponents.push(ec);
3014 }
3015 }
3016}
3017function _normalizeArray(obj) {
3018 return obj || [];
3019}
3020class ProviderMeta {
3021 constructor(token, { useClass, useValue, useExisting, useFactory, deps, multi }) {
3022 this.token = token;
3023 this.useClass = useClass || null;
3024 this.useValue = useValue;
3025 this.useExisting = useExisting;
3026 this.useFactory = useFactory || null;
3027 this.dependencies = deps || null;
3028 this.multi = !!multi;
3029 }
3030}
3031function flatten(list) {
3032 return list.reduce((flat, item) => {
3033 const flatItem = Array.isArray(item) ? flatten(item) : item;
3034 return flat.concat(flatItem);
3035 }, []);
3036}
3037function jitSourceUrl(url) {
3038 // Note: We need 3 "/" so that ng shows up as a separate domain
3039 // in the chrome dev tools.
3040 return url.replace(/(\w+:\/\/[\w:-]+)?(\/+)?/, 'ng:///');
3041}
3042function templateSourceUrl(ngModuleType, compMeta, templateMeta) {
3043 let url;
3044 if (templateMeta.isInline) {
3045 if (compMeta.type.reference instanceof StaticSymbol) {
3046 // Note: a .ts file might contain multiple components with inline templates,
3047 // so we need to give them unique urls, as these will be used for sourcemaps.
3048 url = `${compMeta.type.reference.filePath}.${compMeta.type.reference.name}.html`;
3049 }
3050 else {
3051 url = `${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.html`;
3052 }
3053 }
3054 else {
3055 url = templateMeta.templateUrl;
3056 }
3057 return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url);
3058}
3059function sharedStylesheetJitUrl(meta, id) {
3060 const pathParts = meta.moduleUrl.split(/\/\\/g);
3061 const baseName = pathParts[pathParts.length - 1];
3062 return jitSourceUrl(`css/${id}${baseName}.ngstyle.js`);
3063}
3064function ngModuleJitUrl(moduleMeta) {
3065 return jitSourceUrl(`${identifierName(moduleMeta.type)}/module.ngfactory.js`);
3066}
3067function templateJitUrl(ngModuleType, compMeta) {
3068 return jitSourceUrl(`${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.ngfactory.js`);
3069}
3070
3071/**
3072 * @license
3073 * Copyright Google Inc. All Rights Reserved.
3074 *
3075 * Use of this source code is governed by an MIT-style license that can be
3076 * found in the LICENSE file at https://angular.io/license
3077 */
3078const CORE$1 = '@angular/core';
3079class Identifiers$1 {
3080}
3081/* Methods */
3082Identifiers$1.NEW_METHOD = 'factory';
3083Identifiers$1.TRANSFORM_METHOD = 'transform';
3084Identifiers$1.PATCH_DEPS = 'patchedDeps';
3085/* Instructions */
3086Identifiers$1.namespaceHTML = { name: 'ɵɵnamespaceHTML', moduleName: CORE$1 };
3087Identifiers$1.namespaceMathML = { name: 'ɵɵnamespaceMathML', moduleName: CORE$1 };
3088Identifiers$1.namespaceSVG = { name: 'ɵɵnamespaceSVG', moduleName: CORE$1 };
3089Identifiers$1.element = { name: 'ɵɵelement', moduleName: CORE$1 };
3090Identifiers$1.elementStart = { name: 'ɵɵelementStart', moduleName: CORE$1 };
3091Identifiers$1.elementEnd = { name: 'ɵɵelementEnd', moduleName: CORE$1 };
3092Identifiers$1.select = { name: 'ɵɵselect', moduleName: CORE$1 };
3093Identifiers$1.updateSyntheticHostBinding = { name: 'ɵɵupdateSyntheticHostBinding', moduleName: CORE$1 };
3094Identifiers$1.componentHostSyntheticListener = { name: 'ɵɵcomponentHostSyntheticListener', moduleName: CORE$1 };
3095Identifiers$1.attribute = { name: 'ɵɵattribute', moduleName: CORE$1 };
3096Identifiers$1.attributeInterpolate1 = { name: 'ɵɵattributeInterpolate1', moduleName: CORE$1 };
3097Identifiers$1.attributeInterpolate2 = { name: 'ɵɵattributeInterpolate2', moduleName: CORE$1 };
3098Identifiers$1.attributeInterpolate3 = { name: 'ɵɵattributeInterpolate3', moduleName: CORE$1 };
3099Identifiers$1.attributeInterpolate4 = { name: 'ɵɵattributeInterpolate4', moduleName: CORE$1 };
3100Identifiers$1.attributeInterpolate5 = { name: 'ɵɵattributeInterpolate5', moduleName: CORE$1 };
3101Identifiers$1.attributeInterpolate6 = { name: 'ɵɵattributeInterpolate6', moduleName: CORE$1 };
3102Identifiers$1.attributeInterpolate7 = { name: 'ɵɵattributeInterpolate7', moduleName: CORE$1 };
3103Identifiers$1.attributeInterpolate8 = { name: 'ɵɵattributeInterpolate8', moduleName: CORE$1 };
3104Identifiers$1.attributeInterpolateV = { name: 'ɵɵattributeInterpolateV', moduleName: CORE$1 };
3105Identifiers$1.classProp = { name: 'ɵɵclassProp', moduleName: CORE$1 };
3106Identifiers$1.elementContainerStart = { name: 'ɵɵelementContainerStart', moduleName: CORE$1 };
3107Identifiers$1.elementContainerEnd = { name: 'ɵɵelementContainerEnd', moduleName: CORE$1 };
3108Identifiers$1.elementContainer = { name: 'ɵɵelementContainer', moduleName: CORE$1 };
3109Identifiers$1.styling = { name: 'ɵɵstyling', moduleName: CORE$1 };
3110Identifiers$1.styleMap = { name: 'ɵɵstyleMap', moduleName: CORE$1 };
3111Identifiers$1.classMap = { name: 'ɵɵclassMap', moduleName: CORE$1 };
3112Identifiers$1.classMapInterpolate1 = { name: 'ɵɵclassMapInterpolate1', moduleName: CORE$1 };
3113Identifiers$1.classMapInterpolate2 = { name: 'ɵɵclassMapInterpolate2', moduleName: CORE$1 };
3114Identifiers$1.classMapInterpolate3 = { name: 'ɵɵclassMapInterpolate3', moduleName: CORE$1 };
3115Identifiers$1.classMapInterpolate4 = { name: 'ɵɵclassMapInterpolate4', moduleName: CORE$1 };
3116Identifiers$1.classMapInterpolate5 = { name: 'ɵɵclassMapInterpolate5', moduleName: CORE$1 };
3117Identifiers$1.classMapInterpolate6 = { name: 'ɵɵclassMapInterpolate6', moduleName: CORE$1 };
3118Identifiers$1.classMapInterpolate7 = { name: 'ɵɵclassMapInterpolate7', moduleName: CORE$1 };
3119Identifiers$1.classMapInterpolate8 = { name: 'ɵɵclassMapInterpolate8', moduleName: CORE$1 };
3120Identifiers$1.classMapInterpolateV = { name: 'ɵɵclassMapInterpolateV', moduleName: CORE$1 };
3121Identifiers$1.styleProp = { name: 'ɵɵstyleProp', moduleName: CORE$1 };
3122Identifiers$1.stylePropInterpolate1 = { name: 'ɵɵstylePropInterpolate1', moduleName: CORE$1 };
3123Identifiers$1.stylePropInterpolate2 = { name: 'ɵɵstylePropInterpolate2', moduleName: CORE$1 };
3124Identifiers$1.stylePropInterpolate3 = { name: 'ɵɵstylePropInterpolate3', moduleName: CORE$1 };
3125Identifiers$1.stylePropInterpolate4 = { name: 'ɵɵstylePropInterpolate4', moduleName: CORE$1 };
3126Identifiers$1.stylePropInterpolate5 = { name: 'ɵɵstylePropInterpolate5', moduleName: CORE$1 };
3127Identifiers$1.stylePropInterpolate6 = { name: 'ɵɵstylePropInterpolate6', moduleName: CORE$1 };
3128Identifiers$1.stylePropInterpolate7 = { name: 'ɵɵstylePropInterpolate7', moduleName: CORE$1 };
3129Identifiers$1.stylePropInterpolate8 = { name: 'ɵɵstylePropInterpolate8', moduleName: CORE$1 };
3130Identifiers$1.stylePropInterpolateV = { name: 'ɵɵstylePropInterpolateV', moduleName: CORE$1 };
3131Identifiers$1.stylingApply = { name: 'ɵɵstylingApply', moduleName: CORE$1 };
3132Identifiers$1.styleSanitizer = { name: 'ɵɵstyleSanitizer', moduleName: CORE$1 };
3133Identifiers$1.elementHostAttrs = { name: 'ɵɵelementHostAttrs', moduleName: CORE$1 };
3134Identifiers$1.containerCreate = { name: 'ɵɵcontainer', moduleName: CORE$1 };
3135Identifiers$1.nextContext = { name: 'ɵɵnextContext', moduleName: CORE$1 };
3136Identifiers$1.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE$1 };
3137Identifiers$1.text = { name: 'ɵɵtext', moduleName: CORE$1 };
3138Identifiers$1.textBinding = { name: 'ɵɵtextBinding', moduleName: CORE$1 };
3139Identifiers$1.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE$1 };
3140Identifiers$1.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE$1 };
3141Identifiers$1.allocHostVars = { name: 'ɵɵallocHostVars', moduleName: CORE$1 };
3142Identifiers$1.getCurrentView = { name: 'ɵɵgetCurrentView', moduleName: CORE$1 };
3143Identifiers$1.textInterpolate = { name: 'ɵɵtextInterpolate', moduleName: CORE$1 };
3144Identifiers$1.textInterpolate1 = { name: 'ɵɵtextInterpolate1', moduleName: CORE$1 };
3145Identifiers$1.textInterpolate2 = { name: 'ɵɵtextInterpolate2', moduleName: CORE$1 };
3146Identifiers$1.textInterpolate3 = { name: 'ɵɵtextInterpolate3', moduleName: CORE$1 };
3147Identifiers$1.textInterpolate4 = { name: 'ɵɵtextInterpolate4', moduleName: CORE$1 };
3148Identifiers$1.textInterpolate5 = { name: 'ɵɵtextInterpolate5', moduleName: CORE$1 };
3149Identifiers$1.textInterpolate6 = { name: 'ɵɵtextInterpolate6', moduleName: CORE$1 };
3150Identifiers$1.textInterpolate7 = { name: 'ɵɵtextInterpolate7', moduleName: CORE$1 };
3151Identifiers$1.textInterpolate8 = { name: 'ɵɵtextInterpolate8', moduleName: CORE$1 };
3152Identifiers$1.textInterpolateV = { name: 'ɵɵtextInterpolateV', moduleName: CORE$1 };
3153Identifiers$1.restoreView = { name: 'ɵɵrestoreView', moduleName: CORE$1 };
3154Identifiers$1.pureFunction0 = { name: 'ɵɵpureFunction0', moduleName: CORE$1 };
3155Identifiers$1.pureFunction1 = { name: 'ɵɵpureFunction1', moduleName: CORE$1 };
3156Identifiers$1.pureFunction2 = { name: 'ɵɵpureFunction2', moduleName: CORE$1 };
3157Identifiers$1.pureFunction3 = { name: 'ɵɵpureFunction3', moduleName: CORE$1 };
3158Identifiers$1.pureFunction4 = { name: 'ɵɵpureFunction4', moduleName: CORE$1 };
3159Identifiers$1.pureFunction5 = { name: 'ɵɵpureFunction5', moduleName: CORE$1 };
3160Identifiers$1.pureFunction6 = { name: 'ɵɵpureFunction6', moduleName: CORE$1 };
3161Identifiers$1.pureFunction7 = { name: 'ɵɵpureFunction7', moduleName: CORE$1 };
3162Identifiers$1.pureFunction8 = { name: 'ɵɵpureFunction8', moduleName: CORE$1 };
3163Identifiers$1.pureFunctionV = { name: 'ɵɵpureFunctionV', moduleName: CORE$1 };
3164Identifiers$1.pipeBind1 = { name: 'ɵɵpipeBind1', moduleName: CORE$1 };
3165Identifiers$1.pipeBind2 = { name: 'ɵɵpipeBind2', moduleName: CORE$1 };
3166Identifiers$1.pipeBind3 = { name: 'ɵɵpipeBind3', moduleName: CORE$1 };
3167Identifiers$1.pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE$1 };
3168Identifiers$1.pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE$1 };
3169Identifiers$1.hostProperty = { name: 'ɵɵhostProperty', moduleName: CORE$1 };
3170Identifiers$1.property = { name: 'ɵɵproperty', moduleName: CORE$1 };
3171Identifiers$1.propertyInterpolate = { name: 'ɵɵpropertyInterpolate', moduleName: CORE$1 };
3172Identifiers$1.propertyInterpolate1 = { name: 'ɵɵpropertyInterpolate1', moduleName: CORE$1 };
3173Identifiers$1.propertyInterpolate2 = { name: 'ɵɵpropertyInterpolate2', moduleName: CORE$1 };
3174Identifiers$1.propertyInterpolate3 = { name: 'ɵɵpropertyInterpolate3', moduleName: CORE$1 };
3175Identifiers$1.propertyInterpolate4 = { name: 'ɵɵpropertyInterpolate4', moduleName: CORE$1 };
3176Identifiers$1.propertyInterpolate5 = { name: 'ɵɵpropertyInterpolate5', moduleName: CORE$1 };
3177Identifiers$1.propertyInterpolate6 = { name: 'ɵɵpropertyInterpolate6', moduleName: CORE$1 };
3178Identifiers$1.propertyInterpolate7 = { name: 'ɵɵpropertyInterpolate7', moduleName: CORE$1 };
3179Identifiers$1.propertyInterpolate8 = { name: 'ɵɵpropertyInterpolate8', moduleName: CORE$1 };
3180Identifiers$1.propertyInterpolateV = { name: 'ɵɵpropertyInterpolateV', moduleName: CORE$1 };
3181Identifiers$1.i18n = { name: 'ɵɵi18n', moduleName: CORE$1 };
3182Identifiers$1.i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE$1 };
3183Identifiers$1.i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE$1 };
3184Identifiers$1.i18nStart = { name: 'ɵɵi18nStart', moduleName: CORE$1 };
3185Identifiers$1.i18nEnd = { name: 'ɵɵi18nEnd', moduleName: CORE$1 };
3186Identifiers$1.i18nApply = { name: 'ɵɵi18nApply', moduleName: CORE$1 };
3187Identifiers$1.i18nPostprocess = { name: 'ɵɵi18nPostprocess', moduleName: CORE$1 };
3188Identifiers$1.i18nLocalize = { name: 'ɵɵi18nLocalize', moduleName: CORE$1 };
3189Identifiers$1.load = { name: 'ɵɵload', moduleName: CORE$1 };
3190Identifiers$1.pipe = { name: 'ɵɵpipe', moduleName: CORE$1 };
3191Identifiers$1.projection = { name: 'ɵɵprojection', moduleName: CORE$1 };
3192Identifiers$1.projectionDef = { name: 'ɵɵprojectionDef', moduleName: CORE$1 };
3193Identifiers$1.reference = { name: 'ɵɵreference', moduleName: CORE$1 };
3194Identifiers$1.inject = { name: 'ɵɵinject', moduleName: CORE$1 };
3195Identifiers$1.injectAttribute = { name: 'ɵɵinjectAttribute', moduleName: CORE$1 };
3196Identifiers$1.injectPipeChangeDetectorRef = { name: 'ɵɵinjectPipeChangeDetectorRef', moduleName: CORE$1 };
3197Identifiers$1.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE$1 };
3198Identifiers$1.templateRefExtractor = { name: 'ɵɵtemplateRefExtractor', moduleName: CORE$1 };
3199Identifiers$1.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE$1 };
3200Identifiers$1.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE$1 };
3201Identifiers$1.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE$1 };
3202Identifiers$1.defineBase = { name: 'ɵɵdefineBase', moduleName: CORE$1 };
3203Identifiers$1.BaseDef = {
3204 name: 'ɵɵBaseDef',
3205 moduleName: CORE$1,
3206};
3207Identifiers$1.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE$1 };
3208Identifiers$1.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE$1 };
3209Identifiers$1.ComponentDefWithMeta = {
3210 name: 'ɵɵComponentDefWithMeta',
3211 moduleName: CORE$1,
3212};
3213Identifiers$1.defineDirective = {
3214 name: 'ɵɵdefineDirective',
3215 moduleName: CORE$1,
3216};
3217Identifiers$1.DirectiveDefWithMeta = {
3218 name: 'ɵɵDirectiveDefWithMeta',
3219 moduleName: CORE$1,
3220};
3221Identifiers$1.InjectorDef = {
3222 name: 'ɵɵInjectorDef',
3223 moduleName: CORE$1,
3224};
3225Identifiers$1.defineInjector = {
3226 name: 'ɵɵdefineInjector',
3227 moduleName: CORE$1,
3228};
3229Identifiers$1.NgModuleDefWithMeta = {
3230 name: 'ɵɵNgModuleDefWithMeta',
3231 moduleName: CORE$1,
3232};
3233Identifiers$1.defineNgModule = { name: 'ɵɵdefineNgModule', moduleName: CORE$1 };
3234Identifiers$1.setNgModuleScope = { name: 'ɵɵsetNgModuleScope', moduleName: CORE$1 };
3235Identifiers$1.PipeDefWithMeta = { name: 'ɵɵPipeDefWithMeta', moduleName: CORE$1 };
3236Identifiers$1.definePipe = { name: 'ɵɵdefinePipe', moduleName: CORE$1 };
3237Identifiers$1.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE$1 };
3238Identifiers$1.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE$1 };
3239Identifiers$1.staticViewQuery = { name: 'ɵɵstaticViewQuery', moduleName: CORE$1 };
3240Identifiers$1.staticContentQuery = { name: 'ɵɵstaticContentQuery', moduleName: CORE$1 };
3241Identifiers$1.loadViewQuery = { name: 'ɵɵloadViewQuery', moduleName: CORE$1 };
3242Identifiers$1.contentQuery = { name: 'ɵɵcontentQuery', moduleName: CORE$1 };
3243Identifiers$1.loadContentQuery = { name: 'ɵɵloadContentQuery', moduleName: CORE$1 };
3244Identifiers$1.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE$1 };
3245Identifiers$1.InheritDefinitionFeature = { name: 'ɵɵInheritDefinitionFeature', moduleName: CORE$1 };
3246Identifiers$1.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE$1 };
3247Identifiers$1.listener = { name: 'ɵɵlistener', moduleName: CORE$1 };
3248Identifiers$1.getFactoryOf = {
3249 name: 'ɵɵgetFactoryOf',
3250 moduleName: CORE$1,
3251};
3252Identifiers$1.getInheritedFactory = {
3253 name: 'ɵɵgetInheritedFactory',
3254 moduleName: CORE$1,
3255};
3256// sanitization-related functions
3257Identifiers$1.sanitizeHtml = { name: 'ɵɵsanitizeHtml', moduleName: CORE$1 };
3258Identifiers$1.sanitizeStyle = { name: 'ɵɵsanitizeStyle', moduleName: CORE$1 };
3259Identifiers$1.defaultStyleSanitizer = { name: 'ɵɵdefaultStyleSanitizer', moduleName: CORE$1 };
3260Identifiers$1.sanitizeResourceUrl = { name: 'ɵɵsanitizeResourceUrl', moduleName: CORE$1 };
3261Identifiers$1.sanitizeScript = { name: 'ɵɵsanitizeScript', moduleName: CORE$1 };
3262Identifiers$1.sanitizeUrl = { name: 'ɵɵsanitizeUrl', moduleName: CORE$1 };
3263Identifiers$1.sanitizeUrlOrResourceUrl = { name: 'ɵɵsanitizeUrlOrResourceUrl', moduleName: CORE$1 };
3264
3265/**
3266 * @license
3267 * Copyright Google Inc. All Rights Reserved.
3268 *
3269 * Use of this source code is governed by an MIT-style license that can be
3270 * found in the LICENSE file at https://angular.io/license
3271 */
3272const $EOF = 0;
3273const $BSPACE = 8;
3274const $TAB = 9;
3275const $LF = 10;
3276const $VTAB = 11;
3277const $FF = 12;
3278const $CR = 13;
3279const $SPACE = 32;
3280const $BANG = 33;
3281const $DQ = 34;
3282const $HASH = 35;
3283const $$ = 36;
3284const $PERCENT = 37;
3285const $AMPERSAND = 38;
3286const $SQ = 39;
3287const $LPAREN = 40;
3288const $RPAREN = 41;
3289const $STAR = 42;
3290const $PLUS = 43;
3291const $COMMA = 44;
3292const $MINUS = 45;
3293const $PERIOD = 46;
3294const $SLASH = 47;
3295const $COLON = 58;
3296const $SEMICOLON = 59;
3297const $LT = 60;
3298const $EQ = 61;
3299const $GT = 62;
3300const $QUESTION = 63;
3301const $0 = 48;
3302const $7 = 55;
3303const $9 = 57;
3304const $A = 65;
3305const $E = 69;
3306const $F = 70;
3307const $X = 88;
3308const $Z = 90;
3309const $LBRACKET = 91;
3310const $BACKSLASH = 92;
3311const $RBRACKET = 93;
3312const $CARET = 94;
3313const $_ = 95;
3314const $a = 97;
3315const $b = 98;
3316const $e = 101;
3317const $f = 102;
3318const $n = 110;
3319const $r = 114;
3320const $t = 116;
3321const $u = 117;
3322const $v = 118;
3323const $x = 120;
3324const $z = 122;
3325const $LBRACE = 123;
3326const $BAR = 124;
3327const $RBRACE = 125;
3328const $NBSP = 160;
3329const $PIPE = 124;
3330const $TILDA = 126;
3331const $AT = 64;
3332const $BT = 96;
3333function isWhitespace(code) {
3334 return (code >= $TAB && code <= $SPACE) || (code == $NBSP);
3335}
3336function isDigit(code) {
3337 return $0 <= code && code <= $9;
3338}
3339function isAsciiLetter(code) {
3340 return code >= $a && code <= $z || code >= $A && code <= $Z;
3341}
3342function isAsciiHexDigit(code) {
3343 return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code);
3344}
3345function isNewLine(code) {
3346 return code === $LF || code === $CR;
3347}
3348function isOctalDigit(code) {
3349 return $0 <= code && code <= $7;
3350}
3351
3352/**
3353 * @license
3354 * Copyright Google Inc. All Rights Reserved.
3355 *
3356 * Use of this source code is governed by an MIT-style license that can be
3357 * found in the LICENSE file at https://angular.io/license
3358 */
3359class ParseLocation {
3360 constructor(file, offset, line, col) {
3361 this.file = file;
3362 this.offset = offset;
3363 this.line = line;
3364 this.col = col;
3365 }
3366 toString() {
3367 return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url;
3368 }
3369 moveBy(delta) {
3370 const source = this.file.content;
3371 const len = source.length;
3372 let offset = this.offset;
3373 let line = this.line;
3374 let col = this.col;
3375 while (offset > 0 && delta < 0) {
3376 offset--;
3377 delta++;
3378 const ch = source.charCodeAt(offset);
3379 if (ch == $LF) {
3380 line--;
3381 const priorLine = source.substr(0, offset - 1).lastIndexOf(String.fromCharCode($LF));
3382 col = priorLine > 0 ? offset - priorLine : offset;
3383 }
3384 else {
3385 col--;
3386 }
3387 }
3388 while (offset < len && delta > 0) {
3389 const ch = source.charCodeAt(offset);
3390 offset++;
3391 delta--;
3392 if (ch == $LF) {
3393 line++;
3394 col = 0;
3395 }
3396 else {
3397 col++;
3398 }
3399 }
3400 return new ParseLocation(this.file, offset, line, col);
3401 }
3402 // Return the source around the location
3403 // Up to `maxChars` or `maxLines` on each side of the location
3404 getContext(maxChars, maxLines) {
3405 const content = this.file.content;
3406 let startOffset = this.offset;
3407 if (startOffset != null) {
3408 if (startOffset > content.length - 1) {
3409 startOffset = content.length - 1;
3410 }
3411 let endOffset = startOffset;
3412 let ctxChars = 0;
3413 let ctxLines = 0;
3414 while (ctxChars < maxChars && startOffset > 0) {
3415 startOffset--;
3416 ctxChars++;
3417 if (content[startOffset] == '\n') {
3418 if (++ctxLines == maxLines) {
3419 break;
3420 }
3421 }
3422 }
3423 ctxChars = 0;
3424 ctxLines = 0;
3425 while (ctxChars < maxChars && endOffset < content.length - 1) {
3426 endOffset++;
3427 ctxChars++;
3428 if (content[endOffset] == '\n') {
3429 if (++ctxLines == maxLines) {
3430 break;
3431 }
3432 }
3433 }
3434 return {
3435 before: content.substring(startOffset, this.offset),
3436 after: content.substring(this.offset, endOffset + 1),
3437 };
3438 }
3439 return null;
3440 }
3441}
3442class ParseSourceFile {
3443 constructor(content, url) {
3444 this.content = content;
3445 this.url = url;
3446 }
3447}
3448class ParseSourceSpan {
3449 constructor(start, end, details = null) {
3450 this.start = start;
3451 this.end = end;
3452 this.details = details;
3453 }
3454 toString() {
3455 return this.start.file.content.substring(this.start.offset, this.end.offset);
3456 }
3457}
3458const EMPTY_PARSE_LOCATION = new ParseLocation(new ParseSourceFile('', ''), 0, 0, 0);
3459const EMPTY_SOURCE_SPAN = new ParseSourceSpan(EMPTY_PARSE_LOCATION, EMPTY_PARSE_LOCATION);
3460var ParseErrorLevel;
3461(function (ParseErrorLevel) {
3462 ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING";
3463 ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR";
3464})(ParseErrorLevel || (ParseErrorLevel = {}));
3465class ParseError {
3466 constructor(span, msg, level = ParseErrorLevel.ERROR) {
3467 this.span = span;
3468 this.msg = msg;
3469 this.level = level;
3470 }
3471 contextualMessage() {
3472 const ctx = this.span.start.getContext(100, 3);
3473 return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` :
3474 this.msg;
3475 }
3476 toString() {
3477 const details = this.span.details ? `, ${this.span.details}` : '';
3478 return `${this.contextualMessage()}: ${this.span.start}${details}`;
3479 }
3480}
3481function typeSourceSpan(kind, type) {
3482 const moduleUrl = identifierModuleUrl(type);
3483 const sourceFileName = moduleUrl != null ? `in ${kind} ${identifierName(type)} in ${moduleUrl}` :
3484 `in ${kind} ${identifierName(type)}`;
3485 const sourceFile = new ParseSourceFile('', sourceFileName);
3486 return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
3487}
3488/**
3489 * Generates Source Span object for a given R3 Type for JIT mode.
3490 *
3491 * @param kind Component or Directive.
3492 * @param typeName name of the Component or Directive.
3493 * @param sourceUrl reference to Component or Directive source.
3494 * @returns instance of ParseSourceSpan that represent a given Component or Directive.
3495 */
3496function r3JitTypeSourceSpan(kind, typeName, sourceUrl) {
3497 const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`;
3498 const sourceFile = new ParseSourceFile('', sourceFileName);
3499 return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
3500}
3501
3502/**
3503 * @license
3504 * Copyright Google Inc. All Rights Reserved.
3505 *
3506 * Use of this source code is governed by an MIT-style license that can be
3507 * found in the LICENSE file at https://angular.io/license
3508 */
3509class Text {
3510 constructor(value, sourceSpan) {
3511 this.value = value;
3512 this.sourceSpan = sourceSpan;
3513 }
3514 visit(visitor) { return visitor.visitText(this); }
3515}
3516class BoundText {
3517 constructor(value, sourceSpan, i18n) {
3518 this.value = value;
3519 this.sourceSpan = sourceSpan;
3520 this.i18n = i18n;
3521 }
3522 visit(visitor) { return visitor.visitBoundText(this); }
3523}
3524class TextAttribute {
3525 constructor(name, value, sourceSpan, valueSpan, i18n) {
3526 this.name = name;
3527 this.value = value;
3528 this.sourceSpan = sourceSpan;
3529 this.valueSpan = valueSpan;
3530 this.i18n = i18n;
3531 }
3532 visit(visitor) { return visitor.visitTextAttribute(this); }
3533}
3534class BoundAttribute {
3535 constructor(name, type, securityContext, value, unit, sourceSpan, valueSpan, i18n) {
3536 this.name = name;
3537 this.type = type;
3538 this.securityContext = securityContext;
3539 this.value = value;
3540 this.unit = unit;
3541 this.sourceSpan = sourceSpan;
3542 this.valueSpan = valueSpan;
3543 this.i18n = i18n;
3544 }
3545 static fromBoundElementProperty(prop, i18n) {
3546 return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.valueSpan, i18n);
3547 }
3548 visit(visitor) { return visitor.visitBoundAttribute(this); }
3549}
3550class BoundEvent {
3551 constructor(name, type, handler, target, phase, sourceSpan, handlerSpan) {
3552 this.name = name;
3553 this.type = type;
3554 this.handler = handler;
3555 this.target = target;
3556 this.phase = phase;
3557 this.sourceSpan = sourceSpan;
3558 this.handlerSpan = handlerSpan;
3559 }
3560 static fromParsedEvent(event) {
3561 const target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
3562 const phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
3563 return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan);
3564 }
3565 visit(visitor) { return visitor.visitBoundEvent(this); }
3566}
3567class Element {
3568 constructor(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
3569 this.name = name;
3570 this.attributes = attributes;
3571 this.inputs = inputs;
3572 this.outputs = outputs;
3573 this.children = children;
3574 this.references = references;
3575 this.sourceSpan = sourceSpan;
3576 this.startSourceSpan = startSourceSpan;
3577 this.endSourceSpan = endSourceSpan;
3578 this.i18n = i18n;
3579 // If the element is empty then the source span should include any closing tag
3580 if (children.length === 0 && startSourceSpan && endSourceSpan) {
3581 this.sourceSpan = new ParseSourceSpan(sourceSpan.start, endSourceSpan.end);
3582 }
3583 }
3584 visit(visitor) { return visitor.visitElement(this); }
3585}
3586class Template {
3587 constructor(tagName, attributes, inputs, outputs, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
3588 this.tagName = tagName;
3589 this.attributes = attributes;
3590 this.inputs = inputs;
3591 this.outputs = outputs;
3592 this.templateAttrs = templateAttrs;
3593 this.children = children;
3594 this.references = references;
3595 this.variables = variables;
3596 this.sourceSpan = sourceSpan;
3597 this.startSourceSpan = startSourceSpan;
3598 this.endSourceSpan = endSourceSpan;
3599 this.i18n = i18n;
3600 }
3601 visit(visitor) { return visitor.visitTemplate(this); }
3602}
3603class Content {
3604 constructor(selector, attributes, sourceSpan, i18n) {
3605 this.selector = selector;
3606 this.attributes = attributes;
3607 this.sourceSpan = sourceSpan;
3608 this.i18n = i18n;
3609 }
3610 visit(visitor) { return visitor.visitContent(this); }
3611}
3612class Variable {
3613 constructor(name, value, sourceSpan, valueSpan) {
3614 this.name = name;
3615 this.value = value;
3616 this.sourceSpan = sourceSpan;
3617 this.valueSpan = valueSpan;
3618 }
3619 visit(visitor) { return visitor.visitVariable(this); }
3620}
3621class Reference {
3622 constructor(name, value, sourceSpan, valueSpan) {
3623 this.name = name;
3624 this.value = value;
3625 this.sourceSpan = sourceSpan;
3626 this.valueSpan = valueSpan;
3627 }
3628 visit(visitor) { return visitor.visitReference(this); }
3629}
3630class Icu {
3631 constructor(vars, placeholders, sourceSpan, i18n) {
3632 this.vars = vars;
3633 this.placeholders = placeholders;
3634 this.sourceSpan = sourceSpan;
3635 this.i18n = i18n;
3636 }
3637 visit(visitor) { return visitor.visitIcu(this); }
3638}
3639class NullVisitor {
3640 visitElement(element) { }
3641 visitTemplate(template) { }
3642 visitContent(content) { }
3643 visitVariable(variable) { }
3644 visitReference(reference) { }
3645 visitTextAttribute(attribute) { }
3646 visitBoundAttribute(attribute) { }
3647 visitBoundEvent(attribute) { }
3648 visitText(text) { }
3649 visitBoundText(text) { }
3650 visitIcu(icu) { }
3651}
3652class RecursiveVisitor {
3653 visitElement(element) {
3654 visitAll(this, element.attributes);
3655 visitAll(this, element.children);
3656 visitAll(this, element.references);
3657 }
3658 visitTemplate(template) {
3659 visitAll(this, template.attributes);
3660 visitAll(this, template.children);
3661 visitAll(this, template.references);
3662 visitAll(this, template.variables);
3663 }
3664 visitContent(content) { }
3665 visitVariable(variable) { }
3666 visitReference(reference) { }
3667 visitTextAttribute(attribute) { }
3668 visitBoundAttribute(attribute) { }
3669 visitBoundEvent(attribute) { }
3670 visitText(text) { }
3671 visitBoundText(text) { }
3672 visitIcu(icu) { }
3673}
3674class TransformVisitor {
3675 visitElement(element) {
3676 const newAttributes = transformAll(this, element.attributes);
3677 const newInputs = transformAll(this, element.inputs);
3678 const newOutputs = transformAll(this, element.outputs);
3679 const newChildren = transformAll(this, element.children);
3680 const newReferences = transformAll(this, element.references);
3681 if (newAttributes != element.attributes || newInputs != element.inputs ||
3682 newOutputs != element.outputs || newChildren != element.children ||
3683 newReferences != element.references) {
3684 return new Element(element.name, newAttributes, newInputs, newOutputs, newChildren, newReferences, element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
3685 }
3686 return element;
3687 }
3688 visitTemplate(template) {
3689 const newAttributes = transformAll(this, template.attributes);
3690 const newInputs = transformAll(this, template.inputs);
3691 const newOutputs = transformAll(this, template.outputs);
3692 const newTemplateAttrs = transformAll(this, template.templateAttrs);
3693 const newChildren = transformAll(this, template.children);
3694 const newReferences = transformAll(this, template.references);
3695 const newVariables = transformAll(this, template.variables);
3696 if (newAttributes != template.attributes || newInputs != template.inputs ||
3697 newOutputs != template.outputs || newTemplateAttrs != template.templateAttrs ||
3698 newChildren != template.children || newReferences != template.references ||
3699 newVariables != template.variables) {
3700 return new Template(template.tagName, newAttributes, newInputs, newOutputs, newTemplateAttrs, newChildren, newReferences, newVariables, template.sourceSpan, template.startSourceSpan, template.endSourceSpan);
3701 }
3702 return template;
3703 }
3704 visitContent(content) { return content; }
3705 visitVariable(variable) { return variable; }
3706 visitReference(reference) { return reference; }
3707 visitTextAttribute(attribute) { return attribute; }
3708 visitBoundAttribute(attribute) { return attribute; }
3709 visitBoundEvent(attribute) { return attribute; }
3710 visitText(text) { return text; }
3711 visitBoundText(text) { return text; }
3712 visitIcu(icu) { return icu; }
3713}
3714function visitAll(visitor, nodes) {
3715 const result = [];
3716 if (visitor.visit) {
3717 for (const node of nodes) {
3718 const newNode = visitor.visit(node) || node.visit(visitor);
3719 }
3720 }
3721 else {
3722 for (const node of nodes) {
3723 const newNode = node.visit(visitor);
3724 if (newNode) {
3725 result.push(newNode);
3726 }
3727 }
3728 }
3729 return result;
3730}
3731function transformAll(visitor, nodes) {
3732 const result = [];
3733 let changed = false;
3734 for (const node of nodes) {
3735 const newNode = node.visit(visitor);
3736 if (newNode) {
3737 result.push(newNode);
3738 }
3739 changed = changed || newNode != node;
3740 }
3741 return changed ? result : nodes;
3742}
3743
3744/**
3745 * @license
3746 * Copyright Google Inc. All Rights Reserved.
3747 *
3748 * Use of this source code is governed by an MIT-style license that can be
3749 * found in the LICENSE file at https://angular.io/license
3750 */
3751class Message {
3752 /**
3753 * @param nodes message AST
3754 * @param placeholders maps placeholder names to static content
3755 * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages)
3756 * @param meaning
3757 * @param description
3758 * @param id
3759 */
3760 constructor(nodes, placeholders, placeholderToMessage, meaning, description, id) {
3761 this.nodes = nodes;
3762 this.placeholders = placeholders;
3763 this.placeholderToMessage = placeholderToMessage;
3764 this.meaning = meaning;
3765 this.description = description;
3766 this.id = id;
3767 if (nodes.length) {
3768 this.sources = [{
3769 filePath: nodes[0].sourceSpan.start.file.url,
3770 startLine: nodes[0].sourceSpan.start.line + 1,
3771 startCol: nodes[0].sourceSpan.start.col + 1,
3772 endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1,
3773 endCol: nodes[0].sourceSpan.start.col + 1
3774 }];
3775 }
3776 else {
3777 this.sources = [];
3778 }
3779 }
3780}
3781class Text$1 {
3782 constructor(value, sourceSpan) {
3783 this.value = value;
3784 this.sourceSpan = sourceSpan;
3785 }
3786 visit(visitor, context) { return visitor.visitText(this, context); }
3787}
3788// TODO(vicb): do we really need this node (vs an array) ?
3789class Container {
3790 constructor(children, sourceSpan) {
3791 this.children = children;
3792 this.sourceSpan = sourceSpan;
3793 }
3794 visit(visitor, context) { return visitor.visitContainer(this, context); }
3795}
3796class Icu$1 {
3797 constructor(expression, type, cases, sourceSpan) {
3798 this.expression = expression;
3799 this.type = type;
3800 this.cases = cases;
3801 this.sourceSpan = sourceSpan;
3802 }
3803 visit(visitor, context) { return visitor.visitIcu(this, context); }
3804}
3805class TagPlaceholder {
3806 constructor(tag, attrs, startName, closeName, children, isVoid, sourceSpan) {
3807 this.tag = tag;
3808 this.attrs = attrs;
3809 this.startName = startName;
3810 this.closeName = closeName;
3811 this.children = children;
3812 this.isVoid = isVoid;
3813 this.sourceSpan = sourceSpan;
3814 }
3815 visit(visitor, context) { return visitor.visitTagPlaceholder(this, context); }
3816}
3817class Placeholder {
3818 constructor(value, name, sourceSpan) {
3819 this.value = value;
3820 this.name = name;
3821 this.sourceSpan = sourceSpan;
3822 }
3823 visit(visitor, context) { return visitor.visitPlaceholder(this, context); }
3824}
3825class IcuPlaceholder {
3826 constructor(value, name, sourceSpan) {
3827 this.value = value;
3828 this.name = name;
3829 this.sourceSpan = sourceSpan;
3830 }
3831 visit(visitor, context) { return visitor.visitIcuPlaceholder(this, context); }
3832}
3833// Clone the AST
3834class CloneVisitor {
3835 visitText(text, context) { return new Text$1(text.value, text.sourceSpan); }
3836 visitContainer(container, context) {
3837 const children = container.children.map(n => n.visit(this, context));
3838 return new Container(children, container.sourceSpan);
3839 }
3840 visitIcu(icu, context) {
3841 const cases = {};
3842 Object.keys(icu.cases).forEach(key => cases[key] = icu.cases[key].visit(this, context));
3843 const msg = new Icu$1(icu.expression, icu.type, cases, icu.sourceSpan);
3844 msg.expressionPlaceholder = icu.expressionPlaceholder;
3845 return msg;
3846 }
3847 visitTagPlaceholder(ph, context) {
3848 const children = ph.children.map(n => n.visit(this, context));
3849 return new TagPlaceholder(ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan);
3850 }
3851 visitPlaceholder(ph, context) {
3852 return new Placeholder(ph.value, ph.name, ph.sourceSpan);
3853 }
3854 visitIcuPlaceholder(ph, context) {
3855 return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan);
3856 }
3857}
3858// Visit all the nodes recursively
3859class RecurseVisitor {
3860 visitText(text, context) { }
3861 visitContainer(container, context) {
3862 container.children.forEach(child => child.visit(this));
3863 }
3864 visitIcu(icu, context) {
3865 Object.keys(icu.cases).forEach(k => { icu.cases[k].visit(this); });
3866 }
3867 visitTagPlaceholder(ph, context) {
3868 ph.children.forEach(child => child.visit(this));
3869 }
3870 visitPlaceholder(ph, context) { }
3871 visitIcuPlaceholder(ph, context) { }
3872}
3873
3874/**
3875 * @license
3876 * Copyright Google Inc. All Rights Reserved.
3877 *
3878 * Use of this source code is governed by an MIT-style license that can be
3879 * found in the LICENSE file at https://angular.io/license
3880 */
3881function digest(message) {
3882 return message.id || sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
3883}
3884function decimalDigest(message) {
3885 if (message.id) {
3886 return message.id;
3887 }
3888 const visitor = new _SerializerIgnoreIcuExpVisitor();
3889 const parts = message.nodes.map(a => a.visit(visitor, null));
3890 return computeMsgId(parts.join(''), message.meaning);
3891}
3892/**
3893 * Serialize the i18n ast to something xml-like in order to generate an UID.
3894 *
3895 * The visitor is also used in the i18n parser tests
3896 *
3897 * @internal
3898 */
3899class _SerializerVisitor {
3900 visitText(text, context) { return text.value; }
3901 visitContainer(container, context) {
3902 return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
3903 }
3904 visitIcu(icu, context) {
3905 const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
3906 return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`;
3907 }
3908 visitTagPlaceholder(ph, context) {
3909 return ph.isVoid ?
3910 `<ph tag name="${ph.startName}"/>` :
3911 `<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
3912 }
3913 visitPlaceholder(ph, context) {
3914 return ph.value ? `<ph name="${ph.name}">${ph.value}</ph>` : `<ph name="${ph.name}"/>`;
3915 }
3916 visitIcuPlaceholder(ph, context) {
3917 return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
3918 }
3919}
3920const serializerVisitor = new _SerializerVisitor();
3921function serializeNodes(nodes) {
3922 return nodes.map(a => a.visit(serializerVisitor, null));
3923}
3924/**
3925 * Serialize the i18n ast to something xml-like in order to generate an UID.
3926 *
3927 * Ignore the ICU expressions so that message IDs stays identical if only the expression changes.
3928 *
3929 * @internal
3930 */
3931class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor {
3932 visitIcu(icu, context) {
3933 let strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
3934 // Do not take the expression into account
3935 return `{${icu.type}, ${strCases.join(', ')}}`;
3936 }
3937}
3938/**
3939 * Compute the SHA1 of the given string
3940 *
3941 * see http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
3942 *
3943 * WARNING: this function has not been designed not tested with security in mind.
3944 * DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT.
3945 */
3946function sha1(str) {
3947 const utf8 = utf8Encode(str);
3948 const words32 = stringToWords32(utf8, Endian.Big);
3949 const len = utf8.length * 8;
3950 const w = new Array(80);
3951 let [a, b, c, d, e] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
3952 words32[len >> 5] |= 0x80 << (24 - len % 32);
3953 words32[((len + 64 >> 9) << 4) + 15] = len;
3954 for (let i = 0; i < words32.length; i += 16) {
3955 const [h0, h1, h2, h3, h4] = [a, b, c, d, e];
3956 for (let j = 0; j < 80; j++) {
3957 if (j < 16) {
3958 w[j] = words32[i + j];
3959 }
3960 else {
3961 w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
3962 }
3963 const [f, k] = fk(j, b, c, d);
3964 const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
3965 [e, d, c, b, a] = [d, c, rol32(b, 30), a, temp];
3966 }
3967 [a, b, c, d, e] = [add32(a, h0), add32(b, h1), add32(c, h2), add32(d, h3), add32(e, h4)];
3968 }
3969 return byteStringToHexString(words32ToByteString([a, b, c, d, e]));
3970}
3971function fk(index, b, c, d) {
3972 if (index < 20) {
3973 return [(b & c) | (~b & d), 0x5a827999];
3974 }
3975 if (index < 40) {
3976 return [b ^ c ^ d, 0x6ed9eba1];
3977 }
3978 if (index < 60) {
3979 return [(b & c) | (b & d) | (c & d), 0x8f1bbcdc];
3980 }
3981 return [b ^ c ^ d, 0xca62c1d6];
3982}
3983/**
3984 * Compute the fingerprint of the given string
3985 *
3986 * The output is 64 bit number encoded as a decimal string
3987 *
3988 * based on:
3989 * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
3990 */
3991function fingerprint(str) {
3992 const utf8 = utf8Encode(str);
3993 let [hi, lo] = [hash32(utf8, 0), hash32(utf8, 102072)];
3994 if (hi == 0 && (lo == 0 || lo == 1)) {
3995 hi = hi ^ 0x130f9bef;
3996 lo = lo ^ -0x6b5f56d8;
3997 }
3998 return [hi, lo];
3999}
4000function computeMsgId(msg, meaning) {
4001 let [hi, lo] = fingerprint(msg);
4002 if (meaning) {
4003 const [him, lom] = fingerprint(meaning);
4004 [hi, lo] = add64(rol64([hi, lo], 1), [him, lom]);
4005 }
4006 return byteStringToDecString(words32ToByteString([hi & 0x7fffffff, lo]));
4007}
4008function hash32(str, c) {
4009 let [a, b] = [0x9e3779b9, 0x9e3779b9];
4010 let i;
4011 const len = str.length;
4012 for (i = 0; i + 12 <= len; i += 12) {
4013 a = add32(a, wordAt(str, i, Endian.Little));
4014 b = add32(b, wordAt(str, i + 4, Endian.Little));
4015 c = add32(c, wordAt(str, i + 8, Endian.Little));
4016 [a, b, c] = mix([a, b, c]);
4017 }
4018 a = add32(a, wordAt(str, i, Endian.Little));
4019 b = add32(b, wordAt(str, i + 4, Endian.Little));
4020 // the first byte of c is reserved for the length
4021 c = add32(c, len);
4022 c = add32(c, wordAt(str, i + 8, Endian.Little) << 8);
4023 return mix([a, b, c])[2];
4024}
4025// clang-format off
4026function mix([a, b, c]) {
4027 a = sub32(a, b);
4028 a = sub32(a, c);
4029 a ^= c >>> 13;
4030 b = sub32(b, c);
4031 b = sub32(b, a);
4032 b ^= a << 8;
4033 c = sub32(c, a);
4034 c = sub32(c, b);
4035 c ^= b >>> 13;
4036 a = sub32(a, b);
4037 a = sub32(a, c);
4038 a ^= c >>> 12;
4039 b = sub32(b, c);
4040 b = sub32(b, a);
4041 b ^= a << 16;
4042 c = sub32(c, a);
4043 c = sub32(c, b);
4044 c ^= b >>> 5;
4045 a = sub32(a, b);
4046 a = sub32(a, c);
4047 a ^= c >>> 3;
4048 b = sub32(b, c);
4049 b = sub32(b, a);
4050 b ^= a << 10;
4051 c = sub32(c, a);
4052 c = sub32(c, b);
4053 c ^= b >>> 15;
4054 return [a, b, c];
4055}
4056// clang-format on
4057// Utils
4058var Endian;
4059(function (Endian) {
4060 Endian[Endian["Little"] = 0] = "Little";
4061 Endian[Endian["Big"] = 1] = "Big";
4062})(Endian || (Endian = {}));
4063function add32(a, b) {
4064 return add32to64(a, b)[1];
4065}
4066function add32to64(a, b) {
4067 const low = (a & 0xffff) + (b & 0xffff);
4068 const high = (a >>> 16) + (b >>> 16) + (low >>> 16);
4069 return [high >>> 16, (high << 16) | (low & 0xffff)];
4070}
4071function add64([ah, al], [bh, bl]) {
4072 const [carry, l] = add32to64(al, bl);
4073 const h = add32(add32(ah, bh), carry);
4074 return [h, l];
4075}
4076function sub32(a, b) {
4077 const low = (a & 0xffff) - (b & 0xffff);
4078 const high = (a >> 16) - (b >> 16) + (low >> 16);
4079 return (high << 16) | (low & 0xffff);
4080}
4081// Rotate a 32b number left `count` position
4082function rol32(a, count) {
4083 return (a << count) | (a >>> (32 - count));
4084}
4085// Rotate a 64b number left `count` position
4086function rol64([hi, lo], count) {
4087 const h = (hi << count) | (lo >>> (32 - count));
4088 const l = (lo << count) | (hi >>> (32 - count));
4089 return [h, l];
4090}
4091function stringToWords32(str, endian) {
4092 const words32 = Array((str.length + 3) >>> 2);
4093 for (let i = 0; i < words32.length; i++) {
4094 words32[i] = wordAt(str, i * 4, endian);
4095 }
4096 return words32;
4097}
4098function byteAt(str, index) {
4099 return index >= str.length ? 0 : str.charCodeAt(index) & 0xff;
4100}
4101function wordAt(str, index, endian) {
4102 let word = 0;
4103 if (endian === Endian.Big) {
4104 for (let i = 0; i < 4; i++) {
4105 word += byteAt(str, index + i) << (24 - 8 * i);
4106 }
4107 }
4108 else {
4109 for (let i = 0; i < 4; i++) {
4110 word += byteAt(str, index + i) << 8 * i;
4111 }
4112 }
4113 return word;
4114}
4115function words32ToByteString(words32) {
4116 return words32.reduce((str, word) => str + word32ToByteString(word), '');
4117}
4118function word32ToByteString(word) {
4119 let str = '';
4120 for (let i = 0; i < 4; i++) {
4121 str += String.fromCharCode((word >>> 8 * (3 - i)) & 0xff);
4122 }
4123 return str;
4124}
4125function byteStringToHexString(str) {
4126 let hex = '';
4127 for (let i = 0; i < str.length; i++) {
4128 const b = byteAt(str, i);
4129 hex += (b >>> 4).toString(16) + (b & 0x0f).toString(16);
4130 }
4131 return hex.toLowerCase();
4132}
4133// based on http://www.danvk.org/hex2dec.html (JS can not handle more than 56b)
4134function byteStringToDecString(str) {
4135 let decimal = '';
4136 let toThePower = '1';
4137 for (let i = str.length - 1; i >= 0; i--) {
4138 decimal = addBigInt(decimal, numberTimesBigInt(byteAt(str, i), toThePower));
4139 toThePower = numberTimesBigInt(256, toThePower);
4140 }
4141 return decimal.split('').reverse().join('');
4142}
4143// x and y decimal, lowest significant digit first
4144function addBigInt(x, y) {
4145 let sum = '';
4146 const len = Math.max(x.length, y.length);
4147 for (let i = 0, carry = 0; i < len || carry; i++) {
4148 const tmpSum = carry + +(x[i] || 0) + +(y[i] || 0);
4149 if (tmpSum >= 10) {
4150 carry = 1;
4151 sum += tmpSum - 10;
4152 }
4153 else {
4154 carry = 0;
4155 sum += tmpSum;
4156 }
4157 }
4158 return sum;
4159}
4160function numberTimesBigInt(num, b) {
4161 let product = '';
4162 let bToThePower = b;
4163 for (; num !== 0; num = num >>> 1) {
4164 if (num & 1)
4165 product = addBigInt(product, bToThePower);
4166 bToThePower = addBigInt(bToThePower, bToThePower);
4167 }
4168 return product;
4169}
4170
4171/**
4172 * @license
4173 * Copyright Google Inc. All Rights Reserved.
4174 *
4175 * Use of this source code is governed by an MIT-style license that can be
4176 * found in the LICENSE file at https://angular.io/license
4177 */
4178class Serializer {
4179 // Creates a name mapper, see `PlaceholderMapper`
4180 // Returning `null` means that no name mapping is used.
4181 createNameMapper(message) { return null; }
4182}
4183/**
4184 * A simple mapper that take a function to transform an internal name to a public name
4185 */
4186class SimplePlaceholderMapper extends RecurseVisitor {
4187 // create a mapping from the message
4188 constructor(message, mapName) {
4189 super();
4190 this.mapName = mapName;
4191 this.internalToPublic = {};
4192 this.publicToNextId = {};
4193 this.publicToInternal = {};
4194 message.nodes.forEach(node => node.visit(this));
4195 }
4196 toPublicName(internalName) {
4197 return this.internalToPublic.hasOwnProperty(internalName) ?
4198 this.internalToPublic[internalName] :
4199 null;
4200 }
4201 toInternalName(publicName) {
4202 return this.publicToInternal.hasOwnProperty(publicName) ? this.publicToInternal[publicName] :
4203 null;
4204 }
4205 visitText(text, context) { return null; }
4206 visitTagPlaceholder(ph, context) {
4207 this.visitPlaceholderName(ph.startName);
4208 super.visitTagPlaceholder(ph, context);
4209 this.visitPlaceholderName(ph.closeName);
4210 }
4211 visitPlaceholder(ph, context) { this.visitPlaceholderName(ph.name); }
4212 visitIcuPlaceholder(ph, context) {
4213 this.visitPlaceholderName(ph.name);
4214 }
4215 // XMB placeholders could only contains A-Z, 0-9 and _
4216 visitPlaceholderName(internalName) {
4217 if (!internalName || this.internalToPublic.hasOwnProperty(internalName)) {
4218 return;
4219 }
4220 let publicName = this.mapName(internalName);
4221 if (this.publicToInternal.hasOwnProperty(publicName)) {
4222 // Create a new XMB when it has already been used
4223 const nextId = this.publicToNextId[publicName];
4224 this.publicToNextId[publicName] = nextId + 1;
4225 publicName = `${publicName}_${nextId}`;
4226 }
4227 else {
4228 this.publicToNextId[publicName] = 1;
4229 }
4230 this.internalToPublic[internalName] = publicName;
4231 this.publicToInternal[publicName] = internalName;
4232 }
4233}
4234
4235/**
4236 * @license
4237 * Copyright Google Inc. All Rights Reserved.
4238 *
4239 * Use of this source code is governed by an MIT-style license that can be
4240 * found in the LICENSE file at https://angular.io/license
4241 */
4242class _Visitor {
4243 visitTag(tag) {
4244 const strAttrs = this._serializeAttributes(tag.attrs);
4245 if (tag.children.length == 0) {
4246 return `<${tag.name}${strAttrs}/>`;
4247 }
4248 const strChildren = tag.children.map(node => node.visit(this));
4249 return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`;
4250 }
4251 visitText(text) { return text.value; }
4252 visitDeclaration(decl) {
4253 return `<?xml${this._serializeAttributes(decl.attrs)} ?>`;
4254 }
4255 _serializeAttributes(attrs) {
4256 const strAttrs = Object.keys(attrs).map((name) => `${name}="${attrs[name]}"`).join(' ');
4257 return strAttrs.length > 0 ? ' ' + strAttrs : '';
4258 }
4259 visitDoctype(doctype) {
4260 return `<!DOCTYPE ${doctype.rootTag} [\n${doctype.dtd}\n]>`;
4261 }
4262}
4263const _visitor = new _Visitor();
4264function serialize(nodes) {
4265 return nodes.map((node) => node.visit(_visitor)).join('');
4266}
4267class Declaration {
4268 constructor(unescapedAttrs) {
4269 this.attrs = {};
4270 Object.keys(unescapedAttrs).forEach((k) => {
4271 this.attrs[k] = escapeXml(unescapedAttrs[k]);
4272 });
4273 }
4274 visit(visitor) { return visitor.visitDeclaration(this); }
4275}
4276class Doctype {
4277 constructor(rootTag, dtd) {
4278 this.rootTag = rootTag;
4279 this.dtd = dtd;
4280 }
4281 visit(visitor) { return visitor.visitDoctype(this); }
4282}
4283class Tag {
4284 constructor(name, unescapedAttrs = {}, children = []) {
4285 this.name = name;
4286 this.children = children;
4287 this.attrs = {};
4288 Object.keys(unescapedAttrs).forEach((k) => {
4289 this.attrs[k] = escapeXml(unescapedAttrs[k]);
4290 });
4291 }
4292 visit(visitor) { return visitor.visitTag(this); }
4293}
4294class Text$2 {
4295 constructor(unescapedValue) { this.value = escapeXml(unescapedValue); }
4296 visit(visitor) { return visitor.visitText(this); }
4297}
4298class CR extends Text$2 {
4299 constructor(ws = 0) { super(`\n${new Array(ws + 1).join(' ')}`); }
4300}
4301const _ESCAPED_CHARS = [
4302 [/&/g, '&amp;'],
4303 [/"/g, '&quot;'],
4304 [/'/g, '&apos;'],
4305 [/</g, '&lt;'],
4306 [/>/g, '&gt;'],
4307];
4308// Escape `_ESCAPED_CHARS` characters in the given text with encoded entities
4309function escapeXml(text) {
4310 return _ESCAPED_CHARS.reduce((text, entry) => text.replace(entry[0], entry[1]), text);
4311}
4312
4313/**
4314 * @license
4315 * Copyright Google Inc. All Rights Reserved.
4316 *
4317 * Use of this source code is governed by an MIT-style license that can be
4318 * found in the LICENSE file at https://angular.io/license
4319 */
4320const _MESSAGES_TAG = 'messagebundle';
4321const _MESSAGE_TAG = 'msg';
4322const _PLACEHOLDER_TAG = 'ph';
4323const _EXAMPLE_TAG = 'ex';
4324const _SOURCE_TAG = 'source';
4325const _DOCTYPE = `<!ELEMENT messagebundle (msg)*>
4326<!ATTLIST messagebundle class CDATA #IMPLIED>
4327
4328<!ELEMENT msg (#PCDATA|ph|source)*>
4329<!ATTLIST msg id CDATA #IMPLIED>
4330<!ATTLIST msg seq CDATA #IMPLIED>
4331<!ATTLIST msg name CDATA #IMPLIED>
4332<!ATTLIST msg desc CDATA #IMPLIED>
4333<!ATTLIST msg meaning CDATA #IMPLIED>
4334<!ATTLIST msg obsolete (obsolete) #IMPLIED>
4335<!ATTLIST msg xml:space (default|preserve) "default">
4336<!ATTLIST msg is_hidden CDATA #IMPLIED>
4337
4338<!ELEMENT source (#PCDATA)>
4339
4340<!ELEMENT ph (#PCDATA|ex)*>
4341<!ATTLIST ph name CDATA #REQUIRED>
4342
4343<!ELEMENT ex (#PCDATA)>`;
4344class Xmb extends Serializer {
4345 write(messages, locale) {
4346 const exampleVisitor = new ExampleVisitor();
4347 const visitor = new _Visitor$1();
4348 let rootNode = new Tag(_MESSAGES_TAG);
4349 messages.forEach(message => {
4350 const attrs = { id: message.id };
4351 if (message.description) {
4352 attrs['desc'] = message.description;
4353 }
4354 if (message.meaning) {
4355 attrs['meaning'] = message.meaning;
4356 }
4357 let sourceTags = [];
4358 message.sources.forEach((source) => {
4359 sourceTags.push(new Tag(_SOURCE_TAG, {}, [
4360 new Text$2(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)
4361 ]));
4362 });
4363 rootNode.children.push(new CR(2), new Tag(_MESSAGE_TAG, attrs, [...sourceTags, ...visitor.serialize(message.nodes)]));
4364 });
4365 rootNode.children.push(new CR());
4366 return serialize([
4367 new Declaration({ version: '1.0', encoding: 'UTF-8' }),
4368 new CR(),
4369 new Doctype(_MESSAGES_TAG, _DOCTYPE),
4370 new CR(),
4371 exampleVisitor.addDefaultExamples(rootNode),
4372 new CR(),
4373 ]);
4374 }
4375 load(content, url) {
4376 throw new Error('Unsupported');
4377 }
4378 digest(message) { return digest$1(message); }
4379 createNameMapper(message) {
4380 return new SimplePlaceholderMapper(message, toPublicName);
4381 }
4382}
4383class _Visitor$1 {
4384 visitText(text, context) { return [new Text$2(text.value)]; }
4385 visitContainer(container, context) {
4386 const nodes = [];
4387 container.children.forEach((node) => nodes.push(...node.visit(this)));
4388 return nodes;
4389 }
4390 visitIcu(icu, context) {
4391 const nodes = [new Text$2(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
4392 Object.keys(icu.cases).forEach((c) => {
4393 nodes.push(new Text$2(`${c} {`), ...icu.cases[c].visit(this), new Text$2(`} `));
4394 });
4395 nodes.push(new Text$2(`}`));
4396 return nodes;
4397 }
4398 visitTagPlaceholder(ph, context) {
4399 const startTagAsText = new Text$2(`<${ph.tag}>`);
4400 const startEx = new Tag(_EXAMPLE_TAG, {}, [startTagAsText]);
4401 // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
4402 const startTagPh = new Tag(_PLACEHOLDER_TAG, { name: ph.startName }, [startEx, startTagAsText]);
4403 if (ph.isVoid) {
4404 // void tags have no children nor closing tags
4405 return [startTagPh];
4406 }
4407 const closeTagAsText = new Text$2(`</${ph.tag}>`);
4408 const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeTagAsText]);
4409 // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
4410 const closeTagPh = new Tag(_PLACEHOLDER_TAG, { name: ph.closeName }, [closeEx, closeTagAsText]);
4411 return [startTagPh, ...this.serialize(ph.children), closeTagPh];
4412 }
4413 visitPlaceholder(ph, context) {
4414 const interpolationAsText = new Text$2(`{{${ph.value}}}`);
4415 // Example tag needs to be not-empty for TC.
4416 const exTag = new Tag(_EXAMPLE_TAG, {}, [interpolationAsText]);
4417 return [
4418 // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
4419 new Tag(_PLACEHOLDER_TAG, { name: ph.name }, [exTag, interpolationAsText])
4420 ];
4421 }
4422 visitIcuPlaceholder(ph, context) {
4423 const icuExpression = ph.value.expression;
4424 const icuType = ph.value.type;
4425 const icuCases = Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' ');
4426 const icuAsText = new Text$2(`{${icuExpression}, ${icuType}, ${icuCases}}`);
4427 const exTag = new Tag(_EXAMPLE_TAG, {}, [icuAsText]);
4428 return [
4429 // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
4430 new Tag(_PLACEHOLDER_TAG, { name: ph.name }, [exTag, icuAsText])
4431 ];
4432 }
4433 serialize(nodes) {
4434 return [].concat(...nodes.map(node => node.visit(this)));
4435 }
4436}
4437function digest$1(message) {
4438 return decimalDigest(message);
4439}
4440// TC requires at least one non-empty example on placeholders
4441class ExampleVisitor {
4442 addDefaultExamples(node) {
4443 node.visit(this);
4444 return node;
4445 }
4446 visitTag(tag) {
4447 if (tag.name === _PLACEHOLDER_TAG) {
4448 if (!tag.children || tag.children.length == 0) {
4449 const exText = new Text$2(tag.attrs['name'] || '...');
4450 tag.children = [new Tag(_EXAMPLE_TAG, {}, [exText])];
4451 }
4452 }
4453 else if (tag.children) {
4454 tag.children.forEach(node => node.visit(this));
4455 }
4456 }
4457 visitText(text) { }
4458 visitDeclaration(decl) { }
4459 visitDoctype(doctype) { }
4460}
4461// XMB/XTB placeholders can only contain A-Z, 0-9 and _
4462function toPublicName(internalName) {
4463 return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_');
4464}
4465
4466/**
4467 * @license
4468 * Copyright Google Inc. All Rights Reserved.
4469 *
4470 * Use of this source code is governed by an MIT-style license that can be
4471 * found in the LICENSE file at https://angular.io/license
4472 */
4473function mapEntry(key, value) {
4474 return { key, value, quoted: false };
4475}
4476function mapLiteral(obj, quoted = false) {
4477 return literalMap(Object.keys(obj).map(key => ({
4478 key,
4479 quoted,
4480 value: obj[key],
4481 })));
4482}
4483
4484/**
4485 * @license
4486 * Copyright Google Inc. All Rights Reserved.
4487 *
4488 * Use of this source code is governed by an MIT-style license that can be
4489 * found in the LICENSE file at https://angular.io/license
4490 */
4491/* Closure variables holding messages must be named `MSG_[A-Z0-9]+` */
4492const CLOSURE_TRANSLATION_PREFIX = 'MSG_';
4493/* Prefix for non-`goog.getMsg` i18n-related vars */
4494const TRANSLATION_PREFIX = 'I18N_';
4495/** Closure uses `goog.getMsg(message)` to lookup translations */
4496const GOOG_GET_MSG = 'goog.getMsg';
4497/** Name of the global variable that is used to determine if we use Closure translations or not */
4498const NG_I18N_CLOSURE_MODE = 'ngI18nClosureMode';
4499/** I18n separators for metadata **/
4500const I18N_MEANING_SEPARATOR = '|';
4501const I18N_ID_SEPARATOR = '@@';
4502/** Name of the i18n attributes **/
4503const I18N_ATTR = 'i18n';
4504const I18N_ATTR_PREFIX = 'i18n-';
4505/** Prefix of var expressions used in ICUs */
4506const I18N_ICU_VAR_PREFIX = 'VAR_';
4507/** Prefix of ICU expressions for post processing */
4508const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
4509/** Placeholder wrapper for i18n expressions **/
4510const I18N_PLACEHOLDER_SYMBOL = '�';
4511function i18nTranslationToDeclStmt(variable$1, closureVar, message, meta, params) {
4512 const statements = [];
4513 // var I18N_X;
4514 statements.push(new DeclareVarStmt(variable$1.name, undefined, INFERRED_TYPE, null, variable$1.sourceSpan));
4515 const args = [literal(message)];
4516 if (params && Object.keys(params).length) {
4517 args.push(mapLiteral(params, true));
4518 }
4519 // Closure JSDoc comments
4520 const docStatements = i18nMetaToDocStmt(meta);
4521 const thenStatements = docStatements ? [docStatements] : [];
4522 const googFnCall = variable(GOOG_GET_MSG).callFn(args);
4523 // const MSG_... = goog.getMsg(..);
4524 thenStatements.push(closureVar.set(googFnCall).toConstDecl());
4525 // I18N_X = MSG_...;
4526 thenStatements.push(new ExpressionStatement(variable$1.set(closureVar)));
4527 const localizeFnCall = importExpr(Identifiers$1.i18nLocalize).callFn(args);
4528 // I18N_X = i18nLocalize(...);
4529 const elseStatements = [new ExpressionStatement(variable$1.set(localizeFnCall))];
4530 // if(ngI18nClosureMode) { ... } else { ... }
4531 statements.push(ifStmt(variable(NG_I18N_CLOSURE_MODE), thenStatements, elseStatements));
4532 return statements;
4533}
4534// Converts i18n meta information for a message (id, description, meaning)
4535// to a JsDoc statement formatted as expected by the Closure compiler.
4536function i18nMetaToDocStmt(meta) {
4537 const tags = [];
4538 if (meta.description) {
4539 tags.push({ tagName: "desc" /* Desc */, text: meta.description });
4540 }
4541 if (meta.meaning) {
4542 tags.push({ tagName: "meaning" /* Meaning */, text: meta.meaning });
4543 }
4544 return tags.length == 0 ? null : new JSDocCommentStmt(tags);
4545}
4546function isI18nAttribute(name) {
4547 return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
4548}
4549function isI18nRootNode(meta) {
4550 return meta instanceof Message;
4551}
4552function isSingleI18nIcu(meta) {
4553 return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu$1;
4554}
4555function hasI18nAttrs(element) {
4556 return element.attrs.some((attr) => isI18nAttribute(attr.name));
4557}
4558function metaFromI18nMessage(message, id = null) {
4559 return {
4560 id: typeof id === 'string' ? id : message.id || '',
4561 meaning: message.meaning || '',
4562 description: message.description || ''
4563 };
4564}
4565function icuFromI18nMessage(message) {
4566 return message.nodes[0];
4567}
4568function wrapI18nPlaceholder(content, contextId = 0) {
4569 const blockId = contextId > 0 ? `:${contextId}` : '';
4570 return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`;
4571}
4572function assembleI18nBoundString(strings, bindingStartIndex = 0, contextId = 0) {
4573 if (!strings.length)
4574 return '';
4575 let acc = '';
4576 const lastIdx = strings.length - 1;
4577 for (let i = 0; i < lastIdx; i++) {
4578 acc += `${strings[i]}${wrapI18nPlaceholder(bindingStartIndex + i, contextId)}`;
4579 }
4580 acc += strings[lastIdx];
4581 return acc;
4582}
4583function getSeqNumberGenerator(startsAt = 0) {
4584 let current = startsAt;
4585 return () => current++;
4586}
4587function placeholdersToParams(placeholders) {
4588 const params = {};
4589 placeholders.forEach((values, key) => {
4590 params[key] = literal(values.length > 1 ? `[${values.join('|')}]` : values[0]);
4591 });
4592 return params;
4593}
4594function updatePlaceholderMap(map, name, ...values) {
4595 const current = map.get(name) || [];
4596 current.push(...values);
4597 map.set(name, current);
4598}
4599function assembleBoundTextPlaceholders(meta, bindingStartIndex = 0, contextId = 0) {
4600 const startIdx = bindingStartIndex;
4601 const placeholders = new Map();
4602 const node = meta instanceof Message ? meta.nodes.find(node => node instanceof Container) : meta;
4603 if (node) {
4604 node
4605 .children
4606 .filter((child) => child instanceof Placeholder)
4607 .forEach((child, idx) => {
4608 const content = wrapI18nPlaceholder(startIdx + idx, contextId);
4609 updatePlaceholderMap(placeholders, child.name, content);
4610 });
4611 }
4612 return placeholders;
4613}
4614function findIndex(items, callback) {
4615 for (let i = 0; i < items.length; i++) {
4616 if (callback(items[i])) {
4617 return i;
4618 }
4619 }
4620 return -1;
4621}
4622/**
4623 * Parses i18n metas like:
4624 * - "@@id",
4625 * - "description[@@id]",
4626 * - "meaning|description[@@id]"
4627 * and returns an object with parsed output.
4628 *
4629 * @param meta String that represents i18n meta
4630 * @returns Object with id, meaning and description fields
4631 */
4632function parseI18nMeta(meta) {
4633 let id;
4634 let meaning;
4635 let description;
4636 if (meta) {
4637 const idIndex = meta.indexOf(I18N_ID_SEPARATOR);
4638 const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
4639 let meaningAndDesc;
4640 [meaningAndDesc, id] =
4641 (idIndex > -1) ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''];
4642 [meaning, description] = (descIndex > -1) ?
4643 [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
4644 ['', meaningAndDesc];
4645 }
4646 return { id, meaning, description };
4647}
4648/**
4649 * Converts internal placeholder names to public-facing format
4650 * (for example to use in goog.getMsg call).
4651 * Example: `START_TAG_DIV_1` is converted to `startTagDiv_1`.
4652 *
4653 * @param name The placeholder name that should be formatted
4654 * @returns Formatted placeholder name
4655 */
4656function formatI18nPlaceholderName(name, useCamelCase = true) {
4657 const publicName = toPublicName(name);
4658 if (!useCamelCase) {
4659 return publicName;
4660 }
4661 const chunks = publicName.split('_');
4662 if (chunks.length === 1) {
4663 // if no "_" found - just lowercase the value
4664 return name.toLowerCase();
4665 }
4666 let postfix;
4667 // eject last element if it's a number
4668 if (/^\d+$/.test(chunks[chunks.length - 1])) {
4669 postfix = chunks.pop();
4670 }
4671 let raw = chunks.shift().toLowerCase();
4672 if (chunks.length) {
4673 raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join('');
4674 }
4675 return postfix ? `${raw}_${postfix}` : raw;
4676}
4677/**
4678 * Generates a prefix for translation const name.
4679 *
4680 * @param extra Additional local prefix that should be injected into translation var name
4681 * @returns Complete translation const prefix
4682 */
4683function getTranslationConstPrefix(extra) {
4684 return `${CLOSURE_TRANSLATION_PREFIX}${extra}`.toUpperCase();
4685}
4686/**
4687 * Generates translation declaration statements.
4688 *
4689 * @param variable Translation value reference
4690 * @param closureVar Variable for Closure `goog.getMsg` calls
4691 * @param message Text message to be translated
4692 * @param meta Object that contains meta information (id, meaning and description)
4693 * @param params Object with placeholders key-value pairs
4694 * @param transformFn Optional transformation (post processing) function reference
4695 * @returns Array of Statements that represent a given translation
4696 */
4697function getTranslationDeclStmts(variable, closureVar, message, meta, params = {}, transformFn) {
4698 const statements = [];
4699 statements.push(...i18nTranslationToDeclStmt(variable, closureVar, message, meta, params));
4700 if (transformFn) {
4701 statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
4702 }
4703 return statements;
4704}
4705
4706/**
4707 * @license
4708 * Copyright Google Inc. All Rights Reserved.
4709 *
4710 * Use of this source code is governed by an MIT-style license that can be
4711 * found in the LICENSE file at https://angular.io/license
4712 */
4713/**
4714 * Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in
4715 * quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may
4716 * bot work in some cases when object keys are mangled by minifier.
4717 *
4718 * TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with
4719 * inputs that contain potentially unsafe chars.
4720 */
4721const UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/;
4722/** Name of the temporary to use during data binding */
4723const TEMPORARY_NAME = '_t';
4724/** Name of the context parameter passed into a template function */
4725const CONTEXT_NAME = 'ctx';
4726/** Name of the RenderFlag passed into a template function */
4727const RENDER_FLAGS = 'rf';
4728/** The prefix reference variables */
4729const REFERENCE_PREFIX = '_r';
4730/** The name of the implicit context reference */
4731const IMPLICIT_REFERENCE = '$implicit';
4732/** Non bindable attribute name **/
4733const NON_BINDABLE_ATTR = 'ngNonBindable';
4734/**
4735 * Creates an allocator for a temporary variable.
4736 *
4737 * A variable declaration is added to the statements the first time the allocator is invoked.
4738 */
4739function temporaryAllocator(statements, name) {
4740 let temp = null;
4741 return () => {
4742 if (!temp) {
4743 statements.push(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE));
4744 temp = variable(name);
4745 }
4746 return temp;
4747 };
4748}
4749function unsupported(feature) {
4750 if (this) {
4751 throw new Error(`Builder ${this.constructor.name} doesn't support ${feature} yet`);
4752 }
4753 throw new Error(`Feature ${feature} is not supported yet`);
4754}
4755function invalid$1(arg) {
4756 throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
4757}
4758function asLiteral(value) {
4759 if (Array.isArray(value)) {
4760 return literalArr(value.map(asLiteral));
4761 }
4762 return literal(value, INFERRED_TYPE);
4763}
4764function conditionallyCreateMapObjectLiteral(keys, keepDeclared) {
4765 if (Object.getOwnPropertyNames(keys).length > 0) {
4766 return mapToExpression(keys, keepDeclared);
4767 }
4768 return null;
4769}
4770function mapToExpression(map, keepDeclared) {
4771 return literalMap(Object.getOwnPropertyNames(map).map(key => {
4772 // canonical syntax: `dirProp: publicProp`
4773 // if there is no `:`, use dirProp = elProp
4774 const value = map[key];
4775 let declaredName;
4776 let publicName;
4777 let minifiedName;
4778 if (Array.isArray(value)) {
4779 [publicName, declaredName] = value;
4780 }
4781 else {
4782 [declaredName, publicName] = splitAtColon(key, [key, value]);
4783 }
4784 minifiedName = declaredName;
4785 return {
4786 key: minifiedName,
4787 // put quotes around keys that contain potentially unsafe characters
4788 quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName),
4789 value: (keepDeclared && publicName !== declaredName) ?
4790 literalArr([asLiteral(publicName), asLiteral(declaredName)]) :
4791 asLiteral(publicName)
4792 };
4793 }));
4794}
4795/**
4796 * Remove trailing null nodes as they are implied.
4797 */
4798function trimTrailingNulls(parameters) {
4799 while (isNull(parameters[parameters.length - 1])) {
4800 parameters.pop();
4801 }
4802 return parameters;
4803}
4804function getQueryPredicate(query, constantPool) {
4805 if (Array.isArray(query.predicate)) {
4806 let predicate = [];
4807 query.predicate.forEach((selector) => {
4808 // Each item in predicates array may contain strings with comma-separated refs
4809 // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them
4810 // as separate array entities
4811 const selectors = selector.split(',').map(token => literal(token.trim()));
4812 predicate.push(...selectors);
4813 });
4814 return constantPool.getConstLiteral(literalArr(predicate), true);
4815 }
4816 else {
4817 return query.predicate;
4818 }
4819}
4820function noop() { }
4821class DefinitionMap {
4822 constructor() {
4823 this.values = [];
4824 }
4825 set(key, value) {
4826 if (value) {
4827 this.values.push({ key, value, quoted: false });
4828 }
4829 }
4830 toLiteralMap() { return literalMap(this.values); }
4831}
4832/**
4833 * Extract a map of properties to values for a given element or template node, which can be used
4834 * by the directive matching machinery.
4835 *
4836 * @param elOrTpl the element or template in question
4837 * @return an object set up for directive matching. For attributes on the element/template, this
4838 * object maps a property name to its (static) value. For any bindings, this map simply maps the
4839 * property name to an empty string.
4840 */
4841function getAttrsForDirectiveMatching(elOrTpl) {
4842 const attributesMap = {};
4843 if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') {
4844 elOrTpl.templateAttrs.forEach(a => attributesMap[a.name] = '');
4845 }
4846 else {
4847 elOrTpl.attributes.forEach(a => {
4848 if (!isI18nAttribute(a.name)) {
4849 attributesMap[a.name] = a.value;
4850 }
4851 });
4852 elOrTpl.inputs.forEach(i => { attributesMap[i.name] = ''; });
4853 elOrTpl.outputs.forEach(o => { attributesMap[o.name] = ''; });
4854 }
4855 return attributesMap;
4856}
4857/** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */
4858function chainedInstruction(reference, calls, span) {
4859 let expression = importExpr(reference, null, span);
4860 if (calls.length > 0) {
4861 for (let i = 0; i < calls.length; i++) {
4862 expression = expression.callFn(calls[i], span);
4863 }
4864 }
4865 else {
4866 // Add a blank invocation, in case the `calls` array is empty.
4867 expression = expression.callFn([], span);
4868 }
4869 return expression;
4870}
4871/**
4872 * Gets the number of arguments expected to be passed to a generated instruction in the case of
4873 * interpolation instructions.
4874 * @param interpolation An interpolation ast
4875 */
4876function getInterpolationArgsLength(interpolation) {
4877 const { expressions, strings } = interpolation;
4878 if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
4879 // If the interpolation has one interpolated value, but the prefix and suffix are both empty
4880 // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
4881 // `textInterpolate`.
4882 return 1;
4883 }
4884 else {
4885 return expressions.length + strings.length;
4886 }
4887}
4888
4889/**
4890 * @license
4891 * Copyright Google Inc. All Rights Reserved.
4892 *
4893 * Use of this source code is governed by an MIT-style license that can be
4894 * found in the LICENSE file at https://angular.io/license
4895 */
4896var R3FactoryDelegateType;
4897(function (R3FactoryDelegateType) {
4898 R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class";
4899 R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function";
4900 R3FactoryDelegateType[R3FactoryDelegateType["Factory"] = 2] = "Factory";
4901})(R3FactoryDelegateType || (R3FactoryDelegateType = {}));
4902/**
4903 * Resolved type of a dependency.
4904 *
4905 * Occasionally, dependencies will have special significance which is known statically. In that
4906 * case the `R3ResolvedDependencyType` informs the factory generator that a particular dependency
4907 * should be generated specially (usually by calling a special injection function instead of the
4908 * standard one).
4909 */
4910var R3ResolvedDependencyType;
4911(function (R3ResolvedDependencyType) {
4912 /**
4913 * A normal token dependency.
4914 */
4915 R3ResolvedDependencyType[R3ResolvedDependencyType["Token"] = 0] = "Token";
4916 /**
4917 * The dependency is for an attribute.
4918 *
4919 * The token expression is a string representing the attribute name.
4920 */
4921 R3ResolvedDependencyType[R3ResolvedDependencyType["Attribute"] = 1] = "Attribute";
4922 /**
4923 * Injecting the `ChangeDetectorRef` token. Needs special handling when injected into a pipe.
4924 */
4925 R3ResolvedDependencyType[R3ResolvedDependencyType["ChangeDetectorRef"] = 2] = "ChangeDetectorRef";
4926})(R3ResolvedDependencyType || (R3ResolvedDependencyType = {}));
4927/**
4928 * Construct a factory function expression for the given `R3FactoryMetadata`.
4929 */
4930function compileFactoryFunction(meta, isPipe = false) {
4931 const t = variable('t');
4932 const statements = [];
4933 // The type to instantiate via constructor invocation. If there is no delegated factory, meaning
4934 // this type is always created by constructor invocation, then this is the type-to-create
4935 // parameter provided by the user (t) if specified, or the current type if not. If there is a
4936 // delegated factory (which is used to create the current type) then this is only the type-to-
4937 // create parameter (t).
4938 const typeForCtor = !isDelegatedMetadata(meta) ? new BinaryOperatorExpr(BinaryOperator.Or, t, meta.type) : t;
4939 let ctorExpr = null;
4940 if (meta.deps !== null) {
4941 // There is a constructor (either explicitly or implicitly defined).
4942 if (meta.deps !== 'invalid') {
4943 ctorExpr =
4944 new InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.injectFn, isPipe));
4945 }
4946 }
4947 else {
4948 const baseFactory = variable(${meta.name}_BaseFactory`);
4949 const getInheritedFactory = importExpr(Identifiers$1.getInheritedFactory);
4950 const baseFactoryStmt = baseFactory.set(getInheritedFactory.callFn([meta.type])).toDeclStmt(INFERRED_TYPE, [
4951 StmtModifier.Exported, StmtModifier.Final
4952 ]);
4953 statements.push(baseFactoryStmt);
4954 // There is no constructor, use the base class' factory to construct typeForCtor.
4955 ctorExpr = baseFactory.callFn([typeForCtor]);
4956 }
4957 const ctorExprFinal = ctorExpr;
4958 const body = [];
4959 let retExpr = null;
4960 function makeConditionalFactory(nonCtorExpr) {
4961 const r = variable('r');
4962 body.push(r.set(NULL_EXPR).toDeclStmt());
4963 let ctorStmt = null;
4964 if (ctorExprFinal !== null) {
4965 ctorStmt = r.set(ctorExprFinal).toStmt();
4966 }
4967 else {
4968 ctorStmt = makeErrorStmt(meta.name);
4969 }
4970 body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()]));
4971 return r;
4972 }
4973 if (isDelegatedMetadata(meta) && meta.delegateType === R3FactoryDelegateType.Factory) {
4974 const delegateFactory = variable(${meta.name}_BaseFactory`);
4975 const getFactoryOf = importExpr(Identifiers$1.getFactoryOf);
4976 if (meta.delegate.isEquivalent(meta.type)) {
4977 throw new Error(`Illegal state: compiling factory that delegates to itself`);
4978 }
4979 const delegateFactoryStmt = delegateFactory.set(getFactoryOf.callFn([meta.delegate])).toDeclStmt(INFERRED_TYPE, [
4980 StmtModifier.Exported, StmtModifier.Final
4981 ]);
4982 statements.push(delegateFactoryStmt);
4983 retExpr = makeConditionalFactory(delegateFactory.callFn([]));
4984 }
4985 else if (isDelegatedMetadata(meta)) {
4986 // This type is created with a delegated factory. If a type parameter is not specified, call
4987 // the factory instead.
4988 const delegateArgs = injectDependencies(meta.delegateDeps, meta.injectFn, isPipe);
4989 // Either call `new delegate(...)` or `delegate(...)` depending on meta.useNewForDelegate.
4990 const factoryExpr = new (meta.delegateType === R3FactoryDelegateType.Class ?
4991 InstantiateExpr :
4992 InvokeFunctionExpr)(meta.delegate, delegateArgs);
4993 retExpr = makeConditionalFactory(factoryExpr);
4994 }
4995 else if (isExpressionFactoryMetadata(meta)) {
4996 // TODO(alxhub): decide whether to lower the value here or in the caller
4997 retExpr = makeConditionalFactory(meta.expression);
4998 }
4999 else {
5000 retExpr = ctorExpr;
5001 }
5002 if (retExpr !== null) {
5003 body.push(new ReturnStatement(retExpr));
5004 }
5005 else {
5006 body.push(makeErrorStmt(meta.name));
5007 }
5008 return {
5009 factory: fn([new FnParam('t', DYNAMIC_TYPE)], body, INFERRED_TYPE, undefined, `${meta.name}_Factory`),
5010 statements,
5011 };
5012}
5013function injectDependencies(deps, injectFn, isPipe) {
5014 return deps.map(dep => compileInjectDependency(dep, injectFn, isPipe));
5015}
5016function compileInjectDependency(dep, injectFn, isPipe) {
5017 // Interpret the dependency according to its resolved type.
5018 switch (dep.resolved) {
5019 case R3ResolvedDependencyType.Token:
5020 case R3ResolvedDependencyType.ChangeDetectorRef:
5021 // Build up the injection flags according to the metadata.
5022 const flags = 0 /* Default */ | (dep.self ? 2 /* Self */ : 0) |
5023 (dep.skipSelf ? 4 /* SkipSelf */ : 0) | (dep.host ? 1 /* Host */ : 0) |
5024 (dep.optional ? 8 /* Optional */ : 0);
5025 // If this dependency is optional or otherwise has non-default flags, then additional
5026 // parameters describing how to inject the dependency must be passed to the inject function
5027 // that's being used.
5028 let flagsParam = (flags !== 0 /* Default */ || dep.optional) ? literal(flags) : null;
5029 // We have a separate instruction for injecting ChangeDetectorRef into a pipe.
5030 if (isPipe && dep.resolved === R3ResolvedDependencyType.ChangeDetectorRef) {
5031 return importExpr(Identifiers$1.injectPipeChangeDetectorRef).callFn(flagsParam ? [flagsParam] : []);
5032 }
5033 // Build up the arguments to the injectFn call.
5034 const injectArgs = [dep.token];
5035 if (flagsParam) {
5036 injectArgs.push(flagsParam);
5037 }
5038 return importExpr(injectFn).callFn(injectArgs);
5039 case R3ResolvedDependencyType.Attribute:
5040 // In the case of attributes, the attribute name in question is given as the token.
5041 return importExpr(Identifiers$1.injectAttribute).callFn([dep.token]);
5042 default:
5043 return unsupported(`Unknown R3ResolvedDependencyType: ${R3ResolvedDependencyType[dep.resolved]}`);
5044 }
5045}
5046/**
5047 * A helper function useful for extracting `R3DependencyMetadata` from a Render2
5048 * `CompileTypeMetadata` instance.
5049 */
5050function dependenciesFromGlobalMetadata(type, outputCtx, reflector) {
5051 // Use the `CompileReflector` to look up references to some well-known Angular types. These will
5052 // be compared with the token to statically determine whether the token has significance to
5053 // Angular, and set the correct `R3ResolvedDependencyType` as a result.
5054 const injectorRef = reflector.resolveExternalReference(Identifiers.Injector);
5055 // Iterate through the type's DI dependencies and produce `R3DependencyMetadata` for each of them.
5056 const deps = [];
5057 for (let dependency of type.diDeps) {
5058 if (dependency.token) {
5059 const tokenRef = tokenReference(dependency.token);
5060 let resolved = dependency.isAttribute ?
5061 R3ResolvedDependencyType.Attribute :
5062 R3ResolvedDependencyType.Token;
5063 // In the case of most dependencies, the token will be a reference to a type. Sometimes,
5064 // however, it can be a string, in the case of older Angular code or @Attribute injection.
5065 const token = tokenRef instanceof StaticSymbol ? outputCtx.importExpr(tokenRef) : literal(tokenRef);
5066 // Construct the dependency.
5067 deps.push({
5068 token,
5069 resolved,
5070 host: !!dependency.isHost,
5071 optional: !!dependency.isOptional,
5072 self: !!dependency.isSelf,
5073 skipSelf: !!dependency.isSkipSelf,
5074 });
5075 }
5076 else {
5077 unsupported('dependency without a token');
5078 }
5079 }
5080 return deps;
5081}
5082function makeErrorStmt(name) {
5083 return new ThrowStmt(new InstantiateExpr(new ReadVarExpr('Error'), [
5084 literal(`${name} has a constructor which is not compatible with Dependency Injection. It should probably not be @Injectable().`)
5085 ]));
5086}
5087function isDelegatedMetadata(meta) {
5088 return meta.delegateType !== undefined;
5089}
5090function isExpressionFactoryMetadata(meta) {
5091 return meta.expression !== undefined;
5092}
5093
5094/**
5095 * @license
5096 * Copyright Google Inc. All Rights Reserved.
5097 *
5098 * Use of this source code is governed by an MIT-style license that can be
5099 * found in the LICENSE file at https://angular.io/license
5100 */
5101/**
5102 * Convert an object map with `Expression` values into a `LiteralMapExpr`.
5103 */
5104function mapToMapExpression(map) {
5105 const result = Object.keys(map).map(key => ({ key, value: map[key], quoted: false }));
5106 return literalMap(result);
5107}
5108/**
5109 * Convert metadata into an `Expression` in the given `OutputContext`.
5110 *
5111 * This operation will handle arrays, references to symbols, or literal `null` or `undefined`.
5112 */
5113function convertMetaToOutput(meta, ctx) {
5114 if (Array.isArray(meta)) {
5115 return literalArr(meta.map(entry => convertMetaToOutput(entry, ctx)));
5116 }
5117 if (meta instanceof StaticSymbol) {
5118 return ctx.importExpr(meta);
5119 }
5120 if (meta == null) {
5121 return literal(meta);
5122 }
5123 throw new Error(`Internal error: Unsupported or unknown metadata: ${meta}`);
5124}
5125function typeWithParameters(type, numParams) {
5126 let params = null;
5127 if (numParams > 0) {
5128 params = [];
5129 for (let i = 0; i < numParams; i++) {
5130 params.push(DYNAMIC_TYPE);
5131 }
5132 }
5133 return expressionType(type, null, params);
5134}
5135const ANIMATE_SYMBOL_PREFIX = '@';
5136function prepareSyntheticPropertyName(name) {
5137 return `${ANIMATE_SYMBOL_PREFIX}${name}`;
5138}
5139function prepareSyntheticListenerName(name, phase) {
5140 return `${ANIMATE_SYMBOL_PREFIX}${name}.${phase}`;
5141}
5142function isSyntheticPropertyOrListener(name) {
5143 return name.charAt(0) == ANIMATE_SYMBOL_PREFIX;
5144}
5145function getSyntheticPropertyName(name) {
5146 // this will strip out listener phase values...
5147 // @foo.start => @foo
5148 const i = name.indexOf('.');
5149 name = i > 0 ? name.substring(0, i) : name;
5150 if (name.charAt(0) !== ANIMATE_SYMBOL_PREFIX) {
5151 name = ANIMATE_SYMBOL_PREFIX + name;
5152 }
5153 return name;
5154}
5155function prepareSyntheticListenerFunctionName(name, phase) {
5156 return `animation_${name}_${phase}`;
5157}
5158
5159/**
5160 * @license
5161 * Copyright Google Inc. All Rights Reserved.
5162 *
5163 * Use of this source code is governed by an MIT-style license that can be
5164 * found in the LICENSE file at https://angular.io/license
5165 */
5166function compileInjectable(meta) {
5167 let result = null;
5168 const factoryMeta = {
5169 name: meta.name,
5170 type: meta.type,
5171 deps: meta.ctorDeps,
5172 injectFn: Identifiers.inject,
5173 };
5174 if (meta.useClass !== undefined) {
5175 // meta.useClass has two modes of operation. Either deps are specified, in which case `new` is
5176 // used to instantiate the class with dependencies injected, or deps are not specified and
5177 // the factory of the class is used to instantiate it.
5178 //
5179 // A special case exists for useClass: Type where Type is the injectable type itself and no
5180 // deps are specified, in which case 'useClass' is effectively ignored.
5181 const useClassOnSelf = meta.useClass.isEquivalent(meta.type);
5182 let deps = undefined;
5183 if (meta.userDeps !== undefined) {
5184 deps = meta.userDeps;
5185 }
5186 if (deps !== undefined) {
5187 // factory: () => new meta.useClass(...deps)
5188 result = compileFactoryFunction(Object.assign({}, factoryMeta, { delegate: meta.useClass, delegateDeps: deps, delegateType: R3FactoryDelegateType.Class }));
5189 }
5190 else if (useClassOnSelf) {
5191 result = compileFactoryFunction(factoryMeta);
5192 }
5193 else {
5194 result = compileFactoryFunction(Object.assign({}, factoryMeta, { delegate: meta.useClass, delegateType: R3FactoryDelegateType.Factory }));
5195 }
5196 }
5197 else if (meta.useFactory !== undefined) {
5198 result = compileFactoryFunction(Object.assign({}, factoryMeta, { delegate: meta.useFactory, delegateDeps: meta.userDeps || [], delegateType: R3FactoryDelegateType.Function }));
5199 }
5200 else if (meta.useValue !== undefined) {
5201 // Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for
5202 // client code because meta.useValue is an Expression which will be defined even if the actual
5203 // value is undefined.
5204 result = compileFactoryFunction(Object.assign({}, factoryMeta, { expression: meta.useValue }));
5205 }
5206 else if (meta.useExisting !== undefined) {
5207 // useExisting is an `inject` call on the existing token.
5208 result = compileFactoryFunction(Object.assign({}, factoryMeta, { expression: importExpr(Identifiers.inject).callFn([meta.useExisting]) }));
5209 }
5210 else {
5211 result = compileFactoryFunction(factoryMeta);
5212 }
5213 const token = meta.type;
5214 const providedIn = meta.providedIn;
5215 const expression = importExpr(Identifiers.ɵɵdefineInjectable).callFn([mapToMapExpression({ token, factory: result.factory, providedIn })]);
5216 const type = new ExpressionType(importExpr(Identifiers.InjectableDef, [typeWithParameters(meta.type, meta.typeArgumentCount)]));
5217 return {
5218 expression,
5219 type,
5220 statements: result.statements,
5221 };
5222}
5223
5224/**
5225 * @license
5226 * Copyright Google Inc. All Rights Reserved.
5227 *
5228 * Use of this source code is governed by an MIT-style license that can be
5229 * found in the LICENSE file at https://angular.io/license
5230 */
5231function assertArrayOfStrings(identifier, value) {
5232 if (value == null) {
5233 return;
5234 }
5235 if (!Array.isArray(value)) {
5236 throw new Error(`Expected '${identifier}' to be an array of strings.`);
5237 }
5238 for (let i = 0; i < value.length; i += 1) {
5239 if (typeof value[i] !== 'string') {
5240 throw new Error(`Expected '${identifier}' to be an array of strings.`);
5241 }
5242 }
5243}
5244const UNUSABLE_INTERPOLATION_REGEXPS = [
5245 /^\s*$/,
5246 /[<>]/,
5247 /^[{}]$/,
5248 /&(#|[a-z])/i,
5249 /^\/\//,
5250];
5251function assertInterpolationSymbols(identifier, value) {
5252 if (value != null && !(Array.isArray(value) && value.length == 2)) {
5253 throw new Error(`Expected '${identifier}' to be an array, [start, end].`);
5254 }
5255 else if (value != null) {
5256 const start = value[0];
5257 const end = value[1];
5258 // Check for unusable interpolation symbols
5259 UNUSABLE_INTERPOLATION_REGEXPS.forEach(regexp => {
5260 if (regexp.test(start) || regexp.test(end)) {
5261 throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`);
5262 }
5263 });
5264 }
5265}
5266
5267/**
5268 * @license
5269 * Copyright Google Inc. All Rights Reserved.
5270 *
5271 * Use of this source code is governed by an MIT-style license that can be
5272 * found in the LICENSE file at https://angular.io/license
5273 */
5274class InterpolationConfig {
5275 constructor(start, end) {
5276 this.start = start;
5277 this.end = end;
5278 }
5279 static fromArray(markers) {
5280 if (!markers) {
5281 return DEFAULT_INTERPOLATION_CONFIG;
5282 }
5283 assertInterpolationSymbols('interpolation', markers);
5284 return new InterpolationConfig(markers[0], markers[1]);
5285 }
5286}
5287const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}');
5288
5289/**
5290 * @license
5291 * Copyright Google Inc. All Rights Reserved.
5292 *
5293 * Use of this source code is governed by an MIT-style license that can be
5294 * found in the LICENSE file at https://angular.io/license
5295 */
5296// https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
5297const VERSION = 3;
5298const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,';
5299class SourceMapGenerator {
5300 constructor(file = null) {
5301 this.file = file;
5302 this.sourcesContent = new Map();
5303 this.lines = [];
5304 this.lastCol0 = 0;
5305 this.hasMappings = false;
5306 }
5307 // The content is `null` when the content is expected to be loaded using the URL
5308 addSource(url, content = null) {
5309 if (!this.sourcesContent.has(url)) {
5310 this.sourcesContent.set(url, content);
5311 }
5312 return this;
5313 }
5314 addLine() {
5315 this.lines.push([]);
5316 this.lastCol0 = 0;
5317 return this;
5318 }
5319 addMapping(col0, sourceUrl, sourceLine0, sourceCol0) {
5320 if (!this.currentLine) {
5321 throw new Error(`A line must be added before mappings can be added`);
5322 }
5323 if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) {
5324 throw new Error(`Unknown source file "${sourceUrl}"`);
5325 }
5326 if (col0 == null) {
5327 throw new Error(`The column in the generated code must be provided`);
5328 }
5329 if (col0 < this.lastCol0) {
5330 throw new Error(`Mapping should be added in output order`);
5331 }
5332 if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) {
5333 throw new Error(`The source location must be provided when a source url is provided`);
5334 }
5335 this.hasMappings = true;
5336 this.lastCol0 = col0;
5337 this.currentLine.push({ col0, sourceUrl, sourceLine0, sourceCol0 });
5338 return this;
5339 }
5340 get currentLine() { return this.lines.slice(-1)[0]; }
5341 toJSON() {
5342 if (!this.hasMappings) {
5343 return null;
5344 }
5345 const sourcesIndex = new Map();
5346 const sources = [];
5347 const sourcesContent = [];
5348 Array.from(this.sourcesContent.keys()).forEach((url, i) => {
5349 sourcesIndex.set(url, i);
5350 sources.push(url);
5351 sourcesContent.push(this.sourcesContent.get(url) || null);
5352 });
5353 let mappings = '';
5354 let lastCol0 = 0;
5355 let lastSourceIndex = 0;
5356 let lastSourceLine0 = 0;
5357 let lastSourceCol0 = 0;
5358 this.lines.forEach(segments => {
5359 lastCol0 = 0;
5360 mappings += segments
5361 .map(segment => {
5362 // zero-based starting column of the line in the generated code
5363 let segAsStr = toBase64VLQ(segment.col0 - lastCol0);
5364 lastCol0 = segment.col0;
5365 if (segment.sourceUrl != null) {
5366 // zero-based index into the “sources” list
5367 segAsStr +=
5368 toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex);
5369 lastSourceIndex = sourcesIndex.get(segment.sourceUrl);
5370 // the zero-based starting line in the original source
5371 segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0);
5372 lastSourceLine0 = segment.sourceLine0;
5373 // the zero-based starting column in the original source
5374 segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0);
5375 lastSourceCol0 = segment.sourceCol0;
5376 }
5377 return segAsStr;
5378 })
5379 .join(',');
5380 mappings += ';';
5381 });
5382 mappings = mappings.slice(0, -1);
5383 return {
5384 'file': this.file || '',
5385 'version': VERSION,
5386 'sourceRoot': '',
5387 'sources': sources,
5388 'sourcesContent': sourcesContent,
5389 'mappings': mappings,
5390 };
5391 }
5392 toJsComment() {
5393 return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) :
5394 '';
5395 }
5396}
5397function toBase64String(value) {
5398 let b64 = '';
5399 value = utf8Encode(value);
5400 for (let i = 0; i < value.length;) {
5401 const i1 = value.charCodeAt(i++);
5402 const i2 = value.charCodeAt(i++);
5403 const i3 = value.charCodeAt(i++);
5404 b64 += toBase64Digit(i1 >> 2);
5405 b64 += toBase64Digit(((i1 & 3) << 4) | (isNaN(i2) ? 0 : i2 >> 4));
5406 b64 += isNaN(i2) ? '=' : toBase64Digit(((i2 & 15) << 2) | (i3 >> 6));
5407 b64 += isNaN(i2) || isNaN(i3) ? '=' : toBase64Digit(i3 & 63);
5408 }
5409 return b64;
5410}
5411function toBase64VLQ(value) {
5412 value = value < 0 ? ((-value) << 1) + 1 : value << 1;
5413 let out = '';
5414 do {
5415 let digit = value & 31;
5416 value = value >> 5;
5417 if (value > 0) {
5418 digit = digit | 32;
5419 }
5420 out += toBase64Digit(digit);
5421 } while (value > 0);
5422 return out;
5423}
5424const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
5425function toBase64Digit(value) {
5426 if (value < 0 || value >= 64) {
5427 throw new Error(`Can only encode value in the range [0, 63]`);
5428 }
5429 return B64_DIGITS[value];
5430}
5431
5432/**
5433 * @license
5434 * Copyright Google Inc. All Rights Reserved.
5435 *
5436 * Use of this source code is governed by an MIT-style license that can be
5437 * found in the LICENSE file at https://angular.io/license
5438 */
5439const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
5440const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
5441const _INDENT_WITH = ' ';
5442const CATCH_ERROR_VAR$1 = variable('error', null, null);
5443const CATCH_STACK_VAR$1 = variable('stack', null, null);
5444class _EmittedLine {
5445 constructor(indent) {
5446 this.indent = indent;
5447 this.partsLength = 0;
5448 this.parts = [];
5449 this.srcSpans = [];
5450 }
5451}
5452class EmitterVisitorContext {
5453 constructor(_indent) {
5454 this._indent = _indent;
5455 this._classes = [];
5456 this._preambleLineCount = 0;
5457 this._lines = [new _EmittedLine(_indent)];
5458 }
5459 static createRoot() { return new EmitterVisitorContext(0); }
5460 get _currentLine() { return this._lines[this._lines.length - 1]; }
5461 println(from, lastPart = '') {
5462 this.print(from || null, lastPart, true);
5463 }
5464 lineIsEmpty() { return this._currentLine.parts.length === 0; }
5465 lineLength() {
5466 return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength;
5467 }
5468 print(from, part, newLine = false) {
5469 if (part.length > 0) {
5470 this._currentLine.parts.push(part);
5471 this._currentLine.partsLength += part.length;
5472 this._currentLine.srcSpans.push(from && from.sourceSpan || null);
5473 }
5474 if (newLine) {
5475 this._lines.push(new _EmittedLine(this._indent));
5476 }
5477 }
5478 removeEmptyLastLine() {
5479 if (this.lineIsEmpty()) {
5480 this._lines.pop();
5481 }
5482 }
5483 incIndent() {
5484 this._indent++;
5485 if (this.lineIsEmpty()) {
5486 this._currentLine.indent = this._indent;
5487 }
5488 }
5489 decIndent() {
5490 this._indent--;
5491 if (this.lineIsEmpty()) {
5492 this._currentLine.indent = this._indent;
5493 }
5494 }
5495 pushClass(clazz) { this._classes.push(clazz); }
5496 popClass() { return this._classes.pop(); }
5497 get currentClass() {
5498 return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null;
5499 }
5500 toSource() {
5501 return this.sourceLines
5502 .map(l => l.parts.length > 0 ? _createIndent(l.indent) + l.parts.join('') : '')
5503 .join('\n');
5504 }
5505 toSourceMapGenerator(genFilePath, startsAtLine = 0) {
5506 const map = new SourceMapGenerator(genFilePath);
5507 let firstOffsetMapped = false;
5508 const mapFirstOffsetIfNeeded = () => {
5509 if (!firstOffsetMapped) {
5510 // Add a single space so that tools won't try to load the file from disk.
5511 // Note: We are using virtual urls like `ng:///`, so we have to
5512 // provide a content here.
5513 map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0);
5514 firstOffsetMapped = true;
5515 }
5516 };
5517 for (let i = 0; i < startsAtLine; i++) {
5518 map.addLine();
5519 mapFirstOffsetIfNeeded();
5520 }
5521 this.sourceLines.forEach((line, lineIdx) => {
5522 map.addLine();
5523 const spans = line.srcSpans;
5524 const parts = line.parts;
5525 let col0 = line.indent * _INDENT_WITH.length;
5526 let spanIdx = 0;
5527 // skip leading parts without source spans
5528 while (spanIdx < spans.length && !spans[spanIdx]) {
5529 col0 += parts[spanIdx].length;
5530 spanIdx++;
5531 }
5532 if (spanIdx < spans.length && lineIdx === 0 && col0 === 0) {
5533 firstOffsetMapped = true;
5534 }
5535 else {
5536 mapFirstOffsetIfNeeded();
5537 }
5538 while (spanIdx < spans.length) {
5539 const span = spans[spanIdx];
5540 const source = span.start.file;
5541 const sourceLine = span.start.line;
5542 const sourceCol = span.start.col;
5543 map.addSource(source.url, source.content)
5544 .addMapping(col0, source.url, sourceLine, sourceCol);
5545 col0 += parts[spanIdx].length;
5546 spanIdx++;
5547 // assign parts without span or the same span to the previous segment
5548 while (spanIdx < spans.length && (span === spans[spanIdx] || !spans[spanIdx])) {
5549 col0 += parts[spanIdx].length;
5550 spanIdx++;
5551 }
5552 }
5553 });
5554 return map;
5555 }
5556 setPreambleLineCount(count) { return this._preambleLineCount = count; }
5557 spanOf(line, column) {
5558 const emittedLine = this._lines[line - this._preambleLineCount];
5559 if (emittedLine) {
5560 let columnsLeft = column - _createIndent(emittedLine.indent).length;
5561 for (let partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) {
5562 const part = emittedLine.parts[partIndex];
5563 if (part.length > columnsLeft) {
5564 return emittedLine.srcSpans[partIndex];
5565 }
5566 columnsLeft -= part.length;
5567 }
5568 }
5569 return null;
5570 }
5571 get sourceLines() {
5572 if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) {
5573 return this._lines.slice(0, -1);
5574 }
5575 return this._lines;
5576 }
5577}
5578class AbstractEmitterVisitor {
5579 constructor(_escapeDollarInStrings) {
5580 this._escapeDollarInStrings = _escapeDollarInStrings;
5581 }
5582 visitExpressionStmt(stmt, ctx) {
5583 stmt.expr.visitExpression(this, ctx);
5584 ctx.println(stmt, ';');
5585 return null;
5586 }
5587 visitReturnStmt(stmt, ctx) {
5588 ctx.print(stmt, `return `);
5589 stmt.value.visitExpression(this, ctx);
5590 ctx.println(stmt, ';');
5591 return null;
5592 }
5593 visitIfStmt(stmt, ctx) {
5594 ctx.print(stmt, `if (`);
5595 stmt.condition.visitExpression(this, ctx);
5596 ctx.print(stmt, `) {`);
5597 const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0;
5598 if (stmt.trueCase.length <= 1 && !hasElseCase) {
5599 ctx.print(stmt, ` `);
5600 this.visitAllStatements(stmt.trueCase, ctx);
5601 ctx.removeEmptyLastLine();
5602 ctx.print(stmt, ` `);
5603 }
5604 else {
5605 ctx.println();
5606 ctx.incIndent();
5607 this.visitAllStatements(stmt.trueCase, ctx);
5608 ctx.decIndent();
5609 if (hasElseCase) {
5610 ctx.println(stmt, `} else {`);
5611 ctx.incIndent();
5612 this.visitAllStatements(stmt.falseCase, ctx);
5613 ctx.decIndent();
5614 }
5615 }
5616 ctx.println(stmt, `}`);
5617 return null;
5618 }
5619 visitThrowStmt(stmt, ctx) {
5620 ctx.print(stmt, `throw `);
5621 stmt.error.visitExpression(this, ctx);
5622 ctx.println(stmt, `;`);
5623 return null;
5624 }
5625 visitCommentStmt(stmt, ctx) {
5626 if (stmt.multiline) {
5627 ctx.println(stmt, `/* ${stmt.comment} */`);
5628 }
5629 else {
5630 stmt.comment.split('\n').forEach((line) => { ctx.println(stmt, `// ${line}`); });
5631 }
5632 return null;
5633 }
5634 visitJSDocCommentStmt(stmt, ctx) {
5635 ctx.println(stmt, `/*${stmt.toString()}*/`);
5636 return null;
5637 }
5638 visitWriteVarExpr(expr, ctx) {
5639 const lineWasEmpty = ctx.lineIsEmpty();
5640 if (!lineWasEmpty) {
5641 ctx.print(expr, '(');
5642 }
5643 ctx.print(expr, `${expr.name} = `);
5644 expr.value.visitExpression(this, ctx);
5645 if (!lineWasEmpty) {
5646 ctx.print(expr, ')');
5647 }
5648 return null;
5649 }
5650 visitWriteKeyExpr(expr, ctx) {
5651 const lineWasEmpty = ctx.lineIsEmpty();
5652 if (!lineWasEmpty) {
5653 ctx.print(expr, '(');
5654 }
5655 expr.receiver.visitExpression(this, ctx);
5656 ctx.print(expr, `[`);
5657 expr.index.visitExpression(this, ctx);
5658 ctx.print(expr, `] = `);
5659 expr.value.visitExpression(this, ctx);
5660 if (!lineWasEmpty) {
5661 ctx.print(expr, ')');
5662 }
5663 return null;
5664 }
5665 visitWritePropExpr(expr, ctx) {
5666 const lineWasEmpty = ctx.lineIsEmpty();
5667 if (!lineWasEmpty) {
5668 ctx.print(expr, '(');
5669 }
5670 expr.receiver.visitExpression(this, ctx);
5671 ctx.print(expr, `.${expr.name} = `);
5672 expr.value.visitExpression(this, ctx);
5673 if (!lineWasEmpty) {
5674 ctx.print(expr, ')');
5675 }
5676 return null;
5677 }
5678 visitInvokeMethodExpr(expr, ctx) {
5679 expr.receiver.visitExpression(this, ctx);
5680 let name = expr.name;
5681 if (expr.builtin != null) {
5682 name = this.getBuiltinMethodName(expr.builtin);
5683 if (name == null) {
5684 // some builtins just mean to skip the call.
5685 return null;
5686 }
5687 }
5688 ctx.print(expr, `.${name}(`);
5689 this.visitAllExpressions(expr.args, ctx, `,`);
5690 ctx.print(expr, `)`);
5691 return null;
5692 }
5693 visitInvokeFunctionExpr(expr, ctx) {
5694 expr.fn.visitExpression(this, ctx);
5695 ctx.print(expr, `(`);
5696 this.visitAllExpressions(expr.args, ctx, ',');
5697 ctx.print(expr, `)`);
5698 return null;
5699 }
5700 visitWrappedNodeExpr(ast, ctx) {
5701 throw new Error('Abstract emitter cannot visit WrappedNodeExpr.');
5702 }
5703 visitTypeofExpr(expr, ctx) {
5704 ctx.print(expr, 'typeof ');
5705 expr.expr.visitExpression(this, ctx);
5706 }
5707 visitReadVarExpr(ast, ctx) {
5708 let varName = ast.name;
5709 if (ast.builtin != null) {
5710 switch (ast.builtin) {
5711 case BuiltinVar.Super:
5712 varName = 'super';
5713 break;
5714 case BuiltinVar.This:
5715 varName = 'this';
5716 break;
5717 case BuiltinVar.CatchError:
5718 varName = CATCH_ERROR_VAR$1.name;
5719 break;
5720 case BuiltinVar.CatchStack:
5721 varName = CATCH_STACK_VAR$1.name;
5722 break;
5723 default:
5724 throw new Error(`Unknown builtin variable ${ast.builtin}`);
5725 }
5726 }
5727 ctx.print(ast, varName);
5728 return null;
5729 }
5730 visitInstantiateExpr(ast, ctx) {
5731 ctx.print(ast, `new `);
5732 ast.classExpr.visitExpression(this, ctx);
5733 ctx.print(ast, `(`);
5734 this.visitAllExpressions(ast.args, ctx, ',');
5735 ctx.print(ast, `)`);
5736 return null;
5737 }
5738 visitLiteralExpr(ast, ctx) {
5739 const value = ast.value;
5740 if (typeof value === 'string') {
5741 ctx.print(ast, escapeIdentifier(value, this._escapeDollarInStrings));
5742 }
5743 else {
5744 ctx.print(ast, `${value}`);
5745 }
5746 return null;
5747 }
5748 visitConditionalExpr(ast, ctx) {
5749 ctx.print(ast, `(`);
5750 ast.condition.visitExpression(this, ctx);
5751 ctx.print(ast, '? ');
5752 ast.trueCase.visitExpression(this, ctx);
5753 ctx.print(ast, ': ');
5754 ast.falseCase.visitExpression(this, ctx);
5755 ctx.print(ast, `)`);
5756 return null;
5757 }
5758 visitNotExpr(ast, ctx) {
5759 ctx.print(ast, '!');
5760 ast.condition.visitExpression(this, ctx);
5761 return null;
5762 }
5763 visitAssertNotNullExpr(ast, ctx) {
5764 ast.condition.visitExpression(this, ctx);
5765 return null;
5766 }
5767 visitBinaryOperatorExpr(ast, ctx) {
5768 let opStr;
5769 switch (ast.operator) {
5770 case BinaryOperator.Equals:
5771 opStr = '==';
5772 break;
5773 case BinaryOperator.Identical:
5774 opStr = '===';
5775 break;
5776 case BinaryOperator.NotEquals:
5777 opStr = '!=';
5778 break;
5779 case BinaryOperator.NotIdentical:
5780 opStr = '!==';
5781 break;
5782 case BinaryOperator.And:
5783 opStr = '&&';
5784 break;
5785 case BinaryOperator.BitwiseAnd:
5786 opStr = '&';
5787 break;
5788 case BinaryOperator.Or:
5789 opStr = '||';
5790 break;
5791 case BinaryOperator.Plus:
5792 opStr = '+';
5793 break;
5794 case BinaryOperator.Minus:
5795 opStr = '-';
5796 break;
5797 case BinaryOperator.Divide:
5798 opStr = '/';
5799 break;
5800 case BinaryOperator.Multiply:
5801 opStr = '*';
5802 break;
5803 case BinaryOperator.Modulo:
5804 opStr = '%';
5805 break;
5806 case BinaryOperator.Lower:
5807 opStr = '<';
5808 break;
5809 case BinaryOperator.LowerEquals:
5810 opStr = '<=';
5811 break;
5812 case BinaryOperator.Bigger:
5813 opStr = '>';
5814 break;
5815 case BinaryOperator.BiggerEquals:
5816 opStr = '>=';
5817 break;
5818 default:
5819 throw new Error(`Unknown operator ${ast.operator}`);
5820 }
5821 if (ast.parens)
5822 ctx.print(ast, `(`);
5823 ast.lhs.visitExpression(this, ctx);
5824 ctx.print(ast, ` ${opStr} `);
5825 ast.rhs.visitExpression(this, ctx);
5826 if (ast.parens)
5827 ctx.print(ast, `)`);
5828 return null;
5829 }
5830 visitReadPropExpr(ast, ctx) {
5831 ast.receiver.visitExpression(this, ctx);
5832 ctx.print(ast, `.`);
5833 ctx.print(ast, ast.name);
5834 return null;
5835 }
5836 visitReadKeyExpr(ast, ctx) {
5837 ast.receiver.visitExpression(this, ctx);
5838 ctx.print(ast, `[`);
5839 ast.index.visitExpression(this, ctx);
5840 ctx.print(ast, `]`);
5841 return null;
5842 }
5843 visitLiteralArrayExpr(ast, ctx) {
5844 ctx.print(ast, `[`);
5845 this.visitAllExpressions(ast.entries, ctx, ',');
5846 ctx.print(ast, `]`);
5847 return null;
5848 }
5849 visitLiteralMapExpr(ast, ctx) {
5850 ctx.print(ast, `{`);
5851 this.visitAllObjects(entry => {
5852 ctx.print(ast, `${escapeIdentifier(entry.key, this._escapeDollarInStrings, entry.quoted)}:`);
5853 entry.value.visitExpression(this, ctx);
5854 }, ast.entries, ctx, ',');
5855 ctx.print(ast, `}`);
5856 return null;
5857 }
5858 visitCommaExpr(ast, ctx) {
5859 ctx.print(ast, '(');
5860 this.visitAllExpressions(ast.parts, ctx, ',');
5861 ctx.print(ast, ')');
5862 return null;
5863 }
5864 visitAllExpressions(expressions, ctx, separator) {
5865 this.visitAllObjects(expr => expr.visitExpression(this, ctx), expressions, ctx, separator);
5866 }
5867 visitAllObjects(handler, expressions, ctx, separator) {
5868 let incrementedIndent = false;
5869 for (let i = 0; i < expressions.length; i++) {
5870 if (i > 0) {
5871 if (ctx.lineLength() > 80) {
5872 ctx.print(null, separator, true);
5873 if (!incrementedIndent) {
5874 // continuation are marked with double indent.
5875 ctx.incIndent();
5876 ctx.incIndent();
5877 incrementedIndent = true;
5878 }
5879 }
5880 else {
5881 ctx.print(null, separator, false);
5882 }
5883 }
5884 handler(expressions[i]);
5885 }
5886 if (incrementedIndent) {
5887 // continuation are marked with double indent.
5888 ctx.decIndent();
5889 ctx.decIndent();
5890 }
5891 }
5892 visitAllStatements(statements, ctx) {
5893 statements.forEach((stmt) => stmt.visitStatement(this, ctx));
5894 }
5895}
5896function escapeIdentifier(input, escapeDollar, alwaysQuote = true) {
5897 if (input == null) {
5898 return null;
5899 }
5900 const body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, (...match) => {
5901 if (match[0] == '$') {
5902 return escapeDollar ? '\\$' : '$';
5903 }
5904 else if (match[0] == '\n') {
5905 return '\\n';
5906 }
5907 else if (match[0] == '\r') {
5908 return '\\r';
5909 }
5910 else {
5911 return `\\${match[0]}`;
5912 }
5913 });
5914 const requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body);
5915 return requiresQuotes ? `'${body}'` : body;
5916}
5917function _createIndent(count) {
5918 let res = '';
5919 for (let i = 0; i < count; i++) {
5920 res += _INDENT_WITH;
5921 }
5922 return res;
5923}
5924
5925/**
5926 * @license
5927 * Copyright Google Inc. All Rights Reserved.
5928 *
5929 * Use of this source code is governed by an MIT-style license that can be
5930 * found in the LICENSE file at https://angular.io/license
5931 */
5932class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
5933 constructor() { super(false); }
5934 visitDeclareClassStmt(stmt, ctx) {
5935 ctx.pushClass(stmt);
5936 this._visitClassConstructor(stmt, ctx);
5937 if (stmt.parent != null) {
5938 ctx.print(stmt, `${stmt.name}.prototype = Object.create(`);
5939 stmt.parent.visitExpression(this, ctx);
5940 ctx.println(stmt, `.prototype);`);
5941 }
5942 stmt.getters.forEach((getter) => this._visitClassGetter(stmt, getter, ctx));
5943 stmt.methods.forEach((method) => this._visitClassMethod(stmt, method, ctx));
5944 ctx.popClass();
5945 return null;
5946 }
5947 _visitClassConstructor(stmt, ctx) {
5948 ctx.print(stmt, `function ${stmt.name}(`);
5949 if (stmt.constructorMethod != null) {
5950 this._visitParams(stmt.constructorMethod.params, ctx);
5951 }
5952 ctx.println(stmt, `) {`);
5953 ctx.incIndent();
5954 if (stmt.constructorMethod != null) {
5955 if (stmt.constructorMethod.body.length > 0) {
5956 ctx.println(stmt, `var self = this;`);
5957 this.visitAllStatements(stmt.constructorMethod.body, ctx);
5958 }
5959 }
5960 ctx.decIndent();
5961 ctx.println(stmt, `}`);
5962 }
5963 _visitClassGetter(stmt, getter, ctx) {
5964 ctx.println(stmt, `Object.defineProperty(${stmt.name}.prototype, '${getter.name}', { get: function() {`);
5965 ctx.incIndent();
5966 if (getter.body.length > 0) {
5967 ctx.println(stmt, `var self = this;`);
5968 this.visitAllStatements(getter.body, ctx);
5969 }
5970 ctx.decIndent();
5971 ctx.println(stmt, `}});`);
5972 }
5973 _visitClassMethod(stmt, method, ctx) {
5974 ctx.print(stmt, `${stmt.name}.prototype.${method.name} = function(`);
5975 this._visitParams(method.params, ctx);
5976 ctx.println(stmt, `) {`);
5977 ctx.incIndent();
5978 if (method.body.length > 0) {
5979 ctx.println(stmt, `var self = this;`);
5980 this.visitAllStatements(method.body, ctx);
5981 }
5982 ctx.decIndent();
5983 ctx.println(stmt, `};`);
5984 }
5985 visitWrappedNodeExpr(ast, ctx) {
5986 throw new Error('Cannot emit a WrappedNodeExpr in Javascript.');
5987 }
5988 visitReadVarExpr(ast, ctx) {
5989 if (ast.builtin === BuiltinVar.This) {
5990 ctx.print(ast, 'self');
5991 }
5992 else if (ast.builtin === BuiltinVar.Super) {
5993 throw new Error(`'super' needs to be handled at a parent ast node, not at the variable level!`);
5994 }
5995 else {
5996 super.visitReadVarExpr(ast, ctx);
5997 }
5998 return null;
5999 }
6000 visitDeclareVarStmt(stmt, ctx) {
6001 ctx.print(stmt, `var ${stmt.name}`);
6002 if (stmt.value) {
6003 ctx.print(stmt, ' = ');
6004 stmt.value.visitExpression(this, ctx);
6005 }
6006 ctx.println(stmt, `;`);
6007 return null;
6008 }
6009 visitCastExpr(ast, ctx) {
6010 ast.value.visitExpression(this, ctx);
6011 return null;
6012 }
6013 visitInvokeFunctionExpr(expr, ctx) {
6014 const fnExpr = expr.fn;
6015 if (fnExpr instanceof ReadVarExpr && fnExpr.builtin === BuiltinVar.Super) {
6016 ctx.currentClass.parent.visitExpression(this, ctx);
6017 ctx.print(expr, `.call(this`);
6018 if (expr.args.length > 0) {
6019 ctx.print(expr, `, `);
6020 this.visitAllExpressions(expr.args, ctx, ',');
6021 }
6022 ctx.print(expr, `)`);
6023 }
6024 else {
6025 super.visitInvokeFunctionExpr(expr, ctx);
6026 }
6027 return null;
6028 }
6029 visitFunctionExpr(ast, ctx) {
6030 ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`);
6031 this._visitParams(ast.params, ctx);
6032 ctx.println(ast, `) {`);
6033 ctx.incIndent();
6034 this.visitAllStatements(ast.statements, ctx);
6035 ctx.decIndent();
6036 ctx.print(ast, `}`);
6037 return null;
6038 }
6039 visitDeclareFunctionStmt(stmt, ctx) {
6040 ctx.print(stmt, `function ${stmt.name}(`);
6041 this._visitParams(stmt.params, ctx);
6042 ctx.println(stmt, `) {`);
6043 ctx.incIndent();
6044 this.visitAllStatements(stmt.statements, ctx);
6045 ctx.decIndent();
6046 ctx.println(stmt, `}`);
6047 return null;
6048 }
6049 visitTryCatchStmt(stmt, ctx) {
6050 ctx.println(stmt, `try {`);
6051 ctx.incIndent();
6052 this.visitAllStatements(stmt.bodyStmts, ctx);
6053 ctx.decIndent();
6054 ctx.println(stmt, `} catch (${CATCH_ERROR_VAR$1.name}) {`);
6055 ctx.incIndent();
6056 const catchStmts = [CATCH_STACK_VAR$1.set(CATCH_ERROR_VAR$1.prop('stack')).toDeclStmt(null, [
6057 StmtModifier.Final
6058 ])].concat(stmt.catchStmts);
6059 this.visitAllStatements(catchStmts, ctx);
6060 ctx.decIndent();
6061 ctx.println(stmt, `}`);
6062 return null;
6063 }
6064 _visitParams(params, ctx) {
6065 this.visitAllObjects(param => ctx.print(null, param.name), params, ctx, ',');
6066 }
6067 getBuiltinMethodName(method) {
6068 let name;
6069 switch (method) {
6070 case BuiltinMethod.ConcatArray:
6071 name = 'concat';
6072 break;
6073 case BuiltinMethod.SubscribeObservable:
6074 name = 'subscribe';
6075 break;
6076 case BuiltinMethod.Bind:
6077 name = 'bind';
6078 break;
6079 default:
6080 throw new Error(`Unknown builtin method: ${method}`);
6081 }
6082 return name;
6083 }
6084}
6085
6086/**
6087 * @license
6088 * Copyright Google Inc. All Rights Reserved.
6089 *
6090 * Use of this source code is governed by an MIT-style license that can be
6091 * found in the LICENSE file at https://angular.io/license
6092 */
6093/**
6094 * A helper class to manage the evaluation of JIT generated code.
6095 */
6096class JitEvaluator {
6097 /**
6098 *
6099 * @param sourceUrl The URL of the generated code.
6100 * @param statements An array of Angular statement AST nodes to be evaluated.
6101 * @param reflector A helper used when converting the statements to executable code.
6102 * @param createSourceMaps If true then create a source-map for the generated code and include it
6103 * inline as a source-map comment.
6104 * @returns A map of all the variables in the generated code.
6105 */
6106 evaluateStatements(sourceUrl, statements, reflector, createSourceMaps) {
6107 const converter = new JitEmitterVisitor(reflector);
6108 const ctx = EmitterVisitorContext.createRoot();
6109 // Ensure generated code is in strict mode
6110 if (statements.length > 0 && !isUseStrictStatement(statements[0])) {
6111 statements = [
6112 literal('use strict').toStmt(),
6113 ...statements,
6114 ];
6115 }
6116 converter.visitAllStatements(statements, ctx);
6117 converter.createReturnStmt(ctx);
6118 return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps);
6119 }
6120 /**
6121 * Evaluate a piece of JIT generated code.
6122 * @param sourceUrl The URL of this generated code.
6123 * @param ctx A context object that contains an AST of the code to be evaluated.
6124 * @param vars A map containing the names and values of variables that the evaluated code might
6125 * reference.
6126 * @param createSourceMap If true then create a source-map for the generated code and include it
6127 * inline as a source-map comment.
6128 * @returns The result of evaluating the code.
6129 */
6130 evaluateCode(sourceUrl, ctx, vars, createSourceMap) {
6131 let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`;
6132 const fnArgNames = [];
6133 const fnArgValues = [];
6134 for (const argName in vars) {
6135 fnArgValues.push(vars[argName]);
6136 fnArgNames.push(argName);
6137 }
6138 if (createSourceMap) {
6139 // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise
6140 // E.g. ```
6141 // function anonymous(a,b,c
6142 // /**/) { ... }```
6143 // We don't want to hard code this fact, so we auto detect it via an empty function first.
6144 const emptyFn = new Function(...fnArgNames.concat('return null;')).toString();
6145 const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
6146 fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`;
6147 }
6148 const fn = new Function(...fnArgNames.concat(fnBody));
6149 return this.executeFunction(fn, fnArgValues);
6150 }
6151 /**
6152 * Execute a JIT generated function by calling it.
6153 *
6154 * This method can be overridden in tests to capture the functions that are generated
6155 * by this `JitEvaluator` class.
6156 *
6157 * @param fn A function to execute.
6158 * @param args The arguments to pass to the function being executed.
6159 * @returns The return value of the executed function.
6160 */
6161 executeFunction(fn, args) { return fn(...args); }
6162}
6163/**
6164 * An Angular AST visitor that converts AST nodes into executable JavaScript code.
6165 */
6166class JitEmitterVisitor extends AbstractJsEmitterVisitor {
6167 constructor(reflector) {
6168 super();
6169 this.reflector = reflector;
6170 this._evalArgNames = [];
6171 this._evalArgValues = [];
6172 this._evalExportedVars = [];
6173 }
6174 createReturnStmt(ctx) {
6175 const stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(resultVar => new LiteralMapEntry(resultVar, variable(resultVar), false))));
6176 stmt.visitStatement(this, ctx);
6177 }
6178 getArgs() {
6179 const result = {};
6180 for (let i = 0; i < this._evalArgNames.length; i++) {
6181 result[this._evalArgNames[i]] = this._evalArgValues[i];
6182 }
6183 return result;
6184 }
6185 visitExternalExpr(ast, ctx) {
6186 this._emitReferenceToExternal(ast, this.reflector.resolveExternalReference(ast.value), ctx);
6187 return null;
6188 }
6189 visitWrappedNodeExpr(ast, ctx) {
6190 this._emitReferenceToExternal(ast, ast.node, ctx);
6191 return null;
6192 }
6193 visitDeclareVarStmt(stmt, ctx) {
6194 if (stmt.hasModifier(StmtModifier.Exported)) {
6195 this._evalExportedVars.push(stmt.name);
6196 }
6197 return super.visitDeclareVarStmt(stmt, ctx);
6198 }
6199 visitDeclareFunctionStmt(stmt, ctx) {
6200 if (stmt.hasModifier(StmtModifier.Exported)) {
6201 this._evalExportedVars.push(stmt.name);
6202 }
6203 return super.visitDeclareFunctionStmt(stmt, ctx);
6204 }
6205 visitDeclareClassStmt(stmt, ctx) {
6206 if (stmt.hasModifier(StmtModifier.Exported)) {
6207 this._evalExportedVars.push(stmt.name);
6208 }
6209 return super.visitDeclareClassStmt(stmt, ctx);
6210 }
6211 _emitReferenceToExternal(ast, value, ctx) {
6212 let id = this._evalArgValues.indexOf(value);
6213 if (id === -1) {
6214 id = this._evalArgValues.length;
6215 this._evalArgValues.push(value);
6216 const name = identifierName({ reference: value }) || 'val';
6217 this._evalArgNames.push(`jit_${name}_${id}`);
6218 }
6219 ctx.print(ast, this._evalArgNames[id]);
6220 }
6221}
6222function isUseStrictStatement(statement) {
6223 return statement.isEquivalent(literal('use strict').toStmt());
6224}
6225
6226/**
6227 * @license
6228 * Copyright Google Inc. All Rights Reserved.
6229 *
6230 * Use of this source code is governed by an MIT-style license that can be
6231 * found in the LICENSE file at https://angular.io/license
6232 */
6233/**
6234 * Implementation of `CompileReflector` which resolves references to @angular/core
6235 * symbols at runtime, according to a consumer-provided mapping.
6236 *
6237 * Only supports `resolveExternalReference`, all other methods throw.
6238 */
6239class R3JitReflector {
6240 constructor(context) {
6241 this.context = context;
6242 }
6243 resolveExternalReference(ref) {
6244 // This reflector only handles @angular/core imports.
6245 if (ref.moduleName !== '@angular/core') {
6246 throw new Error(`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`);
6247 }
6248 if (!this.context.hasOwnProperty(ref.name)) {
6249 throw new Error(`No value provided for @angular/core symbol '${ref.name}'.`);
6250 }
6251 return this.context[ref.name];
6252 }
6253 parameters(typeOrFunc) { throw new Error('Not implemented.'); }
6254 annotations(typeOrFunc) { throw new Error('Not implemented.'); }
6255 shallowAnnotations(typeOrFunc) { throw new Error('Not implemented.'); }
6256 tryAnnotations(typeOrFunc) { throw new Error('Not implemented.'); }
6257 propMetadata(typeOrFunc) { throw new Error('Not implemented.'); }
6258 hasLifecycleHook(type, lcProperty) { throw new Error('Not implemented.'); }
6259 guards(typeOrFunc) { throw new Error('Not implemented.'); }
6260 componentModuleUrl(type, cmpMetadata) { throw new Error('Not implemented.'); }
6261}
6262
6263/**
6264 * @license
6265 * Copyright Google Inc. All Rights Reserved.
6266 *
6267 * Use of this source code is governed by an MIT-style license that can be
6268 * found in the LICENSE file at https://angular.io/license
6269 */
6270/**
6271 * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
6272 */
6273function compileNgModule(meta) {
6274 const { type: moduleType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, emitInline, id } = meta;
6275 const additionalStatements = [];
6276 const definitionMap = {
6277 type: moduleType
6278 };
6279 // Only generate the keys in the metadata if the arrays have values.
6280 if (bootstrap.length) {
6281 definitionMap.bootstrap = refsToArray(bootstrap, containsForwardDecls);
6282 }
6283 // If requested to emit scope information inline, pass the declarations, imports and exports to
6284 // the `ɵɵdefineNgModule` call. The JIT compilation uses this.
6285 if (emitInline) {
6286 if (declarations.length) {
6287 definitionMap.declarations = refsToArray(declarations, containsForwardDecls);
6288 }
6289 if (imports.length) {
6290 definitionMap.imports = refsToArray(imports, containsForwardDecls);
6291 }
6292 if (exports.length) {
6293 definitionMap.exports = refsToArray(exports, containsForwardDecls);
6294 }
6295 }
6296 // If not emitting inline, the scope information is not passed into `ɵɵdefineNgModule` as it would
6297 // prevent tree-shaking of the declarations, imports and exports references.
6298 else {
6299 const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta);
6300 if (setNgModuleScopeCall !== null) {
6301 additionalStatements.push(setNgModuleScopeCall);
6302 }
6303 }
6304 if (schemas && schemas.length) {
6305 definitionMap.schemas = literalArr(schemas.map(ref => ref.value));
6306 }
6307 if (id) {
6308 definitionMap.id = id;
6309 }
6310 const expression = importExpr(Identifiers$1.defineNgModule).callFn([mapToMapExpression(definitionMap)]);
6311 const type = new ExpressionType(importExpr(Identifiers$1.NgModuleDefWithMeta, [
6312 new ExpressionType(moduleType), tupleTypeOf(declarations), tupleTypeOf(imports),
6313 tupleTypeOf(exports)
6314 ]));
6315 return { expression, type, additionalStatements };
6316}
6317/**
6318 * Generates a function call to `ɵɵsetNgModuleScope` with all necessary information so that the
6319 * transitive module scope can be computed during runtime in JIT mode. This call is marked pure
6320 * such that the references to declarations, imports and exports may be elided causing these
6321 * symbols to become tree-shakeable.
6322 */
6323function generateSetNgModuleScopeCall(meta) {
6324 const { type: moduleType, declarations, imports, exports, containsForwardDecls } = meta;
6325 const scopeMap = {};
6326 if (declarations.length) {
6327 scopeMap.declarations = refsToArray(declarations, containsForwardDecls);
6328 }
6329 if (imports.length) {
6330 scopeMap.imports = refsToArray(imports, containsForwardDecls);
6331 }
6332 if (exports.length) {
6333 scopeMap.exports = refsToArray(exports, containsForwardDecls);
6334 }
6335 if (Object.keys(scopeMap).length === 0) {
6336 return null;
6337 }
6338 const fnCall = new InvokeFunctionExpr(
6339 /* fn */ importExpr(Identifiers$1.setNgModuleScope),
6340 /* args */ [moduleType, mapToMapExpression(scopeMap)],
6341 /* type */ undefined,
6342 /* sourceSpan */ undefined,
6343 /* pure */ true);
6344 return fnCall.toStmt();
6345}
6346function compileInjector(meta) {
6347 const result = compileFactoryFunction({
6348 name: meta.name,
6349 type: meta.type,
6350 deps: meta.deps,
6351 injectFn: Identifiers$1.inject,
6352 });
6353 const definitionMap = {
6354 factory: result.factory,
6355 };
6356 if (meta.providers !== null) {
6357 definitionMap.providers = meta.providers;
6358 }
6359 if (meta.imports.length > 0) {
6360 definitionMap.imports = literalArr(meta.imports);
6361 }
6362 const expression = importExpr(Identifiers$1.defineInjector).callFn([mapToMapExpression(definitionMap)]);
6363 const type = new ExpressionType(importExpr(Identifiers$1.InjectorDef, [new ExpressionType(meta.type)]));
6364 return { expression, type, statements: result.statements };
6365}
6366// TODO(alxhub): integrate this with `compileNgModule`. Currently the two are separate operations.
6367function compileNgModuleFromRender2(ctx, ngModule, injectableCompiler) {
6368 const className = identifierName(ngModule.type);
6369 const rawImports = ngModule.rawImports ? [ngModule.rawImports] : [];
6370 const rawExports = ngModule.rawExports ? [ngModule.rawExports] : [];
6371 const injectorDefArg = mapLiteral({
6372 'factory': injectableCompiler.factoryFor({ type: ngModule.type, symbol: ngModule.type.reference }, ctx),
6373 'providers': convertMetaToOutput(ngModule.rawProviders, ctx),
6374 'imports': convertMetaToOutput([...rawImports, ...rawExports], ctx),
6375 });
6376 const injectorDef = importExpr(Identifiers$1.defineInjector).callFn([injectorDefArg]);
6377 ctx.statements.push(new ClassStmt(
6378 /* name */ className,
6379 /* parent */ null,
6380 /* fields */ [new ClassField(
6381 /* name */ 'ngInjectorDef',
6382 /* type */ INFERRED_TYPE,
6383 /* modifiers */ [StmtModifier.Static],
6384 /* initializer */ injectorDef)],
6385 /* getters */ [],
6386 /* constructorMethod */ new ClassMethod(null, [], []),
6387 /* methods */ []));
6388}
6389function accessExportScope(module) {
6390 const selectorScope = new ReadPropExpr(module, 'ngModuleDef');
6391 return new ReadPropExpr(selectorScope, 'exported');
6392}
6393function tupleTypeOf(exp) {
6394 const types = exp.map(ref => typeofExpr(ref.type));
6395 return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE;
6396}
6397function refsToArray(refs, shouldForwardDeclare) {
6398 const values = literalArr(refs.map(ref => ref.value));
6399 return shouldForwardDeclare ? fn([], [new ReturnStatement(values)]) : values;
6400}
6401
6402/**
6403 * @license
6404 * Copyright Google Inc. All Rights Reserved.
6405 *
6406 * Use of this source code is governed by an MIT-style license that can be
6407 * found in the LICENSE file at https://angular.io/license
6408 */
6409function compilePipeFromMetadata(metadata) {
6410 const definitionMapValues = [];
6411 // e.g. `name: 'myPipe'`
6412 definitionMapValues.push({ key: 'name', value: literal(metadata.pipeName), quoted: false });
6413 // e.g. `type: MyPipe`
6414 definitionMapValues.push({ key: 'type', value: metadata.type, quoted: false });
6415 const templateFactory = compileFactoryFunction({
6416 name: metadata.name,
6417 type: metadata.type,
6418 deps: metadata.deps,
6419 injectFn: Identifiers$1.directiveInject,
6420 }, true);
6421 definitionMapValues.push({ key: 'factory', value: templateFactory.factory, quoted: false });
6422 // e.g. `pure: true`
6423 definitionMapValues.push({ key: 'pure', value: literal(metadata.pure), quoted: false });
6424 const expression = importExpr(Identifiers$1.definePipe).callFn([literalMap(definitionMapValues)]);
6425 const type = new ExpressionType(importExpr(Identifiers$1.PipeDefWithMeta, [
6426 typeWithParameters(metadata.type, metadata.typeArgumentCount),
6427 new ExpressionType(new LiteralExpr(metadata.pipeName)),
6428 ]));
6429 return { expression, type, statements: templateFactory.statements };
6430}
6431/**
6432 * Write a pipe definition to the output context.
6433 */
6434function compilePipeFromRender2(outputCtx, pipe, reflector) {
6435 const definitionMapValues = [];
6436 const name = identifierName(pipe.type);
6437 if (!name) {
6438 return error(`Cannot resolve the name of ${pipe.type}`);
6439 }
6440 const metadata = {
6441 name,
6442 pipeName: pipe.name,
6443 type: outputCtx.importExpr(pipe.type.reference),
6444 typeArgumentCount: 0,
6445 deps: dependenciesFromGlobalMetadata(pipe.type, outputCtx, reflector),
6446 pure: pipe.pure,
6447 };
6448 const res = compilePipeFromMetadata(metadata);
6449 const definitionField = outputCtx.constantPool.propertyNameOf(3 /* Pipe */);
6450 outputCtx.statements.push(new ClassStmt(
6451 /* name */ name,
6452 /* parent */ null,
6453 /* fields */ [new ClassField(
6454 /* name */ definitionField,
6455 /* type */ INFERRED_TYPE,
6456 /* modifiers */ [StmtModifier.Static],
6457 /* initializer */ res.expression)],
6458 /* getters */ [],
6459 /* constructorMethod */ new ClassMethod(null, [], []),
6460 /* methods */ []));
6461}
6462
6463/**
6464 * @license
6465 * Copyright Google Inc. All Rights Reserved.
6466 *
6467 * Use of this source code is governed by an MIT-style license that can be
6468 * found in the LICENSE file at https://angular.io/license
6469 */
6470class ParserError {
6471 constructor(message, input, errLocation, ctxLocation) {
6472 this.input = input;
6473 this.errLocation = errLocation;
6474 this.ctxLocation = ctxLocation;
6475 this.message = `Parser Error: ${message} ${errLocation} [${input}] in ${ctxLocation}`;
6476 }
6477}
6478class ParseSpan {
6479 constructor(start, end) {
6480 this.start = start;
6481 this.end = end;
6482 }
6483}
6484class AST {
6485 constructor(span) {
6486 this.span = span;
6487 }
6488 visit(visitor, context = null) { return null; }
6489 toString() { return 'AST'; }
6490}
6491/**
6492 * Represents a quoted expression of the form:
6493 *
6494 * quote = prefix `:` uninterpretedExpression
6495 * prefix = identifier
6496 * uninterpretedExpression = arbitrary string
6497 *
6498 * A quoted expression is meant to be pre-processed by an AST transformer that
6499 * converts it into another AST that no longer contains quoted expressions.
6500 * It is meant to allow third-party developers to extend Angular template
6501 * expression language. The `uninterpretedExpression` part of the quote is
6502 * therefore not interpreted by the Angular's own expression parser.
6503 */
6504class Quote extends AST {
6505 constructor(span, prefix, uninterpretedExpression, location) {
6506 super(span);
6507 this.prefix = prefix;
6508 this.uninterpretedExpression = uninterpretedExpression;
6509 this.location = location;
6510 }
6511 visit(visitor, context = null) { return visitor.visitQuote(this, context); }
6512 toString() { return 'Quote'; }
6513}
6514class EmptyExpr extends AST {
6515 visit(visitor, context = null) {
6516 // do nothing
6517 }
6518}
6519class ImplicitReceiver extends AST {
6520 visit(visitor, context = null) {
6521 return visitor.visitImplicitReceiver(this, context);
6522 }
6523}
6524/**
6525 * Multiple expressions separated by a semicolon.
6526 */
6527class Chain extends AST {
6528 constructor(span, expressions) {
6529 super(span);
6530 this.expressions = expressions;
6531 }
6532 visit(visitor, context = null) { return visitor.visitChain(this, context); }
6533}
6534class Conditional extends AST {
6535 constructor(span, condition, trueExp, falseExp) {
6536 super(span);
6537 this.condition = condition;
6538 this.trueExp = trueExp;
6539 this.falseExp = falseExp;
6540 }
6541 visit(visitor, context = null) {
6542 return visitor.visitConditional(this, context);
6543 }
6544}
6545class PropertyRead extends AST {
6546 constructor(span, receiver, name) {
6547 super(span);
6548 this.receiver = receiver;
6549 this.name = name;
6550 }
6551 visit(visitor, context = null) {
6552 return visitor.visitPropertyRead(this, context);
6553 }
6554}
6555class PropertyWrite extends AST {
6556 constructor(span, receiver, name, value) {
6557 super(span);
6558 this.receiver = receiver;
6559 this.name = name;
6560 this.value = value;
6561 }
6562 visit(visitor, context = null) {
6563 return visitor.visitPropertyWrite(this, context);
6564 }
6565}
6566class SafePropertyRead extends AST {
6567 constructor(span, receiver, name) {
6568 super(span);
6569 this.receiver = receiver;
6570 this.name = name;
6571 }
6572 visit(visitor, context = null) {
6573 return visitor.visitSafePropertyRead(this, context);
6574 }
6575}
6576class KeyedRead extends AST {
6577 constructor(span, obj, key) {
6578 super(span);
6579 this.obj = obj;
6580 this.key = key;
6581 }
6582 visit(visitor, context = null) {
6583 return visitor.visitKeyedRead(this, context);
6584 }
6585}
6586class KeyedWrite extends AST {
6587 constructor(span, obj, key, value) {
6588 super(span);
6589 this.obj = obj;
6590 this.key = key;
6591 this.value = value;
6592 }
6593 visit(visitor, context = null) {
6594 return visitor.visitKeyedWrite(this, context);
6595 }
6596}
6597class BindingPipe extends AST {
6598 constructor(span, exp, name, args) {
6599 super(span);
6600 this.exp = exp;
6601 this.name = name;
6602 this.args = args;
6603 }
6604 visit(visitor, context = null) { return visitor.visitPipe(this, context); }
6605}
6606class LiteralPrimitive extends AST {
6607 constructor(span, value) {
6608 super(span);
6609 this.value = value;
6610 }
6611 visit(visitor, context = null) {
6612 return visitor.visitLiteralPrimitive(this, context);
6613 }
6614}
6615class LiteralArray extends AST {
6616 constructor(span, expressions) {
6617 super(span);
6618 this.expressions = expressions;
6619 }
6620 visit(visitor, context = null) {
6621 return visitor.visitLiteralArray(this, context);
6622 }
6623}
6624class LiteralMap extends AST {
6625 constructor(span, keys, values) {
6626 super(span);
6627 this.keys = keys;
6628 this.values = values;
6629 }
6630 visit(visitor, context = null) {
6631 return visitor.visitLiteralMap(this, context);
6632 }
6633}
6634class Interpolation extends AST {
6635 constructor(span, strings, expressions) {
6636 super(span);
6637 this.strings = strings;
6638 this.expressions = expressions;
6639 }
6640 visit(visitor, context = null) {
6641 return visitor.visitInterpolation(this, context);
6642 }
6643}
6644class Binary extends AST {
6645 constructor(span, operation, left, right) {
6646 super(span);
6647 this.operation = operation;
6648 this.left = left;
6649 this.right = right;
6650 }
6651 visit(visitor, context = null) {
6652 return visitor.visitBinary(this, context);
6653 }
6654}
6655class PrefixNot extends AST {
6656 constructor(span, expression) {
6657 super(span);
6658 this.expression = expression;
6659 }
6660 visit(visitor, context = null) {
6661 return visitor.visitPrefixNot(this, context);
6662 }
6663}
6664class NonNullAssert extends AST {
6665 constructor(span, expression) {
6666 super(span);
6667 this.expression = expression;
6668 }
6669 visit(visitor, context = null) {
6670 return visitor.visitNonNullAssert(this, context);
6671 }
6672}
6673class MethodCall extends AST {
6674 constructor(span, receiver, name, args) {
6675 super(span);
6676 this.receiver = receiver;
6677 this.name = name;
6678 this.args = args;
6679 }
6680 visit(visitor, context = null) {
6681 return visitor.visitMethodCall(this, context);
6682 }
6683}
6684class SafeMethodCall extends AST {
6685 constructor(span, receiver, name, args) {
6686 super(span);
6687 this.receiver = receiver;
6688 this.name = name;
6689 this.args = args;
6690 }
6691 visit(visitor, context = null) {
6692 return visitor.visitSafeMethodCall(this, context);
6693 }
6694}
6695class FunctionCall extends AST {
6696 constructor(span, target, args) {
6697 super(span);
6698 this.target = target;
6699 this.args = args;
6700 }
6701 visit(visitor, context = null) {
6702 return visitor.visitFunctionCall(this, context);
6703 }
6704}
6705/**
6706 * Records the absolute position of a text span in a source file, where `start` and `end` are the
6707 * starting and ending byte offsets, respectively, of the text span in a source file.
6708 */
6709class AbsoluteSourceSpan {
6710 constructor(start, end) {
6711 this.start = start;
6712 this.end = end;
6713 }
6714}
6715class ASTWithSource extends AST {
6716 constructor(ast, source, location, absoluteOffset, errors) {
6717 super(new ParseSpan(0, source == null ? 0 : source.length));
6718 this.ast = ast;
6719 this.source = source;
6720 this.location = location;
6721 this.errors = errors;
6722 this.sourceSpan = new AbsoluteSourceSpan(absoluteOffset, absoluteOffset + this.span.end);
6723 }
6724 visit(visitor, context = null) {
6725 if (visitor.visitASTWithSource) {
6726 return visitor.visitASTWithSource(this, context);
6727 }
6728 return this.ast.visit(visitor, context);
6729 }
6730 toString() { return `${this.source} in ${this.location}`; }
6731}
6732class TemplateBinding {
6733 constructor(span, key, keyIsVar, name, expression) {
6734 this.span = span;
6735 this.key = key;
6736 this.keyIsVar = keyIsVar;
6737 this.name = name;
6738 this.expression = expression;
6739 }
6740}
6741class NullAstVisitor {
6742 visitBinary(ast, context) { }
6743 visitChain(ast, context) { }
6744 visitConditional(ast, context) { }
6745 visitFunctionCall(ast, context) { }
6746 visitImplicitReceiver(ast, context) { }
6747 visitInterpolation(ast, context) { }
6748 visitKeyedRead(ast, context) { }
6749 visitKeyedWrite(ast, context) { }
6750 visitLiteralArray(ast, context) { }
6751 visitLiteralMap(ast, context) { }
6752 visitLiteralPrimitive(ast, context) { }
6753 visitMethodCall(ast, context) { }
6754 visitPipe(ast, context) { }
6755 visitPrefixNot(ast, context) { }
6756 visitNonNullAssert(ast, context) { }
6757 visitPropertyRead(ast, context) { }
6758 visitPropertyWrite(ast, context) { }
6759 visitQuote(ast, context) { }
6760 visitSafeMethodCall(ast, context) { }
6761 visitSafePropertyRead(ast, context) { }
6762}
6763class RecursiveAstVisitor$1 {
6764 visitBinary(ast, context) {
6765 ast.left.visit(this, context);
6766 ast.right.visit(this, context);
6767 return null;
6768 }
6769 visitChain(ast, context) { return this.visitAll(ast.expressions, context); }
6770 visitConditional(ast, context) {
6771 ast.condition.visit(this, context);
6772 ast.trueExp.visit(this, context);
6773 ast.falseExp.visit(this, context);
6774 return null;
6775 }
6776 visitPipe(ast, context) {
6777 ast.exp.visit(this, context);
6778 this.visitAll(ast.args, context);
6779 return null;
6780 }
6781 visitFunctionCall(ast, context) {
6782 ast.target.visit(this, context);
6783 this.visitAll(ast.args, context);
6784 return null;
6785 }
6786 visitImplicitReceiver(ast, context) { return null; }
6787 visitInterpolation(ast, context) {
6788 return this.visitAll(ast.expressions, context);
6789 }
6790 visitKeyedRead(ast, context) {
6791 ast.obj.visit(this, context);
6792 ast.key.visit(this, context);
6793 return null;
6794 }
6795 visitKeyedWrite(ast, context) {
6796 ast.obj.visit(this, context);
6797 ast.key.visit(this, context);
6798 ast.value.visit(this, context);
6799 return null;
6800 }
6801 visitLiteralArray(ast, context) {
6802 return this.visitAll(ast.expressions, context);
6803 }
6804 visitLiteralMap(ast, context) { return this.visitAll(ast.values, context); }
6805 visitLiteralPrimitive(ast, context) { return null; }
6806 visitMethodCall(ast, context) {
6807 ast.receiver.visit(this, context);
6808 return this.visitAll(ast.args, context);
6809 }
6810 visitPrefixNot(ast, context) {
6811 ast.expression.visit(this, context);
6812 return null;
6813 }
6814 visitNonNullAssert(ast, context) {
6815 ast.expression.visit(this, context);
6816 return null;
6817 }
6818 visitPropertyRead(ast, context) {
6819 ast.receiver.visit(this, context);
6820 return null;
6821 }
6822 visitPropertyWrite(ast, context) {
6823 ast.receiver.visit(this, context);
6824 ast.value.visit(this, context);
6825 return null;
6826 }
6827 visitSafePropertyRead(ast, context) {
6828 ast.receiver.visit(this, context);
6829 return null;
6830 }
6831 visitSafeMethodCall(ast, context) {
6832 ast.receiver.visit(this, context);
6833 return this.visitAll(ast.args, context);
6834 }
6835 visitAll(asts, context) {
6836 asts.forEach(ast => ast.visit(this, context));
6837 return null;
6838 }
6839 visitQuote(ast, context) { return null; }
6840}
6841class AstTransformer$1 {
6842 visitImplicitReceiver(ast, context) { return ast; }
6843 visitInterpolation(ast, context) {
6844 return new Interpolation(ast.span, ast.strings, this.visitAll(ast.expressions));
6845 }
6846 visitLiteralPrimitive(ast, context) {
6847 return new LiteralPrimitive(ast.span, ast.value);
6848 }
6849 visitPropertyRead(ast, context) {
6850 return new PropertyRead(ast.span, ast.receiver.visit(this), ast.name);
6851 }
6852 visitPropertyWrite(ast, context) {
6853 return new PropertyWrite(ast.span, ast.receiver.visit(this), ast.name, ast.value.visit(this));
6854 }
6855 visitSafePropertyRead(ast, context) {
6856 return new SafePropertyRead(ast.span, ast.receiver.visit(this), ast.name);
6857 }
6858 visitMethodCall(ast, context) {
6859 return new MethodCall(ast.span, ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
6860 }
6861 visitSafeMethodCall(ast, context) {
6862 return new SafeMethodCall(ast.span, ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
6863 }
6864 visitFunctionCall(ast, context) {
6865 return new FunctionCall(ast.span, ast.target.visit(this), this.visitAll(ast.args));
6866 }
6867 visitLiteralArray(ast, context) {
6868 return new LiteralArray(ast.span, this.visitAll(ast.expressions));
6869 }
6870 visitLiteralMap(ast, context) {
6871 return new LiteralMap(ast.span, ast.keys, this.visitAll(ast.values));
6872 }
6873 visitBinary(ast, context) {
6874 return new Binary(ast.span, ast.operation, ast.left.visit(this), ast.right.visit(this));
6875 }
6876 visitPrefixNot(ast, context) {
6877 return new PrefixNot(ast.span, ast.expression.visit(this));
6878 }
6879 visitNonNullAssert(ast, context) {
6880 return new NonNullAssert(ast.span, ast.expression.visit(this));
6881 }
6882 visitConditional(ast, context) {
6883 return new Conditional(ast.span, ast.condition.visit(this), ast.trueExp.visit(this), ast.falseExp.visit(this));
6884 }
6885 visitPipe(ast, context) {
6886 return new BindingPipe(ast.span, ast.exp.visit(this), ast.name, this.visitAll(ast.args));
6887 }
6888 visitKeyedRead(ast, context) {
6889 return new KeyedRead(ast.span, ast.obj.visit(this), ast.key.visit(this));
6890 }
6891 visitKeyedWrite(ast, context) {
6892 return new KeyedWrite(ast.span, ast.obj.visit(this), ast.key.visit(this), ast.value.visit(this));
6893 }
6894 visitAll(asts) {
6895 const res = new Array(asts.length);
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, this.visitAll(ast.expressions));
6903 }
6904 visitQuote(ast, context) {
6905 return new Quote(ast.span, 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.
6910class AstMemoryEfficientTransformer {
6911 visitImplicitReceiver(ast, context) { return ast; }
6912 visitInterpolation(ast, context) {
6913 const expressions = this.visitAll(ast.expressions);
6914 if (expressions !== ast.expressions)
6915 return new Interpolation(ast.span, ast.strings, expressions);
6916 return ast;
6917 }
6918 visitLiteralPrimitive(ast, context) { return ast; }
6919 visitPropertyRead(ast, context) {
6920 const receiver = ast.receiver.visit(this);
6921 if (receiver !== ast.receiver) {
6922 return new PropertyRead(ast.span, receiver, ast.name);
6923 }
6924 return ast;
6925 }
6926 visitPropertyWrite(ast, context) {
6927 const receiver = ast.receiver.visit(this);
6928 const value = ast.value.visit(this);
6929 if (receiver !== ast.receiver || value !== ast.value) {
6930 return new PropertyWrite(ast.span, receiver, ast.name, value);
6931 }
6932 return ast;
6933 }
6934 visitSafePropertyRead(ast, context) {
6935 const receiver = ast.receiver.visit(this);
6936 if (receiver !== ast.receiver) {
6937 return new SafePropertyRead(ast.span, receiver, ast.name);
6938 }
6939 return ast;
6940 }
6941 visitMethodCall(ast, context) {
6942 const receiver = ast.receiver.visit(this);
6943 const args = this.visitAll(ast.args);
6944 if (receiver !== ast.receiver || args !== ast.args) {
6945 return new MethodCall(ast.span, receiver, ast.name, args);
6946 }
6947 return ast;
6948 }
6949 visitSafeMethodCall(ast, context) {
6950 const receiver = ast.receiver.visit(this);
6951 const args = this.visitAll(ast.args);
6952 if (receiver !== ast.receiver || args !== ast.args) {
6953 return new SafeMethodCall(ast.span, receiver, ast.name, args);
6954 }
6955 return ast;
6956 }
6957 visitFunctionCall(ast, context) {
6958 const target = ast.target && ast.target.visit(this);
6959 const args = this.visitAll(ast.args);
6960 if (target !== ast.target || args !== ast.args) {
6961 return new FunctionCall(ast.span, target, args);
6962 }
6963 return ast;
6964 }
6965 visitLiteralArray(ast, context) {
6966 const expressions = this.visitAll(ast.expressions);
6967 if (expressions !== ast.expressions) {
6968 return new LiteralArray(ast.span, expressions);
6969 }
6970 return ast;
6971 }
6972 visitLiteralMap(ast, context) {
6973 const values = this.visitAll(ast.values);
6974 if (values !== ast.values) {
6975 return new LiteralMap(ast.span, ast.keys, values);
6976 }
6977 return ast;
6978 }
6979 visitBinary(ast, context) {
6980 const left = ast.left.visit(this);
6981 const right = ast.right.visit(this);
6982 if (left !== ast.left || right !== ast.right) {
6983 return new Binary(ast.span, ast.operation, left, right);
6984 }
6985 return ast;
6986 }
6987 visitPrefixNot(ast, context) {
6988 const expression = ast.expression.visit(this);
6989 if (expression !== ast.expression) {
6990 return new PrefixNot(ast.span, expression);
6991 }
6992 return ast;
6993 }
6994 visitNonNullAssert(ast, context) {
6995 const expression = ast.expression.visit(this);
6996 if (expression !== ast.expression) {
6997 return new NonNullAssert(ast.span, expression);
6998 }
6999 return ast;
7000 }
7001 visitConditional(ast, context) {
7002 const condition = ast.condition.visit(this);
7003 const trueExp = ast.trueExp.visit(this);
7004 const falseExp = ast.falseExp.visit(this);
7005 if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== ast.falseExp) {
7006 return new Conditional(ast.span, condition, trueExp, falseExp);
7007 }
7008 return ast;
7009 }
7010 visitPipe(ast, context) {
7011 const exp = ast.exp.visit(this);
7012 const args = this.visitAll(ast.args);
7013 if (exp !== ast.exp || args !== ast.args) {
7014 return new BindingPipe(ast.span, exp, ast.name, args);
7015 }
7016 return ast;
7017 }
7018 visitKeyedRead(ast, context) {
7019 const obj = ast.obj.visit(this);
7020 const key = ast.key.visit(this);
7021 if (obj !== ast.obj || key !== ast.key) {
7022 return new KeyedRead(ast.span, obj, key);
7023 }
7024 return ast;
7025 }
7026 visitKeyedWrite(ast, context) {
7027 const obj = ast.obj.visit(this);
7028 const key = ast.key.visit(this);
7029 const value = ast.value.visit(this);
7030 if (obj !== ast.obj || key !== ast.key || value !== ast.value) {
7031 return new KeyedWrite(ast.span, obj, key, value);
7032 }
7033 return ast;
7034 }
7035 visitAll(asts) {
7036 const res = new Array(asts.length);
7037 let modified = false;
7038 for (let i = 0; i < asts.length; ++i) {
7039 const original = asts[i];
7040 const value = original.visit(this);
7041 res[i] = value;
7042 modified = modified || value !== original;
7043 }
7044 return modified ? res : asts;
7045 }
7046 visitChain(ast, context) {
7047 const expressions = this.visitAll(ast.expressions);
7048 if (expressions !== ast.expressions) {
7049 return new Chain(ast.span, expressions);
7050 }
7051 return ast;
7052 }
7053 visitQuote(ast, context) { return ast; }
7054}
7055function visitAstChildren(ast, visitor, context) {
7056 function visit(ast) {
7057 visitor.visit && visitor.visit(ast, context) || ast.visit(visitor, context);
7058 }
7059 function visitAll(asts) { asts.forEach(visit); }
7060 ast.visit({
7061 visitBinary(ast) {
7062 visit(ast.left);
7063 visit(ast.right);
7064 },
7065 visitChain(ast) { visitAll(ast.expressions); },
7066 visitConditional(ast) {
7067 visit(ast.condition);
7068 visit(ast.trueExp);
7069 visit(ast.falseExp);
7070 },
7071 visitFunctionCall(ast) {
7072 if (ast.target) {
7073 visit(ast.target);
7074 }
7075 visitAll(ast.args);
7076 },
7077 visitImplicitReceiver(ast) { },
7078 visitInterpolation(ast) { visitAll(ast.expressions); },
7079 visitKeyedRead(ast) {
7080 visit(ast.obj);
7081 visit(ast.key);
7082 },
7083 visitKeyedWrite(ast) {
7084 visit(ast.obj);
7085 visit(ast.key);
7086 visit(ast.obj);
7087 },
7088 visitLiteralArray(ast) { visitAll(ast.expressions); },
7089 visitLiteralMap(ast) { },
7090 visitLiteralPrimitive(ast) { },
7091 visitMethodCall(ast) {
7092 visit(ast.receiver);
7093 visitAll(ast.args);
7094 },
7095 visitPipe(ast) {
7096 visit(ast.exp);
7097 visitAll(ast.args);
7098 },
7099 visitPrefixNot(ast) { visit(ast.expression); },
7100 visitNonNullAssert(ast) { visit(ast.expression); },
7101 visitPropertyRead(ast) { visit(ast.receiver); },
7102 visitPropertyWrite(ast) {
7103 visit(ast.receiver);
7104 visit(ast.value);
7105 },
7106 visitQuote(ast) { },
7107 visitSafeMethodCall(ast) {
7108 visit(ast.receiver);
7109 visitAll(ast.args);
7110 },
7111 visitSafePropertyRead(ast) { visit(ast.receiver); },
7112 });
7113}
7114// Bindings
7115class ParsedProperty {
7116 constructor(name, expression, type, sourceSpan, valueSpan) {
7117 this.name = name;
7118 this.expression = expression;
7119 this.type = type;
7120 this.sourceSpan = sourceSpan;
7121 this.valueSpan = valueSpan;
7122 this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR;
7123 this.isAnimation = this.type === ParsedPropertyType.ANIMATION;
7124 }
7125}
7126var ParsedPropertyType;
7127(function (ParsedPropertyType) {
7128 ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT";
7129 ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
7130 ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION";
7131})(ParsedPropertyType || (ParsedPropertyType = {}));
7132class ParsedEvent {
7133 // Regular events have a target
7134 // Animation events have a phase
7135 constructor(name, targetOrPhase, type, handler, sourceSpan, handlerSpan) {
7136 this.name = name;
7137 this.targetOrPhase = targetOrPhase;
7138 this.type = type;
7139 this.handler = handler;
7140 this.sourceSpan = sourceSpan;
7141 this.handlerSpan = handlerSpan;
7142 }
7143}
7144class ParsedVariable {
7145 constructor(name, value, sourceSpan) {
7146 this.name = name;
7147 this.value = value;
7148 this.sourceSpan = sourceSpan;
7149 }
7150}
7151class BoundElementProperty {
7152 constructor(name, type, securityContext, value, unit, sourceSpan, valueSpan) {
7153 this.name = name;
7154 this.type = type;
7155 this.securityContext = securityContext;
7156 this.value = value;
7157 this.unit = unit;
7158 this.sourceSpan = sourceSpan;
7159 this.valueSpan = valueSpan;
7160 }
7161}
7162
7163/**
7164 * @license
7165 * Copyright Google Inc. All Rights Reserved.
7166 *
7167 * Use of this source code is governed by an MIT-style license that can be
7168 * found in the LICENSE file at https://angular.io/license
7169 */
7170class EventHandlerVars {
7171}
7172EventHandlerVars.event = variable('$event');
7173class ConvertActionBindingResult {
7174 constructor(
7175 /**
7176 * Render2 compatible statements,
7177 */
7178 stmts,
7179 /**
7180 * Variable name used with render2 compatible statements.
7181 */
7182 allowDefault) {
7183 this.stmts = stmts;
7184 this.allowDefault = allowDefault;
7185 /**
7186 * This is bit of a hack. It converts statements which render2 expects to statements which are
7187 * expected by render3.
7188 *
7189 * Example: `<div click="doSomething($event)">` will generate:
7190 *
7191 * Render3:
7192 * ```
7193 * const pd_b:any = ((<any>ctx.doSomething($event)) !== false);
7194 * return pd_b;
7195 * ```
7196 *
7197 * but render2 expects:
7198 * ```
7199 * return ctx.doSomething($event);
7200 * ```
7201 */
7202 // TODO(misko): remove this hack once we no longer support ViewEngine.
7203 this.render3Stmts = stmts.map((statement) => {
7204 if (statement instanceof DeclareVarStmt && statement.name == allowDefault.name &&
7205 statement.value instanceof BinaryOperatorExpr) {
7206 const lhs = statement.value.lhs;
7207 return new ReturnStatement(lhs.value);
7208 }
7209 return statement;
7210 });
7211 }
7212}
7213/**
7214 * Converts the given expression AST into an executable output AST, assuming the expression is
7215 * used in an action binding (e.g. an event handler).
7216 */
7217function convertActionBinding(localResolver, implicitReceiver, action, bindingId, interpolationFunction, baseSourceSpan) {
7218 if (!localResolver) {
7219 localResolver = new DefaultLocalResolver();
7220 }
7221 const actionWithoutBuiltins = convertPropertyBindingBuiltins({
7222 createLiteralArrayConverter: (argCount) => {
7223 // Note: no caching for literal arrays in actions.
7224 return (args) => literalArr(args);
7225 },
7226 createLiteralMapConverter: (keys) => {
7227 // Note: no caching for literal maps in actions.
7228 return (values) => {
7229 const entries = keys.map((k, i) => ({
7230 key: k.key,
7231 value: values[i],
7232 quoted: k.quoted,
7233 }));
7234 return literalMap(entries);
7235 };
7236 },
7237 createPipeConverter: (name) => {
7238 throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`);
7239 }
7240 }, action);
7241 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan);
7242 const actionStmts = [];
7243 flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
7244 prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
7245 if (visitor.usesImplicitReceiver) {
7246 localResolver.notifyImplicitReceiverUse();
7247 }
7248 const lastIndex = actionStmts.length - 1;
7249 let preventDefaultVar = null;
7250 if (lastIndex >= 0) {
7251 const lastStatement = actionStmts[lastIndex];
7252 const returnExpr = convertStmtIntoExpression(lastStatement);
7253 if (returnExpr) {
7254 // Note: We need to cast the result of the method call to dynamic,
7255 // as it might be a void method!
7256 preventDefaultVar = createPreventDefaultVar(bindingId);
7257 actionStmts[lastIndex] =
7258 preventDefaultVar.set(returnExpr.cast(DYNAMIC_TYPE).notIdentical(literal(false)))
7259 .toDeclStmt(null, [StmtModifier.Final]);
7260 }
7261 }
7262 return new ConvertActionBindingResult(actionStmts, preventDefaultVar);
7263}
7264function convertPropertyBindingBuiltins(converterFactory, ast) {
7265 return convertBuiltins(converterFactory, ast);
7266}
7267class ConvertPropertyBindingResult {
7268 constructor(stmts, currValExpr) {
7269 this.stmts = stmts;
7270 this.currValExpr = currValExpr;
7271 }
7272}
7273var BindingForm;
7274(function (BindingForm) {
7275 // The general form of binding expression, supports all expressions.
7276 BindingForm[BindingForm["General"] = 0] = "General";
7277 // Try to generate a simple binding (no temporaries or statements)
7278 // otherwise generate a general binding
7279 BindingForm[BindingForm["TrySimple"] = 1] = "TrySimple";
7280})(BindingForm || (BindingForm = {}));
7281/**
7282 * Converts the given expression AST into an executable output AST, assuming the expression
7283 * is used in property binding. The expression has to be preprocessed via
7284 * `convertPropertyBindingBuiltins`.
7285 */
7286function convertPropertyBinding(localResolver, implicitReceiver, expressionWithoutBuiltins, bindingId, form, interpolationFunction) {
7287 if (!localResolver) {
7288 localResolver = new DefaultLocalResolver();
7289 }
7290 const currValExpr = createCurrValueExpr(bindingId);
7291 const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
7292 const outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
7293 const stmts = getStatementsFromVisitor(visitor, bindingId);
7294 if (visitor.usesImplicitReceiver) {
7295 localResolver.notifyImplicitReceiverUse();
7296 }
7297 if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) {
7298 return new ConvertPropertyBindingResult([], outputExpr);
7299 }
7300 stmts.push(currValExpr.set(outputExpr).toDeclStmt(DYNAMIC_TYPE, [StmtModifier.Final]));
7301 return new ConvertPropertyBindingResult(stmts, currValExpr);
7302}
7303/**
7304 * Given some expression, such as a binding or interpolation expression, and a context expression to
7305 * look values up on, visit each facet of the given expression resolving values from the context
7306 * expression such that a list of arguments can be derived from the found values that can be used as
7307 * arguments to an external update instruction.
7308 *
7309 * @param localResolver The resolver to use to look up expressions by name appropriately
7310 * @param contextVariableExpression The expression representing the context variable used to create
7311 * the final argument expressions
7312 * @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to
7313 * be resolved and what arguments list to build.
7314 * @param bindingId A name prefix used to create temporary variable names if they're needed for the
7315 * arguments generated
7316 * @returns An array of expressions that can be passed as arguments to instruction expressions like
7317 * `o.importExpr(R3.propertyInterpolate).callFn(result)`
7318 */
7319function convertUpdateArguments(localResolver, contextVariableExpression, expressionWithArgumentsToExtract, bindingId) {
7320 const visitor = new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, undefined);
7321 const outputExpr = expressionWithArgumentsToExtract.visit(visitor, _Mode.Expression);
7322 if (visitor.usesImplicitReceiver) {
7323 localResolver.notifyImplicitReceiverUse();
7324 }
7325 const stmts = getStatementsFromVisitor(visitor, bindingId);
7326 // Removing the first argument, because it was a length for ViewEngine, not Ivy.
7327 let args = outputExpr.args.slice(1);
7328 if (expressionWithArgumentsToExtract instanceof Interpolation) {
7329 // If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the
7330 // args returned to just the value, because we're going to pass it to a special instruction.
7331 const strings = expressionWithArgumentsToExtract.strings;
7332 if (args.length === 3 && strings[0] === '' && strings[1] === '') {
7333 // Single argument interpolate instructions.
7334 args = [args[1]];
7335 }
7336 else if (args.length >= 19) {
7337 // 19 or more arguments must be passed to the `interpolateV`-style instructions, which accept
7338 // an array of arguments
7339 args = [literalArr(args)];
7340 }
7341 }
7342 return { stmts, args };
7343}
7344function getStatementsFromVisitor(visitor, bindingId) {
7345 const stmts = [];
7346 for (let i = 0; i < visitor.temporaryCount; i++) {
7347 stmts.push(temporaryDeclaration(bindingId, i));
7348 }
7349 return stmts;
7350}
7351function convertBuiltins(converterFactory, ast) {
7352 const visitor = new _BuiltinAstConverter(converterFactory);
7353 return ast.visit(visitor);
7354}
7355function temporaryName(bindingId, temporaryNumber) {
7356 return `tmp_${bindingId}_${temporaryNumber}`;
7357}
7358function temporaryDeclaration(bindingId, temporaryNumber) {
7359 return new DeclareVarStmt(temporaryName(bindingId, temporaryNumber), NULL_EXPR);
7360}
7361function prependTemporaryDecls(temporaryCount, bindingId, statements) {
7362 for (let i = temporaryCount - 1; i >= 0; i--) {
7363 statements.unshift(temporaryDeclaration(bindingId, i));
7364 }
7365}
7366var _Mode;
7367(function (_Mode) {
7368 _Mode[_Mode["Statement"] = 0] = "Statement";
7369 _Mode[_Mode["Expression"] = 1] = "Expression";
7370})(_Mode || (_Mode = {}));
7371function ensureStatementMode(mode, ast) {
7372 if (mode !== _Mode.Statement) {
7373 throw new Error(`Expected a statement, but saw ${ast}`);
7374 }
7375}
7376function ensureExpressionMode(mode, ast) {
7377 if (mode !== _Mode.Expression) {
7378 throw new Error(`Expected an expression, but saw ${ast}`);
7379 }
7380}
7381function convertToStatementIfNeeded(mode, expr) {
7382 if (mode === _Mode.Statement) {
7383 return expr.toStmt();
7384 }
7385 else {
7386 return expr;
7387 }
7388}
7389class _BuiltinAstConverter extends AstTransformer$1 {
7390 constructor(_converterFactory) {
7391 super();
7392 this._converterFactory = _converterFactory;
7393 }
7394 visitPipe(ast, context) {
7395 const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context));
7396 return new BuiltinFunctionCall(ast.span, args, this._converterFactory.createPipeConverter(ast.name, args.length));
7397 }
7398 visitLiteralArray(ast, context) {
7399 const args = ast.expressions.map(ast => ast.visit(this, context));
7400 return new BuiltinFunctionCall(ast.span, args, this._converterFactory.createLiteralArrayConverter(ast.expressions.length));
7401 }
7402 visitLiteralMap(ast, context) {
7403 const args = ast.values.map(ast => ast.visit(this, context));
7404 return new BuiltinFunctionCall(ast.span, args, this._converterFactory.createLiteralMapConverter(ast.keys));
7405 }
7406}
7407class _AstToIrVisitor {
7408 constructor(_localResolver, _implicitReceiver, bindingId, interpolationFunction, baseSourceSpan) {
7409 this._localResolver = _localResolver;
7410 this._implicitReceiver = _implicitReceiver;
7411 this.bindingId = bindingId;
7412 this.interpolationFunction = interpolationFunction;
7413 this.baseSourceSpan = baseSourceSpan;
7414 this._nodeMap = new Map();
7415 this._resultMap = new Map();
7416 this._currentTemporary = 0;
7417 this.temporaryCount = 0;
7418 this.usesImplicitReceiver = false;
7419 }
7420 visitBinary(ast, mode) {
7421 let op;
7422 switch (ast.operation) {
7423 case '+':
7424 op = BinaryOperator.Plus;
7425 break;
7426 case '-':
7427 op = BinaryOperator.Minus;
7428 break;
7429 case '*':
7430 op = BinaryOperator.Multiply;
7431 break;
7432 case '/':
7433 op = BinaryOperator.Divide;
7434 break;
7435 case '%':
7436 op = BinaryOperator.Modulo;
7437 break;
7438 case '&&':
7439 op = BinaryOperator.And;
7440 break;
7441 case '||':
7442 op = BinaryOperator.Or;
7443 break;
7444 case '==':
7445 op = BinaryOperator.Equals;
7446 break;
7447 case '!=':
7448 op = BinaryOperator.NotEquals;
7449 break;
7450 case '===':
7451 op = BinaryOperator.Identical;
7452 break;
7453 case '!==':
7454 op = BinaryOperator.NotIdentical;
7455 break;
7456 case '<':
7457 op = BinaryOperator.Lower;
7458 break;
7459 case '>':
7460 op = BinaryOperator.Bigger;
7461 break;
7462 case '<=':
7463 op = BinaryOperator.LowerEquals;
7464 break;
7465 case '>=':
7466 op = BinaryOperator.BiggerEquals;
7467 break;
7468 default:
7469 throw new Error(`Unsupported operation ${ast.operation}`);
7470 }
7471 return convertToStatementIfNeeded(mode, new BinaryOperatorExpr(op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression), undefined, this.convertSourceSpan(ast.span)));
7472 }
7473 visitChain(ast, mode) {
7474 ensureStatementMode(mode, ast);
7475 return this.visitAll(ast.expressions, mode);
7476 }
7477 visitConditional(ast, mode) {
7478 const value = this._visit(ast.condition, _Mode.Expression);
7479 return convertToStatementIfNeeded(mode, value.conditional(this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span)));
7480 }
7481 visitPipe(ast, mode) {
7482 throw new Error(`Illegal state: Pipes should have been converted into functions. Pipe: ${ast.name}`);
7483 }
7484 visitFunctionCall(ast, mode) {
7485 const convertedArgs = this.visitAll(ast.args, _Mode.Expression);
7486 let fnResult;
7487 if (ast instanceof BuiltinFunctionCall) {
7488 fnResult = ast.converter(convertedArgs);
7489 }
7490 else {
7491 fnResult = this._visit(ast.target, _Mode.Expression)
7492 .callFn(convertedArgs, this.convertSourceSpan(ast.span));
7493 }
7494 return convertToStatementIfNeeded(mode, fnResult);
7495 }
7496 visitImplicitReceiver(ast, mode) {
7497 ensureExpressionMode(mode, ast);
7498 this.usesImplicitReceiver = true;
7499 return this._implicitReceiver;
7500 }
7501 visitInterpolation(ast, mode) {
7502 ensureExpressionMode(mode, ast);
7503 const args = [literal(ast.expressions.length)];
7504 for (let i = 0; i < ast.strings.length - 1; i++) {
7505 args.push(literal(ast.strings[i]));
7506 args.push(this._visit(ast.expressions[i], _Mode.Expression));
7507 }
7508 args.push(literal(ast.strings[ast.strings.length - 1]));
7509 if (this.interpolationFunction) {
7510 return this.interpolationFunction(args);
7511 }
7512 return ast.expressions.length <= 9 ?
7513 importExpr(Identifiers.inlineInterpolate).callFn(args) :
7514 importExpr(Identifiers.interpolate).callFn([
7515 args[0], literalArr(args.slice(1), undefined, this.convertSourceSpan(ast.span))
7516 ]);
7517 }
7518 visitKeyedRead(ast, mode) {
7519 const leftMostSafe = this.leftMostSafeNode(ast);
7520 if (leftMostSafe) {
7521 return this.convertSafeAccess(ast, leftMostSafe, mode);
7522 }
7523 else {
7524 return convertToStatementIfNeeded(mode, this._visit(ast.obj, _Mode.Expression).key(this._visit(ast.key, _Mode.Expression)));
7525 }
7526 }
7527 visitKeyedWrite(ast, mode) {
7528 const obj = this._visit(ast.obj, _Mode.Expression);
7529 const key = this._visit(ast.key, _Mode.Expression);
7530 const value = this._visit(ast.value, _Mode.Expression);
7531 return convertToStatementIfNeeded(mode, obj.key(key).set(value));
7532 }
7533 visitLiteralArray(ast, mode) {
7534 throw new Error(`Illegal State: literal arrays should have been converted into functions`);
7535 }
7536 visitLiteralMap(ast, mode) {
7537 throw new Error(`Illegal State: literal maps should have been converted into functions`);
7538 }
7539 visitLiteralPrimitive(ast, mode) {
7540 // For literal values of null, undefined, true, or false allow type interference
7541 // to infer the type.
7542 const type = ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
7543 INFERRED_TYPE :
7544 undefined;
7545 return convertToStatementIfNeeded(mode, literal(ast.value, type, this.convertSourceSpan(ast.span)));
7546 }
7547 _getLocal(name) { return this._localResolver.getLocal(name); }
7548 visitMethodCall(ast, mode) {
7549 if (ast.receiver instanceof ImplicitReceiver && ast.name == '$any') {
7550 const args = this.visitAll(ast.args, _Mode.Expression);
7551 if (args.length != 1) {
7552 throw new Error(`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
7553 }
7554 return args[0].cast(DYNAMIC_TYPE, this.convertSourceSpan(ast.span));
7555 }
7556 const leftMostSafe = this.leftMostSafeNode(ast);
7557 if (leftMostSafe) {
7558 return this.convertSafeAccess(ast, leftMostSafe, mode);
7559 }
7560 else {
7561 const args = this.visitAll(ast.args, _Mode.Expression);
7562 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7563 let result = null;
7564 const receiver = this._visit(ast.receiver, _Mode.Expression);
7565 if (receiver === this._implicitReceiver) {
7566 const varExpr = this._getLocal(ast.name);
7567 if (varExpr) {
7568 // Restore the previous "usesImplicitReceiver" state since the implicit
7569 // receiver has been replaced with a resolved local expression.
7570 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7571 result = varExpr.callFn(args);
7572 }
7573 }
7574 if (result == null) {
7575 result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span));
7576 }
7577 return convertToStatementIfNeeded(mode, result);
7578 }
7579 }
7580 visitPrefixNot(ast, mode) {
7581 return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression)));
7582 }
7583 visitNonNullAssert(ast, mode) {
7584 return convertToStatementIfNeeded(mode, assertNotNull(this._visit(ast.expression, _Mode.Expression)));
7585 }
7586 visitPropertyRead(ast, mode) {
7587 const leftMostSafe = this.leftMostSafeNode(ast);
7588 if (leftMostSafe) {
7589 return this.convertSafeAccess(ast, leftMostSafe, mode);
7590 }
7591 else {
7592 let result = null;
7593 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7594 const receiver = this._visit(ast.receiver, _Mode.Expression);
7595 if (receiver === this._implicitReceiver) {
7596 result = this._getLocal(ast.name);
7597 if (result) {
7598 // Restore the previous "usesImplicitReceiver" state since the implicit
7599 // receiver has been replaced with a resolved local expression.
7600 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7601 }
7602 }
7603 if (result == null) {
7604 result = receiver.prop(ast.name);
7605 }
7606 return convertToStatementIfNeeded(mode, result);
7607 }
7608 }
7609 visitPropertyWrite(ast, mode) {
7610 const receiver = this._visit(ast.receiver, _Mode.Expression);
7611 const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7612 let varExpr = null;
7613 if (receiver === this._implicitReceiver) {
7614 const localExpr = this._getLocal(ast.name);
7615 if (localExpr) {
7616 if (localExpr instanceof ReadPropExpr) {
7617 // If the local variable is a property read expression, it's a reference
7618 // to a 'context.property' value and will be used as the target of the
7619 // write expression.
7620 varExpr = localExpr;
7621 // Restore the previous "usesImplicitReceiver" state since the implicit
7622 // receiver has been replaced with a resolved local expression.
7623 this.usesImplicitReceiver = prevUsesImplicitReceiver;
7624 }
7625 else {
7626 // Otherwise it's an error.
7627 throw new Error('Cannot assign to a reference or variable!');
7628 }
7629 }
7630 }
7631 // If no local expression could be produced, use the original receiver's
7632 // property as the target.
7633 if (varExpr === null) {
7634 varExpr = receiver.prop(ast.name);
7635 }
7636 return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression)));
7637 }
7638 visitSafePropertyRead(ast, mode) {
7639 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7640 }
7641 visitSafeMethodCall(ast, mode) {
7642 return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7643 }
7644 visitAll(asts, mode) { return asts.map(ast => this._visit(ast, mode)); }
7645 visitQuote(ast, mode) {
7646 throw new Error(`Quotes are not supported for evaluation!
7647 Statement: ${ast.uninterpretedExpression} located at ${ast.location}`);
7648 }
7649 _visit(ast, mode) {
7650 const result = this._resultMap.get(ast);
7651 if (result)
7652 return result;
7653 return (this._nodeMap.get(ast) || ast).visit(this, mode);
7654 }
7655 convertSafeAccess(ast, leftMostSafe, mode) {
7656 // If the expression contains a safe access node on the left it needs to be converted to
7657 // an expression that guards the access to the member by checking the receiver for blank. As
7658 // execution proceeds from left to right, the left most part of the expression must be guarded
7659 // first but, because member access is left associative, the right side of the expression is at
7660 // the top of the AST. The desired result requires lifting a copy of the the left part of the
7661 // expression up to test it for blank before generating the unguarded version.
7662 // Consider, for example the following expression: a?.b.c?.d.e
7663 // This results in the ast:
7664 // .
7665 // / \
7666 // ?. e
7667 // / \
7668 // . d
7669 // / \
7670 // ?. c
7671 // / \
7672 // a b
7673 // The following tree should be generated:
7674 //
7675 // /---- ? ----\
7676 // / | \
7677 // a /--- ? ---\ null
7678 // / | \
7679 // . . null
7680 // / \ / \
7681 // . c . e
7682 // / \ / \
7683 // a b . d
7684 // / \
7685 // . c
7686 // / \
7687 // a b
7688 //
7689 // Notice that the first guard condition is the left hand of the left most safe access node
7690 // which comes in as leftMostSafe to this routine.
7691 let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression);
7692 let temporary = undefined;
7693 if (this.needsTemporary(leftMostSafe.receiver)) {
7694 // If the expression has method calls or pipes then we need to save the result into a
7695 // temporary variable to avoid calling stateful or impure code more than once.
7696 temporary = this.allocateTemporary();
7697 // Preserve the result in the temporary variable
7698 guardedExpression = temporary.set(guardedExpression);
7699 // Ensure all further references to the guarded expression refer to the temporary instead.
7700 this._resultMap.set(leftMostSafe.receiver, temporary);
7701 }
7702 const condition = guardedExpression.isBlank();
7703 // Convert the ast to an unguarded access to the receiver's member. The map will substitute
7704 // leftMostNode with its unguarded version in the call to `this.visit()`.
7705 if (leftMostSafe instanceof SafeMethodCall) {
7706 this._nodeMap.set(leftMostSafe, new MethodCall(leftMostSafe.span, leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args));
7707 }
7708 else {
7709 this._nodeMap.set(leftMostSafe, new PropertyRead(leftMostSafe.span, leftMostSafe.receiver, leftMostSafe.name));
7710 }
7711 // Recursively convert the node now without the guarded member access.
7712 const access = this._visit(ast, _Mode.Expression);
7713 // Remove the mapping. This is not strictly required as the converter only traverses each node
7714 // once but is safer if the conversion is changed to traverse the nodes more than once.
7715 this._nodeMap.delete(leftMostSafe);
7716 // If we allocated a temporary, release it.
7717 if (temporary) {
7718 this.releaseTemporary(temporary);
7719 }
7720 // Produce the conditional
7721 return convertToStatementIfNeeded(mode, condition.conditional(literal(null), access));
7722 }
7723 // Given a expression of the form a?.b.c?.d.e the the left most safe node is
7724 // the (a?.b). The . and ?. are left associative thus can be rewritten as:
7725 // ((((a?.c).b).c)?.d).e. This returns the most deeply nested safe read or
7726 // safe method call as this needs be transform initially to:
7727 // a == null ? null : a.c.b.c?.d.e
7728 // then to:
7729 // a == null ? null : a.b.c == null ? null : a.b.c.d.e
7730 leftMostSafeNode(ast) {
7731 const visit = (visitor, ast) => {
7732 return (this._nodeMap.get(ast) || ast).visit(visitor);
7733 };
7734 return ast.visit({
7735 visitBinary(ast) { return null; },
7736 visitChain(ast) { return null; },
7737 visitConditional(ast) { return null; },
7738 visitFunctionCall(ast) { return null; },
7739 visitImplicitReceiver(ast) { return null; },
7740 visitInterpolation(ast) { return null; },
7741 visitKeyedRead(ast) { return visit(this, ast.obj); },
7742 visitKeyedWrite(ast) { return null; },
7743 visitLiteralArray(ast) { return null; },
7744 visitLiteralMap(ast) { return null; },
7745 visitLiteralPrimitive(ast) { return null; },
7746 visitMethodCall(ast) { return visit(this, ast.receiver); },
7747 visitPipe(ast) { return null; },
7748 visitPrefixNot(ast) { return null; },
7749 visitNonNullAssert(ast) { return null; },
7750 visitPropertyRead(ast) { return visit(this, ast.receiver); },
7751 visitPropertyWrite(ast) { return null; },
7752 visitQuote(ast) { return null; },
7753 visitSafeMethodCall(ast) { return visit(this, ast.receiver) || ast; },
7754 visitSafePropertyRead(ast) {
7755 return visit(this, ast.receiver) || ast;
7756 }
7757 });
7758 }
7759 // Returns true of the AST includes a method or a pipe indicating that, if the
7760 // expression is used as the target of a safe property or method access then
7761 // the expression should be stored into a temporary variable.
7762 needsTemporary(ast) {
7763 const visit = (visitor, ast) => {
7764 return ast && (this._nodeMap.get(ast) || ast).visit(visitor);
7765 };
7766 const visitSome = (visitor, ast) => {
7767 return ast.some(ast => visit(visitor, ast));
7768 };
7769 return ast.visit({
7770 visitBinary(ast) { return visit(this, ast.left) || visit(this, ast.right); },
7771 visitChain(ast) { return false; },
7772 visitConditional(ast) {
7773 return visit(this, ast.condition) || visit(this, ast.trueExp) ||
7774 visit(this, ast.falseExp);
7775 },
7776 visitFunctionCall(ast) { return true; },
7777 visitImplicitReceiver(ast) { return false; },
7778 visitInterpolation(ast) { return visitSome(this, ast.expressions); },
7779 visitKeyedRead(ast) { return false; },
7780 visitKeyedWrite(ast) { return false; },
7781 visitLiteralArray(ast) { return true; },
7782 visitLiteralMap(ast) { return true; },
7783 visitLiteralPrimitive(ast) { return false; },
7784 visitMethodCall(ast) { return true; },
7785 visitPipe(ast) { return true; },
7786 visitPrefixNot(ast) { return visit(this, ast.expression); },
7787 visitNonNullAssert(ast) { return visit(this, ast.expression); },
7788 visitPropertyRead(ast) { return false; },
7789 visitPropertyWrite(ast) { return false; },
7790 visitQuote(ast) { return false; },
7791 visitSafeMethodCall(ast) { return true; },
7792 visitSafePropertyRead(ast) { return false; }
7793 });
7794 }
7795 allocateTemporary() {
7796 const tempNumber = this._currentTemporary++;
7797 this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount);
7798 return new ReadVarExpr(temporaryName(this.bindingId, tempNumber));
7799 }
7800 releaseTemporary(temporary) {
7801 this._currentTemporary--;
7802 if (temporary.name != temporaryName(this.bindingId, this._currentTemporary)) {
7803 throw new Error(`Temporary ${temporary.name} released out of order`);
7804 }
7805 }
7806 /**
7807 * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`.
7808 *
7809 * `ParseSpan` objects are relative to the start of the expression.
7810 * This method converts these to full `ParseSourceSpan` objects that
7811 * show where the span is within the overall source file.
7812 *
7813 * @param span the relative span to convert.
7814 * @returns a `ParseSourceSpan` for the the given span or null if no
7815 * `baseSourceSpan` was provided to this class.
7816 */
7817 convertSourceSpan(span) {
7818 if (this.baseSourceSpan) {
7819 const start = this.baseSourceSpan.start.moveBy(span.start);
7820 const end = this.baseSourceSpan.start.moveBy(span.end);
7821 return new ParseSourceSpan(start, end);
7822 }
7823 else {
7824 return null;
7825 }
7826 }
7827}
7828function flattenStatements(arg, output) {
7829 if (Array.isArray(arg)) {
7830 arg.forEach((entry) => flattenStatements(entry, output));
7831 }
7832 else {
7833 output.push(arg);
7834 }
7835}
7836class DefaultLocalResolver {
7837 notifyImplicitReceiverUse() { }
7838 getLocal(name) {
7839 if (name === EventHandlerVars.event.name) {
7840 return EventHandlerVars.event;
7841 }
7842 return null;
7843 }
7844}
7845function createCurrValueExpr(bindingId) {
7846 return variable(`currVal_${bindingId}`); // fix syntax highlighting: `
7847}
7848function createPreventDefaultVar(bindingId) {
7849 return variable(`pd_${bindingId}`);
7850}
7851function convertStmtIntoExpression(stmt) {
7852 if (stmt instanceof ExpressionStatement) {
7853 return stmt.expr;
7854 }
7855 else if (stmt instanceof ReturnStatement) {
7856 return stmt.value;
7857 }
7858 return null;
7859}
7860class BuiltinFunctionCall extends FunctionCall {
7861 constructor(span, args, converter) {
7862 super(span, null, args);
7863 this.args = args;
7864 this.converter = converter;
7865 }
7866}
7867
7868/**
7869 * @license
7870 * Copyright Google Inc. All Rights Reserved.
7871 *
7872 * Use of this source code is governed by an MIT-style license that can be
7873 * found in the LICENSE file at https://angular.io/license
7874 */
7875/**
7876 * This file is a port of shadowCSS from webcomponents.js to TypeScript.
7877 *
7878 * Please make sure to keep to edits in sync with the source file.
7879 *
7880 * Source:
7881 * https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
7882 *
7883 * The original file level comment is reproduced below
7884 */
7885/*
7886 This is a limited shim for ShadowDOM css styling.
7887 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles
7888
7889 The intention here is to support only the styling features which can be
7890 relatively simply implemented. The goal is to allow users to avoid the
7891 most obvious pitfalls and do so without compromising performance significantly.
7892 For ShadowDOM styling that's not covered here, a set of best practices
7893 can be provided that should allow users to accomplish more complex styling.
7894
7895 The following is a list of specific ShadowDOM styling features and a brief
7896 discussion of the approach used to shim.
7897
7898 Shimmed features:
7899
7900 * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
7901 element using the :host rule. To shim this feature, the :host styles are
7902 reformatted and prefixed with a given scope name and promoted to a
7903 document level stylesheet.
7904 For example, given a scope name of .foo, a rule like this:
7905
7906 :host {
7907 background: red;
7908 }
7909 }
7910
7911 becomes:
7912
7913 .foo {
7914 background: red;
7915 }
7916
7917 * encapsulation: Styles defined within ShadowDOM, apply only to
7918 dom inside the ShadowDOM. Polymer uses one of two techniques to implement
7919 this feature.
7920
7921 By default, rules are prefixed with the host element tag name
7922 as a descendant selector. This ensures styling does not leak out of the 'top'
7923 of the element's ShadowDOM. For example,
7924
7925 div {
7926 font-weight: bold;
7927 }
7928
7929 becomes:
7930
7931 x-foo div {
7932 font-weight: bold;
7933 }
7934
7935 becomes:
7936
7937
7938 Alternatively, if WebComponents.ShadowCSS.strictStyling is set to true then
7939 selectors are scoped by adding an attribute selector suffix to each
7940 simple selector that contains the host element tag name. Each element
7941 in the element's ShadowDOM template is also given the scope attribute.
7942 Thus, these rules match only elements that have the scope attribute.
7943 For example, given a scope name of x-foo, a rule like this:
7944
7945 div {
7946 font-weight: bold;
7947 }
7948
7949 becomes:
7950
7951 div[x-foo] {
7952 font-weight: bold;
7953 }
7954
7955 Note that elements that are dynamically added to a scope must have the scope
7956 selector added to them manually.
7957
7958 * upper/lower bound encapsulation: Styles which are defined outside a
7959 shadowRoot should not cross the ShadowDOM boundary and should not apply
7960 inside a shadowRoot.
7961
7962 This styling behavior is not emulated. Some possible ways to do this that
7963 were rejected due to complexity and/or performance concerns include: (1) reset
7964 every possible property for every possible selector for a given scope name;
7965 (2) re-implement css in javascript.
7966
7967 As an alternative, users should make sure to use selectors
7968 specific to the scope in which they are working.
7969
7970 * ::distributed: This behavior is not emulated. It's often not necessary
7971 to style the contents of a specific insertion point and instead, descendants
7972 of the host element can be styled selectively. Users can also create an
7973 extra node around an insertion point and style that node's contents
7974 via descendent selectors. For example, with a shadowRoot like this:
7975
7976 <style>
7977 ::content(div) {
7978 background: red;
7979 }
7980 </style>
7981 <content></content>
7982
7983 could become:
7984
7985 <style>
7986 / *@polyfill .content-container div * /
7987 ::content(div) {
7988 background: red;
7989 }
7990 </style>
7991 <div class="content-container">
7992 <content></content>
7993 </div>
7994
7995 Note the use of @polyfill in the comment above a ShadowDOM specific style
7996 declaration. This is a directive to the styling shim to use the selector
7997 in comments in lieu of the next selector when running under polyfill.
7998*/
7999class ShadowCss {
8000 constructor() {
8001 this.strictStyling = true;
8002 }
8003 /*
8004 * Shim some cssText with the given selector. Returns cssText that can
8005 * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css).
8006 *
8007 * When strictStyling is true:
8008 * - selector is the attribute added to all elements inside the host,
8009 * - hostSelector is the attribute added to the host itself.
8010 */
8011 shimCssText(cssText, selector, hostSelector = '') {
8012 const commentsWithHash = extractCommentsWithHash(cssText);
8013 cssText = stripComments(cssText);
8014 cssText = this._insertDirectives(cssText);
8015 const scopedCssText = this._scopeCssText(cssText, selector, hostSelector);
8016 return [scopedCssText, ...commentsWithHash].join('\n');
8017 }
8018 _insertDirectives(cssText) {
8019 cssText = this._insertPolyfillDirectivesInCssText(cssText);
8020 return this._insertPolyfillRulesInCssText(cssText);
8021 }
8022 /*
8023 * Process styles to convert native ShadowDOM rules that will trip
8024 * up the css parser; we rely on decorating the stylesheet with inert rules.
8025 *
8026 * For example, we convert this rule:
8027 *
8028 * polyfill-next-selector { content: ':host menu-item'; }
8029 * ::content menu-item {
8030 *
8031 * to this:
8032 *
8033 * scopeName menu-item {
8034 *
8035 **/
8036 _insertPolyfillDirectivesInCssText(cssText) {
8037 // Difference with webcomponents.js: does not handle comments
8038 return cssText.replace(_cssContentNextSelectorRe, function (...m) { return m[2] + '{'; });
8039 }
8040 /*
8041 * Process styles to add rules which will only apply under the polyfill
8042 *
8043 * For example, we convert this rule:
8044 *
8045 * polyfill-rule {
8046 * content: ':host menu-item';
8047 * ...
8048 * }
8049 *
8050 * to this:
8051 *
8052 * scopeName menu-item {...}
8053 *
8054 **/
8055 _insertPolyfillRulesInCssText(cssText) {
8056 // Difference with webcomponents.js: does not handle comments
8057 return cssText.replace(_cssContentRuleRe, (...m) => {
8058 const rule = m[0].replace(m[1], '').replace(m[2], '');
8059 return m[4] + rule;
8060 });
8061 }
8062 /* Ensure styles are scoped. Pseudo-scoping takes a rule like:
8063 *
8064 * .foo {... }
8065 *
8066 * and converts this to
8067 *
8068 * scopeName .foo { ... }
8069 */
8070 _scopeCssText(cssText, scopeSelector, hostSelector) {
8071 const unscopedRules = this._extractUnscopedRulesFromCssText(cssText);
8072 // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively
8073 cssText = this._insertPolyfillHostInCssText(cssText);
8074 cssText = this._convertColonHost(cssText);
8075 cssText = this._convertColonHostContext(cssText);
8076 cssText = this._convertShadowDOMSelectors(cssText);
8077 if (scopeSelector) {
8078 cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
8079 }
8080 cssText = cssText + '\n' + unscopedRules;
8081 return cssText.trim();
8082 }
8083 /*
8084 * Process styles to add rules which will only apply under the polyfill
8085 * and do not process via CSSOM. (CSSOM is destructive to rules on rare
8086 * occasions, e.g. -webkit-calc on Safari.)
8087 * For example, we convert this rule:
8088 *
8089 * @polyfill-unscoped-rule {
8090 * content: 'menu-item';
8091 * ... }
8092 *
8093 * to this:
8094 *
8095 * menu-item {...}
8096 *
8097 **/
8098 _extractUnscopedRulesFromCssText(cssText) {
8099 // Difference with webcomponents.js: does not handle comments
8100 let r = '';
8101 let m;
8102 _cssContentUnscopedRuleRe.lastIndex = 0;
8103 while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
8104 const rule = m[0].replace(m[2], '').replace(m[1], m[4]);
8105 r += rule + '\n\n';
8106 }
8107 return r;
8108 }
8109 /*
8110 * convert a rule like :host(.foo) > .bar { }
8111 *
8112 * to
8113 *
8114 * .foo<scopeName> > .bar
8115 */
8116 _convertColonHost(cssText) {
8117 return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer);
8118 }
8119 /*
8120 * convert a rule like :host-context(.foo) > .bar { }
8121 *
8122 * to
8123 *
8124 * .foo<scopeName> > .bar, .foo scopeName > .bar { }
8125 *
8126 * and
8127 *
8128 * :host-context(.foo:host) .bar { ... }
8129 *
8130 * to
8131 *
8132 * .foo<scopeName> .bar { ... }
8133 */
8134 _convertColonHostContext(cssText) {
8135 return this._convertColonRule(cssText, _cssColonHostContextRe, this._colonHostContextPartReplacer);
8136 }
8137 _convertColonRule(cssText, regExp, partReplacer) {
8138 // m[1] = :host(-context), m[2] = contents of (), m[3] rest of rule
8139 return cssText.replace(regExp, function (...m) {
8140 if (m[2]) {
8141 const parts = m[2].split(',');
8142 const r = [];
8143 for (let i = 0; i < parts.length; i++) {
8144 const p = parts[i].trim();
8145 if (!p)
8146 break;
8147 r.push(partReplacer(_polyfillHostNoCombinator, p, m[3]));
8148 }
8149 return r.join(',');
8150 }
8151 else {
8152 return _polyfillHostNoCombinator + m[3];
8153 }
8154 });
8155 }
8156 _colonHostContextPartReplacer(host, part, suffix) {
8157 if (part.indexOf(_polyfillHost) > -1) {
8158 return this._colonHostPartReplacer(host, part, suffix);
8159 }
8160 else {
8161 return host + part + suffix + ', ' + part + ' ' + host + suffix;
8162 }
8163 }
8164 _colonHostPartReplacer(host, part, suffix) {
8165 return host + part.replace(_polyfillHost, '') + suffix;
8166 }
8167 /*
8168 * Convert combinators like ::shadow and pseudo-elements like ::content
8169 * by replacing with space.
8170 */
8171 _convertShadowDOMSelectors(cssText) {
8172 return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText);
8173 }
8174 // change a selector like 'div' to 'name div'
8175 _scopeSelectors(cssText, scopeSelector, hostSelector) {
8176 return processRules(cssText, (rule) => {
8177 let selector = rule.selector;
8178 let content = rule.content;
8179 if (rule.selector[0] != '@') {
8180 selector =
8181 this._scopeSelector(rule.selector, scopeSelector, hostSelector, this.strictStyling);
8182 }
8183 else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') ||
8184 rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) {
8185 content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
8186 }
8187 return new CssRule(selector, content);
8188 });
8189 }
8190 _scopeSelector(selector, scopeSelector, hostSelector, strict) {
8191 return selector.split(',')
8192 .map(part => part.trim().split(_shadowDeepSelectors))
8193 .map((deepParts) => {
8194 const [shallowPart, ...otherParts] = deepParts;
8195 const applyScope = (shallowPart) => {
8196 if (this._selectorNeedsScoping(shallowPart, scopeSelector)) {
8197 return strict ?
8198 this._applyStrictSelectorScope(shallowPart, scopeSelector, hostSelector) :
8199 this._applySelectorScope(shallowPart, scopeSelector, hostSelector);
8200 }
8201 else {
8202 return shallowPart;
8203 }
8204 };
8205 return [applyScope(shallowPart), ...otherParts].join(' ');
8206 })
8207 .join(', ');
8208 }
8209 _selectorNeedsScoping(selector, scopeSelector) {
8210 const re = this._makeScopeMatcher(scopeSelector);
8211 return !re.test(selector);
8212 }
8213 _makeScopeMatcher(scopeSelector) {
8214 const lre = /\[/g;
8215 const rre = /\]/g;
8216 scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
8217 return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
8218 }
8219 _applySelectorScope(selector, scopeSelector, hostSelector) {
8220 // Difference from webcomponents.js: scopeSelector could not be an array
8221 return this._applySimpleSelectorScope(selector, scopeSelector, hostSelector);
8222 }
8223 // scope via name and [is=name]
8224 _applySimpleSelectorScope(selector, scopeSelector, hostSelector) {
8225 // In Android browser, the lastIndex is not reset when the regex is used in String.replace()
8226 _polyfillHostRe.lastIndex = 0;
8227 if (_polyfillHostRe.test(selector)) {
8228 const replaceBy = this.strictStyling ? `[${hostSelector}]` : scopeSelector;
8229 return selector
8230 .replace(_polyfillHostNoCombinatorRe, (hnc, selector) => {
8231 return selector.replace(/([^:]*)(:*)(.*)/, (_, before, colon, after) => {
8232 return before + replaceBy + colon + after;
8233 });
8234 })
8235 .replace(_polyfillHostRe, replaceBy + ' ');
8236 }
8237 return scopeSelector + ' ' + selector;
8238 }
8239 // return a selector with [name] suffix on each simple selector
8240 // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */
8241 _applyStrictSelectorScope(selector, scopeSelector, hostSelector) {
8242 const isRe = /\[is=([^\]]*)\]/g;
8243 scopeSelector = scopeSelector.replace(isRe, (_, ...parts) => parts[0]);
8244 const attrName = '[' + scopeSelector + ']';
8245 const _scopeSelectorPart = (p) => {
8246 let scopedP = p.trim();
8247 if (!scopedP) {
8248 return '';
8249 }
8250 if (p.indexOf(_polyfillHostNoCombinator) > -1) {
8251 scopedP = this._applySimpleSelectorScope(p, scopeSelector, hostSelector);
8252 }
8253 else {
8254 // remove :host since it should be unnecessary
8255 const t = p.replace(_polyfillHostRe, '');
8256 if (t.length > 0) {
8257 const matches = t.match(/([^:]*)(:*)(.*)/);
8258 if (matches) {
8259 scopedP = matches[1] + attrName + matches[2] + matches[3];
8260 }
8261 }
8262 }
8263 return scopedP;
8264 };
8265 const safeContent = new SafeSelector(selector);
8266 selector = safeContent.content();
8267 let scopedSelector = '';
8268 let startIndex = 0;
8269 let res;
8270 const sep = /( |>|\+|~(?!=))\s*/g;
8271 // If a selector appears before :host it should not be shimmed as it
8272 // matches on ancestor elements and not on elements in the host's shadow
8273 // `:host-context(div)` is transformed to
8274 // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator`
8275 // the `div` is not part of the component in the 2nd selectors and should not be scoped.
8276 // Historically `component-tag:host` was matching the component so we also want to preserve
8277 // this behavior to avoid breaking legacy apps (it should not match).
8278 // The behavior should be:
8279 // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything)
8280 // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a
8281 // `:host-context(tag)`)
8282 const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;
8283 // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present
8284 let shouldScope = !hasHost;
8285 while ((res = sep.exec(selector)) !== null) {
8286 const separator = res[1];
8287 const part = selector.slice(startIndex, res.index).trim();
8288 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
8289 const scopedPart = shouldScope ? _scopeSelectorPart(part) : part;
8290 scopedSelector += `${scopedPart} ${separator} `;
8291 startIndex = sep.lastIndex;
8292 }
8293 const part = selector.substring(startIndex);
8294 shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
8295 scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;
8296 // replace the placeholders with their original values
8297 return safeContent.restore(scopedSelector);
8298 }
8299 _insertPolyfillHostInCssText(selector) {
8300 return selector.replace(_colonHostContextRe, _polyfillHostContext)
8301 .replace(_colonHostRe, _polyfillHost);
8302 }
8303}
8304class SafeSelector {
8305 constructor(selector) {
8306 this.placeholders = [];
8307 this.index = 0;
8308 // Replaces attribute selectors with placeholders.
8309 // The WS in [attr="va lue"] would otherwise be interpreted as a selector separator.
8310 selector = selector.replace(/(\[[^\]]*\])/g, (_, keep) => {
8311 const replaceBy = `__ph-${this.index}__`;
8312 this.placeholders.push(keep);
8313 this.index++;
8314 return replaceBy;
8315 });
8316 // Replaces the expression in `:nth-child(2n + 1)` with a placeholder.
8317 // WS and "+" would otherwise be interpreted as selector separators.
8318 this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => {
8319 const replaceBy = `__ph-${this.index}__`;
8320 this.placeholders.push(exp);
8321 this.index++;
8322 return pseudo + replaceBy;
8323 });
8324 }
8325 restore(content) {
8326 return content.replace(/__ph-(\d+)__/g, (ph, index) => this.placeholders[+index]);
8327 }
8328 content() { return this._content; }
8329}
8330const _cssContentNextSelectorRe = /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim;
8331const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
8332const _cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
8333const _polyfillHost = '-shadowcsshost';
8334// note: :host-context pre-processed to -shadowcsshostcontext.
8335const _polyfillHostContext = '-shadowcsscontext';
8336const _parenSuffix = ')(?:\\((' +
8337 '(?:\\([^)(]*\\)|[^)(]*)+?' +
8338 ')\\))?([^,{]*)';
8339const _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim');
8340const _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim');
8341const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
8342const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
8343const _shadowDOMSelectorsRe = [
8344 /::shadow/g,
8345 /::content/g,
8346 // Deprecated selectors
8347 /\/shadow-deep\//g,
8348 /\/shadow\//g,
8349];
8350// The deep combinator is deprecated in the CSS spec
8351// Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future.
8352// see https://github.com/angular/angular/pull/17677
8353const _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g;
8354const _selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$';
8355const _polyfillHostRe = /-shadowcsshost/gim;
8356const _colonHostRe = /:host/gim;
8357const _colonHostContextRe = /:host-context/gim;
8358const _commentRe = /\/\*\s*[\s\S]*?\*\//g;
8359function stripComments(input) {
8360 return input.replace(_commentRe, '');
8361}
8362const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g;
8363function extractCommentsWithHash(input) {
8364 return input.match(_commentWithHashRe) || [];
8365}
8366const _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g;
8367const _curlyRe = /([{}])/g;
8368const OPEN_CURLY = '{';
8369const CLOSE_CURLY = '}';
8370const BLOCK_PLACEHOLDER = '%BLOCK%';
8371class CssRule {
8372 constructor(selector, content) {
8373 this.selector = selector;
8374 this.content = content;
8375 }
8376}
8377function processRules(input, ruleCallback) {
8378 const inputWithEscapedBlocks = escapeBlocks(input);
8379 let nextBlockIndex = 0;
8380 return inputWithEscapedBlocks.escapedString.replace(_ruleRe, function (...m) {
8381 const selector = m[2];
8382 let content = '';
8383 let suffix = m[4];
8384 let contentPrefix = '';
8385 if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
8386 content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
8387 suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
8388 contentPrefix = '{';
8389 }
8390 const rule = ruleCallback(new CssRule(selector, content));
8391 return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
8392 });
8393}
8394class StringWithEscapedBlocks {
8395 constructor(escapedString, blocks) {
8396 this.escapedString = escapedString;
8397 this.blocks = blocks;
8398 }
8399}
8400function escapeBlocks(input) {
8401 const inputParts = input.split(_curlyRe);
8402 const resultParts = [];
8403 const escapedBlocks = [];
8404 let bracketCount = 0;
8405 let currentBlockParts = [];
8406 for (let partIndex = 0; partIndex < inputParts.length; partIndex++) {
8407 const part = inputParts[partIndex];
8408 if (part == CLOSE_CURLY) {
8409 bracketCount--;
8410 }
8411 if (bracketCount > 0) {
8412 currentBlockParts.push(part);
8413 }
8414 else {
8415 if (currentBlockParts.length > 0) {
8416 escapedBlocks.push(currentBlockParts.join(''));
8417 resultParts.push(BLOCK_PLACEHOLDER);
8418 currentBlockParts = [];
8419 }
8420 resultParts.push(part);
8421 }
8422 if (part == OPEN_CURLY) {
8423 bracketCount++;
8424 }
8425 }
8426 if (currentBlockParts.length > 0) {
8427 escapedBlocks.push(currentBlockParts.join(''));
8428 resultParts.push(BLOCK_PLACEHOLDER);
8429 }
8430 return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
8431}
8432
8433/**
8434 * @license
8435 * Copyright Google Inc. All Rights Reserved.
8436 *
8437 * Use of this source code is governed by an MIT-style license that can be
8438 * found in the LICENSE file at https://angular.io/license
8439 */
8440const COMPONENT_VARIABLE = '%COMP%';
8441const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
8442const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
8443class StylesCompileDependency {
8444 constructor(name, moduleUrl, setValue) {
8445 this.name = name;
8446 this.moduleUrl = moduleUrl;
8447 this.setValue = setValue;
8448 }
8449}
8450class CompiledStylesheet {
8451 constructor(outputCtx, stylesVar, dependencies, isShimmed, meta) {
8452 this.outputCtx = outputCtx;
8453 this.stylesVar = stylesVar;
8454 this.dependencies = dependencies;
8455 this.isShimmed = isShimmed;
8456 this.meta = meta;
8457 }
8458}
8459class StyleCompiler {
8460 constructor(_urlResolver) {
8461 this._urlResolver = _urlResolver;
8462 this._shadowCss = new ShadowCss();
8463 }
8464 compileComponent(outputCtx, comp) {
8465 const template = comp.template;
8466 return this._compileStyles(outputCtx, comp, new CompileStylesheetMetadata({
8467 styles: template.styles,
8468 styleUrls: template.styleUrls,
8469 moduleUrl: identifierModuleUrl(comp.type)
8470 }), this.needsStyleShim(comp), true);
8471 }
8472 compileStyles(outputCtx, comp, stylesheet, shim = this.needsStyleShim(comp)) {
8473 return this._compileStyles(outputCtx, comp, stylesheet, shim, false);
8474 }
8475 needsStyleShim(comp) {
8476 return comp.template.encapsulation === ViewEncapsulation.Emulated;
8477 }
8478 _compileStyles(outputCtx, comp, stylesheet, shim, isComponentStylesheet) {
8479 const styleExpressions = stylesheet.styles.map(plainStyle => literal(this._shimIfNeeded(plainStyle, shim)));
8480 const dependencies = [];
8481 stylesheet.styleUrls.forEach((styleUrl) => {
8482 const exprIndex = styleExpressions.length;
8483 // Note: This placeholder will be filled later.
8484 styleExpressions.push(null);
8485 dependencies.push(new StylesCompileDependency(getStylesVarName(null), styleUrl, (value) => styleExpressions[exprIndex] = outputCtx.importExpr(value)));
8486 });
8487 // styles variable contains plain strings and arrays of other styles arrays (recursive),
8488 // so we set its type to dynamic.
8489 const stylesVar = getStylesVarName(isComponentStylesheet ? comp : null);
8490 const stmt = variable(stylesVar)
8491 .set(literalArr(styleExpressions, new ArrayType(DYNAMIC_TYPE, [TypeModifier.Const])))
8492 .toDeclStmt(null, isComponentStylesheet ? [StmtModifier.Final] : [
8493 StmtModifier.Final, StmtModifier.Exported
8494 ]);
8495 outputCtx.statements.push(stmt);
8496 return new CompiledStylesheet(outputCtx, stylesVar, dependencies, shim, stylesheet);
8497 }
8498 _shimIfNeeded(style, shim) {
8499 return shim ? this._shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR) : style;
8500 }
8501}
8502function getStylesVarName(component) {
8503 let result = `styles`;
8504 if (component) {
8505 result += `_${identifierName(component.type)}`;
8506 }
8507 return result;
8508}
8509
8510/**
8511 * @license
8512 * Copyright Google Inc. All Rights Reserved.
8513 *
8514 * Use of this source code is governed by an MIT-style license that can be
8515 * found in the LICENSE file at https://angular.io/license
8516 */
8517/**
8518 * A path is an ordered set of elements. Typically a path is to a
8519 * particular offset in a source file. The head of the list is the top
8520 * most node. The tail is the node that contains the offset directly.
8521 *
8522 * For example, the expression `a + b + c` might have an ast that looks
8523 * like:
8524 * +
8525 * / \
8526 * a +
8527 * / \
8528 * b c
8529 *
8530 * The path to the node at offset 9 would be `['+' at 1-10, '+' at 7-10,
8531 * 'c' at 9-10]` and the path the node at offset 1 would be
8532 * `['+' at 1-10, 'a' at 1-2]`.
8533 */
8534class AstPath {
8535 constructor(path, position = -1) {
8536 this.path = path;
8537 this.position = position;
8538 }
8539 get empty() { return !this.path || !this.path.length; }
8540 get head() { return this.path[0]; }
8541 get tail() { return this.path[this.path.length - 1]; }
8542 parentOf(node) {
8543 return node && this.path[this.path.indexOf(node) - 1];
8544 }
8545 childOf(node) { return this.path[this.path.indexOf(node) + 1]; }
8546 first(ctor) {
8547 for (let i = this.path.length - 1; i >= 0; i--) {
8548 let item = this.path[i];
8549 if (item instanceof ctor)
8550 return item;
8551 }
8552 }
8553 push(node) { this.path.push(node); }
8554 pop() { return this.path.pop(); }
8555}
8556
8557/**
8558 * @license
8559 * Copyright Google Inc. All Rights Reserved.
8560 *
8561 * Use of this source code is governed by an MIT-style license that can be
8562 * found in the LICENSE file at https://angular.io/license
8563 */
8564class Text$3 {
8565 constructor(value, sourceSpan, i18n) {
8566 this.value = value;
8567 this.sourceSpan = sourceSpan;
8568 this.i18n = i18n;
8569 }
8570 visit(visitor, context) { return visitor.visitText(this, context); }
8571}
8572class Expansion {
8573 constructor(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) {
8574 this.switchValue = switchValue;
8575 this.type = type;
8576 this.cases = cases;
8577 this.sourceSpan = sourceSpan;
8578 this.switchValueSourceSpan = switchValueSourceSpan;
8579 this.i18n = i18n;
8580 }
8581 visit(visitor, context) { return visitor.visitExpansion(this, context); }
8582}
8583class ExpansionCase {
8584 constructor(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) {
8585 this.value = value;
8586 this.expression = expression;
8587 this.sourceSpan = sourceSpan;
8588 this.valueSourceSpan = valueSourceSpan;
8589 this.expSourceSpan = expSourceSpan;
8590 }
8591 visit(visitor, context) { return visitor.visitExpansionCase(this, context); }
8592}
8593class Attribute {
8594 constructor(name, value, sourceSpan, valueSpan, i18n) {
8595 this.name = name;
8596 this.value = value;
8597 this.sourceSpan = sourceSpan;
8598 this.valueSpan = valueSpan;
8599 this.i18n = i18n;
8600 }
8601 visit(visitor, context) { return visitor.visitAttribute(this, context); }
8602}
8603class Element$1 {
8604 constructor(name, attrs, children, sourceSpan, startSourceSpan = null, endSourceSpan = null, i18n) {
8605 this.name = name;
8606 this.attrs = attrs;
8607 this.children = children;
8608 this.sourceSpan = sourceSpan;
8609 this.startSourceSpan = startSourceSpan;
8610 this.endSourceSpan = endSourceSpan;
8611 this.i18n = i18n;
8612 }
8613 visit(visitor, context) { return visitor.visitElement(this, context); }
8614}
8615class Comment {
8616 constructor(value, sourceSpan) {
8617 this.value = value;
8618 this.sourceSpan = sourceSpan;
8619 }
8620 visit(visitor, context) { return visitor.visitComment(this, context); }
8621}
8622function visitAll$1(visitor, nodes, context = null) {
8623 const result = [];
8624 const visit = visitor.visit ?
8625 (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) :
8626 (ast) => ast.visit(visitor, context);
8627 nodes.forEach(ast => {
8628 const astResult = visit(ast);
8629 if (astResult) {
8630 result.push(astResult);
8631 }
8632 });
8633 return result;
8634}
8635class RecursiveVisitor$1 {
8636 constructor() { }
8637 visitElement(ast, context) {
8638 this.visitChildren(context, visit => {
8639 visit(ast.attrs);
8640 visit(ast.children);
8641 });
8642 }
8643 visitAttribute(ast, context) { }
8644 visitText(ast, context) { }
8645 visitComment(ast, context) { }
8646 visitExpansion(ast, context) {
8647 return this.visitChildren(context, visit => { visit(ast.cases); });
8648 }
8649 visitExpansionCase(ast, context) { }
8650 visitChildren(context, cb) {
8651 let results = [];
8652 let t = this;
8653 function visit(children) {
8654 if (children)
8655 results.push(visitAll$1(t, children, context));
8656 }
8657 cb(visit);
8658 return Array.prototype.concat.apply([], results);
8659 }
8660}
8661function spanOf(ast) {
8662 const start = ast.sourceSpan.start.offset;
8663 let end = ast.sourceSpan.end.offset;
8664 if (ast instanceof Element$1) {
8665 if (ast.endSourceSpan) {
8666 end = ast.endSourceSpan.end.offset;
8667 }
8668 else if (ast.children && ast.children.length) {
8669 end = spanOf(ast.children[ast.children.length - 1]).end;
8670 }
8671 }
8672 return { start, end };
8673}
8674function findNode(nodes, position) {
8675 const path = [];
8676 const visitor = new class extends RecursiveVisitor$1 {
8677 visit(ast, context) {
8678 const span = spanOf(ast);
8679 if (span.start <= position && position < span.end) {
8680 path.push(ast);
8681 }
8682 else {
8683 // Returning a value here will result in the children being skipped.
8684 return true;
8685 }
8686 }
8687 };
8688 visitAll$1(visitor, nodes);
8689 return new AstPath(path, position);
8690}
8691
8692/**
8693 * @license
8694 * Copyright Google Inc. All Rights Reserved.
8695 *
8696 * Use of this source code is governed by an MIT-style license that can be
8697 * found in the LICENSE file at https://angular.io/license
8698 */
8699var TokenType;
8700(function (TokenType) {
8701 TokenType[TokenType["TAG_OPEN_START"] = 0] = "TAG_OPEN_START";
8702 TokenType[TokenType["TAG_OPEN_END"] = 1] = "TAG_OPEN_END";
8703 TokenType[TokenType["TAG_OPEN_END_VOID"] = 2] = "TAG_OPEN_END_VOID";
8704 TokenType[TokenType["TAG_CLOSE"] = 3] = "TAG_CLOSE";
8705 TokenType[TokenType["TEXT"] = 4] = "TEXT";
8706 TokenType[TokenType["ESCAPABLE_RAW_TEXT"] = 5] = "ESCAPABLE_RAW_TEXT";
8707 TokenType[TokenType["RAW_TEXT"] = 6] = "RAW_TEXT";
8708 TokenType[TokenType["COMMENT_START"] = 7] = "COMMENT_START";
8709 TokenType[TokenType["COMMENT_END"] = 8] = "COMMENT_END";
8710 TokenType[TokenType["CDATA_START"] = 9] = "CDATA_START";
8711 TokenType[TokenType["CDATA_END"] = 10] = "CDATA_END";
8712 TokenType[TokenType["ATTR_NAME"] = 11] = "ATTR_NAME";
8713 TokenType[TokenType["ATTR_QUOTE"] = 12] = "ATTR_QUOTE";
8714 TokenType[TokenType["ATTR_VALUE"] = 13] = "ATTR_VALUE";
8715 TokenType[TokenType["DOC_TYPE"] = 14] = "DOC_TYPE";
8716 TokenType[TokenType["EXPANSION_FORM_START"] = 15] = "EXPANSION_FORM_START";
8717 TokenType[TokenType["EXPANSION_CASE_VALUE"] = 16] = "EXPANSION_CASE_VALUE";
8718 TokenType[TokenType["EXPANSION_CASE_EXP_START"] = 17] = "EXPANSION_CASE_EXP_START";
8719 TokenType[TokenType["EXPANSION_CASE_EXP_END"] = 18] = "EXPANSION_CASE_EXP_END";
8720 TokenType[TokenType["EXPANSION_FORM_END"] = 19] = "EXPANSION_FORM_END";
8721 TokenType[TokenType["EOF"] = 20] = "EOF";
8722})(TokenType || (TokenType = {}));
8723class Token {
8724 constructor(type, parts, sourceSpan) {
8725 this.type = type;
8726 this.parts = parts;
8727 this.sourceSpan = sourceSpan;
8728 }
8729}
8730class TokenError extends ParseError {
8731 constructor(errorMsg, tokenType, span) {
8732 super(span, errorMsg);
8733 this.tokenType = tokenType;
8734 }
8735}
8736class TokenizeResult {
8737 constructor(tokens, errors) {
8738 this.tokens = tokens;
8739 this.errors = errors;
8740 }
8741}
8742function tokenize(source, url, getTagDefinition, options = {}) {
8743 return new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options).tokenize();
8744}
8745const _CR_OR_CRLF_REGEXP = /\r\n?/g;
8746function _unexpectedCharacterErrorMsg(charCode) {
8747 const char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode);
8748 return `Unexpected character "${char}"`;
8749}
8750function _unknownEntityErrorMsg(entitySrc) {
8751 return `Unknown entity "${entitySrc}" - use the "&#<decimal>;" or "&#x<hex>;" syntax`;
8752}
8753class _ControlFlowError {
8754 constructor(error) {
8755 this.error = error;
8756 }
8757}
8758// See http://www.w3.org/TR/html51/syntax.html#writing
8759class _Tokenizer {
8760 /**
8761 * @param _file The html source file being tokenized.
8762 * @param _getTagDefinition A function that will retrieve a tag definition for a given tag name.
8763 * @param options Configuration of the tokenization.
8764 */
8765 constructor(_file, _getTagDefinition, options) {
8766 this._getTagDefinition = _getTagDefinition;
8767 this._currentTokenStart = null;
8768 this._currentTokenType = null;
8769 this._expansionCaseStack = [];
8770 this._inInterpolation = false;
8771 this.tokens = [];
8772 this.errors = [];
8773 this._tokenizeIcu = options.tokenizeExpansionForms || false;
8774 this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
8775 this._leadingTriviaCodePoints =
8776 options.leadingTriviaChars && options.leadingTriviaChars.map(c => c.codePointAt(0) || 0);
8777 const range = options.range || { endPos: _file.content.length, startPos: 0, startLine: 0, startCol: 0 };
8778 this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) :
8779 new PlainCharacterCursor(_file, range);
8780 try {
8781 this._cursor.init();
8782 }
8783 catch (e) {
8784 this.handleError(e);
8785 }
8786 }
8787 _processCarriageReturns(content) {
8788 // http://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream
8789 // In order to keep the original position in the source, we can not
8790 // pre-process it.
8791 // Instead CRs are processed right before instantiating the tokens.
8792 return content.replace(_CR_OR_CRLF_REGEXP, '\n');
8793 }
8794 tokenize() {
8795 while (this._cursor.peek() !== $EOF) {
8796 const start = this._cursor.clone();
8797 try {
8798 if (this._attemptCharCode($LT)) {
8799 if (this._attemptCharCode($BANG)) {
8800 if (this._attemptCharCode($LBRACKET)) {
8801 this._consumeCdata(start);
8802 }
8803 else if (this._attemptCharCode($MINUS)) {
8804 this._consumeComment(start);
8805 }
8806 else {
8807 this._consumeDocType(start);
8808 }
8809 }
8810 else if (this._attemptCharCode($SLASH)) {
8811 this._consumeTagClose(start);
8812 }
8813 else {
8814 this._consumeTagOpen(start);
8815 }
8816 }
8817 else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
8818 this._consumeText();
8819 }
8820 }
8821 catch (e) {
8822 this.handleError(e);
8823 }
8824 }
8825 this._beginToken(TokenType.EOF);
8826 this._endToken([]);
8827 return new TokenizeResult(mergeTextTokens(this.tokens), this.errors);
8828 }
8829 /**
8830 * @returns whether an ICU token has been created
8831 * @internal
8832 */
8833 _tokenizeExpansionForm() {
8834 if (this.isExpansionFormStart()) {
8835 this._consumeExpansionFormStart();
8836 return true;
8837 }
8838 if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) {
8839 this._consumeExpansionCaseStart();
8840 return true;
8841 }
8842 if (this._cursor.peek() === $RBRACE) {
8843 if (this._isInExpansionCase()) {
8844 this._consumeExpansionCaseEnd();
8845 return true;
8846 }
8847 if (this._isInExpansionForm()) {
8848 this._consumeExpansionFormEnd();
8849 return true;
8850 }
8851 }
8852 return false;
8853 }
8854 _beginToken(type, start = this._cursor.clone()) {
8855 this._currentTokenStart = start;
8856 this._currentTokenType = type;
8857 }
8858 _endToken(parts, end = this._cursor.clone()) {
8859 if (this._currentTokenStart === null) {
8860 throw new TokenError('Programming error - attempted to end a token when there was no start to the token', this._currentTokenType, this._cursor.getSpan(end));
8861 }
8862 if (this._currentTokenType === null) {
8863 throw new TokenError('Programming error - attempted to end a token which has no token type', null, this._cursor.getSpan(this._currentTokenStart));
8864 }
8865 const token = new Token(this._currentTokenType, parts, this._cursor.getSpan(this._currentTokenStart, this._leadingTriviaCodePoints));
8866 this.tokens.push(token);
8867 this._currentTokenStart = null;
8868 this._currentTokenType = null;
8869 return token;
8870 }
8871 _createError(msg, span) {
8872 if (this._isInExpansionForm()) {
8873 msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`;
8874 }
8875 const error = new TokenError(msg, this._currentTokenType, span);
8876 this._currentTokenStart = null;
8877 this._currentTokenType = null;
8878 return new _ControlFlowError(error);
8879 }
8880 handleError(e) {
8881 if (e instanceof CursorError) {
8882 e = this._createError(e.msg, this._cursor.getSpan(e.cursor));
8883 }
8884 if (e instanceof _ControlFlowError) {
8885 this.errors.push(e.error);
8886 }
8887 else {
8888 throw e;
8889 }
8890 }
8891 _attemptCharCode(charCode) {
8892 if (this._cursor.peek() === charCode) {
8893 this._cursor.advance();
8894 return true;
8895 }
8896 return false;
8897 }
8898 _attemptCharCodeCaseInsensitive(charCode) {
8899 if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCode)) {
8900 this._cursor.advance();
8901 return true;
8902 }
8903 return false;
8904 }
8905 _requireCharCode(charCode) {
8906 const location = this._cursor.clone();
8907 if (!this._attemptCharCode(charCode)) {
8908 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
8909 }
8910 }
8911 _attemptStr(chars) {
8912 const len = chars.length;
8913 if (this._cursor.charsLeft() < len) {
8914 return false;
8915 }
8916 const initialPosition = this._cursor.clone();
8917 for (let i = 0; i < len; i++) {
8918 if (!this._attemptCharCode(chars.charCodeAt(i))) {
8919 // If attempting to parse the string fails, we want to reset the parser
8920 // to where it was before the attempt
8921 this._cursor = initialPosition;
8922 return false;
8923 }
8924 }
8925 return true;
8926 }
8927 _attemptStrCaseInsensitive(chars) {
8928 for (let i = 0; i < chars.length; i++) {
8929 if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) {
8930 return false;
8931 }
8932 }
8933 return true;
8934 }
8935 _requireStr(chars) {
8936 const location = this._cursor.clone();
8937 if (!this._attemptStr(chars)) {
8938 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
8939 }
8940 }
8941 _attemptCharCodeUntilFn(predicate) {
8942 while (!predicate(this._cursor.peek())) {
8943 this._cursor.advance();
8944 }
8945 }
8946 _requireCharCodeUntilFn(predicate, len) {
8947 const start = this._cursor.clone();
8948 this._attemptCharCodeUntilFn(predicate);
8949 const end = this._cursor.clone();
8950 if (end.diff(start) < len) {
8951 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
8952 }
8953 }
8954 _attemptUntilChar(char) {
8955 while (this._cursor.peek() !== char) {
8956 this._cursor.advance();
8957 }
8958 }
8959 _readChar(decodeEntities) {
8960 if (decodeEntities && this._cursor.peek() === $AMPERSAND) {
8961 return this._decodeEntity();
8962 }
8963 else {
8964 // Don't rely upon reading directly from `_input` as the actual char value
8965 // may have been generated from an escape sequence.
8966 const char = String.fromCodePoint(this._cursor.peek());
8967 this._cursor.advance();
8968 return char;
8969 }
8970 }
8971 _decodeEntity() {
8972 const start = this._cursor.clone();
8973 this._cursor.advance();
8974 if (this._attemptCharCode($HASH)) {
8975 const isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
8976 const codeStart = this._cursor.clone();
8977 this._attemptCharCodeUntilFn(isDigitEntityEnd);
8978 if (this._cursor.peek() != $SEMICOLON) {
8979 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan());
8980 }
8981 const strNum = this._cursor.getChars(codeStart);
8982 this._cursor.advance();
8983 try {
8984 const charCode = parseInt(strNum, isHex ? 16 : 10);
8985 return String.fromCharCode(charCode);
8986 }
8987 catch (_a) {
8988 throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan());
8989 }
8990 }
8991 else {
8992 const nameStart = this._cursor.clone();
8993 this._attemptCharCodeUntilFn(isNamedEntityEnd);
8994 if (this._cursor.peek() != $SEMICOLON) {
8995 this._cursor = nameStart;
8996 return '&';
8997 }
8998 const name = this._cursor.getChars(nameStart);
8999 this._cursor.advance();
9000 const char = NAMED_ENTITIES[name];
9001 if (!char) {
9002 throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
9003 }
9004 return char;
9005 }
9006 }
9007 _consumeRawText(decodeEntities, endMarkerPredicate) {
9008 this._beginToken(decodeEntities ? TokenType.ESCAPABLE_RAW_TEXT : TokenType.RAW_TEXT);
9009 const parts = [];
9010 while (true) {
9011 const tagCloseStart = this._cursor.clone();
9012 const foundEndMarker = endMarkerPredicate();
9013 this._cursor = tagCloseStart;
9014 if (foundEndMarker) {
9015 break;
9016 }
9017 parts.push(this._readChar(decodeEntities));
9018 }
9019 return this._endToken([this._processCarriageReturns(parts.join(''))]);
9020 }
9021 _consumeComment(start) {
9022 this._beginToken(TokenType.COMMENT_START, start);
9023 this._requireCharCode($MINUS);
9024 this._endToken([]);
9025 this._consumeRawText(false, () => this._attemptStr('-->'));
9026 this._beginToken(TokenType.COMMENT_END);
9027 this._requireStr('-->');
9028 this._endToken([]);
9029 }
9030 _consumeCdata(start) {
9031 this._beginToken(TokenType.CDATA_START, start);
9032 this._requireStr('CDATA[');
9033 this._endToken([]);
9034 this._consumeRawText(false, () => this._attemptStr(']]>'));
9035 this._beginToken(TokenType.CDATA_END);
9036 this._requireStr(']]>');
9037 this._endToken([]);
9038 }
9039 _consumeDocType(start) {
9040 this._beginToken(TokenType.DOC_TYPE, start);
9041 const contentStart = this._cursor.clone();
9042 this._attemptUntilChar($GT);
9043 const content = this._cursor.getChars(contentStart);
9044 this._cursor.advance();
9045 this._endToken([content]);
9046 }
9047 _consumePrefixAndName() {
9048 const nameOrPrefixStart = this._cursor.clone();
9049 let prefix = '';
9050 while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) {
9051 this._cursor.advance();
9052 }
9053 let nameStart;
9054 if (this._cursor.peek() === $COLON) {
9055 prefix = this._cursor.getChars(nameOrPrefixStart);
9056 this._cursor.advance();
9057 nameStart = this._cursor.clone();
9058 }
9059 else {
9060 nameStart = nameOrPrefixStart;
9061 }
9062 this._requireCharCodeUntilFn(isNameEnd, prefix === '' ? 0 : 1);
9063 const name = this._cursor.getChars(nameStart);
9064 return [prefix, name];
9065 }
9066 _consumeTagOpen(start) {
9067 let tagName;
9068 let prefix;
9069 let openTagToken;
9070 let tokensBeforeTagOpen = this.tokens.length;
9071 const innerStart = this._cursor.clone();
9072 try {
9073 if (!isAsciiLetter(this._cursor.peek())) {
9074 throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
9075 }
9076 openTagToken = this._consumeTagOpenStart(start);
9077 prefix = openTagToken.parts[0];
9078 tagName = openTagToken.parts[1];
9079 this._attemptCharCodeUntilFn(isNotWhitespace);
9080 while (this._cursor.peek() !== $SLASH && this._cursor.peek() !== $GT) {
9081 this._consumeAttributeName();
9082 this._attemptCharCodeUntilFn(isNotWhitespace);
9083 if (this._attemptCharCode($EQ)) {
9084 this._attemptCharCodeUntilFn(isNotWhitespace);
9085 this._consumeAttributeValue();
9086 }
9087 this._attemptCharCodeUntilFn(isNotWhitespace);
9088 }
9089 this._consumeTagOpenEnd();
9090 }
9091 catch (e) {
9092 if (e instanceof _ControlFlowError) {
9093 // When the start tag is invalid (including invalid "attributes"), assume we want a "<"
9094 this._cursor = innerStart;
9095 if (openTagToken) {
9096 this.tokens.length = tokensBeforeTagOpen;
9097 }
9098 // Back to back text tokens are merged at the end
9099 this._beginToken(TokenType.TEXT, start);
9100 this._endToken(['<']);
9101 return;
9102 }
9103 throw e;
9104 }
9105 const contentTokenType = this._getTagDefinition(tagName).contentType;
9106 if (contentTokenType === TagContentType.RAW_TEXT) {
9107 this._consumeRawTextWithTagClose(prefix, tagName, false);
9108 }
9109 else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) {
9110 this._consumeRawTextWithTagClose(prefix, tagName, true);
9111 }
9112 }
9113 _consumeRawTextWithTagClose(prefix, tagName, decodeEntities) {
9114 const textToken = this._consumeRawText(decodeEntities, () => {
9115 if (!this._attemptCharCode($LT))
9116 return false;
9117 if (!this._attemptCharCode($SLASH))
9118 return false;
9119 this._attemptCharCodeUntilFn(isNotWhitespace);
9120 if (!this._attemptStrCaseInsensitive(tagName))
9121 return false;
9122 this._attemptCharCodeUntilFn(isNotWhitespace);
9123 return this._attemptCharCode($GT);
9124 });
9125 this._beginToken(TokenType.TAG_CLOSE);
9126 this._requireCharCodeUntilFn(code => code === $GT, 3);
9127 this._cursor.advance(); // Consume the `>`
9128 this._endToken([prefix, tagName]);
9129 }
9130 _consumeTagOpenStart(start) {
9131 this._beginToken(TokenType.TAG_OPEN_START, start);
9132 const parts = this._consumePrefixAndName();
9133 return this._endToken(parts);
9134 }
9135 _consumeAttributeName() {
9136 const attrNameStart = this._cursor.peek();
9137 if (attrNameStart === $SQ || attrNameStart === $DQ) {
9138 throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
9139 }
9140 this._beginToken(TokenType.ATTR_NAME);
9141 const prefixAndName = this._consumePrefixAndName();
9142 this._endToken(prefixAndName);
9143 }
9144 _consumeAttributeValue() {
9145 let value;
9146 if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
9147 this._beginToken(TokenType.ATTR_QUOTE);
9148 const quoteChar = this._cursor.peek();
9149 this._cursor.advance();
9150 this._endToken([String.fromCodePoint(quoteChar)]);
9151 this._beginToken(TokenType.ATTR_VALUE);
9152 const parts = [];
9153 while (this._cursor.peek() !== quoteChar) {
9154 parts.push(this._readChar(true));
9155 }
9156 value = parts.join('');
9157 this._endToken([this._processCarriageReturns(value)]);
9158 this._beginToken(TokenType.ATTR_QUOTE);
9159 this._cursor.advance();
9160 this._endToken([String.fromCodePoint(quoteChar)]);
9161 }
9162 else {
9163 this._beginToken(TokenType.ATTR_VALUE);
9164 const valueStart = this._cursor.clone();
9165 this._requireCharCodeUntilFn(isNameEnd, 1);
9166 value = this._cursor.getChars(valueStart);
9167 this._endToken([this._processCarriageReturns(value)]);
9168 }
9169 }
9170 _consumeTagOpenEnd() {
9171 const tokenType = this._attemptCharCode($SLASH) ? TokenType.TAG_OPEN_END_VOID : TokenType.TAG_OPEN_END;
9172 this._beginToken(tokenType);
9173 this._requireCharCode($GT);
9174 this._endToken([]);
9175 }
9176 _consumeTagClose(start) {
9177 this._beginToken(TokenType.TAG_CLOSE, start);
9178 this._attemptCharCodeUntilFn(isNotWhitespace);
9179 const prefixAndName = this._consumePrefixAndName();
9180 this._attemptCharCodeUntilFn(isNotWhitespace);
9181 this._requireCharCode($GT);
9182 this._endToken(prefixAndName);
9183 }
9184 _consumeExpansionFormStart() {
9185 this._beginToken(TokenType.EXPANSION_FORM_START);
9186 this._requireCharCode($LBRACE);
9187 this._endToken([]);
9188 this._expansionCaseStack.push(TokenType.EXPANSION_FORM_START);
9189 this._beginToken(TokenType.RAW_TEXT);
9190 const condition = this._readUntil($COMMA);
9191 this._endToken([condition]);
9192 this._requireCharCode($COMMA);
9193 this._attemptCharCodeUntilFn(isNotWhitespace);
9194 this._beginToken(TokenType.RAW_TEXT);
9195 const type = this._readUntil($COMMA);
9196 this._endToken([type]);
9197 this._requireCharCode($COMMA);
9198 this._attemptCharCodeUntilFn(isNotWhitespace);
9199 }
9200 _consumeExpansionCaseStart() {
9201 this._beginToken(TokenType.EXPANSION_CASE_VALUE);
9202 const value = this._readUntil($LBRACE).trim();
9203 this._endToken([value]);
9204 this._attemptCharCodeUntilFn(isNotWhitespace);
9205 this._beginToken(TokenType.EXPANSION_CASE_EXP_START);
9206 this._requireCharCode($LBRACE);
9207 this._endToken([]);
9208 this._attemptCharCodeUntilFn(isNotWhitespace);
9209 this._expansionCaseStack.push(TokenType.EXPANSION_CASE_EXP_START);
9210 }
9211 _consumeExpansionCaseEnd() {
9212 this._beginToken(TokenType.EXPANSION_CASE_EXP_END);
9213 this._requireCharCode($RBRACE);
9214 this._endToken([]);
9215 this._attemptCharCodeUntilFn(isNotWhitespace);
9216 this._expansionCaseStack.pop();
9217 }
9218 _consumeExpansionFormEnd() {
9219 this._beginToken(TokenType.EXPANSION_FORM_END);
9220 this._requireCharCode($RBRACE);
9221 this._endToken([]);
9222 this._expansionCaseStack.pop();
9223 }
9224 _consumeText() {
9225 const start = this._cursor.clone();
9226 this._beginToken(TokenType.TEXT, start);
9227 const parts = [];
9228 do {
9229 if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) {
9230 parts.push(this._interpolationConfig.start);
9231 this._inInterpolation = true;
9232 }
9233 else if (this._interpolationConfig && this._inInterpolation &&
9234 this._attemptStr(this._interpolationConfig.end)) {
9235 parts.push(this._interpolationConfig.end);
9236 this._inInterpolation = false;
9237 }
9238 else {
9239 parts.push(this._readChar(true));
9240 }
9241 } while (!this._isTextEnd());
9242 this._endToken([this._processCarriageReturns(parts.join(''))]);
9243 }
9244 _isTextEnd() {
9245 if (this._cursor.peek() === $LT || this._cursor.peek() === $EOF) {
9246 return true;
9247 }
9248 if (this._tokenizeIcu && !this._inInterpolation) {
9249 if (this.isExpansionFormStart()) {
9250 // start of an expansion form
9251 return true;
9252 }
9253 if (this._cursor.peek() === $RBRACE && this._isInExpansionCase()) {
9254 // end of and expansion case
9255 return true;
9256 }
9257 }
9258 return false;
9259 }
9260 _readUntil(char) {
9261 const start = this._cursor.clone();
9262 this._attemptUntilChar(char);
9263 return this._cursor.getChars(start);
9264 }
9265 _isInExpansionCase() {
9266 return this._expansionCaseStack.length > 0 &&
9267 this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
9268 TokenType.EXPANSION_CASE_EXP_START;
9269 }
9270 _isInExpansionForm() {
9271 return this._expansionCaseStack.length > 0 &&
9272 this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
9273 TokenType.EXPANSION_FORM_START;
9274 }
9275 isExpansionFormStart() {
9276 if (this._cursor.peek() !== $LBRACE) {
9277 return false;
9278 }
9279 if (this._interpolationConfig) {
9280 const start = this._cursor.clone();
9281 const isInterpolation = this._attemptStr(this._interpolationConfig.start);
9282 this._cursor = start;
9283 return !isInterpolation;
9284 }
9285 return true;
9286 }
9287}
9288function isNotWhitespace(code) {
9289 return !isWhitespace(code) || code === $EOF;
9290}
9291function isNameEnd(code) {
9292 return isWhitespace(code) || code === $GT || code === $SLASH ||
9293 code === $SQ || code === $DQ || code === $EQ;
9294}
9295function isPrefixEnd(code) {
9296 return (code < $a || $z < code) && (code < $A || $Z < code) &&
9297 (code < $0 || code > $9);
9298}
9299function isDigitEntityEnd(code) {
9300 return code == $SEMICOLON || code == $EOF || !isAsciiHexDigit(code);
9301}
9302function isNamedEntityEnd(code) {
9303 return code == $SEMICOLON || code == $EOF || !isAsciiLetter(code);
9304}
9305function isExpansionCaseStart(peek) {
9306 return peek === $EQ || isAsciiLetter(peek) || isDigit(peek);
9307}
9308function compareCharCodeCaseInsensitive(code1, code2) {
9309 return toUpperCaseCharCode(code1) == toUpperCaseCharCode(code2);
9310}
9311function toUpperCaseCharCode(code) {
9312 return code >= $a && code <= $z ? code - $a + $A : code;
9313}
9314function mergeTextTokens(srcTokens) {
9315 const dstTokens = [];
9316 let lastDstToken = undefined;
9317 for (let i = 0; i < srcTokens.length; i++) {
9318 const token = srcTokens[i];
9319 if (lastDstToken && lastDstToken.type == TokenType.TEXT && token.type == TokenType.TEXT) {
9320 lastDstToken.parts[0] += token.parts[0];
9321 lastDstToken.sourceSpan.end = token.sourceSpan.end;
9322 }
9323 else {
9324 lastDstToken = token;
9325 dstTokens.push(lastDstToken);
9326 }
9327 }
9328 return dstTokens;
9329}
9330class PlainCharacterCursor {
9331 constructor(fileOrCursor, range) {
9332 if (fileOrCursor instanceof PlainCharacterCursor) {
9333 this.file = fileOrCursor.file;
9334 this.input = fileOrCursor.input;
9335 this.end = fileOrCursor.end;
9336 this.state = Object.assign({}, fileOrCursor.state);
9337 }
9338 else {
9339 if (!range) {
9340 throw new Error('Programming error: the range argument must be provided with a file argument.');
9341 }
9342 this.file = fileOrCursor;
9343 this.input = fileOrCursor.content;
9344 this.end = range.endPos;
9345 this.state = {
9346 peek: -1,
9347 offset: range.startPos,
9348 line: range.startLine,
9349 column: range.startCol,
9350 };
9351 }
9352 }
9353 clone() { return new PlainCharacterCursor(this); }
9354 peek() { return this.state.peek; }
9355 charsLeft() { return this.end - this.state.offset; }
9356 diff(other) { return this.state.offset - other.state.offset; }
9357 advance() { this.advanceState(this.state); }
9358 init() { this.updatePeek(this.state); }
9359 getSpan(start, leadingTriviaCodePoints) {
9360 start = start || this;
9361 if (leadingTriviaCodePoints) {
9362 start = start.clone();
9363 while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) {
9364 start.advance();
9365 }
9366 }
9367 return new ParseSourceSpan(new ParseLocation(start.file, start.state.offset, start.state.line, start.state.column), new ParseLocation(this.file, this.state.offset, this.state.line, this.state.column));
9368 }
9369 getChars(start) {
9370 return this.input.substring(start.state.offset, this.state.offset);
9371 }
9372 charAt(pos) { return this.input.charCodeAt(pos); }
9373 advanceState(state) {
9374 if (state.offset >= this.end) {
9375 this.state = state;
9376 throw new CursorError('Unexpected character "EOF"', this);
9377 }
9378 const currentChar = this.charAt(state.offset);
9379 if (currentChar === $LF) {
9380 state.line++;
9381 state.column = 0;
9382 }
9383 else if (!isNewLine(currentChar)) {
9384 state.column++;
9385 }
9386 state.offset++;
9387 this.updatePeek(state);
9388 }
9389 updatePeek(state) {
9390 state.peek = state.offset >= this.end ? $EOF : this.charAt(state.offset);
9391 }
9392}
9393class EscapedCharacterCursor extends PlainCharacterCursor {
9394 constructor(fileOrCursor, range) {
9395 if (fileOrCursor instanceof EscapedCharacterCursor) {
9396 super(fileOrCursor);
9397 this.internalState = Object.assign({}, fileOrCursor.internalState);
9398 }
9399 else {
9400 super(fileOrCursor, range);
9401 this.internalState = this.state;
9402 }
9403 }
9404 advance() {
9405 this.state = this.internalState;
9406 super.advance();
9407 this.processEscapeSequence();
9408 }
9409 init() {
9410 super.init();
9411 this.processEscapeSequence();
9412 }
9413 clone() { return new EscapedCharacterCursor(this); }
9414 getChars(start) {
9415 const cursor = start.clone();
9416 let chars = '';
9417 while (cursor.internalState.offset < this.internalState.offset) {
9418 chars += String.fromCodePoint(cursor.peek());
9419 cursor.advance();
9420 }
9421 return chars;
9422 }
9423 /**
9424 * Process the escape sequence that starts at the current position in the text.
9425 *
9426 * This method is called to ensure that `peek` has the unescaped value of escape sequences.
9427 */
9428 processEscapeSequence() {
9429 const peek = () => this.internalState.peek;
9430 if (peek() === $BACKSLASH) {
9431 // We have hit an escape sequence so we need the internal state to become independent
9432 // of the external state.
9433 this.internalState = Object.assign({}, this.state);
9434 // Move past the backslash
9435 this.advanceState(this.internalState);
9436 // First check for standard control char sequences
9437 if (peek() === $n) {
9438 this.state.peek = $LF;
9439 }
9440 else if (peek() === $r) {
9441 this.state.peek = $CR;
9442 }
9443 else if (peek() === $v) {
9444 this.state.peek = $VTAB;
9445 }
9446 else if (peek() === $t) {
9447 this.state.peek = $TAB;
9448 }
9449 else if (peek() === $b) {
9450 this.state.peek = $BSPACE;
9451 }
9452 else if (peek() === $f) {
9453 this.state.peek = $FF;
9454 }
9455 // Now consider more complex sequences
9456 else if (peek() === $u) {
9457 // Unicode code-point sequence
9458 this.advanceState(this.internalState); // advance past the `u` char
9459 if (peek() === $LBRACE) {
9460 // Variable length Unicode, e.g. `\x{123}`
9461 this.advanceState(this.internalState); // advance past the `{` char
9462 // Advance past the variable number of hex digits until we hit a `}` char
9463 const digitStart = this.clone();
9464 let length = 0;
9465 while (peek() !== $RBRACE) {
9466 this.advanceState(this.internalState);
9467 length++;
9468 }
9469 this.state.peek = this.decodeHexDigits(digitStart, length);
9470 }
9471 else {
9472 // Fixed length Unicode, e.g. `\u1234`
9473 const digitStart = this.clone();
9474 this.advanceState(this.internalState);
9475 this.advanceState(this.internalState);
9476 this.advanceState(this.internalState);
9477 this.state.peek = this.decodeHexDigits(digitStart, 4);
9478 }
9479 }
9480 else if (peek() === $x) {
9481 // Hex char code, e.g. `\x2F`
9482 this.advanceState(this.internalState); // advance past the `x` char
9483 const digitStart = this.clone();
9484 this.advanceState(this.internalState);
9485 this.state.peek = this.decodeHexDigits(digitStart, 2);
9486 }
9487 else if (isOctalDigit(peek())) {
9488 // Octal char code, e.g. `\012`,
9489 let octal = '';
9490 let length = 0;
9491 let previous = this.clone();
9492 while (isOctalDigit(peek()) && length < 3) {
9493 previous = this.clone();
9494 octal += String.fromCodePoint(peek());
9495 this.advanceState(this.internalState);
9496 length++;
9497 }
9498 this.state.peek = parseInt(octal, 8);
9499 // Backup one char
9500 this.internalState = previous.internalState;
9501 }
9502 else if (isNewLine(this.internalState.peek)) {
9503 // Line continuation `\` followed by a new line
9504 this.advanceState(this.internalState); // advance over the newline
9505 this.state = this.internalState;
9506 }
9507 else {
9508 // If none of the `if` blocks were executed then we just have an escaped normal character.
9509 // In that case we just, effectively, skip the backslash from the character.
9510 this.state.peek = this.internalState.peek;
9511 }
9512 }
9513 }
9514 decodeHexDigits(start, length) {
9515 const hex = this.input.substr(start.internalState.offset, length);
9516 const charCode = parseInt(hex, 16);
9517 if (!isNaN(charCode)) {
9518 return charCode;
9519 }
9520 else {
9521 start.state = start.internalState;
9522 throw new CursorError('Invalid hexadecimal escape sequence', start);
9523 }
9524 }
9525}
9526class CursorError {
9527 constructor(msg, cursor) {
9528 this.msg = msg;
9529 this.cursor = cursor;
9530 }
9531}
9532
9533/**
9534 * @license
9535 * Copyright Google Inc. All Rights Reserved.
9536 *
9537 * Use of this source code is governed by an MIT-style license that can be
9538 * found in the LICENSE file at https://angular.io/license
9539 */
9540class TreeError extends ParseError {
9541 constructor(elementName, span, msg) {
9542 super(span, msg);
9543 this.elementName = elementName;
9544 }
9545 static create(elementName, span, msg) {
9546 return new TreeError(elementName, span, msg);
9547 }
9548}
9549class ParseTreeResult {
9550 constructor(rootNodes, errors) {
9551 this.rootNodes = rootNodes;
9552 this.errors = errors;
9553 }
9554}
9555class Parser {
9556 constructor(getTagDefinition) {
9557 this.getTagDefinition = getTagDefinition;
9558 }
9559 parse(source, url, options) {
9560 const tokensAndErrors = tokenize(source, url, this.getTagDefinition, options);
9561 const treeAndErrors = new _TreeBuilder(tokensAndErrors.tokens, this.getTagDefinition).build();
9562 return new ParseTreeResult(treeAndErrors.rootNodes, tokensAndErrors.errors.concat(treeAndErrors.errors));
9563 }
9564}
9565class _TreeBuilder {
9566 constructor(tokens, getTagDefinition) {
9567 this.tokens = tokens;
9568 this.getTagDefinition = getTagDefinition;
9569 this._index = -1;
9570 this._rootNodes = [];
9571 this._errors = [];
9572 this._elementStack = [];
9573 this._advance();
9574 }
9575 build() {
9576 while (this._peek.type !== TokenType.EOF) {
9577 if (this._peek.type === TokenType.TAG_OPEN_START) {
9578 this._consumeStartTag(this._advance());
9579 }
9580 else if (this._peek.type === TokenType.TAG_CLOSE) {
9581 this._consumeEndTag(this._advance());
9582 }
9583 else if (this._peek.type === TokenType.CDATA_START) {
9584 this._closeVoidElement();
9585 this._consumeCdata(this._advance());
9586 }
9587 else if (this._peek.type === TokenType.COMMENT_START) {
9588 this._closeVoidElement();
9589 this._consumeComment(this._advance());
9590 }
9591 else if (this._peek.type === TokenType.TEXT || this._peek.type === TokenType.RAW_TEXT ||
9592 this._peek.type === TokenType.ESCAPABLE_RAW_TEXT) {
9593 this._closeVoidElement();
9594 this._consumeText(this._advance());
9595 }
9596 else if (this._peek.type === TokenType.EXPANSION_FORM_START) {
9597 this._consumeExpansion(this._advance());
9598 }
9599 else {
9600 // Skip all other tokens...
9601 this._advance();
9602 }
9603 }
9604 return new ParseTreeResult(this._rootNodes, this._errors);
9605 }
9606 _advance() {
9607 const prev = this._peek;
9608 if (this._index < this.tokens.length - 1) {
9609 // Note: there is always an EOF token at the end
9610 this._index++;
9611 }
9612 this._peek = this.tokens[this._index];
9613 return prev;
9614 }
9615 _advanceIf(type) {
9616 if (this._peek.type === type) {
9617 return this._advance();
9618 }
9619 return null;
9620 }
9621 _consumeCdata(startToken) {
9622 this._consumeText(this._advance());
9623 this._advanceIf(TokenType.CDATA_END);
9624 }
9625 _consumeComment(token) {
9626 const text = this._advanceIf(TokenType.RAW_TEXT);
9627 this._advanceIf(TokenType.COMMENT_END);
9628 const value = text != null ? text.parts[0].trim() : null;
9629 this._addToParent(new Comment(value, token.sourceSpan));
9630 }
9631 _consumeExpansion(token) {
9632 const switchValue = this._advance();
9633 const type = this._advance();
9634 const cases = [];
9635 // read =
9636 while (this._peek.type === TokenType.EXPANSION_CASE_VALUE) {
9637 const expCase = this._parseExpansionCase();
9638 if (!expCase)
9639 return; // error
9640 cases.push(expCase);
9641 }
9642 // read the final }
9643 if (this._peek.type !== TokenType.EXPANSION_FORM_END) {
9644 this._errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`));
9645 return;
9646 }
9647 const sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end);
9648 this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan));
9649 this._advance();
9650 }
9651 _parseExpansionCase() {
9652 const value = this._advance();
9653 // read {
9654 if (this._peek.type !== TokenType.EXPANSION_CASE_EXP_START) {
9655 this._errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`));
9656 return null;
9657 }
9658 // read until }
9659 const start = this._advance();
9660 const exp = this._collectExpansionExpTokens(start);
9661 if (!exp)
9662 return null;
9663 const end = this._advance();
9664 exp.push(new Token(TokenType.EOF, [], end.sourceSpan));
9665 // parse everything in between { and }
9666 const parsedExp = new _TreeBuilder(exp, this.getTagDefinition).build();
9667 if (parsedExp.errors.length > 0) {
9668 this._errors = this._errors.concat(parsedExp.errors);
9669 return null;
9670 }
9671 const sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end);
9672 const expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end);
9673 return new ExpansionCase(value.parts[0], parsedExp.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan);
9674 }
9675 _collectExpansionExpTokens(start) {
9676 const exp = [];
9677 const expansionFormStack = [TokenType.EXPANSION_CASE_EXP_START];
9678 while (true) {
9679 if (this._peek.type === TokenType.EXPANSION_FORM_START ||
9680 this._peek.type === TokenType.EXPANSION_CASE_EXP_START) {
9681 expansionFormStack.push(this._peek.type);
9682 }
9683 if (this._peek.type === TokenType.EXPANSION_CASE_EXP_END) {
9684 if (lastOnStack(expansionFormStack, TokenType.EXPANSION_CASE_EXP_START)) {
9685 expansionFormStack.pop();
9686 if (expansionFormStack.length == 0)
9687 return exp;
9688 }
9689 else {
9690 this._errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9691 return null;
9692 }
9693 }
9694 if (this._peek.type === TokenType.EXPANSION_FORM_END) {
9695 if (lastOnStack(expansionFormStack, TokenType.EXPANSION_FORM_START)) {
9696 expansionFormStack.pop();
9697 }
9698 else {
9699 this._errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9700 return null;
9701 }
9702 }
9703 if (this._peek.type === TokenType.EOF) {
9704 this._errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
9705 return null;
9706 }
9707 exp.push(this._advance());
9708 }
9709 }
9710 _consumeText(token) {
9711 let text = token.parts[0];
9712 if (text.length > 0 && text[0] == '\n') {
9713 const parent = this._getParentElement();
9714 if (parent != null && parent.children.length == 0 &&
9715 this.getTagDefinition(parent.name).ignoreFirstLf) {
9716 text = text.substring(1);
9717 }
9718 }
9719 if (text.length > 0) {
9720 this._addToParent(new Text$3(text, token.sourceSpan));
9721 }
9722 }
9723 _closeVoidElement() {
9724 const el = this._getParentElement();
9725 if (el && this.getTagDefinition(el.name).isVoid) {
9726 this._elementStack.pop();
9727 }
9728 }
9729 _consumeStartTag(startTagToken) {
9730 const prefix = startTagToken.parts[0];
9731 const name = startTagToken.parts[1];
9732 const attrs = [];
9733 while (this._peek.type === TokenType.ATTR_NAME) {
9734 attrs.push(this._consumeAttr(this._advance()));
9735 }
9736 const fullName = this._getElementFullName(prefix, name, this._getParentElement());
9737 let selfClosing = false;
9738 // Note: There could have been a tokenizer error
9739 // so that we don't get a token for the end tag...
9740 if (this._peek.type === TokenType.TAG_OPEN_END_VOID) {
9741 this._advance();
9742 selfClosing = true;
9743 const tagDef = this.getTagDefinition(fullName);
9744 if (!(tagDef.canSelfClose || getNsPrefix(fullName) !== null || tagDef.isVoid)) {
9745 this._errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void and foreign elements can be self closed "${startTagToken.parts[1]}"`));
9746 }
9747 }
9748 else if (this._peek.type === TokenType.TAG_OPEN_END) {
9749 this._advance();
9750 selfClosing = false;
9751 }
9752 const end = this._peek.sourceSpan.start;
9753 const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end);
9754 const el = new Element$1(fullName, attrs, [], span, span, undefined);
9755 this._pushElement(el);
9756 if (selfClosing) {
9757 this._popElement(fullName);
9758 el.endSourceSpan = span;
9759 }
9760 }
9761 _pushElement(el) {
9762 const parentEl = this._getParentElement();
9763 if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
9764 this._elementStack.pop();
9765 }
9766 this._addToParent(el);
9767 this._elementStack.push(el);
9768 }
9769 _consumeEndTag(endTagToken) {
9770 const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
9771 if (this._getParentElement()) {
9772 this._getParentElement().endSourceSpan = endTagToken.sourceSpan;
9773 }
9774 if (this.getTagDefinition(fullName).isVoid) {
9775 this._errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
9776 }
9777 else if (!this._popElement(fullName)) {
9778 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`;
9779 this._errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
9780 }
9781 }
9782 _popElement(fullName) {
9783 for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
9784 const el = this._elementStack[stackIndex];
9785 if (el.name == fullName) {
9786 this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
9787 return true;
9788 }
9789 if (!this.getTagDefinition(el.name).closedByParent) {
9790 return false;
9791 }
9792 }
9793 return false;
9794 }
9795 _consumeAttr(attrName) {
9796 const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
9797 let end = attrName.sourceSpan.end;
9798 let value = '';
9799 let valueSpan = undefined;
9800 if (this._peek.type === TokenType.ATTR_QUOTE) {
9801 this._advance();
9802 }
9803 if (this._peek.type === TokenType.ATTR_VALUE) {
9804 const valueToken = this._advance();
9805 value = valueToken.parts[0];
9806 end = valueToken.sourceSpan.end;
9807 valueSpan = valueToken.sourceSpan;
9808 }
9809 if (this._peek.type === TokenType.ATTR_QUOTE) {
9810 const quoteToken = this._advance();
9811 end = quoteToken.sourceSpan.end;
9812 }
9813 return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end), valueSpan);
9814 }
9815 _getParentElement() {
9816 return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
9817 }
9818 /**
9819 * Returns the parent in the DOM and the container.
9820 *
9821 * `<ng-container>` elements are skipped as they are not rendered as DOM element.
9822 */
9823 _getParentElementSkippingContainers() {
9824 let container = null;
9825 for (let i = this._elementStack.length - 1; i >= 0; i--) {
9826 if (!isNgContainer(this._elementStack[i].name)) {
9827 return { parent: this._elementStack[i], container };
9828 }
9829 container = this._elementStack[i];
9830 }
9831 return { parent: null, container };
9832 }
9833 _addToParent(node) {
9834 const parent = this._getParentElement();
9835 if (parent != null) {
9836 parent.children.push(node);
9837 }
9838 else {
9839 this._rootNodes.push(node);
9840 }
9841 }
9842 /**
9843 * Insert a node between the parent and the container.
9844 * When no container is given, the node is appended as a child of the parent.
9845 * Also updates the element stack accordingly.
9846 *
9847 * @internal
9848 */
9849 _insertBeforeContainer(parent, container, node) {
9850 if (!container) {
9851 this._addToParent(node);
9852 this._elementStack.push(node);
9853 }
9854 else {
9855 if (parent) {
9856 // replace the container with the new node in the children
9857 const index = parent.children.indexOf(container);
9858 parent.children[index] = node;
9859 }
9860 else {
9861 this._rootNodes.push(node);
9862 }
9863 node.children.push(container);
9864 this._elementStack.splice(this._elementStack.indexOf(container), 0, node);
9865 }
9866 }
9867 _getElementFullName(prefix, localName, parentElement) {
9868 if (prefix === '') {
9869 prefix = this.getTagDefinition(localName).implicitNamespacePrefix || '';
9870 if (prefix === '' && parentElement != null) {
9871 prefix = getNsPrefix(parentElement.name);
9872 }
9873 }
9874 return mergeNsAndName(prefix, localName);
9875 }
9876}
9877function lastOnStack(stack, element) {
9878 return stack.length > 0 && stack[stack.length - 1] === element;
9879}
9880
9881/**
9882 * @license
9883 * Copyright Google Inc. All Rights Reserved.
9884 *
9885 * Use of this source code is governed by an MIT-style license that can be
9886 * found in the LICENSE file at https://angular.io/license
9887 */
9888class HtmlParser extends Parser {
9889 constructor() { super(getHtmlTagDefinition); }
9890 parse(source, url, options) {
9891 return super.parse(source, url, options);
9892 }
9893}
9894
9895/**
9896 * @license
9897 * Copyright Google Inc. All Rights Reserved.
9898 *
9899 * Use of this source code is governed by an MIT-style license that can be
9900 * found in the LICENSE file at https://angular.io/license
9901 */
9902const PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces';
9903const SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']);
9904// Equivalent to \s with \u00a0 (non-breaking space) excluded.
9905// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
9906const WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
9907const NO_WS_REGEXP = new RegExp(`[^${WS_CHARS}]`);
9908const WS_REPLACE_REGEXP = new RegExp(`[${WS_CHARS}]{2,}`, 'g');
9909function hasPreserveWhitespacesAttr(attrs) {
9910 return attrs.some((attr) => attr.name === PRESERVE_WS_ATTR_NAME);
9911}
9912/**
9913 * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
9914 * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
9915 * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
9916 * and later on replaced by a space. We are re-implementing the same idea here.
9917 */
9918function replaceNgsp(value) {
9919 // lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE
9920 return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' ');
9921}
9922/**
9923 * This visitor can walk HTML parse tree and remove / trim text nodes using the following rules:
9924 * - consider spaces, tabs and new lines as whitespace characters;
9925 * - drop text nodes consisting of whitespace characters only;
9926 * - for all other text nodes replace consecutive whitespace characters with one space;
9927 * - convert &ngsp; pseudo-entity to a single space;
9928 *
9929 * Removal and trimming of whitespaces have positive performance impact (less code to generate
9930 * while compiling templates, faster view creation). At the same time it can be "destructive"
9931 * in some cases (whitespaces can influence layout). Because of the potential of breaking layout
9932 * this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for
9933 * whitespace removal. The default option for whitespace removal will be revisited in Angular 6
9934 * and might be changed to "on" by default.
9935 */
9936class WhitespaceVisitor {
9937 visitElement(element, context) {
9938 if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
9939 // don't descent into elements where we need to preserve whitespaces
9940 // but still visit all attributes to eliminate one used as a market to preserve WS
9941 return new Element$1(element.name, visitAll$1(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
9942 }
9943 return new Element$1(element.name, element.attrs, visitAll$1(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
9944 }
9945 visitAttribute(attribute, context) {
9946 return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null;
9947 }
9948 visitText(text, context) {
9949 const isNotBlank = text.value.match(NO_WS_REGEXP);
9950 if (isNotBlank) {
9951 return new Text$3(replaceNgsp(text.value).replace(WS_REPLACE_REGEXP, ' '), text.sourceSpan, text.i18n);
9952 }
9953 return null;
9954 }
9955 visitComment(comment, context) { return comment; }
9956 visitExpansion(expansion, context) { return expansion; }
9957 visitExpansionCase(expansionCase, context) { return expansionCase; }
9958}
9959function removeWhitespaces(htmlAstWithErrors) {
9960 return new ParseTreeResult(visitAll$1(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors);
9961}
9962
9963/**
9964 * @license
9965 * Copyright Google Inc. All Rights Reserved.
9966 *
9967 * Use of this source code is governed by an MIT-style license that can be
9968 * found in the LICENSE file at https://angular.io/license
9969 */
9970// http://cldr.unicode.org/index/cldr-spec/plural-rules
9971const PLURAL_CASES = ['zero', 'one', 'two', 'few', 'many', 'other'];
9972/**
9973 * Expands special forms into elements.
9974 *
9975 * For example,
9976 *
9977 * ```
9978 * { messages.length, plural,
9979 * =0 {zero}
9980 * =1 {one}
9981 * other {more than one}
9982 * }
9983 * ```
9984 *
9985 * will be expanded into
9986 *
9987 * ```
9988 * <ng-container [ngPlural]="messages.length">
9989 * <ng-template ngPluralCase="=0">zero</ng-template>
9990 * <ng-template ngPluralCase="=1">one</ng-template>
9991 * <ng-template ngPluralCase="other">more than one</ng-template>
9992 * </ng-container>
9993 * ```
9994 */
9995function expandNodes(nodes) {
9996 const expander = new _Expander();
9997 return new ExpansionResult(visitAll$1(expander, nodes), expander.isExpanded, expander.errors);
9998}
9999class ExpansionResult {
10000 constructor(nodes, expanded, errors) {
10001 this.nodes = nodes;
10002 this.expanded = expanded;
10003 this.errors = errors;
10004 }
10005}
10006class ExpansionError extends ParseError {
10007 constructor(span, errorMsg) { super(span, errorMsg); }
10008}
10009/**
10010 * Expand expansion forms (plural, select) to directives
10011 *
10012 * @internal
10013 */
10014class _Expander {
10015 constructor() {
10016 this.isExpanded = false;
10017 this.errors = [];
10018 }
10019 visitElement(element, context) {
10020 return new Element$1(element.name, element.attrs, visitAll$1(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
10021 }
10022 visitAttribute(attribute, context) { return attribute; }
10023 visitText(text, context) { return text; }
10024 visitComment(comment, context) { return comment; }
10025 visitExpansion(icu, context) {
10026 this.isExpanded = true;
10027 return icu.type == 'plural' ? _expandPluralForm(icu, this.errors) :
10028 _expandDefaultForm(icu, this.errors);
10029 }
10030 visitExpansionCase(icuCase, context) {
10031 throw new Error('Should not be reached');
10032 }
10033}
10034// Plural forms are expanded to `NgPlural` and `NgPluralCase`s
10035function _expandPluralForm(ast, errors) {
10036 const children = ast.cases.map(c => {
10037 if (PLURAL_CASES.indexOf(c.value) == -1 && !c.value.match(/^=\d+$/)) {
10038 errors.push(new ExpansionError(c.valueSourceSpan, `Plural cases should be "=<number>" or one of ${PLURAL_CASES.join(", ")}`));
10039 }
10040 const expansionResult = expandNodes(c.expression);
10041 errors.push(...expansionResult.errors);
10042 return new Element$1(`ng-template`, [new Attribute('ngPluralCase', `${c.value}`, c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
10043 });
10044 const switchAttr = new Attribute('[ngPlural]', ast.switchValue, ast.switchValueSourceSpan);
10045 return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
10046}
10047// ICU messages (excluding plural form) are expanded to `NgSwitch` and `NgSwitchCase`s
10048function _expandDefaultForm(ast, errors) {
10049 const children = ast.cases.map(c => {
10050 const expansionResult = expandNodes(c.expression);
10051 errors.push(...expansionResult.errors);
10052 if (c.value === 'other') {
10053 // other is the default case when no values match
10054 return new Element$1(`ng-template`, [new Attribute('ngSwitchDefault', '', c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
10055 }
10056 return new Element$1(`ng-template`, [new Attribute('ngSwitchCase', `${c.value}`, c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
10057 });
10058 const switchAttr = new Attribute('[ngSwitch]', ast.switchValue, ast.switchValueSourceSpan);
10059 return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
10060}
10061
10062/**
10063 * @license
10064 * Copyright Google Inc. All Rights Reserved.
10065 *
10066 * Use of this source code is governed by an MIT-style license that can be
10067 * found in the LICENSE file at https://angular.io/license
10068 */
10069/**
10070 * A segment of text within the template.
10071 */
10072class TextAst {
10073 constructor(value, ngContentIndex, sourceSpan) {
10074 this.value = value;
10075 this.ngContentIndex = ngContentIndex;
10076 this.sourceSpan = sourceSpan;
10077 }
10078 visit(visitor, context) { return visitor.visitText(this, context); }
10079}
10080/**
10081 * A bound expression within the text of a template.
10082 */
10083class BoundTextAst {
10084 constructor(value, ngContentIndex, sourceSpan) {
10085 this.value = value;
10086 this.ngContentIndex = ngContentIndex;
10087 this.sourceSpan = sourceSpan;
10088 }
10089 visit(visitor, context) {
10090 return visitor.visitBoundText(this, context);
10091 }
10092}
10093/**
10094 * A plain attribute on an element.
10095 */
10096class AttrAst {
10097 constructor(name, value, sourceSpan) {
10098 this.name = name;
10099 this.value = value;
10100 this.sourceSpan = sourceSpan;
10101 }
10102 visit(visitor, context) { return visitor.visitAttr(this, context); }
10103}
10104const BoundPropertyMapping = {
10105 [4 /* Animation */]: 4 /* Animation */,
10106 [1 /* Attribute */]: 1 /* Attribute */,
10107 [2 /* Class */]: 2 /* Class */,
10108 [0 /* Property */]: 0 /* Property */,
10109 [3 /* Style */]: 3 /* Style */,
10110};
10111/**
10112 * A binding for an element property (e.g. `[property]="expression"`) or an animation trigger (e.g.
10113 * `[@trigger]="stateExp"`)
10114 */
10115class BoundElementPropertyAst {
10116 constructor(name, type, securityContext, value, unit, sourceSpan) {
10117 this.name = name;
10118 this.type = type;
10119 this.securityContext = securityContext;
10120 this.value = value;
10121 this.unit = unit;
10122 this.sourceSpan = sourceSpan;
10123 this.isAnimation = this.type === 4 /* Animation */;
10124 }
10125 static fromBoundProperty(prop) {
10126 const type = BoundPropertyMapping[prop.type];
10127 return new BoundElementPropertyAst(prop.name, type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan);
10128 }
10129 visit(visitor, context) {
10130 return visitor.visitElementProperty(this, context);
10131 }
10132}
10133/**
10134 * A binding for an element event (e.g. `(event)="handler()"`) or an animation trigger event (e.g.
10135 * `(@trigger.phase)="callback($event)"`).
10136 */
10137class BoundEventAst {
10138 constructor(name, target, phase, handler, sourceSpan, handlerSpan) {
10139 this.name = name;
10140 this.target = target;
10141 this.phase = phase;
10142 this.handler = handler;
10143 this.sourceSpan = sourceSpan;
10144 this.handlerSpan = handlerSpan;
10145 this.fullName = BoundEventAst.calcFullName(this.name, this.target, this.phase);
10146 this.isAnimation = !!this.phase;
10147 }
10148 static calcFullName(name, target, phase) {
10149 if (target) {
10150 return `${target}:${name}`;
10151 }
10152 if (phase) {
10153 return `@${name}.${phase}`;
10154 }
10155 return name;
10156 }
10157 static fromParsedEvent(event) {
10158 const target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
10159 const phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
10160 return new BoundEventAst(event.name, target, phase, event.handler, event.sourceSpan, event.handlerSpan);
10161 }
10162 visit(visitor, context) {
10163 return visitor.visitEvent(this, context);
10164 }
10165}
10166/**
10167 * A reference declaration on an element (e.g. `let someName="expression"`).
10168 */
10169class ReferenceAst {
10170 constructor(name, value, originalValue, sourceSpan) {
10171 this.name = name;
10172 this.value = value;
10173 this.originalValue = originalValue;
10174 this.sourceSpan = sourceSpan;
10175 }
10176 visit(visitor, context) {
10177 return visitor.visitReference(this, context);
10178 }
10179}
10180/**
10181 * A variable declaration on a <ng-template> (e.g. `var-someName="someLocalName"`).
10182 */
10183class VariableAst {
10184 constructor(name, value, sourceSpan) {
10185 this.name = name;
10186 this.value = value;
10187 this.sourceSpan = sourceSpan;
10188 }
10189 static fromParsedVariable(v) {
10190 return new VariableAst(v.name, v.value, v.sourceSpan);
10191 }
10192 visit(visitor, context) {
10193 return visitor.visitVariable(this, context);
10194 }
10195}
10196/**
10197 * An element declaration in a template.
10198 */
10199class ElementAst {
10200 constructor(name, attrs, inputs, outputs, references, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan, endSourceSpan) {
10201 this.name = name;
10202 this.attrs = attrs;
10203 this.inputs = inputs;
10204 this.outputs = outputs;
10205 this.references = references;
10206 this.directives = directives;
10207 this.providers = providers;
10208 this.hasViewContainer = hasViewContainer;
10209 this.queryMatches = queryMatches;
10210 this.children = children;
10211 this.ngContentIndex = ngContentIndex;
10212 this.sourceSpan = sourceSpan;
10213 this.endSourceSpan = endSourceSpan;
10214 }
10215 visit(visitor, context) {
10216 return visitor.visitElement(this, context);
10217 }
10218}
10219/**
10220 * A `<ng-template>` element included in an Angular template.
10221 */
10222class EmbeddedTemplateAst {
10223 constructor(attrs, outputs, references, variables, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan) {
10224 this.attrs = attrs;
10225 this.outputs = outputs;
10226 this.references = references;
10227 this.variables = variables;
10228 this.directives = directives;
10229 this.providers = providers;
10230 this.hasViewContainer = hasViewContainer;
10231 this.queryMatches = queryMatches;
10232 this.children = children;
10233 this.ngContentIndex = ngContentIndex;
10234 this.sourceSpan = sourceSpan;
10235 }
10236 visit(visitor, context) {
10237 return visitor.visitEmbeddedTemplate(this, context);
10238 }
10239}
10240/**
10241 * A directive property with a bound value (e.g. `*ngIf="condition").
10242 */
10243class BoundDirectivePropertyAst {
10244 constructor(directiveName, templateName, value, sourceSpan) {
10245 this.directiveName = directiveName;
10246 this.templateName = templateName;
10247 this.value = value;
10248 this.sourceSpan = sourceSpan;
10249 }
10250 visit(visitor, context) {
10251 return visitor.visitDirectiveProperty(this, context);
10252 }
10253}
10254/**
10255 * A directive declared on an element.
10256 */
10257class DirectiveAst {
10258 constructor(directive, inputs, hostProperties, hostEvents, contentQueryStartId, sourceSpan) {
10259 this.directive = directive;
10260 this.inputs = inputs;
10261 this.hostProperties = hostProperties;
10262 this.hostEvents = hostEvents;
10263 this.contentQueryStartId = contentQueryStartId;
10264 this.sourceSpan = sourceSpan;
10265 }
10266 visit(visitor, context) {
10267 return visitor.visitDirective(this, context);
10268 }
10269}
10270/**
10271 * A provider declared on an element
10272 */
10273class ProviderAst {
10274 constructor(token, multiProvider, eager, providers, providerType, lifecycleHooks, sourceSpan, isModule) {
10275 this.token = token;
10276 this.multiProvider = multiProvider;
10277 this.eager = eager;
10278 this.providers = providers;
10279 this.providerType = providerType;
10280 this.lifecycleHooks = lifecycleHooks;
10281 this.sourceSpan = sourceSpan;
10282 this.isModule = isModule;
10283 }
10284 visit(visitor, context) {
10285 // No visit method in the visitor for now...
10286 return null;
10287 }
10288}
10289var ProviderAstType;
10290(function (ProviderAstType) {
10291 ProviderAstType[ProviderAstType["PublicService"] = 0] = "PublicService";
10292 ProviderAstType[ProviderAstType["PrivateService"] = 1] = "PrivateService";
10293 ProviderAstType[ProviderAstType["Component"] = 2] = "Component";
10294 ProviderAstType[ProviderAstType["Directive"] = 3] = "Directive";
10295 ProviderAstType[ProviderAstType["Builtin"] = 4] = "Builtin";
10296})(ProviderAstType || (ProviderAstType = {}));
10297/**
10298 * Position where content is to be projected (instance of `<ng-content>` in a template).
10299 */
10300class NgContentAst {
10301 constructor(index, ngContentIndex, sourceSpan) {
10302 this.index = index;
10303 this.ngContentIndex = ngContentIndex;
10304 this.sourceSpan = sourceSpan;
10305 }
10306 visit(visitor, context) {
10307 return visitor.visitNgContent(this, context);
10308 }
10309}
10310/**
10311 * A visitor that accepts each node but doesn't do anything. It is intended to be used
10312 * as the base class for a visitor that is only interested in a subset of the node types.
10313 */
10314class NullTemplateVisitor {
10315 visitNgContent(ast, context) { }
10316 visitEmbeddedTemplate(ast, context) { }
10317 visitElement(ast, context) { }
10318 visitReference(ast, context) { }
10319 visitVariable(ast, context) { }
10320 visitEvent(ast, context) { }
10321 visitElementProperty(ast, context) { }
10322 visitAttr(ast, context) { }
10323 visitBoundText(ast, context) { }
10324 visitText(ast, context) { }
10325 visitDirective(ast, context) { }
10326 visitDirectiveProperty(ast, context) { }
10327}
10328/**
10329 * Base class that can be used to build a visitor that visits each node
10330 * in an template ast recursively.
10331 */
10332class RecursiveTemplateAstVisitor extends NullTemplateVisitor {
10333 constructor() { super(); }
10334 // Nodes with children
10335 visitEmbeddedTemplate(ast, context) {
10336 return this.visitChildren(context, visit => {
10337 visit(ast.attrs);
10338 visit(ast.references);
10339 visit(ast.variables);
10340 visit(ast.directives);
10341 visit(ast.providers);
10342 visit(ast.children);
10343 });
10344 }
10345 visitElement(ast, context) {
10346 return this.visitChildren(context, visit => {
10347 visit(ast.attrs);
10348 visit(ast.inputs);
10349 visit(ast.outputs);
10350 visit(ast.references);
10351 visit(ast.directives);
10352 visit(ast.providers);
10353 visit(ast.children);
10354 });
10355 }
10356 visitDirective(ast, context) {
10357 return this.visitChildren(context, visit => {
10358 visit(ast.inputs);
10359 visit(ast.hostProperties);
10360 visit(ast.hostEvents);
10361 });
10362 }
10363 visitChildren(context, cb) {
10364 let results = [];
10365 let t = this;
10366 function visit(children) {
10367 if (children && children.length)
10368 results.push(templateVisitAll(t, children, context));
10369 }
10370 cb(visit);
10371 return Array.prototype.concat.apply([], results);
10372 }
10373}
10374/**
10375 * Visit every node in a list of {@link TemplateAst}s with the given {@link TemplateAstVisitor}.
10376 */
10377function templateVisitAll(visitor, asts, context = null) {
10378 const result = [];
10379 const visit = visitor.visit ?
10380 (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) :
10381 (ast) => ast.visit(visitor, context);
10382 asts.forEach(ast => {
10383 const astResult = visit(ast);
10384 if (astResult) {
10385 result.push(astResult);
10386 }
10387 });
10388 return result;
10389}
10390
10391/**
10392 * @license
10393 * Copyright Google Inc. All Rights Reserved.
10394 *
10395 * Use of this source code is governed by an MIT-style license that can be
10396 * found in the LICENSE file at https://angular.io/license
10397 */
10398class ProviderError extends ParseError {
10399 constructor(message, span) { super(span, message); }
10400}
10401class ProviderViewContext {
10402 constructor(reflector, component) {
10403 this.reflector = reflector;
10404 this.component = component;
10405 this.errors = [];
10406 this.viewQueries = _getViewQueries(component);
10407 this.viewProviders = new Map();
10408 component.viewProviders.forEach((provider) => {
10409 if (this.viewProviders.get(tokenReference(provider.token)) == null) {
10410 this.viewProviders.set(tokenReference(provider.token), true);
10411 }
10412 });
10413 }
10414}
10415class ProviderElementContext {
10416 constructor(viewContext, _parent, _isViewRoot, _directiveAsts, attrs, refs, isTemplate, contentQueryStartId, _sourceSpan) {
10417 this.viewContext = viewContext;
10418 this._parent = _parent;
10419 this._isViewRoot = _isViewRoot;
10420 this._directiveAsts = _directiveAsts;
10421 this._sourceSpan = _sourceSpan;
10422 this._transformedProviders = new Map();
10423 this._seenProviders = new Map();
10424 this._queriedTokens = new Map();
10425 this.transformedHasViewContainer = false;
10426 this._attrs = {};
10427 attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
10428 const directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
10429 this._allProviders =
10430 _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, viewContext.errors);
10431 this._contentQueries = _getContentQueries(contentQueryStartId, directivesMeta);
10432 Array.from(this._allProviders.values()).forEach((provider) => {
10433 this._addQueryReadsTo(provider.token, provider.token, this._queriedTokens);
10434 });
10435 if (isTemplate) {
10436 const templateRefId = createTokenForExternalReference(this.viewContext.reflector, Identifiers.TemplateRef);
10437 this._addQueryReadsTo(templateRefId, templateRefId, this._queriedTokens);
10438 }
10439 refs.forEach((refAst) => {
10440 let defaultQueryValue = refAst.value ||
10441 createTokenForExternalReference(this.viewContext.reflector, Identifiers.ElementRef);
10442 this._addQueryReadsTo({ value: refAst.name }, defaultQueryValue, this._queriedTokens);
10443 });
10444 if (this._queriedTokens.get(this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef))) {
10445 this.transformedHasViewContainer = true;
10446 }
10447 // create the providers that we know are eager first
10448 Array.from(this._allProviders.values()).forEach((provider) => {
10449 const eager = provider.eager || this._queriedTokens.get(tokenReference(provider.token));
10450 if (eager) {
10451 this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
10452 }
10453 });
10454 }
10455 afterElement() {
10456 // collect lazy providers
10457 Array.from(this._allProviders.values()).forEach((provider) => {
10458 this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
10459 });
10460 }
10461 get transformProviders() {
10462 // Note: Maps keep their insertion order.
10463 const lazyProviders = [];
10464 const eagerProviders = [];
10465 this._transformedProviders.forEach(provider => {
10466 if (provider.eager) {
10467 eagerProviders.push(provider);
10468 }
10469 else {
10470 lazyProviders.push(provider);
10471 }
10472 });
10473 return lazyProviders.concat(eagerProviders);
10474 }
10475 get transformedDirectiveAsts() {
10476 const sortedProviderTypes = this.transformProviders.map(provider => provider.token.identifier);
10477 const sortedDirectives = this._directiveAsts.slice();
10478 sortedDirectives.sort((dir1, dir2) => sortedProviderTypes.indexOf(dir1.directive.type) -
10479 sortedProviderTypes.indexOf(dir2.directive.type));
10480 return sortedDirectives;
10481 }
10482 get queryMatches() {
10483 const allMatches = [];
10484 this._queriedTokens.forEach((matches) => { allMatches.push(...matches); });
10485 return allMatches;
10486 }
10487 _addQueryReadsTo(token, defaultValue, queryReadTokens) {
10488 this._getQueriesFor(token).forEach((query) => {
10489 const queryValue = query.meta.read || defaultValue;
10490 const tokenRef = tokenReference(queryValue);
10491 let queryMatches = queryReadTokens.get(tokenRef);
10492 if (!queryMatches) {
10493 queryMatches = [];
10494 queryReadTokens.set(tokenRef, queryMatches);
10495 }
10496 queryMatches.push({ queryId: query.queryId, value: queryValue });
10497 });
10498 }
10499 _getQueriesFor(token) {
10500 const result = [];
10501 let currentEl = this;
10502 let distance = 0;
10503 let queries;
10504 while (currentEl !== null) {
10505 queries = currentEl._contentQueries.get(tokenReference(token));
10506 if (queries) {
10507 result.push(...queries.filter((query) => query.meta.descendants || distance <= 1));
10508 }
10509 if (currentEl._directiveAsts.length > 0) {
10510 distance++;
10511 }
10512 currentEl = currentEl._parent;
10513 }
10514 queries = this.viewContext.viewQueries.get(tokenReference(token));
10515 if (queries) {
10516 result.push(...queries);
10517 }
10518 return result;
10519 }
10520 _getOrCreateLocalProvider(requestingProviderType, token, eager) {
10521 const resolvedProvider = this._allProviders.get(tokenReference(token));
10522 if (!resolvedProvider || ((requestingProviderType === ProviderAstType.Directive ||
10523 requestingProviderType === ProviderAstType.PublicService) &&
10524 resolvedProvider.providerType === ProviderAstType.PrivateService) ||
10525 ((requestingProviderType === ProviderAstType.PrivateService ||
10526 requestingProviderType === ProviderAstType.PublicService) &&
10527 resolvedProvider.providerType === ProviderAstType.Builtin)) {
10528 return null;
10529 }
10530 let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
10531 if (transformedProviderAst) {
10532 return transformedProviderAst;
10533 }
10534 if (this._seenProviders.get(tokenReference(token)) != null) {
10535 this.viewContext.errors.push(new ProviderError(`Cannot instantiate cyclic dependency! ${tokenName(token)}`, this._sourceSpan));
10536 return null;
10537 }
10538 this._seenProviders.set(tokenReference(token), true);
10539 const transformedProviders = resolvedProvider.providers.map((provider) => {
10540 let transformedUseValue = provider.useValue;
10541 let transformedUseExisting = provider.useExisting;
10542 let transformedDeps = undefined;
10543 if (provider.useExisting != null) {
10544 const existingDiDep = this._getDependency(resolvedProvider.providerType, { token: provider.useExisting }, eager);
10545 if (existingDiDep.token != null) {
10546 transformedUseExisting = existingDiDep.token;
10547 }
10548 else {
10549 transformedUseExisting = null;
10550 transformedUseValue = existingDiDep.value;
10551 }
10552 }
10553 else if (provider.useFactory) {
10554 const deps = provider.deps || provider.useFactory.diDeps;
10555 transformedDeps =
10556 deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
10557 }
10558 else if (provider.useClass) {
10559 const deps = provider.deps || provider.useClass.diDeps;
10560 transformedDeps =
10561 deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
10562 }
10563 return _transformProvider(provider, {
10564 useExisting: transformedUseExisting,
10565 useValue: transformedUseValue,
10566 deps: transformedDeps
10567 });
10568 });
10569 transformedProviderAst =
10570 _transformProviderAst(resolvedProvider, { eager: eager, providers: transformedProviders });
10571 this._transformedProviders.set(tokenReference(token), transformedProviderAst);
10572 return transformedProviderAst;
10573 }
10574 _getLocalDependency(requestingProviderType, dep, eager = false) {
10575 if (dep.isAttribute) {
10576 const attrValue = this._attrs[dep.token.value];
10577 return { isValue: true, value: attrValue == null ? null : attrValue };
10578 }
10579 if (dep.token != null) {
10580 // access builtints
10581 if ((requestingProviderType === ProviderAstType.Directive ||
10582 requestingProviderType === ProviderAstType.Component)) {
10583 if (tokenReference(dep.token) ===
10584 this.viewContext.reflector.resolveExternalReference(Identifiers.Renderer) ||
10585 tokenReference(dep.token) ===
10586 this.viewContext.reflector.resolveExternalReference(Identifiers.ElementRef) ||
10587 tokenReference(dep.token) ===
10588 this.viewContext.reflector.resolveExternalReference(Identifiers.ChangeDetectorRef) ||
10589 tokenReference(dep.token) ===
10590 this.viewContext.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
10591 return dep;
10592 }
10593 if (tokenReference(dep.token) ===
10594 this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
10595 this.transformedHasViewContainer = true;
10596 }
10597 }
10598 // access the injector
10599 if (tokenReference(dep.token) ===
10600 this.viewContext.reflector.resolveExternalReference(Identifiers.Injector)) {
10601 return dep;
10602 }
10603 // access providers
10604 if (this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager) != null) {
10605 return dep;
10606 }
10607 }
10608 return null;
10609 }
10610 _getDependency(requestingProviderType, dep, eager = false) {
10611 let currElement = this;
10612 let currEager = eager;
10613 let result = null;
10614 if (!dep.isSkipSelf) {
10615 result = this._getLocalDependency(requestingProviderType, dep, eager);
10616 }
10617 if (dep.isSelf) {
10618 if (!result && dep.isOptional) {
10619 result = { isValue: true, value: null };
10620 }
10621 }
10622 else {
10623 // check parent elements
10624 while (!result && currElement._parent) {
10625 const prevElement = currElement;
10626 currElement = currElement._parent;
10627 if (prevElement._isViewRoot) {
10628 currEager = false;
10629 }
10630 result = currElement._getLocalDependency(ProviderAstType.PublicService, dep, currEager);
10631 }
10632 // check @Host restriction
10633 if (!result) {
10634 if (!dep.isHost || this.viewContext.component.isHost ||
10635 this.viewContext.component.type.reference === tokenReference(dep.token) ||
10636 this.viewContext.viewProviders.get(tokenReference(dep.token)) != null) {
10637 result = dep;
10638 }
10639 else {
10640 result = dep.isOptional ? { isValue: true, value: null } : null;
10641 }
10642 }
10643 }
10644 if (!result) {
10645 this.viewContext.errors.push(new ProviderError(`No provider for ${tokenName(dep.token)}`, this._sourceSpan));
10646 }
10647 return result;
10648 }
10649}
10650class NgModuleProviderAnalyzer {
10651 constructor(reflector, ngModule, extraProviders, sourceSpan) {
10652 this.reflector = reflector;
10653 this._transformedProviders = new Map();
10654 this._seenProviders = new Map();
10655 this._errors = [];
10656 this._allProviders = new Map();
10657 ngModule.transitiveModule.modules.forEach((ngModuleType) => {
10658 const ngModuleProvider = { token: { identifier: ngModuleType }, useClass: ngModuleType };
10659 _resolveProviders([ngModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors, this._allProviders, /* isModule */ true);
10660 });
10661 _resolveProviders(ngModule.transitiveModule.providers.map(entry => entry.provider).concat(extraProviders), ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders,
10662 /* isModule */ false);
10663 }
10664 parse() {
10665 Array.from(this._allProviders.values()).forEach((provider) => {
10666 this._getOrCreateLocalProvider(provider.token, provider.eager);
10667 });
10668 if (this._errors.length > 0) {
10669 const errorString = this._errors.join('\n');
10670 throw new Error(`Provider parse errors:\n${errorString}`);
10671 }
10672 // Note: Maps keep their insertion order.
10673 const lazyProviders = [];
10674 const eagerProviders = [];
10675 this._transformedProviders.forEach(provider => {
10676 if (provider.eager) {
10677 eagerProviders.push(provider);
10678 }
10679 else {
10680 lazyProviders.push(provider);
10681 }
10682 });
10683 return lazyProviders.concat(eagerProviders);
10684 }
10685 _getOrCreateLocalProvider(token, eager) {
10686 const resolvedProvider = this._allProviders.get(tokenReference(token));
10687 if (!resolvedProvider) {
10688 return null;
10689 }
10690 let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
10691 if (transformedProviderAst) {
10692 return transformedProviderAst;
10693 }
10694 if (this._seenProviders.get(tokenReference(token)) != null) {
10695 this._errors.push(new ProviderError(`Cannot instantiate cyclic dependency! ${tokenName(token)}`, resolvedProvider.sourceSpan));
10696 return null;
10697 }
10698 this._seenProviders.set(tokenReference(token), true);
10699 const transformedProviders = resolvedProvider.providers.map((provider) => {
10700 let transformedUseValue = provider.useValue;
10701 let transformedUseExisting = provider.useExisting;
10702 let transformedDeps = undefined;
10703 if (provider.useExisting != null) {
10704 const existingDiDep = this._getDependency({ token: provider.useExisting }, eager, resolvedProvider.sourceSpan);
10705 if (existingDiDep.token != null) {
10706 transformedUseExisting = existingDiDep.token;
10707 }
10708 else {
10709 transformedUseExisting = null;
10710 transformedUseValue = existingDiDep.value;
10711 }
10712 }
10713 else if (provider.useFactory) {
10714 const deps = provider.deps || provider.useFactory.diDeps;
10715 transformedDeps =
10716 deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
10717 }
10718 else if (provider.useClass) {
10719 const deps = provider.deps || provider.useClass.diDeps;
10720 transformedDeps =
10721 deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
10722 }
10723 return _transformProvider(provider, {
10724 useExisting: transformedUseExisting,
10725 useValue: transformedUseValue,
10726 deps: transformedDeps
10727 });
10728 });
10729 transformedProviderAst =
10730 _transformProviderAst(resolvedProvider, { eager: eager, providers: transformedProviders });
10731 this._transformedProviders.set(tokenReference(token), transformedProviderAst);
10732 return transformedProviderAst;
10733 }
10734 _getDependency(dep, eager = false, requestorSourceSpan) {
10735 let foundLocal = false;
10736 if (!dep.isSkipSelf && dep.token != null) {
10737 // access the injector
10738 if (tokenReference(dep.token) ===
10739 this.reflector.resolveExternalReference(Identifiers.Injector) ||
10740 tokenReference(dep.token) ===
10741 this.reflector.resolveExternalReference(Identifiers.ComponentFactoryResolver)) {
10742 foundLocal = true;
10743 // access providers
10744 }
10745 else if (this._getOrCreateLocalProvider(dep.token, eager) != null) {
10746 foundLocal = true;
10747 }
10748 }
10749 return dep;
10750 }
10751}
10752function _transformProvider(provider, { useExisting, useValue, deps }) {
10753 return {
10754 token: provider.token,
10755 useClass: provider.useClass,
10756 useExisting: useExisting,
10757 useFactory: provider.useFactory,
10758 useValue: useValue,
10759 deps: deps,
10760 multi: provider.multi
10761 };
10762}
10763function _transformProviderAst(provider, { eager, providers }) {
10764 return new ProviderAst(provider.token, provider.multiProvider, provider.eager || eager, providers, provider.providerType, provider.lifecycleHooks, provider.sourceSpan, provider.isModule);
10765}
10766function _resolveProvidersFromDirectives(directives, sourceSpan, targetErrors) {
10767 const providersByToken = new Map();
10768 directives.forEach((directive) => {
10769 const dirProvider = { token: { identifier: directive.type }, useClass: directive.type };
10770 _resolveProviders([dirProvider], directive.isComponent ? ProviderAstType.Component : ProviderAstType.Directive, true, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10771 });
10772 // Note: directives need to be able to overwrite providers of a component!
10773 const directivesWithComponentFirst = directives.filter(dir => dir.isComponent).concat(directives.filter(dir => !dir.isComponent));
10774 directivesWithComponentFirst.forEach((directive) => {
10775 _resolveProviders(directive.providers, ProviderAstType.PublicService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10776 _resolveProviders(directive.viewProviders, ProviderAstType.PrivateService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
10777 });
10778 return providersByToken;
10779}
10780function _resolveProviders(providers, providerType, eager, sourceSpan, targetErrors, targetProvidersByToken, isModule) {
10781 providers.forEach((provider) => {
10782 let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
10783 if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
10784 targetErrors.push(new ProviderError(`Mixing multi and non multi provider is not possible for token ${tokenName(resolvedProvider.token)}`, sourceSpan));
10785 }
10786 if (!resolvedProvider) {
10787 const lifecycleHooks = provider.token.identifier &&
10788 provider.token.identifier.lifecycleHooks ?
10789 provider.token.identifier.lifecycleHooks :
10790 [];
10791 const isUseValue = !(provider.useClass || provider.useExisting || provider.useFactory);
10792 resolvedProvider = new ProviderAst(provider.token, !!provider.multi, eager || isUseValue, [provider], providerType, lifecycleHooks, sourceSpan, isModule);
10793 targetProvidersByToken.set(tokenReference(provider.token), resolvedProvider);
10794 }
10795 else {
10796 if (!provider.multi) {
10797 resolvedProvider.providers.length = 0;
10798 }
10799 resolvedProvider.providers.push(provider);
10800 }
10801 });
10802}
10803function _getViewQueries(component) {
10804 // Note: queries start with id 1 so we can use the number in a Bloom filter!
10805 let viewQueryId = 1;
10806 const viewQueries = new Map();
10807 if (component.viewQueries) {
10808 component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, { meta: query, queryId: viewQueryId++ }));
10809 }
10810 return viewQueries;
10811}
10812function _getContentQueries(contentQueryStartId, directives) {
10813 let contentQueryId = contentQueryStartId;
10814 const contentQueries = new Map();
10815 directives.forEach((directive, directiveIndex) => {
10816 if (directive.queries) {
10817 directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, { meta: query, queryId: contentQueryId++ }));
10818 }
10819 });
10820 return contentQueries;
10821}
10822function _addQueryToTokenMap(map, query) {
10823 query.meta.selectors.forEach((token) => {
10824 let entry = map.get(tokenReference(token));
10825 if (!entry) {
10826 entry = [];
10827 map.set(tokenReference(token), entry);
10828 }
10829 entry.push(query);
10830 });
10831}
10832
10833/**
10834 * @license
10835 * Copyright Google Inc. All Rights Reserved.
10836 *
10837 * Use of this source code is governed by an MIT-style license that can be
10838 * found in the LICENSE file at https://angular.io/license
10839 */
10840class StyleWithImports {
10841 constructor(style, styleUrls) {
10842 this.style = style;
10843 this.styleUrls = styleUrls;
10844 }
10845}
10846function isStyleUrlResolvable(url) {
10847 if (url == null || url.length === 0 || url[0] == '/')
10848 return false;
10849 const schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP);
10850 return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset';
10851}
10852/**
10853 * Rewrites stylesheets by resolving and removing the @import urls that
10854 * are either relative or don't have a `package:` scheme
10855 */
10856function extractStyleUrls(resolver, baseUrl, cssText) {
10857 const foundUrls = [];
10858 const modifiedCssText = cssText.replace(CSS_STRIPPABLE_COMMENT_REGEXP, '')
10859 .replace(CSS_IMPORT_REGEXP, (...m) => {
10860 const url = m[1] || m[2];
10861 if (!isStyleUrlResolvable(url)) {
10862 // Do not attempt to resolve non-package absolute URLs with URI
10863 // scheme
10864 return m[0];
10865 }
10866 foundUrls.push(resolver.resolve(baseUrl, url));
10867 return '';
10868 });
10869 return new StyleWithImports(modifiedCssText, foundUrls);
10870}
10871const CSS_IMPORT_REGEXP = /@import\s+(?:url\()?\s*(?:(?:['"]([^'"]*))|([^;\)\s]*))[^;]*;?/g;
10872const CSS_STRIPPABLE_COMMENT_REGEXP = /\/\*(?!#\s*(?:sourceURL|sourceMappingURL)=)[\s\S]+?\*\//g;
10873const URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/;
10874
10875/**
10876 * @license
10877 * Copyright Google Inc. All Rights Reserved.
10878 *
10879 * Use of this source code is governed by an MIT-style license that can be
10880 * found in the LICENSE file at https://angular.io/license
10881 */
10882const PROPERTY_PARTS_SEPARATOR = '.';
10883const ATTRIBUTE_PREFIX = 'attr';
10884const CLASS_PREFIX = 'class';
10885const STYLE_PREFIX = 'style';
10886const ANIMATE_PROP_PREFIX = 'animate-';
10887/**
10888 * Parses bindings in templates and in the directive host area.
10889 */
10890class BindingParser {
10891 constructor(_exprParser, _interpolationConfig, _schemaRegistry, pipes, errors) {
10892 this._exprParser = _exprParser;
10893 this._interpolationConfig = _interpolationConfig;
10894 this._schemaRegistry = _schemaRegistry;
10895 this.errors = errors;
10896 this.pipesByName = null;
10897 this._usedPipes = new Map();
10898 // When the `pipes` parameter is `null`, do not check for used pipes
10899 // This is used in IVY when we might not know the available pipes at compile time
10900 if (pipes) {
10901 const pipesByName = new Map();
10902 pipes.forEach(pipe => pipesByName.set(pipe.name, pipe));
10903 this.pipesByName = pipesByName;
10904 }
10905 }
10906 get interpolationConfig() { return this._interpolationConfig; }
10907 getUsedPipes() { return Array.from(this._usedPipes.values()); }
10908 createBoundHostProperties(dirMeta, sourceSpan) {
10909 if (dirMeta.hostProperties) {
10910 const boundProps = [];
10911 Object.keys(dirMeta.hostProperties).forEach(propName => {
10912 const expression = dirMeta.hostProperties[propName];
10913 if (typeof expression === 'string') {
10914 this.parsePropertyBinding(propName, expression, true, sourceSpan, sourceSpan.start.offset, undefined, [], boundProps);
10915 }
10916 else {
10917 this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
10918 }
10919 });
10920 return boundProps;
10921 }
10922 return null;
10923 }
10924 createDirectiveHostPropertyAsts(dirMeta, elementSelector, sourceSpan) {
10925 const boundProps = this.createBoundHostProperties(dirMeta, sourceSpan);
10926 return boundProps &&
10927 boundProps.map((prop) => this.createBoundElementProperty(elementSelector, prop));
10928 }
10929 createDirectiveHostEventAsts(dirMeta, sourceSpan) {
10930 if (dirMeta.hostListeners) {
10931 const targetEvents = [];
10932 Object.keys(dirMeta.hostListeners).forEach(propName => {
10933 const expression = dirMeta.hostListeners[propName];
10934 if (typeof expression === 'string') {
10935 // TODO: pass a more accurate handlerSpan for this event.
10936 this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents);
10937 }
10938 else {
10939 this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
10940 }
10941 });
10942 return targetEvents;
10943 }
10944 return null;
10945 }
10946 parseInterpolation(value, sourceSpan) {
10947 const sourceInfo = sourceSpan.start.toString();
10948 try {
10949 const ast = this._exprParser.parseInterpolation(value, sourceInfo, sourceSpan.start.offset, this._interpolationConfig);
10950 if (ast)
10951 this._reportExpressionParserErrors(ast.errors, sourceSpan);
10952 this._checkPipes(ast, sourceSpan);
10953 return ast;
10954 }
10955 catch (e) {
10956 this._reportError(`${e}`, sourceSpan);
10957 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, sourceSpan.start.offset);
10958 }
10959 }
10960 // Parse an inline template binding. ie `<tag *tplKey="<tplValue>">`
10961 parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteOffset, targetMatchableAttrs, targetProps, targetVars) {
10962 const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan);
10963 for (let i = 0; i < bindings.length; i++) {
10964 const binding = bindings[i];
10965 if (binding.keyIsVar) {
10966 targetVars.push(new ParsedVariable(binding.key, binding.name, sourceSpan));
10967 }
10968 else if (binding.expression) {
10969 this._parsePropertyAst(binding.key, binding.expression, sourceSpan, undefined, targetMatchableAttrs, targetProps);
10970 }
10971 else {
10972 targetMatchableAttrs.push([binding.key, '']);
10973 this.parseLiteralAttr(binding.key, null, sourceSpan, absoluteOffset, undefined, targetMatchableAttrs, targetProps);
10974 }
10975 }
10976 }
10977 _parseTemplateBindings(tplKey, tplValue, sourceSpan) {
10978 const sourceInfo = sourceSpan.start.toString();
10979 try {
10980 const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo, sourceSpan.start.offset);
10981 this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
10982 bindingsResult.templateBindings.forEach((binding) => {
10983 if (binding.expression) {
10984 this._checkPipes(binding.expression, sourceSpan);
10985 }
10986 });
10987 bindingsResult.warnings.forEach((warning) => { this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
10988 return bindingsResult.templateBindings;
10989 }
10990 catch (e) {
10991 this._reportError(`${e}`, sourceSpan);
10992 return [];
10993 }
10994 }
10995 parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps) {
10996 if (isAnimationLabel(name)) {
10997 name = name.substring(1);
10998 if (value) {
10999 this._reportError(`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
11000 ` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`, sourceSpan, ParseErrorLevel.ERROR);
11001 }
11002 this._parseAnimation(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps);
11003 }
11004 else {
11005 targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, valueSpan));
11006 }
11007 }
11008 parsePropertyBinding(name, expression, isHost, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps) {
11009 let isAnimationProp = false;
11010 if (name.startsWith(ANIMATE_PROP_PREFIX)) {
11011 isAnimationProp = true;
11012 name = name.substring(ANIMATE_PROP_PREFIX.length);
11013 }
11014 else if (isAnimationLabel(name)) {
11015 isAnimationProp = true;
11016 name = name.substring(1);
11017 }
11018 if (isAnimationProp) {
11019 this._parseAnimation(name, expression, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps);
11020 }
11021 else {
11022 this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, valueSpan, targetMatchableAttrs, targetProps);
11023 }
11024 }
11025 parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps) {
11026 const expr = this.parseInterpolation(value, valueSpan || sourceSpan);
11027 if (expr) {
11028 this._parsePropertyAst(name, expr, sourceSpan, valueSpan, targetMatchableAttrs, targetProps);
11029 return true;
11030 }
11031 return false;
11032 }
11033 _parsePropertyAst(name, ast, sourceSpan, valueSpan, targetMatchableAttrs, targetProps) {
11034 targetMatchableAttrs.push([name, ast.source]);
11035 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, valueSpan));
11036 }
11037 _parseAnimation(name, expression, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps) {
11038 // This will occur when a @trigger is not paired with an expression.
11039 // For animations it is valid to not have an expression since */void
11040 // states will be applied by angular when the element is attached/detached
11041 const ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
11042 targetMatchableAttrs.push([name, ast.source]);
11043 targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, valueSpan));
11044 }
11045 _parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
11046 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
11047 try {
11048 const ast = isHostBinding ?
11049 this._exprParser.parseSimpleBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig) :
11050 this._exprParser.parseBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11051 if (ast)
11052 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11053 this._checkPipes(ast, sourceSpan);
11054 return ast;
11055 }
11056 catch (e) {
11057 this._reportError(`${e}`, sourceSpan);
11058 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11059 }
11060 }
11061 createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) {
11062 if (boundProp.isAnimation) {
11063 return new BoundElementProperty(boundProp.name, 4 /* Animation */, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.valueSpan);
11064 }
11065 let unit = null;
11066 let bindingType = undefined;
11067 let boundPropertyName = null;
11068 const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
11069 let securityContexts = undefined;
11070 // Check for special cases (prefix style, attr, class)
11071 if (parts.length > 1) {
11072 if (parts[0] == ATTRIBUTE_PREFIX) {
11073 boundPropertyName = parts[1];
11074 if (!skipValidation) {
11075 this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
11076 }
11077 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
11078 const nsSeparatorIdx = boundPropertyName.indexOf(':');
11079 if (nsSeparatorIdx > -1) {
11080 const ns = boundPropertyName.substring(0, nsSeparatorIdx);
11081 const name = boundPropertyName.substring(nsSeparatorIdx + 1);
11082 boundPropertyName = mergeNsAndName(ns, name);
11083 }
11084 bindingType = 1 /* Attribute */;
11085 }
11086 else if (parts[0] == CLASS_PREFIX) {
11087 boundPropertyName = parts[1];
11088 bindingType = 2 /* Class */;
11089 securityContexts = [SecurityContext.NONE];
11090 }
11091 else if (parts[0] == STYLE_PREFIX) {
11092 unit = parts.length > 2 ? parts[2] : null;
11093 boundPropertyName = parts[1];
11094 bindingType = 3 /* Style */;
11095 securityContexts = [SecurityContext.STYLE];
11096 }
11097 }
11098 // If not a special case, use the full property name
11099 if (boundPropertyName === null) {
11100 const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
11101 boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
11102 securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
11103 bindingType = 0 /* Property */;
11104 if (!skipValidation) {
11105 this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
11106 }
11107 }
11108 return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.valueSpan);
11109 }
11110 parseEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents) {
11111 if (isAnimationLabel(name)) {
11112 name = name.substr(1);
11113 this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents);
11114 }
11115 else {
11116 this._parseRegularEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents);
11117 }
11118 }
11119 calcPossibleSecurityContexts(selector, propName, isAttribute) {
11120 const prop = this._schemaRegistry.getMappedPropName(propName);
11121 return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
11122 }
11123 _parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents) {
11124 const matches = splitAtPeriod(name, [name, '']);
11125 const eventName = matches[0];
11126 const phase = matches[1].toLowerCase();
11127 if (phase) {
11128 switch (phase) {
11129 case 'start':
11130 case 'done':
11131 const ast = this._parseAction(expression, handlerSpan);
11132 targetEvents.push(new ParsedEvent(eventName, phase, 1 /* Animation */, ast, sourceSpan, handlerSpan));
11133 break;
11134 default:
11135 this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan);
11136 break;
11137 }
11138 }
11139 else {
11140 this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan);
11141 }
11142 }
11143 _parseRegularEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents) {
11144 // long format: 'target: eventName'
11145 const [target, eventName] = splitAtColon(name, [null, name]);
11146 const ast = this._parseAction(expression, handlerSpan);
11147 targetMatchableAttrs.push([name, ast.source]);
11148 targetEvents.push(new ParsedEvent(eventName, target, 0 /* Regular */, ast, sourceSpan, handlerSpan));
11149 // Don't detect directives for event names for now,
11150 // so don't add the event name to the matchableAttrs
11151 }
11152 _parseAction(value, sourceSpan) {
11153 const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString();
11154 const absoluteOffset = (sourceSpan && sourceSpan.start) ? sourceSpan.start.offset : 0;
11155 try {
11156 const ast = this._exprParser.parseAction(value, sourceInfo, absoluteOffset, this._interpolationConfig);
11157 if (ast) {
11158 this._reportExpressionParserErrors(ast.errors, sourceSpan);
11159 }
11160 if (!ast || ast.ast instanceof EmptyExpr) {
11161 this._reportError(`Empty expressions are not allowed`, sourceSpan);
11162 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11163 }
11164 this._checkPipes(ast, sourceSpan);
11165 return ast;
11166 }
11167 catch (e) {
11168 this._reportError(`${e}`, sourceSpan);
11169 return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
11170 }
11171 }
11172 _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
11173 this.errors.push(new ParseError(sourceSpan, message, level));
11174 }
11175 _reportExpressionParserErrors(errors, sourceSpan) {
11176 for (const error of errors) {
11177 this._reportError(error.message, sourceSpan);
11178 }
11179 }
11180 // Make sure all the used pipes are known in `this.pipesByName`
11181 _checkPipes(ast, sourceSpan) {
11182 if (ast && this.pipesByName) {
11183 const collector = new PipeCollector();
11184 ast.visit(collector);
11185 collector.pipes.forEach((ast, pipeName) => {
11186 const pipeMeta = this.pipesByName.get(pipeName);
11187 if (!pipeMeta) {
11188 this._reportError(`The pipe '${pipeName}' could not be found`, new ParseSourceSpan(sourceSpan.start.moveBy(ast.span.start), sourceSpan.start.moveBy(ast.span.end)));
11189 }
11190 else {
11191 this._usedPipes.set(pipeName, pipeMeta);
11192 }
11193 });
11194 }
11195 }
11196 /**
11197 * @param propName the name of the property / attribute
11198 * @param sourceSpan
11199 * @param isAttr true when binding to an attribute
11200 */
11201 _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) {
11202 const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
11203 this._schemaRegistry.validateProperty(propName);
11204 if (report.error) {
11205 this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
11206 }
11207 }
11208}
11209class PipeCollector extends RecursiveAstVisitor$1 {
11210 constructor() {
11211 super(...arguments);
11212 this.pipes = new Map();
11213 }
11214 visitPipe(ast, context) {
11215 this.pipes.set(ast.name, ast);
11216 ast.exp.visit(this);
11217 this.visitAll(ast.args, context);
11218 return null;
11219 }
11220}
11221function isAnimationLabel(name) {
11222 return name[0] == '@';
11223}
11224function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
11225 const ctxs = [];
11226 CssSelector.parse(selector).forEach((selector) => {
11227 const elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
11228 const notElementNames = new Set(selector.notSelectors.filter(selector => selector.isElementSelector())
11229 .map((selector) => selector.element));
11230 const possibleElementNames = elementNames.filter(elementName => !notElementNames.has(elementName));
11231 ctxs.push(...possibleElementNames.map(elementName => registry.securityContext(elementName, propName, isAttribute)));
11232 });
11233 return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
11234}
11235
11236/**
11237 * @license
11238 * Copyright Google Inc. All Rights Reserved.
11239 *
11240 * Use of this source code is governed by an MIT-style license that can be
11241 * found in the LICENSE file at https://angular.io/license
11242 */
11243const NG_CONTENT_SELECT_ATTR = 'select';
11244const LINK_ELEMENT = 'link';
11245const LINK_STYLE_REL_ATTR = 'rel';
11246const LINK_STYLE_HREF_ATTR = 'href';
11247const LINK_STYLE_REL_VALUE = 'stylesheet';
11248const STYLE_ELEMENT = 'style';
11249const SCRIPT_ELEMENT = 'script';
11250const NG_NON_BINDABLE_ATTR = 'ngNonBindable';
11251const NG_PROJECT_AS = 'ngProjectAs';
11252function preparseElement(ast) {
11253 let selectAttr = null;
11254 let hrefAttr = null;
11255 let relAttr = null;
11256 let nonBindable = false;
11257 let projectAs = '';
11258 ast.attrs.forEach(attr => {
11259 const lcAttrName = attr.name.toLowerCase();
11260 if (lcAttrName == NG_CONTENT_SELECT_ATTR) {
11261 selectAttr = attr.value;
11262 }
11263 else if (lcAttrName == LINK_STYLE_HREF_ATTR) {
11264 hrefAttr = attr.value;
11265 }
11266 else if (lcAttrName == LINK_STYLE_REL_ATTR) {
11267 relAttr = attr.value;
11268 }
11269 else if (attr.name == NG_NON_BINDABLE_ATTR) {
11270 nonBindable = true;
11271 }
11272 else if (attr.name == NG_PROJECT_AS) {
11273 if (attr.value.length > 0) {
11274 projectAs = attr.value;
11275 }
11276 }
11277 });
11278 selectAttr = normalizeNgContentSelect(selectAttr);
11279 const nodeName = ast.name.toLowerCase();
11280 let type = PreparsedElementType.OTHER;
11281 if (isNgContent(nodeName)) {
11282 type = PreparsedElementType.NG_CONTENT;
11283 }
11284 else if (nodeName == STYLE_ELEMENT) {
11285 type = PreparsedElementType.STYLE;
11286 }
11287 else if (nodeName == SCRIPT_ELEMENT) {
11288 type = PreparsedElementType.SCRIPT;
11289 }
11290 else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
11291 type = PreparsedElementType.STYLESHEET;
11292 }
11293 return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs);
11294}
11295var PreparsedElementType;
11296(function (PreparsedElementType) {
11297 PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT";
11298 PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE";
11299 PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET";
11300 PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT";
11301 PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER";
11302})(PreparsedElementType || (PreparsedElementType = {}));
11303class PreparsedElement {
11304 constructor(type, selectAttr, hrefAttr, nonBindable, projectAs) {
11305 this.type = type;
11306 this.selectAttr = selectAttr;
11307 this.hrefAttr = hrefAttr;
11308 this.nonBindable = nonBindable;
11309 this.projectAs = projectAs;
11310 }
11311}
11312function normalizeNgContentSelect(selectAttr) {
11313 if (selectAttr === null || selectAttr.length === 0) {
11314 return '*';
11315 }
11316 return selectAttr;
11317}
11318
11319/**
11320 * @license
11321 * Copyright Google Inc. All Rights Reserved.
11322 *
11323 * Use of this source code is governed by an MIT-style license that can be
11324 * found in the LICENSE file at https://angular.io/license
11325 */
11326const BIND_NAME_REGEXP = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/;
11327// Group 1 = "bind-"
11328const KW_BIND_IDX = 1;
11329// Group 2 = "let-"
11330const KW_LET_IDX = 2;
11331// Group 3 = "ref-/#"
11332const KW_REF_IDX = 3;
11333// Group 4 = "on-"
11334const KW_ON_IDX = 4;
11335// Group 5 = "bindon-"
11336const KW_BINDON_IDX = 5;
11337// Group 6 = "@"
11338const KW_AT_IDX = 6;
11339// Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
11340const IDENT_KW_IDX = 7;
11341// Group 8 = identifier inside [()]
11342const IDENT_BANANA_BOX_IDX = 8;
11343// Group 9 = identifier inside []
11344const IDENT_PROPERTY_IDX = 9;
11345// Group 10 = identifier inside ()
11346const IDENT_EVENT_IDX = 10;
11347const TEMPLATE_ATTR_PREFIX = '*';
11348const CLASS_ATTR = 'class';
11349let _TEXT_CSS_SELECTOR;
11350function TEXT_CSS_SELECTOR() {
11351 if (!_TEXT_CSS_SELECTOR) {
11352 _TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
11353 }
11354 return _TEXT_CSS_SELECTOR;
11355}
11356class TemplateParseError extends ParseError {
11357 constructor(message, span, level) {
11358 super(span, message, level);
11359 }
11360}
11361class TemplateParseResult {
11362 constructor(templateAst, usedPipes, errors) {
11363 this.templateAst = templateAst;
11364 this.usedPipes = usedPipes;
11365 this.errors = errors;
11366 }
11367}
11368class TemplateParser {
11369 constructor(_config, _reflector, _exprParser, _schemaRegistry, _htmlParser, _console, transforms) {
11370 this._config = _config;
11371 this._reflector = _reflector;
11372 this._exprParser = _exprParser;
11373 this._schemaRegistry = _schemaRegistry;
11374 this._htmlParser = _htmlParser;
11375 this._console = _console;
11376 this.transforms = transforms;
11377 }
11378 get expressionParser() { return this._exprParser; }
11379 parse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
11380 const result = this.tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
11381 const warnings = result.errors.filter(error => error.level === ParseErrorLevel.WARNING);
11382 const errors = result.errors.filter(error => error.level === ParseErrorLevel.ERROR);
11383 if (warnings.length > 0) {
11384 this._console.warn(`Template parse warnings:\n${warnings.join('\n')}`);
11385 }
11386 if (errors.length > 0) {
11387 const errorString = errors.join('\n');
11388 throw syntaxError(`Template parse errors:\n${errorString}`, errors);
11389 }
11390 return { template: result.templateAst, pipes: result.usedPipes };
11391 }
11392 tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
11393 let htmlParseResult = typeof template === 'string' ?
11394 this._htmlParser.parse(template, templateUrl, {
11395 tokenizeExpansionForms: true,
11396 interpolationConfig: this.getInterpolationConfig(component)
11397 }) :
11398 template;
11399 if (!preserveWhitespaces) {
11400 htmlParseResult = removeWhitespaces(htmlParseResult);
11401 }
11402 return this.tryParseHtml(this.expandHtml(htmlParseResult), component, directives, pipes, schemas);
11403 }
11404 tryParseHtml(htmlAstWithErrors, component, directives, pipes, schemas) {
11405 let result;
11406 const errors = htmlAstWithErrors.errors;
11407 const usedPipes = [];
11408 if (htmlAstWithErrors.rootNodes.length > 0) {
11409 const uniqDirectives = removeSummaryDuplicates(directives);
11410 const uniqPipes = removeSummaryDuplicates(pipes);
11411 const providerViewContext = new ProviderViewContext(this._reflector, component);
11412 let interpolationConfig = undefined;
11413 if (component.template && component.template.interpolation) {
11414 interpolationConfig = {
11415 start: component.template.interpolation[0],
11416 end: component.template.interpolation[1]
11417 };
11418 }
11419 const bindingParser = new BindingParser(this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors);
11420 const parseVisitor = new TemplateParseVisitor(this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas, errors);
11421 result = visitAll$1(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
11422 errors.push(...providerViewContext.errors);
11423 usedPipes.push(...bindingParser.getUsedPipes());
11424 }
11425 else {
11426 result = [];
11427 }
11428 this._assertNoReferenceDuplicationOnTemplate(result, errors);
11429 if (errors.length > 0) {
11430 return new TemplateParseResult(result, usedPipes, errors);
11431 }
11432 if (this.transforms) {
11433 this.transforms.forEach((transform) => { result = templateVisitAll(transform, result); });
11434 }
11435 return new TemplateParseResult(result, usedPipes, errors);
11436 }
11437 expandHtml(htmlAstWithErrors, forced = false) {
11438 const errors = htmlAstWithErrors.errors;
11439 if (errors.length == 0 || forced) {
11440 // Transform ICU messages to angular directives
11441 const expandedHtmlAst = expandNodes(htmlAstWithErrors.rootNodes);
11442 errors.push(...expandedHtmlAst.errors);
11443 htmlAstWithErrors = new ParseTreeResult(expandedHtmlAst.nodes, errors);
11444 }
11445 return htmlAstWithErrors;
11446 }
11447 getInterpolationConfig(component) {
11448 if (component.template) {
11449 return InterpolationConfig.fromArray(component.template.interpolation);
11450 }
11451 return undefined;
11452 }
11453 /** @internal */
11454 _assertNoReferenceDuplicationOnTemplate(result, errors) {
11455 const existingReferences = [];
11456 result.filter(element => !!element.references)
11457 .forEach(element => element.references.forEach((reference) => {
11458 const name = reference.name;
11459 if (existingReferences.indexOf(name) < 0) {
11460 existingReferences.push(name);
11461 }
11462 else {
11463 const error = new TemplateParseError(`Reference "#${name}" is defined several times`, reference.sourceSpan, ParseErrorLevel.ERROR);
11464 errors.push(error);
11465 }
11466 }));
11467 }
11468}
11469class TemplateParseVisitor {
11470 constructor(reflector, config, providerViewContext, directives, _bindingParser, _schemaRegistry, _schemas, _targetErrors) {
11471 this.reflector = reflector;
11472 this.config = config;
11473 this.providerViewContext = providerViewContext;
11474 this._bindingParser = _bindingParser;
11475 this._schemaRegistry = _schemaRegistry;
11476 this._schemas = _schemas;
11477 this._targetErrors = _targetErrors;
11478 this.selectorMatcher = new SelectorMatcher();
11479 this.directivesIndex = new Map();
11480 this.ngContentCount = 0;
11481 // Note: queries start with id 1 so we can use the number in a Bloom filter!
11482 this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
11483 directives.forEach((directive, index) => {
11484 const selector = CssSelector.parse(directive.selector);
11485 this.selectorMatcher.addSelectables(selector, directive);
11486 this.directivesIndex.set(directive, index);
11487 });
11488 }
11489 visitExpansion(expansion, context) { return null; }
11490 visitExpansionCase(expansionCase, context) { return null; }
11491 visitText(text, parent) {
11492 const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
11493 const valueNoNgsp = replaceNgsp(text.value);
11494 const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan);
11495 return expr ? new BoundTextAst(expr, ngContentIndex, text.sourceSpan) :
11496 new TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan);
11497 }
11498 visitAttribute(attribute, context) {
11499 return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
11500 }
11501 visitComment(comment, context) { return null; }
11502 visitElement(element, parent) {
11503 const queryStartIndex = this.contentQueryStartId;
11504 const elName = element.name;
11505 const preparsedElement = preparseElement(element);
11506 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
11507 preparsedElement.type === PreparsedElementType.STYLE) {
11508 // Skipping <script> for security reasons
11509 // Skipping <style> as we already processed them
11510 // in the StyleCompiler
11511 return null;
11512 }
11513 if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
11514 isStyleUrlResolvable(preparsedElement.hrefAttr)) {
11515 // Skipping stylesheets with either relative urls or package scheme as we already processed
11516 // them in the StyleCompiler
11517 return null;
11518 }
11519 const matchableAttrs = [];
11520 const elementOrDirectiveProps = [];
11521 const elementOrDirectiveRefs = [];
11522 const elementVars = [];
11523 const events = [];
11524 const templateElementOrDirectiveProps = [];
11525 const templateMatchableAttrs = [];
11526 const templateElementVars = [];
11527 let hasInlineTemplates = false;
11528 const attrs = [];
11529 const isTemplateElement = isNgTemplate(element.name);
11530 element.attrs.forEach(attr => {
11531 const parsedVariables = [];
11532 const hasBinding = this._parseAttr(isTemplateElement, attr, matchableAttrs, elementOrDirectiveProps, events, elementOrDirectiveRefs, elementVars);
11533 elementVars.push(...parsedVariables.map(v => VariableAst.fromParsedVariable(v)));
11534 let templateValue;
11535 let templateKey;
11536 const normalizedName = this._normalizeAttributeName(attr.name);
11537 if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
11538 templateValue = attr.value;
11539 templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length);
11540 }
11541 const hasTemplateBinding = templateValue != null;
11542 if (hasTemplateBinding) {
11543 if (hasInlineTemplates) {
11544 this._reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attr.sourceSpan);
11545 }
11546 hasInlineTemplates = true;
11547 const parsedVariables = [];
11548 this._bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attr.sourceSpan, attr.sourceSpan.start.offset, templateMatchableAttrs, templateElementOrDirectiveProps, parsedVariables);
11549 templateElementVars.push(...parsedVariables.map(v => VariableAst.fromParsedVariable(v)));
11550 }
11551 if (!hasBinding && !hasTemplateBinding) {
11552 // don't include the bindings as attributes as well in the AST
11553 attrs.push(this.visitAttribute(attr, null));
11554 matchableAttrs.push([attr.name, attr.value]);
11555 }
11556 });
11557 const elementCssSelector = createElementCssSelector(elName, matchableAttrs);
11558 const { directives: directiveMetas, matchElement } = this._parseDirectives(this.selectorMatcher, elementCssSelector);
11559 const references = [];
11560 const boundDirectivePropNames = new Set();
11561 const directiveAsts = this._createDirectiveAsts(isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps, elementOrDirectiveRefs, element.sourceSpan, references, boundDirectivePropNames);
11562 const elementProps = this._createElementPropertyAsts(element.name, elementOrDirectiveProps, boundDirectivePropNames);
11563 const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
11564 const providerContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot, directiveAsts, attrs, references, isTemplateElement, queryStartIndex, element.sourceSpan);
11565 const children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, ElementContext.create(isTemplateElement, directiveAsts, isTemplateElement ? parent.providerContext : providerContext));
11566 providerContext.afterElement();
11567 // Override the actual selector when the `ngProjectAs` attribute is provided
11568 const projectionSelector = preparsedElement.projectAs != '' ?
11569 CssSelector.parse(preparsedElement.projectAs)[0] :
11570 elementCssSelector;
11571 const ngContentIndex = parent.findNgContentIndex(projectionSelector);
11572 let parsedElement;
11573 if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
11574 // `<ng-content>` element
11575 if (element.children && !element.children.every(_isEmptyTextNode)) {
11576 this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
11577 }
11578 parsedElement = new NgContentAst(this.ngContentCount++, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
11579 }
11580 else if (isTemplateElement) {
11581 // `<ng-template>` element
11582 this._assertAllEventsPublishedByDirectives(directiveAsts, events);
11583 this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps, element.sourceSpan);
11584 parsedElement = new EmbeddedTemplateAst(attrs, events, references, elementVars, providerContext.transformedDirectiveAsts, providerContext.transformProviders, providerContext.transformedHasViewContainer, providerContext.queryMatches, children, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
11585 }
11586 else {
11587 // element other than `<ng-content>` and `<ng-template>`
11588 this._assertElementExists(matchElement, element);
11589 this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
11590 const ngContentIndex = hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
11591 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);
11592 }
11593 if (hasInlineTemplates) {
11594 // The element as a *-attribute
11595 const templateQueryStartIndex = this.contentQueryStartId;
11596 const templateSelector = createElementCssSelector('ng-template', templateMatchableAttrs);
11597 const { directives } = this._parseDirectives(this.selectorMatcher, templateSelector);
11598 const templateBoundDirectivePropNames = new Set();
11599 const templateDirectiveAsts = this._createDirectiveAsts(true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan, [], templateBoundDirectivePropNames);
11600 const templateElementProps = this._createElementPropertyAsts(elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames);
11601 this._assertNoComponentsNorElementBindingsOnTemplate(templateDirectiveAsts, templateElementProps, element.sourceSpan);
11602 const templateProviderContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, parent.isTemplateElement, templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan);
11603 templateProviderContext.afterElement();
11604 parsedElement = new EmbeddedTemplateAst([], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts, templateProviderContext.transformProviders, templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches, [parsedElement], ngContentIndex, element.sourceSpan);
11605 }
11606 return parsedElement;
11607 }
11608 _parseAttr(isTemplateElement, attr, targetMatchableAttrs, targetProps, targetEvents, targetRefs, targetVars) {
11609 const name = this._normalizeAttributeName(attr.name);
11610 const value = attr.value;
11611 const srcSpan = attr.sourceSpan;
11612 const absoluteOffset = attr.valueSpan ? attr.valueSpan.start.offset : srcSpan.start.offset;
11613 const boundEvents = [];
11614 const bindParts = name.match(BIND_NAME_REGEXP);
11615 let hasBinding = false;
11616 if (bindParts !== null) {
11617 hasBinding = true;
11618 if (bindParts[KW_BIND_IDX] != null) {
11619 this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11620 }
11621 else if (bindParts[KW_LET_IDX]) {
11622 if (isTemplateElement) {
11623 const identifier = bindParts[IDENT_KW_IDX];
11624 this._parseVariable(identifier, value, srcSpan, targetVars);
11625 }
11626 else {
11627 this._reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
11628 }
11629 }
11630 else if (bindParts[KW_REF_IDX]) {
11631 const identifier = bindParts[IDENT_KW_IDX];
11632 this._parseReference(identifier, value, srcSpan, targetRefs);
11633 }
11634 else if (bindParts[KW_ON_IDX]) {
11635 this._bindingParser.parseEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11636 }
11637 else if (bindParts[KW_BINDON_IDX]) {
11638 this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11639 this._parseAssignmentEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11640 }
11641 else if (bindParts[KW_AT_IDX]) {
11642 this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11643 }
11644 else if (bindParts[IDENT_BANANA_BOX_IDX]) {
11645 this._bindingParser.parsePropertyBinding(bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11646 this._parseAssignmentEvent(bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11647 }
11648 else if (bindParts[IDENT_PROPERTY_IDX]) {
11649 this._bindingParser.parsePropertyBinding(bindParts[IDENT_PROPERTY_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11650 }
11651 else if (bindParts[IDENT_EVENT_IDX]) {
11652 this._bindingParser.parseEvent(bindParts[IDENT_EVENT_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
11653 }
11654 }
11655 else {
11656 hasBinding = this._bindingParser.parsePropertyInterpolation(name, value, srcSpan, attr.valueSpan, targetMatchableAttrs, targetProps);
11657 }
11658 if (!hasBinding) {
11659 this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
11660 }
11661 targetEvents.push(...boundEvents.map(e => BoundEventAst.fromParsedEvent(e)));
11662 return hasBinding;
11663 }
11664 _normalizeAttributeName(attrName) {
11665 return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
11666 }
11667 _parseVariable(identifier, value, sourceSpan, targetVars) {
11668 if (identifier.indexOf('-') > -1) {
11669 this._reportError(`"-" is not allowed in variable names`, sourceSpan);
11670 }
11671 targetVars.push(new VariableAst(identifier, value, sourceSpan));
11672 }
11673 _parseReference(identifier, value, sourceSpan, targetRefs) {
11674 if (identifier.indexOf('-') > -1) {
11675 this._reportError(`"-" is not allowed in reference names`, sourceSpan);
11676 }
11677 targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
11678 }
11679 _parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, targetEvents) {
11680 this._bindingParser.parseEvent(`${name}Change`, `${expression}=$event`, sourceSpan, valueSpan, targetMatchableAttrs, targetEvents);
11681 }
11682 _parseDirectives(selectorMatcher, elementCssSelector) {
11683 // Need to sort the directives so that we get consistent results throughout,
11684 // as selectorMatcher uses Maps inside.
11685 // Also deduplicate directives as they might match more than one time!
11686 const directives = new Array(this.directivesIndex.size);
11687 // Whether any directive selector matches on the element name
11688 let matchElement = false;
11689 selectorMatcher.match(elementCssSelector, (selector, directive) => {
11690 directives[this.directivesIndex.get(directive)] = directive;
11691 matchElement = matchElement || selector.hasElementSelector();
11692 });
11693 return {
11694 directives: directives.filter(dir => !!dir),
11695 matchElement,
11696 };
11697 }
11698 _createDirectiveAsts(isTemplateElement, elementName, directives, props, elementOrDirectiveRefs, elementSourceSpan, targetReferences, targetBoundDirectivePropNames) {
11699 const matchedReferences = new Set();
11700 let component = null;
11701 const directiveAsts = directives.map((directive) => {
11702 const sourceSpan = new ParseSourceSpan(elementSourceSpan.start, elementSourceSpan.end, `Directive ${identifierName(directive.type)}`);
11703 if (directive.isComponent) {
11704 component = directive;
11705 }
11706 const directiveProperties = [];
11707 const boundProperties = this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan);
11708 let hostProperties = boundProperties.map(prop => BoundElementPropertyAst.fromBoundProperty(prop));
11709 // Note: We need to check the host properties here as well,
11710 // as we don't know the element name in the DirectiveWrapperCompiler yet.
11711 hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);
11712 const parsedEvents = this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan);
11713 this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties, targetBoundDirectivePropNames);
11714 elementOrDirectiveRefs.forEach((elOrDirRef) => {
11715 if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
11716 (elOrDirRef.isReferenceToDirective(directive))) {
11717 targetReferences.push(new ReferenceAst(elOrDirRef.name, createTokenForReference(directive.type.reference), elOrDirRef.value, elOrDirRef.sourceSpan));
11718 matchedReferences.add(elOrDirRef.name);
11719 }
11720 });
11721 const hostEvents = parsedEvents.map(e => BoundEventAst.fromParsedEvent(e));
11722 const contentQueryStartId = this.contentQueryStartId;
11723 this.contentQueryStartId += directive.queries.length;
11724 return new DirectiveAst(directive, directiveProperties, hostProperties, hostEvents, contentQueryStartId, sourceSpan);
11725 });
11726 elementOrDirectiveRefs.forEach((elOrDirRef) => {
11727 if (elOrDirRef.value.length > 0) {
11728 if (!matchedReferences.has(elOrDirRef.name)) {
11729 this._reportError(`There is no directive with "exportAs" set to "${elOrDirRef.value}"`, elOrDirRef.sourceSpan);
11730 }
11731 }
11732 else if (!component) {
11733 let refToken = null;
11734 if (isTemplateElement) {
11735 refToken = createTokenForExternalReference(this.reflector, Identifiers.TemplateRef);
11736 }
11737 targetReferences.push(new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.value, elOrDirRef.sourceSpan));
11738 }
11739 });
11740 return directiveAsts;
11741 }
11742 _createDirectivePropertyAsts(directiveProperties, boundProps, targetBoundDirectiveProps, targetBoundDirectivePropNames) {
11743 if (directiveProperties) {
11744 const boundPropsByName = new Map();
11745 boundProps.forEach(boundProp => {
11746 const prevValue = boundPropsByName.get(boundProp.name);
11747 if (!prevValue || prevValue.isLiteral) {
11748 // give [a]="b" a higher precedence than a="b" on the same element
11749 boundPropsByName.set(boundProp.name, boundProp);
11750 }
11751 });
11752 Object.keys(directiveProperties).forEach(dirProp => {
11753 const elProp = directiveProperties[dirProp];
11754 const boundProp = boundPropsByName.get(elProp);
11755 // Bindings are optional, so this binding only needs to be set up if an expression is given.
11756 if (boundProp) {
11757 targetBoundDirectivePropNames.add(boundProp.name);
11758 if (!isEmptyExpression(boundProp.expression)) {
11759 targetBoundDirectiveProps.push(new BoundDirectivePropertyAst(dirProp, boundProp.name, boundProp.expression, boundProp.sourceSpan));
11760 }
11761 }
11762 });
11763 }
11764 }
11765 _createElementPropertyAsts(elementName, props, boundDirectivePropNames) {
11766 const boundElementProps = [];
11767 props.forEach((prop) => {
11768 if (!prop.isLiteral && !boundDirectivePropNames.has(prop.name)) {
11769 const boundProp = this._bindingParser.createBoundElementProperty(elementName, prop);
11770 boundElementProps.push(BoundElementPropertyAst.fromBoundProperty(boundProp));
11771 }
11772 });
11773 return this._checkPropertiesInSchema(elementName, boundElementProps);
11774 }
11775 _findComponentDirectives(directives) {
11776 return directives.filter(directive => directive.directive.isComponent);
11777 }
11778 _findComponentDirectiveNames(directives) {
11779 return this._findComponentDirectives(directives)
11780 .map(directive => identifierName(directive.directive.type));
11781 }
11782 _assertOnlyOneComponent(directives, sourceSpan) {
11783 const componentTypeNames = this._findComponentDirectiveNames(directives);
11784 if (componentTypeNames.length > 1) {
11785 this._reportError(`More than one component matched on this element.\n` +
11786 `Make sure that only one component's selector can match a given element.\n` +
11787 `Conflicting components: ${componentTypeNames.join(',')}`, sourceSpan);
11788 }
11789 }
11790 /**
11791 * Make sure that non-angular tags conform to the schemas.
11792 *
11793 * Note: An element is considered an angular tag when at least one directive selector matches the
11794 * tag name.
11795 *
11796 * @param matchElement Whether any directive has matched on the tag name
11797 * @param element the html element
11798 */
11799 _assertElementExists(matchElement, element) {
11800 const elName = element.name.replace(/^:xhtml:/, '');
11801 if (!matchElement && !this._schemaRegistry.hasElement(elName, this._schemas)) {
11802 let errorMsg = `'${elName}' is not a known element:\n`;
11803 errorMsg +=
11804 `1. If '${elName}' is an Angular component, then verify that it is part of this module.\n`;
11805 if (elName.indexOf('-') > -1) {
11806 errorMsg +=
11807 `2. If '${elName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`;
11808 }
11809 else {
11810 errorMsg +=
11811 `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
11812 }
11813 this._reportError(errorMsg, element.sourceSpan);
11814 }
11815 }
11816 _assertNoComponentsNorElementBindingsOnTemplate(directives, elementProps, sourceSpan) {
11817 const componentTypeNames = this._findComponentDirectiveNames(directives);
11818 if (componentTypeNames.length > 0) {
11819 this._reportError(`Components on an embedded template: ${componentTypeNames.join(',')}`, sourceSpan);
11820 }
11821 elementProps.forEach(prop => {
11822 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);
11823 });
11824 }
11825 _assertAllEventsPublishedByDirectives(directives, events) {
11826 const allDirectiveEvents = new Set();
11827 directives.forEach(directive => {
11828 Object.keys(directive.directive.outputs).forEach(k => {
11829 const eventName = directive.directive.outputs[k];
11830 allDirectiveEvents.add(eventName);
11831 });
11832 });
11833 events.forEach(event => {
11834 if (event.target != null || !allDirectiveEvents.has(event.name)) {
11835 this._reportError(`Event binding ${event.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);
11836 }
11837 });
11838 }
11839 _checkPropertiesInSchema(elementName, boundProps) {
11840 // Note: We can't filter out empty expressions before this method,
11841 // as we still want to validate them!
11842 return boundProps.filter((boundProp) => {
11843 if (boundProp.type === 0 /* Property */ &&
11844 !this._schemaRegistry.hasProperty(elementName, boundProp.name, this._schemas)) {
11845 let errorMsg = `Can't bind to '${boundProp.name}' since it isn't a known property of '${elementName}'.`;
11846 if (elementName.startsWith('ng-')) {
11847 errorMsg +=
11848 `\n1. If '${boundProp.name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` +
11849 `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
11850 }
11851 else if (elementName.indexOf('-') > -1) {
11852 errorMsg +=
11853 `\n1. If '${elementName}' is an Angular component and it has '${boundProp.name}' input, then verify that it is part of this module.` +
11854 `\n2. If '${elementName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` +
11855 `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
11856 }
11857 this._reportError(errorMsg, boundProp.sourceSpan);
11858 }
11859 return !isEmptyExpression(boundProp.value);
11860 });
11861 }
11862 _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
11863 this._targetErrors.push(new ParseError(sourceSpan, message, level));
11864 }
11865}
11866class NonBindableVisitor {
11867 visitElement(ast, parent) {
11868 const preparsedElement = preparseElement(ast);
11869 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
11870 preparsedElement.type === PreparsedElementType.STYLE ||
11871 preparsedElement.type === PreparsedElementType.STYLESHEET) {
11872 // Skipping <script> for security reasons
11873 // Skipping <style> and stylesheets as we already processed them
11874 // in the StyleCompiler
11875 return null;
11876 }
11877 const attrNameAndValues = ast.attrs.map((attr) => [attr.name, attr.value]);
11878 const selector = createElementCssSelector(ast.name, attrNameAndValues);
11879 const ngContentIndex = parent.findNgContentIndex(selector);
11880 const children = visitAll$1(this, ast.children, EMPTY_ELEMENT_CONTEXT);
11881 return new ElementAst(ast.name, visitAll$1(this, ast.attrs), [], [], [], [], [], false, [], children, ngContentIndex, ast.sourceSpan, ast.endSourceSpan);
11882 }
11883 visitComment(comment, context) { return null; }
11884 visitAttribute(attribute, context) {
11885 return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
11886 }
11887 visitText(text, parent) {
11888 const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
11889 return new TextAst(text.value, ngContentIndex, text.sourceSpan);
11890 }
11891 visitExpansion(expansion, context) { return expansion; }
11892 visitExpansionCase(expansionCase, context) { return expansionCase; }
11893}
11894/**
11895 * A reference to an element or directive in a template. E.g., the reference in this template:
11896 *
11897 * <div #myMenu="coolMenu">
11898 *
11899 * would be {name: 'myMenu', value: 'coolMenu', sourceSpan: ...}
11900 */
11901class ElementOrDirectiveRef {
11902 constructor(name, value, sourceSpan) {
11903 this.name = name;
11904 this.value = value;
11905 this.sourceSpan = sourceSpan;
11906 }
11907 /** Gets whether this is a reference to the given directive. */
11908 isReferenceToDirective(directive) {
11909 return splitExportAs(directive.exportAs).indexOf(this.value) !== -1;
11910 }
11911}
11912/** Splits a raw, potentially comma-delimited `exportAs` value into an array of names. */
11913function splitExportAs(exportAs) {
11914 return exportAs ? exportAs.split(',').map(e => e.trim()) : [];
11915}
11916function splitClasses(classAttrValue) {
11917 return classAttrValue.trim().split(/\s+/g);
11918}
11919class ElementContext {
11920 constructor(isTemplateElement, _ngContentIndexMatcher, _wildcardNgContentIndex, providerContext) {
11921 this.isTemplateElement = isTemplateElement;
11922 this._ngContentIndexMatcher = _ngContentIndexMatcher;
11923 this._wildcardNgContentIndex = _wildcardNgContentIndex;
11924 this.providerContext = providerContext;
11925 }
11926 static create(isTemplateElement, directives, providerContext) {
11927 const matcher = new SelectorMatcher();
11928 let wildcardNgContentIndex = null;
11929 const component = directives.find(directive => directive.directive.isComponent);
11930 if (component) {
11931 const ngContentSelectors = component.directive.template.ngContentSelectors;
11932 for (let i = 0; i < ngContentSelectors.length; i++) {
11933 const selector = ngContentSelectors[i];
11934 if (selector === '*') {
11935 wildcardNgContentIndex = i;
11936 }
11937 else {
11938 matcher.addSelectables(CssSelector.parse(ngContentSelectors[i]), i);
11939 }
11940 }
11941 }
11942 return new ElementContext(isTemplateElement, matcher, wildcardNgContentIndex, providerContext);
11943 }
11944 findNgContentIndex(selector) {
11945 const ngContentIndices = [];
11946 this._ngContentIndexMatcher.match(selector, (selector, ngContentIndex) => { ngContentIndices.push(ngContentIndex); });
11947 ngContentIndices.sort();
11948 if (this._wildcardNgContentIndex != null) {
11949 ngContentIndices.push(this._wildcardNgContentIndex);
11950 }
11951 return ngContentIndices.length > 0 ? ngContentIndices[0] : null;
11952 }
11953}
11954function createElementCssSelector(elementName, attributes) {
11955 const cssSelector = new CssSelector();
11956 const elNameNoNs = splitNsName(elementName)[1];
11957 cssSelector.setElement(elNameNoNs);
11958 for (let i = 0; i < attributes.length; i++) {
11959 const attrName = attributes[i][0];
11960 const attrNameNoNs = splitNsName(attrName)[1];
11961 const attrValue = attributes[i][1];
11962 cssSelector.addAttribute(attrNameNoNs, attrValue);
11963 if (attrName.toLowerCase() == CLASS_ATTR) {
11964 const classes = splitClasses(attrValue);
11965 classes.forEach(className => cssSelector.addClassName(className));
11966 }
11967 }
11968 return cssSelector;
11969}
11970const EMPTY_ELEMENT_CONTEXT = new ElementContext(true, new SelectorMatcher(), null, null);
11971const NON_BINDABLE_VISITOR = new NonBindableVisitor();
11972function _isEmptyTextNode(node) {
11973 return node instanceof Text$3 && node.value.trim().length == 0;
11974}
11975function removeSummaryDuplicates(items) {
11976 const map = new Map();
11977 items.forEach((item) => {
11978 if (!map.get(item.type.reference)) {
11979 map.set(item.type.reference, item);
11980 }
11981 });
11982 return Array.from(map.values());
11983}
11984function isEmptyExpression(ast) {
11985 if (ast instanceof ASTWithSource) {
11986 ast = ast.ast;
11987 }
11988 return ast instanceof EmptyExpr;
11989}
11990
11991/**
11992 * @license
11993 * Copyright Google Inc. All Rights Reserved.
11994 *
11995 * Use of this source code is governed by an MIT-style license that can be
11996 * found in the LICENSE file at https://angular.io/license
11997 */
11998/**
11999 * Parses string representation of a style and converts it into object literal.
12000 *
12001 * @param value string representation of style as used in the `style` attribute in HTML.
12002 * Example: `color: red; height: auto`.
12003 * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
12004 * 'auto']`
12005 */
12006function parse(value) {
12007 // we use a string array here instead of a string map
12008 // because a string-map is not guaranteed to retain the
12009 // order of the entries whereas a string array can be
12010 // construted in a [key, value, key, value] format.
12011 const styles = [];
12012 let i = 0;
12013 let parenDepth = 0;
12014 let quote = 0 /* QuoteNone */;
12015 let valueStart = 0;
12016 let propStart = 0;
12017 let currentProp = null;
12018 let valueHasQuotes = false;
12019 while (i < value.length) {
12020 const token = value.charCodeAt(i++);
12021 switch (token) {
12022 case 40 /* OpenParen */:
12023 parenDepth++;
12024 break;
12025 case 41 /* CloseParen */:
12026 parenDepth--;
12027 break;
12028 case 39 /* QuoteSingle */:
12029 // valueStart needs to be there since prop values don't
12030 // have quotes in CSS
12031 valueHasQuotes = valueHasQuotes || valueStart > 0;
12032 if (quote === 0 /* QuoteNone */) {
12033 quote = 39 /* QuoteSingle */;
12034 }
12035 else if (quote === 39 /* QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
12036 quote = 0 /* QuoteNone */;
12037 }
12038 break;
12039 case 34 /* QuoteDouble */:
12040 // same logic as above
12041 valueHasQuotes = valueHasQuotes || valueStart > 0;
12042 if (quote === 0 /* QuoteNone */) {
12043 quote = 34 /* QuoteDouble */;
12044 }
12045 else if (quote === 34 /* QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
12046 quote = 0 /* QuoteNone */;
12047 }
12048 break;
12049 case 58 /* Colon */:
12050 if (!currentProp && parenDepth === 0 && quote === 0 /* QuoteNone */) {
12051 currentProp = hyphenate(value.substring(propStart, i - 1).trim());
12052 valueStart = i;
12053 }
12054 break;
12055 case 59 /* Semicolon */:
12056 if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* QuoteNone */) {
12057 const styleVal = value.substring(valueStart, i - 1).trim();
12058 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
12059 propStart = i;
12060 valueStart = 0;
12061 currentProp = null;
12062 valueHasQuotes = false;
12063 }
12064 break;
12065 }
12066 }
12067 if (currentProp && valueStart) {
12068 const styleVal = value.substr(valueStart).trim();
12069 styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
12070 }
12071 return styles;
12072}
12073function stripUnnecessaryQuotes(value) {
12074 const qS = value.charCodeAt(0);
12075 const qE = value.charCodeAt(value.length - 1);
12076 if (qS == qE && (qS == 39 /* QuoteSingle */ || qS == 34 /* QuoteDouble */)) {
12077 const tempValue = value.substring(1, value.length - 1);
12078 // special case to avoid using a multi-quoted string that was just chomped
12079 // (e.g. `font-family: "Verdana", "sans-serif"`)
12080 if (tempValue.indexOf('\'') == -1 && tempValue.indexOf('"') == -1) {
12081 value = tempValue;
12082 }
12083 }
12084 return value;
12085}
12086function hyphenate(value) {
12087 return value.replace(/[a-z][A-Z]/g, v => {
12088 return v.charAt(0) + '-' + v.charAt(1);
12089 }).toLowerCase();
12090}
12091
12092const IMPORTANT_FLAG = '!important';
12093/**
12094 * Produces creation/update instructions for all styling bindings (class and style)
12095 *
12096 * It also produces the creation instruction to register all initial styling values
12097 * (which are all the static class="..." and style="..." attribute values that exist
12098 * on an element within a template).
12099 *
12100 * The builder class below handles producing instructions for the following cases:
12101 *
12102 * - Static style/class attributes (style="..." and class="...")
12103 * - Dynamic style/class map bindings ([style]="map" and [class]="map|string")
12104 * - Dynamic style/class property bindings ([style.prop]="exp" and [class.name]="exp")
12105 *
12106 * Due to the complex relationship of all of these cases, the instructions generated
12107 * for these attributes/properties/bindings must be done so in the correct order. The
12108 * order which these must be generated is as follows:
12109 *
12110 * if (createMode) {
12111 * styling(...)
12112 * }
12113 * if (updateMode) {
12114 * styleMap(...)
12115 * classMap(...)
12116 * styleProp(...)
12117 * classProp(...)
12118 * stylingApply(...)
12119 * }
12120 *
12121 * The creation/update methods within the builder class produce these instructions.
12122 */
12123class StylingBuilder {
12124 constructor(_elementIndexExpr, _directiveExpr) {
12125 this._elementIndexExpr = _elementIndexExpr;
12126 this._directiveExpr = _directiveExpr;
12127 /** Whether or not there are any static styling values present */
12128 this._hasInitialValues = false;
12129 /**
12130 * Whether or not there are any styling bindings present
12131 * (i.e. `[style]`, `[class]`, `[style.prop]` or `[class.name]`)
12132 */
12133 this.hasBindings = false;
12134 /** the input for [class] (if it exists) */
12135 this._classMapInput = null;
12136 /** the input for [style] (if it exists) */
12137 this._styleMapInput = null;
12138 /** an array of each [style.prop] input */
12139 this._singleStyleInputs = null;
12140 /** an array of each [class.name] input */
12141 this._singleClassInputs = null;
12142 this._lastStylingInput = null;
12143 this._firstStylingInput = null;
12144 // maps are used instead of hash maps because a Map will
12145 // retain the ordering of the keys
12146 /**
12147 * Represents the location of each style binding in the template
12148 * (e.g. `<div [style.width]="w" [style.height]="h">` implies
12149 * that `width=0` and `height=1`)
12150 */
12151 this._stylesIndex = new Map();
12152 /**
12153 * Represents the location of each class binding in the template
12154 * (e.g. `<div [class.big]="b" [class.hidden]="h">` implies
12155 * that `big=0` and `hidden=1`)
12156 */
12157 this._classesIndex = new Map();
12158 this._initialStyleValues = [];
12159 this._initialClassValues = [];
12160 // certain style properties ALWAYS need sanitization
12161 // this is checked each time new styles are encountered
12162 this._useDefaultSanitizer = false;
12163 }
12164 /**
12165 * Registers a given input to the styling builder to be later used when producing AOT code.
12166 *
12167 * The code below will only accept the input if it is somehow tied to styling (whether it be
12168 * style/class bindings or static style/class attributes).
12169 */
12170 registerBoundInput(input) {
12171 // [attr.style] or [attr.class] are skipped in the code below,
12172 // they should not be treated as styling-based bindings since
12173 // they are intended to be written directly to the attr and
12174 // will therefore skip all style/class resolution that is present
12175 // with style="", [style]="" and [style.prop]="", class="",
12176 // [class.prop]="". [class]="" assignments
12177 let binding = null;
12178 let name = input.name;
12179 switch (input.type) {
12180 case 0 /* Property */:
12181 binding = this.registerInputBasedOnName(name, input.value, input.sourceSpan);
12182 break;
12183 case 3 /* Style */:
12184 binding = this.registerStyleInput(name, false, input.value, input.sourceSpan, input.unit);
12185 break;
12186 case 2 /* Class */:
12187 binding = this.registerClassInput(name, false, input.value, input.sourceSpan);
12188 break;
12189 }
12190 return binding ? true : false;
12191 }
12192 registerInputBasedOnName(name, expression, sourceSpan) {
12193 let binding = null;
12194 const nameToMatch = name.substring(0, 5); // class | style
12195 const isStyle = nameToMatch === 'style';
12196 const isClass = isStyle ? false : (nameToMatch === 'class');
12197 if (isStyle || isClass) {
12198 const isMapBased = name.charAt(5) !== '.'; // style.prop or class.prop makes this a no
12199 const property = name.substr(isMapBased ? 5 : 6); // the dot explains why there's a +1
12200 if (isStyle) {
12201 binding = this.registerStyleInput(property, isMapBased, expression, sourceSpan);
12202 }
12203 else {
12204 binding = this.registerClassInput(property, isMapBased, expression, sourceSpan);
12205 }
12206 }
12207 return binding;
12208 }
12209 registerStyleInput(name, isMapBased, value, sourceSpan, unit) {
12210 if (isEmptyExpression(value)) {
12211 return null;
12212 }
12213 name = normalizePropName(name);
12214 const { property, hasOverrideFlag, unit: bindingUnit } = parseProperty(name);
12215 const entry = {
12216 name: property,
12217 unit: unit || bindingUnit, value, sourceSpan, hasOverrideFlag
12218 };
12219 if (isMapBased) {
12220 this._useDefaultSanitizer = true;
12221 this._styleMapInput = entry;
12222 }
12223 else {
12224 (this._singleStyleInputs = this._singleStyleInputs || []).push(entry);
12225 this._useDefaultSanitizer = this._useDefaultSanitizer || isStyleSanitizable(name);
12226 registerIntoMap(this._stylesIndex, property);
12227 }
12228 this._lastStylingInput = entry;
12229 this._firstStylingInput = this._firstStylingInput || entry;
12230 this.hasBindings = true;
12231 return entry;
12232 }
12233 registerClassInput(name, isMapBased, value, sourceSpan) {
12234 if (isEmptyExpression(value)) {
12235 return null;
12236 }
12237 const { property, hasOverrideFlag } = parseProperty(name);
12238 const entry = { name: property, value, sourceSpan, hasOverrideFlag, unit: null };
12239 if (isMapBased) {
12240 this._classMapInput = entry;
12241 }
12242 else {
12243 (this._singleClassInputs = this._singleClassInputs || []).push(entry);
12244 registerIntoMap(this._classesIndex, property);
12245 }
12246 this._lastStylingInput = entry;
12247 this._firstStylingInput = this._firstStylingInput || entry;
12248 this.hasBindings = true;
12249 return entry;
12250 }
12251 /**
12252 * Registers the element's static style string value to the builder.
12253 *
12254 * @param value the style string (e.g. `width:100px; height:200px;`)
12255 */
12256 registerStyleAttr(value) {
12257 this._initialStyleValues = parse(value);
12258 this._hasInitialValues = true;
12259 }
12260 /**
12261 * Registers the element's static class string value to the builder.
12262 *
12263 * @param value the className string (e.g. `disabled gold zoom`)
12264 */
12265 registerClassAttr(value) {
12266 this._initialClassValues = value.trim().split(/\s+/g);
12267 this._hasInitialValues = true;
12268 }
12269 /**
12270 * Appends all styling-related expressions to the provided attrs array.
12271 *
12272 * @param attrs an existing array where each of the styling expressions
12273 * will be inserted into.
12274 */
12275 populateInitialStylingAttrs(attrs) {
12276 // [CLASS_MARKER, 'foo', 'bar', 'baz' ...]
12277 if (this._initialClassValues.length) {
12278 attrs.push(literal(1 /* Classes */));
12279 for (let i = 0; i < this._initialClassValues.length; i++) {
12280 attrs.push(literal(this._initialClassValues[i]));
12281 }
12282 }
12283 // [STYLE_MARKER, 'width', '200px', 'height', '100px', ...]
12284 if (this._initialStyleValues.length) {
12285 attrs.push(literal(2 /* Styles */));
12286 for (let i = 0; i < this._initialStyleValues.length; i += 2) {
12287 attrs.push(literal(this._initialStyleValues[i]), literal(this._initialStyleValues[i + 1]));
12288 }
12289 }
12290 }
12291 /**
12292 * Builds an instruction with all the expressions and parameters for `elementHostAttrs`.
12293 *
12294 * The instruction generation code below is used for producing the AOT statement code which is
12295 * responsible for registering initial styles (within a directive hostBindings' creation block),
12296 * as well as any of the provided attribute values, to the directive host element.
12297 */
12298 buildHostAttrsInstruction(sourceSpan, attrs, constantPool) {
12299 if (this._directiveExpr && (attrs.length || this._hasInitialValues)) {
12300 return {
12301 sourceSpan,
12302 reference: Identifiers$1.elementHostAttrs,
12303 allocateBindingSlots: 0,
12304 params: () => {
12305 // params => elementHostAttrs(attrs)
12306 this.populateInitialStylingAttrs(attrs);
12307 const attrArray = !attrs.some(attr => attr instanceof WrappedNodeExpr) ?
12308 getConstantLiteralFromArray(constantPool, attrs) :
12309 literalArr(attrs);
12310 return [attrArray];
12311 }
12312 };
12313 }
12314 return null;
12315 }
12316 /**
12317 * Builds an instruction with all the expressions and parameters for `styling`.
12318 *
12319 * The instruction generation code below is used for producing the AOT statement code which is
12320 * responsible for registering style/class bindings to an element.
12321 */
12322 buildStylingInstruction(sourceSpan, constantPool) {
12323 if (this.hasBindings) {
12324 return {
12325 sourceSpan,
12326 allocateBindingSlots: 0,
12327 reference: Identifiers$1.styling,
12328 params: () => [],
12329 };
12330 }
12331 return null;
12332 }
12333 /**
12334 * Builds an instruction with all the expressions and parameters for `classMap`.
12335 *
12336 * The instruction data will contain all expressions for `classMap` to function
12337 * which includes the `[class]` expression params.
12338 */
12339 buildClassMapInstruction(valueConverter) {
12340 if (this._classMapInput) {
12341 return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput);
12342 }
12343 return null;
12344 }
12345 /**
12346 * Builds an instruction with all the expressions and parameters for `styleMap`.
12347 *
12348 * The instruction data will contain all expressions for `styleMap` to function
12349 * which includes the `[style]` expression params.
12350 */
12351 buildStyleMapInstruction(valueConverter) {
12352 if (this._styleMapInput) {
12353 return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput);
12354 }
12355 return null;
12356 }
12357 _buildMapBasedInstruction(valueConverter, isClassBased, stylingInput) {
12358 // each styling binding value is stored in the LView
12359 let totalBindingSlotsRequired = 1;
12360 // these values must be outside of the update block so that they can
12361 // be evaluated (the AST visit call) during creation time so that any
12362 // pipes can be picked up in time before the template is built
12363 const mapValue = stylingInput.value.visit(valueConverter);
12364 let reference;
12365 if (mapValue instanceof Interpolation && isClassBased) {
12366 totalBindingSlotsRequired += mapValue.expressions.length;
12367 reference = getClassMapInterpolationExpression(mapValue);
12368 }
12369 else {
12370 reference = isClassBased ? Identifiers$1.classMap : Identifiers$1.styleMap;
12371 }
12372 return {
12373 sourceSpan: stylingInput.sourceSpan,
12374 reference,
12375 allocateBindingSlots: totalBindingSlotsRequired,
12376 supportsInterpolation: isClassBased,
12377 params: (convertFn) => {
12378 const convertResult = convertFn(mapValue);
12379 return Array.isArray(convertResult) ? convertResult : [convertResult];
12380 }
12381 };
12382 }
12383 _buildSingleInputs(reference, inputs, mapIndex, allowUnits, valueConverter, getInterpolationExpressionFn) {
12384 let totalBindingSlotsRequired = 0;
12385 return inputs.map(input => {
12386 const value = input.value.visit(valueConverter);
12387 // each styling binding value is stored in the LView
12388 let totalBindingSlotsRequired = 1;
12389 if (value instanceof Interpolation) {
12390 totalBindingSlotsRequired += value.expressions.length;
12391 if (getInterpolationExpressionFn) {
12392 reference = getInterpolationExpressionFn(value);
12393 }
12394 }
12395 return {
12396 sourceSpan: input.sourceSpan,
12397 supportsInterpolation: !!getInterpolationExpressionFn,
12398 allocateBindingSlots: totalBindingSlotsRequired, reference,
12399 params: (convertFn) => {
12400 // params => stylingProp(propName, value)
12401 const params = [];
12402 params.push(literal(input.name));
12403 const convertResult = convertFn(value);
12404 if (Array.isArray(convertResult)) {
12405 params.push(...convertResult);
12406 }
12407 else {
12408 params.push(convertResult);
12409 }
12410 if (allowUnits && input.unit) {
12411 params.push(literal(input.unit));
12412 }
12413 return params;
12414 }
12415 };
12416 });
12417 }
12418 _buildClassInputs(valueConverter) {
12419 if (this._singleClassInputs) {
12420 return this._buildSingleInputs(Identifiers$1.classProp, this._singleClassInputs, this._classesIndex, false, valueConverter);
12421 }
12422 return [];
12423 }
12424 _buildStyleInputs(valueConverter) {
12425 if (this._singleStyleInputs) {
12426 return this._buildSingleInputs(Identifiers$1.styleProp, this._singleStyleInputs, this._stylesIndex, true, valueConverter, getStylePropInterpolationExpression);
12427 }
12428 return [];
12429 }
12430 _buildApplyFn() {
12431 return {
12432 sourceSpan: this._lastStylingInput ? this._lastStylingInput.sourceSpan : null,
12433 reference: Identifiers$1.stylingApply,
12434 allocateBindingSlots: 0,
12435 params: () => { return []; }
12436 };
12437 }
12438 _buildSanitizerFn() {
12439 return {
12440 sourceSpan: this._firstStylingInput ? this._firstStylingInput.sourceSpan : null,
12441 reference: Identifiers$1.styleSanitizer,
12442 allocateBindingSlots: 0,
12443 params: () => [importExpr(Identifiers$1.defaultStyleSanitizer)]
12444 };
12445 }
12446 /**
12447 * Constructs all instructions which contain the expressions that will be placed
12448 * into the update block of a template function or a directive hostBindings function.
12449 */
12450 buildUpdateLevelInstructions(valueConverter) {
12451 const instructions = [];
12452 if (this.hasBindings) {
12453 if (this._useDefaultSanitizer) {
12454 instructions.push(this._buildSanitizerFn());
12455 }
12456 const styleMapInstruction = this.buildStyleMapInstruction(valueConverter);
12457 if (styleMapInstruction) {
12458 instructions.push(styleMapInstruction);
12459 }
12460 const classMapInstruction = this.buildClassMapInstruction(valueConverter);
12461 if (classMapInstruction) {
12462 instructions.push(classMapInstruction);
12463 }
12464 instructions.push(...this._buildStyleInputs(valueConverter));
12465 instructions.push(...this._buildClassInputs(valueConverter));
12466 instructions.push(this._buildApplyFn());
12467 }
12468 return instructions;
12469 }
12470}
12471function registerIntoMap(map, key) {
12472 if (!map.has(key)) {
12473 map.set(key, map.size);
12474 }
12475}
12476function isStyleSanitizable(prop) {
12477 // Note that browsers support both the dash case and
12478 // camel case property names when setting through JS.
12479 return prop === 'background-image' || prop === 'backgroundImage' || prop === 'background' ||
12480 prop === 'border-image' || prop === 'borderImage' || prop === 'filter' ||
12481 prop === 'list-style' || prop === 'listStyle' || prop === 'list-style-image' ||
12482 prop === 'listStyleImage' || prop === 'clip-path' || prop === 'clipPath';
12483}
12484/**
12485 * Simple helper function to either provide the constant literal that will house the value
12486 * here or a null value if the provided values are empty.
12487 */
12488function getConstantLiteralFromArray(constantPool, values) {
12489 return values.length ? constantPool.getConstLiteral(literalArr(values), true) : NULL_EXPR;
12490}
12491/**
12492 * Simple helper function that adds a parameter or does nothing at all depending on the provided
12493 * predicate and totalExpectedArgs values
12494 */
12495function addParam(params, predicate, value, argNumber, totalExpectedArgs) {
12496 if (predicate && value) {
12497 params.push(value);
12498 }
12499 else if (argNumber < totalExpectedArgs) {
12500 params.push(NULL_EXPR);
12501 }
12502}
12503function parseProperty(name) {
12504 let hasOverrideFlag = false;
12505 const overrideIndex = name.indexOf(IMPORTANT_FLAG);
12506 if (overrideIndex !== -1) {
12507 name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
12508 hasOverrideFlag = true;
12509 }
12510 let unit = '';
12511 let property = name;
12512 const unitIndex = name.lastIndexOf('.');
12513 if (unitIndex > 0) {
12514 unit = name.substr(unitIndex + 1);
12515 property = name.substring(0, unitIndex);
12516 }
12517 return { property, unit, hasOverrideFlag };
12518}
12519/**
12520 * Gets the instruction to generate for an interpolated class map.
12521 * @param interpolation An Interpolation AST
12522 */
12523function getClassMapInterpolationExpression(interpolation) {
12524 switch (getInterpolationArgsLength(interpolation)) {
12525 case 1:
12526 return Identifiers$1.classMap;
12527 case 3:
12528 return Identifiers$1.classMapInterpolate1;
12529 case 5:
12530 return Identifiers$1.classMapInterpolate2;
12531 case 7:
12532 return Identifiers$1.classMapInterpolate3;
12533 case 9:
12534 return Identifiers$1.classMapInterpolate4;
12535 case 11:
12536 return Identifiers$1.classMapInterpolate5;
12537 case 13:
12538 return Identifiers$1.classMapInterpolate6;
12539 case 15:
12540 return Identifiers$1.classMapInterpolate7;
12541 case 17:
12542 return Identifiers$1.classMapInterpolate8;
12543 default:
12544 return Identifiers$1.classMapInterpolateV;
12545 }
12546}
12547/**
12548 * Gets the instruction to generate for an interpolated style prop.
12549 * @param interpolation An Interpolation AST
12550 */
12551function getStylePropInterpolationExpression(interpolation) {
12552 switch (getInterpolationArgsLength(interpolation)) {
12553 case 1:
12554 return Identifiers$1.styleProp;
12555 case 3:
12556 return Identifiers$1.stylePropInterpolate1;
12557 case 5:
12558 return Identifiers$1.stylePropInterpolate2;
12559 case 7:
12560 return Identifiers$1.stylePropInterpolate3;
12561 case 9:
12562 return Identifiers$1.stylePropInterpolate4;
12563 case 11:
12564 return Identifiers$1.stylePropInterpolate5;
12565 case 13:
12566 return Identifiers$1.stylePropInterpolate6;
12567 case 15:
12568 return Identifiers$1.stylePropInterpolate7;
12569 case 17:
12570 return Identifiers$1.stylePropInterpolate8;
12571 default:
12572 return Identifiers$1.stylePropInterpolateV;
12573 }
12574}
12575function normalizePropName(prop) {
12576 return hyphenate(prop);
12577}
12578
12579/**
12580 * @license
12581 * Copyright Google Inc. All Rights Reserved.
12582 *
12583 * Use of this source code is governed by an MIT-style license that can be
12584 * found in the LICENSE file at https://angular.io/license
12585 */
12586var TokenType$1;
12587(function (TokenType) {
12588 TokenType[TokenType["Character"] = 0] = "Character";
12589 TokenType[TokenType["Identifier"] = 1] = "Identifier";
12590 TokenType[TokenType["Keyword"] = 2] = "Keyword";
12591 TokenType[TokenType["String"] = 3] = "String";
12592 TokenType[TokenType["Operator"] = 4] = "Operator";
12593 TokenType[TokenType["Number"] = 5] = "Number";
12594 TokenType[TokenType["Error"] = 6] = "Error";
12595})(TokenType$1 || (TokenType$1 = {}));
12596const KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
12597class Lexer {
12598 tokenize(text) {
12599 const scanner = new _Scanner(text);
12600 const tokens = [];
12601 let token = scanner.scanToken();
12602 while (token != null) {
12603 tokens.push(token);
12604 token = scanner.scanToken();
12605 }
12606 return tokens;
12607 }
12608}
12609class Token$1 {
12610 constructor(index, type, numValue, strValue) {
12611 this.index = index;
12612 this.type = type;
12613 this.numValue = numValue;
12614 this.strValue = strValue;
12615 }
12616 isCharacter(code) {
12617 return this.type == TokenType$1.Character && this.numValue == code;
12618 }
12619 isNumber() { return this.type == TokenType$1.Number; }
12620 isString() { return this.type == TokenType$1.String; }
12621 isOperator(operator) {
12622 return this.type == TokenType$1.Operator && this.strValue == operator;
12623 }
12624 isIdentifier() { return this.type == TokenType$1.Identifier; }
12625 isKeyword() { return this.type == TokenType$1.Keyword; }
12626 isKeywordLet() { return this.type == TokenType$1.Keyword && this.strValue == 'let'; }
12627 isKeywordAs() { return this.type == TokenType$1.Keyword && this.strValue == 'as'; }
12628 isKeywordNull() { return this.type == TokenType$1.Keyword && this.strValue == 'null'; }
12629 isKeywordUndefined() {
12630 return this.type == TokenType$1.Keyword && this.strValue == 'undefined';
12631 }
12632 isKeywordTrue() { return this.type == TokenType$1.Keyword && this.strValue == 'true'; }
12633 isKeywordFalse() { return this.type == TokenType$1.Keyword && this.strValue == 'false'; }
12634 isKeywordThis() { return this.type == TokenType$1.Keyword && this.strValue == 'this'; }
12635 isError() { return this.type == TokenType$1.Error; }
12636 toNumber() { return this.type == TokenType$1.Number ? this.numValue : -1; }
12637 toString() {
12638 switch (this.type) {
12639 case TokenType$1.Character:
12640 case TokenType$1.Identifier:
12641 case TokenType$1.Keyword:
12642 case TokenType$1.Operator:
12643 case TokenType$1.String:
12644 case TokenType$1.Error:
12645 return this.strValue;
12646 case TokenType$1.Number:
12647 return this.numValue.toString();
12648 default:
12649 return null;
12650 }
12651 }
12652}
12653function newCharacterToken(index, code) {
12654 return new Token$1(index, TokenType$1.Character, code, String.fromCharCode(code));
12655}
12656function newIdentifierToken(index, text) {
12657 return new Token$1(index, TokenType$1.Identifier, 0, text);
12658}
12659function newKeywordToken(index, text) {
12660 return new Token$1(index, TokenType$1.Keyword, 0, text);
12661}
12662function newOperatorToken(index, text) {
12663 return new Token$1(index, TokenType$1.Operator, 0, text);
12664}
12665function newStringToken(index, text) {
12666 return new Token$1(index, TokenType$1.String, 0, text);
12667}
12668function newNumberToken(index, n) {
12669 return new Token$1(index, TokenType$1.Number, n, '');
12670}
12671function newErrorToken(index, message) {
12672 return new Token$1(index, TokenType$1.Error, 0, message);
12673}
12674const EOF = new Token$1(-1, TokenType$1.Character, 0, '');
12675class _Scanner {
12676 constructor(input) {
12677 this.input = input;
12678 this.peek = 0;
12679 this.index = -1;
12680 this.length = input.length;
12681 this.advance();
12682 }
12683 advance() {
12684 this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index);
12685 }
12686 scanToken() {
12687 const input = this.input, length = this.length;
12688 let peek = this.peek, index = this.index;
12689 // Skip whitespace.
12690 while (peek <= $SPACE) {
12691 if (++index >= length) {
12692 peek = $EOF;
12693 break;
12694 }
12695 else {
12696 peek = input.charCodeAt(index);
12697 }
12698 }
12699 this.peek = peek;
12700 this.index = index;
12701 if (index >= length) {
12702 return null;
12703 }
12704 // Handle identifiers and numbers.
12705 if (isIdentifierStart(peek))
12706 return this.scanIdentifier();
12707 if (isDigit(peek))
12708 return this.scanNumber(index);
12709 const start = index;
12710 switch (peek) {
12711 case $PERIOD:
12712 this.advance();
12713 return isDigit(this.peek) ? this.scanNumber(start) :
12714 newCharacterToken(start, $PERIOD);
12715 case $LPAREN:
12716 case $RPAREN:
12717 case $LBRACE:
12718 case $RBRACE:
12719 case $LBRACKET:
12720 case $RBRACKET:
12721 case $COMMA:
12722 case $COLON:
12723 case $SEMICOLON:
12724 return this.scanCharacter(start, peek);
12725 case $SQ:
12726 case $DQ:
12727 return this.scanString();
12728 case $HASH:
12729 case $PLUS:
12730 case $MINUS:
12731 case $STAR:
12732 case $SLASH:
12733 case $PERCENT:
12734 case $CARET:
12735 return this.scanOperator(start, String.fromCharCode(peek));
12736 case $QUESTION:
12737 return this.scanComplexOperator(start, '?', $PERIOD, '.');
12738 case $LT:
12739 case $GT:
12740 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=');
12741 case $BANG:
12742 case $EQ:
12743 return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=', $EQ, '=');
12744 case $AMPERSAND:
12745 return this.scanComplexOperator(start, '&', $AMPERSAND, '&');
12746 case $BAR:
12747 return this.scanComplexOperator(start, '|', $BAR, '|');
12748 case $NBSP:
12749 while (isWhitespace(this.peek))
12750 this.advance();
12751 return this.scanToken();
12752 }
12753 this.advance();
12754 return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0);
12755 }
12756 scanCharacter(start, code) {
12757 this.advance();
12758 return newCharacterToken(start, code);
12759 }
12760 scanOperator(start, str) {
12761 this.advance();
12762 return newOperatorToken(start, str);
12763 }
12764 /**
12765 * Tokenize a 2/3 char long operator
12766 *
12767 * @param start start index in the expression
12768 * @param one first symbol (always part of the operator)
12769 * @param twoCode code point for the second symbol
12770 * @param two second symbol (part of the operator when the second code point matches)
12771 * @param threeCode code point for the third symbol
12772 * @param three third symbol (part of the operator when provided and matches source expression)
12773 */
12774 scanComplexOperator(start, one, twoCode, two, threeCode, three) {
12775 this.advance();
12776 let str = one;
12777 if (this.peek == twoCode) {
12778 this.advance();
12779 str += two;
12780 }
12781 if (threeCode != null && this.peek == threeCode) {
12782 this.advance();
12783 str += three;
12784 }
12785 return newOperatorToken(start, str);
12786 }
12787 scanIdentifier() {
12788 const start = this.index;
12789 this.advance();
12790 while (isIdentifierPart(this.peek))
12791 this.advance();
12792 const str = this.input.substring(start, this.index);
12793 return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, str) :
12794 newIdentifierToken(start, str);
12795 }
12796 scanNumber(start) {
12797 let simple = (this.index === start);
12798 this.advance(); // Skip initial digit.
12799 while (true) {
12800 if (isDigit(this.peek)) {
12801 // Do nothing.
12802 }
12803 else if (this.peek == $PERIOD) {
12804 simple = false;
12805 }
12806 else if (isExponentStart(this.peek)) {
12807 this.advance();
12808 if (isExponentSign(this.peek))
12809 this.advance();
12810 if (!isDigit(this.peek))
12811 return this.error('Invalid exponent', -1);
12812 simple = false;
12813 }
12814 else {
12815 break;
12816 }
12817 this.advance();
12818 }
12819 const str = this.input.substring(start, this.index);
12820 const value = simple ? parseIntAutoRadix(str) : parseFloat(str);
12821 return newNumberToken(start, value);
12822 }
12823 scanString() {
12824 const start = this.index;
12825 const quote = this.peek;
12826 this.advance(); // Skip initial quote.
12827 let buffer = '';
12828 let marker = this.index;
12829 const input = this.input;
12830 while (this.peek != quote) {
12831 if (this.peek == $BACKSLASH) {
12832 buffer += input.substring(marker, this.index);
12833 this.advance();
12834 let unescapedCode;
12835 // Workaround for TS2.1-introduced type strictness
12836 this.peek = this.peek;
12837 if (this.peek == $u) {
12838 // 4 character hex code for unicode character.
12839 const hex = input.substring(this.index + 1, this.index + 5);
12840 if (/^[0-9a-f]+$/i.test(hex)) {
12841 unescapedCode = parseInt(hex, 16);
12842 }
12843 else {
12844 return this.error(`Invalid unicode escape [\\u${hex}]`, 0);
12845 }
12846 for (let i = 0; i < 5; i++) {
12847 this.advance();
12848 }
12849 }
12850 else {
12851 unescapedCode = unescape(this.peek);
12852 this.advance();
12853 }
12854 buffer += String.fromCharCode(unescapedCode);
12855 marker = this.index;
12856 }
12857 else if (this.peek == $EOF) {
12858 return this.error('Unterminated quote', 0);
12859 }
12860 else {
12861 this.advance();
12862 }
12863 }
12864 const last = input.substring(marker, this.index);
12865 this.advance(); // Skip terminating quote.
12866 return newStringToken(start, buffer + last);
12867 }
12868 error(message, offset) {
12869 const position = this.index + offset;
12870 return newErrorToken(position, `Lexer Error: ${message} at column ${position} in expression [${this.input}]`);
12871 }
12872}
12873function isIdentifierStart(code) {
12874 return ($a <= code && code <= $z) || ($A <= code && code <= $Z) ||
12875 (code == $_) || (code == $$);
12876}
12877function isIdentifier(input) {
12878 if (input.length == 0)
12879 return false;
12880 const scanner = new _Scanner(input);
12881 if (!isIdentifierStart(scanner.peek))
12882 return false;
12883 scanner.advance();
12884 while (scanner.peek !== $EOF) {
12885 if (!isIdentifierPart(scanner.peek))
12886 return false;
12887 scanner.advance();
12888 }
12889 return true;
12890}
12891function isIdentifierPart(code) {
12892 return isAsciiLetter(code) || isDigit(code) || (code == $_) ||
12893 (code == $$);
12894}
12895function isExponentStart(code) {
12896 return code == $e || code == $E;
12897}
12898function isExponentSign(code) {
12899 return code == $MINUS || code == $PLUS;
12900}
12901function isQuote(code) {
12902 return code === $SQ || code === $DQ || code === $BT;
12903}
12904function unescape(code) {
12905 switch (code) {
12906 case $n:
12907 return $LF;
12908 case $f:
12909 return $FF;
12910 case $r:
12911 return $CR;
12912 case $t:
12913 return $TAB;
12914 case $v:
12915 return $VTAB;
12916 default:
12917 return code;
12918 }
12919}
12920function parseIntAutoRadix(text) {
12921 const result = parseInt(text);
12922 if (isNaN(result)) {
12923 throw new Error('Invalid integer literal when parsing ' + text);
12924 }
12925 return result;
12926}
12927
12928/**
12929 * @license
12930 * Copyright Google Inc. All Rights Reserved.
12931 *
12932 * Use of this source code is governed by an MIT-style license that can be
12933 * found in the LICENSE file at https://angular.io/license
12934 */
12935class SplitInterpolation {
12936 constructor(strings, expressions, offsets) {
12937 this.strings = strings;
12938 this.expressions = expressions;
12939 this.offsets = offsets;
12940 }
12941}
12942class TemplateBindingParseResult {
12943 constructor(templateBindings, warnings, errors) {
12944 this.templateBindings = templateBindings;
12945 this.warnings = warnings;
12946 this.errors = errors;
12947 }
12948}
12949function _createInterpolateRegExp(config) {
12950 const pattern = escapeRegExp(config.start) + '([\\s\\S]*?)' + escapeRegExp(config.end);
12951 return new RegExp(pattern, 'g');
12952}
12953class Parser$1 {
12954 constructor(_lexer) {
12955 this._lexer = _lexer;
12956 this.errors = [];
12957 }
12958 parseAction(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
12959 this._checkNoInterpolation(input, location, interpolationConfig);
12960 const sourceToLex = this._stripComments(input);
12961 const tokens = this._lexer.tokenize(this._stripComments(input));
12962 const ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, true, this.errors, input.length - sourceToLex.length)
12963 .parseChain();
12964 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
12965 }
12966 parseBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
12967 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
12968 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
12969 }
12970 parseSimpleBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
12971 const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
12972 const errors = SimpleExpressionChecker.check(ast);
12973 if (errors.length > 0) {
12974 this._reportError(`Host binding expression cannot contain ${errors.join(' ')}`, input, location);
12975 }
12976 return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
12977 }
12978 _reportError(message, input, errLocation, ctxLocation) {
12979 this.errors.push(new ParserError(message, input, errLocation, ctxLocation));
12980 }
12981 _parseBindingAst(input, location, absoluteOffset, interpolationConfig) {
12982 // Quotes expressions use 3rd-party expression language. We don't want to use
12983 // our lexer or parser for that, so we check for that ahead of time.
12984 const quote = this._parseQuote(input, location);
12985 if (quote != null) {
12986 return quote;
12987 }
12988 this._checkNoInterpolation(input, location, interpolationConfig);
12989 const sourceToLex = this._stripComments(input);
12990 const tokens = this._lexer.tokenize(sourceToLex);
12991 return new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, input.length - sourceToLex.length)
12992 .parseChain();
12993 }
12994 _parseQuote(input, location) {
12995 if (input == null)
12996 return null;
12997 const prefixSeparatorIndex = input.indexOf(':');
12998 if (prefixSeparatorIndex == -1)
12999 return null;
13000 const prefix = input.substring(0, prefixSeparatorIndex).trim();
13001 if (!isIdentifier(prefix))
13002 return null;
13003 const uninterpretedExpression = input.substring(prefixSeparatorIndex + 1);
13004 return new Quote(new ParseSpan(0, input.length), prefix, uninterpretedExpression, location);
13005 }
13006 parseTemplateBindings(tplKey, tplValue, location, absoluteOffset) {
13007 const tokens = this._lexer.tokenize(tplValue);
13008 return new _ParseAST(tplValue, location, absoluteOffset, tokens, tplValue.length, false, this.errors, 0)
13009 .parseTemplateBindings(tplKey);
13010 }
13011 parseInterpolation(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13012 const split = this.splitInterpolation(input, location, interpolationConfig);
13013 if (split == null)
13014 return null;
13015 const expressions = [];
13016 for (let i = 0; i < split.expressions.length; ++i) {
13017 const expressionText = split.expressions[i];
13018 const sourceToLex = this._stripComments(expressionText);
13019 const tokens = this._lexer.tokenize(sourceToLex);
13020 const ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, split.offsets[i] + (expressionText.length - sourceToLex.length))
13021 .parseChain();
13022 expressions.push(ast);
13023 }
13024 return new ASTWithSource(new Interpolation(new ParseSpan(0, input == null ? 0 : input.length), split.strings, expressions), input, location, absoluteOffset, this.errors);
13025 }
13026 splitInterpolation(input, location, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
13027 const regexp = _createInterpolateRegExp(interpolationConfig);
13028 const parts = input.split(regexp);
13029 if (parts.length <= 1) {
13030 return null;
13031 }
13032 const strings = [];
13033 const expressions = [];
13034 const offsets = [];
13035 let offset = 0;
13036 for (let i = 0; i < parts.length; i++) {
13037 const part = parts[i];
13038 if (i % 2 === 0) {
13039 // fixed string
13040 strings.push(part);
13041 offset += part.length;
13042 }
13043 else if (part.trim().length > 0) {
13044 offset += interpolationConfig.start.length;
13045 expressions.push(part);
13046 offsets.push(offset);
13047 offset += part.length + interpolationConfig.end.length;
13048 }
13049 else {
13050 this._reportError('Blank expressions are not allowed in interpolated strings', input, `at column ${this._findInterpolationErrorColumn(parts, i, interpolationConfig)} in`, location);
13051 expressions.push('$implict');
13052 offsets.push(offset);
13053 }
13054 }
13055 return new SplitInterpolation(strings, expressions, offsets);
13056 }
13057 wrapLiteralPrimitive(input, location, absoluteOffset) {
13058 return new ASTWithSource(new LiteralPrimitive(new ParseSpan(0, input == null ? 0 : input.length), input), input, location, absoluteOffset, this.errors);
13059 }
13060 _stripComments(input) {
13061 const i = this._commentStart(input);
13062 return i != null ? input.substring(0, i).trim() : input;
13063 }
13064 _commentStart(input) {
13065 let outerQuote = null;
13066 for (let i = 0; i < input.length - 1; i++) {
13067 const char = input.charCodeAt(i);
13068 const nextChar = input.charCodeAt(i + 1);
13069 if (char === $SLASH && nextChar == $SLASH && outerQuote == null)
13070 return i;
13071 if (outerQuote === char) {
13072 outerQuote = null;
13073 }
13074 else if (outerQuote == null && isQuote(char)) {
13075 outerQuote = char;
13076 }
13077 }
13078 return null;
13079 }
13080 _checkNoInterpolation(input, location, interpolationConfig) {
13081 const regexp = _createInterpolateRegExp(interpolationConfig);
13082 const parts = input.split(regexp);
13083 if (parts.length > 1) {
13084 this._reportError(`Got interpolation (${interpolationConfig.start}${interpolationConfig.end}) where expression was expected`, input, `at column ${this._findInterpolationErrorColumn(parts, 1, interpolationConfig)} in`, location);
13085 }
13086 }
13087 _findInterpolationErrorColumn(parts, partInErrIdx, interpolationConfig) {
13088 let errLocation = '';
13089 for (let j = 0; j < partInErrIdx; j++) {
13090 errLocation += j % 2 === 0 ?
13091 parts[j] :
13092 `${interpolationConfig.start}${parts[j]}${interpolationConfig.end}`;
13093 }
13094 return errLocation.length;
13095 }
13096}
13097class _ParseAST {
13098 constructor(input, location, absoluteOffset, tokens, inputLength, parseAction, errors, offset) {
13099 this.input = input;
13100 this.location = location;
13101 this.absoluteOffset = absoluteOffset;
13102 this.tokens = tokens;
13103 this.inputLength = inputLength;
13104 this.parseAction = parseAction;
13105 this.errors = errors;
13106 this.offset = offset;
13107 this.rparensExpected = 0;
13108 this.rbracketsExpected = 0;
13109 this.rbracesExpected = 0;
13110 this.index = 0;
13111 }
13112 peek(offset) {
13113 const i = this.index + offset;
13114 return i < this.tokens.length ? this.tokens[i] : EOF;
13115 }
13116 get next() { return this.peek(0); }
13117 get inputIndex() {
13118 return (this.index < this.tokens.length) ? this.next.index + this.offset :
13119 this.inputLength + this.offset;
13120 }
13121 span(start) { return new ParseSpan(start, this.inputIndex); }
13122 advance() { this.index++; }
13123 optionalCharacter(code) {
13124 if (this.next.isCharacter(code)) {
13125 this.advance();
13126 return true;
13127 }
13128 else {
13129 return false;
13130 }
13131 }
13132 peekKeywordLet() { return this.next.isKeywordLet(); }
13133 peekKeywordAs() { return this.next.isKeywordAs(); }
13134 expectCharacter(code) {
13135 if (this.optionalCharacter(code))
13136 return;
13137 this.error(`Missing expected ${String.fromCharCode(code)}`);
13138 }
13139 optionalOperator(op) {
13140 if (this.next.isOperator(op)) {
13141 this.advance();
13142 return true;
13143 }
13144 else {
13145 return false;
13146 }
13147 }
13148 expectOperator(operator) {
13149 if (this.optionalOperator(operator))
13150 return;
13151 this.error(`Missing expected operator ${operator}`);
13152 }
13153 expectIdentifierOrKeyword() {
13154 const n = this.next;
13155 if (!n.isIdentifier() && !n.isKeyword()) {
13156 this.error(`Unexpected token ${n}, expected identifier or keyword`);
13157 return '';
13158 }
13159 this.advance();
13160 return n.toString();
13161 }
13162 expectIdentifierOrKeywordOrString() {
13163 const n = this.next;
13164 if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) {
13165 this.error(`Unexpected token ${n}, expected identifier, keyword, or string`);
13166 return '';
13167 }
13168 this.advance();
13169 return n.toString();
13170 }
13171 parseChain() {
13172 const exprs = [];
13173 const start = this.inputIndex;
13174 while (this.index < this.tokens.length) {
13175 const expr = this.parsePipe();
13176 exprs.push(expr);
13177 if (this.optionalCharacter($SEMICOLON)) {
13178 if (!this.parseAction) {
13179 this.error('Binding expression cannot contain chained expression');
13180 }
13181 while (this.optionalCharacter($SEMICOLON)) {
13182 } // read all semicolons
13183 }
13184 else if (this.index < this.tokens.length) {
13185 this.error(`Unexpected token '${this.next}'`);
13186 }
13187 }
13188 if (exprs.length == 0)
13189 return new EmptyExpr(this.span(start));
13190 if (exprs.length == 1)
13191 return exprs[0];
13192 return new Chain(this.span(start), exprs);
13193 }
13194 parsePipe() {
13195 let result = this.parseExpression();
13196 if (this.optionalOperator('|')) {
13197 if (this.parseAction) {
13198 this.error('Cannot have a pipe in an action expression');
13199 }
13200 do {
13201 const name = this.expectIdentifierOrKeyword();
13202 const args = [];
13203 while (this.optionalCharacter($COLON)) {
13204 args.push(this.parseExpression());
13205 }
13206 result = new BindingPipe(this.span(result.span.start), result, name, args);
13207 } while (this.optionalOperator('|'));
13208 }
13209 return result;
13210 }
13211 parseExpression() { return this.parseConditional(); }
13212 parseConditional() {
13213 const start = this.inputIndex;
13214 const result = this.parseLogicalOr();
13215 if (this.optionalOperator('?')) {
13216 const yes = this.parsePipe();
13217 let no;
13218 if (!this.optionalCharacter($COLON)) {
13219 const end = this.inputIndex;
13220 const expression = this.input.substring(start, end);
13221 this.error(`Conditional expression ${expression} requires all 3 expressions`);
13222 no = new EmptyExpr(this.span(start));
13223 }
13224 else {
13225 no = this.parsePipe();
13226 }
13227 return new Conditional(this.span(start), result, yes, no);
13228 }
13229 else {
13230 return result;
13231 }
13232 }
13233 parseLogicalOr() {
13234 // '||'
13235 let result = this.parseLogicalAnd();
13236 while (this.optionalOperator('||')) {
13237 const right = this.parseLogicalAnd();
13238 result = new Binary(this.span(result.span.start), '||', result, right);
13239 }
13240 return result;
13241 }
13242 parseLogicalAnd() {
13243 // '&&'
13244 let result = this.parseEquality();
13245 while (this.optionalOperator('&&')) {
13246 const right = this.parseEquality();
13247 result = new Binary(this.span(result.span.start), '&&', result, right);
13248 }
13249 return result;
13250 }
13251 parseEquality() {
13252 // '==','!=','===','!=='
13253 let result = this.parseRelational();
13254 while (this.next.type == TokenType$1.Operator) {
13255 const operator = this.next.strValue;
13256 switch (operator) {
13257 case '==':
13258 case '===':
13259 case '!=':
13260 case '!==':
13261 this.advance();
13262 const right = this.parseRelational();
13263 result = new Binary(this.span(result.span.start), operator, result, right);
13264 continue;
13265 }
13266 break;
13267 }
13268 return result;
13269 }
13270 parseRelational() {
13271 // '<', '>', '<=', '>='
13272 let result = this.parseAdditive();
13273 while (this.next.type == TokenType$1.Operator) {
13274 const operator = this.next.strValue;
13275 switch (operator) {
13276 case '<':
13277 case '>':
13278 case '<=':
13279 case '>=':
13280 this.advance();
13281 const right = this.parseAdditive();
13282 result = new Binary(this.span(result.span.start), operator, result, right);
13283 continue;
13284 }
13285 break;
13286 }
13287 return result;
13288 }
13289 parseAdditive() {
13290 // '+', '-'
13291 let result = this.parseMultiplicative();
13292 while (this.next.type == TokenType$1.Operator) {
13293 const operator = this.next.strValue;
13294 switch (operator) {
13295 case '+':
13296 case '-':
13297 this.advance();
13298 let right = this.parseMultiplicative();
13299 result = new Binary(this.span(result.span.start), operator, result, right);
13300 continue;
13301 }
13302 break;
13303 }
13304 return result;
13305 }
13306 parseMultiplicative() {
13307 // '*', '%', '/'
13308 let result = this.parsePrefix();
13309 while (this.next.type == TokenType$1.Operator) {
13310 const operator = this.next.strValue;
13311 switch (operator) {
13312 case '*':
13313 case '%':
13314 case '/':
13315 this.advance();
13316 let right = this.parsePrefix();
13317 result = new Binary(this.span(result.span.start), operator, result, right);
13318 continue;
13319 }
13320 break;
13321 }
13322 return result;
13323 }
13324 parsePrefix() {
13325 if (this.next.type == TokenType$1.Operator) {
13326 const start = this.inputIndex;
13327 const operator = this.next.strValue;
13328 let result;
13329 switch (operator) {
13330 case '+':
13331 this.advance();
13332 result = this.parsePrefix();
13333 return new Binary(this.span(start), '-', result, new LiteralPrimitive(new ParseSpan(start, start), 0));
13334 case '-':
13335 this.advance();
13336 result = this.parsePrefix();
13337 return new Binary(this.span(start), operator, new LiteralPrimitive(new ParseSpan(start, start), 0), result);
13338 case '!':
13339 this.advance();
13340 result = this.parsePrefix();
13341 return new PrefixNot(this.span(start), result);
13342 }
13343 }
13344 return this.parseCallChain();
13345 }
13346 parseCallChain() {
13347 let result = this.parsePrimary();
13348 while (true) {
13349 if (this.optionalCharacter($PERIOD)) {
13350 result = this.parseAccessMemberOrMethodCall(result, false);
13351 }
13352 else if (this.optionalOperator('?.')) {
13353 result = this.parseAccessMemberOrMethodCall(result, true);
13354 }
13355 else if (this.optionalCharacter($LBRACKET)) {
13356 this.rbracketsExpected++;
13357 const key = this.parsePipe();
13358 this.rbracketsExpected--;
13359 this.expectCharacter($RBRACKET);
13360 if (this.optionalOperator('=')) {
13361 const value = this.parseConditional();
13362 result = new KeyedWrite(this.span(result.span.start), result, key, value);
13363 }
13364 else {
13365 result = new KeyedRead(this.span(result.span.start), result, key);
13366 }
13367 }
13368 else if (this.optionalCharacter($LPAREN)) {
13369 this.rparensExpected++;
13370 const args = this.parseCallArguments();
13371 this.rparensExpected--;
13372 this.expectCharacter($RPAREN);
13373 result = new FunctionCall(this.span(result.span.start), result, args);
13374 }
13375 else if (this.optionalOperator('!')) {
13376 result = new NonNullAssert(this.span(result.span.start), result);
13377 }
13378 else {
13379 return result;
13380 }
13381 }
13382 }
13383 parsePrimary() {
13384 const start = this.inputIndex;
13385 if (this.optionalCharacter($LPAREN)) {
13386 this.rparensExpected++;
13387 const result = this.parsePipe();
13388 this.rparensExpected--;
13389 this.expectCharacter($RPAREN);
13390 return result;
13391 }
13392 else if (this.next.isKeywordNull()) {
13393 this.advance();
13394 return new LiteralPrimitive(this.span(start), null);
13395 }
13396 else if (this.next.isKeywordUndefined()) {
13397 this.advance();
13398 return new LiteralPrimitive(this.span(start), void 0);
13399 }
13400 else if (this.next.isKeywordTrue()) {
13401 this.advance();
13402 return new LiteralPrimitive(this.span(start), true);
13403 }
13404 else if (this.next.isKeywordFalse()) {
13405 this.advance();
13406 return new LiteralPrimitive(this.span(start), false);
13407 }
13408 else if (this.next.isKeywordThis()) {
13409 this.advance();
13410 return new ImplicitReceiver(this.span(start));
13411 }
13412 else if (this.optionalCharacter($LBRACKET)) {
13413 this.rbracketsExpected++;
13414 const elements = this.parseExpressionList($RBRACKET);
13415 this.rbracketsExpected--;
13416 this.expectCharacter($RBRACKET);
13417 return new LiteralArray(this.span(start), elements);
13418 }
13419 else if (this.next.isCharacter($LBRACE)) {
13420 return this.parseLiteralMap();
13421 }
13422 else if (this.next.isIdentifier()) {
13423 return this.parseAccessMemberOrMethodCall(new ImplicitReceiver(this.span(start)), false);
13424 }
13425 else if (this.next.isNumber()) {
13426 const value = this.next.toNumber();
13427 this.advance();
13428 return new LiteralPrimitive(this.span(start), value);
13429 }
13430 else if (this.next.isString()) {
13431 const literalValue = this.next.toString();
13432 this.advance();
13433 return new LiteralPrimitive(this.span(start), literalValue);
13434 }
13435 else if (this.index >= this.tokens.length) {
13436 this.error(`Unexpected end of expression: ${this.input}`);
13437 return new EmptyExpr(this.span(start));
13438 }
13439 else {
13440 this.error(`Unexpected token ${this.next}`);
13441 return new EmptyExpr(this.span(start));
13442 }
13443 }
13444 parseExpressionList(terminator) {
13445 const result = [];
13446 if (!this.next.isCharacter(terminator)) {
13447 do {
13448 result.push(this.parsePipe());
13449 } while (this.optionalCharacter($COMMA));
13450 }
13451 return result;
13452 }
13453 parseLiteralMap() {
13454 const keys = [];
13455 const values = [];
13456 const start = this.inputIndex;
13457 this.expectCharacter($LBRACE);
13458 if (!this.optionalCharacter($RBRACE)) {
13459 this.rbracesExpected++;
13460 do {
13461 const quoted = this.next.isString();
13462 const key = this.expectIdentifierOrKeywordOrString();
13463 keys.push({ key, quoted });
13464 this.expectCharacter($COLON);
13465 values.push(this.parsePipe());
13466 } while (this.optionalCharacter($COMMA));
13467 this.rbracesExpected--;
13468 this.expectCharacter($RBRACE);
13469 }
13470 return new LiteralMap(this.span(start), keys, values);
13471 }
13472 parseAccessMemberOrMethodCall(receiver, isSafe = false) {
13473 const start = receiver.span.start;
13474 const id = this.expectIdentifierOrKeyword();
13475 if (this.optionalCharacter($LPAREN)) {
13476 this.rparensExpected++;
13477 const args = this.parseCallArguments();
13478 this.expectCharacter($RPAREN);
13479 this.rparensExpected--;
13480 const span = this.span(start);
13481 return isSafe ? new SafeMethodCall(span, receiver, id, args) :
13482 new MethodCall(span, receiver, id, args);
13483 }
13484 else {
13485 if (isSafe) {
13486 if (this.optionalOperator('=')) {
13487 this.error('The \'?.\' operator cannot be used in the assignment');
13488 return new EmptyExpr(this.span(start));
13489 }
13490 else {
13491 return new SafePropertyRead(this.span(start), receiver, id);
13492 }
13493 }
13494 else {
13495 if (this.optionalOperator('=')) {
13496 if (!this.parseAction) {
13497 this.error('Bindings cannot contain assignments');
13498 return new EmptyExpr(this.span(start));
13499 }
13500 const value = this.parseConditional();
13501 return new PropertyWrite(this.span(start), receiver, id, value);
13502 }
13503 else {
13504 return new PropertyRead(this.span(start), receiver, id);
13505 }
13506 }
13507 }
13508 }
13509 parseCallArguments() {
13510 if (this.next.isCharacter($RPAREN))
13511 return [];
13512 const positionals = [];
13513 do {
13514 positionals.push(this.parsePipe());
13515 } while (this.optionalCharacter($COMMA));
13516 return positionals;
13517 }
13518 /**
13519 * An identifier, a keyword, a string with an optional `-` in between.
13520 */
13521 expectTemplateBindingKey() {
13522 let result = '';
13523 let operatorFound = false;
13524 do {
13525 result += this.expectIdentifierOrKeywordOrString();
13526 operatorFound = this.optionalOperator('-');
13527 if (operatorFound) {
13528 result += '-';
13529 }
13530 } while (operatorFound);
13531 return result.toString();
13532 }
13533 // Parses the AST for `<some-tag *tplKey=AST>`
13534 parseTemplateBindings(tplKey) {
13535 let firstBinding = true;
13536 const bindings = [];
13537 const warnings = [];
13538 do {
13539 const start = this.inputIndex;
13540 let rawKey;
13541 let key;
13542 let isVar = false;
13543 if (firstBinding) {
13544 rawKey = key = tplKey;
13545 firstBinding = false;
13546 }
13547 else {
13548 isVar = this.peekKeywordLet();
13549 if (isVar)
13550 this.advance();
13551 rawKey = this.expectTemplateBindingKey();
13552 key = isVar ? rawKey : tplKey + rawKey[0].toUpperCase() + rawKey.substring(1);
13553 this.optionalCharacter($COLON);
13554 }
13555 let name = null;
13556 let expression = null;
13557 if (isVar) {
13558 if (this.optionalOperator('=')) {
13559 name = this.expectTemplateBindingKey();
13560 }
13561 else {
13562 name = '\$implicit';
13563 }
13564 }
13565 else if (this.peekKeywordAs()) {
13566 this.advance(); // consume `as`
13567 name = rawKey;
13568 key = this.expectTemplateBindingKey(); // read local var name
13569 isVar = true;
13570 }
13571 else if (this.next !== EOF && !this.peekKeywordLet()) {
13572 const start = this.inputIndex;
13573 const ast = this.parsePipe();
13574 const source = this.input.substring(start - this.offset, this.inputIndex - this.offset);
13575 expression =
13576 new ASTWithSource(ast, source, this.location, this.absoluteOffset, this.errors);
13577 }
13578 bindings.push(new TemplateBinding(this.span(start), key, isVar, name, expression));
13579 if (this.peekKeywordAs() && !isVar) {
13580 const letStart = this.inputIndex;
13581 this.advance(); // consume `as`
13582 const letName = this.expectTemplateBindingKey(); // read local var name
13583 bindings.push(new TemplateBinding(this.span(letStart), letName, true, key, null));
13584 }
13585 if (!this.optionalCharacter($SEMICOLON)) {
13586 this.optionalCharacter($COMMA);
13587 }
13588 } while (this.index < this.tokens.length);
13589 return new TemplateBindingParseResult(bindings, warnings, this.errors);
13590 }
13591 error(message, index = null) {
13592 this.errors.push(new ParserError(message, this.input, this.locationText(index), this.location));
13593 this.skip();
13594 }
13595 locationText(index = null) {
13596 if (index == null)
13597 index = this.index;
13598 return (index < this.tokens.length) ? `at column ${this.tokens[index].index + 1} in` :
13599 `at the end of the expression`;
13600 }
13601 // Error recovery should skip tokens until it encounters a recovery point. skip() treats
13602 // the end of input and a ';' as unconditionally a recovery point. It also treats ')',
13603 // '}' and ']' as conditional recovery points if one of calling productions is expecting
13604 // one of these symbols. This allows skip() to recover from errors such as '(a.) + 1' allowing
13605 // more of the AST to be retained (it doesn't skip any tokens as the ')' is retained because
13606 // of the '(' begins an '(' <expr> ')' production). The recovery points of grouping symbols
13607 // must be conditional as they must be skipped if none of the calling productions are not
13608 // expecting the closing token else we will never make progress in the case of an
13609 // extraneous group closing symbol (such as a stray ')'). This is not the case for ';' because
13610 // parseChain() is always the root production and it expects a ';'.
13611 // If a production expects one of these token it increments the corresponding nesting count,
13612 // and then decrements it just prior to checking if the token is in the input.
13613 skip() {
13614 let n = this.next;
13615 while (this.index < this.tokens.length && !n.isCharacter($SEMICOLON) &&
13616 (this.rparensExpected <= 0 || !n.isCharacter($RPAREN)) &&
13617 (this.rbracesExpected <= 0 || !n.isCharacter($RBRACE)) &&
13618 (this.rbracketsExpected <= 0 || !n.isCharacter($RBRACKET))) {
13619 if (this.next.isError()) {
13620 this.errors.push(new ParserError(this.next.toString(), this.input, this.locationText(), this.location));
13621 }
13622 this.advance();
13623 n = this.next;
13624 }
13625 }
13626}
13627class SimpleExpressionChecker {
13628 constructor() {
13629 this.errors = [];
13630 }
13631 static check(ast) {
13632 const s = new SimpleExpressionChecker();
13633 ast.visit(s);
13634 return s.errors;
13635 }
13636 visitImplicitReceiver(ast, context) { }
13637 visitInterpolation(ast, context) { }
13638 visitLiteralPrimitive(ast, context) { }
13639 visitPropertyRead(ast, context) { }
13640 visitPropertyWrite(ast, context) { }
13641 visitSafePropertyRead(ast, context) { }
13642 visitMethodCall(ast, context) { }
13643 visitSafeMethodCall(ast, context) { }
13644 visitFunctionCall(ast, context) { }
13645 visitLiteralArray(ast, context) { this.visitAll(ast.expressions); }
13646 visitLiteralMap(ast, context) { this.visitAll(ast.values); }
13647 visitBinary(ast, context) { }
13648 visitPrefixNot(ast, context) { }
13649 visitNonNullAssert(ast, context) { }
13650 visitConditional(ast, context) { }
13651 visitPipe(ast, context) { this.errors.push('pipes'); }
13652 visitKeyedRead(ast, context) { }
13653 visitKeyedWrite(ast, context) { }
13654 visitAll(asts) { return asts.map(node => node.visit(this)); }
13655 visitChain(ast, context) { }
13656 visitQuote(ast, context) { }
13657}
13658
13659/**
13660 * @license
13661 * Copyright Google Inc. All Rights Reserved.
13662 *
13663 * Use of this source code is governed by an MIT-style license that can be
13664 * found in the LICENSE file at https://angular.io/license
13665 */
13666// =================================================================================================
13667// =================================================================================================
13668// =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
13669// =================================================================================================
13670// =================================================================================================
13671//
13672// DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
13673// Reach out to mprobst for details.
13674//
13675// =================================================================================================
13676/** Map from tagName|propertyName SecurityContext. Properties applying to all tags use '*'. */
13677let _SECURITY_SCHEMA;
13678function SECURITY_SCHEMA() {
13679 if (!_SECURITY_SCHEMA) {
13680 _SECURITY_SCHEMA = {};
13681 // Case is insignificant below, all element and attribute names are lower-cased for lookup.
13682 registerContext(SecurityContext.HTML, [
13683 'iframe|srcdoc',
13684 '*|innerHTML',
13685 '*|outerHTML',
13686 ]);
13687 registerContext(SecurityContext.STYLE, ['*|style']);
13688 // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
13689 registerContext(SecurityContext.URL, [
13690 '*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href',
13691 'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action',
13692 'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite',
13693 'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src',
13694 ]);
13695 registerContext(SecurityContext.RESOURCE_URL, [
13696 'applet|code',
13697 'applet|codebase',
13698 'base|href',
13699 'embed|src',
13700 'frame|src',
13701 'head|profile',
13702 'html|manifest',
13703 'iframe|src',
13704 'link|href',
13705 'media|src',
13706 'object|codebase',
13707 'object|data',
13708 'script|src',
13709 ]);
13710 }
13711 return _SECURITY_SCHEMA;
13712}
13713function registerContext(ctx, specs) {
13714 for (const spec of specs)
13715 _SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
13716}
13717
13718/**
13719 * @license
13720 * Copyright Google Inc. All Rights Reserved.
13721 *
13722 * Use of this source code is governed by an MIT-style license that can be
13723 * found in the LICENSE file at https://angular.io/license
13724 */
13725class ElementSchemaRegistry {
13726}
13727
13728/**
13729 * @license
13730 * Copyright Google Inc. All Rights Reserved.
13731 *
13732 * Use of this source code is governed by an MIT-style license that can be
13733 * found in the LICENSE file at https://angular.io/license
13734 */
13735const BOOLEAN = 'boolean';
13736const NUMBER = 'number';
13737const STRING = 'string';
13738const OBJECT = 'object';
13739/**
13740 * This array represents the DOM schema. It encodes inheritance, properties, and events.
13741 *
13742 * ## Overview
13743 *
13744 * Each line represents one kind of element. The `element_inheritance` and properties are joined
13745 * using `element_inheritance|properties` syntax.
13746 *
13747 * ## Element Inheritance
13748 *
13749 * The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
13750 * Here the individual elements are separated by `,` (commas). Every element in the list
13751 * has identical properties.
13752 *
13753 * An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
13754 * specified then `""` (blank) element is assumed.
13755 *
13756 * NOTE: The blank element inherits from root `[Element]` element, the super element of all
13757 * elements.
13758 *
13759 * NOTE an element prefix such as `:svg:` has no special meaning to the schema.
13760 *
13761 * ## Properties
13762 *
13763 * Each element has a set of properties separated by `,` (commas). Each property can be prefixed
13764 * by a special character designating its type:
13765 *
13766 * - (no prefix): property is a string.
13767 * - `*`: property represents an event.
13768 * - `!`: property is a boolean.
13769 * - `#`: property is a number.
13770 * - `%`: property is an object.
13771 *
13772 * ## Query
13773 *
13774 * The class creates an internal squas representation which allows to easily answer the query of
13775 * if a given property exist on a given element.
13776 *
13777 * NOTE: We don't yet support querying for types or events.
13778 * NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder,
13779 * see dom_element_schema_registry_spec.ts
13780 */
13781// =================================================================================================
13782// =================================================================================================
13783// =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
13784// =================================================================================================
13785// =================================================================================================
13786//
13787// DO NOT EDIT THIS DOM SCHEMA WITHOUT A SECURITY REVIEW!
13788//
13789// Newly added properties must be security reviewed and assigned an appropriate SecurityContext in
13790// dom_security_schema.ts. Reach out to mprobst & rjamet for details.
13791//
13792// =================================================================================================
13793const SCHEMA = [
13794 '[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop,slot' +
13795 /* added manually to avoid breaking changes */
13796 ',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored',
13797 '[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',
13798 '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',
13799 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume',
13800 ':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',
13801 ':svg:graphics^:svg:|',
13802 ':svg:animation^:svg:|*begin,*end,*repeat',
13803 ':svg:geometry^:svg:|',
13804 ':svg:componentTransferFunction^:svg:|',
13805 ':svg:gradient^:svg:|',
13806 ':svg:textContent^:svg:graphics|',
13807 ':svg:textPositioning^:svg:textContent|',
13808 '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',
13809 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username',
13810 'audio^media|',
13811 'br^[HTMLElement]|clear',
13812 'base^[HTMLElement]|href,target',
13813 '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',
13814 'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
13815 'canvas^[HTMLElement]|#height,#width',
13816 'content^[HTMLElement]|select',
13817 'dl^[HTMLElement]|!compact',
13818 'datalist^[HTMLElement]|',
13819 'details^[HTMLElement]|!open',
13820 'dialog^[HTMLElement]|!open,returnValue',
13821 'dir^[HTMLElement]|!compact',
13822 'div^[HTMLElement]|align',
13823 'embed^[HTMLElement]|align,height,name,src,type,width',
13824 'fieldset^[HTMLElement]|!disabled,name',
13825 'font^[HTMLElement]|color,face,size',
13826 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
13827 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
13828 'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
13829 'hr^[HTMLElement]|align,color,!noShade,size,width',
13830 'head^[HTMLElement]|',
13831 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align',
13832 'html^[HTMLElement]|version',
13833 'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width',
13834 'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width',
13835 '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',
13836 'li^[HTMLElement]|type,#value',
13837 'label^[HTMLElement]|htmlFor',
13838 'legend^[HTMLElement]|align',
13839 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type',
13840 'map^[HTMLElement]|name',
13841 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
13842 'menu^[HTMLElement]|!compact',
13843 'meta^[HTMLElement]|content,httpEquiv,name,scheme',
13844 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value',
13845 'ins,del^[HTMLElement]|cite,dateTime',
13846 'ol^[HTMLElement]|!compact,!reversed,#start,type',
13847 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
13848 'optgroup^[HTMLElement]|!disabled,label',
13849 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value',
13850 'output^[HTMLElement]|defaultValue,%htmlFor,name,value',
13851 'p^[HTMLElement]|align',
13852 'param^[HTMLElement]|name,type,value,valueType',
13853 'picture^[HTMLElement]|',
13854 'pre^[HTMLElement]|#width',
13855 'progress^[HTMLElement]|#max,#value',
13856 'q,blockquote,cite^[HTMLElement]|',
13857 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
13858 'select^[HTMLElement]|!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
13859 'shadow^[HTMLElement]|',
13860 'slot^[HTMLElement]|name',
13861 'source^[HTMLElement]|media,sizes,src,srcset,type',
13862 'span^[HTMLElement]|',
13863 'style^[HTMLElement]|!disabled,media,type',
13864 'caption^[HTMLElement]|align',
13865 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
13866 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width',
13867 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
13868 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign',
13869 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign',
13870 'template^[HTMLElement]|',
13871 'textarea^[HTMLElement]|autocapitalize,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
13872 'title^[HTMLElement]|text',
13873 'track^[HTMLElement]|!default,kind,label,src,srclang',
13874 'ul^[HTMLElement]|!compact,type',
13875 'unknown^[HTMLElement]|',
13876 'video^media|#height,poster,#width',
13877 ':svg:a^:svg:graphics|',
13878 ':svg:animate^:svg:animation|',
13879 ':svg:animateMotion^:svg:animation|',
13880 ':svg:animateTransform^:svg:animation|',
13881 ':svg:circle^:svg:geometry|',
13882 ':svg:clipPath^:svg:graphics|',
13883 ':svg:defs^:svg:graphics|',
13884 ':svg:desc^:svg:|',
13885 ':svg:discard^:svg:|',
13886 ':svg:ellipse^:svg:geometry|',
13887 ':svg:feBlend^:svg:|',
13888 ':svg:feColorMatrix^:svg:|',
13889 ':svg:feComponentTransfer^:svg:|',
13890 ':svg:feComposite^:svg:|',
13891 ':svg:feConvolveMatrix^:svg:|',
13892 ':svg:feDiffuseLighting^:svg:|',
13893 ':svg:feDisplacementMap^:svg:|',
13894 ':svg:feDistantLight^:svg:|',
13895 ':svg:feDropShadow^:svg:|',
13896 ':svg:feFlood^:svg:|',
13897 ':svg:feFuncA^:svg:componentTransferFunction|',
13898 ':svg:feFuncB^:svg:componentTransferFunction|',
13899 ':svg:feFuncG^:svg:componentTransferFunction|',
13900 ':svg:feFuncR^:svg:componentTransferFunction|',
13901 ':svg:feGaussianBlur^:svg:|',
13902 ':svg:feImage^:svg:|',
13903 ':svg:feMerge^:svg:|',
13904 ':svg:feMergeNode^:svg:|',
13905 ':svg:feMorphology^:svg:|',
13906 ':svg:feOffset^:svg:|',
13907 ':svg:fePointLight^:svg:|',
13908 ':svg:feSpecularLighting^:svg:|',
13909 ':svg:feSpotLight^:svg:|',
13910 ':svg:feTile^:svg:|',
13911 ':svg:feTurbulence^:svg:|',
13912 ':svg:filter^:svg:|',
13913 ':svg:foreignObject^:svg:graphics|',
13914 ':svg:g^:svg:graphics|',
13915 ':svg:image^:svg:graphics|',
13916 ':svg:line^:svg:geometry|',
13917 ':svg:linearGradient^:svg:gradient|',
13918 ':svg:mpath^:svg:|',
13919 ':svg:marker^:svg:|',
13920 ':svg:mask^:svg:|',
13921 ':svg:metadata^:svg:|',
13922 ':svg:path^:svg:geometry|',
13923 ':svg:pattern^:svg:|',
13924 ':svg:polygon^:svg:geometry|',
13925 ':svg:polyline^:svg:geometry|',
13926 ':svg:radialGradient^:svg:gradient|',
13927 ':svg:rect^:svg:geometry|',
13928 ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan',
13929 ':svg:script^:svg:|type',
13930 ':svg:set^:svg:animation|',
13931 ':svg:stop^:svg:|',
13932 ':svg:style^:svg:|!disabled,media,title,type',
13933 ':svg:switch^:svg:graphics|',
13934 ':svg:symbol^:svg:|',
13935 ':svg:tspan^:svg:textPositioning|',
13936 ':svg:text^:svg:textPositioning|',
13937 ':svg:textPath^:svg:textContent|',
13938 ':svg:title^:svg:|',
13939 ':svg:use^:svg:graphics|',
13940 ':svg:view^:svg:|#zoomAndPan',
13941 'data^[HTMLElement]|value',
13942 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name',
13943 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
13944 'summary^[HTMLElement]|',
13945 'time^[HTMLElement]|dateTime',
13946 ':svg:cursor^:svg:|',
13947];
13948const _ATTR_TO_PROP = {
13949 'class': 'className',
13950 'for': 'htmlFor',
13951 'formaction': 'formAction',
13952 'innerHtml': 'innerHTML',
13953 'readonly': 'readOnly',
13954 'tabindex': 'tabIndex',
13955};
13956class DomElementSchemaRegistry extends ElementSchemaRegistry {
13957 constructor() {
13958 super();
13959 this._schema = {};
13960 SCHEMA.forEach(encodedType => {
13961 const type = {};
13962 const [strType, strProperties] = encodedType.split('|');
13963 const properties = strProperties.split(',');
13964 const [typeNames, superName] = strType.split('^');
13965 typeNames.split(',').forEach(tag => this._schema[tag.toLowerCase()] = type);
13966 const superType = superName && this._schema[superName.toLowerCase()];
13967 if (superType) {
13968 Object.keys(superType).forEach((prop) => { type[prop] = superType[prop]; });
13969 }
13970 properties.forEach((property) => {
13971 if (property.length > 0) {
13972 switch (property[0]) {
13973 case '*':
13974 // We don't yet support events.
13975 // If ever allowing to bind to events, GO THROUGH A SECURITY REVIEW, allowing events
13976 // will
13977 // almost certainly introduce bad XSS vulnerabilities.
13978 // type[property.substring(1)] = EVENT;
13979 break;
13980 case '!':
13981 type[property.substring(1)] = BOOLEAN;
13982 break;
13983 case '#':
13984 type[property.substring(1)] = NUMBER;
13985 break;
13986 case '%':
13987 type[property.substring(1)] = OBJECT;
13988 break;
13989 default:
13990 type[property] = STRING;
13991 }
13992 }
13993 });
13994 });
13995 }
13996 hasProperty(tagName, propName, schemaMetas) {
13997 if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) {
13998 return true;
13999 }
14000 if (tagName.indexOf('-') > -1) {
14001 if (isNgContainer(tagName) || isNgContent(tagName)) {
14002 return false;
14003 }
14004 if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
14005 // Can't tell now as we don't know which properties a custom element will get
14006 // once it is instantiated
14007 return true;
14008 }
14009 }
14010 const elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
14011 return !!elementProperties[propName];
14012 }
14013 hasElement(tagName, schemaMetas) {
14014 if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) {
14015 return true;
14016 }
14017 if (tagName.indexOf('-') > -1) {
14018 if (isNgContainer(tagName) || isNgContent(tagName)) {
14019 return true;
14020 }
14021 if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
14022 // Allow any custom elements
14023 return true;
14024 }
14025 }
14026 return !!this._schema[tagName.toLowerCase()];
14027 }
14028 /**
14029 * securityContext returns the security context for the given property on the given DOM tag.
14030 *
14031 * Tag and property name are statically known and cannot change at runtime, i.e. it is not
14032 * possible to bind a value into a changing attribute or tag name.
14033 *
14034 * The filtering is based on a list of allowed tags|attributes. All attributes in the schema
14035 * above are assumed to have the 'NONE' security context, i.e. that they are safe inert
14036 * string values. Only specific well known attack vectors are assigned their appropriate context.
14037 */
14038 securityContext(tagName, propName, isAttribute) {
14039 if (isAttribute) {
14040 // NB: For security purposes, use the mapped property name, not the attribute name.
14041 propName = this.getMappedPropName(propName);
14042 }
14043 // Make sure comparisons are case insensitive, so that case differences between attribute and
14044 // property names do not have a security impact.
14045 tagName = tagName.toLowerCase();
14046 propName = propName.toLowerCase();
14047 let ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
14048 if (ctx) {
14049 return ctx;
14050 }
14051 ctx = SECURITY_SCHEMA()['*|' + propName];
14052 return ctx ? ctx : SecurityContext.NONE;
14053 }
14054 getMappedPropName(propName) { return _ATTR_TO_PROP[propName] || propName; }
14055 getDefaultComponentElementName() { return 'ng-component'; }
14056 validateProperty(name) {
14057 if (name.toLowerCase().startsWith('on')) {
14058 const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
14059 `please use (${name.slice(2)})=...` +
14060 `\nIf '${name}' is a directive input, make sure the directive is imported by the` +
14061 ` current module.`;
14062 return { error: true, msg: msg };
14063 }
14064 else {
14065 return { error: false };
14066 }
14067 }
14068 validateAttribute(name) {
14069 if (name.toLowerCase().startsWith('on')) {
14070 const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
14071 `please use (${name.slice(2)})=...`;
14072 return { error: true, msg: msg };
14073 }
14074 else {
14075 return { error: false };
14076 }
14077 }
14078 allKnownElementNames() { return Object.keys(this._schema); }
14079 normalizeAnimationStyleProperty(propName) {
14080 return dashCaseToCamelCase(propName);
14081 }
14082 normalizeAnimationStyleValue(camelCaseProp, userProvidedProp, val) {
14083 let unit = '';
14084 const strVal = val.toString().trim();
14085 let errorMsg = null;
14086 if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
14087 if (typeof val === 'number') {
14088 unit = 'px';
14089 }
14090 else {
14091 const valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/);
14092 if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
14093 errorMsg = `Please provide a CSS unit value for ${userProvidedProp}:${val}`;
14094 }
14095 }
14096 }
14097 return { error: errorMsg, value: strVal + unit };
14098 }
14099}
14100function _isPixelDimensionStyle(prop) {
14101 switch (prop) {
14102 case 'width':
14103 case 'height':
14104 case 'minWidth':
14105 case 'minHeight':
14106 case 'maxWidth':
14107 case 'maxHeight':
14108 case 'left':
14109 case 'top':
14110 case 'bottom':
14111 case 'right':
14112 case 'fontSize':
14113 case 'outlineWidth':
14114 case 'outlineOffset':
14115 case 'paddingTop':
14116 case 'paddingLeft':
14117 case 'paddingBottom':
14118 case 'paddingRight':
14119 case 'marginTop':
14120 case 'marginLeft':
14121 case 'marginBottom':
14122 case 'marginRight':
14123 case 'borderRadius':
14124 case 'borderWidth':
14125 case 'borderTopWidth':
14126 case 'borderLeftWidth':
14127 case 'borderRightWidth':
14128 case 'borderBottomWidth':
14129 case 'textIndent':
14130 return true;
14131 default:
14132 return false;
14133 }
14134}
14135
14136/**
14137 * @license
14138 * Copyright Google Inc. All Rights Reserved.
14139 *
14140 * Use of this source code is governed by an MIT-style license that can be
14141 * found in the LICENSE file at https://angular.io/license
14142 */
14143const BIND_NAME_REGEXP$1 = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/;
14144// Group 1 = "bind-"
14145const KW_BIND_IDX$1 = 1;
14146// Group 2 = "let-"
14147const KW_LET_IDX$1 = 2;
14148// Group 3 = "ref-/#"
14149const KW_REF_IDX$1 = 3;
14150// Group 4 = "on-"
14151const KW_ON_IDX$1 = 4;
14152// Group 5 = "bindon-"
14153const KW_BINDON_IDX$1 = 5;
14154// Group 6 = "@"
14155const KW_AT_IDX$1 = 6;
14156// Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
14157const IDENT_KW_IDX$1 = 7;
14158// Group 8 = identifier inside [()]
14159const IDENT_BANANA_BOX_IDX$1 = 8;
14160// Group 9 = identifier inside []
14161const IDENT_PROPERTY_IDX$1 = 9;
14162// Group 10 = identifier inside ()
14163const IDENT_EVENT_IDX$1 = 10;
14164const TEMPLATE_ATTR_PREFIX$1 = '*';
14165function htmlAstToRender3Ast(htmlNodes, bindingParser) {
14166 const transformer = new HtmlAstToIvyAst(bindingParser);
14167 const ivyNodes = visitAll$1(transformer, htmlNodes);
14168 // Errors might originate in either the binding parser or the html to ivy transformer
14169 const allErrors = bindingParser.errors.concat(transformer.errors);
14170 const errors = allErrors.filter(e => e.level === ParseErrorLevel.ERROR);
14171 if (errors.length > 0) {
14172 const errorString = errors.join('\n');
14173 throw syntaxError(`Template parse errors:\n${errorString}`, errors);
14174 }
14175 return {
14176 nodes: ivyNodes,
14177 errors: allErrors,
14178 styleUrls: transformer.styleUrls,
14179 styles: transformer.styles,
14180 };
14181}
14182class HtmlAstToIvyAst {
14183 constructor(bindingParser) {
14184 this.bindingParser = bindingParser;
14185 this.errors = [];
14186 this.styles = [];
14187 this.styleUrls = [];
14188 }
14189 // HTML visitor
14190 visitElement(element) {
14191 const preparsedElement = preparseElement(element);
14192 if (preparsedElement.type === PreparsedElementType.SCRIPT) {
14193 return null;
14194 }
14195 else if (preparsedElement.type === PreparsedElementType.STYLE) {
14196 const contents = textContents(element);
14197 if (contents !== null) {
14198 this.styles.push(contents);
14199 }
14200 return null;
14201 }
14202 else if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
14203 isStyleUrlResolvable(preparsedElement.hrefAttr)) {
14204 this.styleUrls.push(preparsedElement.hrefAttr);
14205 return null;
14206 }
14207 // Whether the element is a `<ng-template>`
14208 const isTemplateElement = isNgTemplate(element.name);
14209 const parsedProperties = [];
14210 const boundEvents = [];
14211 const variables = [];
14212 const references = [];
14213 const attributes = [];
14214 const i18nAttrsMeta = {};
14215 const templateParsedProperties = [];
14216 const templateVariables = [];
14217 // Whether the element has any *-attribute
14218 let elementHasInlineTemplate = false;
14219 for (const attribute of element.attrs) {
14220 let hasBinding = false;
14221 const normalizedName = normalizeAttributeName(attribute.name);
14222 // `*attr` defines template bindings
14223 let isTemplateBinding = false;
14224 if (attribute.i18n) {
14225 i18nAttrsMeta[attribute.name] = attribute.i18n;
14226 }
14227 if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX$1)) {
14228 // *-attributes
14229 if (elementHasInlineTemplate) {
14230 this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan);
14231 }
14232 isTemplateBinding = true;
14233 elementHasInlineTemplate = true;
14234 const templateValue = attribute.value;
14235 const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX$1.length);
14236 const parsedVariables = [];
14237 const absoluteOffset = attribute.valueSpan ? attribute.valueSpan.start.offset :
14238 attribute.sourceSpan.start.offset;
14239 this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteOffset, [], templateParsedProperties, parsedVariables);
14240 templateVariables.push(...parsedVariables.map(v => new Variable(v.name, v.value, v.sourceSpan)));
14241 }
14242 else {
14243 // Check for variables, events, property bindings, interpolation
14244 hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
14245 }
14246 if (!hasBinding && !isTemplateBinding) {
14247 // don't include the bindings as attributes as well in the AST
14248 attributes.push(this.visitAttribute(attribute));
14249 }
14250 }
14251 const children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR$1 : this, element.children);
14252 let parsedElement;
14253 if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
14254 // `<ng-content>`
14255 if (element.children &&
14256 !element.children.every((node) => isEmptyTextNode(node) || isCommentNode(node))) {
14257 this.reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
14258 }
14259 const selector = preparsedElement.selectAttr;
14260 const attrs = element.attrs.map(attr => this.visitAttribute(attr));
14261 parsedElement = new Content(selector, attrs, element.sourceSpan, element.i18n);
14262 }
14263 else if (isTemplateElement) {
14264 // `<ng-template>`
14265 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
14266 parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, [ /* no template attributes */], children, references, variables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
14267 }
14268 else {
14269 const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
14270 parsedElement = new Element(element.name, attributes, attrs.bound, boundEvents, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
14271 }
14272 if (elementHasInlineTemplate) {
14273 // If this node is an inline-template (e.g. has *ngFor) then we need to create a template
14274 // node that contains this node.
14275 // Moreover, if the node is an element, then we need to hoist its attributes to the template
14276 // node for matching against content projection selectors.
14277 const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
14278 const templateAttrs = [];
14279 attrs.literal.forEach(attr => templateAttrs.push(attr));
14280 attrs.bound.forEach(attr => templateAttrs.push(attr));
14281 const hoistedAttrs = parsedElement instanceof Element ?
14282 {
14283 attributes: parsedElement.attributes,
14284 inputs: parsedElement.inputs,
14285 outputs: parsedElement.outputs,
14286 } :
14287 { attributes: [], inputs: [], outputs: [] };
14288 // TODO(pk): test for this case
14289 parsedElement = new Template(parsedElement.name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, templateAttrs, [parsedElement], [ /* no references */], templateVariables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
14290 }
14291 return parsedElement;
14292 }
14293 visitAttribute(attribute) {
14294 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.valueSpan, attribute.i18n);
14295 }
14296 visitText(text) {
14297 return this._visitTextWithInterpolation(text.value, text.sourceSpan, text.i18n);
14298 }
14299 visitExpansion(expansion) {
14300 const meta = expansion.i18n;
14301 // do not generate Icu in case it was created
14302 // outside of i18n block in a template
14303 if (!meta) {
14304 return null;
14305 }
14306 const vars = {};
14307 const placeholders = {};
14308 // extract VARs from ICUs - we process them separately while
14309 // assembling resulting message via goog.getMsg function, since
14310 // we need to pass them to top-level goog.getMsg call
14311 Object.keys(meta.placeholders).forEach(key => {
14312 const value = meta.placeholders[key];
14313 if (key.startsWith(I18N_ICU_VAR_PREFIX)) {
14314 const config = this.bindingParser.interpolationConfig;
14315 // ICU expression is a plain string, not wrapped into start
14316 // and end tags, so we wrap it before passing to binding parser
14317 const wrapped = `${config.start}${value}${config.end}`;
14318 vars[key] = this._visitTextWithInterpolation(wrapped, expansion.sourceSpan);
14319 }
14320 else {
14321 placeholders[key] = this._visitTextWithInterpolation(value, expansion.sourceSpan);
14322 }
14323 });
14324 return new Icu(vars, placeholders, expansion.sourceSpan, meta);
14325 }
14326 visitExpansionCase(expansionCase) { return null; }
14327 visitComment(comment) { return null; }
14328 // convert view engine `ParsedProperty` to a format suitable for IVY
14329 extractAttributes(elementName, properties, i18nPropsMeta) {
14330 const bound = [];
14331 const literal = [];
14332 properties.forEach(prop => {
14333 const i18n = i18nPropsMeta[prop.name];
14334 if (prop.isLiteral) {
14335 literal.push(new TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan, undefined, i18n));
14336 }
14337 else {
14338 // Note that validation is skipped and property mapping is disabled
14339 // due to the fact that we need to make sure a given prop is not an
14340 // input of a directive and directive matching happens at runtime.
14341 const bep = this.bindingParser.createBoundElementProperty(elementName, prop, /* skipValidation */ true, /* mapPropertyName */ false);
14342 bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n));
14343 }
14344 });
14345 return { bound, literal };
14346 }
14347 parseAttribute(isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) {
14348 const name = normalizeAttributeName(attribute.name);
14349 const value = attribute.value;
14350 const srcSpan = attribute.sourceSpan;
14351 const absoluteOffset = attribute.valueSpan ? attribute.valueSpan.start.offset : srcSpan.start.offset;
14352 const bindParts = name.match(BIND_NAME_REGEXP$1);
14353 let hasBinding = false;
14354 if (bindParts) {
14355 hasBinding = true;
14356 if (bindParts[KW_BIND_IDX$1] != null) {
14357 this.bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX$1], value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties);
14358 }
14359 else if (bindParts[KW_LET_IDX$1]) {
14360 if (isTemplateElement) {
14361 const identifier = bindParts[IDENT_KW_IDX$1];
14362 this.parseVariable(identifier, value, srcSpan, attribute.valueSpan, variables);
14363 }
14364 else {
14365 this.reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
14366 }
14367 }
14368 else if (bindParts[KW_REF_IDX$1]) {
14369 const identifier = bindParts[IDENT_KW_IDX$1];
14370 this.parseReference(identifier, value, srcSpan, attribute.valueSpan, references);
14371 }
14372 else if (bindParts[KW_ON_IDX$1]) {
14373 const events = [];
14374 this.bindingParser.parseEvent(bindParts[IDENT_KW_IDX$1], value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events);
14375 addEvents(events, boundEvents);
14376 }
14377 else if (bindParts[KW_BINDON_IDX$1]) {
14378 this.bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX$1], value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties);
14379 this.parseAssignmentEvent(bindParts[IDENT_KW_IDX$1], value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents);
14380 }
14381 else if (bindParts[KW_AT_IDX$1]) {
14382 this.bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties);
14383 }
14384 else if (bindParts[IDENT_BANANA_BOX_IDX$1]) {
14385 this.bindingParser.parsePropertyBinding(bindParts[IDENT_BANANA_BOX_IDX$1], value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties);
14386 this.parseAssignmentEvent(bindParts[IDENT_BANANA_BOX_IDX$1], value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents);
14387 }
14388 else if (bindParts[IDENT_PROPERTY_IDX$1]) {
14389 this.bindingParser.parsePropertyBinding(bindParts[IDENT_PROPERTY_IDX$1], value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties);
14390 }
14391 else if (bindParts[IDENT_EVENT_IDX$1]) {
14392 const events = [];
14393 this.bindingParser.parseEvent(bindParts[IDENT_EVENT_IDX$1], value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events);
14394 addEvents(events, boundEvents);
14395 }
14396 }
14397 else {
14398 hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties);
14399 }
14400 return hasBinding;
14401 }
14402 _visitTextWithInterpolation(value, sourceSpan, i18n) {
14403 const valueNoNgsp = replaceNgsp(value);
14404 const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan);
14405 return expr ? new BoundText(expr, sourceSpan, i18n) : new Text(valueNoNgsp, sourceSpan);
14406 }
14407 parseVariable(identifier, value, sourceSpan, valueSpan, variables) {
14408 if (identifier.indexOf('-') > -1) {
14409 this.reportError(`"-" is not allowed in variable names`, sourceSpan);
14410 }
14411 variables.push(new Variable(identifier, value, sourceSpan, valueSpan));
14412 }
14413 parseReference(identifier, value, sourceSpan, valueSpan, references) {
14414 if (identifier.indexOf('-') > -1) {
14415 this.reportError(`"-" is not allowed in reference names`, sourceSpan);
14416 }
14417 references.push(new Reference(identifier, value, sourceSpan, valueSpan));
14418 }
14419 parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents) {
14420 const events = [];
14421 this.bindingParser.parseEvent(`${name}Change`, `${expression}=$event`, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events);
14422 addEvents(events, boundEvents);
14423 }
14424 reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
14425 this.errors.push(new ParseError(sourceSpan, message, level));
14426 }
14427}
14428class NonBindableVisitor$1 {
14429 visitElement(ast) {
14430 const preparsedElement = preparseElement(ast);
14431 if (preparsedElement.type === PreparsedElementType.SCRIPT ||
14432 preparsedElement.type === PreparsedElementType.STYLE ||
14433 preparsedElement.type === PreparsedElementType.STYLESHEET) {
14434 // Skipping <script> for security reasons
14435 // Skipping <style> and stylesheets as we already processed them
14436 // in the StyleCompiler
14437 return null;
14438 }
14439 const children = visitAll$1(this, ast.children, null);
14440 return new Element(ast.name, visitAll$1(this, ast.attrs),
14441 /* inputs */ [], /* outputs */ [], children, /* references */ [], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
14442 }
14443 visitComment(comment) { return null; }
14444 visitAttribute(attribute) {
14445 return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, undefined, attribute.i18n);
14446 }
14447 visitText(text) { return new Text(text.value, text.sourceSpan); }
14448 visitExpansion(expansion) { return null; }
14449 visitExpansionCase(expansionCase) { return null; }
14450}
14451const NON_BINDABLE_VISITOR$1 = new NonBindableVisitor$1();
14452function normalizeAttributeName(attrName) {
14453 return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
14454}
14455function addEvents(events, boundEvents) {
14456 boundEvents.push(...events.map(e => BoundEvent.fromParsedEvent(e)));
14457}
14458function isEmptyTextNode(node) {
14459 return node instanceof Text$3 && node.value.trim().length == 0;
14460}
14461function isCommentNode(node) {
14462 return node instanceof Comment;
14463}
14464function textContents(node) {
14465 if (node.children.length !== 1 || !(node.children[0] instanceof Text$3)) {
14466 return null;
14467 }
14468 else {
14469 return node.children[0].value;
14470 }
14471}
14472
14473/**
14474 * @license
14475 * Copyright Google Inc. All Rights Reserved.
14476 *
14477 * Use of this source code is governed by an MIT-style license that can be
14478 * found in the LICENSE file at https://angular.io/license
14479 */
14480var TagType;
14481(function (TagType) {
14482 TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
14483 TagType[TagType["TEMPLATE"] = 1] = "TEMPLATE";
14484 TagType[TagType["PROJECTION"] = 2] = "PROJECTION";
14485})(TagType || (TagType = {}));
14486/**
14487 * Generates an object that is used as a shared state between parent and all child contexts.
14488 */
14489function setupRegistry() {
14490 return { getUniqueId: getSeqNumberGenerator(), icus: new Map() };
14491}
14492/**
14493 * I18nContext is a helper class which keeps track of all i18n-related aspects
14494 * (accumulates placeholders, bindings, etc) between i18nStart and i18nEnd instructions.
14495 *
14496 * When we enter a nested template, the top-level context is being passed down
14497 * to the nested component, which uses this context to generate a child instance
14498 * of I18nContext class (to handle nested template) and at the end, reconciles it back
14499 * with the parent context.
14500 *
14501 * @param index Instruction index of i18nStart, which initiates this context
14502 * @param ref Reference to a translation const that represents the content if thus context
14503 * @param level Nestng level defined for child contexts
14504 * @param templateIndex Instruction index of a template which this context belongs to
14505 * @param meta Meta information (id, meaning, description, etc) associated with this context
14506 */
14507class I18nContext {
14508 constructor(index, ref, level = 0, templateIndex = null, meta, registry) {
14509 this.index = index;
14510 this.ref = ref;
14511 this.level = level;
14512 this.templateIndex = templateIndex;
14513 this.meta = meta;
14514 this.registry = registry;
14515 this.bindings = new Set();
14516 this.placeholders = new Map();
14517 this.isEmitted = false;
14518 this._unresolvedCtxCount = 0;
14519 this._registry = registry || setupRegistry();
14520 this.id = this._registry.getUniqueId();
14521 }
14522 appendTag(type, node, index, closed) {
14523 if (node.isVoid && closed) {
14524 return; // ignore "close" for void tags
14525 }
14526 const ph = node.isVoid || !closed ? node.startName : node.closeName;
14527 const content = { type, index, ctx: this.id, isVoid: node.isVoid, closed };
14528 updatePlaceholderMap(this.placeholders, ph, content);
14529 }
14530 get icus() { return this._registry.icus; }
14531 get isRoot() { return this.level === 0; }
14532 get isResolved() { return this._unresolvedCtxCount === 0; }
14533 getSerializedPlaceholders() {
14534 const result = new Map();
14535 this.placeholders.forEach((values, key) => result.set(key, values.map(serializePlaceholderValue)));
14536 return result;
14537 }
14538 // public API to accumulate i18n-related content
14539 appendBinding(binding) { this.bindings.add(binding); }
14540 appendIcu(name, ref) {
14541 updatePlaceholderMap(this._registry.icus, name, ref);
14542 }
14543 appendBoundText(node) {
14544 const phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id);
14545 phs.forEach((values, key) => updatePlaceholderMap(this.placeholders, key, ...values));
14546 }
14547 appendTemplate(node, index) {
14548 // add open and close tags at the same time,
14549 // since we process nested templates separately
14550 this.appendTag(TagType.TEMPLATE, node, index, false);
14551 this.appendTag(TagType.TEMPLATE, node, index, true);
14552 this._unresolvedCtxCount++;
14553 }
14554 appendElement(node, index, closed) {
14555 this.appendTag(TagType.ELEMENT, node, index, closed);
14556 }
14557 appendProjection(node, index) {
14558 // add open and close tags at the same time,
14559 // since we process projected content separately
14560 this.appendTag(TagType.PROJECTION, node, index, false);
14561 this.appendTag(TagType.PROJECTION, node, index, true);
14562 }
14563 /**
14564 * Generates an instance of a child context based on the root one,
14565 * when we enter a nested template within I18n section.
14566 *
14567 * @param index Instruction index of corresponding i18nStart, which initiates this context
14568 * @param templateIndex Instruction index of a template which this context belongs to
14569 * @param meta Meta information (id, meaning, description, etc) associated with this context
14570 *
14571 * @returns I18nContext instance
14572 */
14573 forkChildContext(index, templateIndex, meta) {
14574 return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry);
14575 }
14576 /**
14577 * Reconciles child context into parent one once the end of the i18n block is reached (i18nEnd).
14578 *
14579 * @param context Child I18nContext instance to be reconciled with parent context.
14580 */
14581 reconcileChildContext(context) {
14582 // set the right context id for open and close
14583 // template tags, so we can use it as sub-block ids
14584 ['start', 'close'].forEach((op) => {
14585 const key = context.meta[`${op}Name`];
14586 const phs = this.placeholders.get(key) || [];
14587 const tag = phs.find(findTemplateFn(this.id, context.templateIndex));
14588 if (tag) {
14589 tag.ctx = context.id;
14590 }
14591 });
14592 // reconcile placeholders
14593 const childPhs = context.placeholders;
14594 childPhs.forEach((values, key) => {
14595 const phs = this.placeholders.get(key);
14596 if (!phs) {
14597 this.placeholders.set(key, values);
14598 return;
14599 }
14600 // try to find matching template...
14601 const tmplIdx = findIndex(phs, findTemplateFn(context.id, context.templateIndex));
14602 if (tmplIdx >= 0) {
14603 // ... if found - replace it with nested template content
14604 const isCloseTag = key.startsWith('CLOSE');
14605 const isTemplateTag = key.endsWith('NG-TEMPLATE');
14606 if (isTemplateTag) {
14607 // current template's content is placed before or after
14608 // parent template tag, depending on the open/close atrribute
14609 phs.splice(tmplIdx + (isCloseTag ? 0 : 1), 0, ...values);
14610 }
14611 else {
14612 const idx = isCloseTag ? values.length - 1 : 0;
14613 values[idx].tmpl = phs[tmplIdx];
14614 phs.splice(tmplIdx, 1, ...values);
14615 }
14616 }
14617 else {
14618 // ... otherwise just append content to placeholder value
14619 phs.push(...values);
14620 }
14621 this.placeholders.set(key, phs);
14622 });
14623 this._unresolvedCtxCount--;
14624 }
14625}
14626//
14627// Helper methods
14628//
14629function wrap(symbol, index, contextId, closed) {
14630 const state = closed ? '/' : '';
14631 return wrapI18nPlaceholder(`${state}${symbol}${index}`, contextId);
14632}
14633function wrapTag(symbol, { index, ctx, isVoid }, closed) {
14634 return isVoid ? wrap(symbol, index, ctx) + wrap(symbol, index, ctx, true) :
14635 wrap(symbol, index, ctx, closed);
14636}
14637function findTemplateFn(ctx, templateIndex) {
14638 return (token) => typeof token === 'object' && token.type === TagType.TEMPLATE &&
14639 token.index === templateIndex && token.ctx === ctx;
14640}
14641function serializePlaceholderValue(value) {
14642 const element = (data, closed) => wrapTag('#', data, closed);
14643 const template = (data, closed) => wrapTag('*', data, closed);
14644 const projection = (data, closed) => wrapTag('!', data, closed);
14645 switch (value.type) {
14646 case TagType.ELEMENT:
14647 // close element tag
14648 if (value.closed) {
14649 return element(value, true) + (value.tmpl ? template(value.tmpl, true) : '');
14650 }
14651 // open element tag that also initiates a template
14652 if (value.tmpl) {
14653 return template(value.tmpl) + element(value) +
14654 (value.isVoid ? template(value.tmpl, true) : '');
14655 }
14656 return element(value);
14657 case TagType.TEMPLATE:
14658 return template(value, value.closed);
14659 case TagType.PROJECTION:
14660 return projection(value, value.closed);
14661 default:
14662 return value;
14663 }
14664}
14665
14666/**
14667 * @license
14668 * Copyright Google Inc. All Rights Reserved.
14669 *
14670 * Use of this source code is governed by an MIT-style license that can be
14671 * found in the LICENSE file at https://angular.io/license
14672 */
14673const TAG_TO_PLACEHOLDER_NAMES = {
14674 'A': 'LINK',
14675 'B': 'BOLD_TEXT',
14676 'BR': 'LINE_BREAK',
14677 'EM': 'EMPHASISED_TEXT',
14678 'H1': 'HEADING_LEVEL1',
14679 'H2': 'HEADING_LEVEL2',
14680 'H3': 'HEADING_LEVEL3',
14681 'H4': 'HEADING_LEVEL4',
14682 'H5': 'HEADING_LEVEL5',
14683 'H6': 'HEADING_LEVEL6',
14684 'HR': 'HORIZONTAL_RULE',
14685 'I': 'ITALIC_TEXT',
14686 'LI': 'LIST_ITEM',
14687 'LINK': 'MEDIA_LINK',
14688 'OL': 'ORDERED_LIST',
14689 'P': 'PARAGRAPH',
14690 'Q': 'QUOTATION',
14691 'S': 'STRIKETHROUGH_TEXT',
14692 'SMALL': 'SMALL_TEXT',
14693 'SUB': 'SUBSTRIPT',
14694 'SUP': 'SUPERSCRIPT',
14695 'TBODY': 'TABLE_BODY',
14696 'TD': 'TABLE_CELL',
14697 'TFOOT': 'TABLE_FOOTER',
14698 'TH': 'TABLE_HEADER_CELL',
14699 'THEAD': 'TABLE_HEADER',
14700 'TR': 'TABLE_ROW',
14701 'TT': 'MONOSPACED_TEXT',
14702 'U': 'UNDERLINED_TEXT',
14703 'UL': 'UNORDERED_LIST',
14704};
14705/**
14706 * Creates unique names for placeholder with different content.
14707 *
14708 * Returns the same placeholder name when the content is identical.
14709 */
14710class PlaceholderRegistry {
14711 constructor() {
14712 // Count the occurrence of the base name top generate a unique name
14713 this._placeHolderNameCounts = {};
14714 // Maps signature to placeholder names
14715 this._signatureToName = {};
14716 }
14717 getStartTagPlaceholderName(tag, attrs, isVoid) {
14718 const signature = this._hashTag(tag, attrs, isVoid);
14719 if (this._signatureToName[signature]) {
14720 return this._signatureToName[signature];
14721 }
14722 const upperTag = tag.toUpperCase();
14723 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
14724 const name = this._generateUniqueName(isVoid ? baseName : `START_${baseName}`);
14725 this._signatureToName[signature] = name;
14726 return name;
14727 }
14728 getCloseTagPlaceholderName(tag) {
14729 const signature = this._hashClosingTag(tag);
14730 if (this._signatureToName[signature]) {
14731 return this._signatureToName[signature];
14732 }
14733 const upperTag = tag.toUpperCase();
14734 const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
14735 const name = this._generateUniqueName(`CLOSE_${baseName}`);
14736 this._signatureToName[signature] = name;
14737 return name;
14738 }
14739 getPlaceholderName(name, content) {
14740 const upperName = name.toUpperCase();
14741 const signature = `PH: ${upperName}=${content}`;
14742 if (this._signatureToName[signature]) {
14743 return this._signatureToName[signature];
14744 }
14745 const uniqueName = this._generateUniqueName(upperName);
14746 this._signatureToName[signature] = uniqueName;
14747 return uniqueName;
14748 }
14749 getUniquePlaceholder(name) {
14750 return this._generateUniqueName(name.toUpperCase());
14751 }
14752 // Generate a hash for a tag - does not take attribute order into account
14753 _hashTag(tag, attrs, isVoid) {
14754 const start = `<${tag}`;
14755 const strAttrs = Object.keys(attrs).sort().map((name) => ` ${name}=${attrs[name]}`).join('');
14756 const end = isVoid ? '/>' : `></${tag}>`;
14757 return start + strAttrs + end;
14758 }
14759 _hashClosingTag(tag) { return this._hashTag(`/${tag}`, {}, false); }
14760 _generateUniqueName(base) {
14761 const seen = this._placeHolderNameCounts.hasOwnProperty(base);
14762 if (!seen) {
14763 this._placeHolderNameCounts[base] = 1;
14764 return base;
14765 }
14766 const id = this._placeHolderNameCounts[base];
14767 this._placeHolderNameCounts[base] = id + 1;
14768 return `${base}_${id}`;
14769 }
14770}
14771
14772/**
14773 * @license
14774 * Copyright Google Inc. All Rights Reserved.
14775 *
14776 * Use of this source code is governed by an MIT-style license that can be
14777 * found in the LICENSE file at https://angular.io/license
14778 */
14779const _expParser = new Parser$1(new Lexer());
14780/**
14781 * Returns a function converting html nodes to an i18n Message given an interpolationConfig
14782 */
14783function createI18nMessageFactory(interpolationConfig) {
14784 const visitor = new _I18nVisitor(_expParser, interpolationConfig);
14785 return (nodes, meaning, description, id, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, id, visitNodeFn);
14786}
14787class _I18nVisitor {
14788 constructor(_expressionParser, _interpolationConfig) {
14789 this._expressionParser = _expressionParser;
14790 this._interpolationConfig = _interpolationConfig;
14791 }
14792 toI18nMessage(nodes, meaning, description, id, visitNodeFn) {
14793 this._isIcu = nodes.length == 1 && nodes[0] instanceof Expansion;
14794 this._icuDepth = 0;
14795 this._placeholderRegistry = new PlaceholderRegistry();
14796 this._placeholderToContent = {};
14797 this._placeholderToMessage = {};
14798 this._visitNodeFn = visitNodeFn;
14799 const i18nodes = visitAll$1(this, nodes, {});
14800 return new Message(i18nodes, this._placeholderToContent, this._placeholderToMessage, meaning, description, id);
14801 }
14802 _visitNode(html, i18n) {
14803 if (this._visitNodeFn) {
14804 this._visitNodeFn(html, i18n);
14805 }
14806 return i18n;
14807 }
14808 visitElement(el, context) {
14809 const children = visitAll$1(this, el.children);
14810 const attrs = {};
14811 el.attrs.forEach(attr => {
14812 // Do not visit the attributes, translatable ones are top-level ASTs
14813 attrs[attr.name] = attr.value;
14814 });
14815 const isVoid = getHtmlTagDefinition(el.name).isVoid;
14816 const startPhName = this._placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
14817 this._placeholderToContent[startPhName] = el.sourceSpan.toString();
14818 let closePhName = '';
14819 if (!isVoid) {
14820 closePhName = this._placeholderRegistry.getCloseTagPlaceholderName(el.name);
14821 this._placeholderToContent[closePhName] = `</${el.name}>`;
14822 }
14823 const node = new TagPlaceholder(el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan);
14824 return this._visitNode(el, node);
14825 }
14826 visitAttribute(attribute, context) {
14827 const node = this._visitTextWithInterpolation(attribute.value, attribute.sourceSpan);
14828 return this._visitNode(attribute, node);
14829 }
14830 visitText(text, context) {
14831 const node = this._visitTextWithInterpolation(text.value, text.sourceSpan);
14832 return this._visitNode(text, node);
14833 }
14834 visitComment(comment, context) { return null; }
14835 visitExpansion(icu, context) {
14836 this._icuDepth++;
14837 const i18nIcuCases = {};
14838 const i18nIcu = new Icu$1(icu.switchValue, icu.type, i18nIcuCases, icu.sourceSpan);
14839 icu.cases.forEach((caze) => {
14840 i18nIcuCases[caze.value] = new Container(caze.expression.map((node) => node.visit(this, {})), caze.expSourceSpan);
14841 });
14842 this._icuDepth--;
14843 if (this._isIcu || this._icuDepth > 0) {
14844 // Returns an ICU node when:
14845 // - the message (vs a part of the message) is an ICU message, or
14846 // - the ICU message is nested.
14847 const expPh = this._placeholderRegistry.getUniquePlaceholder(`VAR_${icu.type}`);
14848 i18nIcu.expressionPlaceholder = expPh;
14849 this._placeholderToContent[expPh] = icu.switchValue;
14850 return this._visitNode(icu, i18nIcu);
14851 }
14852 // Else returns a placeholder
14853 // ICU placeholders should not be replaced with their original content but with the their
14854 // translations. We need to create a new visitor (they are not re-entrant) to compute the
14855 // message id.
14856 // TODO(vicb): add a html.Node -> i18n.Message cache to avoid having to re-create the msg
14857 const phName = this._placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
14858 const visitor = new _I18nVisitor(this._expressionParser, this._interpolationConfig);
14859 this._placeholderToMessage[phName] = visitor.toI18nMessage([icu], '', '', '');
14860 const node = new IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
14861 return this._visitNode(icu, node);
14862 }
14863 visitExpansionCase(icuCase, context) {
14864 throw new Error('Unreachable code');
14865 }
14866 _visitTextWithInterpolation(text, sourceSpan) {
14867 const splitInterpolation = this._expressionParser.splitInterpolation(text, sourceSpan.start.toString(), this._interpolationConfig);
14868 if (!splitInterpolation) {
14869 // No expression, return a single text
14870 return new Text$1(text, sourceSpan);
14871 }
14872 // Return a group of text + expressions
14873 const nodes = [];
14874 const container = new Container(nodes, sourceSpan);
14875 const { start: sDelimiter, end: eDelimiter } = this._interpolationConfig;
14876 for (let i = 0; i < splitInterpolation.strings.length - 1; i++) {
14877 const expression = splitInterpolation.expressions[i];
14878 const baseName = _extractPlaceholderName(expression) || 'INTERPOLATION';
14879 const phName = this._placeholderRegistry.getPlaceholderName(baseName, expression);
14880 if (splitInterpolation.strings[i].length) {
14881 // No need to add empty strings
14882 nodes.push(new Text$1(splitInterpolation.strings[i], sourceSpan));
14883 }
14884 nodes.push(new Placeholder(expression, phName, sourceSpan));
14885 this._placeholderToContent[phName] = sDelimiter + expression + eDelimiter;
14886 }
14887 // The last index contains no expression
14888 const lastStringIdx = splitInterpolation.strings.length - 1;
14889 if (splitInterpolation.strings[lastStringIdx].length) {
14890 nodes.push(new Text$1(splitInterpolation.strings[lastStringIdx], sourceSpan));
14891 }
14892 return container;
14893 }
14894}
14895const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
14896function _extractPlaceholderName(input) {
14897 return input.split(_CUSTOM_PH_EXP)[2];
14898}
14899
14900/**
14901 * @license
14902 * Copyright Google Inc. All Rights Reserved.
14903 *
14904 * Use of this source code is governed by an MIT-style license that can be
14905 * found in the LICENSE file at https://angular.io/license
14906 */
14907function setI18nRefs(html, i18n) {
14908 html.i18n = i18n;
14909}
14910/**
14911 * This visitor walks over HTML parse tree and converts information stored in
14912 * i18n-related attributes ("i18n" and "i18n-*") into i18n meta object that is
14913 * stored with other element's and attribute's information.
14914 */
14915class I18nMetaVisitor {
14916 constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false) {
14917 this.interpolationConfig = interpolationConfig;
14918 this.keepI18nAttrs = keepI18nAttrs;
14919 // i18n message generation factory
14920 this._createI18nMessage = createI18nMessageFactory(interpolationConfig);
14921 }
14922 _generateI18nMessage(nodes, meta = '', visitNodeFn) {
14923 const parsed = typeof meta === 'string' ? parseI18nMeta(meta) : metaFromI18nMessage(meta);
14924 const message = this._createI18nMessage(nodes, parsed.meaning || '', parsed.description || '', parsed.id || '', visitNodeFn);
14925 if (!message.id) {
14926 // generate (or restore) message id if not specified in template
14927 message.id = typeof meta !== 'string' && meta.id || decimalDigest(message);
14928 }
14929 return message;
14930 }
14931 visitElement(element, context) {
14932 if (hasI18nAttrs(element)) {
14933 const attrs = [];
14934 const attrsMeta = {};
14935 for (const attr of element.attrs) {
14936 if (attr.name === I18N_ATTR) {
14937 // root 'i18n' node attribute
14938 const i18n = element.i18n || attr.value;
14939 const message = this._generateI18nMessage(element.children, i18n, setI18nRefs);
14940 // do not assign empty i18n meta
14941 if (message.nodes.length) {
14942 element.i18n = message;
14943 }
14944 }
14945 else if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
14946 // 'i18n-*' attributes
14947 const key = attr.name.slice(I18N_ATTR_PREFIX.length);
14948 attrsMeta[key] = attr.value;
14949 }
14950 else {
14951 // non-i18n attributes
14952 attrs.push(attr);
14953 }
14954 }
14955 // set i18n meta for attributes
14956 if (Object.keys(attrsMeta).length) {
14957 for (const attr of attrs) {
14958 const meta = attrsMeta[attr.name];
14959 // do not create translation for empty attributes
14960 if (meta !== undefined && attr.value) {
14961 attr.i18n = this._generateI18nMessage([attr], attr.i18n || meta);
14962 }
14963 }
14964 }
14965 if (!this.keepI18nAttrs) {
14966 // update element's attributes,
14967 // keeping only non-i18n related ones
14968 element.attrs = attrs;
14969 }
14970 }
14971 visitAll$1(this, element.children);
14972 return element;
14973 }
14974 visitExpansion(expansion, context) {
14975 let message;
14976 const meta = expansion.i18n;
14977 if (meta instanceof IcuPlaceholder) {
14978 // set ICU placeholder name (e.g. "ICU_1"),
14979 // generated while processing root element contents,
14980 // so we can reference it when we output translation
14981 const name = meta.name;
14982 message = this._generateI18nMessage([expansion], meta);
14983 const icu = icuFromI18nMessage(message);
14984 icu.name = name;
14985 }
14986 else {
14987 // when ICU is a root level translation
14988 message = this._generateI18nMessage([expansion], meta);
14989 }
14990 expansion.i18n = message;
14991 return expansion;
14992 }
14993 visitText(text, context) { return text; }
14994 visitAttribute(attribute, context) { return attribute; }
14995 visitComment(comment, context) { return comment; }
14996 visitExpansionCase(expansionCase, context) { return expansionCase; }
14997}
14998function processI18nMeta(htmlAstWithErrors, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
14999 return new ParseTreeResult(visitAll$1(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors);
15000}
15001
15002/**
15003 * @license
15004 * Copyright Google Inc. All Rights Reserved.
15005 *
15006 * Use of this source code is governed by an MIT-style license that can be
15007 * found in the LICENSE file at https://angular.io/license
15008 */
15009/**
15010 * This visitor walks over i18n tree and generates its string representation, including ICUs and
15011 * placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format.
15012 */
15013class SerializerVisitor {
15014 constructor() {
15015 /**
15016 * Keeps track of ICU nesting level, allowing to detect that we are processing elements of an ICU.
15017 *
15018 * This is needed due to the fact that placeholders in ICUs and in other messages are represented
15019 * differently in Closure:
15020 * - {$placeholder} in non-ICU case
15021 * - {PLACEHOLDER} inside ICU
15022 */
15023 this.icuNestingLevel = 0;
15024 }
15025 formatPh(value) {
15026 const isInsideIcu = this.icuNestingLevel > 0;
15027 const formatted = formatI18nPlaceholderName(value, /* useCamelCase */ !isInsideIcu);
15028 return isInsideIcu ? `{${formatted}}` : `{$${formatted}}`;
15029 }
15030 visitText(text, context) { return text.value; }
15031 visitContainer(container, context) {
15032 return container.children.map(child => child.visit(this)).join('');
15033 }
15034 visitIcu(icu, context) {
15035 this.icuNestingLevel++;
15036 const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`);
15037 const result = `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`;
15038 this.icuNestingLevel--;
15039 return result;
15040 }
15041 visitTagPlaceholder(ph, context) {
15042 return ph.isVoid ?
15043 this.formatPh(ph.startName) :
15044 `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
15045 }
15046 visitPlaceholder(ph, context) { return this.formatPh(ph.name); }
15047 visitIcuPlaceholder(ph, context) {
15048 return this.formatPh(ph.name);
15049 }
15050}
15051const serializerVisitor$1 = new SerializerVisitor();
15052function getSerializedI18nContent(message) {
15053 return message.nodes.map(node => node.visit(serializerVisitor$1, null)).join('');
15054}
15055
15056/**
15057 * @license
15058 * Copyright Google Inc. All Rights Reserved.
15059 *
15060 * Use of this source code is governed by an MIT-style license that can be
15061 * found in the LICENSE file at https://angular.io/license
15062 */
15063// Selector attribute name of `<ng-content>`
15064const NG_CONTENT_SELECT_ATTR$1 = 'select';
15065// Attribute name of `ngProjectAs`.
15066const NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs';
15067// List of supported global targets for event listeners
15068const GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers$1.resolveWindow], ['document', Identifiers$1.resolveDocument], ['body', Identifiers$1.resolveBody]]);
15069const LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t'];
15070// if (rf & flags) { .. }
15071function renderFlagCheckIfStmt(flags, statements) {
15072 return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null, false), statements);
15073}
15074function prepareEventListenerParameters(eventAst, handlerName = null, scope = null) {
15075 const { type, name, target, phase, handler } = eventAst;
15076 if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) {
15077 throw new Error(`Unexpected global target '${target}' defined for '${name}' event.
15078 Supported list of global targets: ${Array.from(GLOBAL_TARGET_RESOLVERS.keys())}.`);
15079 }
15080 const implicitReceiverExpr = (scope === null || scope.bindingLevel === 0) ?
15081 variable(CONTEXT_NAME) :
15082 scope.getOrCreateSharedContextVar(0);
15083 const bindingExpr = convertActionBinding(scope, implicitReceiverExpr, handler, 'b', () => error('Unexpected interpolation'), eventAst.handlerSpan);
15084 const statements = [];
15085 if (scope) {
15086 statements.push(...scope.restoreViewStatement());
15087 statements.push(...scope.variableDeclarations());
15088 }
15089 statements.push(...bindingExpr.render3Stmts);
15090 const eventName = type === 1 /* Animation */ ? prepareSyntheticListenerName(name, phase) : name;
15091 const fnName = handlerName && sanitizeIdentifier(handlerName);
15092 const fnArgs = [new FnParam('$event', DYNAMIC_TYPE)];
15093 const handlerFn = fn(fnArgs, statements, INFERRED_TYPE, null, fnName);
15094 const params = [literal(eventName), handlerFn];
15095 if (target) {
15096 params.push(literal(false), // `useCapture` flag, defaults to `false`
15097 importExpr(GLOBAL_TARGET_RESOLVERS.get(target)));
15098 }
15099 return params;
15100}
15101class TemplateDefinitionBuilder {
15102 constructor(constantPool, parentBindingScope, level = 0, contextName, i18nContext, templateIndex, templateName, directiveMatcher, directives, pipeTypeByName, pipes, _namespace, relativeContextFilePath, i18nUseExternalIds) {
15103 this.constantPool = constantPool;
15104 this.level = level;
15105 this.contextName = contextName;
15106 this.i18nContext = i18nContext;
15107 this.templateIndex = templateIndex;
15108 this.templateName = templateName;
15109 this.directiveMatcher = directiveMatcher;
15110 this.directives = directives;
15111 this.pipeTypeByName = pipeTypeByName;
15112 this.pipes = pipes;
15113 this._namespace = _namespace;
15114 this.relativeContextFilePath = relativeContextFilePath;
15115 this.i18nUseExternalIds = i18nUseExternalIds;
15116 this._dataIndex = 0;
15117 this._bindingContext = 0;
15118 this._prefixCode = [];
15119 /**
15120 * List of callbacks to generate creation mode instructions. We store them here as we process
15121 * the template so bindings in listeners are resolved only once all nodes have been visited.
15122 * This ensures all local refs and context variables are available for matching.
15123 */
15124 this._creationCodeFns = [];
15125 /**
15126 * List of callbacks to generate update mode instructions. We store them here as we process
15127 * the template so bindings are resolved only once all nodes have been visited. This ensures
15128 * all local refs and context variables are available for matching.
15129 */
15130 this._updateCodeFns = [];
15131 /**
15132 * Memorizes the last node index for which a select instruction has been generated.
15133 * We're initializing this to -1 to ensure the `select(0)` instruction is generated before any
15134 * relevant update instructions.
15135 */
15136 this._lastNodeIndexWithFlush = -1;
15137 /** Temporary variable declarations generated from visiting pipes, literals, etc. */
15138 this._tempVariables = [];
15139 /**
15140 * List of callbacks to build nested templates. Nested templates must not be visited until
15141 * after the parent template has finished visiting all of its nodes. This ensures that all
15142 * local ref bindings in nested templates are able to find local ref values if the refs
15143 * are defined after the template declaration.
15144 */
15145 this._nestedTemplateFns = [];
15146 this._unsupported = unsupported;
15147 // i18n context local to this template
15148 this.i18n = null;
15149 // Number of slots to reserve for pureFunctions
15150 this._pureFunctionSlots = 0;
15151 // Number of binding slots
15152 this._bindingSlots = 0;
15153 // Projection slots found in the template. Projection slots can distribute projected
15154 // nodes based on a selector, or can just use the wildcard selector to match
15155 // all nodes which aren't matching any selector.
15156 this._ngContentReservedSlots = [];
15157 // Number of non-default selectors found in all parent templates of this template. We need to
15158 // track it to properly adjust projection slot index in the `projection` instruction.
15159 this._ngContentSelectorsOffset = 0;
15160 // Expression that should be used as implicit receiver when converting template
15161 // expressions to output AST.
15162 this._implicitReceiverExpr = null;
15163 // These should be handled in the template or element directly.
15164 this.visitReference = invalid$1;
15165 this.visitVariable = invalid$1;
15166 this.visitTextAttribute = invalid$1;
15167 this.visitBoundAttribute = invalid$1;
15168 this.visitBoundEvent = invalid$1;
15169 this._bindingScope = parentBindingScope.nestedScope(level);
15170 // Turn the relative context file path into an identifier by replacing non-alphanumeric
15171 // characters with underscores.
15172 this.fileBasedI18nSuffix = relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_') + '_';
15173 this._valueConverter = new ValueConverter(constantPool, () => this.allocateDataSlot(), (numSlots) => this.allocatePureFunctionSlots(numSlots), (name, localName, slot, value) => {
15174 const pipeType = pipeTypeByName.get(name);
15175 if (pipeType) {
15176 this.pipes.add(pipeType);
15177 }
15178 this._bindingScope.set(this.level, localName, value);
15179 this.creationInstruction(null, Identifiers$1.pipe, [literal(slot), literal(name)]);
15180 });
15181 }
15182 registerContextVariables(variable$1) {
15183 const scopedName = this._bindingScope.freshReferenceName();
15184 const retrievalLevel = this.level;
15185 const lhs = variable(variable$1.name + scopedName);
15186 this._bindingScope.set(retrievalLevel, variable$1.name, lhs, 1 /* CONTEXT */, (scope, relativeLevel) => {
15187 let rhs;
15188 if (scope.bindingLevel === retrievalLevel) {
15189 // e.g. ctx
15190 rhs = variable(CONTEXT_NAME);
15191 }
15192 else {
15193 const sharedCtxVar = scope.getSharedContextName(retrievalLevel);
15194 // e.g. ctx_r0 OR x(2);
15195 rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel);
15196 }
15197 // e.g. const $item$ = x(2).$implicit;
15198 return [lhs.set(rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()];
15199 });
15200 }
15201 buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n) {
15202 this._ngContentSelectorsOffset = ngContentSelectorsOffset;
15203 if (this._namespace !== Identifiers$1.namespaceHTML) {
15204 this.creationInstruction(null, this._namespace);
15205 }
15206 // Create variable bindings
15207 variables.forEach(v => this.registerContextVariables(v));
15208 // Initiate i18n context in case:
15209 // - this template has parent i18n context
15210 // - or the template has i18n meta associated with it,
15211 // but it's not initiated by the Element (e.g. <ng-template i18n>)
15212 const initI18nContext = this.i18nContext || (isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) &&
15213 !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n));
15214 const selfClosingI18nInstruction = hasTextChildrenOnly(nodes);
15215 if (initI18nContext) {
15216 this.i18nStart(null, i18n, selfClosingI18nInstruction);
15217 }
15218 // This is the initial pass through the nodes of this template. In this pass, we
15219 // queue all creation mode and update mode instructions for generation in the second
15220 // pass. It's necessary to separate the passes to ensure local refs are defined before
15221 // resolving bindings. We also count bindings in this pass as we walk bound expressions.
15222 visitAll(this, nodes);
15223 // Add total binding count to pure function count so pure function instructions are
15224 // generated with the correct slot offset when update instructions are processed.
15225 this._pureFunctionSlots += this._bindingSlots;
15226 // Pipes are walked in the first pass (to enqueue `pipe()` creation instructions and
15227 // `pipeBind` update instructions), so we have to update the slot offsets manually
15228 // to account for bindings.
15229 this._valueConverter.updatePipeSlotOffsets(this._bindingSlots);
15230 // Nested templates must be processed before creation instructions so template()
15231 // instructions can be generated with the correct internal const count.
15232 this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn());
15233 // Output the `projectionDef` instruction when some `<ng-content>` tags are present.
15234 // The `projectionDef` instruction is only emitted for the component template and
15235 // is skipped for nested templates (<ng-template> tags).
15236 if (this.level === 0 && this._ngContentReservedSlots.length) {
15237 const parameters = [];
15238 // By default the `projectionDef` instructions creates one slot for the wildcard
15239 // selector if no parameters are passed. Therefore we only want to allocate a new
15240 // array for the projection slots if the default projection slot is not sufficient.
15241 if (this._ngContentReservedSlots.length > 1 || this._ngContentReservedSlots[0] !== '*') {
15242 const r3ReservedSlots = this._ngContentReservedSlots.map(s => s !== '*' ? parseSelectorToR3Selector(s) : s);
15243 parameters.push(this.constantPool.getConstLiteral(asLiteral(r3ReservedSlots), true));
15244 }
15245 // Since we accumulate ngContent selectors while processing template elements,
15246 // we *prepend* `projectionDef` to creation instructions block, to put it before
15247 // any `projection` instructions
15248 this.creationInstruction(null, Identifiers$1.projectionDef, parameters, /* prepend */ true);
15249 }
15250 if (initI18nContext) {
15251 this.i18nEnd(null, selfClosingI18nInstruction);
15252 }
15253 // Generate all the creation mode instructions (e.g. resolve bindings in listeners)
15254 const creationStatements = this._creationCodeFns.map((fn) => fn());
15255 // Generate all the update mode instructions (e.g. resolve property or text bindings)
15256 const updateStatements = this._updateCodeFns.map((fn) => fn());
15257 // Variable declaration must occur after binding resolution so we can generate context
15258 // instructions that build on each other.
15259 // e.g. const b = nextContext().$implicit(); const b = nextContext();
15260 const creationVariables = this._bindingScope.viewSnapshotStatements();
15261 const updateVariables = this._bindingScope.variableDeclarations().concat(this._tempVariables);
15262 const creationBlock = creationStatements.length > 0 ?
15263 [renderFlagCheckIfStmt(1 /* Create */, creationVariables.concat(creationStatements))] :
15264 [];
15265 const updateBlock = updateStatements.length > 0 ?
15266 [renderFlagCheckIfStmt(2 /* Update */, updateVariables.concat(updateStatements))] :
15267 [];
15268 return fn(
15269 // i.e. (rf: RenderFlags, ctx: any)
15270 [new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
15271 // Temporary variable declarations for query refresh (i.e. let _t: any;)
15272 ...this._prefixCode,
15273 // Creating mode (i.e. if (rf & RenderFlags.Create) { ... })
15274 ...creationBlock,
15275 // Binding and refresh mode (i.e. if (rf & RenderFlags.Update) {...})
15276 ...updateBlock,
15277 ], INFERRED_TYPE, null, this.templateName);
15278 }
15279 // LocalResolver
15280 getLocal(name) { return this._bindingScope.get(name); }
15281 // LocalResolver
15282 notifyImplicitReceiverUse() { this._bindingScope.notifyImplicitReceiverUse(); }
15283 i18nTranslate(message, params = {}, ref, transformFn) {
15284 const _ref = ref || variable(this.constantPool.uniqueName(TRANSLATION_PREFIX));
15285 // Closure Compiler requires const names to start with `MSG_` but disallows any other const to
15286 // start with `MSG_`. We define a variable starting with `MSG_` just for the `goog.getMsg` call
15287 const closureVar = this.i18nGenerateClosureVar(message.id);
15288 const formattedParams = this.i18nFormatPlaceholderNames(params, /* useCamelCase */ true);
15289 const meta = metaFromI18nMessage(message);
15290 const content = getSerializedI18nContent(message);
15291 const statements = getTranslationDeclStmts(_ref, closureVar, content, meta, formattedParams, transformFn);
15292 this.constantPool.statements.push(...statements);
15293 return _ref;
15294 }
15295 i18nFormatPlaceholderNames(params = {}, useCamelCase) {
15296 const _params = {};
15297 if (params && Object.keys(params).length) {
15298 Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key, useCamelCase)] = params[key]);
15299 }
15300 return _params;
15301 }
15302 i18nAppendBindings(expressions) {
15303 if (expressions.length > 0) {
15304 expressions.forEach(expression => this.i18n.appendBinding(expression));
15305 }
15306 }
15307 i18nBindProps(props) {
15308 const bound = {};
15309 Object.keys(props).forEach(key => {
15310 const prop = props[key];
15311 if (prop instanceof Text) {
15312 bound[key] = literal(prop.value);
15313 }
15314 else {
15315 const value = prop.value.visit(this._valueConverter);
15316 this.allocateBindingSlots(value);
15317 if (value instanceof Interpolation) {
15318 const { strings, expressions } = value;
15319 const { id, bindings } = this.i18n;
15320 const label = assembleI18nBoundString(strings, bindings.size, id);
15321 this.i18nAppendBindings(expressions);
15322 bound[key] = literal(label);
15323 }
15324 }
15325 });
15326 return bound;
15327 }
15328 i18nGenerateClosureVar(messageId) {
15329 let name;
15330 const suffix = this.fileBasedI18nSuffix.toUpperCase();
15331 if (this.i18nUseExternalIds) {
15332 const prefix = getTranslationConstPrefix(`EXTERNAL_`);
15333 const uniqueSuffix = this.constantPool.uniqueName(suffix);
15334 name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`;
15335 }
15336 else {
15337 const prefix = getTranslationConstPrefix(suffix);
15338 name = this.constantPool.uniqueName(prefix);
15339 }
15340 return variable(name);
15341 }
15342 i18nUpdateRef(context) {
15343 const { icus, meta, isRoot, isResolved, isEmitted } = context;
15344 if (isRoot && isResolved && !isEmitted && !isSingleI18nIcu(meta)) {
15345 context.isEmitted = true;
15346 const placeholders = context.getSerializedPlaceholders();
15347 let icuMapping = {};
15348 let params = placeholders.size ? placeholdersToParams(placeholders) : {};
15349 if (icus.size) {
15350 icus.forEach((refs, key) => {
15351 if (refs.length === 1) {
15352 // if we have one ICU defined for a given
15353 // placeholder - just output its reference
15354 params[key] = refs[0];
15355 }
15356 else {
15357 // ... otherwise we need to activate post-processing
15358 // to replace ICU placeholders with proper values
15359 const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX}${key}`);
15360 params[key] = literal(placeholder);
15361 icuMapping[key] = literalArr(refs);
15362 }
15363 });
15364 }
15365 // translation requires post processing in 2 cases:
15366 // - if we have placeholders with multiple values (ex. `START_DIV`: [�#1�, �#2�, ...])
15367 // - if we have multiple ICUs that refer to the same placeholder name
15368 const needsPostprocessing = Array.from(placeholders.values()).some((value) => value.length > 1) ||
15369 Object.keys(icuMapping).length;
15370 let transformFn;
15371 if (needsPostprocessing) {
15372 transformFn = (raw) => {
15373 const args = [raw];
15374 if (Object.keys(icuMapping).length) {
15375 args.push(mapLiteral(icuMapping, true));
15376 }
15377 return instruction(null, Identifiers$1.i18nPostprocess, args);
15378 };
15379 }
15380 this.i18nTranslate(meta, params, context.ref, transformFn);
15381 }
15382 }
15383 i18nStart(span = null, meta, selfClosing) {
15384 const index = this.allocateDataSlot();
15385 if (this.i18nContext) {
15386 this.i18n = this.i18nContext.forkChildContext(index, this.templateIndex, meta);
15387 }
15388 else {
15389 const ref = variable(this.constantPool.uniqueName(TRANSLATION_PREFIX));
15390 this.i18n = new I18nContext(index, ref, 0, this.templateIndex, meta);
15391 }
15392 // generate i18nStart instruction
15393 const { id, ref } = this.i18n;
15394 const params = [literal(index), ref];
15395 if (id > 0) {
15396 // do not push 3rd argument (sub-block id)
15397 // into i18nStart call for top level i18n context
15398 params.push(literal(id));
15399 }
15400 this.creationInstruction(span, selfClosing ? Identifiers$1.i18n : Identifiers$1.i18nStart, params);
15401 }
15402 i18nEnd(span = null, selfClosing) {
15403 if (!this.i18n) {
15404 throw new Error('i18nEnd is executed with no i18n context present');
15405 }
15406 if (this.i18nContext) {
15407 this.i18nContext.reconcileChildContext(this.i18n);
15408 this.i18nUpdateRef(this.i18nContext);
15409 }
15410 else {
15411 this.i18nUpdateRef(this.i18n);
15412 }
15413 // setup accumulated bindings
15414 const { index, bindings } = this.i18n;
15415 if (bindings.size) {
15416 const chainBindings = [];
15417 bindings.forEach(binding => {
15418 chainBindings.push({ sourceSpan: span, value: () => this.convertPropertyBinding(binding) });
15419 });
15420 this.updateInstructionChain(index, Identifiers$1.i18nExp, chainBindings);
15421 this.updateInstruction(index, span, Identifiers$1.i18nApply, [literal(index)]);
15422 }
15423 if (!selfClosing) {
15424 this.creationInstruction(span, Identifiers$1.i18nEnd);
15425 }
15426 this.i18n = null; // reset local i18n context
15427 }
15428 visitContent(ngContent) {
15429 const slot = this.allocateDataSlot();
15430 const projectionSlotIdx = this._ngContentSelectorsOffset + this._ngContentReservedSlots.length;
15431 const parameters = [literal(slot)];
15432 const attributes = [];
15433 this._ngContentReservedSlots.push(ngContent.selector);
15434 ngContent.attributes.forEach((attribute) => {
15435 const { name, value } = attribute;
15436 if (name === NG_PROJECT_AS_ATTR_NAME) {
15437 attributes.push(...getNgProjectAsLiteral(attribute));
15438 }
15439 else if (name.toLowerCase() !== NG_CONTENT_SELECT_ATTR$1) {
15440 attributes.push(literal(name), literal(value));
15441 }
15442 });
15443 if (attributes.length > 0) {
15444 parameters.push(literal(projectionSlotIdx), literalArr(attributes));
15445 }
15446 else if (projectionSlotIdx !== 0) {
15447 parameters.push(literal(projectionSlotIdx));
15448 }
15449 this.creationInstruction(ngContent.sourceSpan, Identifiers$1.projection, parameters);
15450 if (this.i18n) {
15451 this.i18n.appendProjection(ngContent.i18n, slot);
15452 }
15453 }
15454 getNamespaceInstruction(namespaceKey) {
15455 switch (namespaceKey) {
15456 case 'math':
15457 return Identifiers$1.namespaceMathML;
15458 case 'svg':
15459 return Identifiers$1.namespaceSVG;
15460 default:
15461 return Identifiers$1.namespaceHTML;
15462 }
15463 }
15464 addNamespaceInstruction(nsInstruction, element) {
15465 this._namespace = nsInstruction;
15466 this.creationInstruction(element.sourceSpan, nsInstruction);
15467 }
15468 visitElement(element) {
15469 const elementIndex = this.allocateDataSlot();
15470 const stylingBuilder = new StylingBuilder(literal(elementIndex), null);
15471 let isNonBindableMode = false;
15472 const isI18nRootElement = isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n);
15473 if (isI18nRootElement && this.i18n) {
15474 throw new Error(`Could not mark an element as translatable inside of a translatable section`);
15475 }
15476 const i18nAttrs = [];
15477 const outputAttrs = [];
15478 const [namespaceKey, elementName] = splitNsName(element.name);
15479 const isNgContainer$1 = isNgContainer(element.name);
15480 // Handle styling, i18n, ngNonBindable attributes
15481 for (const attr of element.attributes) {
15482 const { name, value } = attr;
15483 if (name === NON_BINDABLE_ATTR) {
15484 isNonBindableMode = true;
15485 }
15486 else if (name === 'style') {
15487 stylingBuilder.registerStyleAttr(value);
15488 }
15489 else if (name === 'class') {
15490 stylingBuilder.registerClassAttr(value);
15491 }
15492 else {
15493 if (attr.i18n) {
15494 // Place attributes into a separate array for i18n processing, but also keep such
15495 // attributes in the main list to make them available for directive matching at runtime.
15496 // TODO(FW-1248): prevent attributes duplication in `i18nAttributes` and `elementStart`
15497 // arguments
15498 i18nAttrs.push(attr);
15499 }
15500 else {
15501 outputAttrs.push(attr);
15502 }
15503 }
15504 }
15505 // Match directives on non i18n attributes
15506 this.matchDirectives(element.name, element);
15507 // Regular element or ng-container creation mode
15508 const parameters = [literal(elementIndex)];
15509 if (!isNgContainer$1) {
15510 parameters.push(literal(elementName));
15511 }
15512 // Add the attributes
15513 const attributes = [];
15514 const allOtherInputs = [];
15515 element.inputs.forEach((input) => {
15516 const stylingInputWasSet = stylingBuilder.registerBoundInput(input);
15517 if (!stylingInputWasSet) {
15518 if (input.type === 0 /* Property */ && input.i18n) {
15519 // Place attributes into a separate array for i18n processing, but also keep such
15520 // attributes in the main list to make them available for directive matching at runtime.
15521 // TODO(FW-1248): prevent attributes duplication in `i18nAttributes` and `elementStart`
15522 // arguments
15523 i18nAttrs.push(input);
15524 }
15525 else {
15526 allOtherInputs.push(input);
15527 }
15528 }
15529 });
15530 outputAttrs.forEach(attr => {
15531 if (attr.name === NG_PROJECT_AS_ATTR_NAME) {
15532 attributes.push(...getNgProjectAsLiteral(attr));
15533 }
15534 else {
15535 attributes.push(...getAttributeNameLiterals(attr.name), literal(attr.value));
15536 }
15537 });
15538 // add attributes for directive and projection matching purposes
15539 attributes.push(...this.prepareNonRenderAttrs(allOtherInputs, element.outputs, stylingBuilder, [], i18nAttrs));
15540 parameters.push(this.toAttrsParam(attributes));
15541 // local refs (ex.: <div #foo #bar="baz">)
15542 parameters.push(this.prepareRefsParameter(element.references));
15543 const wasInNamespace = this._namespace;
15544 const currentNamespace = this.getNamespaceInstruction(namespaceKey);
15545 // If the namespace is changing now, include an instruction to change it
15546 // during element creation.
15547 if (currentNamespace !== wasInNamespace) {
15548 this.addNamespaceInstruction(currentNamespace, element);
15549 }
15550 if (this.i18n) {
15551 this.i18n.appendElement(element.i18n, elementIndex);
15552 }
15553 // Note that we do not append text node instructions and ICUs inside i18n section,
15554 // so we exclude them while calculating whether current element has children
15555 const hasChildren = (!isI18nRootElement && this.i18n) ? !hasTextChildrenOnly(element.children) :
15556 element.children.length > 0;
15557 const createSelfClosingInstruction = !stylingBuilder.hasBindings &&
15558 element.outputs.length === 0 && i18nAttrs.length === 0 && !hasChildren;
15559 const createSelfClosingI18nInstruction = !createSelfClosingInstruction &&
15560 !stylingBuilder.hasBindings && hasTextChildrenOnly(element.children);
15561 if (createSelfClosingInstruction) {
15562 this.creationInstruction(element.sourceSpan, isNgContainer$1 ? Identifiers$1.elementContainer : Identifiers$1.element, trimTrailingNulls(parameters));
15563 }
15564 else {
15565 this.creationInstruction(element.sourceSpan, isNgContainer$1 ? Identifiers$1.elementContainerStart : Identifiers$1.elementStart, trimTrailingNulls(parameters));
15566 if (isNonBindableMode) {
15567 this.creationInstruction(element.sourceSpan, Identifiers$1.disableBindings);
15568 }
15569 // process i18n element attributes
15570 if (i18nAttrs.length) {
15571 let hasBindings = false;
15572 const i18nAttrArgs = [];
15573 const bindings = [];
15574 i18nAttrs.forEach(attr => {
15575 const message = attr.i18n;
15576 if (attr instanceof TextAttribute) {
15577 i18nAttrArgs.push(literal(attr.name), this.i18nTranslate(message));
15578 }
15579 else {
15580 const converted = attr.value.visit(this._valueConverter);
15581 this.allocateBindingSlots(converted);
15582 if (converted instanceof Interpolation) {
15583 const placeholders = assembleBoundTextPlaceholders(message);
15584 const params = placeholdersToParams(placeholders);
15585 i18nAttrArgs.push(literal(attr.name), this.i18nTranslate(message, params));
15586 converted.expressions.forEach(expression => {
15587 hasBindings = true;
15588 bindings.push({
15589 sourceSpan: element.sourceSpan,
15590 value: () => this.convertExpressionBinding(expression)
15591 });
15592 });
15593 }
15594 }
15595 });
15596 if (bindings.length) {
15597 this.updateInstructionChain(elementIndex, Identifiers$1.i18nExp, bindings);
15598 }
15599 if (i18nAttrArgs.length) {
15600 const index = literal(this.allocateDataSlot());
15601 const args = this.constantPool.getConstLiteral(literalArr(i18nAttrArgs), true);
15602 this.creationInstruction(element.sourceSpan, Identifiers$1.i18nAttributes, [index, args]);
15603 if (hasBindings) {
15604 this.updateInstruction(elementIndex, element.sourceSpan, Identifiers$1.i18nApply, [index]);
15605 }
15606 }
15607 }
15608 // The style bindings code is placed into two distinct blocks within the template function AOT
15609 // code: creation and update. The creation code contains the `styling` instructions
15610 // which will apply the collected binding values to the element. `styling` is
15611 // designed to run inside of `elementStart` and `elementEnd`. The update instructions
15612 // (things like `styleProp`, `classProp`, etc..) are applied later on in this
15613 // file
15614 this.processStylingInstruction(elementIndex, stylingBuilder.buildStylingInstruction(element.sourceSpan, this.constantPool), true);
15615 // Generate Listeners (outputs)
15616 element.outputs.forEach((outputAst) => {
15617 this.creationInstruction(outputAst.sourceSpan, Identifiers$1.listener, this.prepareListenerParameter(element.name, outputAst, elementIndex));
15618 });
15619 // Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
15620 // listeners, to make sure i18nAttributes instruction targets current element at runtime.
15621 if (isI18nRootElement) {
15622 this.i18nStart(element.sourceSpan, element.i18n, createSelfClosingI18nInstruction);
15623 }
15624 }
15625 // the code here will collect all update-level styling instructions and add them to the
15626 // update block of the template function AOT code. Instructions like `styleProp`,
15627 // `styleMap`, `classMap`, `classProp` and `stylingApply`
15628 // are all generated and assigned in the code below.
15629 const stylingInstructions = stylingBuilder.buildUpdateLevelInstructions(this._valueConverter);
15630 const limit = stylingInstructions.length - 1;
15631 for (let i = 0; i <= limit; i++) {
15632 const instruction = stylingInstructions[i];
15633 this._bindingSlots += instruction.allocateBindingSlots;
15634 this.processStylingInstruction(elementIndex, instruction, false);
15635 }
15636 // the reason why `undefined` is used is because the renderer understands this as a
15637 // special value to symbolize that there is no RHS to this binding
15638 // TODO (matsko): revisit this once FW-959 is approached
15639 const emptyValueBindInstruction = literal(undefined);
15640 const propertyBindings = [];
15641 const attributeBindings = [];
15642 // Generate element input bindings
15643 allOtherInputs.forEach((input) => {
15644 const inputType = input.type;
15645 if (inputType === 4 /* Animation */) {
15646 const value = input.value.visit(this._valueConverter);
15647 // animation bindings can be presented in the following formats:
15648 // 1. [@binding]="fooExp"
15649 // 2. [@binding]="{value:fooExp, params:{...}}"
15650 // 3. [@binding]
15651 // 4. @binding
15652 // All formats will be valid for when a synthetic binding is created.
15653 // The reasoning for this is because the renderer should get each
15654 // synthetic binding value in the order of the array that they are
15655 // defined in...
15656 const hasValue = value instanceof LiteralPrimitive ? !!value.value : true;
15657 this.allocateBindingSlots(value);
15658 propertyBindings.push({
15659 name: prepareSyntheticPropertyName(input.name),
15660 sourceSpan: input.sourceSpan,
15661 value: () => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction
15662 });
15663 }
15664 else {
15665 // we must skip attributes with associated i18n context, since these attributes are handled
15666 // separately and corresponding `i18nExp` and `i18nApply` instructions will be generated
15667 if (input.i18n)
15668 return;
15669 const value = input.value.visit(this._valueConverter);
15670 if (value !== undefined) {
15671 const params = [];
15672 const [attrNamespace, attrName] = splitNsName(input.name);
15673 const isAttributeBinding = inputType === 1 /* Attribute */;
15674 const sanitizationRef = resolveSanitizationFn(input.securityContext, isAttributeBinding);
15675 if (sanitizationRef)
15676 params.push(sanitizationRef);
15677 if (attrNamespace) {
15678 const namespaceLiteral = literal(attrNamespace);
15679 if (sanitizationRef) {
15680 params.push(namespaceLiteral);
15681 }
15682 else {
15683 // If there wasn't a sanitization ref, we need to add
15684 // an extra param so that we can pass in the namespace.
15685 params.push(literal(null), namespaceLiteral);
15686 }
15687 }
15688 this.allocateBindingSlots(value);
15689 if (inputType === 0 /* Property */) {
15690 if (value instanceof Interpolation) {
15691 // prop="{{value}}" and friends
15692 this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), elementIndex, attrName, input, value, params);
15693 }
15694 else {
15695 // [prop]="value"
15696 // Collect all the properties so that we can chain into a single function at the end.
15697 propertyBindings.push({
15698 name: attrName,
15699 sourceSpan: input.sourceSpan,
15700 value: () => this.convertPropertyBinding(value), params
15701 });
15702 }
15703 }
15704 else if (inputType === 1 /* Attribute */) {
15705 if (value instanceof Interpolation && getInterpolationArgsLength(value) > 1) {
15706 // attr.name="text{{value}}" and friends
15707 this.interpolatedUpdateInstruction(getAttributeInterpolationExpression(value), elementIndex, attrName, input, value, params);
15708 }
15709 else {
15710 const boundValue = value instanceof Interpolation ? value.expressions[0] : value;
15711 // [attr.name]="value" or attr.name="{{value}}"
15712 // Collect the attribute bindings so that they can be chained at the end.
15713 attributeBindings.push({
15714 name: attrName,
15715 sourceSpan: input.sourceSpan,
15716 value: () => this.convertPropertyBinding(boundValue), params
15717 });
15718 }
15719 }
15720 else {
15721 // class prop
15722 this.updateInstruction(elementIndex, input.sourceSpan, Identifiers$1.classProp, () => {
15723 return [
15724 literal(elementIndex), literal(attrName), this.convertPropertyBinding(value),
15725 ...params
15726 ];
15727 });
15728 }
15729 }
15730 }
15731 });
15732 if (propertyBindings.length > 0) {
15733 this.updateInstructionChain(elementIndex, Identifiers$1.property, propertyBindings);
15734 }
15735 if (attributeBindings.length > 0) {
15736 this.updateInstructionChain(elementIndex, Identifiers$1.attribute, attributeBindings);
15737 }
15738 // Traverse element child nodes
15739 visitAll(this, element.children);
15740 if (!isI18nRootElement && this.i18n) {
15741 this.i18n.appendElement(element.i18n, elementIndex, true);
15742 }
15743 if (!createSelfClosingInstruction) {
15744 // Finish element construction mode.
15745 const span = element.endSourceSpan || element.sourceSpan;
15746 if (isI18nRootElement) {
15747 this.i18nEnd(span, createSelfClosingI18nInstruction);
15748 }
15749 if (isNonBindableMode) {
15750 this.creationInstruction(span, Identifiers$1.enableBindings);
15751 }
15752 this.creationInstruction(span, isNgContainer$1 ? Identifiers$1.elementContainerEnd : Identifiers$1.elementEnd);
15753 }
15754 }
15755 /**
15756 * Adds an update instruction for an interpolated property or attribute, such as
15757 * `prop="{{value}}"` or `attr.title="{{value}}"`
15758 */
15759 interpolatedUpdateInstruction(instruction, elementIndex, attrName, input, value, params) {
15760 this.updateInstruction(elementIndex, input.sourceSpan, instruction, () => [literal(attrName), ...this.getUpdateInstructionArguments(value), ...params]);
15761 }
15762 visitTemplate(template) {
15763 const NG_TEMPLATE_TAG_NAME = 'ng-template';
15764 const templateIndex = this.allocateDataSlot();
15765 if (this.i18n) {
15766 this.i18n.appendTemplate(template.i18n, templateIndex);
15767 }
15768 const tagName = sanitizeIdentifier(template.tagName || '');
15769 const contextName = `${this.contextName}${tagName ? '_' + tagName : ''}_${templateIndex}`;
15770 const templateName = `${contextName}_Template`;
15771 const parameters = [
15772 literal(templateIndex),
15773 variable(templateName),
15774 // We don't care about the tag's namespace here, because we infer
15775 // it based on the parent nodes inside the template instruction.
15776 literal(template.tagName ? splitNsName(template.tagName)[1] : template.tagName),
15777 ];
15778 // find directives matching on a given <ng-template> node
15779 this.matchDirectives(NG_TEMPLATE_TAG_NAME, template);
15780 // prepare attributes parameter (including attributes used for directive matching)
15781 const attrsExprs = [];
15782 template.attributes.forEach((a) => { attrsExprs.push(asLiteral(a.name), asLiteral(a.value)); });
15783 attrsExprs.push(...this.prepareNonRenderAttrs(template.inputs, template.outputs, undefined, template.templateAttrs));
15784 parameters.push(this.toAttrsParam(attrsExprs));
15785 // local refs (ex.: <ng-template #foo>)
15786 if (template.references && template.references.length) {
15787 parameters.push(this.prepareRefsParameter(template.references));
15788 parameters.push(importExpr(Identifiers$1.templateRefExtractor));
15789 }
15790 // Create the template function
15791 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);
15792 // Nested templates must not be visited until after their parent templates have completed
15793 // processing, so they are queued here until after the initial pass. Otherwise, we wouldn't
15794 // be able to support bindings in nested templates to local refs that occur after the
15795 // template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
15796 this._nestedTemplateFns.push(() => {
15797 const templateFunctionExpr = templateVisitor.buildTemplateFunction(template.children, template.variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, template.i18n);
15798 this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName, null));
15799 if (templateVisitor._ngContentReservedSlots.length) {
15800 this._ngContentReservedSlots.push(...templateVisitor._ngContentReservedSlots);
15801 }
15802 });
15803 // e.g. template(1, MyComp_Template_1)
15804 this.creationInstruction(template.sourceSpan, Identifiers$1.templateCreate, () => {
15805 parameters.splice(2, 0, literal(templateVisitor.getConstCount()), literal(templateVisitor.getVarCount()));
15806 return trimTrailingNulls(parameters);
15807 });
15808 // handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al;
15809 this.templatePropertyBindings(templateIndex, template.templateAttrs);
15810 // Only add normal input/output binding instructions on explicit ng-template elements.
15811 if (template.tagName === NG_TEMPLATE_TAG_NAME) {
15812 // Add the input bindings
15813 this.templatePropertyBindings(templateIndex, template.inputs);
15814 // Generate listeners for directive output
15815 template.outputs.forEach((outputAst) => {
15816 this.creationInstruction(outputAst.sourceSpan, Identifiers$1.listener, this.prepareListenerParameter('ng_template', outputAst, templateIndex));
15817 });
15818 }
15819 }
15820 visitBoundText(text) {
15821 if (this.i18n) {
15822 const value = text.value.visit(this._valueConverter);
15823 this.allocateBindingSlots(value);
15824 if (value instanceof Interpolation) {
15825 this.i18n.appendBoundText(text.i18n);
15826 this.i18nAppendBindings(value.expressions);
15827 }
15828 return;
15829 }
15830 const nodeIndex = this.allocateDataSlot();
15831 this.creationInstruction(text.sourceSpan, Identifiers$1.text, [literal(nodeIndex)]);
15832 const value = text.value.visit(this._valueConverter);
15833 this.allocateBindingSlots(value);
15834 if (value instanceof Interpolation) {
15835 this.updateInstruction(nodeIndex, text.sourceSpan, getTextInterpolationExpression(value), () => this.getUpdateInstructionArguments(value));
15836 }
15837 else {
15838 this.updateInstruction(nodeIndex, text.sourceSpan, Identifiers$1.textBinding, () => [this.convertPropertyBinding(value)]);
15839 }
15840 }
15841 visitText(text) {
15842 // when a text element is located within a translatable
15843 // block, we exclude this text element from instructions set,
15844 // since it will be captured in i18n content and processed at runtime
15845 if (!this.i18n) {
15846 this.creationInstruction(text.sourceSpan, Identifiers$1.text, [literal(this.allocateDataSlot()), literal(text.value)]);
15847 }
15848 }
15849 visitIcu(icu) {
15850 let initWasInvoked = false;
15851 // if an ICU was created outside of i18n block, we still treat
15852 // it as a translatable entity and invoke i18nStart and i18nEnd
15853 // to generate i18n context and the necessary instructions
15854 if (!this.i18n) {
15855 initWasInvoked = true;
15856 this.i18nStart(null, icu.i18n, true);
15857 }
15858 const i18n = this.i18n;
15859 const vars = this.i18nBindProps(icu.vars);
15860 const placeholders = this.i18nBindProps(icu.placeholders);
15861 // output ICU directly and keep ICU reference in context
15862 const message = icu.i18n;
15863 // we always need post-processing function for ICUs, to make sure that:
15864 // - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note:
15865 // `goog.getMsg` does not process ICUs and uses the `{PLACEHOLDER}` format for placeholders
15866 // inside ICUs)
15867 // - all ICU vars (such as `VAR_SELECT` or `VAR_PLURAL`) are replaced with correct values
15868 const transformFn = (raw) => {
15869 const params = Object.assign({}, vars, placeholders);
15870 const formatted = this.i18nFormatPlaceholderNames(params, /* useCamelCase */ false);
15871 return instruction(null, Identifiers$1.i18nPostprocess, [raw, mapLiteral(formatted, true)]);
15872 };
15873 // in case the whole i18n message is a single ICU - we do not need to
15874 // create a separate top-level translation, we can use the root ref instead
15875 // and make this ICU a top-level translation
15876 // note: ICU placeholders are replaced with actual values in `i18nPostprocess` function
15877 // separately, so we do not pass placeholders into `i18nTranslate` function.
15878 if (isSingleI18nIcu(i18n.meta)) {
15879 this.i18nTranslate(message, /* placeholders */ {}, i18n.ref, transformFn);
15880 }
15881 else {
15882 // output ICU directly and keep ICU reference in context
15883 const ref = this.i18nTranslate(message, /* placeholders */ {}, /* ref */ undefined, transformFn);
15884 i18n.appendIcu(icuFromI18nMessage(message).name, ref);
15885 }
15886 if (initWasInvoked) {
15887 this.i18nEnd(null, true);
15888 }
15889 return null;
15890 }
15891 allocateDataSlot() { return this._dataIndex++; }
15892 getConstCount() { return this._dataIndex; }
15893 getVarCount() { return this._pureFunctionSlots; }
15894 getNgContentSelectors() {
15895 return this._ngContentReservedSlots.length ?
15896 this.constantPool.getConstLiteral(asLiteral(this._ngContentReservedSlots), true) :
15897 null;
15898 }
15899 bindingContext() { return `${this._bindingContext++}`; }
15900 templatePropertyBindings(templateIndex, attrs) {
15901 const propertyBindings = [];
15902 attrs.forEach(input => {
15903 if (input instanceof BoundAttribute) {
15904 const value = input.value.visit(this._valueConverter);
15905 if (value !== undefined) {
15906 this.allocateBindingSlots(value);
15907 propertyBindings.push({
15908 name: input.name,
15909 sourceSpan: input.sourceSpan,
15910 value: () => this.convertPropertyBinding(value)
15911 });
15912 }
15913 }
15914 });
15915 if (propertyBindings.length > 0) {
15916 this.updateInstructionChain(templateIndex, Identifiers$1.property, propertyBindings);
15917 }
15918 }
15919 // Bindings must only be resolved after all local refs have been visited, so all
15920 // instructions are queued in callbacks that execute once the initial pass has completed.
15921 // Otherwise, we wouldn't be able to support local refs that are defined after their
15922 // bindings. e.g. {{ foo }} <div #foo></div>
15923 instructionFn(fns, span, reference, paramsOrFn, prepend = false) {
15924 fns[prepend ? 'unshift' : 'push'](() => {
15925 const params = Array.isArray(paramsOrFn) ? paramsOrFn : paramsOrFn();
15926 return instruction(span, reference, params).toStmt();
15927 });
15928 }
15929 processStylingInstruction(elementIndex, instruction, createMode) {
15930 if (instruction) {
15931 if (createMode) {
15932 this.creationInstruction(instruction.sourceSpan, instruction.reference, () => {
15933 return instruction.params(value => this.convertPropertyBinding(value));
15934 });
15935 }
15936 else {
15937 this.updateInstruction(elementIndex, instruction.sourceSpan, instruction.reference, () => {
15938 return instruction
15939 .params(value => {
15940 return (instruction.supportsInterpolation && value instanceof Interpolation) ?
15941 this.getUpdateInstructionArguments(value) :
15942 this.convertPropertyBinding(value);
15943 });
15944 });
15945 }
15946 }
15947 }
15948 creationInstruction(span, reference, paramsOrFn, prepend) {
15949 this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend);
15950 }
15951 updateInstruction(nodeIndex, span, reference, paramsOrFn) {
15952 this.addSelectInstructionIfNecessary(nodeIndex, span);
15953 this.instructionFn(this._updateCodeFns, span, reference, paramsOrFn || []);
15954 }
15955 updateInstructionChain(nodeIndex, reference, bindings) {
15956 const span = bindings.length ? bindings[0].sourceSpan : null;
15957 this.addSelectInstructionIfNecessary(nodeIndex, span);
15958 this._updateCodeFns.push(() => {
15959 const calls = bindings.map(property => {
15960 const fnParams = [property.value(), ...(property.params || [])];
15961 if (property.name) {
15962 fnParams.unshift(literal(property.name));
15963 }
15964 return fnParams;
15965 });
15966 return chainedInstruction(reference, calls, span).toStmt();
15967 });
15968 }
15969 addSelectInstructionIfNecessary(nodeIndex, span) {
15970 if (this._lastNodeIndexWithFlush < nodeIndex) {
15971 if (nodeIndex > 0) {
15972 this.instructionFn(this._updateCodeFns, span, Identifiers$1.select, [literal(nodeIndex)]);
15973 }
15974 this._lastNodeIndexWithFlush = nodeIndex;
15975 }
15976 }
15977 allocatePureFunctionSlots(numSlots) {
15978 const originalSlots = this._pureFunctionSlots;
15979 this._pureFunctionSlots += numSlots;
15980 return originalSlots;
15981 }
15982 allocateBindingSlots(value) {
15983 this._bindingSlots += value instanceof Interpolation ? value.expressions.length : 1;
15984 }
15985 /**
15986 * Gets an expression that refers to the implicit receiver. The implicit
15987 * receiver is always the root level context.
15988 */
15989 getImplicitReceiverExpr() {
15990 if (this._implicitReceiverExpr) {
15991 return this._implicitReceiverExpr;
15992 }
15993 return this._implicitReceiverExpr = this.level === 0 ?
15994 variable(CONTEXT_NAME) :
15995 this._bindingScope.getOrCreateSharedContextVar(0);
15996 }
15997 convertExpressionBinding(value) {
15998 const convertedPropertyBinding = convertPropertyBinding(this, this.getImplicitReceiverExpr(), value, this.bindingContext(), BindingForm.TrySimple);
15999 return convertedPropertyBinding.currValExpr;
16000 }
16001 convertPropertyBinding(value) {
16002 const convertedPropertyBinding = convertPropertyBinding(this, this.getImplicitReceiverExpr(), value, this.bindingContext(), BindingForm.TrySimple, () => error('Unexpected interpolation'));
16003 const valExpr = convertedPropertyBinding.currValExpr;
16004 this._tempVariables.push(...convertedPropertyBinding.stmts);
16005 return valExpr;
16006 }
16007 /**
16008 * Gets a list of argument expressions to pass to an update instruction expression. Also updates
16009 * the temp variables state with temp variables that were identified as needing to be created
16010 * while visiting the arguments.
16011 * @param value The original expression we will be resolving an arguments list from.
16012 */
16013 getUpdateInstructionArguments(value) {
16014 const { args, stmts } = convertUpdateArguments(this, this.getImplicitReceiverExpr(), value, this.bindingContext());
16015 this._tempVariables.push(...stmts);
16016 return args;
16017 }
16018 matchDirectives(tagName, elOrTpl) {
16019 if (this.directiveMatcher) {
16020 const selector = createCssSelector(tagName, getAttrsForDirectiveMatching(elOrTpl));
16021 this.directiveMatcher.match(selector, (cssSelector, staticType) => { this.directives.add(staticType); });
16022 }
16023 }
16024 /**
16025 * Prepares all attribute expression values for the `TAttributes` array.
16026 *
16027 * The purpose of this function is to properly construct an attributes array that
16028 * is passed into the `elementStart` (or just `element`) functions. Because there
16029 * are many different types of attributes, the array needs to be constructed in a
16030 * special way so that `elementStart` can properly evaluate them.
16031 *
16032 * The format looks like this:
16033 *
16034 * ```
16035 * attrs = [prop, value, prop2, value2,
16036 * CLASSES, class1, class2,
16037 * STYLES, style1, value1, style2, value2,
16038 * BINDINGS, name1, name2, name3,
16039 * TEMPLATE, name4, name5, name6,
16040 * I18N, name7, name8, ...]
16041 * ```
16042 *
16043 * Note that this function will fully ignore all synthetic (@foo) attribute values
16044 * because those values are intended to always be generated as property instructions.
16045 */
16046 prepareNonRenderAttrs(inputs, outputs, styles, templateAttrs = [], i18nAttrs = []) {
16047 const alreadySeen = new Set();
16048 const attrExprs = [];
16049 function addAttrExpr(key, value) {
16050 if (typeof key === 'string') {
16051 if (!alreadySeen.has(key)) {
16052 attrExprs.push(...getAttributeNameLiterals(key));
16053 value !== undefined && attrExprs.push(value);
16054 alreadySeen.add(key);
16055 }
16056 }
16057 else {
16058 attrExprs.push(literal(key));
16059 }
16060 }
16061 // it's important that this occurs before BINDINGS and TEMPLATE because once `elementStart`
16062 // comes across the BINDINGS or TEMPLATE markers then it will continue reading each value as
16063 // as single property value cell by cell.
16064 if (styles) {
16065 styles.populateInitialStylingAttrs(attrExprs);
16066 }
16067 if (inputs.length || outputs.length) {
16068 const attrsLengthBeforeInputs = attrExprs.length;
16069 for (let i = 0; i < inputs.length; i++) {
16070 const input = inputs[i];
16071 // We don't want the animation and attribute bindings in the
16072 // attributes array since they aren't used for directive matching.
16073 if (input.type !== 4 /* Animation */ && input.type !== 1 /* Attribute */) {
16074 addAttrExpr(input.name);
16075 }
16076 }
16077 for (let i = 0; i < outputs.length; i++) {
16078 const output = outputs[i];
16079 if (output.type !== 1 /* Animation */) {
16080 addAttrExpr(output.name);
16081 }
16082 }
16083 // this is a cheap way of adding the marker only after all the input/output
16084 // values have been filtered (by not including the animation ones) and added
16085 // to the expressions. The marker is important because it tells the runtime
16086 // code that this is where attributes without values start...
16087 if (attrExprs.length !== attrsLengthBeforeInputs) {
16088 attrExprs.splice(attrsLengthBeforeInputs, 0, literal(3 /* Bindings */));
16089 }
16090 }
16091 if (templateAttrs.length) {
16092 attrExprs.push(literal(4 /* Template */));
16093 templateAttrs.forEach(attr => addAttrExpr(attr.name));
16094 }
16095 if (i18nAttrs.length) {
16096 attrExprs.push(literal(6 /* I18n */));
16097 i18nAttrs.forEach(attr => addAttrExpr(attr.name));
16098 }
16099 return attrExprs;
16100 }
16101 toAttrsParam(attrsExprs) {
16102 return attrsExprs.length > 0 ?
16103 this.constantPool.getConstLiteral(literalArr(attrsExprs), true) :
16104 TYPED_NULL_EXPR;
16105 }
16106 prepareRefsParameter(references) {
16107 if (!references || references.length === 0) {
16108 return TYPED_NULL_EXPR;
16109 }
16110 const refsParam = flatten(references.map(reference => {
16111 const slot = this.allocateDataSlot();
16112 // Generate the update temporary.
16113 const variableName = this._bindingScope.freshReferenceName();
16114 const retrievalLevel = this.level;
16115 const lhs = variable(variableName);
16116 this._bindingScope.set(retrievalLevel, reference.name, lhs, 0 /* DEFAULT */, (scope, relativeLevel) => {
16117 // e.g. nextContext(2);
16118 const nextContextStmt = relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : [];
16119 // e.g. const $foo$ = reference(1);
16120 const refExpr = lhs.set(importExpr(Identifiers$1.reference).callFn([literal(slot)]));
16121 return nextContextStmt.concat(refExpr.toConstDecl());
16122 }, true);
16123 return [reference.name, reference.value];
16124 }));
16125 return this.constantPool.getConstLiteral(asLiteral(refsParam), true);
16126 }
16127 prepareListenerParameter(tagName, outputAst, index) {
16128 return () => {
16129 const eventName = outputAst.name;
16130 const bindingFnName = outputAst.type === 1 /* Animation */ ?
16131 // synthetic @listener.foo values are treated the exact same as are standard listeners
16132 prepareSyntheticListenerFunctionName(eventName, outputAst.phase) :
16133 sanitizeIdentifier(eventName);
16134 const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`;
16135 const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel);
16136 return prepareEventListenerParameters(outputAst, handlerName, scope);
16137 };
16138 }
16139}
16140class ValueConverter extends AstMemoryEfficientTransformer {
16141 constructor(constantPool, allocateSlot, allocatePureFunctionSlots, definePipe) {
16142 super();
16143 this.constantPool = constantPool;
16144 this.allocateSlot = allocateSlot;
16145 this.allocatePureFunctionSlots = allocatePureFunctionSlots;
16146 this.definePipe = definePipe;
16147 this._pipeBindExprs = [];
16148 }
16149 // AstMemoryEfficientTransformer
16150 visitPipe(pipe, context) {
16151 // Allocate a slot to create the pipe
16152 const slot = this.allocateSlot();
16153 const slotPseudoLocal = `PIPE:${slot}`;
16154 // Allocate one slot for the result plus one slot per pipe argument
16155 const pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length);
16156 const target = new PropertyRead(pipe.span, new ImplicitReceiver(pipe.span), slotPseudoLocal);
16157 const { identifier, isVarLength } = pipeBindingCallInfo(pipe.args);
16158 this.definePipe(pipe.name, slotPseudoLocal, slot, importExpr(identifier));
16159 const args = [pipe.exp, ...pipe.args];
16160 const convertedArgs = isVarLength ? this.visitAll([new LiteralArray(pipe.span, args)]) : this.visitAll(args);
16161 const pipeBindExpr = new FunctionCall(pipe.span, target, [
16162 new LiteralPrimitive(pipe.span, slot),
16163 new LiteralPrimitive(pipe.span, pureFunctionSlot),
16164 ...convertedArgs,
16165 ]);
16166 this._pipeBindExprs.push(pipeBindExpr);
16167 return pipeBindExpr;
16168 }
16169 updatePipeSlotOffsets(bindingSlots) {
16170 this._pipeBindExprs.forEach((pipe) => {
16171 // update the slot offset arg (index 1) to account for binding slots
16172 const slotOffset = pipe.args[1];
16173 slotOffset.value += bindingSlots;
16174 });
16175 }
16176 visitLiteralArray(array, context) {
16177 return new BuiltinFunctionCall(array.span, this.visitAll(array.expressions), values => {
16178 // If the literal has calculated (non-literal) elements transform it into
16179 // calls to literal factories that compose the literal and will cache intermediate
16180 // values. Otherwise, just return an literal array that contains the values.
16181 const literal = literalArr(values);
16182 return values.every(a => a.isConstant()) ?
16183 this.constantPool.getConstLiteral(literal, true) :
16184 getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
16185 });
16186 }
16187 visitLiteralMap(map, context) {
16188 return new BuiltinFunctionCall(map.span, this.visitAll(map.values), values => {
16189 // If the literal has calculated (non-literal) elements transform it into
16190 // calls to literal factories that compose the literal and will cache intermediate
16191 // values. Otherwise, just return an literal array that contains the values.
16192 const literal = literalMap(values.map((value, index) => ({ key: map.keys[index].key, value, quoted: map.keys[index].quoted })));
16193 return values.every(a => a.isConstant()) ?
16194 this.constantPool.getConstLiteral(literal, true) :
16195 getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
16196 });
16197 }
16198}
16199// Pipes always have at least one parameter, the value they operate on
16200const pipeBindingIdentifiers = [Identifiers$1.pipeBind1, Identifiers$1.pipeBind2, Identifiers$1.pipeBind3, Identifiers$1.pipeBind4];
16201function pipeBindingCallInfo(args) {
16202 const identifier = pipeBindingIdentifiers[args.length];
16203 return {
16204 identifier: identifier || Identifiers$1.pipeBindV,
16205 isVarLength: !identifier,
16206 };
16207}
16208const pureFunctionIdentifiers = [
16209 Identifiers$1.pureFunction0, Identifiers$1.pureFunction1, Identifiers$1.pureFunction2, Identifiers$1.pureFunction3, Identifiers$1.pureFunction4,
16210 Identifiers$1.pureFunction5, Identifiers$1.pureFunction6, Identifiers$1.pureFunction7, Identifiers$1.pureFunction8
16211];
16212function pureFunctionCallInfo(args) {
16213 const identifier = pureFunctionIdentifiers[args.length];
16214 return {
16215 identifier: identifier || Identifiers$1.pureFunctionV,
16216 isVarLength: !identifier,
16217 };
16218}
16219function instruction(span, reference, params) {
16220 return importExpr(reference, null, span).callFn(params, span);
16221}
16222// e.g. x(2);
16223function generateNextContextExpr(relativeLevelDiff) {
16224 return importExpr(Identifiers$1.nextContext)
16225 .callFn(relativeLevelDiff > 1 ? [literal(relativeLevelDiff)] : []);
16226}
16227function getLiteralFactory(constantPool, literal$1, allocateSlots) {
16228 const { literalFactory, literalFactoryArguments } = constantPool.getLiteralFactory(literal$1);
16229 // Allocate 1 slot for the result plus 1 per argument
16230 const startSlot = allocateSlots(1 + literalFactoryArguments.length);
16231 literalFactoryArguments.length > 0 || error(`Expected arguments to a literal factory function`);
16232 const { identifier, isVarLength } = pureFunctionCallInfo(literalFactoryArguments);
16233 // Literal factories are pure functions that only need to be re-invoked when the parameters
16234 // change.
16235 const args = [
16236 literal(startSlot),
16237 literalFactory,
16238 ];
16239 if (isVarLength) {
16240 args.push(literalArr(literalFactoryArguments));
16241 }
16242 else {
16243 args.push(...literalFactoryArguments);
16244 }
16245 return importExpr(identifier).callFn(args);
16246}
16247/**
16248 * Gets an array of literals that can be added to an expression
16249 * to represent the name and namespace of an attribute. E.g.
16250 * `:xlink:href` turns into `[AttributeMarker.NamespaceURI, 'xlink', 'href']`.
16251 *
16252 * @param name Name of the attribute, including the namespace.
16253 */
16254function getAttributeNameLiterals(name) {
16255 const [attributeNamespace, attributeName] = splitNsName(name);
16256 const nameLiteral = literal(attributeName);
16257 if (attributeNamespace) {
16258 return [
16259 literal(0 /* NamespaceURI */), literal(attributeNamespace), nameLiteral
16260 ];
16261 }
16262 return [nameLiteral];
16263}
16264/** The prefix used to get a shared context in BindingScope's map. */
16265const SHARED_CONTEXT_KEY = '$$shared_ctx$$';
16266class BindingScope {
16267 constructor(bindingLevel = 0, parent = null) {
16268 this.bindingLevel = bindingLevel;
16269 this.parent = parent;
16270 /** Keeps a map from local variables to their BindingData. */
16271 this.map = new Map();
16272 this.referenceNameIndex = 0;
16273 this.restoreViewVariable = null;
16274 }
16275 static get ROOT_SCOPE() {
16276 if (!BindingScope._ROOT_SCOPE) {
16277 BindingScope._ROOT_SCOPE = new BindingScope().set(0, '$event', variable('$event'));
16278 }
16279 return BindingScope._ROOT_SCOPE;
16280 }
16281 get(name) {
16282 let current = this;
16283 while (current) {
16284 let value = current.map.get(name);
16285 if (value != null) {
16286 if (current !== this) {
16287 // make a local copy and reset the `declare` state
16288 value = {
16289 retrievalLevel: value.retrievalLevel,
16290 lhs: value.lhs,
16291 declareLocalCallback: value.declareLocalCallback,
16292 declare: false,
16293 priority: value.priority,
16294 localRef: value.localRef
16295 };
16296 // Cache the value locally.
16297 this.map.set(name, value);
16298 // Possibly generate a shared context var
16299 this.maybeGenerateSharedContextVar(value);
16300 this.maybeRestoreView(value.retrievalLevel, value.localRef);
16301 }
16302 if (value.declareLocalCallback && !value.declare) {
16303 value.declare = true;
16304 }
16305 return value.lhs;
16306 }
16307 current = current.parent;
16308 }
16309 // If we get to this point, we are looking for a property on the top level component
16310 // - If level === 0, we are on the top and don't need to re-declare `ctx`.
16311 // - If level > 0, we are in an embedded view. We need to retrieve the name of the
16312 // local var we used to store the component context, e.g. const $comp$ = x();
16313 return this.bindingLevel === 0 ? null : this.getComponentProperty(name);
16314 }
16315 /**
16316 * Create a local variable for later reference.
16317 *
16318 * @param retrievalLevel The level from which this value can be retrieved
16319 * @param name Name of the variable.
16320 * @param lhs AST representing the left hand side of the `let lhs = rhs;`.
16321 * @param priority The sorting priority of this var
16322 * @param declareLocalCallback The callback to invoke when declaring this local var
16323 * @param localRef Whether or not this is a local ref
16324 */
16325 set(retrievalLevel, name, lhs, priority = 0 /* DEFAULT */, declareLocalCallback, localRef) {
16326 if (this.map.has(name)) {
16327 if (localRef) {
16328 // Do not throw an error if it's a local ref and do not update existing value,
16329 // so the first defined ref is always returned.
16330 return this;
16331 }
16332 error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`);
16333 }
16334 this.map.set(name, {
16335 retrievalLevel: retrievalLevel,
16336 lhs: lhs,
16337 declare: false,
16338 declareLocalCallback: declareLocalCallback,
16339 priority: priority,
16340 localRef: localRef || false
16341 });
16342 return this;
16343 }
16344 // Implemented as part of LocalResolver.
16345 getLocal(name) { return this.get(name); }
16346 // Implemented as part of LocalResolver.
16347 notifyImplicitReceiverUse() {
16348 if (this.bindingLevel !== 0) {
16349 // Since the implicit receiver is accessed in an embedded view, we need to
16350 // ensure that we declare a shared context variable for the current template
16351 // in the update variables.
16352 this.map.get(SHARED_CONTEXT_KEY + 0).declare = true;
16353 }
16354 }
16355 nestedScope(level) {
16356 const newScope = new BindingScope(level, this);
16357 if (level > 0)
16358 newScope.generateSharedContextVar(0);
16359 return newScope;
16360 }
16361 /**
16362 * Gets or creates a shared context variable and returns its expression. Note that
16363 * this does not mean that the shared variable will be declared. Variables in the
16364 * binding scope will be only declared if they are used.
16365 */
16366 getOrCreateSharedContextVar(retrievalLevel) {
16367 const bindingKey = SHARED_CONTEXT_KEY + retrievalLevel;
16368 if (!this.map.has(bindingKey)) {
16369 this.generateSharedContextVar(retrievalLevel);
16370 }
16371 // Shared context variables are always generated as "ReadVarExpr".
16372 return this.map.get(bindingKey).lhs;
16373 }
16374 getSharedContextName(retrievalLevel) {
16375 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + retrievalLevel);
16376 // Shared context variables are always generated as "ReadVarExpr".
16377 return sharedCtxObj && sharedCtxObj.declare ? sharedCtxObj.lhs : null;
16378 }
16379 maybeGenerateSharedContextVar(value) {
16380 if (value.priority === 1 /* CONTEXT */ &&
16381 value.retrievalLevel < this.bindingLevel) {
16382 const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + value.retrievalLevel);
16383 if (sharedCtxObj) {
16384 sharedCtxObj.declare = true;
16385 }
16386 else {
16387 this.generateSharedContextVar(value.retrievalLevel);
16388 }
16389 }
16390 }
16391 generateSharedContextVar(retrievalLevel) {
16392 const lhs = variable(CONTEXT_NAME + this.freshReferenceName());
16393 this.map.set(SHARED_CONTEXT_KEY + retrievalLevel, {
16394 retrievalLevel: retrievalLevel,
16395 lhs: lhs,
16396 declareLocalCallback: (scope, relativeLevel) => {
16397 // const ctx_r0 = nextContext(2);
16398 return [lhs.set(generateNextContextExpr(relativeLevel)).toConstDecl()];
16399 },
16400 declare: false,
16401 priority: 2 /* SHARED_CONTEXT */,
16402 localRef: false
16403 });
16404 }
16405 getComponentProperty(name) {
16406 const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
16407 componentValue.declare = true;
16408 this.maybeRestoreView(0, false);
16409 return componentValue.lhs.prop(name);
16410 }
16411 maybeRestoreView(retrievalLevel, localRefLookup) {
16412 // We want to restore the current view in listener fns if:
16413 // 1 - we are accessing a value in a parent view, which requires walking the view tree rather
16414 // than using the ctx arg. In this case, the retrieval and binding level will be different.
16415 // 2 - we are looking up a local ref, which requires restoring the view where the local
16416 // ref is stored
16417 if (this.isListenerScope() && (retrievalLevel < this.bindingLevel || localRefLookup)) {
16418 if (!this.parent.restoreViewVariable) {
16419 // parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction
16420 this.parent.restoreViewVariable = variable(this.parent.freshReferenceName());
16421 }
16422 this.restoreViewVariable = this.parent.restoreViewVariable;
16423 }
16424 }
16425 restoreViewStatement() {
16426 // restoreView($state$);
16427 return this.restoreViewVariable ?
16428 [instruction(null, Identifiers$1.restoreView, [this.restoreViewVariable]).toStmt()] :
16429 [];
16430 }
16431 viewSnapshotStatements() {
16432 // const $state$ = getCurrentView();
16433 const getCurrentViewInstruction = instruction(null, Identifiers$1.getCurrentView, []);
16434 return this.restoreViewVariable ?
16435 [this.restoreViewVariable.set(getCurrentViewInstruction).toConstDecl()] :
16436 [];
16437 }
16438 isListenerScope() { return this.parent && this.parent.bindingLevel === this.bindingLevel; }
16439 variableDeclarations() {
16440 let currentContextLevel = 0;
16441 return Array.from(this.map.values())
16442 .filter(value => value.declare)
16443 .sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority)
16444 .reduce((stmts, value) => {
16445 const levelDiff = this.bindingLevel - value.retrievalLevel;
16446 const currStmts = value.declareLocalCallback(this, levelDiff - currentContextLevel);
16447 currentContextLevel = levelDiff;
16448 return stmts.concat(currStmts);
16449 }, []);
16450 }
16451 freshReferenceName() {
16452 let current = this;
16453 // Find the top scope as it maintains the global reference count
16454 while (current.parent)
16455 current = current.parent;
16456 const ref = `${REFERENCE_PREFIX}${current.referenceNameIndex++}`;
16457 return ref;
16458 }
16459}
16460/**
16461 * Creates a `CssSelector` given a tag name and a map of attributes
16462 */
16463function createCssSelector(tag, attributes) {
16464 const cssSelector = new CssSelector();
16465 cssSelector.setElement(tag);
16466 Object.getOwnPropertyNames(attributes).forEach((name) => {
16467 const value = attributes[name];
16468 cssSelector.addAttribute(name, value);
16469 if (name.toLowerCase() === 'class') {
16470 const classes = value.trim().split(/\s+/);
16471 classes.forEach(className => cssSelector.addClassName(className));
16472 }
16473 });
16474 return cssSelector;
16475}
16476/**
16477 * Creates an array of expressions out of an `ngProjectAs` attributes
16478 * which can be added to the instruction parameters.
16479 */
16480function getNgProjectAsLiteral(attribute) {
16481 // Parse the attribute value into a CssSelectorList. Note that we only take the
16482 // first selector, because we don't support multiple selectors in ngProjectAs.
16483 const parsedR3Selector = parseSelectorToR3Selector(attribute.value)[0];
16484 return [literal(5 /* ProjectAs */), asLiteral(parsedR3Selector)];
16485}
16486/**
16487 * Gets the instruction to generate for an interpolated property
16488 * @param interpolation An Interpolation AST
16489 */
16490function getPropertyInterpolationExpression(interpolation) {
16491 switch (getInterpolationArgsLength(interpolation)) {
16492 case 1:
16493 return Identifiers$1.propertyInterpolate;
16494 case 3:
16495 return Identifiers$1.propertyInterpolate1;
16496 case 5:
16497 return Identifiers$1.propertyInterpolate2;
16498 case 7:
16499 return Identifiers$1.propertyInterpolate3;
16500 case 9:
16501 return Identifiers$1.propertyInterpolate4;
16502 case 11:
16503 return Identifiers$1.propertyInterpolate5;
16504 case 13:
16505 return Identifiers$1.propertyInterpolate6;
16506 case 15:
16507 return Identifiers$1.propertyInterpolate7;
16508 case 17:
16509 return Identifiers$1.propertyInterpolate8;
16510 default:
16511 return Identifiers$1.propertyInterpolateV;
16512 }
16513}
16514/**
16515 * Gets the instruction to generate for an interpolated attribute
16516 * @param interpolation An Interpolation AST
16517 */
16518function getAttributeInterpolationExpression(interpolation) {
16519 switch (getInterpolationArgsLength(interpolation)) {
16520 case 3:
16521 return Identifiers$1.attributeInterpolate1;
16522 case 5:
16523 return Identifiers$1.attributeInterpolate2;
16524 case 7:
16525 return Identifiers$1.attributeInterpolate3;
16526 case 9:
16527 return Identifiers$1.attributeInterpolate4;
16528 case 11:
16529 return Identifiers$1.attributeInterpolate5;
16530 case 13:
16531 return Identifiers$1.attributeInterpolate6;
16532 case 15:
16533 return Identifiers$1.attributeInterpolate7;
16534 case 17:
16535 return Identifiers$1.attributeInterpolate8;
16536 default:
16537 return Identifiers$1.attributeInterpolateV;
16538 }
16539}
16540/**
16541 * Gets the instruction to generate for interpolated text.
16542 * @param interpolation An Interpolation AST
16543 */
16544function getTextInterpolationExpression(interpolation) {
16545 switch (getInterpolationArgsLength(interpolation)) {
16546 case 1:
16547 return Identifiers$1.textInterpolate;
16548 case 3:
16549 return Identifiers$1.textInterpolate1;
16550 case 5:
16551 return Identifiers$1.textInterpolate2;
16552 case 7:
16553 return Identifiers$1.textInterpolate3;
16554 case 9:
16555 return Identifiers$1.textInterpolate4;
16556 case 11:
16557 return Identifiers$1.textInterpolate5;
16558 case 13:
16559 return Identifiers$1.textInterpolate6;
16560 case 15:
16561 return Identifiers$1.textInterpolate7;
16562 case 17:
16563 return Identifiers$1.textInterpolate8;
16564 default:
16565 return Identifiers$1.textInterpolateV;
16566 }
16567}
16568/**
16569 * Parse a template into render3 `Node`s and additional metadata, with no other dependencies.
16570 *
16571 * @param template text of the template to parse
16572 * @param templateUrl URL to use for source mapping of the parsed template
16573 * @param options options to modify how the template is parsed
16574 */
16575function parseTemplate(template, templateUrl, options = {}) {
16576 const { interpolationConfig, preserveWhitespaces } = options;
16577 const bindingParser = makeBindingParser(interpolationConfig);
16578 const htmlParser = new HtmlParser();
16579 const parseResult = htmlParser.parse(template, templateUrl, Object.assign({ leadingTriviaChars: LEADING_TRIVIA_CHARS }, options, { tokenizeExpansionForms: true }));
16580 if (parseResult.errors && parseResult.errors.length > 0) {
16581 return { errors: parseResult.errors, nodes: [], styleUrls: [], styles: [] };
16582 }
16583 let rootNodes = parseResult.rootNodes;
16584 // process i18n meta information (scan attributes, generate ids)
16585 // before we run whitespace removal process, because existing i18n
16586 // extraction process (ng xi18n) relies on a raw content to generate
16587 // message ids
16588 rootNodes =
16589 visitAll$1(new I18nMetaVisitor(interpolationConfig, !preserveWhitespaces), rootNodes);
16590 if (!preserveWhitespaces) {
16591 rootNodes = visitAll$1(new WhitespaceVisitor(), rootNodes);
16592 // run i18n meta visitor again in case we remove whitespaces, because
16593 // that might affect generated i18n message content. During this pass
16594 // i18n IDs generated at the first pass will be preserved, so we can mimic
16595 // existing extraction process (ng xi18n)
16596 rootNodes = visitAll$1(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
16597 }
16598 const { nodes, errors, styleUrls, styles } = htmlAstToRender3Ast(rootNodes, bindingParser);
16599 if (errors && errors.length > 0) {
16600 return { errors, nodes: [], styleUrls: [], styles: [] };
16601 }
16602 return { nodes, styleUrls, styles };
16603}
16604/**
16605 * Construct a `BindingParser` with a default configuration.
16606 */
16607function makeBindingParser(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
16608 return new BindingParser(new Parser$1(new Lexer()), interpolationConfig, new DomElementSchemaRegistry(), null, []);
16609}
16610function resolveSanitizationFn(context, isAttribute) {
16611 switch (context) {
16612 case SecurityContext.HTML:
16613 return importExpr(Identifiers$1.sanitizeHtml);
16614 case SecurityContext.SCRIPT:
16615 return importExpr(Identifiers$1.sanitizeScript);
16616 case SecurityContext.STYLE:
16617 // the compiler does not fill in an instruction for [style.prop?] binding
16618 // values because the style algorithm knows internally what props are subject
16619 // to sanitization (only [attr.style] values are explicitly sanitized)
16620 return isAttribute ? importExpr(Identifiers$1.sanitizeStyle) : null;
16621 case SecurityContext.URL:
16622 return importExpr(Identifiers$1.sanitizeUrl);
16623 case SecurityContext.RESOURCE_URL:
16624 return importExpr(Identifiers$1.sanitizeResourceUrl);
16625 default:
16626 return null;
16627 }
16628}
16629function isSingleElementTemplate(children) {
16630 return children.length === 1 && children[0] instanceof Element;
16631}
16632function isTextNode(node) {
16633 return node instanceof Text || node instanceof BoundText || node instanceof Icu;
16634}
16635function hasTextChildrenOnly(children) {
16636 return children.every(isTextNode);
16637}
16638
16639/**
16640 * @license
16641 * Copyright Google Inc. All Rights Reserved.
16642 *
16643 * Use of this source code is governed by an MIT-style license that can be
16644 * found in the LICENSE file at https://angular.io/license
16645 */
16646const EMPTY_ARRAY = [];
16647// This regex matches any binding names that contain the "attr." prefix, e.g. "attr.required"
16648// If there is a match, the first matching group will contain the attribute name to bind.
16649const ATTR_REGEX = /attr\.([^\]]+)/;
16650function getStylingPrefix(name) {
16651 return name.substring(0, 5); // style or class
16652}
16653function baseDirectiveFields(meta, constantPool, bindingParser) {
16654 const definitionMap = new DefinitionMap();
16655 // e.g. `type: MyDirective`
16656 definitionMap.set('type', meta.type);
16657 // e.g. `selectors: [['', 'someDir', '']]`
16658 definitionMap.set('selectors', createDirectiveSelector(meta.selector));
16659 // e.g. `factory: () => new MyApp(directiveInject(ElementRef))`
16660 const result = compileFactoryFunction({
16661 name: meta.name,
16662 type: meta.type,
16663 deps: meta.deps,
16664 injectFn: Identifiers$1.directiveInject,
16665 });
16666 definitionMap.set('factory', result.factory);
16667 if (meta.queries.length > 0) {
16668 // e.g. `contentQueries: (rf, ctx, dirIndex) => { ... }
16669 definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name));
16670 }
16671 if (meta.viewQueries.length) {
16672 definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name));
16673 }
16674 // e.g. `hostBindings: (rf, ctx, elIndex) => { ... }
16675 definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', meta.name));
16676 // e.g 'inputs: {a: 'a'}`
16677 definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
16678 // e.g 'outputs: {a: 'a'}`
16679 definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
16680 if (meta.exportAs !== null) {
16681 definitionMap.set('exportAs', literalArr(meta.exportAs.map(e => literal(e))));
16682 }
16683 return { definitionMap, statements: result.statements };
16684}
16685/**
16686 * Add features to the definition map.
16687 */
16688function addFeatures(definitionMap, meta) {
16689 // e.g. `features: [NgOnChangesFeature()]`
16690 const features = [];
16691 const providers = meta.providers;
16692 const viewProviders = meta.viewProviders;
16693 if (providers || viewProviders) {
16694 const args = [providers || new LiteralArrayExpr([])];
16695 if (viewProviders) {
16696 args.push(viewProviders);
16697 }
16698 features.push(importExpr(Identifiers$1.ProvidersFeature).callFn(args));
16699 }
16700 if (meta.usesInheritance) {
16701 features.push(importExpr(Identifiers$1.InheritDefinitionFeature));
16702 }
16703 if (meta.lifecycle.usesOnChanges) {
16704 features.push(importExpr(Identifiers$1.NgOnChangesFeature).callFn(EMPTY_ARRAY));
16705 }
16706 if (features.length) {
16707 definitionMap.set('features', literalArr(features));
16708 }
16709}
16710/**
16711 * Compile a directive for the render3 runtime as defined by the `R3DirectiveMetadata`.
16712 */
16713function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
16714 const { definitionMap, statements } = baseDirectiveFields(meta, constantPool, bindingParser);
16715 addFeatures(definitionMap, meta);
16716 const expression = importExpr(Identifiers$1.defineDirective).callFn([definitionMap.toLiteralMap()]);
16717 if (!meta.selector) {
16718 throw new Error(`Directive ${meta.name} has no selector, please add it!`);
16719 }
16720 const type = createTypeForDef(meta, Identifiers$1.DirectiveDefWithMeta);
16721 return { expression, type, statements };
16722}
16723/**
16724 * Compile a base definition for the render3 runtime as defined by {@link R3BaseRefMetadata}
16725 * @param meta the metadata used for compilation.
16726 */
16727function compileBaseDefFromMetadata(meta, constantPool, bindingParser) {
16728 const definitionMap = new DefinitionMap();
16729 if (meta.inputs) {
16730 const inputs = meta.inputs;
16731 const inputsMap = Object.keys(inputs).map(key => {
16732 const v = inputs[key];
16733 const value = Array.isArray(v) ? literalArr(v.map(vx => literal(vx))) : literal(v);
16734 return { key, value, quoted: false };
16735 });
16736 definitionMap.set('inputs', literalMap(inputsMap));
16737 }
16738 if (meta.outputs) {
16739 const outputs = meta.outputs;
16740 const outputsMap = Object.keys(outputs).map(key => {
16741 const value = literal(outputs[key]);
16742 return { key, value, quoted: false };
16743 });
16744 definitionMap.set('outputs', literalMap(outputsMap));
16745 }
16746 if (meta.viewQueries && meta.viewQueries.length > 0) {
16747 definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool));
16748 }
16749 if (meta.queries && meta.queries.length > 0) {
16750 definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool));
16751 }
16752 if (meta.host) {
16753 definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.name));
16754 }
16755 const expression = importExpr(Identifiers$1.defineBase).callFn([definitionMap.toLiteralMap()]);
16756 const type = new ExpressionType(importExpr(Identifiers$1.BaseDef), /* modifiers */ null, [expressionType(meta.type)]);
16757 return { expression, type };
16758}
16759/**
16760 * Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
16761 */
16762function compileComponentFromMetadata(meta, constantPool, bindingParser) {
16763 const { definitionMap, statements } = baseDirectiveFields(meta, constantPool, bindingParser);
16764 addFeatures(definitionMap, meta);
16765 const selector = meta.selector && CssSelector.parse(meta.selector);
16766 const firstSelector = selector && selector[0];
16767 // e.g. `attr: ["class", ".my.app"]`
16768 // This is optional an only included if the first selector of a component specifies attributes.
16769 if (firstSelector) {
16770 const selectorAttributes = firstSelector.getAttrs();
16771 if (selectorAttributes.length) {
16772 definitionMap.set('attrs', constantPool.getConstLiteral(literalArr(selectorAttributes.map(value => value != null ? literal(value) : literal(undefined))),
16773 /* forceShared */ true));
16774 }
16775 }
16776 // Generate the CSS matcher that recognize directive
16777 let directiveMatcher = null;
16778 if (meta.directives.length > 0) {
16779 const matcher = new SelectorMatcher();
16780 for (const { selector, expression } of meta.directives) {
16781 matcher.addSelectables(CssSelector.parse(selector), expression);
16782 }
16783 directiveMatcher = matcher;
16784 }
16785 // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
16786 const templateTypeName = meta.name;
16787 const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
16788 const directivesUsed = new Set();
16789 const pipesUsed = new Set();
16790 const changeDetection = meta.changeDetection;
16791 const template = meta.template;
16792 const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, null, null, templateName, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, Identifiers$1.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);
16793 const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
16794 // We need to provide this so that dynamically generated components know what
16795 // projected content blocks to pass through to the component when it is instantiated.
16796 const ngContentSelectors = templateBuilder.getNgContentSelectors();
16797 if (ngContentSelectors) {
16798 definitionMap.set('ngContentSelectors', ngContentSelectors);
16799 }
16800 // e.g. `consts: 2`
16801 definitionMap.set('consts', literal(templateBuilder.getConstCount()));
16802 // e.g. `vars: 2`
16803 definitionMap.set('vars', literal(templateBuilder.getVarCount()));
16804 definitionMap.set('template', templateFunctionExpression);
16805 // e.g. `directives: [MyDirective]`
16806 if (directivesUsed.size) {
16807 let directivesExpr = literalArr(Array.from(directivesUsed));
16808 if (meta.wrapDirectivesAndPipesInClosure) {
16809 directivesExpr = fn([], [new ReturnStatement(directivesExpr)]);
16810 }
16811 definitionMap.set('directives', directivesExpr);
16812 }
16813 // e.g. `pipes: [MyPipe]`
16814 if (pipesUsed.size) {
16815 let pipesExpr = literalArr(Array.from(pipesUsed));
16816 if (meta.wrapDirectivesAndPipesInClosure) {
16817 pipesExpr = fn([], [new ReturnStatement(pipesExpr)]);
16818 }
16819 definitionMap.set('pipes', pipesExpr);
16820 }
16821 if (meta.encapsulation === null) {
16822 meta.encapsulation = ViewEncapsulation.Emulated;
16823 }
16824 // e.g. `styles: [str1, str2]`
16825 if (meta.styles && meta.styles.length) {
16826 const styleValues = meta.encapsulation == ViewEncapsulation.Emulated ?
16827 compileStyles(meta.styles, CONTENT_ATTR, HOST_ATTR) :
16828 meta.styles;
16829 const strings = styleValues.map(str => literal(str));
16830 definitionMap.set('styles', literalArr(strings));
16831 }
16832 else if (meta.encapsulation === ViewEncapsulation.Emulated) {
16833 // If there is no style, don't generate css selectors on elements
16834 meta.encapsulation = ViewEncapsulation.None;
16835 }
16836 // Only set view encapsulation if it's not the default value
16837 if (meta.encapsulation !== ViewEncapsulation.Emulated) {
16838 definitionMap.set('encapsulation', literal(meta.encapsulation));
16839 }
16840 // e.g. `animation: [trigger('123', [])]`
16841 if (meta.animations !== null) {
16842 definitionMap.set('data', literalMap([{ key: 'animation', value: meta.animations, quoted: false }]));
16843 }
16844 // Only set the change detection flag if it's defined and it's not the default.
16845 if (changeDetection != null && changeDetection !== ChangeDetectionStrategy.Default) {
16846 definitionMap.set('changeDetection', literal(changeDetection));
16847 }
16848 // On the type side, remove newlines from the selector as it will need to fit into a TypeScript
16849 // string literal, which must be on one line.
16850 const selectorForType = (meta.selector || '').replace(/\n/g, '');
16851 const expression = importExpr(Identifiers$1.defineComponent).callFn([definitionMap.toLiteralMap()]);
16852 const type = createTypeForDef(meta, Identifiers$1.ComponentDefWithMeta);
16853 return { expression, type, statements };
16854}
16855/**
16856 * A wrapper around `compileDirective` which depends on render2 global analysis data as its input
16857 * instead of the `R3DirectiveMetadata`.
16858 *
16859 * `R3DirectiveMetadata` is computed from `CompileDirectiveMetadata` and other statically reflected
16860 * information.
16861 */
16862function compileDirectiveFromRender2(outputCtx, directive, reflector, bindingParser) {
16863 const name = identifierName(directive.type);
16864 name || error(`Cannot resolver the name of ${directive.type}`);
16865 const definitionField = outputCtx.constantPool.propertyNameOf(1 /* Directive */);
16866 const meta = directiveMetadataFromGlobalMetadata(directive, outputCtx, reflector);
16867 const res = compileDirectiveFromMetadata(meta, outputCtx.constantPool, bindingParser);
16868 // Create the partial class to be merged with the actual class.
16869 outputCtx.statements.push(new ClassStmt(name, null, [new ClassField(definitionField, INFERRED_TYPE, [StmtModifier.Static], res.expression)], [], new ClassMethod(null, [], []), []));
16870}
16871/**
16872 * A wrapper around `compileComponent` which depends on render2 global analysis data as its input
16873 * instead of the `R3DirectiveMetadata`.
16874 *
16875 * `R3ComponentMetadata` is computed from `CompileDirectiveMetadata` and other statically reflected
16876 * information.
16877 */
16878function compileComponentFromRender2(outputCtx, component, render3Ast, reflector, bindingParser, directiveTypeBySel, pipeTypeByName) {
16879 const name = identifierName(component.type);
16880 name || error(`Cannot resolver the name of ${component.type}`);
16881 const definitionField = outputCtx.constantPool.propertyNameOf(2 /* Component */);
16882 const summary = component.toSummary();
16883 // Compute the R3ComponentMetadata from the CompileDirectiveMetadata
16884 const meta = Object.assign({}, directiveMetadataFromGlobalMetadata(component, outputCtx, reflector), { selector: component.selector, template: { nodes: render3Ast.nodes }, directives: [], pipes: typeMapToExpressionMap(pipeTypeByName, outputCtx), viewQueries: queriesFromGlobalMetadata(component.viewQueries, outputCtx), wrapDirectivesAndPipesInClosure: false, styles: (summary.template && summary.template.styles) || EMPTY_ARRAY, encapsulation: (summary.template && summary.template.encapsulation) || ViewEncapsulation.Emulated, interpolation: DEFAULT_INTERPOLATION_CONFIG, animations: null, viewProviders: component.viewProviders.length > 0 ? new WrappedNodeExpr(component.viewProviders) : null, relativeContextFilePath: '', i18nUseExternalIds: true });
16885 const res = compileComponentFromMetadata(meta, outputCtx.constantPool, bindingParser);
16886 // Create the partial class to be merged with the actual class.
16887 outputCtx.statements.push(new ClassStmt(name, null, [new ClassField(definitionField, INFERRED_TYPE, [StmtModifier.Static], res.expression)], [], new ClassMethod(null, [], []), []));
16888}
16889/**
16890 * Compute `R3DirectiveMetadata` given `CompileDirectiveMetadata` and a `CompileReflector`.
16891 */
16892function directiveMetadataFromGlobalMetadata(directive, outputCtx, reflector) {
16893 // The global-analysis based Ivy mode in ngc is no longer utilized/supported.
16894 throw new Error('unsupported');
16895}
16896/**
16897 * Convert `CompileQueryMetadata` into `R3QueryMetadata`.
16898 */
16899function queriesFromGlobalMetadata(queries, outputCtx) {
16900 return queries.map(query => {
16901 let read = null;
16902 if (query.read && query.read.identifier) {
16903 read = outputCtx.importExpr(query.read.identifier.reference);
16904 }
16905 return {
16906 propertyName: query.propertyName,
16907 first: query.first,
16908 predicate: selectorsFromGlobalMetadata(query.selectors, outputCtx),
16909 descendants: query.descendants, read,
16910 static: !!query.static
16911 };
16912 });
16913}
16914/**
16915 * Convert `CompileTokenMetadata` for query selectors into either an expression for a predicate
16916 * type, or a list of string predicates.
16917 */
16918function selectorsFromGlobalMetadata(selectors, outputCtx) {
16919 if (selectors.length > 1 || (selectors.length == 1 && selectors[0].value)) {
16920 const selectorStrings = selectors.map(value => value.value);
16921 selectorStrings.some(value => !value) &&
16922 error('Found a type among the string selectors expected');
16923 return outputCtx.constantPool.getConstLiteral(literalArr(selectorStrings.map(value => literal(value))));
16924 }
16925 if (selectors.length == 1) {
16926 const first = selectors[0];
16927 if (first.identifier) {
16928 return outputCtx.importExpr(first.identifier.reference);
16929 }
16930 }
16931 error('Unexpected query form');
16932 return NULL_EXPR;
16933}
16934function prepareQueryParams(query, constantPool) {
16935 const parameters = [getQueryPredicate(query, constantPool), literal(query.descendants)];
16936 if (query.read) {
16937 parameters.push(query.read);
16938 }
16939 return parameters;
16940}
16941// Turn a directive selector into an R3-compatible selector for directive def
16942function createDirectiveSelector(selector) {
16943 return asLiteral(parseSelectorToR3Selector(selector));
16944}
16945function convertAttributesToExpressions(attributes) {
16946 const values = [];
16947 for (let key of Object.getOwnPropertyNames(attributes)) {
16948 const value = attributes[key];
16949 values.push(literal(key), value);
16950 }
16951 return values;
16952}
16953// Define and update any content queries
16954function createContentQueriesFunction(queries, constantPool, name) {
16955 const createStatements = [];
16956 const updateStatements = [];
16957 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
16958 for (const query of queries) {
16959 const queryInstruction = query.static ? Identifiers$1.staticContentQuery : Identifiers$1.contentQuery;
16960 // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null);
16961 createStatements.push(importExpr(queryInstruction)
16962 .callFn([variable('dirIndex'), ...prepareQueryParams(query, constantPool)])
16963 .toStmt());
16964 // update, e.g. (r3.queryRefresh(tmp = r3.loadContentQuery()) && (ctx.someDir = tmp));
16965 const temporary = tempAllocator();
16966 const getQueryList = importExpr(Identifiers$1.loadContentQuery).callFn([]);
16967 const refresh = importExpr(Identifiers$1.queryRefresh).callFn([temporary.set(getQueryList)]);
16968 const updateDirective = variable(CONTEXT_NAME)
16969 .prop(query.propertyName)
16970 .set(query.first ? temporary.prop('first') : temporary);
16971 updateStatements.push(refresh.and(updateDirective).toStmt());
16972 }
16973 const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
16974 return fn([
16975 new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null),
16976 new FnParam('dirIndex', null)
16977 ], [
16978 renderFlagCheckIfStmt(1 /* Create */, createStatements),
16979 renderFlagCheckIfStmt(2 /* Update */, updateStatements)
16980 ], INFERRED_TYPE, null, contentQueriesFnName);
16981}
16982function stringAsType(str) {
16983 return expressionType(literal(str));
16984}
16985function stringMapAsType(map) {
16986 const mapValues = Object.keys(map).map(key => {
16987 const value = Array.isArray(map[key]) ? map[key][0] : map[key];
16988 return {
16989 key,
16990 value: literal(value),
16991 quoted: true,
16992 };
16993 });
16994 return expressionType(literalMap(mapValues));
16995}
16996function stringArrayAsType(arr) {
16997 return arr.length > 0 ? expressionType(literalArr(arr.map(value => literal(value)))) :
16998 NONE_TYPE;
16999}
17000function createTypeForDef(meta, typeBase) {
17001 // On the type side, remove newlines from the selector as it will need to fit into a TypeScript
17002 // string literal, which must be on one line.
17003 const selectorForType = (meta.selector || '').replace(/\n/g, '');
17004 return expressionType(importExpr(typeBase, [
17005 typeWithParameters(meta.type, meta.typeArgumentCount),
17006 stringAsType(selectorForType),
17007 meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : NONE_TYPE,
17008 stringMapAsType(meta.inputs),
17009 stringMapAsType(meta.outputs),
17010 stringArrayAsType(meta.queries.map(q => q.propertyName)),
17011 ]));
17012}
17013// Define and update any view queries
17014function createViewQueriesFunction(viewQueries, constantPool, name) {
17015 const createStatements = [];
17016 const updateStatements = [];
17017 const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
17018 viewQueries.forEach((query) => {
17019 const queryInstruction = query.static ? Identifiers$1.staticViewQuery : Identifiers$1.viewQuery;
17020 // creation, e.g. r3.viewQuery(somePredicate, true);
17021 const queryDefinition = importExpr(queryInstruction).callFn(prepareQueryParams(query, constantPool));
17022 createStatements.push(queryDefinition.toStmt());
17023 // update, e.g. (r3.queryRefresh(tmp = r3.loadViewQuery()) && (ctx.someDir = tmp));
17024 const temporary = tempAllocator();
17025 const getQueryList = importExpr(Identifiers$1.loadViewQuery).callFn([]);
17026 const refresh = importExpr(Identifiers$1.queryRefresh).callFn([temporary.set(getQueryList)]);
17027 const updateDirective = variable(CONTEXT_NAME)
17028 .prop(query.propertyName)
17029 .set(query.first ? temporary.prop('first') : temporary);
17030 updateStatements.push(refresh.and(updateDirective).toStmt());
17031 });
17032 const viewQueryFnName = name ? `${name}_Query` : null;
17033 return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
17034 renderFlagCheckIfStmt(1 /* Create */, createStatements),
17035 renderFlagCheckIfStmt(2 /* Update */, updateStatements)
17036 ], INFERRED_TYPE, null, viewQueryFnName);
17037}
17038// Return a host binding function or null if one is not necessary.
17039function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name) {
17040 // Initialize hostVarsCount to number of bound host properties (interpolations illegal)
17041 const hostVarsCount = Object.keys(hostBindingsMetadata.properties).length;
17042 const elVarExp = variable('elIndex');
17043 const bindingContext = variable(CONTEXT_NAME);
17044 const styleBuilder = new StylingBuilder(elVarExp, bindingContext);
17045 const { styleAttr, classAttr } = hostBindingsMetadata.specialAttributes;
17046 if (styleAttr !== undefined) {
17047 styleBuilder.registerStyleAttr(styleAttr);
17048 }
17049 if (classAttr !== undefined) {
17050 styleBuilder.registerClassAttr(classAttr);
17051 }
17052 const createStatements = [];
17053 const updateStatements = [];
17054 let totalHostVarsCount = hostVarsCount;
17055 const hostBindingSourceSpan = typeSourceSpan;
17056 const directiveSummary = metadataAsSummary(hostBindingsMetadata);
17057 let valueConverter;
17058 const getValueConverter = () => {
17059 if (!valueConverter) {
17060 const hostVarsCountFn = (numSlots) => {
17061 const originalVarsCount = totalHostVarsCount;
17062 totalHostVarsCount += numSlots;
17063 return originalVarsCount;
17064 };
17065 valueConverter = new ValueConverter(constantPool, () => error('Unexpected node'), // new nodes are illegal here
17066 hostVarsCountFn, () => error('Unexpected pipe')); // pipes are illegal here
17067 }
17068 return valueConverter;
17069 };
17070 // Calculate host event bindings
17071 const eventBindings = bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan);
17072 if (eventBindings && eventBindings.length) {
17073 const listeners = createHostListeners(eventBindings, name);
17074 createStatements.push(...listeners);
17075 }
17076 // Calculate the host property bindings
17077 const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan);
17078 const propertyBindings = [];
17079 const attributeBindings = [];
17080 const syntheticHostBindings = [];
17081 bindings && bindings.forEach((binding) => {
17082 const name = binding.name;
17083 const stylingInputWasSet = styleBuilder.registerInputBasedOnName(name, binding.expression, binding.sourceSpan);
17084 if (!stylingInputWasSet) {
17085 // resolve literal arrays and literal objects
17086 const value = binding.expression.visit(getValueConverter());
17087 const bindingExpr = bindingFn(bindingContext, value);
17088 const { bindingName, instruction, isAttribute } = getBindingNameAndInstruction(binding);
17089 const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
17090 .filter(context => context !== SecurityContext.NONE);
17091 let sanitizerFn = null;
17092 if (securityContexts.length) {
17093 if (securityContexts.length === 2 &&
17094 securityContexts.indexOf(SecurityContext.URL) > -1 &&
17095 securityContexts.indexOf(SecurityContext.RESOURCE_URL) > -1) {
17096 // Special case for some URL attributes (such as "src" and "href") that may be a part
17097 // of different security contexts. In this case we use special santitization function and
17098 // select the actual sanitizer at runtime based on a tag name that is provided while
17099 // invoking sanitization function.
17100 sanitizerFn = importExpr(Identifiers$1.sanitizeUrlOrResourceUrl);
17101 }
17102 else {
17103 sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute);
17104 }
17105 }
17106 const instructionParams = [literal(bindingName), bindingExpr.currValExpr];
17107 if (sanitizerFn) {
17108 instructionParams.push(sanitizerFn);
17109 }
17110 updateStatements.push(...bindingExpr.stmts);
17111 if (instruction === Identifiers$1.hostProperty) {
17112 propertyBindings.push(instructionParams);
17113 }
17114 else if (instruction === Identifiers$1.attribute) {
17115 attributeBindings.push(instructionParams);
17116 }
17117 else if (instruction === Identifiers$1.updateSyntheticHostBinding) {
17118 syntheticHostBindings.push(instructionParams);
17119 }
17120 else {
17121 updateStatements.push(importExpr(instruction).callFn(instructionParams).toStmt());
17122 }
17123 }
17124 });
17125 if (propertyBindings.length > 0) {
17126 updateStatements.push(chainedInstruction(Identifiers$1.hostProperty, propertyBindings).toStmt());
17127 }
17128 if (attributeBindings.length > 0) {
17129 updateStatements.push(chainedInstruction(Identifiers$1.attribute, attributeBindings).toStmt());
17130 }
17131 if (syntheticHostBindings.length > 0) {
17132 updateStatements.push(chainedInstruction(Identifiers$1.updateSyntheticHostBinding, syntheticHostBindings).toStmt());
17133 }
17134 // since we're dealing with directives/components and both have hostBinding
17135 // functions, we need to generate a special hostAttrs instruction that deals
17136 // with both the assignment of styling as well as static attributes to the host
17137 // element. The instruction below will instruct all initial styling (styling
17138 // that is inside of a host binding within a directive/component) to be attached
17139 // to the host element alongside any of the provided host attributes that were
17140 // collected earlier.
17141 const hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes);
17142 const hostInstruction = styleBuilder.buildHostAttrsInstruction(null, hostAttrs, constantPool);
17143 if (hostInstruction) {
17144 createStatements.push(createStylingStmt(hostInstruction, bindingContext, bindingFn));
17145 }
17146 if (styleBuilder.hasBindings) {
17147 // singular style/class bindings (things like `[style.prop]` and `[class.name]`)
17148 // MUST be registered on a given element within the component/directive
17149 // templateFn/hostBindingsFn functions. The instruction below will figure out
17150 // what all the bindings are and then generate the statements required to register
17151 // those bindings to the element via `styling`.
17152 const stylingInstruction = styleBuilder.buildStylingInstruction(null, constantPool);
17153 if (stylingInstruction) {
17154 createStatements.push(createStylingStmt(stylingInstruction, bindingContext, bindingFn));
17155 }
17156 // finally each binding that was registered in the statement above will need to be added to
17157 // the update block of a component/directive templateFn/hostBindingsFn so that the bindings
17158 // are evaluated and updated for the element.
17159 styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(instruction => {
17160 // we subtract a value of `1` here because the binding slot was already
17161 // allocated at the top of this method when all the input bindings were
17162 // counted.
17163 totalHostVarsCount += Math.max(instruction.allocateBindingSlots - 1, 0);
17164 updateStatements.push(createStylingStmt(instruction, bindingContext, bindingFn));
17165 });
17166 }
17167 if (totalHostVarsCount) {
17168 createStatements.unshift(importExpr(Identifiers$1.allocHostVars).callFn([literal(totalHostVarsCount)]).toStmt());
17169 }
17170 if (createStatements.length > 0 || updateStatements.length > 0) {
17171 const hostBindingsFnName = name ? `${name}_HostBindings` : null;
17172 const statements = [];
17173 if (createStatements.length > 0) {
17174 statements.push(renderFlagCheckIfStmt(1 /* Create */, createStatements));
17175 }
17176 if (updateStatements.length > 0) {
17177 statements.push(renderFlagCheckIfStmt(2 /* Update */, updateStatements));
17178 }
17179 return fn([
17180 new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null),
17181 new FnParam(elVarExp.name, NUMBER_TYPE)
17182 ], statements, INFERRED_TYPE, null, hostBindingsFnName);
17183 }
17184 return null;
17185}
17186function bindingFn(implicit, value) {
17187 return convertPropertyBinding(null, implicit, value, 'b', BindingForm.TrySimple, () => error('Unexpected interpolation'));
17188}
17189function createStylingStmt(instruction, bindingContext, bindingFn) {
17190 const params = instruction.params(value => bindingFn(bindingContext, value).currValExpr);
17191 return importExpr(instruction.reference, null, instruction.sourceSpan)
17192 .callFn(params, instruction.sourceSpan)
17193 .toStmt();
17194}
17195function getBindingNameAndInstruction(binding) {
17196 let bindingName = binding.name;
17197 let instruction;
17198 // Check to see if this is an attr binding or a property binding
17199 const attrMatches = bindingName.match(ATTR_REGEX);
17200 if (attrMatches) {
17201 bindingName = attrMatches[1];
17202 instruction = Identifiers$1.attribute;
17203 }
17204 else {
17205 if (binding.isAnimation) {
17206 bindingName = prepareSyntheticPropertyName(bindingName);
17207 // host bindings that have a synthetic property (e.g. @foo) should always be rendered
17208 // in the context of the component and not the parent. Therefore there is a special
17209 // compatibility instruction available for this purpose.
17210 instruction = Identifiers$1.updateSyntheticHostBinding;
17211 }
17212 else {
17213 instruction = Identifiers$1.hostProperty;
17214 }
17215 }
17216 return { bindingName, instruction, isAttribute: !!attrMatches };
17217}
17218function createHostListeners(eventBindings, name) {
17219 return eventBindings.map(binding => {
17220 let bindingName = binding.name && sanitizeIdentifier(binding.name);
17221 const bindingFnName = binding.type === 1 /* Animation */ ?
17222 prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) :
17223 bindingName;
17224 const handlerName = name && bindingName ? `${name}_${bindingFnName}_HostBindingHandler` : null;
17225 const params = prepareEventListenerParameters(BoundEvent.fromParsedEvent(binding), handlerName);
17226 const instruction = binding.type == 1 /* Animation */ ? Identifiers$1.componentHostSyntheticListener : Identifiers$1.listener;
17227 return importExpr(instruction).callFn(params).toStmt();
17228 });
17229}
17230function metadataAsSummary(meta) {
17231 // clang-format off
17232 return {
17233 // This is used by the BindingParser, which only deals with listeners and properties. There's no
17234 // need to pass attributes to it.
17235 hostAttributes: {},
17236 hostListeners: meta.listeners,
17237 hostProperties: meta.properties,
17238 };
17239 // clang-format on
17240}
17241function typeMapToExpressionMap(map, outputCtx) {
17242 // Convert each map entry into another entry where the value is an expression importing the type.
17243 const entries = Array.from(map).map(([key, type]) => [key, outputCtx.importExpr(type)]);
17244 return new Map(entries);
17245}
17246const HOST_REG_EXP$1 = /^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/;
17247function parseHostBindings(host) {
17248 const attributes = {};
17249 const listeners = {};
17250 const properties = {};
17251 const specialAttributes = {};
17252 for (const key of Object.keys(host)) {
17253 const value = host[key];
17254 const matches = key.match(HOST_REG_EXP$1);
17255 if (matches === null) {
17256 switch (key) {
17257 case 'class':
17258 if (typeof value !== 'string') {
17259 // TODO(alxhub): make this a diagnostic.
17260 throw new Error(`Class binding must be string`);
17261 }
17262 specialAttributes.classAttr = value;
17263 break;
17264 case 'style':
17265 if (typeof value !== 'string') {
17266 // TODO(alxhub): make this a diagnostic.
17267 throw new Error(`Style binding must be string`);
17268 }
17269 specialAttributes.styleAttr = value;
17270 break;
17271 default:
17272 if (typeof value === 'string') {
17273 attributes[key] = literal(value);
17274 }
17275 else {
17276 attributes[key] = value;
17277 }
17278 }
17279 }
17280 else if (matches[1 /* Binding */] != null) {
17281 if (typeof value !== 'string') {
17282 // TODO(alxhub): make this a diagnostic.
17283 throw new Error(`Property binding must be string`);
17284 }
17285 // synthetic properties (the ones that have a `@` as a prefix)
17286 // are still treated the same as regular properties. Therefore
17287 // there is no point in storing them in a separate map.
17288 properties[matches[1 /* Binding */]] = value;
17289 }
17290 else if (matches[2 /* Event */] != null) {
17291 if (typeof value !== 'string') {
17292 // TODO(alxhub): make this a diagnostic.
17293 throw new Error(`Event binding must be string`);
17294 }
17295 listeners[matches[2 /* Event */]] = value;
17296 }
17297 }
17298 return { attributes, listeners, properties, specialAttributes };
17299}
17300/**
17301 * Verifies host bindings and returns the list of errors (if any). Empty array indicates that a
17302 * given set of host bindings has no errors.
17303 *
17304 * @param bindings set of host bindings to verify.
17305 * @param sourceSpan source span where host bindings were defined.
17306 * @returns array of errors associated with a given set of host bindings.
17307 */
17308function verifyHostBindings(bindings, sourceSpan) {
17309 const summary = metadataAsSummary(bindings);
17310 // TODO: abstract out host bindings verification logic and use it instead of
17311 // creating events and properties ASTs to detect errors (FW-996)
17312 const bindingParser = makeBindingParser();
17313 bindingParser.createDirectiveHostEventAsts(summary, sourceSpan);
17314 bindingParser.createBoundHostProperties(summary, sourceSpan);
17315 return bindingParser.errors;
17316}
17317function compileStyles(styles, selector, hostSelector) {
17318 const shadowCss = new ShadowCss();
17319 return styles.map(style => { return shadowCss.shimCssText(style, selector, hostSelector); });
17320}
17321
17322/**
17323 * @license
17324 * Copyright Google Inc. All Rights Reserved.
17325 *
17326 * Use of this source code is governed by an MIT-style license that can be
17327 * found in the LICENSE file at https://angular.io/license
17328 */
17329/**
17330 * An interface for retrieving documents by URL that the compiler uses
17331 * to load templates.
17332 */
17333class ResourceLoader {
17334 get(url) { return ''; }
17335}
17336
17337/**
17338 * @license
17339 * Copyright Google Inc. All Rights Reserved.
17340 *
17341 * Use of this source code is governed by an MIT-style license that can be
17342 * found in the LICENSE file at https://angular.io/license
17343 */
17344class CompilerFacadeImpl {
17345 constructor(jitEvaluator = new JitEvaluator()) {
17346 this.jitEvaluator = jitEvaluator;
17347 this.R3ResolvedDependencyType = R3ResolvedDependencyType;
17348 this.ResourceLoader = ResourceLoader;
17349 this.elementSchemaRegistry = new DomElementSchemaRegistry();
17350 }
17351 compilePipe(angularCoreEnv, sourceMapUrl, facade) {
17352 const res = compilePipeFromMetadata({
17353 name: facade.name,
17354 type: new WrappedNodeExpr(facade.type),
17355 typeArgumentCount: facade.typeArgumentCount,
17356 deps: convertR3DependencyMetadataArray(facade.deps),
17357 pipeName: facade.pipeName,
17358 pure: facade.pure,
17359 });
17360 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
17361 }
17362 compileInjectable(angularCoreEnv, sourceMapUrl, facade) {
17363 const { expression, statements } = compileInjectable({
17364 name: facade.name,
17365 type: new WrappedNodeExpr(facade.type),
17366 typeArgumentCount: facade.typeArgumentCount,
17367 providedIn: computeProvidedIn(facade.providedIn),
17368 useClass: wrapExpression(facade, USE_CLASS),
17369 useFactory: wrapExpression(facade, USE_FACTORY),
17370 useValue: wrapExpression(facade, USE_VALUE),
17371 useExisting: wrapExpression(facade, USE_EXISTING),
17372 ctorDeps: convertR3DependencyMetadataArray(facade.ctorDeps),
17373 userDeps: convertR3DependencyMetadataArray(facade.userDeps) || undefined,
17374 });
17375 return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
17376 }
17377 compileInjector(angularCoreEnv, sourceMapUrl, facade) {
17378 const meta = {
17379 name: facade.name,
17380 type: new WrappedNodeExpr(facade.type),
17381 deps: convertR3DependencyMetadataArray(facade.deps),
17382 providers: new WrappedNodeExpr(facade.providers),
17383 imports: facade.imports.map(i => new WrappedNodeExpr(i)),
17384 };
17385 const res = compileInjector(meta);
17386 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
17387 }
17388 compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
17389 const meta = {
17390 type: new WrappedNodeExpr(facade.type),
17391 bootstrap: facade.bootstrap.map(wrapReference),
17392 declarations: facade.declarations.map(wrapReference),
17393 imports: facade.imports.map(wrapReference),
17394 exports: facade.exports.map(wrapReference),
17395 emitInline: true,
17396 containsForwardDecls: false,
17397 schemas: facade.schemas ? facade.schemas.map(wrapReference) : null,
17398 id: facade.id ? new WrappedNodeExpr(facade.id) : null,
17399 };
17400 const res = compileNgModule(meta);
17401 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
17402 }
17403 compileDirective(angularCoreEnv, sourceMapUrl, facade) {
17404 const constantPool = new ConstantPool();
17405 const bindingParser = makeBindingParser();
17406 const meta = convertDirectiveFacadeToMetadata(facade);
17407 const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser);
17408 const preStatements = [...constantPool.statements, ...res.statements];
17409 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements);
17410 }
17411 compileComponent(angularCoreEnv, sourceMapUrl, facade) {
17412 // The ConstantPool is a requirement of the JIT'er.
17413 const constantPool = new ConstantPool();
17414 const interpolationConfig = facade.interpolation ?
17415 InterpolationConfig.fromArray(facade.interpolation) :
17416 DEFAULT_INTERPOLATION_CONFIG;
17417 // Parse the template and check for errors.
17418 const template = parseTemplate(facade.template, sourceMapUrl, { preserveWhitespaces: facade.preserveWhitespaces, interpolationConfig });
17419 if (template.errors !== undefined) {
17420 const errors = template.errors.map(err => err.toString()).join(', ');
17421 throw new Error(`Errors during JIT compilation of template for ${facade.name}: ${errors}`);
17422 }
17423 // Compile the component metadata, including template, into an expression.
17424 // TODO(alxhub): implement inputs, outputs, queries, etc.
17425 const res = compileComponentFromMetadata(Object.assign({}, facade, convertDirectiveFacadeToMetadata(facade), { selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(), template, wrapDirectivesAndPipesInClosure: false, styles: facade.styles || [], encapsulation: facade.encapsulation, interpolation: interpolationConfig, changeDetection: facade.changeDetection, animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) :
17426 null, relativeContextFilePath: '', i18nUseExternalIds: true }), constantPool, makeBindingParser(interpolationConfig));
17427 const preStatements = [...constantPool.statements, ...res.statements];
17428 return this.jitExpression(res.expression, angularCoreEnv, `ng:///${facade.name}.js`, preStatements);
17429 }
17430 compileBase(angularCoreEnv, sourceMapUrl, facade) {
17431 const constantPool = new ConstantPool();
17432 const typeSourceSpan = this.createParseSourceSpan('Base', facade.name, `ng:///${facade.name}.js`);
17433 const meta = Object.assign({}, facade, { typeSourceSpan, viewQueries: facade.viewQueries ? facade.viewQueries.map(convertToR3QueryMetadata) :
17434 facade.viewQueries, queries: facade.queries ? facade.queries.map(convertToR3QueryMetadata) : facade.queries, host: extractHostBindings(facade.propMetadata, typeSourceSpan) });
17435 const res = compileBaseDefFromMetadata(meta, constantPool, makeBindingParser());
17436 return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
17437 }
17438 createParseSourceSpan(kind, typeName, sourceUrl) {
17439 return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
17440 }
17441 /**
17442 * JIT compiles an expression and returns the result of executing that expression.
17443 *
17444 * @param def the definition which will be compiled and executed to get the value to patch
17445 * @param context an object map of @angular/core symbol names to symbols which will be available
17446 * in the context of the compiled expression
17447 * @param sourceUrl a URL to use for the source map of the compiled expression
17448 * @param preStatements a collection of statements that should be evaluated before the expression.
17449 */
17450 jitExpression(def, context, sourceUrl, preStatements) {
17451 // The ConstantPool may contain Statements which declare variables used in the final expression.
17452 // Therefore, its statements need to precede the actual JIT operation. The final statement is a
17453 // declaration of $def which is set to the expression being compiled.
17454 const statements = [
17455 ...preStatements,
17456 new DeclareVarStmt('$def', def, undefined, [StmtModifier.Exported]),
17457 ];
17458 const res = this.jitEvaluator.evaluateStatements(sourceUrl, statements, new R3JitReflector(context), /* enableSourceMaps */ true);
17459 return res['$def'];
17460 }
17461}
17462const USE_CLASS = Object.keys({ useClass: null })[0];
17463const USE_FACTORY = Object.keys({ useFactory: null })[0];
17464const USE_VALUE = Object.keys({ useValue: null })[0];
17465const USE_EXISTING = Object.keys({ useExisting: null })[0];
17466const wrapReference = function (value) {
17467 const wrapped = new WrappedNodeExpr(value);
17468 return { value: wrapped, type: wrapped };
17469};
17470function convertToR3QueryMetadata(facade) {
17471 return Object.assign({}, facade, { predicate: Array.isArray(facade.predicate) ? facade.predicate :
17472 new WrappedNodeExpr(facade.predicate), read: facade.read ? new WrappedNodeExpr(facade.read) : null, static: facade.static });
17473}
17474function convertDirectiveFacadeToMetadata(facade) {
17475 const inputsFromMetadata = parseInputOutputs(facade.inputs || []);
17476 const outputsFromMetadata = parseInputOutputs(facade.outputs || []);
17477 const propMetadata = facade.propMetadata;
17478 const inputsFromType = {};
17479 const outputsFromType = {};
17480 for (const field in propMetadata) {
17481 if (propMetadata.hasOwnProperty(field)) {
17482 propMetadata[field].forEach(ann => {
17483 if (isInput(ann)) {
17484 inputsFromType[field] =
17485 ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field;
17486 }
17487 else if (isOutput(ann)) {
17488 outputsFromType[field] = ann.bindingPropertyName || field;
17489 }
17490 });
17491 }
17492 }
17493 return Object.assign({}, facade, { typeSourceSpan: facade.typeSourceSpan, type: new WrappedNodeExpr(facade.type), deps: convertR3DependencyMetadataArray(facade.deps), host: extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host), inputs: Object.assign({}, inputsFromMetadata, inputsFromType), outputs: Object.assign({}, outputsFromMetadata, outputsFromType), queries: facade.queries.map(convertToR3QueryMetadata), providers: facade.providers != null ? new WrappedNodeExpr(facade.providers) : null, viewQueries: facade.viewQueries.map(convertToR3QueryMetadata) });
17494}
17495function wrapExpression(obj, property) {
17496 if (obj.hasOwnProperty(property)) {
17497 return new WrappedNodeExpr(obj[property]);
17498 }
17499 else {
17500 return undefined;
17501 }
17502}
17503function computeProvidedIn(providedIn) {
17504 if (providedIn == null || typeof providedIn === 'string') {
17505 return new LiteralExpr(providedIn);
17506 }
17507 else {
17508 return new WrappedNodeExpr(providedIn);
17509 }
17510}
17511function convertR3DependencyMetadata(facade) {
17512 let tokenExpr;
17513 if (facade.token === null) {
17514 tokenExpr = new LiteralExpr(null);
17515 }
17516 else if (facade.resolved === R3ResolvedDependencyType.Attribute) {
17517 tokenExpr = new LiteralExpr(facade.token);
17518 }
17519 else {
17520 tokenExpr = new WrappedNodeExpr(facade.token);
17521 }
17522 return {
17523 token: tokenExpr,
17524 resolved: facade.resolved,
17525 host: facade.host,
17526 optional: facade.optional,
17527 self: facade.self,
17528 skipSelf: facade.skipSelf
17529 };
17530}
17531function convertR3DependencyMetadataArray(facades) {
17532 return facades == null ? null : facades.map(convertR3DependencyMetadata);
17533}
17534function extractHostBindings(propMetadata, sourceSpan, host) {
17535 // First parse the declarations from the metadata.
17536 const bindings = parseHostBindings(host || {});
17537 // After that check host bindings for errors
17538 const errors = verifyHostBindings(bindings, sourceSpan);
17539 if (errors.length) {
17540 throw new Error(errors.map((error) => error.msg).join('\n'));
17541 }
17542 // Next, loop over the properties of the object, looking for @HostBinding and @HostListener.
17543 for (const field in propMetadata) {
17544 if (propMetadata.hasOwnProperty(field)) {
17545 propMetadata[field].forEach(ann => {
17546 if (isHostBinding(ann)) {
17547 bindings.properties[ann.hostPropertyName || field] = field;
17548 }
17549 else if (isHostListener(ann)) {
17550 bindings.listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`;
17551 }
17552 });
17553 }
17554 }
17555 return bindings;
17556}
17557function isHostBinding(value) {
17558 return value.ngMetadataName === 'HostBinding';
17559}
17560function isHostListener(value) {
17561 return value.ngMetadataName === 'HostListener';
17562}
17563function isInput(value) {
17564 return value.ngMetadataName === 'Input';
17565}
17566function isOutput(value) {
17567 return value.ngMetadataName === 'Output';
17568}
17569function parseInputOutputs(values) {
17570 return values.reduce((map, value) => {
17571 const [field, property] = value.split(',').map(piece => piece.trim());
17572 map[field] = property || field;
17573 return map;
17574 }, {});
17575}
17576function publishFacade(global) {
17577 const ng = global.ng || (global.ng = {});
17578 ng.ɵcompilerFacade = new CompilerFacadeImpl();
17579}
17580
17581/**
17582 * @license
17583 * Copyright Google Inc. All Rights Reserved.
17584 *
17585 * Use of this source code is governed by an MIT-style license that can be
17586 * found in the LICENSE file at https://angular.io/license
17587 */
17588const VERSION$1 = new Version('8.2.14');
17589
17590/**
17591 * @license
17592 * Copyright Google Inc. All Rights Reserved.
17593 *
17594 * Use of this source code is governed by an MIT-style license that can be
17595 * found in the LICENSE file at https://angular.io/license
17596 */
17597class CompilerConfig {
17598 constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, jitDevMode = false, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
17599 this.defaultEncapsulation = defaultEncapsulation;
17600 this.useJit = !!useJit;
17601 this.jitDevMode = !!jitDevMode;
17602 this.missingTranslation = missingTranslation;
17603 this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
17604 this.strictInjectionParameters = strictInjectionParameters === true;
17605 }
17606}
17607function preserveWhitespacesDefault(preserveWhitespacesOption, defaultSetting = false) {
17608 return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
17609}
17610
17611/**
17612 * @license
17613 * Copyright Google Inc. All Rights Reserved.
17614 *
17615 * Use of this source code is governed by an MIT-style license that can be
17616 * found in the LICENSE file at https://angular.io/license
17617 */
17618class DirectiveNormalizer {
17619 constructor(_resourceLoader, _urlResolver, _htmlParser, _config) {
17620 this._resourceLoader = _resourceLoader;
17621 this._urlResolver = _urlResolver;
17622 this._htmlParser = _htmlParser;
17623 this._config = _config;
17624 this._resourceLoaderCache = new Map();
17625 }
17626 clearCache() { this._resourceLoaderCache.clear(); }
17627 clearCacheFor(normalizedDirective) {
17628 if (!normalizedDirective.isComponent) {
17629 return;
17630 }
17631 const template = normalizedDirective.template;
17632 this._resourceLoaderCache.delete(template.templateUrl);
17633 template.externalStylesheets.forEach((stylesheet) => { this._resourceLoaderCache.delete(stylesheet.moduleUrl); });
17634 }
17635 _fetch(url) {
17636 let result = this._resourceLoaderCache.get(url);
17637 if (!result) {
17638 result = this._resourceLoader.get(url);
17639 this._resourceLoaderCache.set(url, result);
17640 }
17641 return result;
17642 }
17643 normalizeTemplate(prenormData) {
17644 if (isDefined(prenormData.template)) {
17645 if (isDefined(prenormData.templateUrl)) {
17646 throw syntaxError(`'${stringify(prenormData.componentType)}' component cannot define both template and templateUrl`);
17647 }
17648 if (typeof prenormData.template !== 'string') {
17649 throw syntaxError(`The template specified for component ${stringify(prenormData.componentType)} is not a string`);
17650 }
17651 }
17652 else if (isDefined(prenormData.templateUrl)) {
17653 if (typeof prenormData.templateUrl !== 'string') {
17654 throw syntaxError(`The templateUrl specified for component ${stringify(prenormData.componentType)} is not a string`);
17655 }
17656 }
17657 else {
17658 throw syntaxError(`No template specified for component ${stringify(prenormData.componentType)}`);
17659 }
17660 if (isDefined(prenormData.preserveWhitespaces) &&
17661 typeof prenormData.preserveWhitespaces !== 'boolean') {
17662 throw syntaxError(`The preserveWhitespaces option for component ${stringify(prenormData.componentType)} must be a boolean`);
17663 }
17664 return SyncAsync.then(this._preParseTemplate(prenormData), (preparsedTemplate) => this._normalizeTemplateMetadata(prenormData, preparsedTemplate));
17665 }
17666 _preParseTemplate(prenomData) {
17667 let template;
17668 let templateUrl;
17669 if (prenomData.template != null) {
17670 template = prenomData.template;
17671 templateUrl = prenomData.moduleUrl;
17672 }
17673 else {
17674 templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl);
17675 template = this._fetch(templateUrl);
17676 }
17677 return SyncAsync.then(template, (template) => this._preparseLoadedTemplate(prenomData, template, templateUrl));
17678 }
17679 _preparseLoadedTemplate(prenormData, template, templateAbsUrl) {
17680 const isInline = !!prenormData.template;
17681 const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation);
17682 const templateUrl = templateSourceUrl({ reference: prenormData.ngModuleType }, { type: { reference: prenormData.componentType } }, { isInline, templateUrl: templateAbsUrl });
17683 const rootNodesAndErrors = this._htmlParser.parse(template, templateUrl, { tokenizeExpansionForms: true, interpolationConfig });
17684 if (rootNodesAndErrors.errors.length > 0) {
17685 const errorString = rootNodesAndErrors.errors.join('\n');
17686 throw syntaxError(`Template parse errors:\n${errorString}`);
17687 }
17688 const templateMetadataStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: prenormData.styles, moduleUrl: prenormData.moduleUrl }));
17689 const visitor = new TemplatePreparseVisitor();
17690 visitAll$1(visitor, rootNodesAndErrors.rootNodes);
17691 const templateStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl }));
17692 const styles = templateMetadataStyles.styles.concat(templateStyles.styles);
17693 const inlineStyleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
17694 const styleUrls = this
17695 ._normalizeStylesheet(new CompileStylesheetMetadata({ styleUrls: prenormData.styleUrls, moduleUrl: prenormData.moduleUrl }))
17696 .styleUrls;
17697 return {
17698 template,
17699 templateUrl: templateAbsUrl, isInline,
17700 htmlAst: rootNodesAndErrors, styles, inlineStyleUrls, styleUrls,
17701 ngContentSelectors: visitor.ngContentSelectors,
17702 };
17703 }
17704 _normalizeTemplateMetadata(prenormData, preparsedTemplate) {
17705 return SyncAsync.then(this._loadMissingExternalStylesheets(preparsedTemplate.styleUrls.concat(preparsedTemplate.inlineStyleUrls)), (externalStylesheets) => this._normalizeLoadedTemplateMetadata(prenormData, preparsedTemplate, externalStylesheets));
17706 }
17707 _normalizeLoadedTemplateMetadata(prenormData, preparsedTemplate, stylesheets) {
17708 // Algorithm:
17709 // - produce exactly 1 entry per original styleUrl in
17710 // CompileTemplateMetadata.externalStylesheets with all styles inlined
17711 // - inline all styles that are referenced by the template into CompileTemplateMetadata.styles.
17712 // Reason: be able to determine how many stylesheets there are even without loading
17713 // the template nor the stylesheets, so we can create a stub for TypeScript always synchronously
17714 // (as resource loading may be async)
17715 const styles = [...preparsedTemplate.styles];
17716 this._inlineStyles(preparsedTemplate.inlineStyleUrls, stylesheets, styles);
17717 const styleUrls = preparsedTemplate.styleUrls;
17718 const externalStylesheets = styleUrls.map(styleUrl => {
17719 const stylesheet = stylesheets.get(styleUrl);
17720 const styles = [...stylesheet.styles];
17721 this._inlineStyles(stylesheet.styleUrls, stylesheets, styles);
17722 return new CompileStylesheetMetadata({ moduleUrl: styleUrl, styles: styles });
17723 });
17724 let encapsulation = prenormData.encapsulation;
17725 if (encapsulation == null) {
17726 encapsulation = this._config.defaultEncapsulation;
17727 }
17728 if (encapsulation === ViewEncapsulation.Emulated && styles.length === 0 &&
17729 styleUrls.length === 0) {
17730 encapsulation = ViewEncapsulation.None;
17731 }
17732 return new CompileTemplateMetadata({
17733 encapsulation,
17734 template: preparsedTemplate.template,
17735 templateUrl: preparsedTemplate.templateUrl,
17736 htmlAst: preparsedTemplate.htmlAst, styles, styleUrls,
17737 ngContentSelectors: preparsedTemplate.ngContentSelectors,
17738 animations: prenormData.animations,
17739 interpolation: prenormData.interpolation,
17740 isInline: preparsedTemplate.isInline, externalStylesheets,
17741 preserveWhitespaces: preserveWhitespacesDefault(prenormData.preserveWhitespaces, this._config.preserveWhitespaces),
17742 });
17743 }
17744 _inlineStyles(styleUrls, stylesheets, targetStyles) {
17745 styleUrls.forEach(styleUrl => {
17746 const stylesheet = stylesheets.get(styleUrl);
17747 stylesheet.styles.forEach(style => targetStyles.push(style));
17748 this._inlineStyles(stylesheet.styleUrls, stylesheets, targetStyles);
17749 });
17750 }
17751 _loadMissingExternalStylesheets(styleUrls, loadedStylesheets = new Map()) {
17752 return SyncAsync.then(SyncAsync.all(styleUrls.filter((styleUrl) => !loadedStylesheets.has(styleUrl))
17753 .map(styleUrl => SyncAsync.then(this._fetch(styleUrl), (loadedStyle) => {
17754 const stylesheet = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: [loadedStyle], moduleUrl: styleUrl }));
17755 loadedStylesheets.set(styleUrl, stylesheet);
17756 return this._loadMissingExternalStylesheets(stylesheet.styleUrls, loadedStylesheets);
17757 }))), (_) => loadedStylesheets);
17758 }
17759 _normalizeStylesheet(stylesheet) {
17760 const moduleUrl = stylesheet.moduleUrl;
17761 const allStyleUrls = stylesheet.styleUrls.filter(isStyleUrlResolvable)
17762 .map(url => this._urlResolver.resolve(moduleUrl, url));
17763 const allStyles = stylesheet.styles.map(style => {
17764 const styleWithImports = extractStyleUrls(this._urlResolver, moduleUrl, style);
17765 allStyleUrls.push(...styleWithImports.styleUrls);
17766 return styleWithImports.style;
17767 });
17768 return new CompileStylesheetMetadata({ styles: allStyles, styleUrls: allStyleUrls, moduleUrl: moduleUrl });
17769 }
17770}
17771class TemplatePreparseVisitor {
17772 constructor() {
17773 this.ngContentSelectors = [];
17774 this.styles = [];
17775 this.styleUrls = [];
17776 this.ngNonBindableStackCount = 0;
17777 }
17778 visitElement(ast, context) {
17779 const preparsedElement = preparseElement(ast);
17780 switch (preparsedElement.type) {
17781 case PreparsedElementType.NG_CONTENT:
17782 if (this.ngNonBindableStackCount === 0) {
17783 this.ngContentSelectors.push(preparsedElement.selectAttr);
17784 }
17785 break;
17786 case PreparsedElementType.STYLE:
17787 let textContent = '';
17788 ast.children.forEach(child => {
17789 if (child instanceof Text$3) {
17790 textContent += child.value;
17791 }
17792 });
17793 this.styles.push(textContent);
17794 break;
17795 case PreparsedElementType.STYLESHEET:
17796 this.styleUrls.push(preparsedElement.hrefAttr);
17797 break;
17798 default:
17799 break;
17800 }
17801 if (preparsedElement.nonBindable) {
17802 this.ngNonBindableStackCount++;
17803 }
17804 visitAll$1(this, ast.children);
17805 if (preparsedElement.nonBindable) {
17806 this.ngNonBindableStackCount--;
17807 }
17808 return null;
17809 }
17810 visitExpansion(ast, context) { visitAll$1(this, ast.cases); }
17811 visitExpansionCase(ast, context) {
17812 visitAll$1(this, ast.expression);
17813 }
17814 visitComment(ast, context) { return null; }
17815 visitAttribute(ast, context) { return null; }
17816 visitText(ast, context) { return null; }
17817}
17818
17819/**
17820 * @license
17821 * Copyright Google Inc. All Rights Reserved.
17822 *
17823 * Use of this source code is governed by an MIT-style license that can be
17824 * found in the LICENSE file at https://angular.io/license
17825 */
17826const QUERY_METADATA_IDENTIFIERS = [
17827 createViewChild,
17828 createViewChildren,
17829 createContentChild,
17830 createContentChildren,
17831];
17832/*
17833 * Resolve a `Type` for {@link Directive}.
17834 *
17835 * This interface can be overridden by the application developer to create custom behavior.
17836 *
17837 * See {@link Compiler}
17838 */
17839class DirectiveResolver {
17840 constructor(_reflector) {
17841 this._reflector = _reflector;
17842 }
17843 isDirective(type) {
17844 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
17845 return typeMetadata && typeMetadata.some(isDirectiveMetadata);
17846 }
17847 resolve(type, throwIfNotFound = true) {
17848 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
17849 if (typeMetadata) {
17850 const metadata = findLast(typeMetadata, isDirectiveMetadata);
17851 if (metadata) {
17852 const propertyMetadata = this._reflector.propMetadata(type);
17853 const guards = this._reflector.guards(type);
17854 return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
17855 }
17856 }
17857 if (throwIfNotFound) {
17858 throw new Error(`No Directive annotation found on ${stringify(type)}`);
17859 }
17860 return null;
17861 }
17862 _mergeWithPropertyMetadata(dm, propertyMetadata, guards, directiveType) {
17863 const inputs = [];
17864 const outputs = [];
17865 const host = {};
17866 const queries = {};
17867 Object.keys(propertyMetadata).forEach((propName) => {
17868 const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
17869 if (input) {
17870 if (input.bindingPropertyName) {
17871 inputs.push(`${propName}: ${input.bindingPropertyName}`);
17872 }
17873 else {
17874 inputs.push(propName);
17875 }
17876 }
17877 const output = findLast(propertyMetadata[propName], (a) => createOutput.isTypeOf(a));
17878 if (output) {
17879 if (output.bindingPropertyName) {
17880 outputs.push(`${propName}: ${output.bindingPropertyName}`);
17881 }
17882 else {
17883 outputs.push(propName);
17884 }
17885 }
17886 const hostBindings = propertyMetadata[propName].filter(a => createHostBinding.isTypeOf(a));
17887 hostBindings.forEach(hostBinding => {
17888 if (hostBinding.hostPropertyName) {
17889 const startWith = hostBinding.hostPropertyName[0];
17890 if (startWith === '(') {
17891 throw new Error(`@HostBinding can not bind to events. Use @HostListener instead.`);
17892 }
17893 else if (startWith === '[') {
17894 throw new Error(`@HostBinding parameter should be a property name, 'class.<name>', or 'attr.<name>'.`);
17895 }
17896 host[`[${hostBinding.hostPropertyName}]`] = propName;
17897 }
17898 else {
17899 host[`[${propName}]`] = propName;
17900 }
17901 });
17902 const hostListeners = propertyMetadata[propName].filter(a => createHostListener.isTypeOf(a));
17903 hostListeners.forEach(hostListener => {
17904 const args = hostListener.args || [];
17905 host[`(${hostListener.eventName})`] = `${propName}(${args.join(',')})`;
17906 });
17907 const query = findLast(propertyMetadata[propName], (a) => QUERY_METADATA_IDENTIFIERS.some(i => i.isTypeOf(a)));
17908 if (query) {
17909 queries[propName] = query;
17910 }
17911 });
17912 return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
17913 }
17914 _extractPublicName(def) { return splitAtColon(def, [null, def])[1].trim(); }
17915 _dedupeBindings(bindings) {
17916 const names = new Set();
17917 const publicNames = new Set();
17918 const reversedResult = [];
17919 // go last to first to allow later entries to overwrite previous entries
17920 for (let i = bindings.length - 1; i >= 0; i--) {
17921 const binding = bindings[i];
17922 const name = this._extractPublicName(binding);
17923 publicNames.add(name);
17924 if (!names.has(name)) {
17925 names.add(name);
17926 reversedResult.push(binding);
17927 }
17928 }
17929 return reversedResult.reverse();
17930 }
17931 _merge(directive, inputs, outputs, host, queries, guards, directiveType) {
17932 const mergedInputs = this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
17933 const mergedOutputs = this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
17934 const mergedHost = directive.host ? Object.assign({}, directive.host, host) : host;
17935 const mergedQueries = directive.queries ? Object.assign({}, directive.queries, queries) : queries;
17936 if (createComponent.isTypeOf(directive)) {
17937 const comp = directive;
17938 return createComponent({
17939 selector: comp.selector,
17940 inputs: mergedInputs,
17941 outputs: mergedOutputs,
17942 host: mergedHost,
17943 exportAs: comp.exportAs,
17944 moduleId: comp.moduleId,
17945 queries: mergedQueries,
17946 changeDetection: comp.changeDetection,
17947 providers: comp.providers,
17948 viewProviders: comp.viewProviders,
17949 entryComponents: comp.entryComponents,
17950 template: comp.template,
17951 templateUrl: comp.templateUrl,
17952 styles: comp.styles,
17953 styleUrls: comp.styleUrls,
17954 encapsulation: comp.encapsulation,
17955 animations: comp.animations,
17956 interpolation: comp.interpolation,
17957 preserveWhitespaces: directive.preserveWhitespaces,
17958 });
17959 }
17960 else {
17961 return createDirective({
17962 selector: directive.selector,
17963 inputs: mergedInputs,
17964 outputs: mergedOutputs,
17965 host: mergedHost,
17966 exportAs: directive.exportAs,
17967 queries: mergedQueries,
17968 providers: directive.providers, guards
17969 });
17970 }
17971 }
17972}
17973function isDirectiveMetadata(type) {
17974 return createDirective.isTypeOf(type) || createComponent.isTypeOf(type);
17975}
17976function findLast(arr, condition) {
17977 for (let i = arr.length - 1; i >= 0; i--) {
17978 if (condition(arr[i])) {
17979 return arr[i];
17980 }
17981 }
17982 return null;
17983}
17984
17985/**
17986 * @license
17987 * Copyright Google Inc. All Rights Reserved.
17988 *
17989 * Use of this source code is governed by an MIT-style license that can be
17990 * found in the LICENSE file at https://angular.io/license
17991 */
17992/**
17993 * An i18n error.
17994 */
17995class I18nError extends ParseError {
17996 constructor(span, msg) { super(span, msg); }
17997}
17998
17999/**
18000 * @license
18001 * Copyright Google Inc. All Rights Reserved.
18002 *
18003 * Use of this source code is governed by an MIT-style license that can be
18004 * found in the LICENSE file at https://angular.io/license
18005 */
18006const _I18N_ATTR = 'i18n';
18007const _I18N_ATTR_PREFIX = 'i18n-';
18008const _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/;
18009const MEANING_SEPARATOR = '|';
18010const ID_SEPARATOR = '@@';
18011let i18nCommentsWarned = false;
18012/**
18013 * Extract translatable messages from an html AST
18014 */
18015function extractMessages(nodes, interpolationConfig, implicitTags, implicitAttrs) {
18016 const visitor = new _Visitor$2(implicitTags, implicitAttrs);
18017 return visitor.extract(nodes, interpolationConfig);
18018}
18019function mergeTranslations(nodes, translations, interpolationConfig, implicitTags, implicitAttrs) {
18020 const visitor = new _Visitor$2(implicitTags, implicitAttrs);
18021 return visitor.merge(nodes, translations, interpolationConfig);
18022}
18023class ExtractionResult {
18024 constructor(messages, errors) {
18025 this.messages = messages;
18026 this.errors = errors;
18027 }
18028}
18029var _VisitorMode;
18030(function (_VisitorMode) {
18031 _VisitorMode[_VisitorMode["Extract"] = 0] = "Extract";
18032 _VisitorMode[_VisitorMode["Merge"] = 1] = "Merge";
18033})(_VisitorMode || (_VisitorMode = {}));
18034/**
18035 * This Visitor is used:
18036 * 1. to extract all the translatable strings from an html AST (see `extract()`),
18037 * 2. to replace the translatable strings with the actual translations (see `merge()`)
18038 *
18039 * @internal
18040 */
18041class _Visitor$2 {
18042 constructor(_implicitTags, _implicitAttrs) {
18043 this._implicitTags = _implicitTags;
18044 this._implicitAttrs = _implicitAttrs;
18045 }
18046 /**
18047 * Extracts the messages from the tree
18048 */
18049 extract(nodes, interpolationConfig) {
18050 this._init(_VisitorMode.Extract, interpolationConfig);
18051 nodes.forEach(node => node.visit(this, null));
18052 if (this._inI18nBlock) {
18053 this._reportError(nodes[nodes.length - 1], 'Unclosed block');
18054 }
18055 return new ExtractionResult(this._messages, this._errors);
18056 }
18057 /**
18058 * Returns a tree where all translatable nodes are translated
18059 */
18060 merge(nodes, translations, interpolationConfig) {
18061 this._init(_VisitorMode.Merge, interpolationConfig);
18062 this._translations = translations;
18063 // Construct a single fake root element
18064 const wrapper = new Element$1('wrapper', [], nodes, undefined, undefined, undefined);
18065 const translatedNode = wrapper.visit(this, null);
18066 if (this._inI18nBlock) {
18067 this._reportError(nodes[nodes.length - 1], 'Unclosed block');
18068 }
18069 return new ParseTreeResult(translatedNode.children, this._errors);
18070 }
18071 visitExpansionCase(icuCase, context) {
18072 // Parse cases for translatable html attributes
18073 const expression = visitAll$1(this, icuCase.expression, context);
18074 if (this._mode === _VisitorMode.Merge) {
18075 return new ExpansionCase(icuCase.value, expression, icuCase.sourceSpan, icuCase.valueSourceSpan, icuCase.expSourceSpan);
18076 }
18077 }
18078 visitExpansion(icu, context) {
18079 this._mayBeAddBlockChildren(icu);
18080 const wasInIcu = this._inIcu;
18081 if (!this._inIcu) {
18082 // nested ICU messages should not be extracted but top-level translated as a whole
18083 if (this._isInTranslatableSection) {
18084 this._addMessage([icu]);
18085 }
18086 this._inIcu = true;
18087 }
18088 const cases = visitAll$1(this, icu.cases, context);
18089 if (this._mode === _VisitorMode.Merge) {
18090 icu = new Expansion(icu.switchValue, icu.type, cases, icu.sourceSpan, icu.switchValueSourceSpan);
18091 }
18092 this._inIcu = wasInIcu;
18093 return icu;
18094 }
18095 visitComment(comment, context) {
18096 const isOpening = _isOpeningComment(comment);
18097 if (isOpening && this._isInTranslatableSection) {
18098 this._reportError(comment, 'Could not start a block inside a translatable section');
18099 return;
18100 }
18101 const isClosing = _isClosingComment(comment);
18102 if (isClosing && !this._inI18nBlock) {
18103 this._reportError(comment, 'Trying to close an unopened block');
18104 return;
18105 }
18106 if (!this._inI18nNode && !this._inIcu) {
18107 if (!this._inI18nBlock) {
18108 if (isOpening) {
18109 // deprecated from v5 you should use <ng-container i18n> instead of i18n comments
18110 if (!i18nCommentsWarned && console && console.warn) {
18111 i18nCommentsWarned = true;
18112 const details = comment.sourceSpan.details ? `, ${comment.sourceSpan.details}` : '';
18113 // TODO(ocombe): use a log service once there is a public one available
18114 console.warn(`I18n comments are deprecated, use an <ng-container> element instead (${comment.sourceSpan.start}${details})`);
18115 }
18116 this._inI18nBlock = true;
18117 this._blockStartDepth = this._depth;
18118 this._blockChildren = [];
18119 this._blockMeaningAndDesc =
18120 comment.value.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim();
18121 this._openTranslatableSection(comment);
18122 }
18123 }
18124 else {
18125 if (isClosing) {
18126 if (this._depth == this._blockStartDepth) {
18127 this._closeTranslatableSection(comment, this._blockChildren);
18128 this._inI18nBlock = false;
18129 const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc);
18130 // merge attributes in sections
18131 const nodes = this._translateMessage(comment, message);
18132 return visitAll$1(this, nodes);
18133 }
18134 else {
18135 this._reportError(comment, 'I18N blocks should not cross element boundaries');
18136 return;
18137 }
18138 }
18139 }
18140 }
18141 }
18142 visitText(text, context) {
18143 if (this._isInTranslatableSection) {
18144 this._mayBeAddBlockChildren(text);
18145 }
18146 return text;
18147 }
18148 visitElement(el, context) {
18149 this._mayBeAddBlockChildren(el);
18150 this._depth++;
18151 const wasInI18nNode = this._inI18nNode;
18152 const wasInImplicitNode = this._inImplicitNode;
18153 let childNodes = [];
18154 let translatedChildNodes = undefined;
18155 // Extract:
18156 // - top level nodes with the (implicit) "i18n" attribute if not already in a section
18157 // - ICU messages
18158 const i18nAttr = _getI18nAttr(el);
18159 const i18nMeta = i18nAttr ? i18nAttr.value : '';
18160 const isImplicit = this._implicitTags.some(tag => el.name === tag) && !this._inIcu &&
18161 !this._isInTranslatableSection;
18162 const isTopLevelImplicit = !wasInImplicitNode && isImplicit;
18163 this._inImplicitNode = wasInImplicitNode || isImplicit;
18164 if (!this._isInTranslatableSection && !this._inIcu) {
18165 if (i18nAttr || isTopLevelImplicit) {
18166 this._inI18nNode = true;
18167 const message = this._addMessage(el.children, i18nMeta);
18168 translatedChildNodes = this._translateMessage(el, message);
18169 }
18170 if (this._mode == _VisitorMode.Extract) {
18171 const isTranslatable = i18nAttr || isTopLevelImplicit;
18172 if (isTranslatable)
18173 this._openTranslatableSection(el);
18174 visitAll$1(this, el.children);
18175 if (isTranslatable)
18176 this._closeTranslatableSection(el, el.children);
18177 }
18178 }
18179 else {
18180 if (i18nAttr || isTopLevelImplicit) {
18181 this._reportError(el, 'Could not mark an element as translatable inside a translatable section');
18182 }
18183 if (this._mode == _VisitorMode.Extract) {
18184 // Descend into child nodes for extraction
18185 visitAll$1(this, el.children);
18186 }
18187 }
18188 if (this._mode === _VisitorMode.Merge) {
18189 const visitNodes = translatedChildNodes || el.children;
18190 visitNodes.forEach(child => {
18191 const visited = child.visit(this, context);
18192 if (visited && !this._isInTranslatableSection) {
18193 // Do not add the children from translatable sections (= i18n blocks here)
18194 // They will be added later in this loop when the block closes (i.e. on `<!-- /i18n -->`)
18195 childNodes = childNodes.concat(visited);
18196 }
18197 });
18198 }
18199 this._visitAttributesOf(el);
18200 this._depth--;
18201 this._inI18nNode = wasInI18nNode;
18202 this._inImplicitNode = wasInImplicitNode;
18203 if (this._mode === _VisitorMode.Merge) {
18204 const translatedAttrs = this._translateAttributes(el);
18205 return new Element$1(el.name, translatedAttrs, childNodes, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
18206 }
18207 return null;
18208 }
18209 visitAttribute(attribute, context) {
18210 throw new Error('unreachable code');
18211 }
18212 _init(mode, interpolationConfig) {
18213 this._mode = mode;
18214 this._inI18nBlock = false;
18215 this._inI18nNode = false;
18216 this._depth = 0;
18217 this._inIcu = false;
18218 this._msgCountAtSectionStart = undefined;
18219 this._errors = [];
18220 this._messages = [];
18221 this._inImplicitNode = false;
18222 this._createI18nMessage = createI18nMessageFactory(interpolationConfig);
18223 }
18224 // looks for translatable attributes
18225 _visitAttributesOf(el) {
18226 const explicitAttrNameToValue = {};
18227 const implicitAttrNames = this._implicitAttrs[el.name] || [];
18228 el.attrs.filter(attr => attr.name.startsWith(_I18N_ATTR_PREFIX))
18229 .forEach(attr => explicitAttrNameToValue[attr.name.slice(_I18N_ATTR_PREFIX.length)] =
18230 attr.value);
18231 el.attrs.forEach(attr => {
18232 if (attr.name in explicitAttrNameToValue) {
18233 this._addMessage([attr], explicitAttrNameToValue[attr.name]);
18234 }
18235 else if (implicitAttrNames.some(name => attr.name === name)) {
18236 this._addMessage([attr]);
18237 }
18238 });
18239 }
18240 // add a translatable message
18241 _addMessage(ast, msgMeta) {
18242 if (ast.length == 0 ||
18243 ast.length == 1 && ast[0] instanceof Attribute && !ast[0].value) {
18244 // Do not create empty messages
18245 return null;
18246 }
18247 const { meaning, description, id } = _parseMessageMeta(msgMeta);
18248 const message = this._createI18nMessage(ast, meaning, description, id);
18249 this._messages.push(message);
18250 return message;
18251 }
18252 // Translates the given message given the `TranslationBundle`
18253 // This is used for translating elements / blocks - see `_translateAttributes` for attributes
18254 // no-op when called in extraction mode (returns [])
18255 _translateMessage(el, message) {
18256 if (message && this._mode === _VisitorMode.Merge) {
18257 const nodes = this._translations.get(message);
18258 if (nodes) {
18259 return nodes;
18260 }
18261 this._reportError(el, `Translation unavailable for message id="${this._translations.digest(message)}"`);
18262 }
18263 return [];
18264 }
18265 // translate the attributes of an element and remove i18n specific attributes
18266 _translateAttributes(el) {
18267 const attributes = el.attrs;
18268 const i18nParsedMessageMeta = {};
18269 attributes.forEach(attr => {
18270 if (attr.name.startsWith(_I18N_ATTR_PREFIX)) {
18271 i18nParsedMessageMeta[attr.name.slice(_I18N_ATTR_PREFIX.length)] =
18272 _parseMessageMeta(attr.value);
18273 }
18274 });
18275 const translatedAttributes = [];
18276 attributes.forEach((attr) => {
18277 if (attr.name === _I18N_ATTR || attr.name.startsWith(_I18N_ATTR_PREFIX)) {
18278 // strip i18n specific attributes
18279 return;
18280 }
18281 if (attr.value && attr.value != '' && i18nParsedMessageMeta.hasOwnProperty(attr.name)) {
18282 const { meaning, description, id } = i18nParsedMessageMeta[attr.name];
18283 const message = this._createI18nMessage([attr], meaning, description, id);
18284 const nodes = this._translations.get(message);
18285 if (nodes) {
18286 if (nodes.length == 0) {
18287 translatedAttributes.push(new Attribute(attr.name, '', attr.sourceSpan));
18288 }
18289 else if (nodes[0] instanceof Text$3) {
18290 const value = nodes[0].value;
18291 translatedAttributes.push(new Attribute(attr.name, value, attr.sourceSpan));
18292 }
18293 else {
18294 this._reportError(el, `Unexpected translation for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
18295 }
18296 }
18297 else {
18298 this._reportError(el, `Translation unavailable for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
18299 }
18300 }
18301 else {
18302 translatedAttributes.push(attr);
18303 }
18304 });
18305 return translatedAttributes;
18306 }
18307 /**
18308 * Add the node as a child of the block when:
18309 * - we are in a block,
18310 * - we are not inside a ICU message (those are handled separately),
18311 * - the node is a "direct child" of the block
18312 */
18313 _mayBeAddBlockChildren(node) {
18314 if (this._inI18nBlock && !this._inIcu && this._depth == this._blockStartDepth) {
18315 this._blockChildren.push(node);
18316 }
18317 }
18318 /**
18319 * Marks the start of a section, see `_closeTranslatableSection`
18320 */
18321 _openTranslatableSection(node) {
18322 if (this._isInTranslatableSection) {
18323 this._reportError(node, 'Unexpected section start');
18324 }
18325 else {
18326 this._msgCountAtSectionStart = this._messages.length;
18327 }
18328 }
18329 /**
18330 * A translatable section could be:
18331 * - the content of translatable element,
18332 * - nodes between `<!-- i18n -->` and `<!-- /i18n -->` comments
18333 */
18334 get _isInTranslatableSection() {
18335 return this._msgCountAtSectionStart !== void 0;
18336 }
18337 /**
18338 * Terminates a section.
18339 *
18340 * If a section has only one significant children (comments not significant) then we should not
18341 * keep the message from this children:
18342 *
18343 * `<p i18n="meaning|description">{ICU message}</p>` would produce two messages:
18344 * - one for the <p> content with meaning and description,
18345 * - another one for the ICU message.
18346 *
18347 * In this case the last message is discarded as it contains less information (the AST is
18348 * otherwise identical).
18349 *
18350 * Note that we should still keep messages extracted from attributes inside the section (ie in the
18351 * ICU message here)
18352 */
18353 _closeTranslatableSection(node, directChildren) {
18354 if (!this._isInTranslatableSection) {
18355 this._reportError(node, 'Unexpected section end');
18356 return;
18357 }
18358 const startIndex = this._msgCountAtSectionStart;
18359 const significantChildren = directChildren.reduce((count, node) => count + (node instanceof Comment ? 0 : 1), 0);
18360 if (significantChildren == 1) {
18361 for (let i = this._messages.length - 1; i >= startIndex; i--) {
18362 const ast = this._messages[i].nodes;
18363 if (!(ast.length == 1 && ast[0] instanceof Text$1)) {
18364 this._messages.splice(i, 1);
18365 break;
18366 }
18367 }
18368 }
18369 this._msgCountAtSectionStart = undefined;
18370 }
18371 _reportError(node, msg) {
18372 this._errors.push(new I18nError(node.sourceSpan, msg));
18373 }
18374}
18375function _isOpeningComment(n) {
18376 return !!(n instanceof Comment && n.value && n.value.startsWith('i18n'));
18377}
18378function _isClosingComment(n) {
18379 return !!(n instanceof Comment && n.value && n.value === '/i18n');
18380}
18381function _getI18nAttr(p) {
18382 return p.attrs.find(attr => attr.name === _I18N_ATTR) || null;
18383}
18384function _parseMessageMeta(i18n) {
18385 if (!i18n)
18386 return { meaning: '', description: '', id: '' };
18387 const idIndex = i18n.indexOf(ID_SEPARATOR);
18388 const descIndex = i18n.indexOf(MEANING_SEPARATOR);
18389 const [meaningAndDesc, id] = (idIndex > -1) ? [i18n.slice(0, idIndex), i18n.slice(idIndex + 2)] : [i18n, ''];
18390 const [meaning, description] = (descIndex > -1) ?
18391 [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
18392 ['', meaningAndDesc];
18393 return { meaning, description, id };
18394}
18395
18396/**
18397 * @license
18398 * Copyright Google Inc. All Rights Reserved.
18399 *
18400 * Use of this source code is governed by an MIT-style license that can be
18401 * found in the LICENSE file at https://angular.io/license
18402 */
18403class XmlTagDefinition {
18404 constructor() {
18405 this.closedByParent = false;
18406 this.contentType = TagContentType.PARSABLE_DATA;
18407 this.isVoid = false;
18408 this.ignoreFirstLf = false;
18409 this.canSelfClose = true;
18410 }
18411 requireExtraParent(currentParent) { return false; }
18412 isClosedByChild(name) { return false; }
18413}
18414const _TAG_DEFINITION = new XmlTagDefinition();
18415function getXmlTagDefinition(tagName) {
18416 return _TAG_DEFINITION;
18417}
18418
18419/**
18420 * @license
18421 * Copyright Google Inc. All Rights Reserved.
18422 *
18423 * Use of this source code is governed by an MIT-style license that can be
18424 * found in the LICENSE file at https://angular.io/license
18425 */
18426class XmlParser extends Parser {
18427 constructor() { super(getXmlTagDefinition); }
18428 parse(source, url, options) {
18429 return super.parse(source, url, options);
18430 }
18431}
18432
18433/**
18434 * @license
18435 * Copyright Google Inc. All Rights Reserved.
18436 *
18437 * Use of this source code is governed by an MIT-style license that can be
18438 * found in the LICENSE file at https://angular.io/license
18439 */
18440const _VERSION = '1.2';
18441const _XMLNS = 'urn:oasis:names:tc:xliff:document:1.2';
18442// TODO(vicb): make this a param (s/_/-/)
18443const _DEFAULT_SOURCE_LANG = 'en';
18444const _PLACEHOLDER_TAG$1 = 'x';
18445const _MARKER_TAG = 'mrk';
18446const _FILE_TAG = 'file';
18447const _SOURCE_TAG$1 = 'source';
18448const _SEGMENT_SOURCE_TAG = 'seg-source';
18449const _ALT_TRANS_TAG = 'alt-trans';
18450const _TARGET_TAG = 'target';
18451const _UNIT_TAG = 'trans-unit';
18452const _CONTEXT_GROUP_TAG = 'context-group';
18453const _CONTEXT_TAG = 'context';
18454// http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html
18455// http://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html
18456class Xliff extends Serializer {
18457 write(messages, locale) {
18458 const visitor = new _WriteVisitor();
18459 const transUnits = [];
18460 messages.forEach(message => {
18461 let contextTags = [];
18462 message.sources.forEach((source) => {
18463 let contextGroupTag = new Tag(_CONTEXT_GROUP_TAG, { purpose: 'location' });
18464 contextGroupTag.children.push(new CR(10), new Tag(_CONTEXT_TAG, { 'context-type': 'sourcefile' }, [new Text$2(source.filePath)]), new CR(10), new Tag(_CONTEXT_TAG, { 'context-type': 'linenumber' }, [new Text$2(`${source.startLine}`)]), new CR(8));
18465 contextTags.push(new CR(8), contextGroupTag);
18466 });
18467 const transUnit = new Tag(_UNIT_TAG, { id: message.id, datatype: 'html' });
18468 transUnit.children.push(new CR(8), new Tag(_SOURCE_TAG$1, {}, visitor.serialize(message.nodes)), ...contextTags);
18469 if (message.description) {
18470 transUnit.children.push(new CR(8), new Tag('note', { priority: '1', from: 'description' }, [new Text$2(message.description)]));
18471 }
18472 if (message.meaning) {
18473 transUnit.children.push(new CR(8), new Tag('note', { priority: '1', from: 'meaning' }, [new Text$2(message.meaning)]));
18474 }
18475 transUnit.children.push(new CR(6));
18476 transUnits.push(new CR(6), transUnit);
18477 });
18478 const body = new Tag('body', {}, [...transUnits, new CR(4)]);
18479 const file = new Tag('file', {
18480 'source-language': locale || _DEFAULT_SOURCE_LANG,
18481 datatype: 'plaintext',
18482 original: 'ng2.template',
18483 }, [new CR(4), body, new CR(2)]);
18484 const xliff = new Tag('xliff', { version: _VERSION, xmlns: _XMLNS }, [new CR(2), file, new CR()]);
18485 return serialize([
18486 new Declaration({ version: '1.0', encoding: 'UTF-8' }), new CR(), xliff, new CR()
18487 ]);
18488 }
18489 load(content, url) {
18490 // xliff to xml nodes
18491 const xliffParser = new XliffParser();
18492 const { locale, msgIdToHtml, errors } = xliffParser.parse(content, url);
18493 // xml nodes to i18n nodes
18494 const i18nNodesByMsgId = {};
18495 const converter = new XmlToI18n();
18496 Object.keys(msgIdToHtml).forEach(msgId => {
18497 const { i18nNodes, errors: e } = converter.convert(msgIdToHtml[msgId], url);
18498 errors.push(...e);
18499 i18nNodesByMsgId[msgId] = i18nNodes;
18500 });
18501 if (errors.length) {
18502 throw new Error(`xliff parse errors:\n${errors.join('\n')}`);
18503 }
18504 return { locale: locale, i18nNodesByMsgId };
18505 }
18506 digest(message) { return digest(message); }
18507}
18508class _WriteVisitor {
18509 visitText(text, context) { return [new Text$2(text.value)]; }
18510 visitContainer(container, context) {
18511 const nodes = [];
18512 container.children.forEach((node) => nodes.push(...node.visit(this)));
18513 return nodes;
18514 }
18515 visitIcu(icu, context) {
18516 const nodes = [new Text$2(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
18517 Object.keys(icu.cases).forEach((c) => {
18518 nodes.push(new Text$2(`${c} {`), ...icu.cases[c].visit(this), new Text$2(`} `));
18519 });
18520 nodes.push(new Text$2(`}`));
18521 return nodes;
18522 }
18523 visitTagPlaceholder(ph, context) {
18524 const ctype = getCtypeForTag(ph.tag);
18525 if (ph.isVoid) {
18526 // void tags have no children nor closing tags
18527 return [new Tag(_PLACEHOLDER_TAG$1, { id: ph.startName, ctype, 'equiv-text': `<${ph.tag}/>` })];
18528 }
18529 const startTagPh = new Tag(_PLACEHOLDER_TAG$1, { id: ph.startName, ctype, 'equiv-text': `<${ph.tag}>` });
18530 const closeTagPh = new Tag(_PLACEHOLDER_TAG$1, { id: ph.closeName, ctype, 'equiv-text': `</${ph.tag}>` });
18531 return [startTagPh, ...this.serialize(ph.children), closeTagPh];
18532 }
18533 visitPlaceholder(ph, context) {
18534 return [new Tag(_PLACEHOLDER_TAG$1, { id: ph.name, 'equiv-text': `{{${ph.value}}}` })];
18535 }
18536 visitIcuPlaceholder(ph, context) {
18537 const equivText = `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' ')}}`;
18538 return [new Tag(_PLACEHOLDER_TAG$1, { id: ph.name, 'equiv-text': equivText })];
18539 }
18540 serialize(nodes) {
18541 return [].concat(...nodes.map(node => node.visit(this)));
18542 }
18543}
18544// TODO(vicb): add error management (structure)
18545// Extract messages as xml nodes from the xliff file
18546class XliffParser {
18547 constructor() {
18548 this._locale = null;
18549 }
18550 parse(xliff, url) {
18551 this._unitMlString = null;
18552 this._msgIdToHtml = {};
18553 const xml = new XmlParser().parse(xliff, url);
18554 this._errors = xml.errors;
18555 visitAll$1(this, xml.rootNodes, null);
18556 return {
18557 msgIdToHtml: this._msgIdToHtml,
18558 errors: this._errors,
18559 locale: this._locale,
18560 };
18561 }
18562 visitElement(element, context) {
18563 switch (element.name) {
18564 case _UNIT_TAG:
18565 this._unitMlString = null;
18566 const idAttr = element.attrs.find((attr) => attr.name === 'id');
18567 if (!idAttr) {
18568 this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`);
18569 }
18570 else {
18571 const id = idAttr.value;
18572 if (this._msgIdToHtml.hasOwnProperty(id)) {
18573 this._addError(element, `Duplicated translations for msg ${id}`);
18574 }
18575 else {
18576 visitAll$1(this, element.children, null);
18577 if (typeof this._unitMlString === 'string') {
18578 this._msgIdToHtml[id] = this._unitMlString;
18579 }
18580 else {
18581 this._addError(element, `Message ${id} misses a translation`);
18582 }
18583 }
18584 }
18585 break;
18586 // ignore those tags
18587 case _SOURCE_TAG$1:
18588 case _SEGMENT_SOURCE_TAG:
18589 case _ALT_TRANS_TAG:
18590 break;
18591 case _TARGET_TAG:
18592 const innerTextStart = element.startSourceSpan.end.offset;
18593 const innerTextEnd = element.endSourceSpan.start.offset;
18594 const content = element.startSourceSpan.start.file.content;
18595 const innerText = content.slice(innerTextStart, innerTextEnd);
18596 this._unitMlString = innerText;
18597 break;
18598 case _FILE_TAG:
18599 const localeAttr = element.attrs.find((attr) => attr.name === 'target-language');
18600 if (localeAttr) {
18601 this._locale = localeAttr.value;
18602 }
18603 visitAll$1(this, element.children, null);
18604 break;
18605 default:
18606 // TODO(vicb): assert file structure, xliff version
18607 // For now only recurse on unhandled nodes
18608 visitAll$1(this, element.children, null);
18609 }
18610 }
18611 visitAttribute(attribute, context) { }
18612 visitText(text, context) { }
18613 visitComment(comment, context) { }
18614 visitExpansion(expansion, context) { }
18615 visitExpansionCase(expansionCase, context) { }
18616 _addError(node, message) {
18617 this._errors.push(new I18nError(node.sourceSpan, message));
18618 }
18619}
18620// Convert ml nodes (xliff syntax) to i18n nodes
18621class XmlToI18n {
18622 convert(message, url) {
18623 const xmlIcu = new XmlParser().parse(message, url, { tokenizeExpansionForms: true });
18624 this._errors = xmlIcu.errors;
18625 const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
18626 [] :
18627 [].concat(...visitAll$1(this, xmlIcu.rootNodes));
18628 return {
18629 i18nNodes: i18nNodes,
18630 errors: this._errors,
18631 };
18632 }
18633 visitText(text, context) { return new Text$1(text.value, text.sourceSpan); }
18634 visitElement(el, context) {
18635 if (el.name === _PLACEHOLDER_TAG$1) {
18636 const nameAttr = el.attrs.find((attr) => attr.name === 'id');
18637 if (nameAttr) {
18638 return new Placeholder('', nameAttr.value, el.sourceSpan);
18639 }
18640 this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "id" attribute`);
18641 return null;
18642 }
18643 if (el.name === _MARKER_TAG) {
18644 return [].concat(...visitAll$1(this, el.children));
18645 }
18646 this._addError(el, `Unexpected tag`);
18647 return null;
18648 }
18649 visitExpansion(icu, context) {
18650 const caseMap = {};
18651 visitAll$1(this, icu.cases).forEach((c) => {
18652 caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
18653 });
18654 return new Icu$1(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
18655 }
18656 visitExpansionCase(icuCase, context) {
18657 return {
18658 value: icuCase.value,
18659 nodes: visitAll$1(this, icuCase.expression),
18660 };
18661 }
18662 visitComment(comment, context) { }
18663 visitAttribute(attribute, context) { }
18664 _addError(node, message) {
18665 this._errors.push(new I18nError(node.sourceSpan, message));
18666 }
18667}
18668function getCtypeForTag(tag) {
18669 switch (tag.toLowerCase()) {
18670 case 'br':
18671 return 'lb';
18672 case 'img':
18673 return 'image';
18674 default:
18675 return `x-${tag}`;
18676 }
18677}
18678
18679/**
18680 * @license
18681 * Copyright Google Inc. All Rights Reserved.
18682 *
18683 * Use of this source code is governed by an MIT-style license that can be
18684 * found in the LICENSE file at https://angular.io/license
18685 */
18686const _VERSION$1 = '2.0';
18687const _XMLNS$1 = 'urn:oasis:names:tc:xliff:document:2.0';
18688// TODO(vicb): make this a param (s/_/-/)
18689const _DEFAULT_SOURCE_LANG$1 = 'en';
18690const _PLACEHOLDER_TAG$2 = 'ph';
18691const _PLACEHOLDER_SPANNING_TAG = 'pc';
18692const _MARKER_TAG$1 = 'mrk';
18693const _XLIFF_TAG = 'xliff';
18694const _SOURCE_TAG$2 = 'source';
18695const _TARGET_TAG$1 = 'target';
18696const _UNIT_TAG$1 = 'unit';
18697// http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html
18698class Xliff2 extends Serializer {
18699 write(messages, locale) {
18700 const visitor = new _WriteVisitor$1();
18701 const units = [];
18702 messages.forEach(message => {
18703 const unit = new Tag(_UNIT_TAG$1, { id: message.id });
18704 const notes = new Tag('notes');
18705 if (message.description || message.meaning) {
18706 if (message.description) {
18707 notes.children.push(new CR(8), new Tag('note', { category: 'description' }, [new Text$2(message.description)]));
18708 }
18709 if (message.meaning) {
18710 notes.children.push(new CR(8), new Tag('note', { category: 'meaning' }, [new Text$2(message.meaning)]));
18711 }
18712 }
18713 message.sources.forEach((source) => {
18714 notes.children.push(new CR(8), new Tag('note', { category: 'location' }, [
18715 new Text$2(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)
18716 ]));
18717 });
18718 notes.children.push(new CR(6));
18719 unit.children.push(new CR(6), notes);
18720 const segment = new Tag('segment');
18721 segment.children.push(new CR(8), new Tag(_SOURCE_TAG$2, {}, visitor.serialize(message.nodes)), new CR(6));
18722 unit.children.push(new CR(6), segment, new CR(4));
18723 units.push(new CR(4), unit);
18724 });
18725 const file = new Tag('file', { 'original': 'ng.template', id: 'ngi18n' }, [...units, new CR(2)]);
18726 const xliff = new Tag(_XLIFF_TAG, { version: _VERSION$1, xmlns: _XMLNS$1, srcLang: locale || _DEFAULT_SOURCE_LANG$1 }, [new CR(2), file, new CR()]);
18727 return serialize([
18728 new Declaration({ version: '1.0', encoding: 'UTF-8' }), new CR(), xliff, new CR()
18729 ]);
18730 }
18731 load(content, url) {
18732 // xliff to xml nodes
18733 const xliff2Parser = new Xliff2Parser();
18734 const { locale, msgIdToHtml, errors } = xliff2Parser.parse(content, url);
18735 // xml nodes to i18n nodes
18736 const i18nNodesByMsgId = {};
18737 const converter = new XmlToI18n$1();
18738 Object.keys(msgIdToHtml).forEach(msgId => {
18739 const { i18nNodes, errors: e } = converter.convert(msgIdToHtml[msgId], url);
18740 errors.push(...e);
18741 i18nNodesByMsgId[msgId] = i18nNodes;
18742 });
18743 if (errors.length) {
18744 throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`);
18745 }
18746 return { locale: locale, i18nNodesByMsgId };
18747 }
18748 digest(message) { return decimalDigest(message); }
18749}
18750class _WriteVisitor$1 {
18751 visitText(text, context) { return [new Text$2(text.value)]; }
18752 visitContainer(container, context) {
18753 const nodes = [];
18754 container.children.forEach((node) => nodes.push(...node.visit(this)));
18755 return nodes;
18756 }
18757 visitIcu(icu, context) {
18758 const nodes = [new Text$2(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
18759 Object.keys(icu.cases).forEach((c) => {
18760 nodes.push(new Text$2(`${c} {`), ...icu.cases[c].visit(this), new Text$2(`} `));
18761 });
18762 nodes.push(new Text$2(`}`));
18763 return nodes;
18764 }
18765 visitTagPlaceholder(ph, context) {
18766 const type = getTypeForTag(ph.tag);
18767 if (ph.isVoid) {
18768 const tagPh = new Tag(_PLACEHOLDER_TAG$2, {
18769 id: (this._nextPlaceholderId++).toString(),
18770 equiv: ph.startName,
18771 type: type,
18772 disp: `<${ph.tag}/>`,
18773 });
18774 return [tagPh];
18775 }
18776 const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
18777 id: (this._nextPlaceholderId++).toString(),
18778 equivStart: ph.startName,
18779 equivEnd: ph.closeName,
18780 type: type,
18781 dispStart: `<${ph.tag}>`,
18782 dispEnd: `</${ph.tag}>`,
18783 });
18784 const nodes = [].concat(...ph.children.map(node => node.visit(this)));
18785 if (nodes.length) {
18786 nodes.forEach((node) => tagPc.children.push(node));
18787 }
18788 else {
18789 tagPc.children.push(new Text$2(''));
18790 }
18791 return [tagPc];
18792 }
18793 visitPlaceholder(ph, context) {
18794 const idStr = (this._nextPlaceholderId++).toString();
18795 return [new Tag(_PLACEHOLDER_TAG$2, {
18796 id: idStr,
18797 equiv: ph.name,
18798 disp: `{{${ph.value}}}`,
18799 })];
18800 }
18801 visitIcuPlaceholder(ph, context) {
18802 const cases = Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' ');
18803 const idStr = (this._nextPlaceholderId++).toString();
18804 return [new Tag(_PLACEHOLDER_TAG$2, { id: idStr, equiv: ph.name, disp: `{${ph.value.expression}, ${ph.value.type}, ${cases}}` })];
18805 }
18806 serialize(nodes) {
18807 this._nextPlaceholderId = 0;
18808 return [].concat(...nodes.map(node => node.visit(this)));
18809 }
18810}
18811// Extract messages as xml nodes from the xliff file
18812class Xliff2Parser {
18813 constructor() {
18814 this._locale = null;
18815 }
18816 parse(xliff, url) {
18817 this._unitMlString = null;
18818 this._msgIdToHtml = {};
18819 const xml = new XmlParser().parse(xliff, url);
18820 this._errors = xml.errors;
18821 visitAll$1(this, xml.rootNodes, null);
18822 return {
18823 msgIdToHtml: this._msgIdToHtml,
18824 errors: this._errors,
18825 locale: this._locale,
18826 };
18827 }
18828 visitElement(element, context) {
18829 switch (element.name) {
18830 case _UNIT_TAG$1:
18831 this._unitMlString = null;
18832 const idAttr = element.attrs.find((attr) => attr.name === 'id');
18833 if (!idAttr) {
18834 this._addError(element, `<${_UNIT_TAG$1}> misses the "id" attribute`);
18835 }
18836 else {
18837 const id = idAttr.value;
18838 if (this._msgIdToHtml.hasOwnProperty(id)) {
18839 this._addError(element, `Duplicated translations for msg ${id}`);
18840 }
18841 else {
18842 visitAll$1(this, element.children, null);
18843 if (typeof this._unitMlString === 'string') {
18844 this._msgIdToHtml[id] = this._unitMlString;
18845 }
18846 else {
18847 this._addError(element, `Message ${id} misses a translation`);
18848 }
18849 }
18850 }
18851 break;
18852 case _SOURCE_TAG$2:
18853 // ignore source message
18854 break;
18855 case _TARGET_TAG$1:
18856 const innerTextStart = element.startSourceSpan.end.offset;
18857 const innerTextEnd = element.endSourceSpan.start.offset;
18858 const content = element.startSourceSpan.start.file.content;
18859 const innerText = content.slice(innerTextStart, innerTextEnd);
18860 this._unitMlString = innerText;
18861 break;
18862 case _XLIFF_TAG:
18863 const localeAttr = element.attrs.find((attr) => attr.name === 'trgLang');
18864 if (localeAttr) {
18865 this._locale = localeAttr.value;
18866 }
18867 const versionAttr = element.attrs.find((attr) => attr.name === 'version');
18868 if (versionAttr) {
18869 const version = versionAttr.value;
18870 if (version !== '2.0') {
18871 this._addError(element, `The XLIFF file version ${version} is not compatible with XLIFF 2.0 serializer`);
18872 }
18873 else {
18874 visitAll$1(this, element.children, null);
18875 }
18876 }
18877 break;
18878 default:
18879 visitAll$1(this, element.children, null);
18880 }
18881 }
18882 visitAttribute(attribute, context) { }
18883 visitText(text, context) { }
18884 visitComment(comment, context) { }
18885 visitExpansion(expansion, context) { }
18886 visitExpansionCase(expansionCase, context) { }
18887 _addError(node, message) {
18888 this._errors.push(new I18nError(node.sourceSpan, message));
18889 }
18890}
18891// Convert ml nodes (xliff syntax) to i18n nodes
18892class XmlToI18n$1 {
18893 convert(message, url) {
18894 const xmlIcu = new XmlParser().parse(message, url, { tokenizeExpansionForms: true });
18895 this._errors = xmlIcu.errors;
18896 const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
18897 [] :
18898 [].concat(...visitAll$1(this, xmlIcu.rootNodes));
18899 return {
18900 i18nNodes,
18901 errors: this._errors,
18902 };
18903 }
18904 visitText(text, context) { return new Text$1(text.value, text.sourceSpan); }
18905 visitElement(el, context) {
18906 switch (el.name) {
18907 case _PLACEHOLDER_TAG$2:
18908 const nameAttr = el.attrs.find((attr) => attr.name === 'equiv');
18909 if (nameAttr) {
18910 return [new Placeholder('', nameAttr.value, el.sourceSpan)];
18911 }
18912 this._addError(el, `<${_PLACEHOLDER_TAG$2}> misses the "equiv" attribute`);
18913 break;
18914 case _PLACEHOLDER_SPANNING_TAG:
18915 const startAttr = el.attrs.find((attr) => attr.name === 'equivStart');
18916 const endAttr = el.attrs.find((attr) => attr.name === 'equivEnd');
18917 if (!startAttr) {
18918 this._addError(el, `<${_PLACEHOLDER_TAG$2}> misses the "equivStart" attribute`);
18919 }
18920 else if (!endAttr) {
18921 this._addError(el, `<${_PLACEHOLDER_TAG$2}> misses the "equivEnd" attribute`);
18922 }
18923 else {
18924 const startId = startAttr.value;
18925 const endId = endAttr.value;
18926 const nodes = [];
18927 return nodes.concat(new Placeholder('', startId, el.sourceSpan), ...el.children.map(node => node.visit(this, null)), new Placeholder('', endId, el.sourceSpan));
18928 }
18929 break;
18930 case _MARKER_TAG$1:
18931 return [].concat(...visitAll$1(this, el.children));
18932 default:
18933 this._addError(el, `Unexpected tag`);
18934 }
18935 return null;
18936 }
18937 visitExpansion(icu, context) {
18938 const caseMap = {};
18939 visitAll$1(this, icu.cases).forEach((c) => {
18940 caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
18941 });
18942 return new Icu$1(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
18943 }
18944 visitExpansionCase(icuCase, context) {
18945 return {
18946 value: icuCase.value,
18947 nodes: [].concat(...visitAll$1(this, icuCase.expression)),
18948 };
18949 }
18950 visitComment(comment, context) { }
18951 visitAttribute(attribute, context) { }
18952 _addError(node, message) {
18953 this._errors.push(new I18nError(node.sourceSpan, message));
18954 }
18955}
18956function getTypeForTag(tag) {
18957 switch (tag.toLowerCase()) {
18958 case 'br':
18959 case 'b':
18960 case 'i':
18961 case 'u':
18962 return 'fmt';
18963 case 'img':
18964 return 'image';
18965 case 'a':
18966 return 'link';
18967 default:
18968 return 'other';
18969 }
18970}
18971
18972/**
18973 * @license
18974 * Copyright Google Inc. All Rights Reserved.
18975 *
18976 * Use of this source code is governed by an MIT-style license that can be
18977 * found in the LICENSE file at https://angular.io/license
18978 */
18979const _TRANSLATIONS_TAG = 'translationbundle';
18980const _TRANSLATION_TAG = 'translation';
18981const _PLACEHOLDER_TAG$3 = 'ph';
18982class Xtb extends Serializer {
18983 write(messages, locale) { throw new Error('Unsupported'); }
18984 load(content, url) {
18985 // xtb to xml nodes
18986 const xtbParser = new XtbParser();
18987 const { locale, msgIdToHtml, errors } = xtbParser.parse(content, url);
18988 // xml nodes to i18n nodes
18989 const i18nNodesByMsgId = {};
18990 const converter = new XmlToI18n$2();
18991 // Because we should be able to load xtb files that rely on features not supported by angular,
18992 // we need to delay the conversion of html to i18n nodes so that non angular messages are not
18993 // converted
18994 Object.keys(msgIdToHtml).forEach(msgId => {
18995 const valueFn = function () {
18996 const { i18nNodes, errors } = converter.convert(msgIdToHtml[msgId], url);
18997 if (errors.length) {
18998 throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
18999 }
19000 return i18nNodes;
19001 };
19002 createLazyProperty(i18nNodesByMsgId, msgId, valueFn);
19003 });
19004 if (errors.length) {
19005 throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
19006 }
19007 return { locale: locale, i18nNodesByMsgId };
19008 }
19009 digest(message) { return digest$1(message); }
19010 createNameMapper(message) {
19011 return new SimplePlaceholderMapper(message, toPublicName);
19012 }
19013}
19014function createLazyProperty(messages, id, valueFn) {
19015 Object.defineProperty(messages, id, {
19016 configurable: true,
19017 enumerable: true,
19018 get: function () {
19019 const value = valueFn();
19020 Object.defineProperty(messages, id, { enumerable: true, value });
19021 return value;
19022 },
19023 set: _ => { throw new Error('Could not overwrite an XTB translation'); },
19024 });
19025}
19026// Extract messages as xml nodes from the xtb file
19027class XtbParser {
19028 constructor() {
19029 this._locale = null;
19030 }
19031 parse(xtb, url) {
19032 this._bundleDepth = 0;
19033 this._msgIdToHtml = {};
19034 // We can not parse the ICU messages at this point as some messages might not originate
19035 // from Angular that could not be lex'd.
19036 const xml = new XmlParser().parse(xtb, url);
19037 this._errors = xml.errors;
19038 visitAll$1(this, xml.rootNodes);
19039 return {
19040 msgIdToHtml: this._msgIdToHtml,
19041 errors: this._errors,
19042 locale: this._locale,
19043 };
19044 }
19045 visitElement(element, context) {
19046 switch (element.name) {
19047 case _TRANSLATIONS_TAG:
19048 this._bundleDepth++;
19049 if (this._bundleDepth > 1) {
19050 this._addError(element, `<${_TRANSLATIONS_TAG}> elements can not be nested`);
19051 }
19052 const langAttr = element.attrs.find((attr) => attr.name === 'lang');
19053 if (langAttr) {
19054 this._locale = langAttr.value;
19055 }
19056 visitAll$1(this, element.children, null);
19057 this._bundleDepth--;
19058 break;
19059 case _TRANSLATION_TAG:
19060 const idAttr = element.attrs.find((attr) => attr.name === 'id');
19061 if (!idAttr) {
19062 this._addError(element, `<${_TRANSLATION_TAG}> misses the "id" attribute`);
19063 }
19064 else {
19065 const id = idAttr.value;
19066 if (this._msgIdToHtml.hasOwnProperty(id)) {
19067 this._addError(element, `Duplicated translations for msg ${id}`);
19068 }
19069 else {
19070 const innerTextStart = element.startSourceSpan.end.offset;
19071 const innerTextEnd = element.endSourceSpan.start.offset;
19072 const content = element.startSourceSpan.start.file.content;
19073 const innerText = content.slice(innerTextStart, innerTextEnd);
19074 this._msgIdToHtml[id] = innerText;
19075 }
19076 }
19077 break;
19078 default:
19079 this._addError(element, 'Unexpected tag');
19080 }
19081 }
19082 visitAttribute(attribute, context) { }
19083 visitText(text, context) { }
19084 visitComment(comment, context) { }
19085 visitExpansion(expansion, context) { }
19086 visitExpansionCase(expansionCase, context) { }
19087 _addError(node, message) {
19088 this._errors.push(new I18nError(node.sourceSpan, message));
19089 }
19090}
19091// Convert ml nodes (xtb syntax) to i18n nodes
19092class XmlToI18n$2 {
19093 convert(message, url) {
19094 const xmlIcu = new XmlParser().parse(message, url, { tokenizeExpansionForms: true });
19095 this._errors = xmlIcu.errors;
19096 const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
19097 [] :
19098 visitAll$1(this, xmlIcu.rootNodes);
19099 return {
19100 i18nNodes,
19101 errors: this._errors,
19102 };
19103 }
19104 visitText(text, context) { return new Text$1(text.value, text.sourceSpan); }
19105 visitExpansion(icu, context) {
19106 const caseMap = {};
19107 visitAll$1(this, icu.cases).forEach(c => {
19108 caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
19109 });
19110 return new Icu$1(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
19111 }
19112 visitExpansionCase(icuCase, context) {
19113 return {
19114 value: icuCase.value,
19115 nodes: visitAll$1(this, icuCase.expression),
19116 };
19117 }
19118 visitElement(el, context) {
19119 if (el.name === _PLACEHOLDER_TAG$3) {
19120 const nameAttr = el.attrs.find((attr) => attr.name === 'name');
19121 if (nameAttr) {
19122 return new Placeholder('', nameAttr.value, el.sourceSpan);
19123 }
19124 this._addError(el, `<${_PLACEHOLDER_TAG$3}> misses the "name" attribute`);
19125 }
19126 else {
19127 this._addError(el, `Unexpected tag`);
19128 }
19129 return null;
19130 }
19131 visitComment(comment, context) { }
19132 visitAttribute(attribute, context) { }
19133 _addError(node, message) {
19134 this._errors.push(new I18nError(node.sourceSpan, message));
19135 }
19136}
19137
19138/**
19139 * @license
19140 * Copyright Google Inc. All Rights Reserved.
19141 *
19142 * Use of this source code is governed by an MIT-style license that can be
19143 * found in the LICENSE file at https://angular.io/license
19144 */
19145/**
19146 * A container for translated messages
19147 */
19148class TranslationBundle {
19149 constructor(_i18nNodesByMsgId = {}, locale, digest, mapperFactory, missingTranslationStrategy = MissingTranslationStrategy.Warning, console) {
19150 this._i18nNodesByMsgId = _i18nNodesByMsgId;
19151 this.digest = digest;
19152 this.mapperFactory = mapperFactory;
19153 this._i18nToHtml = new I18nToHtmlVisitor(_i18nNodesByMsgId, locale, digest, mapperFactory, missingTranslationStrategy, console);
19154 }
19155 // Creates a `TranslationBundle` by parsing the given `content` with the `serializer`.
19156 static load(content, url, serializer, missingTranslationStrategy, console) {
19157 const { locale, i18nNodesByMsgId } = serializer.load(content, url);
19158 const digestFn = (m) => serializer.digest(m);
19159 const mapperFactory = (m) => serializer.createNameMapper(m);
19160 return new TranslationBundle(i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console);
19161 }
19162 // Returns the translation as HTML nodes from the given source message.
19163 get(srcMsg) {
19164 const html = this._i18nToHtml.convert(srcMsg);
19165 if (html.errors.length) {
19166 throw new Error(html.errors.join('\n'));
19167 }
19168 return html.nodes;
19169 }
19170 has(srcMsg) { return this.digest(srcMsg) in this._i18nNodesByMsgId; }
19171}
19172class I18nToHtmlVisitor {
19173 constructor(_i18nNodesByMsgId = {}, _locale, _digest, _mapperFactory, _missingTranslationStrategy, _console) {
19174 this._i18nNodesByMsgId = _i18nNodesByMsgId;
19175 this._locale = _locale;
19176 this._digest = _digest;
19177 this._mapperFactory = _mapperFactory;
19178 this._missingTranslationStrategy = _missingTranslationStrategy;
19179 this._console = _console;
19180 this._contextStack = [];
19181 this._errors = [];
19182 }
19183 convert(srcMsg) {
19184 this._contextStack.length = 0;
19185 this._errors.length = 0;
19186 // i18n to text
19187 const text = this._convertToText(srcMsg);
19188 // text to html
19189 const url = srcMsg.nodes[0].sourceSpan.start.file.url;
19190 const html = new HtmlParser().parse(text, url, { tokenizeExpansionForms: true });
19191 return {
19192 nodes: html.rootNodes,
19193 errors: [...this._errors, ...html.errors],
19194 };
19195 }
19196 visitText(text, context) {
19197 // `convert()` uses an `HtmlParser` to return `html.Node`s
19198 // we should then make sure that any special characters are escaped
19199 return escapeXml(text.value);
19200 }
19201 visitContainer(container, context) {
19202 return container.children.map(n => n.visit(this)).join('');
19203 }
19204 visitIcu(icu, context) {
19205 const cases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
19206 // TODO(vicb): Once all format switch to using expression placeholders
19207 // we should throw when the placeholder is not in the source message
19208 const exp = this._srcMsg.placeholders.hasOwnProperty(icu.expression) ?
19209 this._srcMsg.placeholders[icu.expression] :
19210 icu.expression;
19211 return `{${exp}, ${icu.type}, ${cases.join(' ')}}`;
19212 }
19213 visitPlaceholder(ph, context) {
19214 const phName = this._mapper(ph.name);
19215 if (this._srcMsg.placeholders.hasOwnProperty(phName)) {
19216 return this._srcMsg.placeholders[phName];
19217 }
19218 if (this._srcMsg.placeholderToMessage.hasOwnProperty(phName)) {
19219 return this._convertToText(this._srcMsg.placeholderToMessage[phName]);
19220 }
19221 this._addError(ph, `Unknown placeholder "${ph.name}"`);
19222 return '';
19223 }
19224 // Loaded message contains only placeholders (vs tag and icu placeholders).
19225 // However when a translation can not be found, we need to serialize the source message
19226 // which can contain tag placeholders
19227 visitTagPlaceholder(ph, context) {
19228 const tag = `${ph.tag}`;
19229 const attrs = Object.keys(ph.attrs).map(name => `${name}="${ph.attrs[name]}"`).join(' ');
19230 if (ph.isVoid) {
19231 return `<${tag} ${attrs}/>`;
19232 }
19233 const children = ph.children.map((c) => c.visit(this)).join('');
19234 return `<${tag} ${attrs}>${children}</${tag}>`;
19235 }
19236 // Loaded message contains only placeholders (vs tag and icu placeholders).
19237 // However when a translation can not be found, we need to serialize the source message
19238 // which can contain tag placeholders
19239 visitIcuPlaceholder(ph, context) {
19240 // An ICU placeholder references the source message to be serialized
19241 return this._convertToText(this._srcMsg.placeholderToMessage[ph.name]);
19242 }
19243 /**
19244 * Convert a source message to a translated text string:
19245 * - text nodes are replaced with their translation,
19246 * - placeholders are replaced with their content,
19247 * - ICU nodes are converted to ICU expressions.
19248 */
19249 _convertToText(srcMsg) {
19250 const id = this._digest(srcMsg);
19251 const mapper = this._mapperFactory ? this._mapperFactory(srcMsg) : null;
19252 let nodes;
19253 this._contextStack.push({ msg: this._srcMsg, mapper: this._mapper });
19254 this._srcMsg = srcMsg;
19255 if (this._i18nNodesByMsgId.hasOwnProperty(id)) {
19256 // When there is a translation use its nodes as the source
19257 // And create a mapper to convert serialized placeholder names to internal names
19258 nodes = this._i18nNodesByMsgId[id];
19259 this._mapper = (name) => mapper ? mapper.toInternalName(name) : name;
19260 }
19261 else {
19262 // When no translation has been found
19263 // - report an error / a warning / nothing,
19264 // - use the nodes from the original message
19265 // - placeholders are already internal and need no mapper
19266 if (this._missingTranslationStrategy === MissingTranslationStrategy.Error) {
19267 const ctx = this._locale ? ` for locale "${this._locale}"` : '';
19268 this._addError(srcMsg.nodes[0], `Missing translation for message "${id}"${ctx}`);
19269 }
19270 else if (this._console &&
19271 this._missingTranslationStrategy === MissingTranslationStrategy.Warning) {
19272 const ctx = this._locale ? ` for locale "${this._locale}"` : '';
19273 this._console.warn(`Missing translation for message "${id}"${ctx}`);
19274 }
19275 nodes = srcMsg.nodes;
19276 this._mapper = (name) => name;
19277 }
19278 const text = nodes.map(node => node.visit(this)).join('');
19279 const context = this._contextStack.pop();
19280 this._srcMsg = context.msg;
19281 this._mapper = context.mapper;
19282 return text;
19283 }
19284 _addError(el, msg) {
19285 this._errors.push(new I18nError(el.sourceSpan, msg));
19286 }
19287}
19288
19289/**
19290 * @license
19291 * Copyright Google Inc. All Rights Reserved.
19292 *
19293 * Use of this source code is governed by an MIT-style license that can be
19294 * found in the LICENSE file at https://angular.io/license
19295 */
19296class I18NHtmlParser {
19297 constructor(_htmlParser, translations, translationsFormat, missingTranslation = MissingTranslationStrategy.Warning, console) {
19298 this._htmlParser = _htmlParser;
19299 if (translations) {
19300 const serializer = createSerializer(translationsFormat);
19301 this._translationBundle =
19302 TranslationBundle.load(translations, 'i18n', serializer, missingTranslation, console);
19303 }
19304 else {
19305 this._translationBundle =
19306 new TranslationBundle({}, null, digest, undefined, missingTranslation, console);
19307 }
19308 }
19309 parse(source, url, options = {}) {
19310 const interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
19311 const parseResult = this._htmlParser.parse(source, url, Object.assign({ interpolationConfig }, options));
19312 if (parseResult.errors.length) {
19313 return new ParseTreeResult(parseResult.rootNodes, parseResult.errors);
19314 }
19315 return mergeTranslations(parseResult.rootNodes, this._translationBundle, interpolationConfig, [], {});
19316 }
19317}
19318function createSerializer(format) {
19319 format = (format || 'xlf').toLowerCase();
19320 switch (format) {
19321 case 'xmb':
19322 return new Xmb();
19323 case 'xtb':
19324 return new Xtb();
19325 case 'xliff2':
19326 case 'xlf2':
19327 return new Xliff2();
19328 case 'xliff':
19329 case 'xlf':
19330 default:
19331 return new Xliff();
19332 }
19333}
19334
19335/**
19336 * @license
19337 * Copyright Google Inc. All Rights Reserved.
19338 *
19339 * Use of this source code is governed by an MIT-style license that can be
19340 * found in the LICENSE file at https://angular.io/license
19341 */
19342const QUOTED_KEYS = '$quoted$';
19343function convertValueToOutputAst(ctx, value, type = null) {
19344 return visitValue(value, new _ValueOutputAstTransformer(ctx), type);
19345}
19346class _ValueOutputAstTransformer {
19347 constructor(ctx) {
19348 this.ctx = ctx;
19349 }
19350 visitArray(arr, type) {
19351 return literalArr(arr.map(value => visitValue(value, this, null)), type);
19352 }
19353 visitStringMap(map, type) {
19354 const entries = [];
19355 const quotedSet = new Set(map && map[QUOTED_KEYS]);
19356 Object.keys(map).forEach(key => {
19357 entries.push(new LiteralMapEntry(key, visitValue(map[key], this, null), quotedSet.has(key)));
19358 });
19359 return new LiteralMapExpr(entries, type);
19360 }
19361 visitPrimitive(value, type) { return literal(value, type); }
19362 visitOther(value, type) {
19363 if (value instanceof Expression) {
19364 return value;
19365 }
19366 else {
19367 return this.ctx.importExpr(value);
19368 }
19369 }
19370}
19371
19372/**
19373 * @license
19374 * Copyright Google Inc. All Rights Reserved.
19375 *
19376 * Use of this source code is governed by an MIT-style license that can be
19377 * found in the LICENSE file at https://angular.io/license
19378 */
19379function mapEntry$1(key, value) {
19380 return { key, value, quoted: false };
19381}
19382class InjectableCompiler {
19383 constructor(reflector, alwaysGenerateDef) {
19384 this.reflector = reflector;
19385 this.alwaysGenerateDef = alwaysGenerateDef;
19386 this.tokenInjector = reflector.resolveExternalReference(Identifiers.Injector);
19387 }
19388 depsArray(deps, ctx) {
19389 return deps.map(dep => {
19390 let token = dep;
19391 let args = [token];
19392 let flags = 0 /* Default */;
19393 if (Array.isArray(dep)) {
19394 for (let i = 0; i < dep.length; i++) {
19395 const v = dep[i];
19396 if (v) {
19397 if (v.ngMetadataName === 'Optional') {
19398 flags |= 8 /* Optional */;
19399 }
19400 else if (v.ngMetadataName === 'SkipSelf') {
19401 flags |= 4 /* SkipSelf */;
19402 }
19403 else if (v.ngMetadataName === 'Self') {
19404 flags |= 2 /* Self */;
19405 }
19406 else if (v.ngMetadataName === 'Inject') {
19407 token = v.token;
19408 }
19409 else {
19410 token = v;
19411 }
19412 }
19413 }
19414 }
19415 let tokenExpr;
19416 if (typeof token === 'string') {
19417 tokenExpr = literal(token);
19418 }
19419 else if (token === this.tokenInjector) {
19420 tokenExpr = importExpr(Identifiers.INJECTOR);
19421 }
19422 else {
19423 tokenExpr = ctx.importExpr(token);
19424 }
19425 if (flags !== 0 /* Default */) {
19426 args = [tokenExpr, literal(flags)];
19427 }
19428 else {
19429 args = [tokenExpr];
19430 }
19431 return importExpr(Identifiers.inject).callFn(args);
19432 });
19433 }
19434 factoryFor(injectable, ctx) {
19435 let retValue;
19436 if (injectable.useExisting) {
19437 retValue = importExpr(Identifiers.inject).callFn([ctx.importExpr(injectable.useExisting)]);
19438 }
19439 else if (injectable.useFactory) {
19440 const deps = injectable.deps || [];
19441 if (deps.length > 0) {
19442 retValue = ctx.importExpr(injectable.useFactory).callFn(this.depsArray(deps, ctx));
19443 }
19444 else {
19445 return ctx.importExpr(injectable.useFactory);
19446 }
19447 }
19448 else if (injectable.useValue) {
19449 retValue = convertValueToOutputAst(ctx, injectable.useValue);
19450 }
19451 else {
19452 const clazz = injectable.useClass || injectable.symbol;
19453 const depArgs = this.depsArray(this.reflector.parameters(clazz), ctx);
19454 retValue = new InstantiateExpr(ctx.importExpr(clazz), depArgs);
19455 }
19456 return fn([], [new ReturnStatement(retValue)], undefined, undefined, injectable.symbol.name + '_Factory');
19457 }
19458 injectableDef(injectable, ctx) {
19459 let providedIn = NULL_EXPR;
19460 if (injectable.providedIn !== undefined) {
19461 if (injectable.providedIn === null) {
19462 providedIn = NULL_EXPR;
19463 }
19464 else if (typeof injectable.providedIn === 'string') {
19465 providedIn = literal(injectable.providedIn);
19466 }
19467 else {
19468 providedIn = ctx.importExpr(injectable.providedIn);
19469 }
19470 }
19471 const def = [
19472 mapEntry$1('factory', this.factoryFor(injectable, ctx)),
19473 mapEntry$1('token', ctx.importExpr(injectable.type.reference)),
19474 mapEntry$1('providedIn', providedIn),
19475 ];
19476 return importExpr(Identifiers.ɵɵdefineInjectable).callFn([literalMap(def)]);
19477 }
19478 compile(injectable, ctx) {
19479 if (this.alwaysGenerateDef || injectable.providedIn !== undefined) {
19480 const className = identifierName(injectable.type);
19481 const clazz = new ClassStmt(className, null, [
19482 new ClassField('ngInjectableDef', INFERRED_TYPE, [StmtModifier.Static], this.injectableDef(injectable, ctx)),
19483 ], [], new ClassMethod(null, [], []), []);
19484 ctx.statements.push(clazz);
19485 }
19486 }
19487}
19488
19489/**
19490 * @license
19491 * Copyright Google Inc. All Rights Reserved.
19492 *
19493 * Use of this source code is governed by an MIT-style license that can be
19494 * found in the LICENSE file at https://angular.io/license
19495 */
19496const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
19497const GENERATED_FILE = /\.ngfactory\.|\.ngsummary\./;
19498const JIT_SUMMARY_FILE = /\.ngsummary\./;
19499const JIT_SUMMARY_NAME = /NgSummary$/;
19500function ngfactoryFilePath(filePath, forceSourceFile = false) {
19501 const urlWithSuffix = splitTypescriptSuffix(filePath, forceSourceFile);
19502 return `${urlWithSuffix[0]}.ngfactory${normalizeGenFileSuffix(urlWithSuffix[1])}`;
19503}
19504function stripGeneratedFileSuffix(filePath) {
19505 return filePath.replace(GENERATED_FILE, '.');
19506}
19507function isGeneratedFile(filePath) {
19508 return GENERATED_FILE.test(filePath);
19509}
19510function splitTypescriptSuffix(path, forceSourceFile = false) {
19511 if (path.endsWith('.d.ts')) {
19512 return [path.slice(0, -5), forceSourceFile ? '.ts' : '.d.ts'];
19513 }
19514 const lastDot = path.lastIndexOf('.');
19515 if (lastDot !== -1) {
19516 return [path.substring(0, lastDot), path.substring(lastDot)];
19517 }
19518 return [path, ''];
19519}
19520function normalizeGenFileSuffix(srcFileSuffix) {
19521 return srcFileSuffix === '.tsx' ? '.ts' : srcFileSuffix;
19522}
19523function summaryFileName(fileName) {
19524 const fileNameWithoutSuffix = fileName.replace(STRIP_SRC_FILE_SUFFIXES, '');
19525 return `${fileNameWithoutSuffix}.ngsummary.json`;
19526}
19527function summaryForJitFileName(fileName, forceSourceFile = false) {
19528 const urlWithSuffix = splitTypescriptSuffix(stripGeneratedFileSuffix(fileName), forceSourceFile);
19529 return `${urlWithSuffix[0]}.ngsummary${urlWithSuffix[1]}`;
19530}
19531function stripSummaryForJitFileSuffix(filePath) {
19532 return filePath.replace(JIT_SUMMARY_FILE, '.');
19533}
19534function summaryForJitName(symbolName) {
19535 return `${symbolName}NgSummary`;
19536}
19537function stripSummaryForJitNameSuffix(symbolName) {
19538 return symbolName.replace(JIT_SUMMARY_NAME, '');
19539}
19540const LOWERED_SYMBOL = /\u0275\d+/;
19541function isLoweredSymbol(name) {
19542 return LOWERED_SYMBOL.test(name);
19543}
19544function createLoweredSymbol(id) {
19545 return `\u0275${id}`;
19546}
19547
19548/**
19549 * @license
19550 * Copyright Google Inc. All Rights Reserved.
19551 *
19552 * Use of this source code is governed by an MIT-style license that can be
19553 * found in the LICENSE file at https://angular.io/license
19554 */
19555var LifecycleHooks;
19556(function (LifecycleHooks) {
19557 LifecycleHooks[LifecycleHooks["OnInit"] = 0] = "OnInit";
19558 LifecycleHooks[LifecycleHooks["OnDestroy"] = 1] = "OnDestroy";
19559 LifecycleHooks[LifecycleHooks["DoCheck"] = 2] = "DoCheck";
19560 LifecycleHooks[LifecycleHooks["OnChanges"] = 3] = "OnChanges";
19561 LifecycleHooks[LifecycleHooks["AfterContentInit"] = 4] = "AfterContentInit";
19562 LifecycleHooks[LifecycleHooks["AfterContentChecked"] = 5] = "AfterContentChecked";
19563 LifecycleHooks[LifecycleHooks["AfterViewInit"] = 6] = "AfterViewInit";
19564 LifecycleHooks[LifecycleHooks["AfterViewChecked"] = 7] = "AfterViewChecked";
19565})(LifecycleHooks || (LifecycleHooks = {}));
19566const LIFECYCLE_HOOKS_VALUES = [
19567 LifecycleHooks.OnInit, LifecycleHooks.OnDestroy, LifecycleHooks.DoCheck, LifecycleHooks.OnChanges,
19568 LifecycleHooks.AfterContentInit, LifecycleHooks.AfterContentChecked, LifecycleHooks.AfterViewInit,
19569 LifecycleHooks.AfterViewChecked
19570];
19571function hasLifecycleHook(reflector, hook, token) {
19572 return reflector.hasLifecycleHook(token, getHookName(hook));
19573}
19574function getAllLifecycleHooks(reflector, token) {
19575 return LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(reflector, hook, token));
19576}
19577function getHookName(hook) {
19578 switch (hook) {
19579 case LifecycleHooks.OnInit:
19580 return 'ngOnInit';
19581 case LifecycleHooks.OnDestroy:
19582 return 'ngOnDestroy';
19583 case LifecycleHooks.DoCheck:
19584 return 'ngDoCheck';
19585 case LifecycleHooks.OnChanges:
19586 return 'ngOnChanges';
19587 case LifecycleHooks.AfterContentInit:
19588 return 'ngAfterContentInit';
19589 case LifecycleHooks.AfterContentChecked:
19590 return 'ngAfterContentChecked';
19591 case LifecycleHooks.AfterViewInit:
19592 return 'ngAfterViewInit';
19593 case LifecycleHooks.AfterViewChecked:
19594 return 'ngAfterViewChecked';
19595 default:
19596 // This default case is not needed by TypeScript compiler, as the switch is exhaustive.
19597 // However Closure Compiler does not understand that and reports an error in typed mode.
19598 // The `throw new Error` below works around the problem, and the unexpected: never variable
19599 // makes sure tsc still checks this code is unreachable.
19600 const unexpected = hook;
19601 throw new Error(`unexpected ${unexpected}`);
19602 }
19603}
19604
19605/**
19606 * @license
19607 * Copyright Google Inc. All Rights Reserved.
19608 *
19609 * Use of this source code is governed by an MIT-style license that can be
19610 * found in the LICENSE file at https://angular.io/license
19611 */
19612const ERROR_COMPONENT_TYPE = 'ngComponentType';
19613// Design notes:
19614// - don't lazily create metadata:
19615// For some metadata, we need to do async work sometimes,
19616// so the user has to kick off this loading.
19617// But we want to report errors even when the async work is
19618// not required to check that the user would have been able
19619// to wait correctly.
19620class CompileMetadataResolver {
19621 constructor(_config, _htmlParser, _ngModuleResolver, _directiveResolver, _pipeResolver, _summaryResolver, _schemaRegistry, _directiveNormalizer, _console, _staticSymbolCache, _reflector, _errorCollector) {
19622 this._config = _config;
19623 this._htmlParser = _htmlParser;
19624 this._ngModuleResolver = _ngModuleResolver;
19625 this._directiveResolver = _directiveResolver;
19626 this._pipeResolver = _pipeResolver;
19627 this._summaryResolver = _summaryResolver;
19628 this._schemaRegistry = _schemaRegistry;
19629 this._directiveNormalizer = _directiveNormalizer;
19630 this._console = _console;
19631 this._staticSymbolCache = _staticSymbolCache;
19632 this._reflector = _reflector;
19633 this._errorCollector = _errorCollector;
19634 this._nonNormalizedDirectiveCache = new Map();
19635 this._directiveCache = new Map();
19636 this._summaryCache = new Map();
19637 this._pipeCache = new Map();
19638 this._ngModuleCache = new Map();
19639 this._ngModuleOfTypes = new Map();
19640 this._shallowModuleCache = new Map();
19641 }
19642 getReflector() { return this._reflector; }
19643 clearCacheFor(type) {
19644 const dirMeta = this._directiveCache.get(type);
19645 this._directiveCache.delete(type);
19646 this._nonNormalizedDirectiveCache.delete(type);
19647 this._summaryCache.delete(type);
19648 this._pipeCache.delete(type);
19649 this._ngModuleOfTypes.delete(type);
19650 // Clear all of the NgModule as they contain transitive information!
19651 this._ngModuleCache.clear();
19652 if (dirMeta) {
19653 this._directiveNormalizer.clearCacheFor(dirMeta);
19654 }
19655 }
19656 clearCache() {
19657 this._directiveCache.clear();
19658 this._nonNormalizedDirectiveCache.clear();
19659 this._summaryCache.clear();
19660 this._pipeCache.clear();
19661 this._ngModuleCache.clear();
19662 this._ngModuleOfTypes.clear();
19663 this._directiveNormalizer.clearCache();
19664 }
19665 _createProxyClass(baseType, name) {
19666 let delegate = null;
19667 const proxyClass = function () {
19668 if (!delegate) {
19669 throw new Error(`Illegal state: Class ${name} for type ${stringify(baseType)} is not compiled yet!`);
19670 }
19671 return delegate.apply(this, arguments);
19672 };
19673 proxyClass.setDelegate = (d) => {
19674 delegate = d;
19675 proxyClass.prototype = d.prototype;
19676 };
19677 // Make stringify work correctly
19678 proxyClass.overriddenName = name;
19679 return proxyClass;
19680 }
19681 getGeneratedClass(dirType, name) {
19682 if (dirType instanceof StaticSymbol) {
19683 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), name);
19684 }
19685 else {
19686 return this._createProxyClass(dirType, name);
19687 }
19688 }
19689 getComponentViewClass(dirType) {
19690 return this.getGeneratedClass(dirType, viewClassName(dirType, 0));
19691 }
19692 getHostComponentViewClass(dirType) {
19693 return this.getGeneratedClass(dirType, hostViewClassName(dirType));
19694 }
19695 getHostComponentType(dirType) {
19696 const name = `${identifierName({ reference: dirType })}_Host`;
19697 if (dirType instanceof StaticSymbol) {
19698 return this._staticSymbolCache.get(dirType.filePath, name);
19699 }
19700 return this._createProxyClass(dirType, name);
19701 }
19702 getRendererType(dirType) {
19703 if (dirType instanceof StaticSymbol) {
19704 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), rendererTypeName(dirType));
19705 }
19706 else {
19707 // returning an object as proxy,
19708 // that we fill later during runtime compilation.
19709 return {};
19710 }
19711 }
19712 getComponentFactory(selector, dirType, inputs, outputs) {
19713 if (dirType instanceof StaticSymbol) {
19714 return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), componentFactoryName(dirType));
19715 }
19716 else {
19717 const hostView = this.getHostComponentViewClass(dirType);
19718 // Note: ngContentSelectors will be filled later once the template is
19719 // loaded.
19720 const createComponentFactory = this._reflector.resolveExternalReference(Identifiers.createComponentFactory);
19721 return createComponentFactory(selector, dirType, hostView, inputs, outputs, []);
19722 }
19723 }
19724 initComponentFactory(factory, ngContentSelectors) {
19725 if (!(factory instanceof StaticSymbol)) {
19726 factory.ngContentSelectors.push(...ngContentSelectors);
19727 }
19728 }
19729 _loadSummary(type, kind) {
19730 let typeSummary = this._summaryCache.get(type);
19731 if (!typeSummary) {
19732 const summary = this._summaryResolver.resolveSummary(type);
19733 typeSummary = summary ? summary.type : null;
19734 this._summaryCache.set(type, typeSummary || null);
19735 }
19736 return typeSummary && typeSummary.summaryKind === kind ? typeSummary : null;
19737 }
19738 getHostComponentMetadata(compMeta, hostViewType) {
19739 const hostType = this.getHostComponentType(compMeta.type.reference);
19740 if (!hostViewType) {
19741 hostViewType = this.getHostComponentViewClass(hostType);
19742 }
19743 // Note: ! is ok here as this method should only be called with normalized directive
19744 // metadata, which always fills in the selector.
19745 const template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
19746 const templateUrl = '';
19747 const htmlAst = this._htmlParser.parse(template, templateUrl);
19748 return CompileDirectiveMetadata.create({
19749 isHost: true,
19750 type: { reference: hostType, diDeps: [], lifecycleHooks: [] },
19751 template: new CompileTemplateMetadata({
19752 encapsulation: ViewEncapsulation.None,
19753 template,
19754 templateUrl,
19755 htmlAst,
19756 styles: [],
19757 styleUrls: [],
19758 ngContentSelectors: [],
19759 animations: [],
19760 isInline: true,
19761 externalStylesheets: [],
19762 interpolation: null,
19763 preserveWhitespaces: false,
19764 }),
19765 exportAs: null,
19766 changeDetection: ChangeDetectionStrategy.Default,
19767 inputs: [],
19768 outputs: [],
19769 host: {},
19770 isComponent: true,
19771 selector: '*',
19772 providers: [],
19773 viewProviders: [],
19774 queries: [],
19775 guards: {},
19776 viewQueries: [],
19777 componentViewType: hostViewType,
19778 rendererType: { id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {} },
19779 entryComponents: [],
19780 componentFactory: null
19781 });
19782 }
19783 loadDirectiveMetadata(ngModuleType, directiveType, isSync) {
19784 if (this._directiveCache.has(directiveType)) {
19785 return null;
19786 }
19787 directiveType = resolveForwardRef(directiveType);
19788 const { annotation, metadata } = this.getNonNormalizedDirectiveMetadata(directiveType);
19789 const createDirectiveMetadata = (templateMetadata) => {
19790 const normalizedDirMeta = new CompileDirectiveMetadata({
19791 isHost: false,
19792 type: metadata.type,
19793 isComponent: metadata.isComponent,
19794 selector: metadata.selector,
19795 exportAs: metadata.exportAs,
19796 changeDetection: metadata.changeDetection,
19797 inputs: metadata.inputs,
19798 outputs: metadata.outputs,
19799 hostListeners: metadata.hostListeners,
19800 hostProperties: metadata.hostProperties,
19801 hostAttributes: metadata.hostAttributes,
19802 providers: metadata.providers,
19803 viewProviders: metadata.viewProviders,
19804 queries: metadata.queries,
19805 guards: metadata.guards,
19806 viewQueries: metadata.viewQueries,
19807 entryComponents: metadata.entryComponents,
19808 componentViewType: metadata.componentViewType,
19809 rendererType: metadata.rendererType,
19810 componentFactory: metadata.componentFactory,
19811 template: templateMetadata
19812 });
19813 if (templateMetadata) {
19814 this.initComponentFactory(metadata.componentFactory, templateMetadata.ngContentSelectors);
19815 }
19816 this._directiveCache.set(directiveType, normalizedDirMeta);
19817 this._summaryCache.set(directiveType, normalizedDirMeta.toSummary());
19818 return null;
19819 };
19820 if (metadata.isComponent) {
19821 const template = metadata.template;
19822 const templateMeta = this._directiveNormalizer.normalizeTemplate({
19823 ngModuleType,
19824 componentType: directiveType,
19825 moduleUrl: this._reflector.componentModuleUrl(directiveType, annotation),
19826 encapsulation: template.encapsulation,
19827 template: template.template,
19828 templateUrl: template.templateUrl,
19829 styles: template.styles,
19830 styleUrls: template.styleUrls,
19831 animations: template.animations,
19832 interpolation: template.interpolation,
19833 preserveWhitespaces: template.preserveWhitespaces
19834 });
19835 if (isPromise(templateMeta) && isSync) {
19836 this._reportError(componentStillLoadingError(directiveType), directiveType);
19837 return null;
19838 }
19839 return SyncAsync.then(templateMeta, createDirectiveMetadata);
19840 }
19841 else {
19842 // directive
19843 createDirectiveMetadata(null);
19844 return null;
19845 }
19846 }
19847 getNonNormalizedDirectiveMetadata(directiveType) {
19848 directiveType = resolveForwardRef(directiveType);
19849 if (!directiveType) {
19850 return null;
19851 }
19852 let cacheEntry = this._nonNormalizedDirectiveCache.get(directiveType);
19853 if (cacheEntry) {
19854 return cacheEntry;
19855 }
19856 const dirMeta = this._directiveResolver.resolve(directiveType, false);
19857 if (!dirMeta) {
19858 return null;
19859 }
19860 let nonNormalizedTemplateMetadata = undefined;
19861 if (createComponent.isTypeOf(dirMeta)) {
19862 // component
19863 const compMeta = dirMeta;
19864 assertArrayOfStrings('styles', compMeta.styles);
19865 assertArrayOfStrings('styleUrls', compMeta.styleUrls);
19866 assertInterpolationSymbols('interpolation', compMeta.interpolation);
19867 const animations = compMeta.animations;
19868 nonNormalizedTemplateMetadata = new CompileTemplateMetadata({
19869 encapsulation: noUndefined(compMeta.encapsulation),
19870 template: noUndefined(compMeta.template),
19871 templateUrl: noUndefined(compMeta.templateUrl),
19872 htmlAst: null,
19873 styles: compMeta.styles || [],
19874 styleUrls: compMeta.styleUrls || [],
19875 animations: animations || [],
19876 interpolation: noUndefined(compMeta.interpolation),
19877 isInline: !!compMeta.template,
19878 externalStylesheets: [],
19879 ngContentSelectors: [],
19880 preserveWhitespaces: noUndefined(dirMeta.preserveWhitespaces),
19881 });
19882 }
19883 let changeDetectionStrategy = null;
19884 let viewProviders = [];
19885 let entryComponentMetadata = [];
19886 let selector = dirMeta.selector;
19887 if (createComponent.isTypeOf(dirMeta)) {
19888 // Component
19889 const compMeta = dirMeta;
19890 changeDetectionStrategy = compMeta.changeDetection;
19891 if (compMeta.viewProviders) {
19892 viewProviders = this._getProvidersMetadata(compMeta.viewProviders, entryComponentMetadata, `viewProviders for "${stringifyType(directiveType)}"`, [], directiveType);
19893 }
19894 if (compMeta.entryComponents) {
19895 entryComponentMetadata = flattenAndDedupeArray(compMeta.entryComponents)
19896 .map((type) => this._getEntryComponentMetadata(type))
19897 .concat(entryComponentMetadata);
19898 }
19899 if (!selector) {
19900 selector = this._schemaRegistry.getDefaultComponentElementName();
19901 }
19902 }
19903 else {
19904 // Directive
19905 if (!selector) {
19906 this._reportError(syntaxError(`Directive ${stringifyType(directiveType)} has no selector, please add it!`), directiveType);
19907 selector = 'error';
19908 }
19909 }
19910 let providers = [];
19911 if (dirMeta.providers != null) {
19912 providers = this._getProvidersMetadata(dirMeta.providers, entryComponentMetadata, `providers for "${stringifyType(directiveType)}"`, [], directiveType);
19913 }
19914 let queries = [];
19915 let viewQueries = [];
19916 if (dirMeta.queries != null) {
19917 queries = this._getQueriesMetadata(dirMeta.queries, false, directiveType);
19918 viewQueries = this._getQueriesMetadata(dirMeta.queries, true, directiveType);
19919 }
19920 const metadata = CompileDirectiveMetadata.create({
19921 isHost: false,
19922 selector: selector,
19923 exportAs: noUndefined(dirMeta.exportAs),
19924 isComponent: !!nonNormalizedTemplateMetadata,
19925 type: this._getTypeMetadata(directiveType),
19926 template: nonNormalizedTemplateMetadata,
19927 changeDetection: changeDetectionStrategy,
19928 inputs: dirMeta.inputs || [],
19929 outputs: dirMeta.outputs || [],
19930 host: dirMeta.host || {},
19931 providers: providers || [],
19932 viewProviders: viewProviders || [],
19933 queries: queries || [],
19934 guards: dirMeta.guards || {},
19935 viewQueries: viewQueries || [],
19936 entryComponents: entryComponentMetadata,
19937 componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
19938 null,
19939 rendererType: nonNormalizedTemplateMetadata ? this.getRendererType(directiveType) : null,
19940 componentFactory: null
19941 });
19942 if (nonNormalizedTemplateMetadata) {
19943 metadata.componentFactory =
19944 this.getComponentFactory(selector, directiveType, metadata.inputs, metadata.outputs);
19945 }
19946 cacheEntry = { metadata, annotation: dirMeta };
19947 this._nonNormalizedDirectiveCache.set(directiveType, cacheEntry);
19948 return cacheEntry;
19949 }
19950 /**
19951 * Gets the metadata for the given directive.
19952 * This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
19953 */
19954 getDirectiveMetadata(directiveType) {
19955 const dirMeta = this._directiveCache.get(directiveType);
19956 if (!dirMeta) {
19957 this._reportError(syntaxError(`Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${stringifyType(directiveType)}.`), directiveType);
19958 }
19959 return dirMeta;
19960 }
19961 getDirectiveSummary(dirType) {
19962 const dirSummary = this._loadSummary(dirType, CompileSummaryKind.Directive);
19963 if (!dirSummary) {
19964 this._reportError(syntaxError(`Illegal state: Could not load the summary for directive ${stringifyType(dirType)}.`), dirType);
19965 }
19966 return dirSummary;
19967 }
19968 isDirective(type) {
19969 return !!this._loadSummary(type, CompileSummaryKind.Directive) ||
19970 this._directiveResolver.isDirective(type);
19971 }
19972 isPipe(type) {
19973 return !!this._loadSummary(type, CompileSummaryKind.Pipe) ||
19974 this._pipeResolver.isPipe(type);
19975 }
19976 isNgModule(type) {
19977 return !!this._loadSummary(type, CompileSummaryKind.NgModule) ||
19978 this._ngModuleResolver.isNgModule(type);
19979 }
19980 getNgModuleSummary(moduleType, alreadyCollecting = null) {
19981 let moduleSummary = this._loadSummary(moduleType, CompileSummaryKind.NgModule);
19982 if (!moduleSummary) {
19983 const moduleMeta = this.getNgModuleMetadata(moduleType, false, alreadyCollecting);
19984 moduleSummary = moduleMeta ? moduleMeta.toSummary() : null;
19985 if (moduleSummary) {
19986 this._summaryCache.set(moduleType, moduleSummary);
19987 }
19988 }
19989 return moduleSummary;
19990 }
19991 /**
19992 * Loads the declared directives and pipes of an NgModule.
19993 */
19994 loadNgModuleDirectiveAndPipeMetadata(moduleType, isSync, throwIfNotFound = true) {
19995 const ngModule = this.getNgModuleMetadata(moduleType, throwIfNotFound);
19996 const loading = [];
19997 if (ngModule) {
19998 ngModule.declaredDirectives.forEach((id) => {
19999 const promise = this.loadDirectiveMetadata(moduleType, id.reference, isSync);
20000 if (promise) {
20001 loading.push(promise);
20002 }
20003 });
20004 ngModule.declaredPipes.forEach((id) => this._loadPipeMetadata(id.reference));
20005 }
20006 return Promise.all(loading);
20007 }
20008 getShallowModuleMetadata(moduleType) {
20009 let compileMeta = this._shallowModuleCache.get(moduleType);
20010 if (compileMeta) {
20011 return compileMeta;
20012 }
20013 const ngModuleMeta = findLast(this._reflector.shallowAnnotations(moduleType), createNgModule.isTypeOf);
20014 compileMeta = {
20015 type: this._getTypeMetadata(moduleType),
20016 rawExports: ngModuleMeta.exports,
20017 rawImports: ngModuleMeta.imports,
20018 rawProviders: ngModuleMeta.providers,
20019 };
20020 this._shallowModuleCache.set(moduleType, compileMeta);
20021 return compileMeta;
20022 }
20023 getNgModuleMetadata(moduleType, throwIfNotFound = true, alreadyCollecting = null) {
20024 moduleType = resolveForwardRef(moduleType);
20025 let compileMeta = this._ngModuleCache.get(moduleType);
20026 if (compileMeta) {
20027 return compileMeta;
20028 }
20029 const meta = this._ngModuleResolver.resolve(moduleType, throwIfNotFound);
20030 if (!meta) {
20031 return null;
20032 }
20033 const declaredDirectives = [];
20034 const exportedNonModuleIdentifiers = [];
20035 const declaredPipes = [];
20036 const importedModules = [];
20037 const exportedModules = [];
20038 const providers = [];
20039 const entryComponents = [];
20040 const bootstrapComponents = [];
20041 const schemas = [];
20042 if (meta.imports) {
20043 flattenAndDedupeArray(meta.imports).forEach((importedType) => {
20044 let importedModuleType = undefined;
20045 if (isValidType(importedType)) {
20046 importedModuleType = importedType;
20047 }
20048 else if (importedType && importedType.ngModule) {
20049 const moduleWithProviders = importedType;
20050 importedModuleType = moduleWithProviders.ngModule;
20051 if (moduleWithProviders.providers) {
20052 providers.push(...this._getProvidersMetadata(moduleWithProviders.providers, entryComponents, `provider for the NgModule '${stringifyType(importedModuleType)}'`, [], importedType));
20053 }
20054 }
20055 if (importedModuleType) {
20056 if (this._checkSelfImport(moduleType, importedModuleType))
20057 return;
20058 if (!alreadyCollecting)
20059 alreadyCollecting = new Set();
20060 if (alreadyCollecting.has(importedModuleType)) {
20061 this._reportError(syntaxError(`${this._getTypeDescriptor(importedModuleType)} '${stringifyType(importedType)}' is imported recursively by the module '${stringifyType(moduleType)}'.`), moduleType);
20062 return;
20063 }
20064 alreadyCollecting.add(importedModuleType);
20065 const importedModuleSummary = this.getNgModuleSummary(importedModuleType, alreadyCollecting);
20066 alreadyCollecting.delete(importedModuleType);
20067 if (!importedModuleSummary) {
20068 this._reportError(syntaxError(`Unexpected ${this._getTypeDescriptor(importedType)} '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'. Please add a @NgModule annotation.`), moduleType);
20069 return;
20070 }
20071 importedModules.push(importedModuleSummary);
20072 }
20073 else {
20074 this._reportError(syntaxError(`Unexpected value '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'`), moduleType);
20075 return;
20076 }
20077 });
20078 }
20079 if (meta.exports) {
20080 flattenAndDedupeArray(meta.exports).forEach((exportedType) => {
20081 if (!isValidType(exportedType)) {
20082 this._reportError(syntaxError(`Unexpected value '${stringifyType(exportedType)}' exported by the module '${stringifyType(moduleType)}'`), moduleType);
20083 return;
20084 }
20085 if (!alreadyCollecting)
20086 alreadyCollecting = new Set();
20087 if (alreadyCollecting.has(exportedType)) {
20088 this._reportError(syntaxError(`${this._getTypeDescriptor(exportedType)} '${stringify(exportedType)}' is exported recursively by the module '${stringifyType(moduleType)}'`), moduleType);
20089 return;
20090 }
20091 alreadyCollecting.add(exportedType);
20092 const exportedModuleSummary = this.getNgModuleSummary(exportedType, alreadyCollecting);
20093 alreadyCollecting.delete(exportedType);
20094 if (exportedModuleSummary) {
20095 exportedModules.push(exportedModuleSummary);
20096 }
20097 else {
20098 exportedNonModuleIdentifiers.push(this._getIdentifierMetadata(exportedType));
20099 }
20100 });
20101 }
20102 // Note: This will be modified later, so we rely on
20103 // getting a new instance every time!
20104 const transitiveModule = this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
20105 if (meta.declarations) {
20106 flattenAndDedupeArray(meta.declarations).forEach((declaredType) => {
20107 if (!isValidType(declaredType)) {
20108 this._reportError(syntaxError(`Unexpected value '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'`), moduleType);
20109 return;
20110 }
20111 const declaredIdentifier = this._getIdentifierMetadata(declaredType);
20112 if (this.isDirective(declaredType)) {
20113 transitiveModule.addDirective(declaredIdentifier);
20114 declaredDirectives.push(declaredIdentifier);
20115 this._addTypeToModule(declaredType, moduleType);
20116 }
20117 else if (this.isPipe(declaredType)) {
20118 transitiveModule.addPipe(declaredIdentifier);
20119 transitiveModule.pipes.push(declaredIdentifier);
20120 declaredPipes.push(declaredIdentifier);
20121 this._addTypeToModule(declaredType, moduleType);
20122 }
20123 else {
20124 this._reportError(syntaxError(`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`), moduleType);
20125 return;
20126 }
20127 });
20128 }
20129 const exportedDirectives = [];
20130 const exportedPipes = [];
20131 exportedNonModuleIdentifiers.forEach((exportedId) => {
20132 if (transitiveModule.directivesSet.has(exportedId.reference)) {
20133 exportedDirectives.push(exportedId);
20134 transitiveModule.addExportedDirective(exportedId);
20135 }
20136 else if (transitiveModule.pipesSet.has(exportedId.reference)) {
20137 exportedPipes.push(exportedId);
20138 transitiveModule.addExportedPipe(exportedId);
20139 }
20140 else {
20141 this._reportError(syntaxError(`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringifyType(exportedId.reference)} from ${stringifyType(moduleType)} as it was neither declared nor imported!`), moduleType);
20142 return;
20143 }
20144 });
20145 // The providers of the module have to go last
20146 // so that they overwrite any other provider we already added.
20147 if (meta.providers) {
20148 providers.push(...this._getProvidersMetadata(meta.providers, entryComponents, `provider for the NgModule '${stringifyType(moduleType)}'`, [], moduleType));
20149 }
20150 if (meta.entryComponents) {
20151 entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
20152 .map(type => this._getEntryComponentMetadata(type)));
20153 }
20154 if (meta.bootstrap) {
20155 flattenAndDedupeArray(meta.bootstrap).forEach(type => {
20156 if (!isValidType(type)) {
20157 this._reportError(syntaxError(`Unexpected value '${stringifyType(type)}' used in the bootstrap property of module '${stringifyType(moduleType)}'`), moduleType);
20158 return;
20159 }
20160 bootstrapComponents.push(this._getIdentifierMetadata(type));
20161 });
20162 }
20163 entryComponents.push(...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference)));
20164 if (meta.schemas) {
20165 schemas.push(...flattenAndDedupeArray(meta.schemas));
20166 }
20167 compileMeta = new CompileNgModuleMetadata({
20168 type: this._getTypeMetadata(moduleType),
20169 providers,
20170 entryComponents,
20171 bootstrapComponents,
20172 schemas,
20173 declaredDirectives,
20174 exportedDirectives,
20175 declaredPipes,
20176 exportedPipes,
20177 importedModules,
20178 exportedModules,
20179 transitiveModule,
20180 id: meta.id || null,
20181 });
20182 entryComponents.forEach((id) => transitiveModule.addEntryComponent(id));
20183 providers.forEach((provider) => transitiveModule.addProvider(provider, compileMeta.type));
20184 transitiveModule.addModule(compileMeta.type);
20185 this._ngModuleCache.set(moduleType, compileMeta);
20186 return compileMeta;
20187 }
20188 _checkSelfImport(moduleType, importedModuleType) {
20189 if (moduleType === importedModuleType) {
20190 this._reportError(syntaxError(`'${stringifyType(moduleType)}' module can't import itself`), moduleType);
20191 return true;
20192 }
20193 return false;
20194 }
20195 _getTypeDescriptor(type) {
20196 if (isValidType(type)) {
20197 if (this.isDirective(type)) {
20198 return 'directive';
20199 }
20200 if (this.isPipe(type)) {
20201 return 'pipe';
20202 }
20203 if (this.isNgModule(type)) {
20204 return 'module';
20205 }
20206 }
20207 if (type.provide) {
20208 return 'provider';
20209 }
20210 return 'value';
20211 }
20212 _addTypeToModule(type, moduleType) {
20213 const oldModule = this._ngModuleOfTypes.get(type);
20214 if (oldModule && oldModule !== moduleType) {
20215 this._reportError(syntaxError(`Type ${stringifyType(type)} is part of the declarations of 2 modules: ${stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` +
20216 `Please consider moving ${stringifyType(type)} to a higher module that imports ${stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` +
20217 `You can also create a new NgModule that exports and includes ${stringifyType(type)} then import that NgModule in ${stringifyType(oldModule)} and ${stringifyType(moduleType)}.`), moduleType);
20218 return;
20219 }
20220 this._ngModuleOfTypes.set(type, moduleType);
20221 }
20222 _getTransitiveNgModuleMetadata(importedModules, exportedModules) {
20223 // collect `providers` / `entryComponents` from all imported and all exported modules
20224 const result = new TransitiveCompileNgModuleMetadata();
20225 const modulesByToken = new Map();
20226 importedModules.concat(exportedModules).forEach((modSummary) => {
20227 modSummary.modules.forEach((mod) => result.addModule(mod));
20228 modSummary.entryComponents.forEach((comp) => result.addEntryComponent(comp));
20229 const addedTokens = new Set();
20230 modSummary.providers.forEach((entry) => {
20231 const tokenRef = tokenReference(entry.provider.token);
20232 let prevModules = modulesByToken.get(tokenRef);
20233 if (!prevModules) {
20234 prevModules = new Set();
20235 modulesByToken.set(tokenRef, prevModules);
20236 }
20237 const moduleRef = entry.module.reference;
20238 // Note: the providers of one module may still contain multiple providers
20239 // per token (e.g. for multi providers), and we need to preserve these.
20240 if (addedTokens.has(tokenRef) || !prevModules.has(moduleRef)) {
20241 prevModules.add(moduleRef);
20242 addedTokens.add(tokenRef);
20243 result.addProvider(entry.provider, entry.module);
20244 }
20245 });
20246 });
20247 exportedModules.forEach((modSummary) => {
20248 modSummary.exportedDirectives.forEach((id) => result.addExportedDirective(id));
20249 modSummary.exportedPipes.forEach((id) => result.addExportedPipe(id));
20250 });
20251 importedModules.forEach((modSummary) => {
20252 modSummary.exportedDirectives.forEach((id) => result.addDirective(id));
20253 modSummary.exportedPipes.forEach((id) => result.addPipe(id));
20254 });
20255 return result;
20256 }
20257 _getIdentifierMetadata(type) {
20258 type = resolveForwardRef(type);
20259 return { reference: type };
20260 }
20261 isInjectable(type) {
20262 const annotations = this._reflector.tryAnnotations(type);
20263 return annotations.some(ann => createInjectable.isTypeOf(ann));
20264 }
20265 getInjectableSummary(type) {
20266 return {
20267 summaryKind: CompileSummaryKind.Injectable,
20268 type: this._getTypeMetadata(type, null, false)
20269 };
20270 }
20271 getInjectableMetadata(type, dependencies = null, throwOnUnknownDeps = true) {
20272 const typeSummary = this._loadSummary(type, CompileSummaryKind.Injectable);
20273 const typeMetadata = typeSummary ?
20274 typeSummary.type :
20275 this._getTypeMetadata(type, dependencies, throwOnUnknownDeps);
20276 const annotations = this._reflector.annotations(type).filter(ann => createInjectable.isTypeOf(ann));
20277 if (annotations.length === 0) {
20278 return null;
20279 }
20280 const meta = annotations[annotations.length - 1];
20281 return {
20282 symbol: type,
20283 type: typeMetadata,
20284 providedIn: meta.providedIn,
20285 useValue: meta.useValue,
20286 useClass: meta.useClass,
20287 useExisting: meta.useExisting,
20288 useFactory: meta.useFactory,
20289 deps: meta.deps,
20290 };
20291 }
20292 _getTypeMetadata(type, dependencies = null, throwOnUnknownDeps = true) {
20293 const identifier = this._getIdentifierMetadata(type);
20294 return {
20295 reference: identifier.reference,
20296 diDeps: this._getDependenciesMetadata(identifier.reference, dependencies, throwOnUnknownDeps),
20297 lifecycleHooks: getAllLifecycleHooks(this._reflector, identifier.reference),
20298 };
20299 }
20300 _getFactoryMetadata(factory, dependencies = null) {
20301 factory = resolveForwardRef(factory);
20302 return { reference: factory, diDeps: this._getDependenciesMetadata(factory, dependencies) };
20303 }
20304 /**
20305 * Gets the metadata for the given pipe.
20306 * This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
20307 */
20308 getPipeMetadata(pipeType) {
20309 const pipeMeta = this._pipeCache.get(pipeType);
20310 if (!pipeMeta) {
20311 this._reportError(syntaxError(`Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${stringifyType(pipeType)}.`), pipeType);
20312 }
20313 return pipeMeta || null;
20314 }
20315 getPipeSummary(pipeType) {
20316 const pipeSummary = this._loadSummary(pipeType, CompileSummaryKind.Pipe);
20317 if (!pipeSummary) {
20318 this._reportError(syntaxError(`Illegal state: Could not load the summary for pipe ${stringifyType(pipeType)}.`), pipeType);
20319 }
20320 return pipeSummary;
20321 }
20322 getOrLoadPipeMetadata(pipeType) {
20323 let pipeMeta = this._pipeCache.get(pipeType);
20324 if (!pipeMeta) {
20325 pipeMeta = this._loadPipeMetadata(pipeType);
20326 }
20327 return pipeMeta;
20328 }
20329 _loadPipeMetadata(pipeType) {
20330 pipeType = resolveForwardRef(pipeType);
20331 const pipeAnnotation = this._pipeResolver.resolve(pipeType);
20332 const pipeMeta = new CompilePipeMetadata({
20333 type: this._getTypeMetadata(pipeType),
20334 name: pipeAnnotation.name,
20335 pure: !!pipeAnnotation.pure
20336 });
20337 this._pipeCache.set(pipeType, pipeMeta);
20338 this._summaryCache.set(pipeType, pipeMeta.toSummary());
20339 return pipeMeta;
20340 }
20341 _getDependenciesMetadata(typeOrFunc, dependencies, throwOnUnknownDeps = true) {
20342 let hasUnknownDeps = false;
20343 const params = dependencies || this._reflector.parameters(typeOrFunc) || [];
20344 const dependenciesMetadata = params.map((param) => {
20345 let isAttribute = false;
20346 let isHost = false;
20347 let isSelf = false;
20348 let isSkipSelf = false;
20349 let isOptional = false;
20350 let token = null;
20351 if (Array.isArray(param)) {
20352 param.forEach((paramEntry) => {
20353 if (createHost.isTypeOf(paramEntry)) {
20354 isHost = true;
20355 }
20356 else if (createSelf.isTypeOf(paramEntry)) {
20357 isSelf = true;
20358 }
20359 else if (createSkipSelf.isTypeOf(paramEntry)) {
20360 isSkipSelf = true;
20361 }
20362 else if (createOptional.isTypeOf(paramEntry)) {
20363 isOptional = true;
20364 }
20365 else if (createAttribute.isTypeOf(paramEntry)) {
20366 isAttribute = true;
20367 token = paramEntry.attributeName;
20368 }
20369 else if (createInject.isTypeOf(paramEntry)) {
20370 token = paramEntry.token;
20371 }
20372 else if (createInjectionToken.isTypeOf(paramEntry) ||
20373 paramEntry instanceof StaticSymbol) {
20374 token = paramEntry;
20375 }
20376 else if (isValidType(paramEntry) && token == null) {
20377 token = paramEntry;
20378 }
20379 });
20380 }
20381 else {
20382 token = param;
20383 }
20384 if (token == null) {
20385 hasUnknownDeps = true;
20386 return {};
20387 }
20388 return {
20389 isAttribute,
20390 isHost,
20391 isSelf,
20392 isSkipSelf,
20393 isOptional,
20394 token: this._getTokenMetadata(token)
20395 };
20396 });
20397 if (hasUnknownDeps) {
20398 const depsTokens = dependenciesMetadata.map((dep) => dep.token ? stringifyType(dep.token) : '?').join(', ');
20399 const message = `Can't resolve all parameters for ${stringifyType(typeOrFunc)}: (${depsTokens}).`;
20400 if (throwOnUnknownDeps || this._config.strictInjectionParameters) {
20401 this._reportError(syntaxError(message), typeOrFunc);
20402 }
20403 else {
20404 this._console.warn(`Warning: ${message} This will become an error in Angular v6.x`);
20405 }
20406 }
20407 return dependenciesMetadata;
20408 }
20409 _getTokenMetadata(token) {
20410 token = resolveForwardRef(token);
20411 let compileToken;
20412 if (typeof token === 'string') {
20413 compileToken = { value: token };
20414 }
20415 else {
20416 compileToken = { identifier: { reference: token } };
20417 }
20418 return compileToken;
20419 }
20420 _getProvidersMetadata(providers, targetEntryComponents, debugInfo, compileProviders = [], type) {
20421 providers.forEach((provider, providerIdx) => {
20422 if (Array.isArray(provider)) {
20423 this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
20424 }
20425 else {
20426 provider = resolveForwardRef(provider);
20427 let providerMeta = undefined;
20428 if (provider && typeof provider === 'object' && provider.hasOwnProperty('provide')) {
20429 this._validateProvider(provider);
20430 providerMeta = new ProviderMeta(provider.provide, provider);
20431 }
20432 else if (isValidType(provider)) {
20433 providerMeta = new ProviderMeta(provider, { useClass: provider });
20434 }
20435 else if (provider === void 0) {
20436 this._reportError(syntaxError(`Encountered undefined provider! Usually this means you have a circular dependencies. This might be caused by using 'barrel' index.ts files.`));
20437 return;
20438 }
20439 else {
20440 const providersInfo = providers.reduce((soFar, seenProvider, seenProviderIdx) => {
20441 if (seenProviderIdx < providerIdx) {
20442 soFar.push(`${stringifyType(seenProvider)}`);
20443 }
20444 else if (seenProviderIdx == providerIdx) {
20445 soFar.push(`?${stringifyType(seenProvider)}?`);
20446 }
20447 else if (seenProviderIdx == providerIdx + 1) {
20448 soFar.push('...');
20449 }
20450 return soFar;
20451 }, [])
20452 .join(', ');
20453 this._reportError(syntaxError(`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`), type);
20454 return;
20455 }
20456 if (providerMeta.token ===
20457 this._reflector.resolveExternalReference(Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS)) {
20458 targetEntryComponents.push(...this._getEntryComponentsFromProvider(providerMeta, type));
20459 }
20460 else {
20461 compileProviders.push(this.getProviderMetadata(providerMeta));
20462 }
20463 }
20464 });
20465 return compileProviders;
20466 }
20467 _validateProvider(provider) {
20468 if (provider.hasOwnProperty('useClass') && provider.useClass == null) {
20469 this._reportError(syntaxError(`Invalid provider for ${stringifyType(provider.provide)}. useClass cannot be ${provider.useClass}.
20470 Usually it happens when:
20471 1. There's a circular dependency (might be caused by using index.ts (barrel) files).
20472 2. Class was used before it was declared. Use forwardRef in this case.`));
20473 }
20474 }
20475 _getEntryComponentsFromProvider(provider, type) {
20476 const components = [];
20477 const collectedIdentifiers = [];
20478 if (provider.useFactory || provider.useExisting || provider.useClass) {
20479 this._reportError(syntaxError(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!`), type);
20480 return [];
20481 }
20482 if (!provider.multi) {
20483 this._reportError(syntaxError(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!`), type);
20484 return [];
20485 }
20486 extractIdentifiers(provider.useValue, collectedIdentifiers);
20487 collectedIdentifiers.forEach((identifier) => {
20488 const entry = this._getEntryComponentMetadata(identifier.reference, false);
20489 if (entry) {
20490 components.push(entry);
20491 }
20492 });
20493 return components;
20494 }
20495 _getEntryComponentMetadata(dirType, throwIfNotFound = true) {
20496 const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
20497 if (dirMeta && dirMeta.metadata.isComponent) {
20498 return { componentType: dirType, componentFactory: dirMeta.metadata.componentFactory };
20499 }
20500 const dirSummary = this._loadSummary(dirType, CompileSummaryKind.Directive);
20501 if (dirSummary && dirSummary.isComponent) {
20502 return { componentType: dirType, componentFactory: dirSummary.componentFactory };
20503 }
20504 if (throwIfNotFound) {
20505 throw syntaxError(`${dirType.name} cannot be used as an entry component.`);
20506 }
20507 return null;
20508 }
20509 _getInjectableTypeMetadata(type, dependencies = null) {
20510 const typeSummary = this._loadSummary(type, CompileSummaryKind.Injectable);
20511 if (typeSummary) {
20512 return typeSummary.type;
20513 }
20514 return this._getTypeMetadata(type, dependencies);
20515 }
20516 getProviderMetadata(provider) {
20517 let compileDeps = undefined;
20518 let compileTypeMetadata = null;
20519 let compileFactoryMetadata = null;
20520 let token = this._getTokenMetadata(provider.token);
20521 if (provider.useClass) {
20522 compileTypeMetadata =
20523 this._getInjectableTypeMetadata(provider.useClass, provider.dependencies);
20524 compileDeps = compileTypeMetadata.diDeps;
20525 if (provider.token === provider.useClass) {
20526 // use the compileTypeMetadata as it contains information about lifecycleHooks...
20527 token = { identifier: compileTypeMetadata };
20528 }
20529 }
20530 else if (provider.useFactory) {
20531 compileFactoryMetadata = this._getFactoryMetadata(provider.useFactory, provider.dependencies);
20532 compileDeps = compileFactoryMetadata.diDeps;
20533 }
20534 return {
20535 token: token,
20536 useClass: compileTypeMetadata,
20537 useValue: provider.useValue,
20538 useFactory: compileFactoryMetadata,
20539 useExisting: provider.useExisting ? this._getTokenMetadata(provider.useExisting) : undefined,
20540 deps: compileDeps,
20541 multi: provider.multi
20542 };
20543 }
20544 _getQueriesMetadata(queries, isViewQuery, directiveType) {
20545 const res = [];
20546 Object.keys(queries).forEach((propertyName) => {
20547 const query = queries[propertyName];
20548 if (query.isViewQuery === isViewQuery) {
20549 res.push(this._getQueryMetadata(query, propertyName, directiveType));
20550 }
20551 });
20552 return res;
20553 }
20554 _queryVarBindings(selector) { return selector.split(/\s*,\s*/); }
20555 _getQueryMetadata(q, propertyName, typeOrFunc) {
20556 let selectors;
20557 if (typeof q.selector === 'string') {
20558 selectors =
20559 this._queryVarBindings(q.selector).map(varName => this._getTokenMetadata(varName));
20560 }
20561 else {
20562 if (!q.selector) {
20563 this._reportError(syntaxError(`Can't construct a query for the property "${propertyName}" of "${stringifyType(typeOrFunc)}" since the query selector wasn't defined.`), typeOrFunc);
20564 selectors = [];
20565 }
20566 else {
20567 selectors = [this._getTokenMetadata(q.selector)];
20568 }
20569 }
20570 return {
20571 selectors,
20572 first: q.first,
20573 descendants: q.descendants, propertyName,
20574 read: q.read ? this._getTokenMetadata(q.read) : null,
20575 static: q.static
20576 };
20577 }
20578 _reportError(error, type, otherType) {
20579 if (this._errorCollector) {
20580 this._errorCollector(error, type);
20581 if (otherType) {
20582 this._errorCollector(error, otherType);
20583 }
20584 }
20585 else {
20586 throw error;
20587 }
20588 }
20589}
20590function flattenArray(tree, out = []) {
20591 if (tree) {
20592 for (let i = 0; i < tree.length; i++) {
20593 const item = resolveForwardRef(tree[i]);
20594 if (Array.isArray(item)) {
20595 flattenArray(item, out);
20596 }
20597 else {
20598 out.push(item);
20599 }
20600 }
20601 }
20602 return out;
20603}
20604function dedupeArray(array) {
20605 if (array) {
20606 return Array.from(new Set(array));
20607 }
20608 return [];
20609}
20610function flattenAndDedupeArray(tree) {
20611 return dedupeArray(flattenArray(tree));
20612}
20613function isValidType(value) {
20614 return (value instanceof StaticSymbol) || (value instanceof Type);
20615}
20616function extractIdentifiers(value, targetIdentifiers) {
20617 visitValue(value, new _CompileValueConverter(), targetIdentifiers);
20618}
20619class _CompileValueConverter extends ValueTransformer {
20620 visitOther(value, targetIdentifiers) {
20621 targetIdentifiers.push({ reference: value });
20622 }
20623}
20624function stringifyType(type) {
20625 if (type instanceof StaticSymbol) {
20626 return `${type.name} in ${type.filePath}`;
20627 }
20628 else {
20629 return stringify(type);
20630 }
20631}
20632/**
20633 * Indicates that a component is still being loaded in a synchronous compile.
20634 */
20635function componentStillLoadingError(compType) {
20636 const error = Error(`Can't compile synchronously as ${stringify(compType)} is still being loaded!`);
20637 error[ERROR_COMPONENT_TYPE] = compType;
20638 return error;
20639}
20640
20641/**
20642 * @license
20643 * Copyright Google Inc. All Rights Reserved.
20644 *
20645 * Use of this source code is governed by an MIT-style license that can be
20646 * found in the LICENSE file at https://angular.io/license
20647 */
20648function providerDef(ctx, providerAst) {
20649 let flags = 0 /* None */;
20650 if (!providerAst.eager) {
20651 flags |= 4096 /* LazyProvider */;
20652 }
20653 if (providerAst.providerType === ProviderAstType.PrivateService) {
20654 flags |= 8192 /* PrivateProvider */;
20655 }
20656 if (providerAst.isModule) {
20657 flags |= 1073741824 /* TypeModuleProvider */;
20658 }
20659 providerAst.lifecycleHooks.forEach((lifecycleHook) => {
20660 // for regular providers, we only support ngOnDestroy
20661 if (lifecycleHook === LifecycleHooks.OnDestroy ||
20662 providerAst.providerType === ProviderAstType.Directive ||
20663 providerAst.providerType === ProviderAstType.Component) {
20664 flags |= lifecycleHookToNodeFlag(lifecycleHook);
20665 }
20666 });
20667 const { providerExpr, flags: providerFlags, depsExpr } = providerAst.multiProvider ?
20668 multiProviderDef(ctx, flags, providerAst.providers) :
20669 singleProviderDef(ctx, flags, providerAst.providerType, providerAst.providers[0]);
20670 return {
20671 providerExpr,
20672 flags: providerFlags, depsExpr,
20673 tokenExpr: tokenExpr(ctx, providerAst.token),
20674 };
20675}
20676function multiProviderDef(ctx, flags, providers) {
20677 const allDepDefs = [];
20678 const allParams = [];
20679 const exprs = providers.map((provider, providerIndex) => {
20680 let expr;
20681 if (provider.useClass) {
20682 const depExprs = convertDeps(providerIndex, provider.deps || provider.useClass.diDeps);
20683 expr = ctx.importExpr(provider.useClass.reference).instantiate(depExprs);
20684 }
20685 else if (provider.useFactory) {
20686 const depExprs = convertDeps(providerIndex, provider.deps || provider.useFactory.diDeps);
20687 expr = ctx.importExpr(provider.useFactory.reference).callFn(depExprs);
20688 }
20689 else if (provider.useExisting) {
20690 const depExprs = convertDeps(providerIndex, [{ token: provider.useExisting }]);
20691 expr = depExprs[0];
20692 }
20693 else {
20694 expr = convertValueToOutputAst(ctx, provider.useValue);
20695 }
20696 return expr;
20697 });
20698 const providerExpr = fn(allParams, [new ReturnStatement(literalArr(exprs))], INFERRED_TYPE);
20699 return {
20700 providerExpr,
20701 flags: flags | 1024 /* TypeFactoryProvider */,
20702 depsExpr: literalArr(allDepDefs)
20703 };
20704 function convertDeps(providerIndex, deps) {
20705 return deps.map((dep, depIndex) => {
20706 const paramName = `p${providerIndex}_${depIndex}`;
20707 allParams.push(new FnParam(paramName, DYNAMIC_TYPE));
20708 allDepDefs.push(depDef(ctx, dep));
20709 return variable(paramName);
20710 });
20711 }
20712}
20713function singleProviderDef(ctx, flags, providerType, providerMeta) {
20714 let providerExpr;
20715 let deps;
20716 if (providerType === ProviderAstType.Directive || providerType === ProviderAstType.Component) {
20717 providerExpr = ctx.importExpr(providerMeta.useClass.reference);
20718 flags |= 16384 /* TypeDirective */;
20719 deps = providerMeta.deps || providerMeta.useClass.diDeps;
20720 }
20721 else {
20722 if (providerMeta.useClass) {
20723 providerExpr = ctx.importExpr(providerMeta.useClass.reference);
20724 flags |= 512 /* TypeClassProvider */;
20725 deps = providerMeta.deps || providerMeta.useClass.diDeps;
20726 }
20727 else if (providerMeta.useFactory) {
20728 providerExpr = ctx.importExpr(providerMeta.useFactory.reference);
20729 flags |= 1024 /* TypeFactoryProvider */;
20730 deps = providerMeta.deps || providerMeta.useFactory.diDeps;
20731 }
20732 else if (providerMeta.useExisting) {
20733 providerExpr = NULL_EXPR;
20734 flags |= 2048 /* TypeUseExistingProvider */;
20735 deps = [{ token: providerMeta.useExisting }];
20736 }
20737 else {
20738 providerExpr = convertValueToOutputAst(ctx, providerMeta.useValue);
20739 flags |= 256 /* TypeValueProvider */;
20740 deps = [];
20741 }
20742 }
20743 const depsExpr = literalArr(deps.map(dep => depDef(ctx, dep)));
20744 return { providerExpr, flags, depsExpr };
20745}
20746function tokenExpr(ctx, tokenMeta) {
20747 return tokenMeta.identifier ? ctx.importExpr(tokenMeta.identifier.reference) :
20748 literal(tokenMeta.value);
20749}
20750function depDef(ctx, dep) {
20751 // Note: the following fields have already been normalized out by provider_analyzer:
20752 // - isAttribute, isHost
20753 const expr = dep.isValue ? convertValueToOutputAst(ctx, dep.value) : tokenExpr(ctx, dep.token);
20754 let flags = 0 /* None */;
20755 if (dep.isSkipSelf) {
20756 flags |= 1 /* SkipSelf */;
20757 }
20758 if (dep.isOptional) {
20759 flags |= 2 /* Optional */;
20760 }
20761 if (dep.isSelf) {
20762 flags |= 4 /* Self */;
20763 }
20764 if (dep.isValue) {
20765 flags |= 8 /* Value */;
20766 }
20767 return flags === 0 /* None */ ? expr : literalArr([literal(flags), expr]);
20768}
20769function lifecycleHookToNodeFlag(lifecycleHook) {
20770 let nodeFlag = 0 /* None */;
20771 switch (lifecycleHook) {
20772 case LifecycleHooks.AfterContentChecked:
20773 nodeFlag = 2097152 /* AfterContentChecked */;
20774 break;
20775 case LifecycleHooks.AfterContentInit:
20776 nodeFlag = 1048576 /* AfterContentInit */;
20777 break;
20778 case LifecycleHooks.AfterViewChecked:
20779 nodeFlag = 8388608 /* AfterViewChecked */;
20780 break;
20781 case LifecycleHooks.AfterViewInit:
20782 nodeFlag = 4194304 /* AfterViewInit */;
20783 break;
20784 case LifecycleHooks.DoCheck:
20785 nodeFlag = 262144 /* DoCheck */;
20786 break;
20787 case LifecycleHooks.OnChanges:
20788 nodeFlag = 524288 /* OnChanges */;
20789 break;
20790 case LifecycleHooks.OnDestroy:
20791 nodeFlag = 131072 /* OnDestroy */;
20792 break;
20793 case LifecycleHooks.OnInit:
20794 nodeFlag = 65536 /* OnInit */;
20795 break;
20796 }
20797 return nodeFlag;
20798}
20799function componentFactoryResolverProviderDef(reflector, ctx, flags, entryComponents) {
20800 const entryComponentFactories = entryComponents.map((entryComponent) => ctx.importExpr(entryComponent.componentFactory));
20801 const token = createTokenForExternalReference(reflector, Identifiers.ComponentFactoryResolver);
20802 const classMeta = {
20803 diDeps: [
20804 { isValue: true, value: literalArr(entryComponentFactories) },
20805 { token: token, isSkipSelf: true, isOptional: true },
20806 { token: createTokenForExternalReference(reflector, Identifiers.NgModuleRef) },
20807 ],
20808 lifecycleHooks: [],
20809 reference: reflector.resolveExternalReference(Identifiers.CodegenComponentFactoryResolver)
20810 };
20811 const { providerExpr, flags: providerFlags, depsExpr } = singleProviderDef(ctx, flags, ProviderAstType.PrivateService, {
20812 token,
20813 multi: false,
20814 useClass: classMeta,
20815 });
20816 return { providerExpr, flags: providerFlags, depsExpr, tokenExpr: tokenExpr(ctx, token) };
20817}
20818
20819/**
20820 * @license
20821 * Copyright Google Inc. All Rights Reserved.
20822 *
20823 * Use of this source code is governed by an MIT-style license that can be
20824 * found in the LICENSE file at https://angular.io/license
20825 */
20826class NgModuleCompileResult {
20827 constructor(ngModuleFactoryVar) {
20828 this.ngModuleFactoryVar = ngModuleFactoryVar;
20829 }
20830}
20831const LOG_VAR = variable('_l');
20832class NgModuleCompiler {
20833 constructor(reflector) {
20834 this.reflector = reflector;
20835 }
20836 compile(ctx, ngModuleMeta, extraProviders) {
20837 const sourceSpan = typeSourceSpan('NgModule', ngModuleMeta.type);
20838 const entryComponentFactories = ngModuleMeta.transitiveModule.entryComponents;
20839 const bootstrapComponents = ngModuleMeta.bootstrapComponents;
20840 const providerParser = new NgModuleProviderAnalyzer(this.reflector, ngModuleMeta, extraProviders, sourceSpan);
20841 const providerDefs = [componentFactoryResolverProviderDef(this.reflector, ctx, 0 /* None */, entryComponentFactories)]
20842 .concat(providerParser.parse().map((provider) => providerDef(ctx, provider)))
20843 .map(({ providerExpr, depsExpr, flags, tokenExpr }) => {
20844 return importExpr(Identifiers.moduleProviderDef).callFn([
20845 literal(flags), tokenExpr, providerExpr, depsExpr
20846 ]);
20847 });
20848 const ngModuleDef = importExpr(Identifiers.moduleDef).callFn([literalArr(providerDefs)]);
20849 const ngModuleDefFactory = fn([new FnParam(LOG_VAR.name)], [new ReturnStatement(ngModuleDef)], INFERRED_TYPE);
20850 const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`;
20851 this._createNgModuleFactory(ctx, ngModuleMeta.type.reference, importExpr(Identifiers.createModuleFactory).callFn([
20852 ctx.importExpr(ngModuleMeta.type.reference),
20853 literalArr(bootstrapComponents.map(id => ctx.importExpr(id.reference))),
20854 ngModuleDefFactory
20855 ]));
20856 if (ngModuleMeta.id) {
20857 const id = typeof ngModuleMeta.id === 'string' ? literal(ngModuleMeta.id) :
20858 ctx.importExpr(ngModuleMeta.id);
20859 const registerFactoryStmt = importExpr(Identifiers.RegisterModuleFactoryFn)
20860 .callFn([id, variable(ngModuleFactoryVar)])
20861 .toStmt();
20862 ctx.statements.push(registerFactoryStmt);
20863 }
20864 return new NgModuleCompileResult(ngModuleFactoryVar);
20865 }
20866 createStub(ctx, ngModuleReference) {
20867 this._createNgModuleFactory(ctx, ngModuleReference, NULL_EXPR);
20868 }
20869 _createNgModuleFactory(ctx, reference, value) {
20870 const ngModuleFactoryVar = `${identifierName({ reference: reference })}NgFactory`;
20871 const ngModuleFactoryStmt = variable(ngModuleFactoryVar)
20872 .set(value)
20873 .toDeclStmt(importType(Identifiers.NgModuleFactory, [expressionType(ctx.importExpr(reference))], [TypeModifier.Const]), [StmtModifier.Final, StmtModifier.Exported]);
20874 ctx.statements.push(ngModuleFactoryStmt);
20875 }
20876}
20877
20878/**
20879 * @license
20880 * Copyright Google Inc. All Rights Reserved.
20881 *
20882 * Use of this source code is governed by an MIT-style license that can be
20883 * found in the LICENSE file at https://angular.io/license
20884 */
20885/**
20886 * Resolves types to {@link NgModule}.
20887 */
20888class NgModuleResolver {
20889 constructor(_reflector) {
20890 this._reflector = _reflector;
20891 }
20892 isNgModule(type) { return this._reflector.annotations(type).some(createNgModule.isTypeOf); }
20893 resolve(type, throwIfNotFound = true) {
20894 const ngModuleMeta = findLast(this._reflector.annotations(type), createNgModule.isTypeOf);
20895 if (ngModuleMeta) {
20896 return ngModuleMeta;
20897 }
20898 else {
20899 if (throwIfNotFound) {
20900 throw new Error(`No NgModule metadata found for '${stringify(type)}'.`);
20901 }
20902 return null;
20903 }
20904 }
20905}
20906
20907/**
20908 * @license
20909 * Copyright Google Inc. All Rights Reserved.
20910 *
20911 * Use of this source code is governed by an MIT-style license that can be
20912 * found in the LICENSE file at https://angular.io/license
20913 */
20914const _debugFilePath = '/debug/lib';
20915function debugOutputAstAsTypeScript(ast) {
20916 const converter = new _TsEmitterVisitor();
20917 const ctx = EmitterVisitorContext.createRoot();
20918 const asts = Array.isArray(ast) ? ast : [ast];
20919 asts.forEach((ast) => {
20920 if (ast instanceof Statement) {
20921 ast.visitStatement(converter, ctx);
20922 }
20923 else if (ast instanceof Expression) {
20924 ast.visitExpression(converter, ctx);
20925 }
20926 else if (ast instanceof Type$1) {
20927 ast.visitType(converter, ctx);
20928 }
20929 else {
20930 throw new Error(`Don't know how to print debug info for ${ast}`);
20931 }
20932 });
20933 return ctx.toSource();
20934}
20935class TypeScriptEmitter {
20936 emitStatementsAndContext(genFilePath, stmts, preamble = '', emitSourceMaps = true, referenceFilter, importFilter) {
20937 const converter = new _TsEmitterVisitor(referenceFilter, importFilter);
20938 const ctx = EmitterVisitorContext.createRoot();
20939 converter.visitAllStatements(stmts, ctx);
20940 const preambleLines = preamble ? preamble.split('\n') : [];
20941 converter.reexports.forEach((reexports, exportedModuleName) => {
20942 const reexportsCode = reexports.map(reexport => `${reexport.name} as ${reexport.as}`).join(',');
20943 preambleLines.push(`export {${reexportsCode}} from '${exportedModuleName}';`);
20944 });
20945 converter.importsWithPrefixes.forEach((prefix, importedModuleName) => {
20946 // Note: can't write the real word for import as it screws up system.js auto detection...
20947 preambleLines.push(`imp` +
20948 `ort * as ${prefix} from '${importedModuleName}';`);
20949 });
20950 const sm = emitSourceMaps ?
20951 ctx.toSourceMapGenerator(genFilePath, preambleLines.length).toJsComment() :
20952 '';
20953 const lines = [...preambleLines, ctx.toSource(), sm];
20954 if (sm) {
20955 // always add a newline at the end, as some tools have bugs without it.
20956 lines.push('');
20957 }
20958 ctx.setPreambleLineCount(preambleLines.length);
20959 return { sourceText: lines.join('\n'), context: ctx };
20960 }
20961 emitStatements(genFilePath, stmts, preamble = '') {
20962 return this.emitStatementsAndContext(genFilePath, stmts, preamble).sourceText;
20963 }
20964}
20965class _TsEmitterVisitor extends AbstractEmitterVisitor {
20966 constructor(referenceFilter, importFilter) {
20967 super(false);
20968 this.referenceFilter = referenceFilter;
20969 this.importFilter = importFilter;
20970 this.typeExpression = 0;
20971 this.importsWithPrefixes = new Map();
20972 this.reexports = new Map();
20973 }
20974 visitType(t, ctx, defaultType = 'any') {
20975 if (t) {
20976 this.typeExpression++;
20977 t.visitType(this, ctx);
20978 this.typeExpression--;
20979 }
20980 else {
20981 ctx.print(null, defaultType);
20982 }
20983 }
20984 visitLiteralExpr(ast, ctx) {
20985 const value = ast.value;
20986 if (value == null && ast.type != INFERRED_TYPE) {
20987 ctx.print(ast, `(${value} as any)`);
20988 return null;
20989 }
20990 return super.visitLiteralExpr(ast, ctx);
20991 }
20992 // Temporary workaround to support strictNullCheck enabled consumers of ngc emit.
20993 // In SNC mode, [] have the type never[], so we cast here to any[].
20994 // TODO: narrow the cast to a more explicit type, or use a pattern that does not
20995 // start with [].concat. see https://github.com/angular/angular/pull/11846
20996 visitLiteralArrayExpr(ast, ctx) {
20997 if (ast.entries.length === 0) {
20998 ctx.print(ast, '(');
20999 }
21000 const result = super.visitLiteralArrayExpr(ast, ctx);
21001 if (ast.entries.length === 0) {
21002 ctx.print(ast, ' as any[])');
21003 }
21004 return result;
21005 }
21006 visitExternalExpr(ast, ctx) {
21007 this._visitIdentifier(ast.value, ast.typeParams, ctx);
21008 return null;
21009 }
21010 visitAssertNotNullExpr(ast, ctx) {
21011 const result = super.visitAssertNotNullExpr(ast, ctx);
21012 ctx.print(ast, '!');
21013 return result;
21014 }
21015 visitDeclareVarStmt(stmt, ctx) {
21016 if (stmt.hasModifier(StmtModifier.Exported) && stmt.value instanceof ExternalExpr &&
21017 !stmt.type) {
21018 // check for a reexport
21019 const { name, moduleName } = stmt.value.value;
21020 if (moduleName) {
21021 let reexports = this.reexports.get(moduleName);
21022 if (!reexports) {
21023 reexports = [];
21024 this.reexports.set(moduleName, reexports);
21025 }
21026 reexports.push({ name: name, as: stmt.name });
21027 return null;
21028 }
21029 }
21030 if (stmt.hasModifier(StmtModifier.Exported)) {
21031 ctx.print(stmt, `export `);
21032 }
21033 if (stmt.hasModifier(StmtModifier.Final)) {
21034 ctx.print(stmt, `const`);
21035 }
21036 else {
21037 ctx.print(stmt, `var`);
21038 }
21039 ctx.print(stmt, ` ${stmt.name}`);
21040 this._printColonType(stmt.type, ctx);
21041 if (stmt.value) {
21042 ctx.print(stmt, ` = `);
21043 stmt.value.visitExpression(this, ctx);
21044 }
21045 ctx.println(stmt, `;`);
21046 return null;
21047 }
21048 visitWrappedNodeExpr(ast, ctx) {
21049 throw new Error('Cannot visit a WrappedNodeExpr when outputting Typescript.');
21050 }
21051 visitCastExpr(ast, ctx) {
21052 ctx.print(ast, `(<`);
21053 ast.type.visitType(this, ctx);
21054 ctx.print(ast, `>`);
21055 ast.value.visitExpression(this, ctx);
21056 ctx.print(ast, `)`);
21057 return null;
21058 }
21059 visitInstantiateExpr(ast, ctx) {
21060 ctx.print(ast, `new `);
21061 this.typeExpression++;
21062 ast.classExpr.visitExpression(this, ctx);
21063 this.typeExpression--;
21064 ctx.print(ast, `(`);
21065 this.visitAllExpressions(ast.args, ctx, ',');
21066 ctx.print(ast, `)`);
21067 return null;
21068 }
21069 visitDeclareClassStmt(stmt, ctx) {
21070 ctx.pushClass(stmt);
21071 if (stmt.hasModifier(StmtModifier.Exported)) {
21072 ctx.print(stmt, `export `);
21073 }
21074 ctx.print(stmt, `class ${stmt.name}`);
21075 if (stmt.parent != null) {
21076 ctx.print(stmt, ` extends `);
21077 this.typeExpression++;
21078 stmt.parent.visitExpression(this, ctx);
21079 this.typeExpression--;
21080 }
21081 ctx.println(stmt, ` {`);
21082 ctx.incIndent();
21083 stmt.fields.forEach((field) => this._visitClassField(field, ctx));
21084 if (stmt.constructorMethod != null) {
21085 this._visitClassConstructor(stmt, ctx);
21086 }
21087 stmt.getters.forEach((getter) => this._visitClassGetter(getter, ctx));
21088 stmt.methods.forEach((method) => this._visitClassMethod(method, ctx));
21089 ctx.decIndent();
21090 ctx.println(stmt, `}`);
21091 ctx.popClass();
21092 return null;
21093 }
21094 _visitClassField(field, ctx) {
21095 if (field.hasModifier(StmtModifier.Private)) {
21096 // comment out as a workaround for #10967
21097 ctx.print(null, `/*private*/ `);
21098 }
21099 if (field.hasModifier(StmtModifier.Static)) {
21100 ctx.print(null, 'static ');
21101 }
21102 ctx.print(null, field.name);
21103 this._printColonType(field.type, ctx);
21104 if (field.initializer) {
21105 ctx.print(null, ' = ');
21106 field.initializer.visitExpression(this, ctx);
21107 }
21108 ctx.println(null, `;`);
21109 }
21110 _visitClassGetter(getter, ctx) {
21111 if (getter.hasModifier(StmtModifier.Private)) {
21112 ctx.print(null, `private `);
21113 }
21114 ctx.print(null, `get ${getter.name}()`);
21115 this._printColonType(getter.type, ctx);
21116 ctx.println(null, ` {`);
21117 ctx.incIndent();
21118 this.visitAllStatements(getter.body, ctx);
21119 ctx.decIndent();
21120 ctx.println(null, `}`);
21121 }
21122 _visitClassConstructor(stmt, ctx) {
21123 ctx.print(stmt, `constructor(`);
21124 this._visitParams(stmt.constructorMethod.params, ctx);
21125 ctx.println(stmt, `) {`);
21126 ctx.incIndent();
21127 this.visitAllStatements(stmt.constructorMethod.body, ctx);
21128 ctx.decIndent();
21129 ctx.println(stmt, `}`);
21130 }
21131 _visitClassMethod(method, ctx) {
21132 if (method.hasModifier(StmtModifier.Private)) {
21133 ctx.print(null, `private `);
21134 }
21135 ctx.print(null, `${method.name}(`);
21136 this._visitParams(method.params, ctx);
21137 ctx.print(null, `)`);
21138 this._printColonType(method.type, ctx, 'void');
21139 ctx.println(null, ` {`);
21140 ctx.incIndent();
21141 this.visitAllStatements(method.body, ctx);
21142 ctx.decIndent();
21143 ctx.println(null, `}`);
21144 }
21145 visitFunctionExpr(ast, ctx) {
21146 if (ast.name) {
21147 ctx.print(ast, 'function ');
21148 ctx.print(ast, ast.name);
21149 }
21150 ctx.print(ast, `(`);
21151 this._visitParams(ast.params, ctx);
21152 ctx.print(ast, `)`);
21153 this._printColonType(ast.type, ctx, 'void');
21154 if (!ast.name) {
21155 ctx.print(ast, ` => `);
21156 }
21157 ctx.println(ast, '{');
21158 ctx.incIndent();
21159 this.visitAllStatements(ast.statements, ctx);
21160 ctx.decIndent();
21161 ctx.print(ast, `}`);
21162 return null;
21163 }
21164 visitDeclareFunctionStmt(stmt, ctx) {
21165 if (stmt.hasModifier(StmtModifier.Exported)) {
21166 ctx.print(stmt, `export `);
21167 }
21168 ctx.print(stmt, `function ${stmt.name}(`);
21169 this._visitParams(stmt.params, ctx);
21170 ctx.print(stmt, `)`);
21171 this._printColonType(stmt.type, ctx, 'void');
21172 ctx.println(stmt, ` {`);
21173 ctx.incIndent();
21174 this.visitAllStatements(stmt.statements, ctx);
21175 ctx.decIndent();
21176 ctx.println(stmt, `}`);
21177 return null;
21178 }
21179 visitTryCatchStmt(stmt, ctx) {
21180 ctx.println(stmt, `try {`);
21181 ctx.incIndent();
21182 this.visitAllStatements(stmt.bodyStmts, ctx);
21183 ctx.decIndent();
21184 ctx.println(stmt, `} catch (${CATCH_ERROR_VAR$1.name}) {`);
21185 ctx.incIndent();
21186 const catchStmts = [CATCH_STACK_VAR$1.set(CATCH_ERROR_VAR$1.prop('stack', null)).toDeclStmt(null, [
21187 StmtModifier.Final
21188 ])].concat(stmt.catchStmts);
21189 this.visitAllStatements(catchStmts, ctx);
21190 ctx.decIndent();
21191 ctx.println(stmt, `}`);
21192 return null;
21193 }
21194 visitBuiltinType(type, ctx) {
21195 let typeStr;
21196 switch (type.name) {
21197 case BuiltinTypeName.Bool:
21198 typeStr = 'boolean';
21199 break;
21200 case BuiltinTypeName.Dynamic:
21201 typeStr = 'any';
21202 break;
21203 case BuiltinTypeName.Function:
21204 typeStr = 'Function';
21205 break;
21206 case BuiltinTypeName.Number:
21207 typeStr = 'number';
21208 break;
21209 case BuiltinTypeName.Int:
21210 typeStr = 'number';
21211 break;
21212 case BuiltinTypeName.String:
21213 typeStr = 'string';
21214 break;
21215 case BuiltinTypeName.None:
21216 typeStr = 'never';
21217 break;
21218 default:
21219 throw new Error(`Unsupported builtin type ${type.name}`);
21220 }
21221 ctx.print(null, typeStr);
21222 return null;
21223 }
21224 visitExpressionType(ast, ctx) {
21225 ast.value.visitExpression(this, ctx);
21226 if (ast.typeParams !== null) {
21227 ctx.print(null, '<');
21228 this.visitAllObjects(type => this.visitType(type, ctx), ast.typeParams, ctx, ',');
21229 ctx.print(null, '>');
21230 }
21231 return null;
21232 }
21233 visitArrayType(type, ctx) {
21234 this.visitType(type.of, ctx);
21235 ctx.print(null, `[]`);
21236 return null;
21237 }
21238 visitMapType(type, ctx) {
21239 ctx.print(null, `{[key: string]:`);
21240 this.visitType(type.valueType, ctx);
21241 ctx.print(null, `}`);
21242 return null;
21243 }
21244 getBuiltinMethodName(method) {
21245 let name;
21246 switch (method) {
21247 case BuiltinMethod.ConcatArray:
21248 name = 'concat';
21249 break;
21250 case BuiltinMethod.SubscribeObservable:
21251 name = 'subscribe';
21252 break;
21253 case BuiltinMethod.Bind:
21254 name = 'bind';
21255 break;
21256 default:
21257 throw new Error(`Unknown builtin method: ${method}`);
21258 }
21259 return name;
21260 }
21261 _visitParams(params, ctx) {
21262 this.visitAllObjects(param => {
21263 ctx.print(null, param.name);
21264 this._printColonType(param.type, ctx);
21265 }, params, ctx, ',');
21266 }
21267 _visitIdentifier(value, typeParams, ctx) {
21268 const { name, moduleName } = value;
21269 if (this.referenceFilter && this.referenceFilter(value)) {
21270 ctx.print(null, '(null as any)');
21271 return;
21272 }
21273 if (moduleName && (!this.importFilter || !this.importFilter(value))) {
21274 let prefix = this.importsWithPrefixes.get(moduleName);
21275 if (prefix == null) {
21276 prefix = `i${this.importsWithPrefixes.size}`;
21277 this.importsWithPrefixes.set(moduleName, prefix);
21278 }
21279 ctx.print(null, `${prefix}.`);
21280 }
21281 ctx.print(null, name);
21282 if (this.typeExpression > 0) {
21283 // If we are in a type expression that refers to a generic type then supply
21284 // the required type parameters. If there were not enough type parameters
21285 // supplied, supply any as the type. Outside a type expression the reference
21286 // should not supply type parameters and be treated as a simple value reference
21287 // to the constructor function itself.
21288 const suppliedParameters = typeParams || [];
21289 if (suppliedParameters.length > 0) {
21290 ctx.print(null, `<`);
21291 this.visitAllObjects(type => type.visitType(this, ctx), typeParams, ctx, ',');
21292 ctx.print(null, `>`);
21293 }
21294 }
21295 }
21296 _printColonType(type, ctx, defaultType) {
21297 if (type !== INFERRED_TYPE) {
21298 ctx.print(null, ':');
21299 this.visitType(type, ctx, defaultType);
21300 }
21301 }
21302}
21303
21304/**
21305 * @license
21306 * Copyright Google Inc. All Rights Reserved.
21307 *
21308 * Use of this source code is governed by an MIT-style license that can be
21309 * found in the LICENSE file at https://angular.io/license
21310 */
21311/**
21312 * Resolve a `Type` for {@link Pipe}.
21313 *
21314 * This interface can be overridden by the application developer to create custom behavior.
21315 *
21316 * See {@link Compiler}
21317 */
21318class PipeResolver {
21319 constructor(_reflector) {
21320 this._reflector = _reflector;
21321 }
21322 isPipe(type) {
21323 const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
21324 return typeMetadata && typeMetadata.some(createPipe.isTypeOf);
21325 }
21326 /**
21327 * Return {@link Pipe} for a given `Type`.
21328 */
21329 resolve(type, throwIfNotFound = true) {
21330 const metas = this._reflector.annotations(resolveForwardRef(type));
21331 if (metas) {
21332 const annotation = findLast(metas, createPipe.isTypeOf);
21333 if (annotation) {
21334 return annotation;
21335 }
21336 }
21337 if (throwIfNotFound) {
21338 throw new Error(`No Pipe decorator found on ${stringify(type)}`);
21339 }
21340 return null;
21341 }
21342}
21343
21344/**
21345 * @license
21346 * Copyright Google Inc. All Rights Reserved.
21347 *
21348 * Use of this source code is governed by an MIT-style license that can be
21349 * found in the LICENSE file at https://angular.io/license
21350 */
21351/**
21352 * Generates code that is used to type check templates.
21353 */
21354class TypeCheckCompiler {
21355 constructor(options, reflector) {
21356 this.options = options;
21357 this.reflector = reflector;
21358 }
21359 /**
21360 * Important notes:
21361 * - This must not produce new `import` statements, but only refer to types outside
21362 * of the file via the variables provided via externalReferenceVars.
21363 * This allows Typescript to reuse the old program's structure as no imports have changed.
21364 * - This must not produce any exports, as this would pollute the .d.ts file
21365 * and also violate the point above.
21366 */
21367 compileComponent(componentId, component, template, usedPipes, externalReferenceVars, ctx) {
21368 const pipes = new Map();
21369 usedPipes.forEach(p => pipes.set(p.name, p.type.reference));
21370 let embeddedViewCount = 0;
21371 const viewBuilderFactory = (parent, guards) => {
21372 const embeddedViewIndex = embeddedViewCount++;
21373 return new ViewBuilder(this.options, this.reflector, externalReferenceVars, parent, component.type.reference, component.isHost, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory);
21374 };
21375 const visitor = viewBuilderFactory(null, []);
21376 visitor.visitAll([], template);
21377 return visitor.build(componentId);
21378 }
21379}
21380const DYNAMIC_VAR_NAME = '_any';
21381class TypeCheckLocalResolver {
21382 notifyImplicitReceiverUse() { }
21383 getLocal(name) {
21384 if (name === EventHandlerVars.event.name) {
21385 // References to the event should not be type-checked.
21386 // TODO(chuckj): determine a better type for the event.
21387 return variable(DYNAMIC_VAR_NAME);
21388 }
21389 return null;
21390 }
21391}
21392const defaultResolver = new TypeCheckLocalResolver();
21393class ViewBuilder {
21394 constructor(options, reflector, externalReferenceVars, parent, component, isHostComponent, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory) {
21395 this.options = options;
21396 this.reflector = reflector;
21397 this.externalReferenceVars = externalReferenceVars;
21398 this.parent = parent;
21399 this.component = component;
21400 this.isHostComponent = isHostComponent;
21401 this.embeddedViewIndex = embeddedViewIndex;
21402 this.pipes = pipes;
21403 this.guards = guards;
21404 this.ctx = ctx;
21405 this.viewBuilderFactory = viewBuilderFactory;
21406 this.refOutputVars = new Map();
21407 this.variables = [];
21408 this.children = [];
21409 this.updates = [];
21410 this.actions = [];
21411 }
21412 getOutputVar(type) {
21413 let varName;
21414 if (type === this.component && this.isHostComponent) {
21415 varName = DYNAMIC_VAR_NAME;
21416 }
21417 else if (type instanceof StaticSymbol) {
21418 varName = this.externalReferenceVars.get(type);
21419 }
21420 else {
21421 varName = DYNAMIC_VAR_NAME;
21422 }
21423 if (!varName) {
21424 throw new Error(`Illegal State: referring to a type without a variable ${JSON.stringify(type)}`);
21425 }
21426 return varName;
21427 }
21428 getTypeGuardExpressions(ast) {
21429 const result = [...this.guards];
21430 for (let directive of ast.directives) {
21431 for (let input of directive.inputs) {
21432 const guard = directive.directive.guards[input.directiveName];
21433 if (guard) {
21434 const useIf = guard === 'UseIf';
21435 result.push({
21436 guard,
21437 useIf,
21438 expression: { context: this.component, value: input.value }
21439 });
21440 }
21441 }
21442 }
21443 return result;
21444 }
21445 visitAll(variables, astNodes) {
21446 this.variables = variables;
21447 templateVisitAll(this, astNodes);
21448 }
21449 build(componentId, targetStatements = []) {
21450 this.children.forEach((child) => child.build(componentId, targetStatements));
21451 let viewStmts = [variable(DYNAMIC_VAR_NAME).set(NULL_EXPR).toDeclStmt(DYNAMIC_TYPE)];
21452 let bindingCount = 0;
21453 this.updates.forEach((expression) => {
21454 const { sourceSpan, context, value } = this.preprocessUpdateExpression(expression);
21455 const bindingId = `${bindingCount++}`;
21456 const nameResolver = context === this.component ? this : defaultResolver;
21457 const { stmts, currValExpr } = convertPropertyBinding(nameResolver, variable(this.getOutputVar(context)), value, bindingId, BindingForm.General);
21458 stmts.push(new ExpressionStatement(currValExpr));
21459 viewStmts.push(...stmts.map((stmt) => applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
21460 });
21461 this.actions.forEach(({ sourceSpan, context, value }) => {
21462 const bindingId = `${bindingCount++}`;
21463 const nameResolver = context === this.component ? this : defaultResolver;
21464 const { stmts } = convertActionBinding(nameResolver, variable(this.getOutputVar(context)), value, bindingId);
21465 viewStmts.push(...stmts.map((stmt) => applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
21466 });
21467 if (this.guards.length) {
21468 let guardExpression = undefined;
21469 for (const guard of this.guards) {
21470 const { context, value } = this.preprocessUpdateExpression(guard.expression);
21471 const bindingId = `${bindingCount++}`;
21472 const nameResolver = context === this.component ? this : defaultResolver;
21473 // We only support support simple expressions and ignore others as they
21474 // are unlikely to affect type narrowing.
21475 const { stmts, currValExpr } = convertPropertyBinding(nameResolver, variable(this.getOutputVar(context)), value, bindingId, BindingForm.TrySimple);
21476 if (stmts.length == 0) {
21477 const guardClause = guard.useIf ? currValExpr : this.ctx.importExpr(guard.guard).callFn([currValExpr]);
21478 guardExpression = guardExpression ? guardExpression.and(guardClause) : guardClause;
21479 }
21480 }
21481 if (guardExpression) {
21482 viewStmts = [new IfStmt(guardExpression, viewStmts)];
21483 }
21484 }
21485 const viewName = `_View_${componentId}_${this.embeddedViewIndex}`;
21486 const viewFactory = new DeclareFunctionStmt(viewName, [], viewStmts);
21487 targetStatements.push(viewFactory);
21488 return targetStatements;
21489 }
21490 visitBoundText(ast, context) {
21491 const astWithSource = ast.value;
21492 const inter = astWithSource.ast;
21493 inter.expressions.forEach((expr) => this.updates.push({ context: this.component, value: expr, sourceSpan: ast.sourceSpan }));
21494 }
21495 visitEmbeddedTemplate(ast, context) {
21496 this.visitElementOrTemplate(ast);
21497 // Note: The old view compiler used to use an `any` type
21498 // for the context in any embedded view.
21499 // We keep this behaivor behind a flag for now.
21500 if (this.options.fullTemplateTypeCheck) {
21501 // Find any applicable type guards. For example, NgIf has a type guard on ngIf
21502 // (see NgIf.ngIfTypeGuard) that can be used to indicate that a template is only
21503 // stamped out if ngIf is truthy so any bindings in the template can assume that,
21504 // if a nullable type is used for ngIf, that expression is not null or undefined.
21505 const guards = this.getTypeGuardExpressions(ast);
21506 const childVisitor = this.viewBuilderFactory(this, guards);
21507 this.children.push(childVisitor);
21508 childVisitor.visitAll(ast.variables, ast.children);
21509 }
21510 }
21511 visitElement(ast, context) {
21512 this.visitElementOrTemplate(ast);
21513 let inputDefs = [];
21514 let updateRendererExpressions = [];
21515 let outputDefs = [];
21516 ast.inputs.forEach((inputAst) => {
21517 this.updates.push({ context: this.component, value: inputAst.value, sourceSpan: inputAst.sourceSpan });
21518 });
21519 templateVisitAll(this, ast.children);
21520 }
21521 visitElementOrTemplate(ast) {
21522 ast.directives.forEach((dirAst) => { this.visitDirective(dirAst); });
21523 ast.references.forEach((ref) => {
21524 let outputVarType = null;
21525 // Note: The old view compiler used to use an `any` type
21526 // for directives exposed via `exportAs`.
21527 // We keep this behaivor behind a flag for now.
21528 if (ref.value && ref.value.identifier && this.options.fullTemplateTypeCheck) {
21529 outputVarType = ref.value.identifier.reference;
21530 }
21531 else {
21532 outputVarType = BuiltinTypeName.Dynamic;
21533 }
21534 this.refOutputVars.set(ref.name, outputVarType);
21535 });
21536 ast.outputs.forEach((outputAst) => {
21537 this.actions.push({ context: this.component, value: outputAst.handler, sourceSpan: outputAst.sourceSpan });
21538 });
21539 }
21540 visitDirective(dirAst) {
21541 const dirType = dirAst.directive.type.reference;
21542 dirAst.inputs.forEach((input) => this.updates.push({ context: this.component, value: input.value, sourceSpan: input.sourceSpan }));
21543 // Note: The old view compiler used to use an `any` type
21544 // for expressions in host properties / events.
21545 // We keep this behaivor behind a flag for now.
21546 if (this.options.fullTemplateTypeCheck) {
21547 dirAst.hostProperties.forEach((inputAst) => this.updates.push({ context: dirType, value: inputAst.value, sourceSpan: inputAst.sourceSpan }));
21548 dirAst.hostEvents.forEach((hostEventAst) => this.actions.push({
21549 context: dirType,
21550 value: hostEventAst.handler,
21551 sourceSpan: hostEventAst.sourceSpan
21552 }));
21553 }
21554 }
21555 notifyImplicitReceiverUse() { }
21556 getLocal(name) {
21557 if (name == EventHandlerVars.event.name) {
21558 return variable(this.getOutputVar(BuiltinTypeName.Dynamic));
21559 }
21560 for (let currBuilder = this; currBuilder; currBuilder = currBuilder.parent) {
21561 let outputVarType;
21562 // check references
21563 outputVarType = currBuilder.refOutputVars.get(name);
21564 if (outputVarType == null) {
21565 // check variables
21566 const varAst = currBuilder.variables.find((varAst) => varAst.name === name);
21567 if (varAst) {
21568 outputVarType = BuiltinTypeName.Dynamic;
21569 }
21570 }
21571 if (outputVarType != null) {
21572 return variable(this.getOutputVar(outputVarType));
21573 }
21574 }
21575 return null;
21576 }
21577 pipeOutputVar(name) {
21578 const pipe = this.pipes.get(name);
21579 if (!pipe) {
21580 throw new Error(`Illegal State: Could not find pipe ${name} in template of ${this.component}`);
21581 }
21582 return this.getOutputVar(pipe);
21583 }
21584 preprocessUpdateExpression(expression) {
21585 return {
21586 sourceSpan: expression.sourceSpan,
21587 context: expression.context,
21588 value: convertPropertyBindingBuiltins({
21589 createLiteralArrayConverter: (argCount) => (args) => {
21590 const arr = literalArr(args);
21591 // Note: The old view compiler used to use an `any` type
21592 // for arrays.
21593 return this.options.fullTemplateTypeCheck ? arr : arr.cast(DYNAMIC_TYPE);
21594 },
21595 createLiteralMapConverter: (keys) => (values) => {
21596 const entries = keys.map((k, i) => ({
21597 key: k.key,
21598 value: values[i],
21599 quoted: k.quoted,
21600 }));
21601 const map = literalMap(entries);
21602 // Note: The old view compiler used to use an `any` type
21603 // for maps.
21604 return this.options.fullTemplateTypeCheck ? map : map.cast(DYNAMIC_TYPE);
21605 },
21606 createPipeConverter: (name, argCount) => (args) => {
21607 // Note: The old view compiler used to use an `any` type
21608 // for pipes.
21609 const pipeExpr = this.options.fullTemplateTypeCheck ?
21610 variable(this.pipeOutputVar(name)) :
21611 variable(this.getOutputVar(BuiltinTypeName.Dynamic));
21612 return pipeExpr.callMethod('transform', args);
21613 },
21614 }, expression.value)
21615 };
21616 }
21617 visitNgContent(ast, context) { }
21618 visitText(ast, context) { }
21619 visitDirectiveProperty(ast, context) { }
21620 visitReference(ast, context) { }
21621 visitVariable(ast, context) { }
21622 visitEvent(ast, context) { }
21623 visitElementProperty(ast, context) { }
21624 visitAttr(ast, context) { }
21625}
21626
21627/**
21628 * @license
21629 * Copyright Google Inc. All Rights Reserved.
21630 *
21631 * Use of this source code is governed by an MIT-style license that can be
21632 * found in the LICENSE file at https://angular.io/license
21633 */
21634const CLASS_ATTR$1 = 'class';
21635const STYLE_ATTR = 'style';
21636const IMPLICIT_TEMPLATE_VAR = '\$implicit';
21637class ViewCompileResult {
21638 constructor(viewClassVar, rendererTypeVar) {
21639 this.viewClassVar = viewClassVar;
21640 this.rendererTypeVar = rendererTypeVar;
21641 }
21642}
21643class ViewCompiler {
21644 constructor(_reflector) {
21645 this._reflector = _reflector;
21646 }
21647 compileComponent(outputCtx, component, template, styles, usedPipes) {
21648 let embeddedViewCount = 0;
21649 const staticQueryIds = findStaticQueryIds(template);
21650 let renderComponentVarName = undefined;
21651 if (!component.isHost) {
21652 const template = component.template;
21653 const customRenderData = [];
21654 if (template.animations && template.animations.length) {
21655 customRenderData.push(new LiteralMapEntry('animation', convertValueToOutputAst(outputCtx, template.animations), true));
21656 }
21657 const renderComponentVar = variable(rendererTypeName(component.type.reference));
21658 renderComponentVarName = renderComponentVar.name;
21659 outputCtx.statements.push(renderComponentVar
21660 .set(importExpr(Identifiers.createRendererType2).callFn([new LiteralMapExpr([
21661 new LiteralMapEntry('encapsulation', literal(template.encapsulation), false),
21662 new LiteralMapEntry('styles', styles, false),
21663 new LiteralMapEntry('data', new LiteralMapExpr(customRenderData), false)
21664 ])]))
21665 .toDeclStmt(importType(Identifiers.RendererType2), [StmtModifier.Final, StmtModifier.Exported]));
21666 }
21667 const viewBuilderFactory = (parent) => {
21668 const embeddedViewIndex = embeddedViewCount++;
21669 return new ViewBuilder$1(this._reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, staticQueryIds, viewBuilderFactory);
21670 };
21671 const visitor = viewBuilderFactory(null);
21672 visitor.visitAll([], template);
21673 outputCtx.statements.push(...visitor.build());
21674 return new ViewCompileResult(visitor.viewName, renderComponentVarName);
21675 }
21676}
21677const LOG_VAR$1 = variable('_l');
21678const VIEW_VAR = variable('_v');
21679const CHECK_VAR = variable('_ck');
21680const COMP_VAR = variable('_co');
21681const EVENT_NAME_VAR = variable('en');
21682const ALLOW_DEFAULT_VAR = variable(`ad`);
21683class ViewBuilder$1 {
21684 constructor(reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, staticQueryIds, viewBuilderFactory) {
21685 this.reflector = reflector;
21686 this.outputCtx = outputCtx;
21687 this.parent = parent;
21688 this.component = component;
21689 this.embeddedViewIndex = embeddedViewIndex;
21690 this.usedPipes = usedPipes;
21691 this.staticQueryIds = staticQueryIds;
21692 this.viewBuilderFactory = viewBuilderFactory;
21693 this.nodes = [];
21694 this.purePipeNodeIndices = Object.create(null);
21695 // Need Object.create so that we don't have builtin values...
21696 this.refNodeIndices = Object.create(null);
21697 this.variables = [];
21698 this.children = [];
21699 // TODO(tbosch): The old view compiler used to use an `any` type
21700 // for the context in any embedded view. We keep this behaivor for now
21701 // to be able to introduce the new view compiler without too many errors.
21702 this.compType = this.embeddedViewIndex > 0 ?
21703 DYNAMIC_TYPE :
21704 expressionType(outputCtx.importExpr(this.component.type.reference));
21705 this.viewName = viewClassName(this.component.type.reference, this.embeddedViewIndex);
21706 }
21707 visitAll(variables, astNodes) {
21708 this.variables = variables;
21709 // create the pipes for the pure pipes immediately, so that we know their indices.
21710 if (!this.parent) {
21711 this.usedPipes.forEach((pipe) => {
21712 if (pipe.pure) {
21713 this.purePipeNodeIndices[pipe.name] = this._createPipe(null, pipe);
21714 }
21715 });
21716 }
21717 if (!this.parent) {
21718 const queryIds = staticViewQueryIds(this.staticQueryIds);
21719 this.component.viewQueries.forEach((query, queryIndex) => {
21720 // Note: queries start with id 1 so we can use the number in a Bloom filter!
21721 const queryId = queryIndex + 1;
21722 const bindingType = query.first ? 0 /* First */ : 1 /* All */;
21723 const flags = 134217728 /* TypeViewQuery */ | calcStaticDynamicQueryFlags(queryIds, queryId, query);
21724 this.nodes.push(() => ({
21725 sourceSpan: null,
21726 nodeFlags: flags,
21727 nodeDef: importExpr(Identifiers.queryDef).callFn([
21728 literal(flags), literal(queryId),
21729 new LiteralMapExpr([new LiteralMapEntry(query.propertyName, literal(bindingType), false)])
21730 ])
21731 }));
21732 });
21733 }
21734 templateVisitAll(this, astNodes);
21735 if (this.parent && (astNodes.length === 0 || needsAdditionalRootNode(astNodes))) {
21736 // if the view is an embedded view, then we need to add an additional root node in some cases
21737 this.nodes.push(() => ({
21738 sourceSpan: null,
21739 nodeFlags: 1 /* TypeElement */,
21740 nodeDef: importExpr(Identifiers.anchorDef).callFn([
21741 literal(0 /* None */), NULL_EXPR, NULL_EXPR, literal(0)
21742 ])
21743 }));
21744 }
21745 }
21746 build(targetStatements = []) {
21747 this.children.forEach((child) => child.build(targetStatements));
21748 const { updateRendererStmts, updateDirectivesStmts, nodeDefExprs } = this._createNodeExpressions();
21749 const updateRendererFn = this._createUpdateFn(updateRendererStmts);
21750 const updateDirectivesFn = this._createUpdateFn(updateDirectivesStmts);
21751 let viewFlags = 0 /* None */;
21752 if (!this.parent && this.component.changeDetection === ChangeDetectionStrategy.OnPush) {
21753 viewFlags |= 2 /* OnPush */;
21754 }
21755 const viewFactory = new DeclareFunctionStmt(this.viewName, [new FnParam(LOG_VAR$1.name)], [new ReturnStatement(importExpr(Identifiers.viewDef).callFn([
21756 literal(viewFlags),
21757 literalArr(nodeDefExprs),
21758 updateDirectivesFn,
21759 updateRendererFn,
21760 ]))], importType(Identifiers.ViewDefinition), this.embeddedViewIndex === 0 ? [StmtModifier.Exported] : []);
21761 targetStatements.push(viewFactory);
21762 return targetStatements;
21763 }
21764 _createUpdateFn(updateStmts) {
21765 let updateFn;
21766 if (updateStmts.length > 0) {
21767 const preStmts = [];
21768 if (!this.component.isHost && findReadVarNames(updateStmts).has(COMP_VAR.name)) {
21769 preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
21770 }
21771 updateFn = fn([
21772 new FnParam(CHECK_VAR.name, INFERRED_TYPE),
21773 new FnParam(VIEW_VAR.name, INFERRED_TYPE)
21774 ], [...preStmts, ...updateStmts], INFERRED_TYPE);
21775 }
21776 else {
21777 updateFn = NULL_EXPR;
21778 }
21779 return updateFn;
21780 }
21781 visitNgContent(ast, context) {
21782 // ngContentDef(ngContentIndex: number, index: number): NodeDef;
21783 this.nodes.push(() => ({
21784 sourceSpan: ast.sourceSpan,
21785 nodeFlags: 8 /* TypeNgContent */,
21786 nodeDef: importExpr(Identifiers.ngContentDef).callFn([
21787 literal(ast.ngContentIndex), literal(ast.index)
21788 ])
21789 }));
21790 }
21791 visitText(ast, context) {
21792 // Static text nodes have no check function
21793 const checkIndex = -1;
21794 this.nodes.push(() => ({
21795 sourceSpan: ast.sourceSpan,
21796 nodeFlags: 2 /* TypeText */,
21797 nodeDef: importExpr(Identifiers.textDef).callFn([
21798 literal(checkIndex),
21799 literal(ast.ngContentIndex),
21800 literalArr([literal(ast.value)]),
21801 ])
21802 }));
21803 }
21804 visitBoundText(ast, context) {
21805 const nodeIndex = this.nodes.length;
21806 // reserve the space in the nodeDefs array
21807 this.nodes.push(null);
21808 const astWithSource = ast.value;
21809 const inter = astWithSource.ast;
21810 const updateRendererExpressions = inter.expressions.map((expr, bindingIndex) => this._preprocessUpdateExpression({ nodeIndex, bindingIndex, sourceSpan: ast.sourceSpan, context: COMP_VAR, value: expr }));
21811 // Check index is the same as the node index during compilation
21812 // They might only differ at runtime
21813 const checkIndex = nodeIndex;
21814 this.nodes[nodeIndex] = () => ({
21815 sourceSpan: ast.sourceSpan,
21816 nodeFlags: 2 /* TypeText */,
21817 nodeDef: importExpr(Identifiers.textDef).callFn([
21818 literal(checkIndex),
21819 literal(ast.ngContentIndex),
21820 literalArr(inter.strings.map(s => literal(s))),
21821 ]),
21822 updateRenderer: updateRendererExpressions
21823 });
21824 }
21825 visitEmbeddedTemplate(ast, context) {
21826 const nodeIndex = this.nodes.length;
21827 // reserve the space in the nodeDefs array
21828 this.nodes.push(null);
21829 const { flags, queryMatchesExpr, hostEvents } = this._visitElementOrTemplate(nodeIndex, ast);
21830 const childVisitor = this.viewBuilderFactory(this);
21831 this.children.push(childVisitor);
21832 childVisitor.visitAll(ast.variables, ast.children);
21833 const childCount = this.nodes.length - nodeIndex - 1;
21834 // anchorDef(
21835 // flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
21836 // childCount: number, handleEventFn?: ElementHandleEventFn, templateFactory?:
21837 // ViewDefinitionFactory): NodeDef;
21838 this.nodes[nodeIndex] = () => ({
21839 sourceSpan: ast.sourceSpan,
21840 nodeFlags: 1 /* TypeElement */ | flags,
21841 nodeDef: importExpr(Identifiers.anchorDef).callFn([
21842 literal(flags),
21843 queryMatchesExpr,
21844 literal(ast.ngContentIndex),
21845 literal(childCount),
21846 this._createElementHandleEventFn(nodeIndex, hostEvents),
21847 variable(childVisitor.viewName),
21848 ])
21849 });
21850 }
21851 visitElement(ast, context) {
21852 const nodeIndex = this.nodes.length;
21853 // reserve the space in the nodeDefs array so we can add children
21854 this.nodes.push(null);
21855 // Using a null element name creates an anchor.
21856 const elName = isNgContainer(ast.name) ? null : ast.name;
21857 const { flags, usedEvents, queryMatchesExpr, hostBindings: dirHostBindings, hostEvents } = this._visitElementOrTemplate(nodeIndex, ast);
21858 let inputDefs = [];
21859 let updateRendererExpressions = [];
21860 let outputDefs = [];
21861 if (elName) {
21862 const hostBindings = ast.inputs
21863 .map((inputAst) => ({
21864 context: COMP_VAR,
21865 inputAst,
21866 dirAst: null,
21867 }))
21868 .concat(dirHostBindings);
21869 if (hostBindings.length) {
21870 updateRendererExpressions =
21871 hostBindings.map((hostBinding, bindingIndex) => this._preprocessUpdateExpression({
21872 context: hostBinding.context,
21873 nodeIndex,
21874 bindingIndex,
21875 sourceSpan: hostBinding.inputAst.sourceSpan,
21876 value: hostBinding.inputAst.value
21877 }));
21878 inputDefs = hostBindings.map(hostBinding => elementBindingDef(hostBinding.inputAst, hostBinding.dirAst));
21879 }
21880 outputDefs = usedEvents.map(([target, eventName]) => literalArr([literal(target), literal(eventName)]));
21881 }
21882 templateVisitAll(this, ast.children);
21883 const childCount = this.nodes.length - nodeIndex - 1;
21884 const compAst = ast.directives.find(dirAst => dirAst.directive.isComponent);
21885 let compRendererType = NULL_EXPR;
21886 let compView = NULL_EXPR;
21887 if (compAst) {
21888 compView = this.outputCtx.importExpr(compAst.directive.componentViewType);
21889 compRendererType = this.outputCtx.importExpr(compAst.directive.rendererType);
21890 }
21891 // Check index is the same as the node index during compilation
21892 // They might only differ at runtime
21893 const checkIndex = nodeIndex;
21894 this.nodes[nodeIndex] = () => ({
21895 sourceSpan: ast.sourceSpan,
21896 nodeFlags: 1 /* TypeElement */ | flags,
21897 nodeDef: importExpr(Identifiers.elementDef).callFn([
21898 literal(checkIndex),
21899 literal(flags),
21900 queryMatchesExpr,
21901 literal(ast.ngContentIndex),
21902 literal(childCount),
21903 literal(elName),
21904 elName ? fixedAttrsDef(ast) : NULL_EXPR,
21905 inputDefs.length ? literalArr(inputDefs) : NULL_EXPR,
21906 outputDefs.length ? literalArr(outputDefs) : NULL_EXPR,
21907 this._createElementHandleEventFn(nodeIndex, hostEvents),
21908 compView,
21909 compRendererType,
21910 ]),
21911 updateRenderer: updateRendererExpressions
21912 });
21913 }
21914 _visitElementOrTemplate(nodeIndex, ast) {
21915 let flags = 0 /* None */;
21916 if (ast.hasViewContainer) {
21917 flags |= 16777216 /* EmbeddedViews */;
21918 }
21919 const usedEvents = new Map();
21920 ast.outputs.forEach((event) => {
21921 const { name, target } = elementEventNameAndTarget(event, null);
21922 usedEvents.set(elementEventFullName(target, name), [target, name]);
21923 });
21924 ast.directives.forEach((dirAst) => {
21925 dirAst.hostEvents.forEach((event) => {
21926 const { name, target } = elementEventNameAndTarget(event, dirAst);
21927 usedEvents.set(elementEventFullName(target, name), [target, name]);
21928 });
21929 });
21930 const hostBindings = [];
21931 const hostEvents = [];
21932 this._visitComponentFactoryResolverProvider(ast.directives);
21933 ast.providers.forEach((providerAst, providerIndex) => {
21934 let dirAst = undefined;
21935 let dirIndex = undefined;
21936 ast.directives.forEach((localDirAst, i) => {
21937 if (localDirAst.directive.type.reference === tokenReference(providerAst.token)) {
21938 dirAst = localDirAst;
21939 dirIndex = i;
21940 }
21941 });
21942 if (dirAst) {
21943 const { hostBindings: dirHostBindings, hostEvents: dirHostEvents } = this._visitDirective(providerAst, dirAst, dirIndex, nodeIndex, ast.references, ast.queryMatches, usedEvents, this.staticQueryIds.get(ast));
21944 hostBindings.push(...dirHostBindings);
21945 hostEvents.push(...dirHostEvents);
21946 }
21947 else {
21948 this._visitProvider(providerAst, ast.queryMatches);
21949 }
21950 });
21951 let queryMatchExprs = [];
21952 ast.queryMatches.forEach((match) => {
21953 let valueType = undefined;
21954 if (tokenReference(match.value) ===
21955 this.reflector.resolveExternalReference(Identifiers.ElementRef)) {
21956 valueType = 0 /* ElementRef */;
21957 }
21958 else if (tokenReference(match.value) ===
21959 this.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
21960 valueType = 3 /* ViewContainerRef */;
21961 }
21962 else if (tokenReference(match.value) ===
21963 this.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
21964 valueType = 2 /* TemplateRef */;
21965 }
21966 if (valueType != null) {
21967 queryMatchExprs.push(literalArr([literal(match.queryId), literal(valueType)]));
21968 }
21969 });
21970 ast.references.forEach((ref) => {
21971 let valueType = undefined;
21972 if (!ref.value) {
21973 valueType = 1 /* RenderElement */;
21974 }
21975 else if (tokenReference(ref.value) ===
21976 this.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
21977 valueType = 2 /* TemplateRef */;
21978 }
21979 if (valueType != null) {
21980 this.refNodeIndices[ref.name] = nodeIndex;
21981 queryMatchExprs.push(literalArr([literal(ref.name), literal(valueType)]));
21982 }
21983 });
21984 ast.outputs.forEach((outputAst) => {
21985 hostEvents.push({ context: COMP_VAR, eventAst: outputAst, dirAst: null });
21986 });
21987 return {
21988 flags,
21989 usedEvents: Array.from(usedEvents.values()),
21990 queryMatchesExpr: queryMatchExprs.length ? literalArr(queryMatchExprs) : NULL_EXPR,
21991 hostBindings,
21992 hostEvents: hostEvents
21993 };
21994 }
21995 _visitDirective(providerAst, dirAst, directiveIndex, elementNodeIndex, refs, queryMatches, usedEvents, queryIds) {
21996 const nodeIndex = this.nodes.length;
21997 // reserve the space in the nodeDefs array so we can add children
21998 this.nodes.push(null);
21999 dirAst.directive.queries.forEach((query, queryIndex) => {
22000 const queryId = dirAst.contentQueryStartId + queryIndex;
22001 const flags = 67108864 /* TypeContentQuery */ | calcStaticDynamicQueryFlags(queryIds, queryId, query);
22002 const bindingType = query.first ? 0 /* First */ : 1 /* All */;
22003 this.nodes.push(() => ({
22004 sourceSpan: dirAst.sourceSpan,
22005 nodeFlags: flags,
22006 nodeDef: importExpr(Identifiers.queryDef).callFn([
22007 literal(flags), literal(queryId),
22008 new LiteralMapExpr([new LiteralMapEntry(query.propertyName, literal(bindingType), false)])
22009 ]),
22010 }));
22011 });
22012 // Note: the operation below might also create new nodeDefs,
22013 // but we don't want them to be a child of a directive,
22014 // as they might be a provider/pipe on their own.
22015 // I.e. we only allow queries as children of directives nodes.
22016 const childCount = this.nodes.length - nodeIndex - 1;
22017 let { flags, queryMatchExprs, providerExpr, depsExpr } = this._visitProviderOrDirective(providerAst, queryMatches);
22018 refs.forEach((ref) => {
22019 if (ref.value && tokenReference(ref.value) === tokenReference(providerAst.token)) {
22020 this.refNodeIndices[ref.name] = nodeIndex;
22021 queryMatchExprs.push(literalArr([literal(ref.name), literal(4 /* Provider */)]));
22022 }
22023 });
22024 if (dirAst.directive.isComponent) {
22025 flags |= 32768 /* Component */;
22026 }
22027 const inputDefs = dirAst.inputs.map((inputAst, inputIndex) => {
22028 const mapValue = literalArr([literal(inputIndex), literal(inputAst.directiveName)]);
22029 // Note: it's important to not quote the key so that we can capture renames by minifiers!
22030 return new LiteralMapEntry(inputAst.directiveName, mapValue, false);
22031 });
22032 const outputDefs = [];
22033 const dirMeta = dirAst.directive;
22034 Object.keys(dirMeta.outputs).forEach((propName) => {
22035 const eventName = dirMeta.outputs[propName];
22036 if (usedEvents.has(eventName)) {
22037 // Note: it's important to not quote the key so that we can capture renames by minifiers!
22038 outputDefs.push(new LiteralMapEntry(propName, literal(eventName), false));
22039 }
22040 });
22041 let updateDirectiveExpressions = [];
22042 if (dirAst.inputs.length || (flags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0) {
22043 updateDirectiveExpressions =
22044 dirAst.inputs.map((input, bindingIndex) => this._preprocessUpdateExpression({
22045 nodeIndex,
22046 bindingIndex,
22047 sourceSpan: input.sourceSpan,
22048 context: COMP_VAR,
22049 value: input.value
22050 }));
22051 }
22052 const dirContextExpr = importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, literal(nodeIndex)]);
22053 const hostBindings = dirAst.hostProperties.map((inputAst) => ({
22054 context: dirContextExpr,
22055 dirAst,
22056 inputAst,
22057 }));
22058 const hostEvents = dirAst.hostEvents.map((hostEventAst) => ({
22059 context: dirContextExpr,
22060 eventAst: hostEventAst, dirAst,
22061 }));
22062 // Check index is the same as the node index during compilation
22063 // They might only differ at runtime
22064 const checkIndex = nodeIndex;
22065 this.nodes[nodeIndex] = () => ({
22066 sourceSpan: dirAst.sourceSpan,
22067 nodeFlags: 16384 /* TypeDirective */ | flags,
22068 nodeDef: importExpr(Identifiers.directiveDef).callFn([
22069 literal(checkIndex),
22070 literal(flags),
22071 queryMatchExprs.length ? literalArr(queryMatchExprs) : NULL_EXPR,
22072 literal(childCount),
22073 providerExpr,
22074 depsExpr,
22075 inputDefs.length ? new LiteralMapExpr(inputDefs) : NULL_EXPR,
22076 outputDefs.length ? new LiteralMapExpr(outputDefs) : NULL_EXPR,
22077 ]),
22078 updateDirectives: updateDirectiveExpressions,
22079 directive: dirAst.directive.type,
22080 });
22081 return { hostBindings, hostEvents };
22082 }
22083 _visitProvider(providerAst, queryMatches) {
22084 this._addProviderNode(this._visitProviderOrDirective(providerAst, queryMatches));
22085 }
22086 _visitComponentFactoryResolverProvider(directives) {
22087 const componentDirMeta = directives.find(dirAst => dirAst.directive.isComponent);
22088 if (componentDirMeta && componentDirMeta.directive.entryComponents.length) {
22089 const { providerExpr, depsExpr, flags, tokenExpr } = componentFactoryResolverProviderDef(this.reflector, this.outputCtx, 8192 /* PrivateProvider */, componentDirMeta.directive.entryComponents);
22090 this._addProviderNode({
22091 providerExpr,
22092 depsExpr,
22093 flags,
22094 tokenExpr,
22095 queryMatchExprs: [],
22096 sourceSpan: componentDirMeta.sourceSpan
22097 });
22098 }
22099 }
22100 _addProviderNode(data) {
22101 const nodeIndex = this.nodes.length;
22102 // providerDef(
22103 // flags: NodeFlags, matchedQueries: [string, QueryValueType][], token:any,
22104 // value: any, deps: ([DepFlags, any] | any)[]): NodeDef;
22105 this.nodes.push(() => ({
22106 sourceSpan: data.sourceSpan,
22107 nodeFlags: data.flags,
22108 nodeDef: importExpr(Identifiers.providerDef).callFn([
22109 literal(data.flags),
22110 data.queryMatchExprs.length ? literalArr(data.queryMatchExprs) : NULL_EXPR,
22111 data.tokenExpr, data.providerExpr, data.depsExpr
22112 ])
22113 }));
22114 }
22115 _visitProviderOrDirective(providerAst, queryMatches) {
22116 let flags = 0 /* None */;
22117 let queryMatchExprs = [];
22118 queryMatches.forEach((match) => {
22119 if (tokenReference(match.value) === tokenReference(providerAst.token)) {
22120 queryMatchExprs.push(literalArr([literal(match.queryId), literal(4 /* Provider */)]));
22121 }
22122 });
22123 const { providerExpr, depsExpr, flags: providerFlags, tokenExpr } = providerDef(this.outputCtx, providerAst);
22124 return {
22125 flags: flags | providerFlags,
22126 queryMatchExprs,
22127 providerExpr,
22128 depsExpr,
22129 tokenExpr,
22130 sourceSpan: providerAst.sourceSpan
22131 };
22132 }
22133 getLocal(name) {
22134 if (name == EventHandlerVars.event.name) {
22135 return EventHandlerVars.event;
22136 }
22137 let currViewExpr = VIEW_VAR;
22138 for (let currBuilder = this; currBuilder; currBuilder = currBuilder.parent,
22139 currViewExpr = currViewExpr.prop('parent').cast(DYNAMIC_TYPE)) {
22140 // check references
22141 const refNodeIndex = currBuilder.refNodeIndices[name];
22142 if (refNodeIndex != null) {
22143 return importExpr(Identifiers.nodeValue).callFn([currViewExpr, literal(refNodeIndex)]);
22144 }
22145 // check variables
22146 const varAst = currBuilder.variables.find((varAst) => varAst.name === name);
22147 if (varAst) {
22148 const varValue = varAst.value || IMPLICIT_TEMPLATE_VAR;
22149 return currViewExpr.prop('context').prop(varValue);
22150 }
22151 }
22152 return null;
22153 }
22154 notifyImplicitReceiverUse() {
22155 // Not needed in View Engine as View Engine walks through the generated
22156 // expressions to figure out if the implicit receiver is used and needs
22157 // to be generated as part of the pre-update statements.
22158 }
22159 _createLiteralArrayConverter(sourceSpan, argCount) {
22160 if (argCount === 0) {
22161 const valueExpr = importExpr(Identifiers.EMPTY_ARRAY);
22162 return () => valueExpr;
22163 }
22164 const checkIndex = this.nodes.length;
22165 this.nodes.push(() => ({
22166 sourceSpan,
22167 nodeFlags: 32 /* TypePureArray */,
22168 nodeDef: importExpr(Identifiers.pureArrayDef).callFn([
22169 literal(checkIndex),
22170 literal(argCount),
22171 ])
22172 }));
22173 return (args) => callCheckStmt(checkIndex, args);
22174 }
22175 _createLiteralMapConverter(sourceSpan, keys) {
22176 if (keys.length === 0) {
22177 const valueExpr = importExpr(Identifiers.EMPTY_MAP);
22178 return () => valueExpr;
22179 }
22180 const map = literalMap(keys.map((e, i) => (Object.assign({}, e, { value: literal(i) }))));
22181 const checkIndex = this.nodes.length;
22182 this.nodes.push(() => ({
22183 sourceSpan,
22184 nodeFlags: 64 /* TypePureObject */,
22185 nodeDef: importExpr(Identifiers.pureObjectDef).callFn([
22186 literal(checkIndex),
22187 map,
22188 ])
22189 }));
22190 return (args) => callCheckStmt(checkIndex, args);
22191 }
22192 _createPipeConverter(expression, name, argCount) {
22193 const pipe = this.usedPipes.find((pipeSummary) => pipeSummary.name === name);
22194 if (pipe.pure) {
22195 const checkIndex = this.nodes.length;
22196 this.nodes.push(() => ({
22197 sourceSpan: expression.sourceSpan,
22198 nodeFlags: 128 /* TypePurePipe */,
22199 nodeDef: importExpr(Identifiers.purePipeDef).callFn([
22200 literal(checkIndex),
22201 literal(argCount),
22202 ])
22203 }));
22204 // find underlying pipe in the component view
22205 let compViewExpr = VIEW_VAR;
22206 let compBuilder = this;
22207 while (compBuilder.parent) {
22208 compBuilder = compBuilder.parent;
22209 compViewExpr = compViewExpr.prop('parent').cast(DYNAMIC_TYPE);
22210 }
22211 const pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
22212 const pipeValueExpr = importExpr(Identifiers.nodeValue).callFn([compViewExpr, literal(pipeNodeIndex)]);
22213 return (args) => callUnwrapValue(expression.nodeIndex, expression.bindingIndex, callCheckStmt(checkIndex, [pipeValueExpr].concat(args)));
22214 }
22215 else {
22216 const nodeIndex = this._createPipe(expression.sourceSpan, pipe);
22217 const nodeValueExpr = importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, literal(nodeIndex)]);
22218 return (args) => callUnwrapValue(expression.nodeIndex, expression.bindingIndex, nodeValueExpr.callMethod('transform', args));
22219 }
22220 }
22221 _createPipe(sourceSpan, pipe) {
22222 const nodeIndex = this.nodes.length;
22223 let flags = 0 /* None */;
22224 pipe.type.lifecycleHooks.forEach((lifecycleHook) => {
22225 // for pipes, we only support ngOnDestroy
22226 if (lifecycleHook === LifecycleHooks.OnDestroy) {
22227 flags |= lifecycleHookToNodeFlag(lifecycleHook);
22228 }
22229 });
22230 const depExprs = pipe.type.diDeps.map((diDep) => depDef(this.outputCtx, diDep));
22231 // function pipeDef(
22232 // flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef
22233 this.nodes.push(() => ({
22234 sourceSpan,
22235 nodeFlags: 16 /* TypePipe */,
22236 nodeDef: importExpr(Identifiers.pipeDef).callFn([
22237 literal(flags), this.outputCtx.importExpr(pipe.type.reference), literalArr(depExprs)
22238 ])
22239 }));
22240 return nodeIndex;
22241 }
22242 /**
22243 * For the AST in `UpdateExpression.value`:
22244 * - create nodes for pipes, literal arrays and, literal maps,
22245 * - update the AST to replace pipes, literal arrays and, literal maps with calls to check fn.
22246 *
22247 * WARNING: This might create new nodeDefs (for pipes and literal arrays and literal maps)!
22248 */
22249 _preprocessUpdateExpression(expression) {
22250 return {
22251 nodeIndex: expression.nodeIndex,
22252 bindingIndex: expression.bindingIndex,
22253 sourceSpan: expression.sourceSpan,
22254 context: expression.context,
22255 value: convertPropertyBindingBuiltins({
22256 createLiteralArrayConverter: (argCount) => this._createLiteralArrayConverter(expression.sourceSpan, argCount),
22257 createLiteralMapConverter: (keys) => this._createLiteralMapConverter(expression.sourceSpan, keys),
22258 createPipeConverter: (name, argCount) => this._createPipeConverter(expression, name, argCount)
22259 }, expression.value)
22260 };
22261 }
22262 _createNodeExpressions() {
22263 const self = this;
22264 let updateBindingCount = 0;
22265 const updateRendererStmts = [];
22266 const updateDirectivesStmts = [];
22267 const nodeDefExprs = this.nodes.map((factory, nodeIndex) => {
22268 const { nodeDef, nodeFlags, updateDirectives, updateRenderer, sourceSpan } = factory();
22269 if (updateRenderer) {
22270 updateRendererStmts.push(...createUpdateStatements(nodeIndex, sourceSpan, updateRenderer, false));
22271 }
22272 if (updateDirectives) {
22273 updateDirectivesStmts.push(...createUpdateStatements(nodeIndex, sourceSpan, updateDirectives, (nodeFlags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0));
22274 }
22275 // We use a comma expression to call the log function before
22276 // the nodeDef function, but still use the result of the nodeDef function
22277 // as the value.
22278 // Note: We only add the logger to elements / text nodes,
22279 // so we don't generate too much code.
22280 const logWithNodeDef = nodeFlags & 3 /* CatRenderNode */ ?
22281 new CommaExpr([LOG_VAR$1.callFn([]).callFn([]), nodeDef]) :
22282 nodeDef;
22283 return applySourceSpanToExpressionIfNeeded(logWithNodeDef, sourceSpan);
22284 });
22285 return { updateRendererStmts, updateDirectivesStmts, nodeDefExprs };
22286 function createUpdateStatements(nodeIndex, sourceSpan, expressions, allowEmptyExprs) {
22287 const updateStmts = [];
22288 const exprs = expressions.map(({ sourceSpan, context, value }) => {
22289 const bindingId = `${updateBindingCount++}`;
22290 const nameResolver = context === COMP_VAR ? self : null;
22291 const { stmts, currValExpr } = convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General);
22292 updateStmts.push(...stmts.map((stmt) => applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
22293 return applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);
22294 });
22295 if (expressions.length || allowEmptyExprs) {
22296 updateStmts.push(applySourceSpanToStatementIfNeeded(callCheckStmt(nodeIndex, exprs).toStmt(), sourceSpan));
22297 }
22298 return updateStmts;
22299 }
22300 }
22301 _createElementHandleEventFn(nodeIndex, handlers) {
22302 const handleEventStmts = [];
22303 let handleEventBindingCount = 0;
22304 handlers.forEach(({ context, eventAst, dirAst }) => {
22305 const bindingId = `${handleEventBindingCount++}`;
22306 const nameResolver = context === COMP_VAR ? this : null;
22307 const { stmts, allowDefault } = convertActionBinding(nameResolver, context, eventAst.handler, bindingId);
22308 const trueStmts = stmts;
22309 if (allowDefault) {
22310 trueStmts.push(ALLOW_DEFAULT_VAR.set(allowDefault.and(ALLOW_DEFAULT_VAR)).toStmt());
22311 }
22312 const { target: eventTarget, name: eventName } = elementEventNameAndTarget(eventAst, dirAst);
22313 const fullEventName = elementEventFullName(eventTarget, eventName);
22314 handleEventStmts.push(applySourceSpanToStatementIfNeeded(new IfStmt(literal(fullEventName).identical(EVENT_NAME_VAR), trueStmts), eventAst.sourceSpan));
22315 });
22316 let handleEventFn;
22317 if (handleEventStmts.length > 0) {
22318 const preStmts = [ALLOW_DEFAULT_VAR.set(literal(true)).toDeclStmt(BOOL_TYPE)];
22319 if (!this.component.isHost && findReadVarNames(handleEventStmts).has(COMP_VAR.name)) {
22320 preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
22321 }
22322 handleEventFn = fn([
22323 new FnParam(VIEW_VAR.name, INFERRED_TYPE),
22324 new FnParam(EVENT_NAME_VAR.name, INFERRED_TYPE),
22325 new FnParam(EventHandlerVars.event.name, INFERRED_TYPE)
22326 ], [...preStmts, ...handleEventStmts, new ReturnStatement(ALLOW_DEFAULT_VAR)], INFERRED_TYPE);
22327 }
22328 else {
22329 handleEventFn = NULL_EXPR;
22330 }
22331 return handleEventFn;
22332 }
22333 visitDirective(ast, context) { }
22334 visitDirectiveProperty(ast, context) { }
22335 visitReference(ast, context) { }
22336 visitVariable(ast, context) { }
22337 visitEvent(ast, context) { }
22338 visitElementProperty(ast, context) { }
22339 visitAttr(ast, context) { }
22340}
22341function needsAdditionalRootNode(astNodes) {
22342 const lastAstNode = astNodes[astNodes.length - 1];
22343 if (lastAstNode instanceof EmbeddedTemplateAst) {
22344 return lastAstNode.hasViewContainer;
22345 }
22346 if (lastAstNode instanceof ElementAst) {
22347 if (isNgContainer(lastAstNode.name) && lastAstNode.children.length) {
22348 return needsAdditionalRootNode(lastAstNode.children);
22349 }
22350 return lastAstNode.hasViewContainer;
22351 }
22352 return lastAstNode instanceof NgContentAst;
22353}
22354function elementBindingDef(inputAst, dirAst) {
22355 const inputType = inputAst.type;
22356 switch (inputType) {
22357 case 1 /* Attribute */:
22358 return literalArr([
22359 literal(1 /* TypeElementAttribute */), literal(inputAst.name),
22360 literal(inputAst.securityContext)
22361 ]);
22362 case 0 /* Property */:
22363 return literalArr([
22364 literal(8 /* TypeProperty */), literal(inputAst.name),
22365 literal(inputAst.securityContext)
22366 ]);
22367 case 4 /* Animation */:
22368 const bindingType = 8 /* TypeProperty */ |
22369 (dirAst && dirAst.directive.isComponent ? 32 /* SyntheticHostProperty */ :
22370 16 /* SyntheticProperty */);
22371 return literalArr([
22372 literal(bindingType), literal('@' + inputAst.name), literal(inputAst.securityContext)
22373 ]);
22374 case 2 /* Class */:
22375 return literalArr([literal(2 /* TypeElementClass */), literal(inputAst.name), NULL_EXPR]);
22376 case 3 /* Style */:
22377 return literalArr([
22378 literal(4 /* TypeElementStyle */), literal(inputAst.name), literal(inputAst.unit)
22379 ]);
22380 default:
22381 // This default case is not needed by TypeScript compiler, as the switch is exhaustive.
22382 // However Closure Compiler does not understand that and reports an error in typed mode.
22383 // The `throw new Error` below works around the problem, and the unexpected: never variable
22384 // makes sure tsc still checks this code is unreachable.
22385 const unexpected = inputType;
22386 throw new Error(`unexpected ${unexpected}`);
22387 }
22388}
22389function fixedAttrsDef(elementAst) {
22390 const mapResult = Object.create(null);
22391 elementAst.attrs.forEach(attrAst => { mapResult[attrAst.name] = attrAst.value; });
22392 elementAst.directives.forEach(dirAst => {
22393 Object.keys(dirAst.directive.hostAttributes).forEach(name => {
22394 const value = dirAst.directive.hostAttributes[name];
22395 const prevValue = mapResult[name];
22396 mapResult[name] = prevValue != null ? mergeAttributeValue(name, prevValue, value) : value;
22397 });
22398 });
22399 // Note: We need to sort to get a defined output order
22400 // for tests and for caching generated artifacts...
22401 return literalArr(Object.keys(mapResult).sort().map((attrName) => literalArr([literal(attrName), literal(mapResult[attrName])])));
22402}
22403function mergeAttributeValue(attrName, attrValue1, attrValue2) {
22404 if (attrName == CLASS_ATTR$1 || attrName == STYLE_ATTR) {
22405 return `${attrValue1} ${attrValue2}`;
22406 }
22407 else {
22408 return attrValue2;
22409 }
22410}
22411function callCheckStmt(nodeIndex, exprs) {
22412 if (exprs.length > 10) {
22413 return CHECK_VAR.callFn([VIEW_VAR, literal(nodeIndex), literal(1 /* Dynamic */), literalArr(exprs)]);
22414 }
22415 else {
22416 return CHECK_VAR.callFn([VIEW_VAR, literal(nodeIndex), literal(0 /* Inline */), ...exprs]);
22417 }
22418}
22419function callUnwrapValue(nodeIndex, bindingIdx, expr) {
22420 return importExpr(Identifiers.unwrapValue).callFn([
22421 VIEW_VAR, literal(nodeIndex), literal(bindingIdx), expr
22422 ]);
22423}
22424function findStaticQueryIds(nodes, result = new Map()) {
22425 nodes.forEach((node) => {
22426 const staticQueryIds = new Set();
22427 const dynamicQueryIds = new Set();
22428 let queryMatches = undefined;
22429 if (node instanceof ElementAst) {
22430 findStaticQueryIds(node.children, result);
22431 node.children.forEach((child) => {
22432 const childData = result.get(child);
22433 childData.staticQueryIds.forEach(queryId => staticQueryIds.add(queryId));
22434 childData.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
22435 });
22436 queryMatches = node.queryMatches;
22437 }
22438 else if (node instanceof EmbeddedTemplateAst) {
22439 findStaticQueryIds(node.children, result);
22440 node.children.forEach((child) => {
22441 const childData = result.get(child);
22442 childData.staticQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
22443 childData.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
22444 });
22445 queryMatches = node.queryMatches;
22446 }
22447 if (queryMatches) {
22448 queryMatches.forEach((match) => staticQueryIds.add(match.queryId));
22449 }
22450 dynamicQueryIds.forEach(queryId => staticQueryIds.delete(queryId));
22451 result.set(node, { staticQueryIds, dynamicQueryIds });
22452 });
22453 return result;
22454}
22455function staticViewQueryIds(nodeStaticQueryIds) {
22456 const staticQueryIds = new Set();
22457 const dynamicQueryIds = new Set();
22458 Array.from(nodeStaticQueryIds.values()).forEach((entry) => {
22459 entry.staticQueryIds.forEach(queryId => staticQueryIds.add(queryId));
22460 entry.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
22461 });
22462 dynamicQueryIds.forEach(queryId => staticQueryIds.delete(queryId));
22463 return { staticQueryIds, dynamicQueryIds };
22464}
22465function elementEventNameAndTarget(eventAst, dirAst) {
22466 if (eventAst.isAnimation) {
22467 return {
22468 name: `@${eventAst.name}.${eventAst.phase}`,
22469 target: dirAst && dirAst.directive.isComponent ? 'component' : null
22470 };
22471 }
22472 else {
22473 return eventAst;
22474 }
22475}
22476function calcStaticDynamicQueryFlags(queryIds, queryId, query) {
22477 let flags = 0 /* None */;
22478 // Note: We only make queries static that query for a single item.
22479 // This is because of backwards compatibility with the old view compiler...
22480 if (query.first && shouldResolveAsStaticQuery(queryIds, queryId, query)) {
22481 flags |= 268435456 /* StaticQuery */;
22482 }
22483 else {
22484 flags |= 536870912 /* DynamicQuery */;
22485 }
22486 return flags;
22487}
22488function shouldResolveAsStaticQuery(queryIds, queryId, query) {
22489 // If query.static has been set by the user, use that value to determine whether
22490 // the query is static. If none has been set, sort the query into static/dynamic
22491 // based on query results (i.e. dynamic if CD needs to run to get all results).
22492 return query.static ||
22493 query.static == null &&
22494 (queryIds.staticQueryIds.has(queryId) || !queryIds.dynamicQueryIds.has(queryId));
22495}
22496function elementEventFullName(target, name) {
22497 return target ? `${target}:${name}` : name;
22498}
22499
22500/**
22501 * @license
22502 * Copyright Google Inc. All Rights Reserved.
22503 *
22504 * Use of this source code is governed by an MIT-style license that can be
22505 * found in the LICENSE file at https://angular.io/license
22506 */
22507/**
22508 * A container for message extracted from the templates.
22509 */
22510class MessageBundle {
22511 constructor(_htmlParser, _implicitTags, _implicitAttrs, _locale = null) {
22512 this._htmlParser = _htmlParser;
22513 this._implicitTags = _implicitTags;
22514 this._implicitAttrs = _implicitAttrs;
22515 this._locale = _locale;
22516 this._messages = [];
22517 }
22518 updateFromTemplate(html, url, interpolationConfig) {
22519 const htmlParserResult = this._htmlParser.parse(html, url, { tokenizeExpansionForms: true, interpolationConfig });
22520 if (htmlParserResult.errors.length) {
22521 return htmlParserResult.errors;
22522 }
22523 const i18nParserResult = extractMessages(htmlParserResult.rootNodes, interpolationConfig, this._implicitTags, this._implicitAttrs);
22524 if (i18nParserResult.errors.length) {
22525 return i18nParserResult.errors;
22526 }
22527 this._messages.push(...i18nParserResult.messages);
22528 return [];
22529 }
22530 // Return the message in the internal format
22531 // The public (serialized) format might be different, see the `write` method.
22532 getMessages() { return this._messages; }
22533 write(serializer, filterSources) {
22534 const messages = {};
22535 const mapperVisitor = new MapPlaceholderNames();
22536 // Deduplicate messages based on their ID
22537 this._messages.forEach(message => {
22538 const id = serializer.digest(message);
22539 if (!messages.hasOwnProperty(id)) {
22540 messages[id] = message;
22541 }
22542 else {
22543 messages[id].sources.push(...message.sources);
22544 }
22545 });
22546 // Transform placeholder names using the serializer mapping
22547 const msgList = Object.keys(messages).map(id => {
22548 const mapper = serializer.createNameMapper(messages[id]);
22549 const src = messages[id];
22550 const nodes = mapper ? mapperVisitor.convert(src.nodes, mapper) : src.nodes;
22551 let transformedMessage = new Message(nodes, {}, {}, src.meaning, src.description, id);
22552 transformedMessage.sources = src.sources;
22553 if (filterSources) {
22554 transformedMessage.sources.forEach((source) => source.filePath = filterSources(source.filePath));
22555 }
22556 return transformedMessage;
22557 });
22558 return serializer.write(msgList, this._locale);
22559 }
22560}
22561// Transform an i18n AST by renaming the placeholder nodes with the given mapper
22562class MapPlaceholderNames extends CloneVisitor {
22563 convert(nodes, mapper) {
22564 return mapper ? nodes.map(n => n.visit(this, mapper)) : nodes;
22565 }
22566 visitTagPlaceholder(ph, mapper) {
22567 const startName = mapper.toPublicName(ph.startName);
22568 const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
22569 const children = ph.children.map(n => n.visit(this, mapper));
22570 return new TagPlaceholder(ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan);
22571 }
22572 visitPlaceholder(ph, mapper) {
22573 return new Placeholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
22574 }
22575 visitIcuPlaceholder(ph, mapper) {
22576 return new IcuPlaceholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
22577 }
22578}
22579
22580/**
22581 * @license
22582 * Copyright Google Inc. All Rights Reserved.
22583 *
22584 * Use of this source code is governed by an MIT-style license that can be
22585 * found in the LICENSE file at https://angular.io/license
22586 */
22587class GeneratedFile {
22588 constructor(srcFileUrl, genFileUrl, sourceOrStmts) {
22589 this.srcFileUrl = srcFileUrl;
22590 this.genFileUrl = genFileUrl;
22591 if (typeof sourceOrStmts === 'string') {
22592 this.source = sourceOrStmts;
22593 this.stmts = null;
22594 }
22595 else {
22596 this.source = null;
22597 this.stmts = sourceOrStmts;
22598 }
22599 }
22600 isEquivalent(other) {
22601 if (this.genFileUrl !== other.genFileUrl) {
22602 return false;
22603 }
22604 if (this.source) {
22605 return this.source === other.source;
22606 }
22607 if (other.stmts == null) {
22608 return false;
22609 }
22610 // Note: the constructor guarantees that if this.source is not filled,
22611 // then this.stmts is.
22612 return areAllEquivalent(this.stmts, other.stmts);
22613 }
22614}
22615function toTypeScript(file, preamble = '') {
22616 if (!file.stmts) {
22617 throw new Error(`Illegal state: No stmts present on GeneratedFile ${file.genFileUrl}`);
22618 }
22619 return new TypeScriptEmitter().emitStatements(file.genFileUrl, file.stmts, preamble);
22620}
22621
22622/**
22623 * @license
22624 * Copyright Google Inc. All Rights Reserved.
22625 *
22626 * Use of this source code is governed by an MIT-style license that can be
22627 * found in the LICENSE file at https://angular.io/license
22628 */
22629function listLazyRoutes(moduleMeta, reflector) {
22630 const allLazyRoutes = [];
22631 for (const { provider, module } of moduleMeta.transitiveModule.providers) {
22632 if (tokenReference(provider.token) === reflector.ROUTES) {
22633 const loadChildren = _collectLoadChildren(provider.useValue);
22634 for (const route of loadChildren) {
22635 allLazyRoutes.push(parseLazyRoute(route, reflector, module.reference));
22636 }
22637 }
22638 }
22639 return allLazyRoutes;
22640}
22641function _collectLoadChildren(routes, target = []) {
22642 if (typeof routes === 'string') {
22643 target.push(routes);
22644 }
22645 else if (Array.isArray(routes)) {
22646 for (const route of routes) {
22647 _collectLoadChildren(route, target);
22648 }
22649 }
22650 else if (routes.loadChildren) {
22651 _collectLoadChildren(routes.loadChildren, target);
22652 }
22653 else if (routes.children) {
22654 _collectLoadChildren(routes.children, target);
22655 }
22656 return target;
22657}
22658function parseLazyRoute(route, reflector, module) {
22659 const [routePath, routeName] = route.split('#');
22660 const referencedModule = reflector.resolveExternalReference({
22661 moduleName: routePath,
22662 name: routeName,
22663 }, module ? module.filePath : undefined);
22664 return { route: route, module: module || referencedModule, referencedModule };
22665}
22666
22667/**
22668 * @license
22669 * Copyright Google Inc. All Rights Reserved.
22670 *
22671 * Use of this source code is governed by an MIT-style license that can be
22672 * found in the LICENSE file at https://angular.io/license
22673 */
22674const TS = /^(?!.*\.d\.ts$).*\.ts$/;
22675class ResolvedStaticSymbol {
22676 constructor(symbol, metadata) {
22677 this.symbol = symbol;
22678 this.metadata = metadata;
22679 }
22680}
22681const SUPPORTED_SCHEMA_VERSION = 4;
22682/**
22683 * This class is responsible for loading metadata per symbol,
22684 * and normalizing references between symbols.
22685 *
22686 * Internally, it only uses symbols without members,
22687 * and deduces the values for symbols with members based
22688 * on these symbols.
22689 */
22690class StaticSymbolResolver {
22691 constructor(host, staticSymbolCache, summaryResolver, errorRecorder) {
22692 this.host = host;
22693 this.staticSymbolCache = staticSymbolCache;
22694 this.summaryResolver = summaryResolver;
22695 this.errorRecorder = errorRecorder;
22696 this.metadataCache = new Map();
22697 // Note: this will only contain StaticSymbols without members!
22698 this.resolvedSymbols = new Map();
22699 this.resolvedFilePaths = new Set();
22700 // Note: this will only contain StaticSymbols without members!
22701 this.importAs = new Map();
22702 this.symbolResourcePaths = new Map();
22703 this.symbolFromFile = new Map();
22704 this.knownFileNameToModuleNames = new Map();
22705 }
22706 resolveSymbol(staticSymbol) {
22707 if (staticSymbol.members.length > 0) {
22708 return this._resolveSymbolMembers(staticSymbol);
22709 }
22710 // Note: always ask for a summary first,
22711 // as we might have read shallow metadata via a .d.ts file
22712 // for the symbol.
22713 const resultFromSummary = this._resolveSymbolFromSummary(staticSymbol);
22714 if (resultFromSummary) {
22715 return resultFromSummary;
22716 }
22717 const resultFromCache = this.resolvedSymbols.get(staticSymbol);
22718 if (resultFromCache) {
22719 return resultFromCache;
22720 }
22721 // Note: Some users use libraries that were not compiled with ngc, i.e. they don't
22722 // have summaries, only .d.ts files. So we always need to check both, the summary
22723 // and metadata.
22724 this._createSymbolsOf(staticSymbol.filePath);
22725 return this.resolvedSymbols.get(staticSymbol);
22726 }
22727 /**
22728 * getImportAs produces a symbol that can be used to import the given symbol.
22729 * The import might be different than the symbol if the symbol is exported from
22730 * a library with a summary; in which case we want to import the symbol from the
22731 * ngfactory re-export instead of directly to avoid introducing a direct dependency
22732 * on an otherwise indirect dependency.
22733 *
22734 * @param staticSymbol the symbol for which to generate a import symbol
22735 */
22736 getImportAs(staticSymbol, useSummaries = true) {
22737 if (staticSymbol.members.length) {
22738 const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
22739 const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
22740 return baseImportAs ?
22741 this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
22742 null;
22743 }
22744 const summarizedFileName = stripSummaryForJitFileSuffix(staticSymbol.filePath);
22745 if (summarizedFileName !== staticSymbol.filePath) {
22746 const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
22747 const baseSymbol = this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
22748 const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
22749 return baseImportAs ?
22750 this.getStaticSymbol(summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name), baseSymbol.members) :
22751 null;
22752 }
22753 let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
22754 if (!result) {
22755 result = this.importAs.get(staticSymbol);
22756 }
22757 return result;
22758 }
22759 /**
22760 * getResourcePath produces the path to the original location of the symbol and should
22761 * be used to determine the relative location of resource references recorded in
22762 * symbol metadata.
22763 */
22764 getResourcePath(staticSymbol) {
22765 return this.symbolResourcePaths.get(staticSymbol) || staticSymbol.filePath;
22766 }
22767 /**
22768 * getTypeArity returns the number of generic type parameters the given symbol
22769 * has. If the symbol is not a type the result is null.
22770 */
22771 getTypeArity(staticSymbol) {
22772 // If the file is a factory/ngsummary file, don't resolve the symbol as doing so would
22773 // cause the metadata for an factory/ngsummary file to be loaded which doesn't exist.
22774 // All references to generated classes must include the correct arity whenever
22775 // generating code.
22776 if (isGeneratedFile(staticSymbol.filePath)) {
22777 return null;
22778 }
22779 let resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(staticSymbol));
22780 while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
22781 resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(resolvedSymbol.metadata));
22782 }
22783 return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
22784 }
22785 getKnownModuleName(filePath) {
22786 return this.knownFileNameToModuleNames.get(filePath) || null;
22787 }
22788 recordImportAs(sourceSymbol, targetSymbol) {
22789 sourceSymbol.assertNoMembers();
22790 targetSymbol.assertNoMembers();
22791 this.importAs.set(sourceSymbol, targetSymbol);
22792 }
22793 recordModuleNameForFileName(fileName, moduleName) {
22794 this.knownFileNameToModuleNames.set(fileName, moduleName);
22795 }
22796 /**
22797 * Invalidate all information derived from the given file.
22798 *
22799 * @param fileName the file to invalidate
22800 */
22801 invalidateFile(fileName) {
22802 this.metadataCache.delete(fileName);
22803 this.resolvedFilePaths.delete(fileName);
22804 const symbols = this.symbolFromFile.get(fileName);
22805 if (symbols) {
22806 this.symbolFromFile.delete(fileName);
22807 for (const symbol of symbols) {
22808 this.resolvedSymbols.delete(symbol);
22809 this.importAs.delete(symbol);
22810 this.symbolResourcePaths.delete(symbol);
22811 }
22812 }
22813 }
22814 /** @internal */
22815 ignoreErrorsFor(cb) {
22816 const recorder = this.errorRecorder;
22817 this.errorRecorder = () => { };
22818 try {
22819 return cb();
22820 }
22821 finally {
22822 this.errorRecorder = recorder;
22823 }
22824 }
22825 _resolveSymbolMembers(staticSymbol) {
22826 const members = staticSymbol.members;
22827 const baseResolvedSymbol = this.resolveSymbol(this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name));
22828 if (!baseResolvedSymbol) {
22829 return null;
22830 }
22831 let baseMetadata = unwrapResolvedMetadata(baseResolvedSymbol.metadata);
22832 if (baseMetadata instanceof StaticSymbol) {
22833 return new ResolvedStaticSymbol(staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
22834 }
22835 else if (baseMetadata && baseMetadata.__symbolic === 'class') {
22836 if (baseMetadata.statics && members.length === 1) {
22837 return new ResolvedStaticSymbol(staticSymbol, baseMetadata.statics[members[0]]);
22838 }
22839 }
22840 else {
22841 let value = baseMetadata;
22842 for (let i = 0; i < members.length && value; i++) {
22843 value = value[members[i]];
22844 }
22845 return new ResolvedStaticSymbol(staticSymbol, value);
22846 }
22847 return null;
22848 }
22849 _resolveSymbolFromSummary(staticSymbol) {
22850 const summary = this.summaryResolver.resolveSummary(staticSymbol);
22851 return summary ? new ResolvedStaticSymbol(staticSymbol, summary.metadata) : null;
22852 }
22853 /**
22854 * getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
22855 * All types passed to the StaticResolver should be pseudo-types returned by this method.
22856 *
22857 * @param declarationFile the absolute path of the file where the symbol is declared
22858 * @param name the name of the type.
22859 * @param members a symbol for a static member of the named type
22860 */
22861 getStaticSymbol(declarationFile, name, members) {
22862 return this.staticSymbolCache.get(declarationFile, name, members);
22863 }
22864 /**
22865 * hasDecorators checks a file's metadata for the presence of decorators without evaluating the
22866 * metadata.
22867 *
22868 * @param filePath the absolute path to examine for decorators.
22869 * @returns true if any class in the file has a decorator.
22870 */
22871 hasDecorators(filePath) {
22872 const metadata = this.getModuleMetadata(filePath);
22873 if (metadata['metadata']) {
22874 return Object.keys(metadata['metadata']).some((metadataKey) => {
22875 const entry = metadata['metadata'][metadataKey];
22876 return entry && entry.__symbolic === 'class' && entry.decorators;
22877 });
22878 }
22879 return false;
22880 }
22881 getSymbolsOf(filePath) {
22882 const summarySymbols = this.summaryResolver.getSymbolsOf(filePath);
22883 if (summarySymbols) {
22884 return summarySymbols;
22885 }
22886 // Note: Some users use libraries that were not compiled with ngc, i.e. they don't
22887 // have summaries, only .d.ts files, but `summaryResolver.isLibraryFile` returns true.
22888 this._createSymbolsOf(filePath);
22889 const metadataSymbols = [];
22890 this.resolvedSymbols.forEach((resolvedSymbol) => {
22891 if (resolvedSymbol.symbol.filePath === filePath) {
22892 metadataSymbols.push(resolvedSymbol.symbol);
22893 }
22894 });
22895 return metadataSymbols;
22896 }
22897 _createSymbolsOf(filePath) {
22898 if (this.resolvedFilePaths.has(filePath)) {
22899 return;
22900 }
22901 this.resolvedFilePaths.add(filePath);
22902 const resolvedSymbols = [];
22903 const metadata = this.getModuleMetadata(filePath);
22904 if (metadata['importAs']) {
22905 // Index bundle indices should use the importAs module name defined
22906 // in the bundle.
22907 this.knownFileNameToModuleNames.set(filePath, metadata['importAs']);
22908 }
22909 // handle the symbols in one of the re-export location
22910 if (metadata['exports']) {
22911 for (const moduleExport of metadata['exports']) {
22912 // handle the symbols in the list of explicitly re-exported symbols.
22913 if (moduleExport.export) {
22914 moduleExport.export.forEach((exportSymbol) => {
22915 let symbolName;
22916 if (typeof exportSymbol === 'string') {
22917 symbolName = exportSymbol;
22918 }
22919 else {
22920 symbolName = exportSymbol.as;
22921 }
22922 symbolName = unescapeIdentifier(symbolName);
22923 let symName = symbolName;
22924 if (typeof exportSymbol !== 'string') {
22925 symName = unescapeIdentifier(exportSymbol.name);
22926 }
22927 const resolvedModule = this.resolveModule(moduleExport.from, filePath);
22928 if (resolvedModule) {
22929 const targetSymbol = this.getStaticSymbol(resolvedModule, symName);
22930 const sourceSymbol = this.getStaticSymbol(filePath, symbolName);
22931 resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
22932 }
22933 });
22934 }
22935 else {
22936 // handle the symbols via export * directives.
22937 const resolvedModule = this.resolveModule(moduleExport.from, filePath);
22938 if (resolvedModule) {
22939 const nestedExports = this.getSymbolsOf(resolvedModule);
22940 nestedExports.forEach((targetSymbol) => {
22941 const sourceSymbol = this.getStaticSymbol(filePath, targetSymbol.name);
22942 resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
22943 });
22944 }
22945 }
22946 }
22947 }
22948 // handle the actual metadata. Has to be after the exports
22949 // as there might be collisions in the names, and we want the symbols
22950 // of the current module to win ofter reexports.
22951 if (metadata['metadata']) {
22952 // handle direct declarations of the symbol
22953 const topLevelSymbolNames = new Set(Object.keys(metadata['metadata']).map(unescapeIdentifier));
22954 const origins = metadata['origins'] || {};
22955 Object.keys(metadata['metadata']).forEach((metadataKey) => {
22956 const symbolMeta = metadata['metadata'][metadataKey];
22957 const name = unescapeIdentifier(metadataKey);
22958 const symbol = this.getStaticSymbol(filePath, name);
22959 const origin = origins.hasOwnProperty(metadataKey) && origins[metadataKey];
22960 if (origin) {
22961 // If the symbol is from a bundled index, use the declaration location of the
22962 // symbol so relative references (such as './my.html') will be calculated
22963 // correctly.
22964 const originFilePath = this.resolveModule(origin, filePath);
22965 if (!originFilePath) {
22966 this.reportError(new Error(`Couldn't resolve original symbol for ${origin} from ${this.host.getOutputName(filePath)}`));
22967 }
22968 else {
22969 this.symbolResourcePaths.set(symbol, originFilePath);
22970 }
22971 }
22972 resolvedSymbols.push(this.createResolvedSymbol(symbol, filePath, topLevelSymbolNames, symbolMeta));
22973 });
22974 }
22975 resolvedSymbols.forEach((resolvedSymbol) => this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol));
22976 this.symbolFromFile.set(filePath, resolvedSymbols.map(resolvedSymbol => resolvedSymbol.symbol));
22977 }
22978 createResolvedSymbol(sourceSymbol, topLevelPath, topLevelSymbolNames, metadata) {
22979 // For classes that don't have Angular summaries / metadata,
22980 // we only keep their arity, but nothing else
22981 // (e.g. their constructor parameters).
22982 // We do this to prevent introducing deep imports
22983 // as we didn't generate .ngfactory.ts files with proper reexports.
22984 const isTsFile = TS.test(sourceSymbol.filePath);
22985 if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) && !isTsFile && metadata &&
22986 metadata['__symbolic'] === 'class') {
22987 const transformedMeta = { __symbolic: 'class', arity: metadata.arity };
22988 return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
22989 }
22990 let _originalFileMemo;
22991 const getOriginalName = () => {
22992 if (!_originalFileMemo) {
22993 // Guess what the original file name is from the reference. If it has a `.d.ts` extension
22994 // replace it with `.ts`. If it already has `.ts` just leave it in place. If it doesn't have
22995 // .ts or .d.ts, append `.ts'. Also, if it is in `node_modules`, trim the `node_module`
22996 // location as it is not important to finding the file.
22997 _originalFileMemo =
22998 this.host.getOutputName(topLevelPath.replace(/((\.ts)|(\.d\.ts)|)$/, '.ts')
22999 .replace(/^.*node_modules[/\\]/, ''));
23000 }
23001 return _originalFileMemo;
23002 };
23003 const self = this;
23004 class ReferenceTransformer extends ValueTransformer {
23005 visitStringMap(map, functionParams) {
23006 const symbolic = map['__symbolic'];
23007 if (symbolic === 'function') {
23008 const oldLen = functionParams.length;
23009 functionParams.push(...(map['parameters'] || []));
23010 const result = super.visitStringMap(map, functionParams);
23011 functionParams.length = oldLen;
23012 return result;
23013 }
23014 else if (symbolic === 'reference') {
23015 const module = map['module'];
23016 const name = map['name'] ? unescapeIdentifier(map['name']) : map['name'];
23017 if (!name) {
23018 return null;
23019 }
23020 let filePath;
23021 if (module) {
23022 filePath = self.resolveModule(module, sourceSymbol.filePath);
23023 if (!filePath) {
23024 return {
23025 __symbolic: 'error',
23026 message: `Could not resolve ${module} relative to ${self.host.getMetadataFor(sourceSymbol.filePath)}.`,
23027 line: map['line'],
23028 character: map['character'],
23029 fileName: getOriginalName()
23030 };
23031 }
23032 return {
23033 __symbolic: 'resolved',
23034 symbol: self.getStaticSymbol(filePath, name),
23035 line: map['line'],
23036 character: map['character'],
23037 fileName: getOriginalName()
23038 };
23039 }
23040 else if (functionParams.indexOf(name) >= 0) {
23041 // reference to a function parameter
23042 return { __symbolic: 'reference', name: name };
23043 }
23044 else {
23045 if (topLevelSymbolNames.has(name)) {
23046 return self.getStaticSymbol(topLevelPath, name);
23047 }
23048 // ambient value
23049 null;
23050 }
23051 }
23052 else if (symbolic === 'error') {
23053 return Object.assign({}, map, { fileName: getOriginalName() });
23054 }
23055 else {
23056 return super.visitStringMap(map, functionParams);
23057 }
23058 }
23059 }
23060 const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
23061 let unwrappedTransformedMeta = unwrapResolvedMetadata(transformedMeta);
23062 if (unwrappedTransformedMeta instanceof StaticSymbol) {
23063 return this.createExport(sourceSymbol, unwrappedTransformedMeta);
23064 }
23065 return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
23066 }
23067 createExport(sourceSymbol, targetSymbol) {
23068 sourceSymbol.assertNoMembers();
23069 targetSymbol.assertNoMembers();
23070 if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) &&
23071 this.summaryResolver.isLibraryFile(targetSymbol.filePath)) {
23072 // This case is for an ng library importing symbols from a plain ts library
23073 // transitively.
23074 // Note: We rely on the fact that we discover symbols in the direction
23075 // from source files to library files
23076 this.importAs.set(targetSymbol, this.getImportAs(sourceSymbol) || sourceSymbol);
23077 }
23078 return new ResolvedStaticSymbol(sourceSymbol, targetSymbol);
23079 }
23080 reportError(error, context, path) {
23081 if (this.errorRecorder) {
23082 this.errorRecorder(error, (context && context.filePath) || path);
23083 }
23084 else {
23085 throw error;
23086 }
23087 }
23088 /**
23089 * @param module an absolute path to a module file.
23090 */
23091 getModuleMetadata(module) {
23092 let moduleMetadata = this.metadataCache.get(module);
23093 if (!moduleMetadata) {
23094 const moduleMetadatas = this.host.getMetadataFor(module);
23095 if (moduleMetadatas) {
23096 let maxVersion = -1;
23097 moduleMetadatas.forEach((md) => {
23098 if (md && md['version'] > maxVersion) {
23099 maxVersion = md['version'];
23100 moduleMetadata = md;
23101 }
23102 });
23103 }
23104 if (!moduleMetadata) {
23105 moduleMetadata =
23106 { __symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {} };
23107 }
23108 if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
23109 const errorMessage = moduleMetadata['version'] == 2 ?
23110 `Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` :
23111 `Metadata version mismatch for module ${this.host.getOutputName(module)}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
23112 this.reportError(new Error(errorMessage));
23113 }
23114 this.metadataCache.set(module, moduleMetadata);
23115 }
23116 return moduleMetadata;
23117 }
23118 getSymbolByModule(module, symbolName, containingFile) {
23119 const filePath = this.resolveModule(module, containingFile);
23120 if (!filePath) {
23121 this.reportError(new Error(`Could not resolve module ${module}${containingFile ? ' relative to ' +
23122 this.host.getOutputName(containingFile) : ''}`));
23123 return this.getStaticSymbol(`ERROR:${module}`, symbolName);
23124 }
23125 return this.getStaticSymbol(filePath, symbolName);
23126 }
23127 resolveModule(module, containingFile) {
23128 try {
23129 return this.host.moduleNameToFileName(module, containingFile);
23130 }
23131 catch (e) {
23132 console.error(`Could not resolve module '${module}' relative to file ${containingFile}`);
23133 this.reportError(e, undefined, containingFile);
23134 }
23135 return null;
23136 }
23137}
23138// Remove extra underscore from escaped identifier.
23139// See https://github.com/Microsoft/TypeScript/blob/master/src/compiler/utilities.ts
23140function unescapeIdentifier(identifier) {
23141 return identifier.startsWith('___') ? identifier.substr(1) : identifier;
23142}
23143function unwrapResolvedMetadata(metadata) {
23144 if (metadata && metadata.__symbolic === 'resolved') {
23145 return metadata.symbol;
23146 }
23147 return metadata;
23148}
23149
23150/**
23151 * @license
23152 * Copyright Google Inc. All Rights Reserved.
23153 *
23154 * Use of this source code is governed by an MIT-style license that can be
23155 * found in the LICENSE file at https://angular.io/license
23156 */
23157function serializeSummaries(srcFileName, forJitCtx, summaryResolver, symbolResolver, symbols, types, createExternalSymbolReexports = false) {
23158 const toJsonSerializer = new ToJsonSerializer(symbolResolver, summaryResolver, srcFileName);
23159 // for symbols, we use everything except for the class metadata itself
23160 // (we keep the statics though), as the class metadata is contained in the
23161 // CompileTypeSummary.
23162 symbols.forEach((resolvedSymbol) => toJsonSerializer.addSummary({ symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata }));
23163 // Add type summaries.
23164 types.forEach(({ summary, metadata }) => {
23165 toJsonSerializer.addSummary({ symbol: summary.type.reference, metadata: undefined, type: summary });
23166 });
23167 const { json, exportAs } = toJsonSerializer.serialize(createExternalSymbolReexports);
23168 if (forJitCtx) {
23169 const forJitSerializer = new ForJitSerializer(forJitCtx, symbolResolver, summaryResolver);
23170 types.forEach(({ summary, metadata }) => { forJitSerializer.addSourceType(summary, metadata); });
23171 toJsonSerializer.unprocessedSymbolSummariesBySymbol.forEach((summary) => {
23172 if (summaryResolver.isLibraryFile(summary.symbol.filePath) && summary.type) {
23173 forJitSerializer.addLibType(summary.type);
23174 }
23175 });
23176 forJitSerializer.serialize(exportAs);
23177 }
23178 return { json, exportAs };
23179}
23180function deserializeSummaries(symbolCache, summaryResolver, libraryFileName, json) {
23181 const deserializer = new FromJsonDeserializer(symbolCache, summaryResolver);
23182 return deserializer.deserialize(libraryFileName, json);
23183}
23184function createForJitStub(outputCtx, reference) {
23185 return createSummaryForJitFunction(outputCtx, reference, NULL_EXPR);
23186}
23187function createSummaryForJitFunction(outputCtx, reference, value) {
23188 const fnName = summaryForJitName(reference.name);
23189 outputCtx.statements.push(fn([], [new ReturnStatement(value)], new ArrayType(DYNAMIC_TYPE)).toDeclStmt(fnName, [
23190 StmtModifier.Final, StmtModifier.Exported
23191 ]));
23192}
23193class ToJsonSerializer extends ValueTransformer {
23194 constructor(symbolResolver, summaryResolver, srcFileName) {
23195 super();
23196 this.symbolResolver = symbolResolver;
23197 this.summaryResolver = summaryResolver;
23198 this.srcFileName = srcFileName;
23199 // Note: This only contains symbols without members.
23200 this.symbols = [];
23201 this.indexBySymbol = new Map();
23202 this.reexportedBy = new Map();
23203 // This now contains a `__symbol: number` in the place of
23204 // StaticSymbols, but otherwise has the same shape as the original objects.
23205 this.processedSummaryBySymbol = new Map();
23206 this.processedSummaries = [];
23207 this.unprocessedSymbolSummariesBySymbol = new Map();
23208 this.moduleName = symbolResolver.getKnownModuleName(srcFileName);
23209 }
23210 addSummary(summary) {
23211 let unprocessedSummary = this.unprocessedSymbolSummariesBySymbol.get(summary.symbol);
23212 let processedSummary = this.processedSummaryBySymbol.get(summary.symbol);
23213 if (!unprocessedSummary) {
23214 unprocessedSummary = { symbol: summary.symbol, metadata: undefined };
23215 this.unprocessedSymbolSummariesBySymbol.set(summary.symbol, unprocessedSummary);
23216 processedSummary = { symbol: this.processValue(summary.symbol, 0 /* None */) };
23217 this.processedSummaries.push(processedSummary);
23218 this.processedSummaryBySymbol.set(summary.symbol, processedSummary);
23219 }
23220 if (!unprocessedSummary.metadata && summary.metadata) {
23221 let metadata = summary.metadata || {};
23222 if (metadata.__symbolic === 'class') {
23223 // For classes, we keep everything except their class decorators.
23224 // We need to keep e.g. the ctor args, method names, method decorators
23225 // so that the class can be extended in another compilation unit.
23226 // We don't keep the class decorators as
23227 // 1) they refer to data
23228 // that should not cause a rebuild of downstream compilation units
23229 // (e.g. inline templates of @Component, or @NgModule.declarations)
23230 // 2) their data is already captured in TypeSummaries, e.g. DirectiveSummary.
23231 const clone = {};
23232 Object.keys(metadata).forEach((propName) => {
23233 if (propName !== 'decorators') {
23234 clone[propName] = metadata[propName];
23235 }
23236 });
23237 metadata = clone;
23238 }
23239 else if (isCall(metadata)) {
23240 if (!isFunctionCall(metadata) && !isMethodCallOnVariable(metadata)) {
23241 // Don't store complex calls as we won't be able to simplify them anyways later on.
23242 metadata = {
23243 __symbolic: 'error',
23244 message: 'Complex function calls are not supported.',
23245 };
23246 }
23247 }
23248 // Note: We need to keep storing ctor calls for e.g.
23249 // `export const x = new InjectionToken(...)`
23250 unprocessedSummary.metadata = metadata;
23251 processedSummary.metadata = this.processValue(metadata, 1 /* ResolveValue */);
23252 if (metadata instanceof StaticSymbol &&
23253 this.summaryResolver.isLibraryFile(metadata.filePath)) {
23254 const declarationSymbol = this.symbols[this.indexBySymbol.get(metadata)];
23255 if (!isLoweredSymbol(declarationSymbol.name)) {
23256 // Note: symbols that were introduced during codegen in the user file can have a reexport
23257 // if a user used `export *`. However, we can't rely on this as tsickle will change
23258 // `export *` into named exports, using only the information from the typechecker.
23259 // As we introduce the new symbols after typecheck, Tsickle does not know about them,
23260 // and omits them when expanding `export *`.
23261 // So we have to keep reexporting these symbols manually via .ngfactory files.
23262 this.reexportedBy.set(declarationSymbol, summary.symbol);
23263 }
23264 }
23265 }
23266 if (!unprocessedSummary.type && summary.type) {
23267 unprocessedSummary.type = summary.type;
23268 // Note: We don't add the summaries of all referenced symbols as for the ResolvedSymbols,
23269 // as the type summaries already contain the transitive data that they require
23270 // (in a minimal way).
23271 processedSummary.type = this.processValue(summary.type, 0 /* None */);
23272 // except for reexported directives / pipes, so we need to store
23273 // their summaries explicitly.
23274 if (summary.type.summaryKind === CompileSummaryKind.NgModule) {
23275 const ngModuleSummary = summary.type;
23276 ngModuleSummary.exportedDirectives.concat(ngModuleSummary.exportedPipes).forEach((id) => {
23277 const symbol = id.reference;
23278 if (this.summaryResolver.isLibraryFile(symbol.filePath) &&
23279 !this.unprocessedSymbolSummariesBySymbol.has(symbol)) {
23280 const summary = this.summaryResolver.resolveSummary(symbol);
23281 if (summary) {
23282 this.addSummary(summary);
23283 }
23284 }
23285 });
23286 }
23287 }
23288 }
23289 /**
23290 * @param createExternalSymbolReexports Whether external static symbols should be re-exported.
23291 * This can be enabled if external symbols should be re-exported by the current module in
23292 * order to avoid dynamically generated module dependencies which can break strict dependency
23293 * enforcements (as in Google3). Read more here: https://github.com/angular/angular/issues/25644
23294 */
23295 serialize(createExternalSymbolReexports) {
23296 const exportAs = [];
23297 const json = JSON.stringify({
23298 moduleName: this.moduleName,
23299 summaries: this.processedSummaries,
23300 symbols: this.symbols.map((symbol, index) => {
23301 symbol.assertNoMembers();
23302 let importAs = undefined;
23303 if (this.summaryResolver.isLibraryFile(symbol.filePath)) {
23304 const reexportSymbol = this.reexportedBy.get(symbol);
23305 if (reexportSymbol) {
23306 // In case the given external static symbol is already manually exported by the
23307 // user, we just proxy the external static symbol reference to the manual export.
23308 // This ensures that the AOT compiler imports the external symbol through the
23309 // user export and does not introduce another dependency which is not needed.
23310 importAs = this.indexBySymbol.get(reexportSymbol);
23311 }
23312 else if (createExternalSymbolReexports) {
23313 // In this case, the given external static symbol is *not* manually exported by
23314 // the user, and we manually create a re-export in the factory file so that we
23315 // don't introduce another module dependency. This is useful when running within
23316 // Bazel so that the AOT compiler does not introduce any module dependencies
23317 // which can break the strict dependency enforcement. (e.g. as in Google3)
23318 // Read more about this here: https://github.com/angular/angular/issues/25644
23319 const summary = this.unprocessedSymbolSummariesBySymbol.get(symbol);
23320 if (!summary || !summary.metadata || summary.metadata.__symbolic !== 'interface') {
23321 importAs = `${symbol.name}_${index}`;
23322 exportAs.push({ symbol, exportAs: importAs });
23323 }
23324 }
23325 }
23326 return {
23327 __symbol: index,
23328 name: symbol.name,
23329 filePath: this.summaryResolver.toSummaryFileName(symbol.filePath, this.srcFileName),
23330 importAs: importAs
23331 };
23332 })
23333 });
23334 return { json, exportAs };
23335 }
23336 processValue(value, flags) {
23337 return visitValue(value, this, flags);
23338 }
23339 visitOther(value, context) {
23340 if (value instanceof StaticSymbol) {
23341 let baseSymbol = this.symbolResolver.getStaticSymbol(value.filePath, value.name);
23342 const index = this.visitStaticSymbol(baseSymbol, context);
23343 return { __symbol: index, members: value.members };
23344 }
23345 }
23346 /**
23347 * Strip line and character numbers from ngsummaries.
23348 * Emitting them causes white spaces changes to retrigger upstream
23349 * recompilations in bazel.
23350 * TODO: find out a way to have line and character numbers in errors without
23351 * excessive recompilation in bazel.
23352 */
23353 visitStringMap(map, context) {
23354 if (map['__symbolic'] === 'resolved') {
23355 return visitValue(map['symbol'], this, context);
23356 }
23357 if (map['__symbolic'] === 'error') {
23358 delete map['line'];
23359 delete map['character'];
23360 }
23361 return super.visitStringMap(map, context);
23362 }
23363 /**
23364 * Returns null if the options.resolveValue is true, and the summary for the symbol
23365 * resolved to a type or could not be resolved.
23366 */
23367 visitStaticSymbol(baseSymbol, flags) {
23368 let index = this.indexBySymbol.get(baseSymbol);
23369 let summary = null;
23370 if (flags & 1 /* ResolveValue */ &&
23371 this.summaryResolver.isLibraryFile(baseSymbol.filePath)) {
23372 if (this.unprocessedSymbolSummariesBySymbol.has(baseSymbol)) {
23373 // the summary for this symbol was already added
23374 // -> nothing to do.
23375 return index;
23376 }
23377 summary = this.loadSummary(baseSymbol);
23378 if (summary && summary.metadata instanceof StaticSymbol) {
23379 // The summary is a reexport
23380 index = this.visitStaticSymbol(summary.metadata, flags);
23381 // reset the summary as it is just a reexport, so we don't want to store it.
23382 summary = null;
23383 }
23384 }
23385 else if (index != null) {
23386 // Note: == on purpose to compare with undefined!
23387 // No summary and the symbol is already added -> nothing to do.
23388 return index;
23389 }
23390 // Note: == on purpose to compare with undefined!
23391 if (index == null) {
23392 index = this.symbols.length;
23393 this.symbols.push(baseSymbol);
23394 }
23395 this.indexBySymbol.set(baseSymbol, index);
23396 if (summary) {
23397 this.addSummary(summary);
23398 }
23399 return index;
23400 }
23401 loadSummary(symbol) {
23402 let summary = this.summaryResolver.resolveSummary(symbol);
23403 if (!summary) {
23404 // some symbols might originate from a plain typescript library
23405 // that just exported .d.ts and .metadata.json files, i.e. where no summary
23406 // files were created.
23407 const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
23408 if (resolvedSymbol) {
23409 summary = { symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata };
23410 }
23411 }
23412 return summary;
23413 }
23414}
23415class ForJitSerializer {
23416 constructor(outputCtx, symbolResolver, summaryResolver) {
23417 this.outputCtx = outputCtx;
23418 this.symbolResolver = symbolResolver;
23419 this.summaryResolver = summaryResolver;
23420 this.data = [];
23421 }
23422 addSourceType(summary, metadata) {
23423 this.data.push({ summary, metadata, isLibrary: false });
23424 }
23425 addLibType(summary) {
23426 this.data.push({ summary, metadata: null, isLibrary: true });
23427 }
23428 serialize(exportAsArr) {
23429 const exportAsBySymbol = new Map();
23430 for (const { symbol, exportAs } of exportAsArr) {
23431 exportAsBySymbol.set(symbol, exportAs);
23432 }
23433 const ngModuleSymbols = new Set();
23434 for (const { summary, metadata, isLibrary } of this.data) {
23435 if (summary.summaryKind === CompileSummaryKind.NgModule) {
23436 // collect the symbols that refer to NgModule classes.
23437 // Note: we can't just rely on `summary.type.summaryKind` to determine this as
23438 // we don't add the summaries of all referenced symbols when we serialize type summaries.
23439 // See serializeSummaries for details.
23440 ngModuleSymbols.add(summary.type.reference);
23441 const modSummary = summary;
23442 for (const mod of modSummary.modules) {
23443 ngModuleSymbols.add(mod.reference);
23444 }
23445 }
23446 if (!isLibrary) {
23447 const fnName = summaryForJitName(summary.type.reference.name);
23448 createSummaryForJitFunction(this.outputCtx, summary.type.reference, this.serializeSummaryWithDeps(summary, metadata));
23449 }
23450 }
23451 ngModuleSymbols.forEach((ngModuleSymbol) => {
23452 if (this.summaryResolver.isLibraryFile(ngModuleSymbol.filePath)) {
23453 let exportAs = exportAsBySymbol.get(ngModuleSymbol) || ngModuleSymbol.name;
23454 const jitExportAsName = summaryForJitName(exportAs);
23455 this.outputCtx.statements.push(variable(jitExportAsName)
23456 .set(this.serializeSummaryRef(ngModuleSymbol))
23457 .toDeclStmt(null, [StmtModifier.Exported]));
23458 }
23459 });
23460 }
23461 serializeSummaryWithDeps(summary, metadata) {
23462 const expressions = [this.serializeSummary(summary)];
23463 let providers = [];
23464 if (metadata instanceof CompileNgModuleMetadata) {
23465 expressions.push(...
23466 // For directives / pipes, we only add the declared ones,
23467 // and rely on transitively importing NgModules to get the transitive
23468 // summaries.
23469 metadata.declaredDirectives.concat(metadata.declaredPipes)
23470 .map(type => type.reference)
23471 // For modules,
23472 // we also add the summaries for modules
23473 // from libraries.
23474 // This is ok as we produce reexports for all transitive modules.
23475 .concat(metadata.transitiveModule.modules.map(type => type.reference)
23476 .filter(ref => ref !== metadata.type.reference))
23477 .map((ref) => this.serializeSummaryRef(ref)));
23478 // Note: We don't use `NgModuleSummary.providers`, as that one is transitive,
23479 // and we already have transitive modules.
23480 providers = metadata.providers;
23481 }
23482 else if (summary.summaryKind === CompileSummaryKind.Directive) {
23483 const dirSummary = summary;
23484 providers = dirSummary.providers.concat(dirSummary.viewProviders);
23485 }
23486 // Note: We can't just refer to the `ngsummary.ts` files for `useClass` providers (as we do for
23487 // declaredDirectives / declaredPipes), as we allow
23488 // providers without ctor arguments to skip the `@Injectable` decorator,
23489 // i.e. we didn't generate .ngsummary.ts files for these.
23490 expressions.push(...providers.filter(provider => !!provider.useClass).map(provider => this.serializeSummary({
23491 summaryKind: CompileSummaryKind.Injectable, type: provider.useClass
23492 })));
23493 return literalArr(expressions);
23494 }
23495 serializeSummaryRef(typeSymbol) {
23496 const jitImportedSymbol = this.symbolResolver.getStaticSymbol(summaryForJitFileName(typeSymbol.filePath), summaryForJitName(typeSymbol.name));
23497 return this.outputCtx.importExpr(jitImportedSymbol);
23498 }
23499 serializeSummary(data) {
23500 const outputCtx = this.outputCtx;
23501 class Transformer {
23502 visitArray(arr, context) {
23503 return literalArr(arr.map(entry => visitValue(entry, this, context)));
23504 }
23505 visitStringMap(map, context) {
23506 return new LiteralMapExpr(Object.keys(map).map((key) => new LiteralMapEntry(key, visitValue(map[key], this, context), false)));
23507 }
23508 visitPrimitive(value, context) { return literal(value); }
23509 visitOther(value, context) {
23510 if (value instanceof StaticSymbol) {
23511 return outputCtx.importExpr(value);
23512 }
23513 else {
23514 throw new Error(`Illegal State: Encountered value ${value}`);
23515 }
23516 }
23517 }
23518 return visitValue(data, new Transformer(), null);
23519 }
23520}
23521class FromJsonDeserializer extends ValueTransformer {
23522 constructor(symbolCache, summaryResolver) {
23523 super();
23524 this.symbolCache = symbolCache;
23525 this.summaryResolver = summaryResolver;
23526 }
23527 deserialize(libraryFileName, json) {
23528 const data = JSON.parse(json);
23529 const allImportAs = [];
23530 this.symbols = data.symbols.map((serializedSymbol) => this.symbolCache.get(this.summaryResolver.fromSummaryFileName(serializedSymbol.filePath, libraryFileName), serializedSymbol.name));
23531 data.symbols.forEach((serializedSymbol, index) => {
23532 const symbol = this.symbols[index];
23533 const importAs = serializedSymbol.importAs;
23534 if (typeof importAs === 'number') {
23535 allImportAs.push({ symbol, importAs: this.symbols[importAs] });
23536 }
23537 else if (typeof importAs === 'string') {
23538 allImportAs.push({ symbol, importAs: this.symbolCache.get(ngfactoryFilePath(libraryFileName), importAs) });
23539 }
23540 });
23541 const summaries = visitValue(data.summaries, this, null);
23542 return { moduleName: data.moduleName, summaries, importAs: allImportAs };
23543 }
23544 visitStringMap(map, context) {
23545 if ('__symbol' in map) {
23546 const baseSymbol = this.symbols[map['__symbol']];
23547 const members = map['members'];
23548 return members.length ? this.symbolCache.get(baseSymbol.filePath, baseSymbol.name, members) :
23549 baseSymbol;
23550 }
23551 else {
23552 return super.visitStringMap(map, context);
23553 }
23554 }
23555}
23556function isCall(metadata) {
23557 return metadata && metadata.__symbolic === 'call';
23558}
23559function isFunctionCall(metadata) {
23560 return isCall(metadata) && unwrapResolvedMetadata(metadata.expression) instanceof StaticSymbol;
23561}
23562function isMethodCallOnVariable(metadata) {
23563 return isCall(metadata) && metadata.expression && metadata.expression.__symbolic === 'select' &&
23564 unwrapResolvedMetadata(metadata.expression.expression) instanceof StaticSymbol;
23565}
23566
23567/**
23568 * @license
23569 * Copyright Google Inc. All Rights Reserved.
23570 *
23571 * Use of this source code is governed by an MIT-style license that can be
23572 * found in the LICENSE file at https://angular.io/license
23573 */
23574class AotCompiler {
23575 constructor(_config, _options, _host, reflector, _metadataResolver, _templateParser, _styleCompiler, _viewCompiler, _typeCheckCompiler, _ngModuleCompiler, _injectableCompiler, _outputEmitter, _summaryResolver, _symbolResolver) {
23576 this._config = _config;
23577 this._options = _options;
23578 this._host = _host;
23579 this.reflector = reflector;
23580 this._metadataResolver = _metadataResolver;
23581 this._templateParser = _templateParser;
23582 this._styleCompiler = _styleCompiler;
23583 this._viewCompiler = _viewCompiler;
23584 this._typeCheckCompiler = _typeCheckCompiler;
23585 this._ngModuleCompiler = _ngModuleCompiler;
23586 this._injectableCompiler = _injectableCompiler;
23587 this._outputEmitter = _outputEmitter;
23588 this._summaryResolver = _summaryResolver;
23589 this._symbolResolver = _symbolResolver;
23590 this._templateAstCache = new Map();
23591 this._analyzedFiles = new Map();
23592 this._analyzedFilesForInjectables = new Map();
23593 }
23594 clearCache() { this._metadataResolver.clearCache(); }
23595 analyzeModulesSync(rootFiles) {
23596 const analyzeResult = analyzeAndValidateNgModules(rootFiles, this._host, this._symbolResolver, this._metadataResolver);
23597 analyzeResult.ngModules.forEach(ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, true));
23598 return analyzeResult;
23599 }
23600 analyzeModulesAsync(rootFiles) {
23601 const analyzeResult = analyzeAndValidateNgModules(rootFiles, this._host, this._symbolResolver, this._metadataResolver);
23602 return Promise
23603 .all(analyzeResult.ngModules.map(ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false)))
23604 .then(() => analyzeResult);
23605 }
23606 _analyzeFile(fileName) {
23607 let analyzedFile = this._analyzedFiles.get(fileName);
23608 if (!analyzedFile) {
23609 analyzedFile =
23610 analyzeFile(this._host, this._symbolResolver, this._metadataResolver, fileName);
23611 this._analyzedFiles.set(fileName, analyzedFile);
23612 }
23613 return analyzedFile;
23614 }
23615 _analyzeFileForInjectables(fileName) {
23616 let analyzedFile = this._analyzedFilesForInjectables.get(fileName);
23617 if (!analyzedFile) {
23618 analyzedFile = analyzeFileForInjectables(this._host, this._symbolResolver, this._metadataResolver, fileName);
23619 this._analyzedFilesForInjectables.set(fileName, analyzedFile);
23620 }
23621 return analyzedFile;
23622 }
23623 findGeneratedFileNames(fileName) {
23624 const genFileNames = [];
23625 const file = this._analyzeFile(fileName);
23626 // Make sure we create a .ngfactory if we have a injectable/directive/pipe/NgModule
23627 // or a reference to a non source file.
23628 // Note: This is overestimating the required .ngfactory files as the real calculation is harder.
23629 // Only do this for StubEmitFlags.Basic, as adding a type check block
23630 // does not change this file (as we generate type check blocks based on NgModules).
23631 if (this._options.allowEmptyCodegenFiles || file.directives.length || file.pipes.length ||
23632 file.injectables.length || file.ngModules.length || file.exportsNonSourceFiles) {
23633 genFileNames.push(ngfactoryFilePath(file.fileName, true));
23634 if (this._options.enableSummariesForJit) {
23635 genFileNames.push(summaryForJitFileName(file.fileName, true));
23636 }
23637 }
23638 const fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(file.fileName, true)[1]);
23639 file.directives.forEach((dirSymbol) => {
23640 const compMeta = this._metadataResolver.getNonNormalizedDirectiveMetadata(dirSymbol).metadata;
23641 if (!compMeta.isComponent) {
23642 return;
23643 }
23644 // Note: compMeta is a component and therefore template is non null.
23645 compMeta.template.styleUrls.forEach((styleUrl) => {
23646 const normalizedUrl = this._host.resourceNameToFileName(styleUrl, file.fileName);
23647 if (!normalizedUrl) {
23648 throw syntaxError(`Couldn't resolve resource ${styleUrl} relative to ${file.fileName}`);
23649 }
23650 const needsShim = (compMeta.template.encapsulation ||
23651 this._config.defaultEncapsulation) === ViewEncapsulation.Emulated;
23652 genFileNames.push(_stylesModuleUrl(normalizedUrl, needsShim, fileSuffix));
23653 if (this._options.allowEmptyCodegenFiles) {
23654 genFileNames.push(_stylesModuleUrl(normalizedUrl, !needsShim, fileSuffix));
23655 }
23656 });
23657 });
23658 return genFileNames;
23659 }
23660 emitBasicStub(genFileName, originalFileName) {
23661 const outputCtx = this._createOutputContext(genFileName);
23662 if (genFileName.endsWith('.ngfactory.ts')) {
23663 if (!originalFileName) {
23664 throw new Error(`Assertion error: require the original file for .ngfactory.ts stubs. File: ${genFileName}`);
23665 }
23666 const originalFile = this._analyzeFile(originalFileName);
23667 this._createNgFactoryStub(outputCtx, originalFile, 1 /* Basic */);
23668 }
23669 else if (genFileName.endsWith('.ngsummary.ts')) {
23670 if (this._options.enableSummariesForJit) {
23671 if (!originalFileName) {
23672 throw new Error(`Assertion error: require the original file for .ngsummary.ts stubs. File: ${genFileName}`);
23673 }
23674 const originalFile = this._analyzeFile(originalFileName);
23675 _createEmptyStub(outputCtx);
23676 originalFile.ngModules.forEach(ngModule => {
23677 // create exports that user code can reference
23678 createForJitStub(outputCtx, ngModule.type.reference);
23679 });
23680 }
23681 }
23682 else if (genFileName.endsWith('.ngstyle.ts')) {
23683 _createEmptyStub(outputCtx);
23684 }
23685 // Note: for the stubs, we don't need a property srcFileUrl,
23686 // as later on in emitAllImpls we will create the proper GeneratedFiles with the
23687 // correct srcFileUrl.
23688 // This is good as e.g. for .ngstyle.ts files we can't derive
23689 // the url of components based on the genFileUrl.
23690 return this._codegenSourceModule('unknown', outputCtx);
23691 }
23692 emitTypeCheckStub(genFileName, originalFileName) {
23693 const originalFile = this._analyzeFile(originalFileName);
23694 const outputCtx = this._createOutputContext(genFileName);
23695 if (genFileName.endsWith('.ngfactory.ts')) {
23696 this._createNgFactoryStub(outputCtx, originalFile, 2 /* TypeCheck */);
23697 }
23698 return outputCtx.statements.length > 0 ?
23699 this._codegenSourceModule(originalFile.fileName, outputCtx) :
23700 null;
23701 }
23702 loadFilesAsync(fileNames, tsFiles) {
23703 const files = fileNames.map(fileName => this._analyzeFile(fileName));
23704 const loadingPromises = [];
23705 files.forEach(file => file.ngModules.forEach(ngModule => loadingPromises.push(this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false))));
23706 const analyzedInjectables = tsFiles.map(tsFile => this._analyzeFileForInjectables(tsFile));
23707 return Promise.all(loadingPromises).then(_ => ({
23708 analyzedModules: mergeAndValidateNgFiles(files),
23709 analyzedInjectables: analyzedInjectables,
23710 }));
23711 }
23712 loadFilesSync(fileNames, tsFiles) {
23713 const files = fileNames.map(fileName => this._analyzeFile(fileName));
23714 files.forEach(file => file.ngModules.forEach(ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, true)));
23715 const analyzedInjectables = tsFiles.map(tsFile => this._analyzeFileForInjectables(tsFile));
23716 return {
23717 analyzedModules: mergeAndValidateNgFiles(files),
23718 analyzedInjectables: analyzedInjectables,
23719 };
23720 }
23721 _createNgFactoryStub(outputCtx, file, emitFlags) {
23722 let componentId = 0;
23723 file.ngModules.forEach((ngModuleMeta, ngModuleIndex) => {
23724 // Note: the code below needs to executed for StubEmitFlags.Basic and StubEmitFlags.TypeCheck,
23725 // so we don't change the .ngfactory file too much when adding the type-check block.
23726 // create exports that user code can reference
23727 this._ngModuleCompiler.createStub(outputCtx, ngModuleMeta.type.reference);
23728 // add references to the symbols from the metadata.
23729 // These can be used by the type check block for components,
23730 // and they also cause TypeScript to include these files into the program too,
23731 // which will make them part of the analyzedFiles.
23732 const externalReferences = [
23733 // Add references that are available from all the modules and imports.
23734 ...ngModuleMeta.transitiveModule.directives.map(d => d.reference),
23735 ...ngModuleMeta.transitiveModule.pipes.map(d => d.reference),
23736 ...ngModuleMeta.importedModules.map(m => m.type.reference),
23737 ...ngModuleMeta.exportedModules.map(m => m.type.reference),
23738 // Add references that might be inserted by the template compiler.
23739 ...this._externalIdentifierReferences([Identifiers.TemplateRef, Identifiers.ElementRef]),
23740 ];
23741 const externalReferenceVars = new Map();
23742 externalReferences.forEach((ref, typeIndex) => {
23743 externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
23744 });
23745 externalReferenceVars.forEach((varName, reference) => {
23746 outputCtx.statements.push(variable(varName)
23747 .set(NULL_EXPR.cast(DYNAMIC_TYPE))
23748 .toDeclStmt(expressionType(outputCtx.importExpr(reference, /* typeParams */ null, /* useSummaries */ false))));
23749 });
23750 if (emitFlags & 2 /* TypeCheck */) {
23751 // add the type-check block for all components of the NgModule
23752 ngModuleMeta.declaredDirectives.forEach((dirId) => {
23753 const compMeta = this._metadataResolver.getDirectiveMetadata(dirId.reference);
23754 if (!compMeta.isComponent) {
23755 return;
23756 }
23757 componentId++;
23758 this._createTypeCheckBlock(outputCtx, `${compMeta.type.reference.name}_Host_${componentId}`, ngModuleMeta, this._metadataResolver.getHostComponentMetadata(compMeta), [compMeta.type], externalReferenceVars);
23759 this._createTypeCheckBlock(outputCtx, `${compMeta.type.reference.name}_${componentId}`, ngModuleMeta, compMeta, ngModuleMeta.transitiveModule.directives, externalReferenceVars);
23760 });
23761 }
23762 });
23763 if (outputCtx.statements.length === 0) {
23764 _createEmptyStub(outputCtx);
23765 }
23766 }
23767 _externalIdentifierReferences(references) {
23768 const result = [];
23769 for (let reference of references) {
23770 const token = createTokenForExternalReference(this.reflector, reference);
23771 if (token.identifier) {
23772 result.push(token.identifier.reference);
23773 }
23774 }
23775 return result;
23776 }
23777 _createTypeCheckBlock(ctx, componentId, moduleMeta, compMeta, directives, externalReferenceVars) {
23778 const { template: parsedTemplate, pipes: usedPipes } = this._parseTemplate(compMeta, moduleMeta, directives);
23779 ctx.statements.push(...this._typeCheckCompiler.compileComponent(componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars, ctx));
23780 }
23781 emitMessageBundle(analyzeResult, locale) {
23782 const errors = [];
23783 const htmlParser = new HtmlParser();
23784 // TODO(vicb): implicit tags & attributes
23785 const messageBundle = new MessageBundle(htmlParser, [], {}, locale);
23786 analyzeResult.files.forEach(file => {
23787 const compMetas = [];
23788 file.directives.forEach(directiveType => {
23789 const dirMeta = this._metadataResolver.getDirectiveMetadata(directiveType);
23790 if (dirMeta && dirMeta.isComponent) {
23791 compMetas.push(dirMeta);
23792 }
23793 });
23794 compMetas.forEach(compMeta => {
23795 const html = compMeta.template.template;
23796 // Template URL points to either an HTML or TS file depending on whether
23797 // the file is used with `templateUrl:` or `template:`, respectively.
23798 const templateUrl = compMeta.template.templateUrl;
23799 const interpolationConfig = InterpolationConfig.fromArray(compMeta.template.interpolation);
23800 errors.push(...messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig));
23801 });
23802 });
23803 if (errors.length) {
23804 throw new Error(errors.map(e => e.toString()).join('\n'));
23805 }
23806 return messageBundle;
23807 }
23808 emitAllPartialModules({ ngModuleByPipeOrDirective, files }, r3Files) {
23809 const contextMap = new Map();
23810 const getContext = (fileName) => {
23811 if (!contextMap.has(fileName)) {
23812 contextMap.set(fileName, this._createOutputContext(fileName));
23813 }
23814 return contextMap.get(fileName);
23815 };
23816 files.forEach(file => this._compilePartialModule(file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules, file.injectables, getContext(file.fileName)));
23817 r3Files.forEach(file => this._compileShallowModules(file.fileName, file.shallowModules, getContext(file.fileName)));
23818 return Array.from(contextMap.values())
23819 .map(context => ({
23820 fileName: context.genFilePath,
23821 statements: [...context.constantPool.statements, ...context.statements],
23822 }));
23823 }
23824 _compileShallowModules(fileName, shallowModules, context) {
23825 shallowModules.forEach(module => compileNgModuleFromRender2(context, module, this._injectableCompiler));
23826 }
23827 _compilePartialModule(fileName, ngModuleByPipeOrDirective, directives, pipes, ngModules, injectables, context) {
23828 const errors = [];
23829 const schemaRegistry = new DomElementSchemaRegistry();
23830 const hostBindingParser = new BindingParser(this._templateParser.expressionParser, DEFAULT_INTERPOLATION_CONFIG, schemaRegistry, [], errors);
23831 // Process all components and directives
23832 directives.forEach(directiveType => {
23833 const directiveMetadata = this._metadataResolver.getDirectiveMetadata(directiveType);
23834 if (directiveMetadata.isComponent) {
23835 const module = ngModuleByPipeOrDirective.get(directiveType);
23836 module ||
23837 error(`Cannot determine the module for component '${identifierName(directiveMetadata.type)}'`);
23838 let htmlAst = directiveMetadata.template.htmlAst;
23839 const preserveWhitespaces = directiveMetadata.template.preserveWhitespaces;
23840 if (!preserveWhitespaces) {
23841 htmlAst = removeWhitespaces(htmlAst);
23842 }
23843 const render3Ast = htmlAstToRender3Ast(htmlAst.rootNodes, hostBindingParser);
23844 // Map of StaticType by directive selectors
23845 const directiveTypeBySel = new Map();
23846 const directives = module.transitiveModule.directives.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
23847 directives.forEach(directive => {
23848 if (directive.selector) {
23849 directiveTypeBySel.set(directive.selector, directive.type.reference);
23850 }
23851 });
23852 // Map of StaticType by pipe names
23853 const pipeTypeByName = new Map();
23854 const pipes = module.transitiveModule.pipes.map(pipe => this._metadataResolver.getPipeSummary(pipe.reference));
23855 pipes.forEach(pipe => { pipeTypeByName.set(pipe.name, pipe.type.reference); });
23856 compileComponentFromRender2(context, directiveMetadata, render3Ast, this.reflector, hostBindingParser, directiveTypeBySel, pipeTypeByName);
23857 }
23858 else {
23859 compileDirectiveFromRender2(context, directiveMetadata, this.reflector, hostBindingParser);
23860 }
23861 });
23862 pipes.forEach(pipeType => {
23863 const pipeMetadata = this._metadataResolver.getPipeMetadata(pipeType);
23864 if (pipeMetadata) {
23865 compilePipeFromRender2(context, pipeMetadata, this.reflector);
23866 }
23867 });
23868 injectables.forEach(injectable => this._injectableCompiler.compile(injectable, context));
23869 }
23870 emitAllPartialModules2(files) {
23871 // Using reduce like this is a select many pattern (where map is a select pattern)
23872 return files.reduce((r, file) => {
23873 r.push(...this._emitPartialModule2(file.fileName, file.injectables));
23874 return r;
23875 }, []);
23876 }
23877 _emitPartialModule2(fileName, injectables) {
23878 const context = this._createOutputContext(fileName);
23879 injectables.forEach(injectable => this._injectableCompiler.compile(injectable, context));
23880 if (context.statements && context.statements.length > 0) {
23881 return [{ fileName, statements: [...context.constantPool.statements, ...context.statements] }];
23882 }
23883 return [];
23884 }
23885 emitAllImpls(analyzeResult) {
23886 const { ngModuleByPipeOrDirective, files } = analyzeResult;
23887 const sourceModules = files.map(file => this._compileImplFile(file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules, file.injectables));
23888 return flatten(sourceModules);
23889 }
23890 _compileImplFile(srcFileUrl, ngModuleByPipeOrDirective, directives, pipes, ngModules, injectables) {
23891 const fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(srcFileUrl, true)[1]);
23892 const generatedFiles = [];
23893 const outputCtx = this._createOutputContext(ngfactoryFilePath(srcFileUrl, true));
23894 generatedFiles.push(...this._createSummary(srcFileUrl, directives, pipes, ngModules, injectables, outputCtx));
23895 // compile all ng modules
23896 ngModules.forEach((ngModuleMeta) => this._compileModule(outputCtx, ngModuleMeta));
23897 // compile components
23898 directives.forEach((dirType) => {
23899 const compMeta = this._metadataResolver.getDirectiveMetadata(dirType);
23900 if (!compMeta.isComponent) {
23901 return;
23902 }
23903 const ngModule = ngModuleByPipeOrDirective.get(dirType);
23904 if (!ngModule) {
23905 throw new Error(`Internal Error: cannot determine the module for component ${identifierName(compMeta.type)}!`);
23906 }
23907 // compile styles
23908 const componentStylesheet = this._styleCompiler.compileComponent(outputCtx, compMeta);
23909 // Note: compMeta is a component and therefore template is non null.
23910 compMeta.template.externalStylesheets.forEach((stylesheetMeta) => {
23911 // Note: fill non shim and shim style files as they might
23912 // be shared by component with and without ViewEncapsulation.
23913 const shim = this._styleCompiler.needsStyleShim(compMeta);
23914 generatedFiles.push(this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, shim, fileSuffix));
23915 if (this._options.allowEmptyCodegenFiles) {
23916 generatedFiles.push(this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, !shim, fileSuffix));
23917 }
23918 });
23919 // compile components
23920 const compViewVars = this._compileComponent(outputCtx, compMeta, ngModule, ngModule.transitiveModule.directives, componentStylesheet, fileSuffix);
23921 this._compileComponentFactory(outputCtx, compMeta, ngModule, fileSuffix);
23922 });
23923 if (outputCtx.statements.length > 0 || this._options.allowEmptyCodegenFiles) {
23924 const srcModule = this._codegenSourceModule(srcFileUrl, outputCtx);
23925 generatedFiles.unshift(srcModule);
23926 }
23927 return generatedFiles;
23928 }
23929 _createSummary(srcFileName, directives, pipes, ngModules, injectables, ngFactoryCtx) {
23930 const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileName)
23931 .map(symbol => this._symbolResolver.resolveSymbol(symbol));
23932 const typeData = [
23933 ...ngModules.map(meta => ({
23934 summary: this._metadataResolver.getNgModuleSummary(meta.type.reference),
23935 metadata: this._metadataResolver.getNgModuleMetadata(meta.type.reference)
23936 })),
23937 ...directives.map(ref => ({
23938 summary: this._metadataResolver.getDirectiveSummary(ref),
23939 metadata: this._metadataResolver.getDirectiveMetadata(ref)
23940 })),
23941 ...pipes.map(ref => ({
23942 summary: this._metadataResolver.getPipeSummary(ref),
23943 metadata: this._metadataResolver.getPipeMetadata(ref)
23944 })),
23945 ...injectables.map(ref => ({
23946 summary: this._metadataResolver.getInjectableSummary(ref.symbol),
23947 metadata: this._metadataResolver.getInjectableSummary(ref.symbol).type
23948 }))
23949 ];
23950 const forJitOutputCtx = this._options.enableSummariesForJit ?
23951 this._createOutputContext(summaryForJitFileName(srcFileName, true)) :
23952 null;
23953 const { json, exportAs } = serializeSummaries(srcFileName, forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData, this._options.createExternalSymbolFactoryReexports);
23954 exportAs.forEach((entry) => {
23955 ngFactoryCtx.statements.push(variable(entry.exportAs).set(ngFactoryCtx.importExpr(entry.symbol)).toDeclStmt(null, [
23956 StmtModifier.Exported
23957 ]));
23958 });
23959 const summaryJson = new GeneratedFile(srcFileName, summaryFileName(srcFileName), json);
23960 const result = [summaryJson];
23961 if (forJitOutputCtx) {
23962 result.push(this._codegenSourceModule(srcFileName, forJitOutputCtx));
23963 }
23964 return result;
23965 }
23966 _compileModule(outputCtx, ngModule) {
23967 const providers = [];
23968 if (this._options.locale) {
23969 const normalizedLocale = this._options.locale.replace(/_/g, '-');
23970 providers.push({
23971 token: createTokenForExternalReference(this.reflector, Identifiers.LOCALE_ID),
23972 useValue: normalizedLocale,
23973 });
23974 }
23975 if (this._options.i18nFormat) {
23976 providers.push({
23977 token: createTokenForExternalReference(this.reflector, Identifiers.TRANSLATIONS_FORMAT),
23978 useValue: this._options.i18nFormat
23979 });
23980 }
23981 this._ngModuleCompiler.compile(outputCtx, ngModule, providers);
23982 }
23983 _compileComponentFactory(outputCtx, compMeta, ngModule, fileSuffix) {
23984 const hostMeta = this._metadataResolver.getHostComponentMetadata(compMeta);
23985 const hostViewFactoryVar = this._compileComponent(outputCtx, hostMeta, ngModule, [compMeta.type], null, fileSuffix)
23986 .viewClassVar;
23987 const compFactoryVar = componentFactoryName(compMeta.type.reference);
23988 const inputsExprs = [];
23989 for (let propName in compMeta.inputs) {
23990 const templateName = compMeta.inputs[propName];
23991 // Don't quote so that the key gets minified...
23992 inputsExprs.push(new LiteralMapEntry(propName, literal(templateName), false));
23993 }
23994 const outputsExprs = [];
23995 for (let propName in compMeta.outputs) {
23996 const templateName = compMeta.outputs[propName];
23997 // Don't quote so that the key gets minified...
23998 outputsExprs.push(new LiteralMapEntry(propName, literal(templateName), false));
23999 }
24000 outputCtx.statements.push(variable(compFactoryVar)
24001 .set(importExpr(Identifiers.createComponentFactory).callFn([
24002 literal(compMeta.selector), outputCtx.importExpr(compMeta.type.reference),
24003 variable(hostViewFactoryVar), new LiteralMapExpr(inputsExprs),
24004 new LiteralMapExpr(outputsExprs),
24005 literalArr(compMeta.template.ngContentSelectors.map(selector => literal(selector)))
24006 ]))
24007 .toDeclStmt(importType(Identifiers.ComponentFactory, [expressionType(outputCtx.importExpr(compMeta.type.reference))], [TypeModifier.Const]), [StmtModifier.Final, StmtModifier.Exported]));
24008 }
24009 _compileComponent(outputCtx, compMeta, ngModule, directiveIdentifiers, componentStyles, fileSuffix) {
24010 const { template: parsedTemplate, pipes: usedPipes } = this._parseTemplate(compMeta, ngModule, directiveIdentifiers);
24011 const stylesExpr = componentStyles ? variable(componentStyles.stylesVar) : literalArr([]);
24012 const viewResult = this._viewCompiler.compileComponent(outputCtx, compMeta, parsedTemplate, stylesExpr, usedPipes);
24013 if (componentStyles) {
24014 _resolveStyleStatements(this._symbolResolver, componentStyles, this._styleCompiler.needsStyleShim(compMeta), fileSuffix);
24015 }
24016 return viewResult;
24017 }
24018 _parseTemplate(compMeta, ngModule, directiveIdentifiers) {
24019 if (this._templateAstCache.has(compMeta.type.reference)) {
24020 return this._templateAstCache.get(compMeta.type.reference);
24021 }
24022 const preserveWhitespaces = compMeta.template.preserveWhitespaces;
24023 const directives = directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
24024 const pipes = ngModule.transitiveModule.pipes.map(pipe => this._metadataResolver.getPipeSummary(pipe.reference));
24025 const result = this._templateParser.parse(compMeta, compMeta.template.htmlAst, directives, pipes, ngModule.schemas, templateSourceUrl(ngModule.type, compMeta, compMeta.template), preserveWhitespaces);
24026 this._templateAstCache.set(compMeta.type.reference, result);
24027 return result;
24028 }
24029 _createOutputContext(genFilePath) {
24030 const importExpr$1 = (symbol, typeParams = null, useSummaries = true) => {
24031 if (!(symbol instanceof StaticSymbol)) {
24032 throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
24033 }
24034 const arity = this._symbolResolver.getTypeArity(symbol) || 0;
24035 const { filePath, name, members } = this._symbolResolver.getImportAs(symbol, useSummaries) || symbol;
24036 const importModule = this._fileNameToModuleName(filePath, genFilePath);
24037 // It should be good enough to compare filePath to genFilePath and if they are equal
24038 // there is a self reference. However, ngfactory files generate to .ts but their
24039 // symbols have .d.ts so a simple compare is insufficient. They should be canonical
24040 // and is tracked by #17705.
24041 const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
24042 const moduleName = importModule === selfReference ? null : importModule;
24043 // If we are in a type expression that refers to a generic type then supply
24044 // the required type parameters. If there were not enough type parameters
24045 // supplied, supply any as the type. Outside a type expression the reference
24046 // should not supply type parameters and be treated as a simple value reference
24047 // to the constructor function itself.
24048 const suppliedTypeParams = typeParams || [];
24049 const missingTypeParamsCount = arity - suppliedTypeParams.length;
24050 const allTypeParams = suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(DYNAMIC_TYPE));
24051 return members.reduce((expr, memberName) => expr.prop(memberName), importExpr(new ExternalReference(moduleName, name, null), allTypeParams));
24052 };
24053 return { statements: [], genFilePath, importExpr: importExpr$1, constantPool: new ConstantPool() };
24054 }
24055 _fileNameToModuleName(importedFilePath, containingFilePath) {
24056 return this._summaryResolver.getKnownModuleName(importedFilePath) ||
24057 this._symbolResolver.getKnownModuleName(importedFilePath) ||
24058 this._host.fileNameToModuleName(importedFilePath, containingFilePath);
24059 }
24060 _codegenStyles(srcFileUrl, compMeta, stylesheetMetadata, isShimmed, fileSuffix) {
24061 const outputCtx = this._createOutputContext(_stylesModuleUrl(stylesheetMetadata.moduleUrl, isShimmed, fileSuffix));
24062 const compiledStylesheet = this._styleCompiler.compileStyles(outputCtx, compMeta, stylesheetMetadata, isShimmed);
24063 _resolveStyleStatements(this._symbolResolver, compiledStylesheet, isShimmed, fileSuffix);
24064 return this._codegenSourceModule(srcFileUrl, outputCtx);
24065 }
24066 _codegenSourceModule(srcFileUrl, ctx) {
24067 return new GeneratedFile(srcFileUrl, ctx.genFilePath, ctx.statements);
24068 }
24069 listLazyRoutes(entryRoute, analyzedModules) {
24070 const self = this;
24071 if (entryRoute) {
24072 const symbol = parseLazyRoute(entryRoute, this.reflector).referencedModule;
24073 return visitLazyRoute(symbol);
24074 }
24075 else if (analyzedModules) {
24076 const allLazyRoutes = [];
24077 for (const ngModule of analyzedModules.ngModules) {
24078 const lazyRoutes = listLazyRoutes(ngModule, this.reflector);
24079 for (const lazyRoute of lazyRoutes) {
24080 allLazyRoutes.push(lazyRoute);
24081 }
24082 }
24083 return allLazyRoutes;
24084 }
24085 else {
24086 throw new Error(`Either route or analyzedModules has to be specified!`);
24087 }
24088 function visitLazyRoute(symbol, seenRoutes = new Set(), allLazyRoutes = []) {
24089 // Support pointing to default exports, but stop recursing there,
24090 // as the StaticReflector does not yet support default exports.
24091 if (seenRoutes.has(symbol) || !symbol.name) {
24092 return allLazyRoutes;
24093 }
24094 seenRoutes.add(symbol);
24095 const lazyRoutes = listLazyRoutes(self._metadataResolver.getNgModuleMetadata(symbol, true), self.reflector);
24096 for (const lazyRoute of lazyRoutes) {
24097 allLazyRoutes.push(lazyRoute);
24098 visitLazyRoute(lazyRoute.referencedModule, seenRoutes, allLazyRoutes);
24099 }
24100 return allLazyRoutes;
24101 }
24102 }
24103}
24104function _createEmptyStub(outputCtx) {
24105 // Note: We need to produce at least one import statement so that
24106 // TypeScript knows that the file is an es6 module. Otherwise our generated
24107 // exports / imports won't be emitted properly by TypeScript.
24108 outputCtx.statements.push(importExpr(Identifiers.ComponentFactory).toStmt());
24109}
24110function _resolveStyleStatements(symbolResolver, compileResult, needsShim, fileSuffix) {
24111 compileResult.dependencies.forEach((dep) => {
24112 dep.setValue(symbolResolver.getStaticSymbol(_stylesModuleUrl(dep.moduleUrl, needsShim, fileSuffix), dep.name));
24113 });
24114}
24115function _stylesModuleUrl(stylesheetUrl, shim, suffix) {
24116 return `${stylesheetUrl}${shim ? '.shim' : ''}.ngstyle${suffix}`;
24117}
24118function analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver) {
24119 const files = _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver);
24120 return mergeAnalyzedFiles(files);
24121}
24122function analyzeAndValidateNgModules(fileNames, host, staticSymbolResolver, metadataResolver) {
24123 return validateAnalyzedModules(analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver));
24124}
24125function validateAnalyzedModules(analyzedModules) {
24126 if (analyzedModules.symbolsMissingModule && analyzedModules.symbolsMissingModule.length) {
24127 const messages = analyzedModules.symbolsMissingModule.map(s => `Cannot determine the module for class ${s.name} in ${s.filePath}! Add ${s.name} to the NgModule to fix it.`);
24128 throw syntaxError(messages.join('\n'));
24129 }
24130 return analyzedModules;
24131}
24132// Analyzes all of the program files,
24133// including files that are not part of the program
24134// but are referenced by an NgModule.
24135function _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver) {
24136 const seenFiles = new Set();
24137 const files = [];
24138 const visitFile = (fileName) => {
24139 if (seenFiles.has(fileName) || !host.isSourceFile(fileName)) {
24140 return false;
24141 }
24142 seenFiles.add(fileName);
24143 const analyzedFile = analyzeFile(host, staticSymbolResolver, metadataResolver, fileName);
24144 files.push(analyzedFile);
24145 analyzedFile.ngModules.forEach(ngModule => {
24146 ngModule.transitiveModule.modules.forEach(modMeta => visitFile(modMeta.reference.filePath));
24147 });
24148 };
24149 fileNames.forEach((fileName) => visitFile(fileName));
24150 return files;
24151}
24152function analyzeFile(host, staticSymbolResolver, metadataResolver, fileName) {
24153 const directives = [];
24154 const pipes = [];
24155 const injectables = [];
24156 const ngModules = [];
24157 const hasDecorators = staticSymbolResolver.hasDecorators(fileName);
24158 let exportsNonSourceFiles = false;
24159 // Don't analyze .d.ts files that have no decorators as a shortcut
24160 // to speed up the analysis. This prevents us from
24161 // resolving the references in these files.
24162 // Note: exportsNonSourceFiles is only needed when compiling with summaries,
24163 // which is not the case when .d.ts files are treated as input files.
24164 if (!fileName.endsWith('.d.ts') || hasDecorators) {
24165 staticSymbolResolver.getSymbolsOf(fileName).forEach((symbol) => {
24166 const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
24167 const symbolMeta = resolvedSymbol.metadata;
24168 if (!symbolMeta || symbolMeta.__symbolic === 'error') {
24169 return;
24170 }
24171 let isNgSymbol = false;
24172 if (symbolMeta.__symbolic === 'class') {
24173 if (metadataResolver.isDirective(symbol)) {
24174 isNgSymbol = true;
24175 directives.push(symbol);
24176 }
24177 else if (metadataResolver.isPipe(symbol)) {
24178 isNgSymbol = true;
24179 pipes.push(symbol);
24180 }
24181 else if (metadataResolver.isNgModule(symbol)) {
24182 const ngModule = metadataResolver.getNgModuleMetadata(symbol, false);
24183 if (ngModule) {
24184 isNgSymbol = true;
24185 ngModules.push(ngModule);
24186 }
24187 }
24188 else if (metadataResolver.isInjectable(symbol)) {
24189 isNgSymbol = true;
24190 const injectable = metadataResolver.getInjectableMetadata(symbol, null, false);
24191 if (injectable) {
24192 injectables.push(injectable);
24193 }
24194 }
24195 }
24196 if (!isNgSymbol) {
24197 exportsNonSourceFiles =
24198 exportsNonSourceFiles || isValueExportingNonSourceFile(host, symbolMeta);
24199 }
24200 });
24201 }
24202 return {
24203 fileName, directives, pipes, ngModules, injectables, exportsNonSourceFiles,
24204 };
24205}
24206function analyzeFileForInjectables(host, staticSymbolResolver, metadataResolver, fileName) {
24207 const injectables = [];
24208 const shallowModules = [];
24209 if (staticSymbolResolver.hasDecorators(fileName)) {
24210 staticSymbolResolver.getSymbolsOf(fileName).forEach((symbol) => {
24211 const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
24212 const symbolMeta = resolvedSymbol.metadata;
24213 if (!symbolMeta || symbolMeta.__symbolic === 'error') {
24214 return;
24215 }
24216 if (symbolMeta.__symbolic === 'class') {
24217 if (metadataResolver.isInjectable(symbol)) {
24218 const injectable = metadataResolver.getInjectableMetadata(symbol, null, false);
24219 if (injectable) {
24220 injectables.push(injectable);
24221 }
24222 }
24223 else if (metadataResolver.isNgModule(symbol)) {
24224 const module = metadataResolver.getShallowModuleMetadata(symbol);
24225 if (module) {
24226 shallowModules.push(module);
24227 }
24228 }
24229 }
24230 });
24231 }
24232 return { fileName, injectables, shallowModules };
24233}
24234function isValueExportingNonSourceFile(host, metadata) {
24235 let exportsNonSourceFiles = false;
24236 class Visitor {
24237 visitArray(arr, context) { arr.forEach(v => visitValue(v, this, context)); }
24238 visitStringMap(map, context) {
24239 Object.keys(map).forEach((key) => visitValue(map[key], this, context));
24240 }
24241 visitPrimitive(value, context) { }
24242 visitOther(value, context) {
24243 if (value instanceof StaticSymbol && !host.isSourceFile(value.filePath)) {
24244 exportsNonSourceFiles = true;
24245 }
24246 }
24247 }
24248 visitValue(metadata, new Visitor(), null);
24249 return exportsNonSourceFiles;
24250}
24251function mergeAnalyzedFiles(analyzedFiles) {
24252 const allNgModules = [];
24253 const ngModuleByPipeOrDirective = new Map();
24254 const allPipesAndDirectives = new Set();
24255 analyzedFiles.forEach(af => {
24256 af.ngModules.forEach(ngModule => {
24257 allNgModules.push(ngModule);
24258 ngModule.declaredDirectives.forEach(d => ngModuleByPipeOrDirective.set(d.reference, ngModule));
24259 ngModule.declaredPipes.forEach(p => ngModuleByPipeOrDirective.set(p.reference, ngModule));
24260 });
24261 af.directives.forEach(d => allPipesAndDirectives.add(d));
24262 af.pipes.forEach(p => allPipesAndDirectives.add(p));
24263 });
24264 const symbolsMissingModule = [];
24265 allPipesAndDirectives.forEach(ref => {
24266 if (!ngModuleByPipeOrDirective.has(ref)) {
24267 symbolsMissingModule.push(ref);
24268 }
24269 });
24270 return {
24271 ngModules: allNgModules,
24272 ngModuleByPipeOrDirective,
24273 symbolsMissingModule,
24274 files: analyzedFiles
24275 };
24276}
24277function mergeAndValidateNgFiles(files) {
24278 return validateAnalyzedModules(mergeAnalyzedFiles(files));
24279}
24280
24281/**
24282 * @license
24283 * Copyright Google Inc. All Rights Reserved.
24284 *
24285 * Use of this source code is governed by an MIT-style license that can be
24286 * found in the LICENSE file at https://angular.io/license
24287 */
24288const FORMATTED_MESSAGE = 'ngFormattedMessage';
24289function indentStr(level) {
24290 if (level <= 0)
24291 return '';
24292 if (level < 6)
24293 return ['', ' ', ' ', ' ', ' ', ' '][level];
24294 const half = indentStr(Math.floor(level / 2));
24295 return half + half + (level % 2 === 1 ? ' ' : '');
24296}
24297function formatChain(chain, indent = 0) {
24298 if (!chain)
24299 return '';
24300 const position = chain.position ?
24301 `${chain.position.fileName}(${chain.position.line + 1},${chain.position.column + 1})` :
24302 '';
24303 const prefix = position && indent === 0 ? `${position}: ` : '';
24304 const postfix = position && indent !== 0 ? ` at ${position}` : '';
24305 const message = `${prefix}${chain.message}${postfix}`;
24306 return `${indentStr(indent)}${message}${(chain.next && ('\n' + formatChain(chain.next, indent + 2))) || ''}`;
24307}
24308function formattedError(chain) {
24309 const message = formatChain(chain) + '.';
24310 const error = syntaxError(message);
24311 error[FORMATTED_MESSAGE] = true;
24312 error.chain = chain;
24313 error.position = chain.position;
24314 return error;
24315}
24316function isFormattedError(error) {
24317 return !!error[FORMATTED_MESSAGE];
24318}
24319
24320/**
24321 * @license
24322 * Copyright Google Inc. All Rights Reserved.
24323 *
24324 * Use of this source code is governed by an MIT-style license that can be
24325 * found in the LICENSE file at https://angular.io/license
24326 */
24327const ANGULAR_CORE = '@angular/core';
24328const ANGULAR_ROUTER = '@angular/router';
24329const HIDDEN_KEY = /^\$.*\$$/;
24330const IGNORE = {
24331 __symbolic: 'ignore'
24332};
24333const USE_VALUE$1 = 'useValue';
24334const PROVIDE = 'provide';
24335const REFERENCE_SET = new Set([USE_VALUE$1, 'useFactory', 'data', 'id', 'loadChildren']);
24336const TYPEGUARD_POSTFIX = 'TypeGuard';
24337const USE_IF = 'UseIf';
24338function shouldIgnore(value) {
24339 return value && value.__symbolic == 'ignore';
24340}
24341/**
24342 * A static reflector implements enough of the Reflector API that is necessary to compile
24343 * templates statically.
24344 */
24345class StaticReflector {
24346 constructor(summaryResolver, symbolResolver, knownMetadataClasses = [], knownMetadataFunctions = [], errorRecorder) {
24347 this.summaryResolver = summaryResolver;
24348 this.symbolResolver = symbolResolver;
24349 this.errorRecorder = errorRecorder;
24350 this.annotationCache = new Map();
24351 this.shallowAnnotationCache = new Map();
24352 this.propertyCache = new Map();
24353 this.parameterCache = new Map();
24354 this.methodCache = new Map();
24355 this.staticCache = new Map();
24356 this.conversionMap = new Map();
24357 this.resolvedExternalReferences = new Map();
24358 this.annotationForParentClassWithSummaryKind = new Map();
24359 this.initializeConversionMap();
24360 knownMetadataClasses.forEach((kc) => this._registerDecoratorOrConstructor(this.getStaticSymbol(kc.filePath, kc.name), kc.ctor));
24361 knownMetadataFunctions.forEach((kf) => this._registerFunction(this.getStaticSymbol(kf.filePath, kf.name), kf.fn));
24362 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Directive, [createDirective, createComponent]);
24363 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Pipe, [createPipe]);
24364 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.NgModule, [createNgModule]);
24365 this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Injectable, [createInjectable, createPipe, createDirective, createComponent, createNgModule]);
24366 }
24367 componentModuleUrl(typeOrFunc) {
24368 const staticSymbol = this.findSymbolDeclaration(typeOrFunc);
24369 return this.symbolResolver.getResourcePath(staticSymbol);
24370 }
24371 resolveExternalReference(ref, containingFile) {
24372 let key = undefined;
24373 if (!containingFile) {
24374 key = `${ref.moduleName}:${ref.name}`;
24375 const declarationSymbol = this.resolvedExternalReferences.get(key);
24376 if (declarationSymbol)
24377 return declarationSymbol;
24378 }
24379 const refSymbol = this.symbolResolver.getSymbolByModule(ref.moduleName, ref.name, containingFile);
24380 const declarationSymbol = this.findSymbolDeclaration(refSymbol);
24381 if (!containingFile) {
24382 this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName);
24383 this.symbolResolver.recordImportAs(declarationSymbol, refSymbol);
24384 }
24385 if (key) {
24386 this.resolvedExternalReferences.set(key, declarationSymbol);
24387 }
24388 return declarationSymbol;
24389 }
24390 findDeclaration(moduleUrl, name, containingFile) {
24391 return this.findSymbolDeclaration(this.symbolResolver.getSymbolByModule(moduleUrl, name, containingFile));
24392 }
24393 tryFindDeclaration(moduleUrl, name, containingFile) {
24394 return this.symbolResolver.ignoreErrorsFor(() => this.findDeclaration(moduleUrl, name, containingFile));
24395 }
24396 findSymbolDeclaration(symbol) {
24397 const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
24398 if (resolvedSymbol) {
24399 let resolvedMetadata = resolvedSymbol.metadata;
24400 if (resolvedMetadata && resolvedMetadata.__symbolic === 'resolved') {
24401 resolvedMetadata = resolvedMetadata.symbol;
24402 }
24403 if (resolvedMetadata instanceof StaticSymbol) {
24404 return this.findSymbolDeclaration(resolvedSymbol.metadata);
24405 }
24406 }
24407 return symbol;
24408 }
24409 tryAnnotations(type) {
24410 const originalRecorder = this.errorRecorder;
24411 this.errorRecorder = (error, fileName) => { };
24412 try {
24413 return this.annotations(type);
24414 }
24415 finally {
24416 this.errorRecorder = originalRecorder;
24417 }
24418 }
24419 annotations(type) {
24420 return this._annotations(type, (type, decorators) => this.simplify(type, decorators), this.annotationCache);
24421 }
24422 shallowAnnotations(type) {
24423 return this._annotations(type, (type, decorators) => this.simplify(type, decorators, true), this.shallowAnnotationCache);
24424 }
24425 _annotations(type, simplify, annotationCache) {
24426 let annotations = annotationCache.get(type);
24427 if (!annotations) {
24428 annotations = [];
24429 const classMetadata = this.getTypeMetadata(type);
24430 const parentType = this.findParentType(type, classMetadata);
24431 if (parentType) {
24432 const parentAnnotations = this.annotations(parentType);
24433 annotations.push(...parentAnnotations);
24434 }
24435 let ownAnnotations = [];
24436 if (classMetadata['decorators']) {
24437 ownAnnotations = simplify(type, classMetadata['decorators']);
24438 if (ownAnnotations) {
24439 annotations.push(...ownAnnotations);
24440 }
24441 }
24442 if (parentType && !this.summaryResolver.isLibraryFile(type.filePath) &&
24443 this.summaryResolver.isLibraryFile(parentType.filePath)) {
24444 const summary = this.summaryResolver.resolveSummary(parentType);
24445 if (summary && summary.type) {
24446 const requiredAnnotationTypes = this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind);
24447 const typeHasRequiredAnnotation = requiredAnnotationTypes.some((requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
24448 if (!typeHasRequiredAnnotation) {
24449 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`,
24450 /* summary */ undefined, `Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName).join(' or ')} decorator to the class`), type), type);
24451 }
24452 }
24453 }
24454 annotationCache.set(type, annotations.filter(ann => !!ann));
24455 }
24456 return annotations;
24457 }
24458 propMetadata(type) {
24459 let propMetadata = this.propertyCache.get(type);
24460 if (!propMetadata) {
24461 const classMetadata = this.getTypeMetadata(type);
24462 propMetadata = {};
24463 const parentType = this.findParentType(type, classMetadata);
24464 if (parentType) {
24465 const parentPropMetadata = this.propMetadata(parentType);
24466 Object.keys(parentPropMetadata).forEach((parentProp) => {
24467 propMetadata[parentProp] = parentPropMetadata[parentProp];
24468 });
24469 }
24470 const members = classMetadata['members'] || {};
24471 Object.keys(members).forEach((propName) => {
24472 const propData = members[propName];
24473 const prop = propData
24474 .find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method');
24475 const decorators = [];
24476 if (propMetadata[propName]) {
24477 decorators.push(...propMetadata[propName]);
24478 }
24479 propMetadata[propName] = decorators;
24480 if (prop && prop['decorators']) {
24481 decorators.push(...this.simplify(type, prop['decorators']));
24482 }
24483 });
24484 this.propertyCache.set(type, propMetadata);
24485 }
24486 return propMetadata;
24487 }
24488 parameters(type) {
24489 if (!(type instanceof StaticSymbol)) {
24490 this.reportError(new Error(`parameters received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
24491 return [];
24492 }
24493 try {
24494 let parameters = this.parameterCache.get(type);
24495 if (!parameters) {
24496 const classMetadata = this.getTypeMetadata(type);
24497 const parentType = this.findParentType(type, classMetadata);
24498 const members = classMetadata ? classMetadata['members'] : null;
24499 const ctorData = members ? members['__ctor__'] : null;
24500 if (ctorData) {
24501 const ctor = ctorData.find(a => a['__symbolic'] == 'constructor');
24502 const rawParameterTypes = ctor['parameters'] || [];
24503 const parameterDecorators = this.simplify(type, ctor['parameterDecorators'] || []);
24504 parameters = [];
24505 rawParameterTypes.forEach((rawParamType, index) => {
24506 const nestedResult = [];
24507 const paramType = this.trySimplify(type, rawParamType);
24508 if (paramType)
24509 nestedResult.push(paramType);
24510 const decorators = parameterDecorators ? parameterDecorators[index] : null;
24511 if (decorators) {
24512 nestedResult.push(...decorators);
24513 }
24514 parameters.push(nestedResult);
24515 });
24516 }
24517 else if (parentType) {
24518 parameters = this.parameters(parentType);
24519 }
24520 if (!parameters) {
24521 parameters = [];
24522 }
24523 this.parameterCache.set(type, parameters);
24524 }
24525 return parameters;
24526 }
24527 catch (e) {
24528 console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
24529 throw e;
24530 }
24531 }
24532 _methodNames(type) {
24533 let methodNames = this.methodCache.get(type);
24534 if (!methodNames) {
24535 const classMetadata = this.getTypeMetadata(type);
24536 methodNames = {};
24537 const parentType = this.findParentType(type, classMetadata);
24538 if (parentType) {
24539 const parentMethodNames = this._methodNames(parentType);
24540 Object.keys(parentMethodNames).forEach((parentProp) => {
24541 methodNames[parentProp] = parentMethodNames[parentProp];
24542 });
24543 }
24544 const members = classMetadata['members'] || {};
24545 Object.keys(members).forEach((propName) => {
24546 const propData = members[propName];
24547 const isMethod = propData.some(a => a['__symbolic'] == 'method');
24548 methodNames[propName] = methodNames[propName] || isMethod;
24549 });
24550 this.methodCache.set(type, methodNames);
24551 }
24552 return methodNames;
24553 }
24554 _staticMembers(type) {
24555 let staticMembers = this.staticCache.get(type);
24556 if (!staticMembers) {
24557 const classMetadata = this.getTypeMetadata(type);
24558 const staticMemberData = classMetadata['statics'] || {};
24559 staticMembers = Object.keys(staticMemberData);
24560 this.staticCache.set(type, staticMembers);
24561 }
24562 return staticMembers;
24563 }
24564 findParentType(type, classMetadata) {
24565 const parentType = this.trySimplify(type, classMetadata['extends']);
24566 if (parentType instanceof StaticSymbol) {
24567 return parentType;
24568 }
24569 }
24570 hasLifecycleHook(type, lcProperty) {
24571 if (!(type instanceof StaticSymbol)) {
24572 this.reportError(new Error(`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
24573 }
24574 try {
24575 return !!this._methodNames(type)[lcProperty];
24576 }
24577 catch (e) {
24578 console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
24579 throw e;
24580 }
24581 }
24582 guards(type) {
24583 if (!(type instanceof StaticSymbol)) {
24584 this.reportError(new Error(`guards received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
24585 return {};
24586 }
24587 const staticMembers = this._staticMembers(type);
24588 const result = {};
24589 for (let name of staticMembers) {
24590 if (name.endsWith(TYPEGUARD_POSTFIX)) {
24591 let property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
24592 let value;
24593 if (property.endsWith(USE_IF)) {
24594 property = name.substr(0, property.length - USE_IF.length);
24595 value = USE_IF;
24596 }
24597 else {
24598 value = this.getStaticSymbol(type.filePath, type.name, [name]);
24599 }
24600 result[property] = value;
24601 }
24602 }
24603 return result;
24604 }
24605 _registerDecoratorOrConstructor(type, ctor) {
24606 this.conversionMap.set(type, (context, args) => new ctor(...args));
24607 }
24608 _registerFunction(type, fn) {
24609 this.conversionMap.set(type, (context, args) => fn.apply(undefined, args));
24610 }
24611 initializeConversionMap() {
24612 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Injectable'), createInjectable);
24613 this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');
24614 this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');
24615 this.ROUTES = this.tryFindDeclaration(ANGULAR_ROUTER, 'ROUTES');
24616 this.ANALYZE_FOR_ENTRY_COMPONENTS =
24617 this.findDeclaration(ANGULAR_CORE, 'ANALYZE_FOR_ENTRY_COMPONENTS');
24618 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
24619 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
24620 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
24621 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Inject'), createInject);
24622 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
24623 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Attribute'), createAttribute);
24624 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChild'), createContentChild);
24625 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), createContentChildren);
24626 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChild'), createViewChild);
24627 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), createViewChildren);
24628 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), createInput);
24629 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Output'), createOutput);
24630 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), createPipe);
24631 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostBinding'), createHostBinding);
24632 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostListener'), createHostListener);
24633 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Directive'), createDirective);
24634 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Component'), createComponent);
24635 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'NgModule'), createNgModule);
24636 // Note: Some metadata classes can be used directly with Provider.deps.
24637 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
24638 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
24639 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
24640 this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
24641 }
24642 /**
24643 * getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
24644 * All types passed to the StaticResolver should be pseudo-types returned by this method.
24645 *
24646 * @param declarationFile the absolute path of the file where the symbol is declared
24647 * @param name the name of the type.
24648 */
24649 getStaticSymbol(declarationFile, name, members) {
24650 return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
24651 }
24652 /**
24653 * Simplify but discard any errors
24654 */
24655 trySimplify(context, value) {
24656 const originalRecorder = this.errorRecorder;
24657 this.errorRecorder = (error, fileName) => { };
24658 const result = this.simplify(context, value);
24659 this.errorRecorder = originalRecorder;
24660 return result;
24661 }
24662 /** @internal */
24663 simplify(context, value, lazy = false) {
24664 const self = this;
24665 let scope = BindingScope$1.empty;
24666 const calling = new Map();
24667 const rootContext = context;
24668 function simplifyInContext(context, value, depth, references) {
24669 function resolveReferenceValue(staticSymbol) {
24670 const resolvedSymbol = self.symbolResolver.resolveSymbol(staticSymbol);
24671 return resolvedSymbol ? resolvedSymbol.metadata : null;
24672 }
24673 function simplifyEagerly(value) {
24674 return simplifyInContext(context, value, depth, 0);
24675 }
24676 function simplifyLazily(value) {
24677 return simplifyInContext(context, value, depth, references + 1);
24678 }
24679 function simplifyNested(nestedContext, value) {
24680 if (nestedContext === context) {
24681 // If the context hasn't changed let the exception propagate unmodified.
24682 return simplifyInContext(nestedContext, value, depth + 1, references);
24683 }
24684 try {
24685 return simplifyInContext(nestedContext, value, depth + 1, references);
24686 }
24687 catch (e) {
24688 if (isMetadataError(e)) {
24689 // Propagate the message text up but add a message to the chain that explains how we got
24690 // here.
24691 // e.chain implies e.symbol
24692 const summaryMsg = e.chain ? 'references \'' + e.symbol.name + '\'' : errorSummary(e);
24693 const summary = `'${nestedContext.name}' ${summaryMsg}`;
24694 const chain = { message: summary, position: e.position, next: e.chain };
24695 // TODO(chuckj): retrieve the position information indirectly from the collectors node
24696 // map if the metadata is from a .ts file.
24697 self.error({
24698 message: e.message,
24699 advise: e.advise,
24700 context: e.context, chain,
24701 symbol: nestedContext
24702 }, context);
24703 }
24704 else {
24705 // It is probably an internal error.
24706 throw e;
24707 }
24708 }
24709 }
24710 function simplifyCall(functionSymbol, targetFunction, args, targetExpression) {
24711 if (targetFunction && targetFunction['__symbolic'] == 'function') {
24712 if (calling.get(functionSymbol)) {
24713 self.error({
24714 message: 'Recursion is not supported',
24715 summary: `called '${functionSymbol.name}' recursively`,
24716 value: targetFunction
24717 }, functionSymbol);
24718 }
24719 try {
24720 const value = targetFunction['value'];
24721 if (value && (depth != 0 || value.__symbolic != 'error')) {
24722 const parameters = targetFunction['parameters'];
24723 const defaults = targetFunction.defaults;
24724 args = args.map(arg => simplifyNested(context, arg))
24725 .map(arg => shouldIgnore(arg) ? undefined : arg);
24726 if (defaults && defaults.length > args.length) {
24727 args.push(...defaults.slice(args.length).map((value) => simplify(value)));
24728 }
24729 calling.set(functionSymbol, true);
24730 const functionScope = BindingScope$1.build();
24731 for (let i = 0; i < parameters.length; i++) {
24732 functionScope.define(parameters[i], args[i]);
24733 }
24734 const oldScope = scope;
24735 let result;
24736 try {
24737 scope = functionScope.done();
24738 result = simplifyNested(functionSymbol, value);
24739 }
24740 finally {
24741 scope = oldScope;
24742 }
24743 return result;
24744 }
24745 }
24746 finally {
24747 calling.delete(functionSymbol);
24748 }
24749 }
24750 if (depth === 0) {
24751 // If depth is 0 we are evaluating the top level expression that is describing element
24752 // decorator. In this case, it is a decorator we don't understand, such as a custom
24753 // non-angular decorator, and we should just ignore it.
24754 return IGNORE;
24755 }
24756 let position = undefined;
24757 if (targetExpression && targetExpression.__symbolic == 'resolved') {
24758 const line = targetExpression.line;
24759 const character = targetExpression.character;
24760 const fileName = targetExpression.fileName;
24761 if (fileName != null && line != null && character != null) {
24762 position = { fileName, line, column: character };
24763 }
24764 }
24765 self.error({
24766 message: FUNCTION_CALL_NOT_SUPPORTED,
24767 context: functionSymbol,
24768 value: targetFunction, position
24769 }, context);
24770 }
24771 function simplify(expression) {
24772 if (isPrimitive(expression)) {
24773 return expression;
24774 }
24775 if (expression instanceof Array) {
24776 const result = [];
24777 for (const item of expression) {
24778 // Check for a spread expression
24779 if (item && item.__symbolic === 'spread') {
24780 // We call with references as 0 because we require the actual value and cannot
24781 // tolerate a reference here.
24782 const spreadArray = simplifyEagerly(item.expression);
24783 if (Array.isArray(spreadArray)) {
24784 for (const spreadItem of spreadArray) {
24785 result.push(spreadItem);
24786 }
24787 continue;
24788 }
24789 }
24790 const value = simplify(item);
24791 if (shouldIgnore(value)) {
24792 continue;
24793 }
24794 result.push(value);
24795 }
24796 return result;
24797 }
24798 if (expression instanceof StaticSymbol) {
24799 // Stop simplification at builtin symbols or if we are in a reference context and
24800 // the symbol doesn't have members.
24801 if (expression === self.injectionToken || self.conversionMap.has(expression) ||
24802 (references > 0 && !expression.members.length)) {
24803 return expression;
24804 }
24805 else {
24806 const staticSymbol = expression;
24807 const declarationValue = resolveReferenceValue(staticSymbol);
24808 if (declarationValue != null) {
24809 return simplifyNested(staticSymbol, declarationValue);
24810 }
24811 else {
24812 return staticSymbol;
24813 }
24814 }
24815 }
24816 if (expression) {
24817 if (expression['__symbolic']) {
24818 let staticSymbol;
24819 switch (expression['__symbolic']) {
24820 case 'binop':
24821 let left = simplify(expression['left']);
24822 if (shouldIgnore(left))
24823 return left;
24824 let right = simplify(expression['right']);
24825 if (shouldIgnore(right))
24826 return right;
24827 switch (expression['operator']) {
24828 case '&&':
24829 return left && right;
24830 case '||':
24831 return left || right;
24832 case '|':
24833 return left | right;
24834 case '^':
24835 return left ^ right;
24836 case '&':
24837 return left & right;
24838 case '==':
24839 return left == right;
24840 case '!=':
24841 return left != right;
24842 case '===':
24843 return left === right;
24844 case '!==':
24845 return left !== right;
24846 case '<':
24847 return left < right;
24848 case '>':
24849 return left > right;
24850 case '<=':
24851 return left <= right;
24852 case '>=':
24853 return left >= right;
24854 case '<<':
24855 return left << right;
24856 case '>>':
24857 return left >> right;
24858 case '+':
24859 return left + right;
24860 case '-':
24861 return left - right;
24862 case '*':
24863 return left * right;
24864 case '/':
24865 return left / right;
24866 case '%':
24867 return left % right;
24868 }
24869 return null;
24870 case 'if':
24871 let condition = simplify(expression['condition']);
24872 return condition ? simplify(expression['thenExpression']) :
24873 simplify(expression['elseExpression']);
24874 case 'pre':
24875 let operand = simplify(expression['operand']);
24876 if (shouldIgnore(operand))
24877 return operand;
24878 switch (expression['operator']) {
24879 case '+':
24880 return operand;
24881 case '-':
24882 return -operand;
24883 case '!':
24884 return !operand;
24885 case '~':
24886 return ~operand;
24887 }
24888 return null;
24889 case 'index':
24890 let indexTarget = simplifyEagerly(expression['expression']);
24891 let index = simplifyEagerly(expression['index']);
24892 if (indexTarget && isPrimitive(index))
24893 return indexTarget[index];
24894 return null;
24895 case 'select':
24896 const member = expression['member'];
24897 let selectContext = context;
24898 let selectTarget = simplify(expression['expression']);
24899 if (selectTarget instanceof StaticSymbol) {
24900 const members = selectTarget.members.concat(member);
24901 selectContext =
24902 self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
24903 const declarationValue = resolveReferenceValue(selectContext);
24904 if (declarationValue != null) {
24905 return simplifyNested(selectContext, declarationValue);
24906 }
24907 else {
24908 return selectContext;
24909 }
24910 }
24911 if (selectTarget && isPrimitive(member))
24912 return simplifyNested(selectContext, selectTarget[member]);
24913 return null;
24914 case 'reference':
24915 // Note: This only has to deal with variable references, as symbol references have
24916 // been converted into 'resolved'
24917 // in the StaticSymbolResolver.
24918 const name = expression['name'];
24919 const localValue = scope.resolve(name);
24920 if (localValue != BindingScope$1.missing) {
24921 return localValue;
24922 }
24923 break;
24924 case 'resolved':
24925 try {
24926 return simplify(expression.symbol);
24927 }
24928 catch (e) {
24929 // If an error is reported evaluating the symbol record the position of the
24930 // reference in the error so it can
24931 // be reported in the error message generated from the exception.
24932 if (isMetadataError(e) && expression.fileName != null &&
24933 expression.line != null && expression.character != null) {
24934 e.position = {
24935 fileName: expression.fileName,
24936 line: expression.line,
24937 column: expression.character
24938 };
24939 }
24940 throw e;
24941 }
24942 case 'class':
24943 return context;
24944 case 'function':
24945 return context;
24946 case 'new':
24947 case 'call':
24948 // Determine if the function is a built-in conversion
24949 staticSymbol = simplifyInContext(context, expression['expression'], depth + 1, /* references */ 0);
24950 if (staticSymbol instanceof StaticSymbol) {
24951 if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {
24952 // if somebody calls new InjectionToken, don't create an InjectionToken,
24953 // but rather return the symbol to which the InjectionToken is assigned to.
24954 // OpaqueToken is supported too as it is required by the language service to
24955 // support v4 and prior versions of Angular.
24956 return context;
24957 }
24958 const argExpressions = expression['arguments'] || [];
24959 let converter = self.conversionMap.get(staticSymbol);
24960 if (converter) {
24961 const args = argExpressions.map(arg => simplifyNested(context, arg))
24962 .map(arg => shouldIgnore(arg) ? undefined : arg);
24963 return converter(context, args);
24964 }
24965 else {
24966 // Determine if the function is one we can simplify.
24967 const targetFunction = resolveReferenceValue(staticSymbol);
24968 return simplifyCall(staticSymbol, targetFunction, argExpressions, expression['expression']);
24969 }
24970 }
24971 return IGNORE;
24972 case 'error':
24973 let message = expression.message;
24974 if (expression['line'] != null) {
24975 self.error({
24976 message,
24977 context: expression.context,
24978 value: expression,
24979 position: {
24980 fileName: expression['fileName'],
24981 line: expression['line'],
24982 column: expression['character']
24983 }
24984 }, context);
24985 }
24986 else {
24987 self.error({ message, context: expression.context }, context);
24988 }
24989 return IGNORE;
24990 case 'ignore':
24991 return expression;
24992 }
24993 return null;
24994 }
24995 return mapStringMap(expression, (value, name) => {
24996 if (REFERENCE_SET.has(name)) {
24997 if (name === USE_VALUE$1 && PROVIDE in expression) {
24998 // If this is a provider expression, check for special tokens that need the value
24999 // during analysis.
25000 const provide = simplify(expression.provide);
25001 if (provide === self.ROUTES || provide == self.ANALYZE_FOR_ENTRY_COMPONENTS) {
25002 return simplify(value);
25003 }
25004 }
25005 return simplifyLazily(value);
25006 }
25007 return simplify(value);
25008 });
25009 }
25010 return IGNORE;
25011 }
25012 return simplify(value);
25013 }
25014 let result;
25015 try {
25016 result = simplifyInContext(context, value, 0, lazy ? 1 : 0);
25017 }
25018 catch (e) {
25019 if (this.errorRecorder) {
25020 this.reportError(e, context);
25021 }
25022 else {
25023 throw formatMetadataError(e, context);
25024 }
25025 }
25026 if (shouldIgnore(result)) {
25027 return undefined;
25028 }
25029 return result;
25030 }
25031 getTypeMetadata(type) {
25032 const resolvedSymbol = this.symbolResolver.resolveSymbol(type);
25033 return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
25034 { __symbolic: 'class' };
25035 }
25036 reportError(error, context, path) {
25037 if (this.errorRecorder) {
25038 this.errorRecorder(formatMetadataError(error, context), (context && context.filePath) || path);
25039 }
25040 else {
25041 throw error;
25042 }
25043 }
25044 error({ message, summary, advise, position, context, value, symbol, chain }, reportingContext) {
25045 this.reportError(metadataError(message, summary, advise, position, symbol, context, chain), reportingContext);
25046 }
25047}
25048const METADATA_ERROR = 'ngMetadataError';
25049function metadataError(message, summary, advise, position, symbol, context, chain) {
25050 const error = syntaxError(message);
25051 error[METADATA_ERROR] = true;
25052 if (advise)
25053 error.advise = advise;
25054 if (position)
25055 error.position = position;
25056 if (summary)
25057 error.summary = summary;
25058 if (context)
25059 error.context = context;
25060 if (chain)
25061 error.chain = chain;
25062 if (symbol)
25063 error.symbol = symbol;
25064 return error;
25065}
25066function isMetadataError(error) {
25067 return !!error[METADATA_ERROR];
25068}
25069const REFERENCE_TO_NONEXPORTED_CLASS = 'Reference to non-exported class';
25070const VARIABLE_NOT_INITIALIZED = 'Variable not initialized';
25071const DESTRUCTURE_NOT_SUPPORTED = 'Destructuring not supported';
25072const COULD_NOT_RESOLVE_TYPE = 'Could not resolve type';
25073const FUNCTION_CALL_NOT_SUPPORTED = 'Function call not supported';
25074const REFERENCE_TO_LOCAL_SYMBOL = 'Reference to a local symbol';
25075const LAMBDA_NOT_SUPPORTED = 'Lambda not supported';
25076function expandedMessage(message, context) {
25077 switch (message) {
25078 case REFERENCE_TO_NONEXPORTED_CLASS:
25079 if (context && context.className) {
25080 return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`;
25081 }
25082 break;
25083 case VARIABLE_NOT_INITIALIZED:
25084 return 'Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler';
25085 case DESTRUCTURE_NOT_SUPPORTED:
25086 return 'Referencing an exported destructured variable or constant is not supported in decorators and this value is needed by the template compiler';
25087 case COULD_NOT_RESOLVE_TYPE:
25088 if (context && context.typeName) {
25089 return `Could not resolve type ${context.typeName}`;
25090 }
25091 break;
25092 case FUNCTION_CALL_NOT_SUPPORTED:
25093 if (context && context.name) {
25094 return `Function calls are not supported in decorators but '${context.name}' was called`;
25095 }
25096 return 'Function calls are not supported in decorators';
25097 case REFERENCE_TO_LOCAL_SYMBOL:
25098 if (context && context.name) {
25099 return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`;
25100 }
25101 break;
25102 case LAMBDA_NOT_SUPPORTED:
25103 return `Function expressions are not supported in decorators`;
25104 }
25105 return message;
25106}
25107function messageAdvise(message, context) {
25108 switch (message) {
25109 case REFERENCE_TO_NONEXPORTED_CLASS:
25110 if (context && context.className) {
25111 return `Consider exporting '${context.className}'`;
25112 }
25113 break;
25114 case DESTRUCTURE_NOT_SUPPORTED:
25115 return 'Consider simplifying to avoid destructuring';
25116 case REFERENCE_TO_LOCAL_SYMBOL:
25117 if (context && context.name) {
25118 return `Consider exporting '${context.name}'`;
25119 }
25120 break;
25121 case LAMBDA_NOT_SUPPORTED:
25122 return `Consider changing the function expression into an exported function`;
25123 }
25124 return undefined;
25125}
25126function errorSummary(error) {
25127 if (error.summary) {
25128 return error.summary;
25129 }
25130 switch (error.message) {
25131 case REFERENCE_TO_NONEXPORTED_CLASS:
25132 if (error.context && error.context.className) {
25133 return `references non-exported class ${error.context.className}`;
25134 }
25135 break;
25136 case VARIABLE_NOT_INITIALIZED:
25137 return 'is not initialized';
25138 case DESTRUCTURE_NOT_SUPPORTED:
25139 return 'is a destructured variable';
25140 case COULD_NOT_RESOLVE_TYPE:
25141 return 'could not be resolved';
25142 case FUNCTION_CALL_NOT_SUPPORTED:
25143 if (error.context && error.context.name) {
25144 return `calls '${error.context.name}'`;
25145 }
25146 return `calls a function`;
25147 case REFERENCE_TO_LOCAL_SYMBOL:
25148 if (error.context && error.context.name) {
25149 return `references local variable ${error.context.name}`;
25150 }
25151 return `references a local variable`;
25152 }
25153 return 'contains the error';
25154}
25155function mapStringMap(input, transform) {
25156 if (!input)
25157 return {};
25158 const result = {};
25159 Object.keys(input).forEach((key) => {
25160 const value = transform(input[key], key);
25161 if (!shouldIgnore(value)) {
25162 if (HIDDEN_KEY.test(key)) {
25163 Object.defineProperty(result, key, { enumerable: false, configurable: true, value: value });
25164 }
25165 else {
25166 result[key] = value;
25167 }
25168 }
25169 });
25170 return result;
25171}
25172function isPrimitive(o) {
25173 return o === null || (typeof o !== 'function' && typeof o !== 'object');
25174}
25175class BindingScope$1 {
25176 static build() {
25177 const current = new Map();
25178 return {
25179 define: function (name, value) {
25180 current.set(name, value);
25181 return this;
25182 },
25183 done: function () {
25184 return current.size > 0 ? new PopulatedScope(current) : BindingScope$1.empty;
25185 }
25186 };
25187 }
25188}
25189BindingScope$1.missing = {};
25190BindingScope$1.empty = { resolve: name => BindingScope$1.missing };
25191class PopulatedScope extends BindingScope$1 {
25192 constructor(bindings) {
25193 super();
25194 this.bindings = bindings;
25195 }
25196 resolve(name) {
25197 return this.bindings.has(name) ? this.bindings.get(name) : BindingScope$1.missing;
25198 }
25199}
25200function formatMetadataMessageChain(chain, advise) {
25201 const expanded = expandedMessage(chain.message, chain.context);
25202 const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : '';
25203 const message = `${expanded}${nesting}`;
25204 const position = chain.position;
25205 const next = chain.next ?
25206 formatMetadataMessageChain(chain.next, advise) :
25207 advise ? { message: advise } : undefined;
25208 return { message, position, next };
25209}
25210function formatMetadataError(e, context) {
25211 if (isMetadataError(e)) {
25212 // Produce a formatted version of the and leaving enough information in the original error
25213 // to recover the formatting information to eventually produce a diagnostic error message.
25214 const position = e.position;
25215 const chain = {
25216 message: `Error during template compile of '${context.name}'`,
25217 position: position,
25218 next: { message: e.message, next: e.chain, context: e.context, symbol: e.symbol }
25219 };
25220 const advise = e.advise || messageAdvise(e.message, e.context);
25221 return formattedError(formatMetadataMessageChain(chain, advise));
25222 }
25223 return e;
25224}
25225
25226/**
25227 * @license
25228 * Copyright Google Inc. All Rights Reserved.
25229 *
25230 * Use of this source code is governed by an MIT-style license that can be
25231 * found in the LICENSE file at https://angular.io/license
25232 */
25233class AotSummaryResolver {
25234 constructor(host, staticSymbolCache) {
25235 this.host = host;
25236 this.staticSymbolCache = staticSymbolCache;
25237 // Note: this will only contain StaticSymbols without members!
25238 this.summaryCache = new Map();
25239 this.loadedFilePaths = new Map();
25240 // Note: this will only contain StaticSymbols without members!
25241 this.importAs = new Map();
25242 this.knownFileNameToModuleNames = new Map();
25243 }
25244 isLibraryFile(filePath) {
25245 // Note: We need to strip the .ngfactory. file path,
25246 // so this method also works for generated files
25247 // (for which host.isSourceFile will always return false).
25248 return !this.host.isSourceFile(stripGeneratedFileSuffix(filePath));
25249 }
25250 toSummaryFileName(filePath, referringSrcFileName) {
25251 return this.host.toSummaryFileName(filePath, referringSrcFileName);
25252 }
25253 fromSummaryFileName(fileName, referringLibFileName) {
25254 return this.host.fromSummaryFileName(fileName, referringLibFileName);
25255 }
25256 resolveSummary(staticSymbol) {
25257 const rootSymbol = staticSymbol.members.length ?
25258 this.staticSymbolCache.get(staticSymbol.filePath, staticSymbol.name) :
25259 staticSymbol;
25260 let summary = this.summaryCache.get(rootSymbol);
25261 if (!summary) {
25262 this._loadSummaryFile(staticSymbol.filePath);
25263 summary = this.summaryCache.get(staticSymbol);
25264 }
25265 return (rootSymbol === staticSymbol && summary) || null;
25266 }
25267 getSymbolsOf(filePath) {
25268 if (this._loadSummaryFile(filePath)) {
25269 return Array.from(this.summaryCache.keys()).filter((symbol) => symbol.filePath === filePath);
25270 }
25271 return null;
25272 }
25273 getImportAs(staticSymbol) {
25274 staticSymbol.assertNoMembers();
25275 return this.importAs.get(staticSymbol);
25276 }
25277 /**
25278 * Converts a file path to a module name that can be used as an `import`.
25279 */
25280 getKnownModuleName(importedFilePath) {
25281 return this.knownFileNameToModuleNames.get(importedFilePath) || null;
25282 }
25283 addSummary(summary) { this.summaryCache.set(summary.symbol, summary); }
25284 _loadSummaryFile(filePath) {
25285 let hasSummary = this.loadedFilePaths.get(filePath);
25286 if (hasSummary != null) {
25287 return hasSummary;
25288 }
25289 let json = null;
25290 if (this.isLibraryFile(filePath)) {
25291 const summaryFilePath = summaryFileName(filePath);
25292 try {
25293 json = this.host.loadSummary(summaryFilePath);
25294 }
25295 catch (e) {
25296 console.error(`Error loading summary file ${summaryFilePath}`);
25297 throw e;
25298 }
25299 }
25300 hasSummary = json != null;
25301 this.loadedFilePaths.set(filePath, hasSummary);
25302 if (json) {
25303 const { moduleName, summaries, importAs } = deserializeSummaries(this.staticSymbolCache, this, filePath, json);
25304 summaries.forEach((summary) => this.summaryCache.set(summary.symbol, summary));
25305 if (moduleName) {
25306 this.knownFileNameToModuleNames.set(filePath, moduleName);
25307 }
25308 importAs.forEach((importAs) => { this.importAs.set(importAs.symbol, importAs.importAs); });
25309 }
25310 return hasSummary;
25311 }
25312}
25313
25314/**
25315 * @license
25316 * Copyright Google Inc. All Rights Reserved.
25317 *
25318 * Use of this source code is governed by an MIT-style license that can be
25319 * found in the LICENSE file at https://angular.io/license
25320 */
25321function createAotUrlResolver(host) {
25322 return {
25323 resolve: (basePath, url) => {
25324 const filePath = host.resourceNameToFileName(url, basePath);
25325 if (!filePath) {
25326 throw syntaxError(`Couldn't resolve resource ${url} from ${basePath}`);
25327 }
25328 return filePath;
25329 }
25330 };
25331}
25332/**
25333 * Creates a new AotCompiler based on options and a host.
25334 */
25335function createAotCompiler(compilerHost, options, errorCollector) {
25336 let translations = options.translations || '';
25337 const urlResolver = createAotUrlResolver(compilerHost);
25338 const symbolCache = new StaticSymbolCache();
25339 const summaryResolver = new AotSummaryResolver(compilerHost, symbolCache);
25340 const symbolResolver = new StaticSymbolResolver(compilerHost, symbolCache, summaryResolver);
25341 const staticReflector = new StaticReflector(summaryResolver, symbolResolver, [], [], errorCollector);
25342 let htmlParser;
25343 if (!!options.enableIvy) {
25344 // Ivy handles i18n at the compiler level so we must use a regular parser
25345 htmlParser = new HtmlParser();
25346 }
25347 else {
25348 htmlParser = new I18NHtmlParser(new HtmlParser(), translations, options.i18nFormat, options.missingTranslation, console);
25349 }
25350 const config = new CompilerConfig({
25351 defaultEncapsulation: ViewEncapsulation.Emulated,
25352 useJit: false,
25353 missingTranslation: options.missingTranslation,
25354 preserveWhitespaces: options.preserveWhitespaces,
25355 strictInjectionParameters: options.strictInjectionParameters,
25356 });
25357 const normalizer = new DirectiveNormalizer({ get: (url) => compilerHost.loadResource(url) }, urlResolver, htmlParser, config);
25358 const expressionParser = new Parser$1(new Lexer());
25359 const elementSchemaRegistry = new DomElementSchemaRegistry();
25360 const tmplParser = new TemplateParser(config, staticReflector, expressionParser, elementSchemaRegistry, htmlParser, console, []);
25361 const resolver = new CompileMetadataResolver(config, htmlParser, new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector), new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer, console, symbolCache, staticReflector, errorCollector);
25362 // TODO(vicb): do not pass options.i18nFormat here
25363 const viewCompiler = new ViewCompiler(staticReflector);
25364 const typeCheckCompiler = new TypeCheckCompiler(options, staticReflector);
25365 const compiler = new AotCompiler(config, options, compilerHost, staticReflector, resolver, tmplParser, new StyleCompiler(urlResolver), viewCompiler, typeCheckCompiler, new NgModuleCompiler(staticReflector), new InjectableCompiler(staticReflector, !!options.enableIvy), new TypeScriptEmitter(), summaryResolver, symbolResolver);
25366 return { compiler, reflector: staticReflector };
25367}
25368
25369class SummaryResolver {
25370}
25371class JitSummaryResolver {
25372 constructor() {
25373 this._summaries = new Map();
25374 }
25375 isLibraryFile() { return false; }
25376 toSummaryFileName(fileName) { return fileName; }
25377 fromSummaryFileName(fileName) { return fileName; }
25378 resolveSummary(reference) {
25379 return this._summaries.get(reference) || null;
25380 }
25381 getSymbolsOf() { return []; }
25382 getImportAs(reference) { return reference; }
25383 getKnownModuleName(fileName) { return null; }
25384 addSummary(summary) { this._summaries.set(summary.symbol, summary); }
25385}
25386
25387/**
25388 * @license
25389 * Copyright Google Inc. All Rights Reserved.
25390 *
25391 * Use of this source code is governed by an MIT-style license that can be
25392 * found in the LICENSE file at https://angular.io/license
25393 */
25394function interpretStatements(statements, reflector) {
25395 const ctx = new _ExecutionContext(null, null, null, new Map());
25396 const visitor = new StatementInterpreter(reflector);
25397 visitor.visitAllStatements(statements, ctx);
25398 const result = {};
25399 ctx.exports.forEach((exportName) => { result[exportName] = ctx.vars.get(exportName); });
25400 return result;
25401}
25402function _executeFunctionStatements(varNames, varValues, statements, ctx, visitor) {
25403 const childCtx = ctx.createChildWihtLocalVars();
25404 for (let i = 0; i < varNames.length; i++) {
25405 childCtx.vars.set(varNames[i], varValues[i]);
25406 }
25407 const result = visitor.visitAllStatements(statements, childCtx);
25408 return result ? result.value : null;
25409}
25410class _ExecutionContext {
25411 constructor(parent, instance, className, vars) {
25412 this.parent = parent;
25413 this.instance = instance;
25414 this.className = className;
25415 this.vars = vars;
25416 this.exports = [];
25417 }
25418 createChildWihtLocalVars() {
25419 return new _ExecutionContext(this, this.instance, this.className, new Map());
25420 }
25421}
25422class ReturnValue {
25423 constructor(value) {
25424 this.value = value;
25425 }
25426}
25427function createDynamicClass(_classStmt, _ctx, _visitor) {
25428 const propertyDescriptors = {};
25429 _classStmt.getters.forEach((getter) => {
25430 // Note: use `function` instead of arrow function to capture `this`
25431 propertyDescriptors[getter.name] = {
25432 configurable: false,
25433 get: function () {
25434 const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
25435 return _executeFunctionStatements([], [], getter.body, instanceCtx, _visitor);
25436 }
25437 };
25438 });
25439 _classStmt.methods.forEach(function (method) {
25440 const paramNames = method.params.map(param => param.name);
25441 // Note: use `function` instead of arrow function to capture `this`
25442 propertyDescriptors[method.name] = {
25443 writable: false,
25444 configurable: false,
25445 value: function (...args) {
25446 const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
25447 return _executeFunctionStatements(paramNames, args, method.body, instanceCtx, _visitor);
25448 }
25449 };
25450 });
25451 const ctorParamNames = _classStmt.constructorMethod.params.map(param => param.name);
25452 // Note: use `function` instead of arrow function to capture `this`
25453 const ctor = function (...args) {
25454 const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
25455 _classStmt.fields.forEach((field) => { this[field.name] = undefined; });
25456 _executeFunctionStatements(ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
25457 };
25458 const superClass = _classStmt.parent ? _classStmt.parent.visitExpression(_visitor, _ctx) : Object;
25459 ctor.prototype = Object.create(superClass.prototype, propertyDescriptors);
25460 return ctor;
25461}
25462class StatementInterpreter {
25463 constructor(reflector) {
25464 this.reflector = reflector;
25465 }
25466 debugAst(ast) { return debugOutputAstAsTypeScript(ast); }
25467 visitDeclareVarStmt(stmt, ctx) {
25468 const initialValue = stmt.value ? stmt.value.visitExpression(this, ctx) : undefined;
25469 ctx.vars.set(stmt.name, initialValue);
25470 if (stmt.hasModifier(StmtModifier.Exported)) {
25471 ctx.exports.push(stmt.name);
25472 }
25473 return null;
25474 }
25475 visitWriteVarExpr(expr, ctx) {
25476 const value = expr.value.visitExpression(this, ctx);
25477 let currCtx = ctx;
25478 while (currCtx != null) {
25479 if (currCtx.vars.has(expr.name)) {
25480 currCtx.vars.set(expr.name, value);
25481 return value;
25482 }
25483 currCtx = currCtx.parent;
25484 }
25485 throw new Error(`Not declared variable ${expr.name}`);
25486 }
25487 visitWrappedNodeExpr(ast, ctx) {
25488 throw new Error('Cannot interpret a WrappedNodeExpr.');
25489 }
25490 visitTypeofExpr(ast, ctx) {
25491 throw new Error('Cannot interpret a TypeofExpr');
25492 }
25493 visitReadVarExpr(ast, ctx) {
25494 let varName = ast.name;
25495 if (ast.builtin != null) {
25496 switch (ast.builtin) {
25497 case BuiltinVar.Super:
25498 return Object.getPrototypeOf(ctx.instance);
25499 case BuiltinVar.This:
25500 return ctx.instance;
25501 case BuiltinVar.CatchError:
25502 varName = CATCH_ERROR_VAR$2;
25503 break;
25504 case BuiltinVar.CatchStack:
25505 varName = CATCH_STACK_VAR$2;
25506 break;
25507 default:
25508 throw new Error(`Unknown builtin variable ${ast.builtin}`);
25509 }
25510 }
25511 let currCtx = ctx;
25512 while (currCtx != null) {
25513 if (currCtx.vars.has(varName)) {
25514 return currCtx.vars.get(varName);
25515 }
25516 currCtx = currCtx.parent;
25517 }
25518 throw new Error(`Not declared variable ${varName}`);
25519 }
25520 visitWriteKeyExpr(expr, ctx) {
25521 const receiver = expr.receiver.visitExpression(this, ctx);
25522 const index = expr.index.visitExpression(this, ctx);
25523 const value = expr.value.visitExpression(this, ctx);
25524 receiver[index] = value;
25525 return value;
25526 }
25527 visitWritePropExpr(expr, ctx) {
25528 const receiver = expr.receiver.visitExpression(this, ctx);
25529 const value = expr.value.visitExpression(this, ctx);
25530 receiver[expr.name] = value;
25531 return value;
25532 }
25533 visitInvokeMethodExpr(expr, ctx) {
25534 const receiver = expr.receiver.visitExpression(this, ctx);
25535 const args = this.visitAllExpressions(expr.args, ctx);
25536 let result;
25537 if (expr.builtin != null) {
25538 switch (expr.builtin) {
25539 case BuiltinMethod.ConcatArray:
25540 result = receiver.concat(...args);
25541 break;
25542 case BuiltinMethod.SubscribeObservable:
25543 result = receiver.subscribe({ next: args[0] });
25544 break;
25545 case BuiltinMethod.Bind:
25546 result = receiver.bind(...args);
25547 break;
25548 default:
25549 throw new Error(`Unknown builtin method ${expr.builtin}`);
25550 }
25551 }
25552 else {
25553 result = receiver[expr.name].apply(receiver, args);
25554 }
25555 return result;
25556 }
25557 visitInvokeFunctionExpr(stmt, ctx) {
25558 const args = this.visitAllExpressions(stmt.args, ctx);
25559 const fnExpr = stmt.fn;
25560 if (fnExpr instanceof ReadVarExpr && fnExpr.builtin === BuiltinVar.Super) {
25561 ctx.instance.constructor.prototype.constructor.apply(ctx.instance, args);
25562 return null;
25563 }
25564 else {
25565 const fn = stmt.fn.visitExpression(this, ctx);
25566 return fn.apply(null, args);
25567 }
25568 }
25569 visitReturnStmt(stmt, ctx) {
25570 return new ReturnValue(stmt.value.visitExpression(this, ctx));
25571 }
25572 visitDeclareClassStmt(stmt, ctx) {
25573 const clazz = createDynamicClass(stmt, ctx, this);
25574 ctx.vars.set(stmt.name, clazz);
25575 if (stmt.hasModifier(StmtModifier.Exported)) {
25576 ctx.exports.push(stmt.name);
25577 }
25578 return null;
25579 }
25580 visitExpressionStmt(stmt, ctx) {
25581 return stmt.expr.visitExpression(this, ctx);
25582 }
25583 visitIfStmt(stmt, ctx) {
25584 const condition = stmt.condition.visitExpression(this, ctx);
25585 if (condition) {
25586 return this.visitAllStatements(stmt.trueCase, ctx);
25587 }
25588 else if (stmt.falseCase != null) {
25589 return this.visitAllStatements(stmt.falseCase, ctx);
25590 }
25591 return null;
25592 }
25593 visitTryCatchStmt(stmt, ctx) {
25594 try {
25595 return this.visitAllStatements(stmt.bodyStmts, ctx);
25596 }
25597 catch (e) {
25598 const childCtx = ctx.createChildWihtLocalVars();
25599 childCtx.vars.set(CATCH_ERROR_VAR$2, e);
25600 childCtx.vars.set(CATCH_STACK_VAR$2, e.stack);
25601 return this.visitAllStatements(stmt.catchStmts, childCtx);
25602 }
25603 }
25604 visitThrowStmt(stmt, ctx) {
25605 throw stmt.error.visitExpression(this, ctx);
25606 }
25607 visitCommentStmt(stmt, context) { return null; }
25608 visitJSDocCommentStmt(stmt, context) { return null; }
25609 visitInstantiateExpr(ast, ctx) {
25610 const args = this.visitAllExpressions(ast.args, ctx);
25611 const clazz = ast.classExpr.visitExpression(this, ctx);
25612 return new clazz(...args);
25613 }
25614 visitLiteralExpr(ast, ctx) { return ast.value; }
25615 visitExternalExpr(ast, ctx) {
25616 return this.reflector.resolveExternalReference(ast.value);
25617 }
25618 visitConditionalExpr(ast, ctx) {
25619 if (ast.condition.visitExpression(this, ctx)) {
25620 return ast.trueCase.visitExpression(this, ctx);
25621 }
25622 else if (ast.falseCase != null) {
25623 return ast.falseCase.visitExpression(this, ctx);
25624 }
25625 return null;
25626 }
25627 visitNotExpr(ast, ctx) {
25628 return !ast.condition.visitExpression(this, ctx);
25629 }
25630 visitAssertNotNullExpr(ast, ctx) {
25631 return ast.condition.visitExpression(this, ctx);
25632 }
25633 visitCastExpr(ast, ctx) {
25634 return ast.value.visitExpression(this, ctx);
25635 }
25636 visitFunctionExpr(ast, ctx) {
25637 const paramNames = ast.params.map((param) => param.name);
25638 return _declareFn(paramNames, ast.statements, ctx, this);
25639 }
25640 visitDeclareFunctionStmt(stmt, ctx) {
25641 const paramNames = stmt.params.map((param) => param.name);
25642 ctx.vars.set(stmt.name, _declareFn(paramNames, stmt.statements, ctx, this));
25643 if (stmt.hasModifier(StmtModifier.Exported)) {
25644 ctx.exports.push(stmt.name);
25645 }
25646 return null;
25647 }
25648 visitBinaryOperatorExpr(ast, ctx) {
25649 const lhs = () => ast.lhs.visitExpression(this, ctx);
25650 const rhs = () => ast.rhs.visitExpression(this, ctx);
25651 switch (ast.operator) {
25652 case BinaryOperator.Equals:
25653 return lhs() == rhs();
25654 case BinaryOperator.Identical:
25655 return lhs() === rhs();
25656 case BinaryOperator.NotEquals:
25657 return lhs() != rhs();
25658 case BinaryOperator.NotIdentical:
25659 return lhs() !== rhs();
25660 case BinaryOperator.And:
25661 return lhs() && rhs();
25662 case BinaryOperator.Or:
25663 return lhs() || rhs();
25664 case BinaryOperator.Plus:
25665 return lhs() + rhs();
25666 case BinaryOperator.Minus:
25667 return lhs() - rhs();
25668 case BinaryOperator.Divide:
25669 return lhs() / rhs();
25670 case BinaryOperator.Multiply:
25671 return lhs() * rhs();
25672 case BinaryOperator.Modulo:
25673 return lhs() % rhs();
25674 case BinaryOperator.Lower:
25675 return lhs() < rhs();
25676 case BinaryOperator.LowerEquals:
25677 return lhs() <= rhs();
25678 case BinaryOperator.Bigger:
25679 return lhs() > rhs();
25680 case BinaryOperator.BiggerEquals:
25681 return lhs() >= rhs();
25682 default:
25683 throw new Error(`Unknown operator ${ast.operator}`);
25684 }
25685 }
25686 visitReadPropExpr(ast, ctx) {
25687 let result;
25688 const receiver = ast.receiver.visitExpression(this, ctx);
25689 result = receiver[ast.name];
25690 return result;
25691 }
25692 visitReadKeyExpr(ast, ctx) {
25693 const receiver = ast.receiver.visitExpression(this, ctx);
25694 const prop = ast.index.visitExpression(this, ctx);
25695 return receiver[prop];
25696 }
25697 visitLiteralArrayExpr(ast, ctx) {
25698 return this.visitAllExpressions(ast.entries, ctx);
25699 }
25700 visitLiteralMapExpr(ast, ctx) {
25701 const result = {};
25702 ast.entries.forEach(entry => result[entry.key] = entry.value.visitExpression(this, ctx));
25703 return result;
25704 }
25705 visitCommaExpr(ast, context) {
25706 const values = this.visitAllExpressions(ast.parts, context);
25707 return values[values.length - 1];
25708 }
25709 visitAllExpressions(expressions, ctx) {
25710 return expressions.map((expr) => expr.visitExpression(this, ctx));
25711 }
25712 visitAllStatements(statements, ctx) {
25713 for (let i = 0; i < statements.length; i++) {
25714 const stmt = statements[i];
25715 const val = stmt.visitStatement(this, ctx);
25716 if (val instanceof ReturnValue) {
25717 return val;
25718 }
25719 }
25720 return null;
25721 }
25722}
25723function _declareFn(varNames, statements, ctx, visitor) {
25724 return (...args) => _executeFunctionStatements(varNames, args, statements, ctx, visitor);
25725}
25726const CATCH_ERROR_VAR$2 = 'error';
25727const CATCH_STACK_VAR$2 = 'stack';
25728
25729/**
25730 * @license
25731 * Copyright Google Inc. All Rights Reserved.
25732 *
25733 * Use of this source code is governed by an MIT-style license that can be
25734 * found in the LICENSE file at https://angular.io/license
25735 */
25736/**
25737 * An internal module of the Angular compiler that begins with component types,
25738 * extracts templates, and eventually produces a compiled version of the component
25739 * ready for linking into an application.
25740 *
25741 * @security When compiling templates at runtime, you must ensure that the entire template comes
25742 * from a trusted source. Attacker-controlled data introduced by a template could expose your
25743 * application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security).
25744 */
25745class JitCompiler {
25746 constructor(_metadataResolver, _templateParser, _styleCompiler, _viewCompiler, _ngModuleCompiler, _summaryResolver, _reflector, _jitEvaluator, _compilerConfig, _console, getExtraNgModuleProviders) {
25747 this._metadataResolver = _metadataResolver;
25748 this._templateParser = _templateParser;
25749 this._styleCompiler = _styleCompiler;
25750 this._viewCompiler = _viewCompiler;
25751 this._ngModuleCompiler = _ngModuleCompiler;
25752 this._summaryResolver = _summaryResolver;
25753 this._reflector = _reflector;
25754 this._jitEvaluator = _jitEvaluator;
25755 this._compilerConfig = _compilerConfig;
25756 this._console = _console;
25757 this.getExtraNgModuleProviders = getExtraNgModuleProviders;
25758 this._compiledTemplateCache = new Map();
25759 this._compiledHostTemplateCache = new Map();
25760 this._compiledDirectiveWrapperCache = new Map();
25761 this._compiledNgModuleCache = new Map();
25762 this._sharedStylesheetCount = 0;
25763 this._addedAotSummaries = new Set();
25764 }
25765 compileModuleSync(moduleType) {
25766 return SyncAsync.assertSync(this._compileModuleAndComponents(moduleType, true));
25767 }
25768 compileModuleAsync(moduleType) {
25769 return Promise.resolve(this._compileModuleAndComponents(moduleType, false));
25770 }
25771 compileModuleAndAllComponentsSync(moduleType) {
25772 return SyncAsync.assertSync(this._compileModuleAndAllComponents(moduleType, true));
25773 }
25774 compileModuleAndAllComponentsAsync(moduleType) {
25775 return Promise.resolve(this._compileModuleAndAllComponents(moduleType, false));
25776 }
25777 getComponentFactory(component) {
25778 const summary = this._metadataResolver.getDirectiveSummary(component);
25779 return summary.componentFactory;
25780 }
25781 loadAotSummaries(summaries) {
25782 this.clearCache();
25783 this._addAotSummaries(summaries);
25784 }
25785 _addAotSummaries(fn) {
25786 if (this._addedAotSummaries.has(fn)) {
25787 return;
25788 }
25789 this._addedAotSummaries.add(fn);
25790 const summaries = fn();
25791 for (let i = 0; i < summaries.length; i++) {
25792 const entry = summaries[i];
25793 if (typeof entry === 'function') {
25794 this._addAotSummaries(entry);
25795 }
25796 else {
25797 const summary = entry;
25798 this._summaryResolver.addSummary({ symbol: summary.type.reference, metadata: null, type: summary });
25799 }
25800 }
25801 }
25802 hasAotSummary(ref) { return !!this._summaryResolver.resolveSummary(ref); }
25803 _filterJitIdentifiers(ids) {
25804 return ids.map(mod => mod.reference).filter((ref) => !this.hasAotSummary(ref));
25805 }
25806 _compileModuleAndComponents(moduleType, isSync) {
25807 return SyncAsync.then(this._loadModules(moduleType, isSync), () => {
25808 this._compileComponents(moduleType, null);
25809 return this._compileModule(moduleType);
25810 });
25811 }
25812 _compileModuleAndAllComponents(moduleType, isSync) {
25813 return SyncAsync.then(this._loadModules(moduleType, isSync), () => {
25814 const componentFactories = [];
25815 this._compileComponents(moduleType, componentFactories);
25816 return {
25817 ngModuleFactory: this._compileModule(moduleType),
25818 componentFactories: componentFactories
25819 };
25820 });
25821 }
25822 _loadModules(mainModule, isSync) {
25823 const loading = [];
25824 const mainNgModule = this._metadataResolver.getNgModuleMetadata(mainModule);
25825 // Note: for runtime compilation, we want to transitively compile all modules,
25826 // so we also need to load the declared directives / pipes for all nested modules.
25827 this._filterJitIdentifiers(mainNgModule.transitiveModule.modules).forEach((nestedNgModule) => {
25828 // getNgModuleMetadata only returns null if the value passed in is not an NgModule
25829 const moduleMeta = this._metadataResolver.getNgModuleMetadata(nestedNgModule);
25830 this._filterJitIdentifiers(moduleMeta.declaredDirectives).forEach((ref) => {
25831 const promise = this._metadataResolver.loadDirectiveMetadata(moduleMeta.type.reference, ref, isSync);
25832 if (promise) {
25833 loading.push(promise);
25834 }
25835 });
25836 this._filterJitIdentifiers(moduleMeta.declaredPipes)
25837 .forEach((ref) => this._metadataResolver.getOrLoadPipeMetadata(ref));
25838 });
25839 return SyncAsync.all(loading);
25840 }
25841 _compileModule(moduleType) {
25842 let ngModuleFactory = this._compiledNgModuleCache.get(moduleType);
25843 if (!ngModuleFactory) {
25844 const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType);
25845 // Always provide a bound Compiler
25846 const extraProviders = this.getExtraNgModuleProviders(moduleMeta.type.reference);
25847 const outputCtx = createOutputContext();
25848 const compileResult = this._ngModuleCompiler.compile(outputCtx, moduleMeta, extraProviders);
25849 ngModuleFactory = this._interpretOrJit(ngModuleJitUrl(moduleMeta), outputCtx.statements)[compileResult.ngModuleFactoryVar];
25850 this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory);
25851 }
25852 return ngModuleFactory;
25853 }
25854 /**
25855 * @internal
25856 */
25857 _compileComponents(mainModule, allComponentFactories) {
25858 const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
25859 const moduleByJitDirective = new Map();
25860 const templates = new Set();
25861 const transJitModules = this._filterJitIdentifiers(ngModule.transitiveModule.modules);
25862 transJitModules.forEach((localMod) => {
25863 const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod);
25864 this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => {
25865 moduleByJitDirective.set(dirRef, localModuleMeta);
25866 const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef);
25867 if (dirMeta.isComponent) {
25868 templates.add(this._createCompiledTemplate(dirMeta, localModuleMeta));
25869 if (allComponentFactories) {
25870 const template = this._createCompiledHostTemplate(dirMeta.type.reference, localModuleMeta);
25871 templates.add(template);
25872 allComponentFactories.push(dirMeta.componentFactory);
25873 }
25874 }
25875 });
25876 });
25877 transJitModules.forEach((localMod) => {
25878 const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod);
25879 this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => {
25880 const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef);
25881 if (dirMeta.isComponent) {
25882 dirMeta.entryComponents.forEach((entryComponentType) => {
25883 const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType);
25884 templates.add(this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
25885 });
25886 }
25887 });
25888 localModuleMeta.entryComponents.forEach((entryComponentType) => {
25889 if (!this.hasAotSummary(entryComponentType.componentType)) {
25890 const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType);
25891 templates.add(this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
25892 }
25893 });
25894 });
25895 templates.forEach((template) => this._compileTemplate(template));
25896 }
25897 clearCacheFor(type) {
25898 this._compiledNgModuleCache.delete(type);
25899 this._metadataResolver.clearCacheFor(type);
25900 this._compiledHostTemplateCache.delete(type);
25901 const compiledTemplate = this._compiledTemplateCache.get(type);
25902 if (compiledTemplate) {
25903 this._compiledTemplateCache.delete(type);
25904 }
25905 }
25906 clearCache() {
25907 // Note: don't clear the _addedAotSummaries, as they don't change!
25908 this._metadataResolver.clearCache();
25909 this._compiledTemplateCache.clear();
25910 this._compiledHostTemplateCache.clear();
25911 this._compiledNgModuleCache.clear();
25912 }
25913 _createCompiledHostTemplate(compType, ngModule) {
25914 if (!ngModule) {
25915 throw new Error(`Component ${stringify(compType)} is not part of any NgModule or the module has not been imported into your module.`);
25916 }
25917 let compiledTemplate = this._compiledHostTemplateCache.get(compType);
25918 if (!compiledTemplate) {
25919 const compMeta = this._metadataResolver.getDirectiveMetadata(compType);
25920 assertComponent(compMeta);
25921 const hostMeta = this._metadataResolver.getHostComponentMetadata(compMeta, compMeta.componentFactory.viewDefFactory);
25922 compiledTemplate =
25923 new CompiledTemplate(true, compMeta.type, hostMeta, ngModule, [compMeta.type]);
25924 this._compiledHostTemplateCache.set(compType, compiledTemplate);
25925 }
25926 return compiledTemplate;
25927 }
25928 _createCompiledTemplate(compMeta, ngModule) {
25929 let compiledTemplate = this._compiledTemplateCache.get(compMeta.type.reference);
25930 if (!compiledTemplate) {
25931 assertComponent(compMeta);
25932 compiledTemplate = new CompiledTemplate(false, compMeta.type, compMeta, ngModule, ngModule.transitiveModule.directives);
25933 this._compiledTemplateCache.set(compMeta.type.reference, compiledTemplate);
25934 }
25935 return compiledTemplate;
25936 }
25937 _compileTemplate(template) {
25938 if (template.isCompiled) {
25939 return;
25940 }
25941 const compMeta = template.compMeta;
25942 const externalStylesheetsByModuleUrl = new Map();
25943 const outputContext = createOutputContext();
25944 const componentStylesheet = this._styleCompiler.compileComponent(outputContext, compMeta);
25945 compMeta.template.externalStylesheets.forEach((stylesheetMeta) => {
25946 const compiledStylesheet = this._styleCompiler.compileStyles(createOutputContext(), compMeta, stylesheetMeta);
25947 externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl, compiledStylesheet);
25948 });
25949 this._resolveStylesCompileResult(componentStylesheet, externalStylesheetsByModuleUrl);
25950 const pipes = template.ngModule.transitiveModule.pipes.map(pipe => this._metadataResolver.getPipeSummary(pipe.reference));
25951 const { template: parsedTemplate, pipes: usedPipes } = this._parseTemplate(compMeta, template.ngModule, template.directives);
25952 const compileResult = this._viewCompiler.compileComponent(outputContext, compMeta, parsedTemplate, variable(componentStylesheet.stylesVar), usedPipes);
25953 const evalResult = this._interpretOrJit(templateJitUrl(template.ngModule.type, template.compMeta), outputContext.statements);
25954 const viewClass = evalResult[compileResult.viewClassVar];
25955 const rendererType = evalResult[compileResult.rendererTypeVar];
25956 template.compiled(viewClass, rendererType);
25957 }
25958 _parseTemplate(compMeta, ngModule, directiveIdentifiers) {
25959 // Note: ! is ok here as components always have a template.
25960 const preserveWhitespaces = compMeta.template.preserveWhitespaces;
25961 const directives = directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
25962 const pipes = ngModule.transitiveModule.pipes.map(pipe => this._metadataResolver.getPipeSummary(pipe.reference));
25963 return this._templateParser.parse(compMeta, compMeta.template.htmlAst, directives, pipes, ngModule.schemas, templateSourceUrl(ngModule.type, compMeta, compMeta.template), preserveWhitespaces);
25964 }
25965 _resolveStylesCompileResult(result, externalStylesheetsByModuleUrl) {
25966 result.dependencies.forEach((dep, i) => {
25967 const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl);
25968 const nestedStylesArr = this._resolveAndEvalStylesCompileResult(nestedCompileResult, externalStylesheetsByModuleUrl);
25969 dep.setValue(nestedStylesArr);
25970 });
25971 }
25972 _resolveAndEvalStylesCompileResult(result, externalStylesheetsByModuleUrl) {
25973 this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
25974 return this._interpretOrJit(sharedStylesheetJitUrl(result.meta, this._sharedStylesheetCount++), result.outputCtx.statements)[result.stylesVar];
25975 }
25976 _interpretOrJit(sourceUrl, statements) {
25977 if (!this._compilerConfig.useJit) {
25978 return interpretStatements(statements, this._reflector);
25979 }
25980 else {
25981 return this._jitEvaluator.evaluateStatements(sourceUrl, statements, this._reflector, this._compilerConfig.jitDevMode);
25982 }
25983 }
25984}
25985class CompiledTemplate {
25986 constructor(isHost, compType, compMeta, ngModule, directives) {
25987 this.isHost = isHost;
25988 this.compType = compType;
25989 this.compMeta = compMeta;
25990 this.ngModule = ngModule;
25991 this.directives = directives;
25992 this._viewClass = null;
25993 this.isCompiled = false;
25994 }
25995 compiled(viewClass, rendererType) {
25996 this._viewClass = viewClass;
25997 this.compMeta.componentViewType.setDelegate(viewClass);
25998 for (let prop in rendererType) {
25999 this.compMeta.rendererType[prop] = rendererType[prop];
26000 }
26001 this.isCompiled = true;
26002 }
26003}
26004function assertComponent(meta) {
26005 if (!meta.isComponent) {
26006 throw new Error(`Could not compile '${identifierName(meta.type)}' because it is not a component.`);
26007 }
26008}
26009function createOutputContext() {
26010 const importExpr$1 = (symbol) => importExpr({ name: identifierName(symbol), moduleName: null, runtime: symbol });
26011 return { statements: [], genFilePath: '', importExpr: importExpr$1, constantPool: new ConstantPool() };
26012}
26013
26014/**
26015 * @license
26016 * Copyright Google Inc. All Rights Reserved.
26017 *
26018 * Use of this source code is governed by an MIT-style license that can be
26019 * found in the LICENSE file at https://angular.io/license
26020 */
26021/**
26022 * Provides access to reflection data about symbols that the compiler needs.
26023 */
26024class CompileReflector {
26025}
26026
26027/**
26028 * @license
26029 * Copyright Google Inc. All Rights Reserved.
26030 *
26031 * Use of this source code is governed by an MIT-style license that can be
26032 * found in the LICENSE file at https://angular.io/license
26033 */
26034/**
26035 * Create a {@link UrlResolver} with no package prefix.
26036 */
26037function createUrlResolverWithoutPackagePrefix() {
26038 return new UrlResolver();
26039}
26040function createOfflineCompileUrlResolver() {
26041 return new UrlResolver('.');
26042}
26043const UrlResolver = class UrlResolverImpl {
26044 constructor(_packagePrefix = null) {
26045 this._packagePrefix = _packagePrefix;
26046 }
26047 /**
26048 * Resolves the `url` given the `baseUrl`:
26049 * - when the `url` is null, the `baseUrl` is returned,
26050 * - if `url` is relative ('path/to/here', './path/to/here'), the resolved url is a combination of
26051 * `baseUrl` and `url`,
26052 * - if `url` is absolute (it has a scheme: 'http://', 'https://' or start with '/'), the `url` is
26053 * returned as is (ignoring the `baseUrl`)
26054 */
26055 resolve(baseUrl, url) {
26056 let resolvedUrl = url;
26057 if (baseUrl != null && baseUrl.length > 0) {
26058 resolvedUrl = _resolveUrl(baseUrl, resolvedUrl);
26059 }
26060 const resolvedParts = _split(resolvedUrl);
26061 let prefix = this._packagePrefix;
26062 if (prefix != null && resolvedParts != null &&
26063 resolvedParts[_ComponentIndex.Scheme] == 'package') {
26064 let path = resolvedParts[_ComponentIndex.Path];
26065 prefix = prefix.replace(/\/+$/, '');
26066 path = path.replace(/^\/+/, '');
26067 return `${prefix}/${path}`;
26068 }
26069 return resolvedUrl;
26070 }
26071};
26072/**
26073 * Extract the scheme of a URL.
26074 */
26075function getUrlScheme(url) {
26076 const match = _split(url);
26077 return (match && match[_ComponentIndex.Scheme]) || '';
26078}
26079// The code below is adapted from Traceur:
26080// https://github.com/google/traceur-compiler/blob/9511c1dafa972bf0de1202a8a863bad02f0f95a8/src/runtime/url.js
26081/**
26082 * Builds a URI string from already-encoded parts.
26083 *
26084 * No encoding is performed. Any component may be omitted as either null or
26085 * undefined.
26086 *
26087 * @param opt_scheme The scheme such as 'http'.
26088 * @param opt_userInfo The user name before the '@'.
26089 * @param opt_domain The domain such as 'www.google.com', already
26090 * URI-encoded.
26091 * @param opt_port The port number.
26092 * @param opt_path The path, already URI-encoded. If it is not
26093 * empty, it must begin with a slash.
26094 * @param opt_queryData The URI-encoded query data.
26095 * @param opt_fragment The URI-encoded fragment identifier.
26096 * @return The fully combined URI.
26097 */
26098function _buildFromEncodedParts(opt_scheme, opt_userInfo, opt_domain, opt_port, opt_path, opt_queryData, opt_fragment) {
26099 const out = [];
26100 if (opt_scheme != null) {
26101 out.push(opt_scheme + ':');
26102 }
26103 if (opt_domain != null) {
26104 out.push('//');
26105 if (opt_userInfo != null) {
26106 out.push(opt_userInfo + '@');
26107 }
26108 out.push(opt_domain);
26109 if (opt_port != null) {
26110 out.push(':' + opt_port);
26111 }
26112 }
26113 if (opt_path != null) {
26114 out.push(opt_path);
26115 }
26116 if (opt_queryData != null) {
26117 out.push('?' + opt_queryData);
26118 }
26119 if (opt_fragment != null) {
26120 out.push('#' + opt_fragment);
26121 }
26122 return out.join('');
26123}
26124/**
26125 * A regular expression for breaking a URI into its component parts.
26126 *
26127 * {@link http://www.gbiv.com/protocols/uri/rfc/rfc3986.html#RFC2234} says
26128 * As the "first-match-wins" algorithm is identical to the "greedy"
26129 * disambiguation method used by POSIX regular expressions, it is natural and
26130 * commonplace to use a regular expression for parsing the potential five
26131 * components of a URI reference.
26132 *
26133 * The following line is the regular expression for breaking-down a
26134 * well-formed URI reference into its components.
26135 *
26136 * <pre>
26137 * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
26138 * 12 3 4 5 6 7 8 9
26139 * </pre>
26140 *
26141 * The numbers in the second line above are only to assist readability; they
26142 * indicate the reference points for each subexpression (i.e., each paired
26143 * parenthesis). We refer to the value matched for subexpression <n> as $<n>.
26144 * For example, matching the above expression to
26145 * <pre>
26146 * http://www.ics.uci.edu/pub/ietf/uri/#Related
26147 * </pre>
26148 * results in the following subexpression matches:
26149 * <pre>
26150 * $1 = http:
26151 * $2 = http
26152 * $3 = //www.ics.uci.edu
26153 * $4 = www.ics.uci.edu
26154 * $5 = /pub/ietf/uri/
26155 * $6 = <undefined>
26156 * $7 = <undefined>
26157 * $8 = #Related
26158 * $9 = Related
26159 * </pre>
26160 * where <undefined> indicates that the component is not present, as is the
26161 * case for the query component in the above example. Therefore, we can
26162 * determine the value of the five components as
26163 * <pre>
26164 * scheme = $2
26165 * authority = $4
26166 * path = $5
26167 * query = $7
26168 * fragment = $9
26169 * </pre>
26170 *
26171 * The regular expression has been modified slightly to expose the
26172 * userInfo, domain, and port separately from the authority.
26173 * The modified version yields
26174 * <pre>
26175 * $1 = http scheme
26176 * $2 = <undefined> userInfo -\
26177 * $3 = www.ics.uci.edu domain | authority
26178 * $4 = <undefined> port -/
26179 * $5 = /pub/ietf/uri/ path
26180 * $6 = <undefined> query without ?
26181 * $7 = Related fragment without #
26182 * </pre>
26183 * @internal
26184 */
26185const _splitRe = new RegExp('^' +
26186 '(?:' +
26187 '([^:/?#.]+)' + // scheme - ignore special characters
26188 // used by other URL parts such as :,
26189 // ?, /, #, and .
26190 ':)?' +
26191 '(?://' +
26192 '(?:([^/?#]*)@)?' + // userInfo
26193 '([\\w\\d\\-\\u0100-\\uffff.%]*)' + // domain - restrict to letters,
26194 // digits, dashes, dots, percent
26195 // escapes, and unicode characters.
26196 '(?::([0-9]+))?' + // port
26197 ')?' +
26198 '([^?#]+)?' + // path
26199 '(?:\\?([^#]*))?' + // query
26200 '(?:#(.*))?' + // fragment
26201 '$');
26202/**
26203 * The index of each URI component in the return value of goog.uri.utils.split.
26204 * @enum {number}
26205 */
26206var _ComponentIndex;
26207(function (_ComponentIndex) {
26208 _ComponentIndex[_ComponentIndex["Scheme"] = 1] = "Scheme";
26209 _ComponentIndex[_ComponentIndex["UserInfo"] = 2] = "UserInfo";
26210 _ComponentIndex[_ComponentIndex["Domain"] = 3] = "Domain";
26211 _ComponentIndex[_ComponentIndex["Port"] = 4] = "Port";
26212 _ComponentIndex[_ComponentIndex["Path"] = 5] = "Path";
26213 _ComponentIndex[_ComponentIndex["QueryData"] = 6] = "QueryData";
26214 _ComponentIndex[_ComponentIndex["Fragment"] = 7] = "Fragment";
26215})(_ComponentIndex || (_ComponentIndex = {}));
26216/**
26217 * Splits a URI into its component parts.
26218 *
26219 * Each component can be accessed via the component indices; for example:
26220 * <pre>
26221 * goog.uri.utils.split(someStr)[goog.uri.utils.CompontentIndex.QUERY_DATA];
26222 * </pre>
26223 *
26224 * @param uri The URI string to examine.
26225 * @return Each component still URI-encoded.
26226 * Each component that is present will contain the encoded value, whereas
26227 * components that are not present will be undefined or empty, depending
26228 * on the browser's regular expression implementation. Never null, since
26229 * arbitrary strings may still look like path names.
26230 */
26231function _split(uri) {
26232 return uri.match(_splitRe);
26233}
26234/**
26235 * Removes dot segments in given path component, as described in
26236 * RFC 3986, section 5.2.4.
26237 *
26238 * @param path A non-empty path component.
26239 * @return Path component with removed dot segments.
26240 */
26241function _removeDotSegments(path) {
26242 if (path == '/')
26243 return '/';
26244 const leadingSlash = path[0] == '/' ? '/' : '';
26245 const trailingSlash = path[path.length - 1] === '/' ? '/' : '';
26246 const segments = path.split('/');
26247 const out = [];
26248 let up = 0;
26249 for (let pos = 0; pos < segments.length; pos++) {
26250 const segment = segments[pos];
26251 switch (segment) {
26252 case '':
26253 case '.':
26254 break;
26255 case '..':
26256 if (out.length > 0) {
26257 out.pop();
26258 }
26259 else {
26260 up++;
26261 }
26262 break;
26263 default:
26264 out.push(segment);
26265 }
26266 }
26267 if (leadingSlash == '') {
26268 while (up-- > 0) {
26269 out.unshift('..');
26270 }
26271 if (out.length === 0)
26272 out.push('.');
26273 }
26274 return leadingSlash + out.join('/') + trailingSlash;
26275}
26276/**
26277 * Takes an array of the parts from split and canonicalizes the path part
26278 * and then joins all the parts.
26279 */
26280function _joinAndCanonicalizePath(parts) {
26281 let path = parts[_ComponentIndex.Path];
26282 path = path == null ? '' : _removeDotSegments(path);
26283 parts[_ComponentIndex.Path] = path;
26284 return _buildFromEncodedParts(parts[_ComponentIndex.Scheme], parts[_ComponentIndex.UserInfo], parts[_ComponentIndex.Domain], parts[_ComponentIndex.Port], path, parts[_ComponentIndex.QueryData], parts[_ComponentIndex.Fragment]);
26285}
26286/**
26287 * Resolves a URL.
26288 * @param base The URL acting as the base URL.
26289 * @param to The URL to resolve.
26290 */
26291function _resolveUrl(base, url) {
26292 const parts = _split(encodeURI(url));
26293 const baseParts = _split(base);
26294 if (parts[_ComponentIndex.Scheme] != null) {
26295 return _joinAndCanonicalizePath(parts);
26296 }
26297 else {
26298 parts[_ComponentIndex.Scheme] = baseParts[_ComponentIndex.Scheme];
26299 }
26300 for (let i = _ComponentIndex.Scheme; i <= _ComponentIndex.Port; i++) {
26301 if (parts[i] == null) {
26302 parts[i] = baseParts[i];
26303 }
26304 }
26305 if (parts[_ComponentIndex.Path][0] == '/') {
26306 return _joinAndCanonicalizePath(parts);
26307 }
26308 let path = baseParts[_ComponentIndex.Path];
26309 if (path == null)
26310 path = '/';
26311 const index = path.lastIndexOf('/');
26312 path = path.substring(0, index + 1) + parts[_ComponentIndex.Path];
26313 parts[_ComponentIndex.Path] = path;
26314 return _joinAndCanonicalizePath(parts);
26315}
26316
26317/**
26318 * @license
26319 * Copyright Google Inc. All Rights Reserved.
26320 *
26321 * Use of this source code is governed by an MIT-style license that can be
26322 * found in the LICENSE file at https://angular.io/license
26323 */
26324class Extractor {
26325 constructor(host, staticSymbolResolver, messageBundle, metadataResolver) {
26326 this.host = host;
26327 this.staticSymbolResolver = staticSymbolResolver;
26328 this.messageBundle = messageBundle;
26329 this.metadataResolver = metadataResolver;
26330 }
26331 extract(rootFiles) {
26332 const { files, ngModules } = analyzeAndValidateNgModules(rootFiles, this.host, this.staticSymbolResolver, this.metadataResolver);
26333 return Promise
26334 .all(ngModules.map(ngModule => this.metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false)))
26335 .then(() => {
26336 const errors = [];
26337 files.forEach(file => {
26338 const compMetas = [];
26339 file.directives.forEach(directiveType => {
26340 const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType);
26341 if (dirMeta && dirMeta.isComponent) {
26342 compMetas.push(dirMeta);
26343 }
26344 });
26345 compMetas.forEach(compMeta => {
26346 const html = compMeta.template.template;
26347 // Template URL points to either an HTML or TS file depending on
26348 // whether the file is used with `templateUrl:` or `template:`,
26349 // respectively.
26350 const templateUrl = compMeta.template.templateUrl;
26351 const interpolationConfig = InterpolationConfig.fromArray(compMeta.template.interpolation);
26352 errors.push(...this.messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig));
26353 });
26354 });
26355 if (errors.length) {
26356 throw new Error(errors.map(e => e.toString()).join('\n'));
26357 }
26358 return this.messageBundle;
26359 });
26360 }
26361 static create(host, locale) {
26362 const htmlParser = new HtmlParser();
26363 const urlResolver = createAotUrlResolver(host);
26364 const symbolCache = new StaticSymbolCache();
26365 const summaryResolver = new AotSummaryResolver(host, symbolCache);
26366 const staticSymbolResolver = new StaticSymbolResolver(host, symbolCache, summaryResolver);
26367 const staticReflector = new StaticReflector(summaryResolver, staticSymbolResolver);
26368 const config = new CompilerConfig({ defaultEncapsulation: ViewEncapsulation.Emulated, useJit: false });
26369 const normalizer = new DirectiveNormalizer({ get: (url) => host.loadResource(url) }, urlResolver, htmlParser, config);
26370 const elementSchemaRegistry = new DomElementSchemaRegistry();
26371 const resolver = new CompileMetadataResolver(config, htmlParser, new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector), new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer, console, symbolCache, staticReflector);
26372 // TODO(vicb): implicit tags & attributes
26373 const messageBundle = new MessageBundle(htmlParser, [], {}, locale);
26374 const extractor = new Extractor(host, staticSymbolResolver, messageBundle, resolver);
26375 return { extractor, staticReflector };
26376 }
26377}
26378
26379/**
26380 * @license
26381 * Copyright Google Inc. All Rights Reserved.
26382 *
26383 * Use of this source code is governed by an MIT-style license that can be
26384 * found in the LICENSE file at https://angular.io/license
26385 */
26386
26387/**
26388 * @license
26389 * Copyright Google Inc. All Rights Reserved.
26390 *
26391 * Use of this source code is governed by an MIT-style license that can be
26392 * found in the LICENSE file at https://angular.io/license
26393 */
26394/**
26395 * Processes `Target`s with a given set of directives and performs a binding operation, which
26396 * returns an object similar to TypeScript's `ts.TypeChecker` that contains knowledge about the
26397 * target.
26398 */
26399class R3TargetBinder {
26400 constructor(directiveMatcher) {
26401 this.directiveMatcher = directiveMatcher;
26402 }
26403 /**
26404 * Perform a binding operation on the given `Target` and return a `BoundTarget` which contains
26405 * metadata about the types referenced in the template.
26406 */
26407 bind(target) {
26408 if (!target.template) {
26409 // TODO(alxhub): handle targets which contain things like HostBindings, etc.
26410 throw new Error('Binding without a template not yet supported');
26411 }
26412 // First, parse the template into a `Scope` structure. This operation captures the syntactic
26413 // scopes in the template and makes them available for later use.
26414 const scope = Scope.apply(target.template);
26415 // Next, perform directive matching on the template using the `DirectiveBinder`. This returns:
26416 // - directives: Map of nodes (elements & ng-templates) to the directives on them.
26417 // - bindings: Map of inputs, outputs, and attributes to the directive/element that claims
26418 // them. TODO(alxhub): handle multiple directives claiming an input/output/etc.
26419 // - references: Map of #references to their targets.
26420 const { directives, bindings, references } = DirectiveBinder.apply(target.template, this.directiveMatcher);
26421 // Finally, run the TemplateBinder to bind references, variables, and other entities within the
26422 // template. This extracts all the metadata that doesn't depend on directive matching.
26423 const { expressions, symbols, nestingLevel, usedPipes } = TemplateBinder.apply(target.template, scope);
26424 return new R3BoundTarget(target, directives, bindings, references, expressions, symbols, nestingLevel, usedPipes);
26425 }
26426}
26427/**
26428 * Represents a binding scope within a template.
26429 *
26430 * Any variables, references, or other named entities declared within the template will
26431 * be captured and available by name in `namedEntities`. Additionally, child templates will
26432 * be analyzed and have their child `Scope`s available in `childScopes`.
26433 */
26434class Scope {
26435 constructor(parentScope) {
26436 this.parentScope = parentScope;
26437 /**
26438 * Named members of the `Scope`, such as `Reference`s or `Variable`s.
26439 */
26440 this.namedEntities = new Map();
26441 /**
26442 * Child `Scope`s for immediately nested `Template`s.
26443 */
26444 this.childScopes = new Map();
26445 }
26446 /**
26447 * Process a template (either as a `Template` sub-template with variables, or a plain array of
26448 * template `Node`s) and construct its `Scope`.
26449 */
26450 static apply(template) {
26451 const scope = new Scope();
26452 scope.ingest(template);
26453 return scope;
26454 }
26455 /**
26456 * Internal method to process the template and populate the `Scope`.
26457 */
26458 ingest(template) {
26459 if (template instanceof Template) {
26460 // Variables on an <ng-template> are defined in the inner scope.
26461 template.variables.forEach(node => this.visitVariable(node));
26462 // Process the nodes of the template.
26463 template.children.forEach(node => node.visit(this));
26464 }
26465 else {
26466 // No overarching `Template` instance, so process the nodes directly.
26467 template.forEach(node => node.visit(this));
26468 }
26469 }
26470 visitElement(element) {
26471 // `Element`s in the template may have `Reference`s which are captured in the scope.
26472 element.references.forEach(node => this.visitReference(node));
26473 // Recurse into the `Element`'s children.
26474 element.children.forEach(node => node.visit(this));
26475 }
26476 visitTemplate(template) {
26477 // References on a <ng-template> are defined in the outer scope, so capture them before
26478 // processing the template's child scope.
26479 template.references.forEach(node => this.visitReference(node));
26480 // Next, create an inner scope and process the template within it.
26481 const scope = new Scope(this);
26482 scope.ingest(template);
26483 this.childScopes.set(template, scope);
26484 }
26485 visitVariable(variable) {
26486 // Declare the variable if it's not already.
26487 this.maybeDeclare(variable);
26488 }
26489 visitReference(reference) {
26490 // Declare the variable if it's not already.
26491 this.maybeDeclare(reference);
26492 }
26493 // Unused visitors.
26494 visitContent(content) { }
26495 visitBoundAttribute(attr) { }
26496 visitBoundEvent(event) { }
26497 visitBoundText(text) { }
26498 visitText(text) { }
26499 visitTextAttribute(attr) { }
26500 visitIcu(icu) { }
26501 maybeDeclare(thing) {
26502 // Declare something with a name, as long as that name isn't taken.
26503 if (!this.namedEntities.has(thing.name)) {
26504 this.namedEntities.set(thing.name, thing);
26505 }
26506 }
26507 /**
26508 * Look up a variable within this `Scope`.
26509 *
26510 * This can recurse into a parent `Scope` if it's available.
26511 */
26512 lookup(name) {
26513 if (this.namedEntities.has(name)) {
26514 // Found in the local scope.
26515 return this.namedEntities.get(name);
26516 }
26517 else if (this.parentScope !== undefined) {
26518 // Not in the local scope, but there's a parent scope so check there.
26519 return this.parentScope.lookup(name);
26520 }
26521 else {
26522 // At the top level and it wasn't found.
26523 return null;
26524 }
26525 }
26526 /**
26527 * Get the child scope for a `Template`.
26528 *
26529 * This should always be defined.
26530 */
26531 getChildScope(template) {
26532 const res = this.childScopes.get(template);
26533 if (res === undefined) {
26534 throw new Error(`Assertion error: child scope for ${template} not found`);
26535 }
26536 return res;
26537 }
26538}
26539/**
26540 * Processes a template and matches directives on nodes (elements and templates).
26541 *
26542 * Usually used via the static `apply()` method.
26543 */
26544class DirectiveBinder {
26545 constructor(matcher, directives, bindings, references) {
26546 this.matcher = matcher;
26547 this.directives = directives;
26548 this.bindings = bindings;
26549 this.references = references;
26550 }
26551 /**
26552 * Process a template (list of `Node`s) and perform directive matching against each node.
26553 *
26554 * @param template the list of template `Node`s to match (recursively).
26555 * @param selectorMatcher a `SelectorMatcher` containing the directives that are in scope for
26556 * this template.
26557 * @returns three maps which contain information about directives in the template: the
26558 * `directives` map which lists directives matched on each node, the `bindings` map which
26559 * indicates which directives claimed which bindings (inputs, outputs, etc), and the `references`
26560 * map which resolves #references (`Reference`s) within the template to the named directive or
26561 * template node.
26562 */
26563 static apply(template, selectorMatcher) {
26564 const directives = new Map();
26565 const bindings = new Map();
26566 const references = new Map();
26567 const matcher = new DirectiveBinder(selectorMatcher, directives, bindings, references);
26568 matcher.ingest(template);
26569 return { directives, bindings, references };
26570 }
26571 ingest(template) { template.forEach(node => node.visit(this)); }
26572 visitElement(element) { this.visitElementOrTemplate(element.name, element); }
26573 visitTemplate(template) { this.visitElementOrTemplate('ng-template', template); }
26574 visitElementOrTemplate(tag, node) {
26575 // First, determine the HTML shape of the node for the purpose of directive matching.
26576 // Do this by building up a `CssSelector` for the node.
26577 const cssSelector = new CssSelector();
26578 cssSelector.setElement(tag);
26579 // Add attributes to the CSS selector.
26580 const attrs = getAttrsForDirectiveMatching(node);
26581 Object.getOwnPropertyNames(attrs).forEach((name) => {
26582 const value = attrs[name];
26583 cssSelector.addAttribute(name, value);
26584 // Treat the 'class' attribute specially.
26585 if (name.toLowerCase() === 'class') {
26586 const classes = value.trim().split(/\s+/g);
26587 classes.forEach(className => cssSelector.addClassName(className));
26588 }
26589 });
26590 // Next, use the `SelectorMatcher` to get the list of directives on the node.
26591 const directives = [];
26592 this.matcher.match(cssSelector, (_, directive) => directives.push(directive));
26593 if (directives.length > 0) {
26594 this.directives.set(node, directives);
26595 }
26596 // Resolve any references that are created on this node.
26597 node.references.forEach(ref => {
26598 let dirTarget = null;
26599 // If the reference expression is empty, then it matches the "primary" directive on the node
26600 // (if there is one). Otherwise it matches the host node itself (either an element or
26601 // <ng-template> node).
26602 if (ref.value.trim() === '') {
26603 // This could be a reference to a component if there is one.
26604 dirTarget = directives.find(dir => dir.isComponent) || null;
26605 }
26606 else {
26607 // This is a reference to a directive exported via exportAs. One should exist.
26608 dirTarget =
26609 directives.find(dir => dir.exportAs !== null && dir.exportAs.some(value => value === ref.value)) ||
26610 null;
26611 // Check if a matching directive was found, and error if it wasn't.
26612 if (dirTarget === null) {
26613 // TODO(alxhub): Return an error value here that can be used for template validation.
26614 throw new Error(`Assertion error: failed to find directive with exportAs: ${ref.value}`);
26615 }
26616 }
26617 if (dirTarget !== null) {
26618 // This reference points to a directive.
26619 this.references.set(ref, { directive: dirTarget, node });
26620 }
26621 else {
26622 // This reference points to the node itself.
26623 this.references.set(ref, node);
26624 }
26625 });
26626 // Associate attributes/bindings on the node with directives or with the node itself.
26627 const processAttribute = (attribute) => {
26628 let dir = directives.find(dir => dir.inputs.hasOwnProperty(attribute.name));
26629 if (dir !== undefined) {
26630 this.bindings.set(attribute, dir);
26631 }
26632 else {
26633 this.bindings.set(attribute, node);
26634 }
26635 };
26636 node.attributes.forEach(processAttribute);
26637 node.inputs.forEach(processAttribute);
26638 node.outputs.forEach(processAttribute);
26639 if (node instanceof Template) {
26640 node.templateAttrs.forEach(processAttribute);
26641 }
26642 // Recurse into the node's children.
26643 node.children.forEach(child => child.visit(this));
26644 }
26645 // Unused visitors.
26646 visitContent(content) { }
26647 visitVariable(variable) { }
26648 visitReference(reference) { }
26649 visitTextAttribute(attribute) { }
26650 visitBoundAttribute(attribute) { }
26651 visitBoundEvent(attribute) { }
26652 visitBoundAttributeOrEvent(node) { }
26653 visitText(text) { }
26654 visitBoundText(text) { }
26655 visitIcu(icu) { }
26656}
26657/**
26658 * Processes a template and extract metadata about expressions and symbols within.
26659 *
26660 * This is a companion to the `DirectiveBinder` that doesn't require knowledge of directives matched
26661 * within the template in order to operate.
26662 *
26663 * Expressions are visited by the superclass `RecursiveAstVisitor`, with custom logic provided
26664 * by overridden methods from that visitor.
26665 */
26666class TemplateBinder extends RecursiveAstVisitor$1 {
26667 constructor(bindings, symbols, usedPipes, nestingLevel, scope, template, level) {
26668 super();
26669 this.bindings = bindings;
26670 this.symbols = symbols;
26671 this.usedPipes = usedPipes;
26672 this.nestingLevel = nestingLevel;
26673 this.scope = scope;
26674 this.template = template;
26675 this.level = level;
26676 this.pipesUsed = [];
26677 // Save a bit of processing time by constructing this closure in advance.
26678 this.visitNode = (node) => node.visit(this);
26679 }
26680 /**
26681 * Process a template and extract metadata about expressions and symbols within.
26682 *
26683 * @param template the nodes of the template to process
26684 * @param scope the `Scope` of the template being processed.
26685 * @returns three maps which contain metadata about the template: `expressions` which interprets
26686 * special `AST` nodes in expressions as pointing to references or variables declared within the
26687 * template, `symbols` which maps those variables and references to the nested `Template` which
26688 * declares them, if any, and `nestingLevel` which associates each `Template` with a integer
26689 * nesting level (how many levels deep within the template structure the `Template` is), starting
26690 * at 1.
26691 */
26692 static apply(template, scope) {
26693 const expressions = new Map();
26694 const symbols = new Map();
26695 const nestingLevel = new Map();
26696 const usedPipes = new Set();
26697 // The top-level template has nesting level 0.
26698 const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template instanceof Template ? template : null, 0);
26699 binder.ingest(template);
26700 return { expressions, symbols, nestingLevel, usedPipes };
26701 }
26702 ingest(template) {
26703 if (template instanceof Template) {
26704 // For <ng-template>s, process only variables and child nodes. Inputs, outputs, templateAttrs,
26705 // and references were all processed in the scope of the containing template.
26706 template.variables.forEach(this.visitNode);
26707 template.children.forEach(this.visitNode);
26708 // Set the nesting level.
26709 this.nestingLevel.set(template, this.level);
26710 }
26711 else {
26712 // Visit each node from the top-level template.
26713 template.forEach(this.visitNode);
26714 }
26715 }
26716 visitElement(element) {
26717 // Visit the inputs, outputs, and children of the element.
26718 element.inputs.forEach(this.visitNode);
26719 element.outputs.forEach(this.visitNode);
26720 element.children.forEach(this.visitNode);
26721 }
26722 visitTemplate(template) {
26723 // First, visit inputs, outputs and template attributes of the template node.
26724 template.inputs.forEach(this.visitNode);
26725 template.outputs.forEach(this.visitNode);
26726 template.templateAttrs.forEach(this.visitNode);
26727 // References are also evaluated in the outer context.
26728 template.references.forEach(this.visitNode);
26729 // Next, recurse into the template using its scope, and bumping the nesting level up by one.
26730 const childScope = this.scope.getChildScope(template);
26731 const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.nestingLevel, childScope, template, this.level + 1);
26732 binder.ingest(template);
26733 }
26734 visitVariable(variable) {
26735 // Register the `Variable` as a symbol in the current `Template`.
26736 if (this.template !== null) {
26737 this.symbols.set(variable, this.template);
26738 }
26739 }
26740 visitReference(reference) {
26741 // Register the `Reference` as a symbol in the current `Template`.
26742 if (this.template !== null) {
26743 this.symbols.set(reference, this.template);
26744 }
26745 }
26746 // Unused template visitors
26747 visitText(text) { }
26748 visitContent(content) { }
26749 visitTextAttribute(attribute) { }
26750 visitIcu(icu) { }
26751 // The remaining visitors are concerned with processing AST expressions within template bindings
26752 visitBoundAttribute(attribute) { attribute.value.visit(this); }
26753 visitBoundEvent(event) { event.handler.visit(this); }
26754 visitBoundText(text) { text.value.visit(this); }
26755 visitPipe(ast, context) {
26756 this.usedPipes.add(ast.name);
26757 return super.visitPipe(ast, context);
26758 }
26759 // These five types of AST expressions can refer to expression roots, which could be variables
26760 // or references in the current scope.
26761 visitPropertyRead(ast, context) {
26762 this.maybeMap(context, ast, ast.name);
26763 return super.visitPropertyRead(ast, context);
26764 }
26765 visitSafePropertyRead(ast, context) {
26766 this.maybeMap(context, ast, ast.name);
26767 return super.visitSafePropertyRead(ast, context);
26768 }
26769 visitPropertyWrite(ast, context) {
26770 this.maybeMap(context, ast, ast.name);
26771 return super.visitPropertyWrite(ast, context);
26772 }
26773 visitMethodCall(ast, context) {
26774 this.maybeMap(context, ast, ast.name);
26775 return super.visitMethodCall(ast, context);
26776 }
26777 visitSafeMethodCall(ast, context) {
26778 this.maybeMap(context, ast, ast.name);
26779 return super.visitSafeMethodCall(ast, context);
26780 }
26781 maybeMap(scope, ast, name) {
26782 // If the receiver of the expression isn't the `ImplicitReceiver`, this isn't the root of an
26783 // `AST` expression that maps to a `Variable` or `Reference`.
26784 if (!(ast.receiver instanceof ImplicitReceiver)) {
26785 return;
26786 }
26787 // Check whether the name exists in the current scope. If so, map it. Otherwise, the name is
26788 // probably a property on the top-level component context.
26789 let target = this.scope.lookup(name);
26790 if (target !== null) {
26791 this.bindings.set(ast, target);
26792 }
26793 }
26794}
26795/**
26796 * Metadata container for a `Target` that allows queries for specific bits of metadata.
26797 *
26798 * See `BoundTarget` for documentation on the individual methods.
26799 */
26800class R3BoundTarget {
26801 constructor(target, directives, bindings, references, exprTargets, symbols, nestingLevel, usedPipes) {
26802 this.target = target;
26803 this.directives = directives;
26804 this.bindings = bindings;
26805 this.references = references;
26806 this.exprTargets = exprTargets;
26807 this.symbols = symbols;
26808 this.nestingLevel = nestingLevel;
26809 this.usedPipes = usedPipes;
26810 }
26811 getDirectivesOfNode(node) {
26812 return this.directives.get(node) || null;
26813 }
26814 getReferenceTarget(ref) {
26815 return this.references.get(ref) || null;
26816 }
26817 getConsumerOfBinding(binding) {
26818 return this.bindings.get(binding) || null;
26819 }
26820 getExpressionTarget(expr) {
26821 return this.exprTargets.get(expr) || null;
26822 }
26823 getTemplateOfSymbol(symbol) {
26824 return this.symbols.get(symbol) || null;
26825 }
26826 getNestingLevel(template) { return this.nestingLevel.get(template) || 0; }
26827 getUsedDirectives() {
26828 const set = new Set();
26829 this.directives.forEach(dirs => dirs.forEach(dir => set.add(dir)));
26830 return Array.from(set.values());
26831 }
26832 getUsedPipes() { return Array.from(this.usedPipes); }
26833}
26834
26835/**
26836 * @license
26837 * Copyright Google Inc. All Rights Reserved.
26838 *
26839 * Use of this source code is governed by an MIT-style license that can be
26840 * found in the LICENSE file at https://angular.io/license
26841 */
26842// This file only reexports content of the `src` folder. Keep it that way.
26843// This function call has a global side effects and publishes the compiler into global namespace for
26844// the late binding of the Compiler to the @angular/core for jit compilation.
26845publishFacade(_global);
26846
26847/**
26848 * @license
26849 * Copyright Google Inc. All Rights Reserved.
26850 *
26851 * Use of this source code is governed by an MIT-style license that can be
26852 * found in the LICENSE file at https://angular.io/license
26853 */
26854// This file only reexports content of the `src` folder. Keep it that way.
26855
26856/**
26857 * @license
26858 * Copyright Google Inc. All Rights Reserved.
26859 *
26860 * Use of this source code is governed by an MIT-style license that can be
26861 * found in the LICENSE file at https://angular.io/license
26862 */
26863
26864/**
26865 * @license
26866 * Copyright Google Inc. All Rights Reserved.
26867 *
26868 * Use of this source code is governed by an MIT-style license that can be
26869 * found in the LICENSE file at https://angular.io/license
26870 */
26871
26872export { core, CompilerConfig, preserveWhitespacesDefault, isLoweredSymbol, createLoweredSymbol, Identifiers, JitCompiler, ConstantPool, DirectiveResolver, PipeResolver, NgModuleResolver, DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig, NgModuleCompiler, ArrayType, AssertNotNull, DYNAMIC_TYPE, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinType, BuiltinTypeName, BuiltinVar, CastExpr, ClassField, ClassMethod, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, literalMap, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, ThrowStmt, TryCatchStmt, Type$1 as Type, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, STRING_TYPE, TypeofExpr, collectExternalReferences, EmitterVisitorContext, JitEvaluator, ViewCompiler, findStaticQueryIds, staticViewQueryIds, getParseErrors, isSyntaxError, syntaxError, Version, BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element as TmplAstElement, RecursiveVisitor as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable, Identifiers$1 as R3Identifiers, R3ResolvedDependencyType, compileInjector, compileNgModule, compilePipeFromMetadata, makeBindingParser, parseTemplate, compileBaseDefFromMetadata, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings, publishFacade, VERSION$1 as VERSION, TextAst, BoundTextAst, AttrAst, BoundElementPropertyAst, BoundEventAst, ReferenceAst, VariableAst, ElementAst, EmbeddedTemplateAst, BoundDirectivePropertyAst, DirectiveAst, ProviderAst, ProviderAstType, NgContentAst, NullTemplateVisitor, RecursiveTemplateAstVisitor, templateVisitAll, sanitizeIdentifier, identifierName, identifierModuleUrl, viewClassName, rendererTypeName, hostViewClassName, componentFactoryName, CompileSummaryKind, tokenName, tokenReference, CompileStylesheetMetadata, CompileTemplateMetadata, CompileDirectiveMetadata, CompilePipeMetadata, CompileShallowModuleMetadata, CompileNgModuleMetadata, TransitiveCompileNgModuleMetadata, ProviderMeta, flatten, templateSourceUrl, sharedStylesheetJitUrl, ngModuleJitUrl, templateJitUrl, createAotUrlResolver, createAotCompiler, AotCompiler, analyzeNgModules, analyzeAndValidateNgModules, analyzeFile, analyzeFileForInjectables, mergeAnalyzedFiles, GeneratedFile, toTypeScript, formattedError, isFormattedError, StaticReflector, StaticSymbol, StaticSymbolCache, ResolvedStaticSymbol, StaticSymbolResolver, unescapeIdentifier, unwrapResolvedMetadata, AotSummaryResolver, AstPath, SummaryResolver, JitSummaryResolver, CompileReflector, createUrlResolverWithoutPackagePrefix, createOfflineCompileUrlResolver, UrlResolver, getUrlScheme, ResourceLoader, ElementSchemaRegistry, Extractor, I18NHtmlParser, MessageBundle, Serializer, Xliff, Xliff2, Xmb, Xtb, DirectiveNormalizer, ParserError, ParseSpan, AST, Quote, EmptyExpr, ImplicitReceiver, Chain, Conditional, PropertyRead, PropertyWrite, SafePropertyRead, KeyedRead, KeyedWrite, BindingPipe, LiteralPrimitive, LiteralArray, LiteralMap, Interpolation, Binary, PrefixNot, NonNullAssert, MethodCall, SafeMethodCall, FunctionCall, AbsoluteSourceSpan, ASTWithSource, TemplateBinding, NullAstVisitor, RecursiveAstVisitor$1 as RecursiveAstVisitor, AstTransformer$1 as AstTransformer, AstMemoryEfficientTransformer, visitAstChildren, ParsedProperty, ParsedPropertyType, ParsedEvent, ParsedVariable, BoundElementProperty, TokenType$1 as TokenType, Lexer, Token$1 as Token, EOF, isIdentifier, isQuote, SplitInterpolation, TemplateBindingParseResult, Parser$1 as Parser, _ParseAST, ERROR_COMPONENT_TYPE, CompileMetadataResolver, Text$3 as Text, Expansion, ExpansionCase, Attribute, Element$1 as Element, Comment, visitAll$1 as visitAll, RecursiveVisitor$1 as RecursiveVisitor, findNode, HtmlParser, ParseTreeResult, TreeError, HtmlTagDefinition, getHtmlTagDefinition, TagContentType, splitNsName, isNgContainer, isNgContent, isNgTemplate, getNsPrefix, mergeNsAndName, NAMED_ENTITIES, NGSP_UNICODE, debugOutputAstAsTypeScript, TypeScriptEmitter, ParseLocation, ParseSourceFile, ParseSourceSpan, EMPTY_PARSE_LOCATION, EMPTY_SOURCE_SPAN, ParseErrorLevel, ParseError, typeSourceSpan, r3JitTypeSourceSpan, DomElementSchemaRegistry, CssSelector, SelectorMatcher, SelectorListContext, SelectorContext, HOST_ATTR, CONTENT_ATTR, StylesCompileDependency, CompiledStylesheet, StyleCompiler, TemplateParseError, TemplateParseResult, TemplateParser, splitClasses, createElementCssSelector, removeSummaryDuplicates, isEmptyExpression, compileInjectable, R3TargetBinder, R3BoundTarget };
26873//# sourceMappingURL=compiler.js.map